Skip to content

Commit

Permalink
Build the DNF5 plugin on F41+
Browse files Browse the repository at this point in the history
Fixes: #2
Closes: #4
  • Loading branch information
praiskup committed Feb 9, 2025
1 parent 0468683 commit 83341db
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 10 deletions.
10 changes: 8 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
.deps
.dirstamp
.libs
Makefile
Makefile.in
ar-lib
aclocal.m4
autom4te.cache
config.log
config.status
compile
config.*
configure
depcomp
install-sh
libtool
ltmain.sh
missing
py-compile
stamp-h1
*.la
*.lo
*.log
*.o
*~
2 changes: 2 additions & 0 deletions .packit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
srpm_build_deps:
- automake
- git
- libtool
- libdnf5-cli-devel
- make

specfile_path: rpm/dnf-plugin-diff.spec
Expand Down
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ libexec_SCRIPTS = \
libexec/dnf-diff-changed-files \
libexec/dnf-diff-rpm-filename

SUBDIRS = dnf5-plugins

EXTRA_DIST = $(libexec_SCRIPTS)
13 changes: 11 additions & 2 deletions configure.ac
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
AC_INIT([dnf-plugin-diff], [1.1], [[email protected]])
AC_INIT([dnf-plugin-diff], [2.0], [[email protected]])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AM_PROG_AR
AC_PROG_CXX([c++])
LT_INIT
AM_PATH_PYTHON
AC_CONFIG_FILES([Makefile])
AC_ARG_ENABLE([dnf5],
AS_HELP_STRING([--disable-dnf5], [Do not build against DNF5]))
AS_IF([test "x$enable_dnf5" != "xno"], [
PKG_CHECK_MODULES([LIBDNF5], [libdnf5-cli])
])
AM_CONDITIONAL([BUILD_WITH_DNF5], [test "x$enable_dnf5" != "xno"])
AC_CONFIG_FILES([Makefile dnf5-plugins/Makefile])
AC_OUTPUT
8 changes: 8 additions & 0 deletions dnf5-plugins/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
dnf5plugindir = $(libdir)/dnf5/plugins

if BUILD_WITH_DNF5
dnf5plugin_LTLIBRARIES = diff.la
diff_la_SOURCES = diff.cc diff.hh diff_cmd_plugin.cc
diff_la_LDFLAGS = $(LIBDNF5_LDFLAGS) -module -avoid-version -shared
diff_la_CXXFLAGS = $(LIBDNF5_CXXFLAGS) -UPACKAGE -std=gnu++20 -Wl,--as-needed -fvisibility-inlines-hidden
endif
117 changes: 117 additions & 0 deletions dnf5-plugins/diff.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#include "diff.hh"

#include <libdnf5/rpm/package_query.hpp>
#include <libdnf5/repo/package_downloader.hpp>
#include <libdnf5-cli/session.hpp>
#include <boost/process.hpp>

#include <iostream>
#include <filesystem>

namespace bp = boost::process;

namespace dnf5 {


using namespace libdnf5::cli;

void DiffCommand::set_parent_command() {
// register our command
auto * arg_parser_parent_cmd = get_session().get_argument_parser().get_root_command();
auto * diff_cmd = get_argument_parser_command();
arg_parser_parent_cmd->register_command(diff_cmd);
}

void DiffCommand::set_argument_parser() {
// Register command arguments to the argument parser
auto & diff_cmd = *get_argument_parser_command();
auto & parser = diff_cmd.get_argument_parser();

diff_cmd.set_description("Show changes in installed packages as a diff");

auto args = parser.add_new_positional_arg("PACKAGE [FILENAME]",
ArgumentParser::PositionalArg::UNLIMITED, nullptr, nullptr);
args->set_description("Specify package name you want to diff, and optionally a filename.");
args->set_parse_hook_func(
[this]([[maybe_unused]] ArgumentParser::PositionalArg * arg, int argc, const char * const argv[]) {
for (int i = 0; i < argc; ++i) {
positional_args.emplace_back(argv[i]);
}
return true;
});
diff_cmd.register_positional_arg(args);
}

void DiffCommand::configure() {
auto & context = get_context();
context.set_load_system_repo(true);
context.set_load_available_repos(Context::LoadAvailableRepos::ENABLED);
}

const std::vector<std::string> DiffCommand::changed_files(const std::string & package_name) {
bp::ipstream out;
bp::child c("/usr/libexec/dnf-diff-changed-files",
std::vector<std::string> {package_name},
bp::std_out > out);
std::vector<std::string> changed_files;
std::string changed_file;
while (std::getline(out, changed_file)) {
changed_files.push_back(changed_file);
}
return changed_files;
}

void DiffCommand::run() {
if (positional_args.size() < 1)
throw std::runtime_error("Package name not specified");

auto &package_name = positional_args[0];

// load the installed Package metadata
libdnf5::rpm::PackageQuery installed_pkg(get_context().get_base());
installed_pkg.filter_installed();
installed_pkg.filter_name(std::vector<std::string>{package_name.c_str()});

if (installed_pkg.empty())
throw std::runtime_error("Package not installed: " + package_name);

if (installed_pkg.size() > 1)
throw std::runtime_error("Multiple packages installed: " + package_name);

// separate query for the online counterpart (has location)
libdnf5::rpm::PackageQuery available_pkg(get_context().get_base());
available_pkg.filter_available();

for (const auto & pkg : installed_pkg) {
available_pkg.filter_name(std::vector<std::string>{pkg.get_name()});
available_pkg.filter_version(pkg.get_version());
available_pkg.filter_release(pkg.get_release());
available_pkg.filter_arch(pkg.get_arch());
break;
}

auto const &diff_files = changed_files(package_name);
if (diff_files.empty())
throw std::runtime_error("No changes in '" + package_name + "'.");

// download the RPM file
libdnf5::repo::PackageDownloader downloader(get_context().get_base());
const char * home = getenv("HOME");
std::filesystem::path download_dir(home);
download_dir /= ".cache/dnf-diff";
std::string rpm_filename;
for (const auto & pkg : available_pkg) {
downloader.add(pkg, download_dir);
std::filesystem::path loc = pkg.get_location();
rpm_filename = loc.filename();
break; // we take the first occurrence
}
downloader.download();

// extract the RPM file, and run diff against changed files
for (auto const &filename : diff_files)
bp::system("/usr/libexec/dnf-diff-rpm-filename", rpm_filename, filename);
}


} // namespace dnf5
34 changes: 34 additions & 0 deletions dnf5-plugins/diff.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef DNF5_DIFF_PLUGIN_DIFF_HPP
#define DNF5_DIFF_PLUGIN_DIFF_HPP

#include <dnf5/context.hpp>
#include <libdnf5-cli/session.hpp>

#include <string>
#include <vector>


namespace dnf5 {


class DiffCommand : public Command {
public:
explicit DiffCommand(Context & context) : Command(context, "diff") {}
void set_parent_command() override;
void set_argument_parser() override;
void configure() override;
void run() override;

private:
std::vector<std::string> positional_args{};
std::unique_ptr<libdnf5::cli::session::BoolOption> test_switch{nullptr};
libdnf5::OptionString * test_string_option{nullptr};

const std::vector<std::string> changed_files(const std::string & package_name);
};


} // namespace dnf5


#endif // DNF5_DIFF_PLUGIN_DIFF_HPP
74 changes: 74 additions & 0 deletions dnf5-plugins/diff_cmd_plugin.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include "diff.hh"

#include <dnf5/iplugin.hpp>

#include <iostream>

using namespace dnf5;

namespace {

constexpr const char * PLUGIN_NAME{"diff"};
constexpr PluginVersion PLUGIN_VERSION{.major = 1, .minor = 0, .micro = 0};

constexpr const char * attrs[]{"author.name", "author.email", "description", nullptr};
constexpr const char * attrs_value[]{"Pavel Raiskup", "[email protected]", "diff command."};

class DiffCmdPlugin : public IPlugin {
public:
using IPlugin::IPlugin;

PluginAPIVersion get_api_version() const noexcept override { return PLUGIN_API_VERSION; }

const char * get_name() const noexcept override { return PLUGIN_NAME; }

PluginVersion get_version() const noexcept override { return PLUGIN_VERSION; }

const char * const * get_attributes() const noexcept override { return attrs; }

const char * get_attribute(const char * attribute) const noexcept override {
for (size_t i = 0; attrs[i]; ++i) {
if (std::strcmp(attribute, attrs[i]) == 0) {
return attrs_value[i];
}
}
return nullptr;
}

std::vector<std::unique_ptr<Command>> create_commands() override;

void finish() noexcept override {}
};


std::vector<std::unique_ptr<Command>> DiffCmdPlugin::create_commands() {
std::vector<std::unique_ptr<Command>> commands;
commands.push_back(std::make_unique<DiffCommand>(get_context()));
return commands;
}


} // namespace


PluginAPIVersion dnf5_plugin_get_api_version(void) {
return PLUGIN_API_VERSION;
}

const char * dnf5_plugin_get_name(void) {
return PLUGIN_NAME;
}

PluginVersion dnf5_plugin_get_version(void) {
return PLUGIN_VERSION;
}

IPlugin * dnf5_plugin_new_instance([[maybe_unused]] ApplicationVersion application_version, Context & context) try {
return new DiffCmdPlugin(context);
} catch (...) {
return nullptr;
}

void dnf5_plugin_delete_instance(IPlugin * plugin_object) {
delete plugin_object;
}
53 changes: 47 additions & 6 deletions rpm/dnf-plugin-diff.spec
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
%if 0%{?fedora} >= 41
%bcond_without dnf5
%else
%bcond_with dnf5
%endif

%global __python %__python3

%global _desc \
DNF plugin to compare files from the original package contents with locally \
available files and display differences in text files, such as configuration \
changes or source code (for interpreted languages).

%global _summary Display local changes in files from installed RPM packages

Name: dnf-plugin-diff
Version: 1.1
Version: 2.0
Release: 1%{?dist}
Summary: Display local changes in files from installed RPM packages
BuildArch: noarch
Summary: %_summary

License: GPLv2+
URL: https://github.com/praiskup/%name
Source0: https://github.com/praiskup/%name/archive/v%version/%name-%version.tar.gz

BuildRequires: python3-devel
BuildRequires: /usr/bin/c++
BuildRequires: make

Requires: cpio
Expand All @@ -20,19 +33,38 @@ Requires: file

Provides: dnf-command(diff) = %version

%if %{with dnf5}
BuildRequires: boost-devel
BuildRequires: dnf5-devel
BuildRequires: libdnf5-cli-devel
%else
BuildArch: noarch
%endif

%description
DNF plugin to compare files from the original package contents with locally
available files and display differences in text files, such as configuration
changes or source code (for interpreted languages).
%_desc


%if %{with dnf5}
%package -n dnf5-plugin-diff
Requires: dnf5
Summary: %_summary
Provides: dnf5-command(diff) = %version

%description -n dnf5-plugin-diff
%_desc
%endif

%prep
%setup -q


%build
%if %{with dnf5}
%configure PYTHON=python3
%else
%configure PYTHON=python3 --disable-dnf5
%endif
%make_build


Expand All @@ -47,6 +79,15 @@ changes or source code (for interpreted languages).
%python3_sitelib/dnf-plugins


%if %{with dnf5}
%files -n dnf5-plugin-diff
%license COPYING
%doc README
%_libexecdir/dnf-diff-*
%_libdir/dnf5/plugins/diff.so
%endif


%changelog
* Mon Sep 03 2018 Pavel Raiskup <[email protected]>
- no changelog in upstream git

0 comments on commit 83341db

Please sign in to comment.