summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2020-11-07 21:23:57 +0100
committerDavid Kalnischkies <david@kalnischkies.de>2020-11-07 21:48:21 +0100
commit9e1398b164f55238990907f63dfdef60588d9b24 (patch)
tree1d0976f1eea0c74711a60ed069c0232fbb55f284
parent645ad0c97334265bbfef82a4bdfdc8337cdd0630 (diff)
Prepare rred binary for external usage
Merging patches is a bit of non-trivial code we have for client-side work, but as we support also server-side merging we can export this functionality so that server software can reuse it. Note that this just cleans up and makes rred behave a bit more like all our other binaries by supporting setting configuration at runtime and supporting --help and --version. If you can make due without this, the now advertised functionality is provided already in earlier versions.
-rw-r--r--apt-private/private-cmndline.cc11
-rw-r--r--apt-private/private-cmndline.h1
-rw-r--r--apt-private/private-main.cc1
-rw-r--r--doc/examples/configure-index2
-rw-r--r--methods/CMakeLists.txt2
-rw-r--r--methods/rred.cc131
-rwxr-xr-xtest/integration/test-00-commands-have-help6
-rwxr-xr-xtest/integration/test-method-rred37
8 files changed, 144 insertions, 47 deletions
diff --git a/apt-private/private-cmndline.cc b/apt-private/private-cmndline.cc
index bcafe785b..b6c5ca90a 100644
--- a/apt-private/private-cmndline.cc
+++ b/apt-private/private-cmndline.cc
@@ -362,6 +362,13 @@ static bool addArgumentsAPT(std::vector<CommandLine::Args> &Args, char const * c
return true;
}
/*}}}*/
+static bool addArgumentsRred(std::vector<CommandLine::Args> &Args, char const * const /*Cmd*/)/*{{{*/
+{
+ addArg('t', nullptr, "Rred::T", 0);
+ addArg('f', nullptr, "Rred::F", 0);
+ return true;
+}
+ /*}}}*/
std::vector<CommandLine::Args> getCommandArgs(APT_CMD const Program, char const * const Cmd)/*{{{*/
{
std::vector<CommandLine::Args> Args;
@@ -384,6 +391,7 @@ std::vector<CommandLine::Args> getCommandArgs(APT_CMD const Program, char const
case APT_CMD::APT_INTERNAL_SOLVER: addArgumentsAPTInternalSolver(Args, Cmd); break;
case APT_CMD::APT_MARK: addArgumentsAPTMark(Args, Cmd); break;
case APT_CMD::APT_SORTPKG: addArgumentsAPTSortPkgs(Args, Cmd); break;
+ case APT_CMD::RRED: addArgumentsRred(Args, Cmd); break;
}
// options without a command
@@ -441,11 +449,12 @@ static bool ShowCommonHelp(APT_CMD const Binary, CommandLine &CmdL, std::vector<
case APT_CMD::APT_INTERNAL_SOLVER: cmd = nullptr; break;
case APT_CMD::APT_MARK: cmd = "apt-mark(8)"; break;
case APT_CMD::APT_SORTPKG: cmd = "apt-sortpkgs(1)"; break;
+ case APT_CMD::RRED: cmd = nullptr; break;
}
if (cmd != nullptr)
ioprintf(std::cout, _("See %s for more information about the available commands."), cmd);
if (Binary != APT_CMD::APT_DUMP_SOLVER && Binary != APT_CMD::APT_INTERNAL_SOLVER &&
- Binary != APT_CMD::APT_INTERNAL_PLANNER)
+ Binary != APT_CMD::APT_INTERNAL_PLANNER && Binary != APT_CMD::RRED)
std::cout << std::endl <<
_("Configuration options and syntax is detailed in apt.conf(5).\n"
"Information about how to configure sources can be found in sources.list(5).\n"
diff --git a/apt-private/private-cmndline.h b/apt-private/private-cmndline.h
index 37fe2c91a..22e25d280 100644
--- a/apt-private/private-cmndline.h
+++ b/apt-private/private-cmndline.h
@@ -23,6 +23,7 @@ enum class APT_CMD {
APT_SORTPKG,
APT_DUMP_SOLVER,
APT_INTERNAL_PLANNER,
+ RRED,
};
struct aptDispatchWithHelp
{
diff --git a/apt-private/private-main.cc b/apt-private/private-main.cc
index e9f65bd83..d4ce0ab2a 100644
--- a/apt-private/private-main.cc
+++ b/apt-private/private-main.cc
@@ -33,6 +33,7 @@ void InitLocale(APT_CMD const binary) /*{{{*/
case APT_CMD::APT_HELPER:
case APT_CMD::APT_GET:
case APT_CMD::APT_MARK:
+ case APT_CMD::RRED:
textdomain("apt");
break;
case APT_CMD::APT_EXTRACTTEMPLATES:
diff --git a/doc/examples/configure-index b/doc/examples/configure-index
index d9f269344..ee031c8b4 100644
--- a/doc/examples/configure-index
+++ b/doc/examples/configure-index
@@ -830,6 +830,8 @@ dir::filelistdir "<STRING>";
dir::dpkg::tupletable "<FILE>";
dir::dpkg::triplettable "<FILE>";
dir::dpkg::cputable "<FILE>";
+Rred::t "<BOOL>";
+Rred::f "<BOOL>";
APT::Internal::OpProgress::Absolute "<BOOL>";
APT::Color "<BOOL>";
diff --git a/methods/CMakeLists.txt b/methods/CMakeLists.txt
index d575382f7..a5a360217 100644
--- a/methods/CMakeLists.txt
+++ b/methods/CMakeLists.txt
@@ -23,6 +23,8 @@ target_include_directories(http PRIVATE $<$<BOOL:${SYSTEMD_FOUND}>:${SYSTEMD_INC
target_link_libraries(http ${GNUTLS_LIBRARIES} $<$<BOOL:${SYSTEMD_FOUND}>:${SYSTEMD_LIBRARIES}>)
target_link_libraries(ftp ${GNUTLS_LIBRARIES})
+target_link_libraries(rred apt-private)
+
# Install the library
install(TARGETS file copy store gpgv cdrom http ftp rred rsh mirror
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/apt/methods)
diff --git a/methods/rred.cc b/methods/rred.cc
index 949fa4773..b7825721c 100644
--- a/methods/rred.cc
+++ b/methods/rred.cc
@@ -15,6 +15,8 @@
#include <apt-pkg/init.h>
#include <apt-pkg/strutl.h>
+#include <apt-private/private-cmndline.h>
+
#include <iostream>
#include <list>
#include <string>
@@ -33,6 +35,33 @@
#define BLOCK_SIZE (512*1024)
+static bool ShowHelp(CommandLine &)
+{
+ std::cout <<
+ "Usage: rred [options] -t input output patch-1 … patch-N\n"
+ " rred [options] -f patch-1 … patch-N < input > output\n"
+ " rred [options] patch-1 … patch-N > merged-patch\n"
+ "\n"
+ "The main use of this binary is by APTs acquire system, a mode reached\n"
+ "by calling it without any arguments and driven via messages on stdin.\n"
+ "\n"
+ "For the propose of testing as well as simpler direct usage the above\n"
+ "mentioned modes to work with \"reversed restricted ed\" patches as well.\n"
+ "\n"
+ "The arguments used above are:\n"
+ "* input: denotes a file you want to patch.\n"
+ "* output: a file you want to store the patched content in.\n"
+ "* patch-1 … patch-N: One or more files containing a patch.\n"
+ "* merged-patch: All changes by patch-1 … patch-N in one patch.\n"
+ "\n"
+ "This rred supports the commands 'a', 'c' and 'd', both single as well\n"
+ "as multi line. Other commands are not supported (hence 'restricted').\n"
+ "The command to patch the last line must appear first in the patch\n"
+ "(hence 'reversed'). Such a patch can e.g. be produced with 'diff --ed'.\n"
+ ;
+ return true;
+}
+
class MemBlock {
char *start;
size_t size;
@@ -727,62 +756,74 @@ class RredMethod : public aptMethod {
}
};
-int main(int argc, char **argv)
+static std::vector<aptDispatchWithHelp> GetCommands()
{
- int i;
- bool just_diff = true;
- bool test = false;
- Patch patch;
-
- if (argc <= 1) {
+ return {{nullptr, nullptr, nullptr}};
+}
+int main(int argc, const char *argv[])
+{
+ if (argc <= 1)
return RredMethod().Run();
+
+ CommandLine CmdL;
+ auto const Cmds = ParseCommandLine(CmdL, APT_CMD::RRED, &_config, nullptr, argc, argv, &ShowHelp, &GetCommands);
+
+ FileFd input, output;
+ unsigned int argi = 0;
+ auto const argmax = CmdL.FileSize();
+ bool const quiet = _config->FindI("quiet", 0) >= 2;
+
+ bool just_diff = false;
+ if (_config->FindB("Rred::T", false))
+ {
+ if (argmax < 3)
+ {
+ std::cerr << "E: Not enough filenames given on the command line for mode 't'\n";
+ return 101;
+ }
+ if (not quiet)
+ std::clog << "Patching " << CmdL.FileList[0] << " into " << CmdL.FileList[1] << "\n";
+ input.Open(CmdL.FileList[0], FileFd::ReadOnly,FileFd::Extension);
+ output.Open(CmdL.FileList[1], FileFd::WriteOnly | FileFd::Create | FileFd::Empty | FileFd::BufferedWrite, FileFd::Extension);
+ argi = 2;
+ }
+ else
+ {
+ output.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::Create | FileFd::BufferedWrite);
+ if (_config->FindB("Rred::F", false))
+ input.OpenDescriptor(STDIN_FILENO, FileFd::ReadOnly);
+ else
+ just_diff = true;
}
- // Usage: rred -t input output diff ...
- if (argc > 1 && strcmp(argv[1], "-t") == 0) {
- // Read config files so we see compressors.
- pkgInitConfig(*_config);
- just_diff = false;
- test = true;
- i = 4;
- } else if (argc > 1 && strcmp(argv[1], "-f") == 0) {
- just_diff = false;
- i = 2;
- } else {
- i = 1;
+ if (argi + 1 > argmax)
+ {
+ std::cerr << "E: At least one patch needs to be given on the command line\n";
+ return 101;
}
- for (; i < argc; i++) {
- FileFd p;
- if (p.Open(argv[i], FileFd::ReadOnly) == false) {
+ Patch merged_patch;
+ for (; argi < argmax; ++argi)
+ {
+ FileFd patch;
+ if (not patch.Open(CmdL.FileList[argi], FileFd::ReadOnly))
+ {
_error->DumpErrors(std::cerr);
- exit(1);
+ return 1;
}
- if (patch.read_diff(p, NULL) == false)
+ if (not merged_patch.read_diff(patch, nullptr))
{
_error->DumpErrors(std::cerr);
- exit(2);
+ return 2;
}
}
- if (test) {
- FileFd out, inp;
- std::cerr << "Patching " << argv[2] << " into " << argv[3] << "\n";
- inp.Open(argv[2], FileFd::ReadOnly,FileFd::Extension);
- out.Open(argv[3], FileFd::WriteOnly | FileFd::Create | FileFd::Empty | FileFd::BufferedWrite, FileFd::Extension);
- patch.apply_against_file(out, inp);
- out.Close();
- } else if (just_diff) {
- FileFd out;
- out.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::Create);
- patch.write_diff(out);
- out.Close();
- } else {
- FileFd out, inp;
- out.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::Create | FileFd::BufferedWrite);
- inp.OpenDescriptor(STDIN_FILENO, FileFd::ReadOnly);
- patch.apply_against_file(out, inp);
- out.Close();
- }
- return 0;
+ if (just_diff)
+ merged_patch.write_diff(output);
+ else
+ merged_patch.apply_against_file(output, input);
+
+ output.Close();
+ input.Close();
+ return DispatchCommandLine(CmdL, {});
}
diff --git a/test/integration/test-00-commands-have-help b/test/integration/test-00-commands-have-help
index 4a0cc64d4..f91238d5d 100755
--- a/test/integration/test-00-commands-have-help
+++ b/test/integration/test-00-commands-have-help
@@ -49,7 +49,11 @@ for CMD in 'apt-cache' 'apt-cdrom' 'apt-config' \
checkoptions "$cmd"
done
-for CMD in 'apt-dump-solver' 'apt-internal-solver' 'apt-internal-planner'; do
+
+rred() {
+ runapt "${METHODSDIR}/rred" "$@"
+}
+for CMD in 'apt-dump-solver' 'apt-internal-solver' 'apt-internal-planner' 'rred'; do
checkoptions "$(echo "$CMD" | tr -d '-')"
done
diff --git a/test/integration/test-method-rred b/test/integration/test-method-rred
index 5a885e9d2..00b4b7c0b 100755
--- a/test/integration/test-method-rred
+++ b/test/integration/test-method-rred
@@ -195,3 +195,40 @@ Package: supercoolstuff
failrred 'Wrong order of commands' '7d
17d'
failrred 'End before start' '7,6d'
+
+# deal correctly with patch merging
+mergepatches() {
+ testsuccess runapt "${METHODSDIR}/rred" Packages.ed-*
+ cp -a rootdir/tmp/testsuccess.output patch.ed
+ testfileequal 'patch.ed' "$1"
+}
+createpatch() {
+ echo "$2"
+}
+
+createpatch 'Change dog to cat + kitties' '19c
+ And a cat!
+
+Package: extra-kittens
+Version: unavailable
+Description: fix later
+.' > Packages.ed-0
+createpatch 'Remove more stuff and fix later' '23d,
+6d' > Packages.ed-1
+createpatch 'Remove (old) dog paragraph' '10,19d' > Packages.ed-2
+mergepatches '11,19c
+Package: extra-kittens
+Version: unavailable
+.
+6d'
+testrred 'Apply' 'merged patch' "$(cat patch.ed)" 'Package: coolstuff
+Version: 0.8.15
+Description: collection of stuff
+ A lot, too much to iterate all, but at least this:
+ - stuff
+ - even more stuff
+ .
+ And a cow.
+
+Package: extra-kittens
+Version: unavailable'