aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-06-28 00:33:01 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-06-28 00:33:01 +0000
commitcf7782e184c6c7548bd52349c5ace868890b77d9 (patch)
tree0f61625a92119cf9108588f664e0abc090805dae
parentfe5d06be3529fcd8a11205c6d7762a329a438f3a (diff)
downloadpaludis-cf7782e184c6c7548bd52349c5ace868890b77d9.tar.gz
paludis-cf7782e184c6c7548bd52349c5ace868890b77d9.tar.xz
Replace the icky bash unmerge with a slightly less icky C++ unmerge
-rw-r--r--ebuild/utils/Makefile.am13
-rwxr-xr-xebuild/utils/unmerge128
-rw-r--r--ebuild/utils/unmerge.cc234
-rw-r--r--ebuild/utils/unmerge_TEST.bash4
4 files changed, 244 insertions, 135 deletions
diff --git a/ebuild/utils/Makefile.am b/ebuild/utils/Makefile.am
index b40802c..03bb652 100644
--- a/ebuild/utils/Makefile.am
+++ b/ebuild/utils/Makefile.am
@@ -44,20 +44,23 @@ libexecprog_SCRIPTS = \
newlib.so \
newman \
newsbin \
- unmerge \
$(libexecprog_SCRIPTS_extra)
-libexecprog_PROGRAMS = merge
+libexecprog_PROGRAMS = merge unmerge
AM_CXXFLAGS = -I$(top_srcdir)
+
merge_SOURCES = merge.cc
-merge_DEFS= \
- -DSYSCONFDIR=\"$(sysconfdir)\" \
- -DLIBEXECDIR=\"$(libexecdir)\"
merge_LDADD = \
$(top_builddir)/paludis/libpaludis.a \
$(top_builddir)/paludis/args/libpaludisargs.a \
$(top_builddir)/paludis/util/libpaludisutil.a
+unmerge_SOURCES = unmerge.cc
+unmerge_LDADD = \
+ $(top_builddir)/paludis/libpaludis.a \
+ $(top_builddir)/paludis/args/libpaludisargs.a \
+ $(top_builddir)/paludis/util/libpaludisutil.a
+
TESTS_ENVIRONMENT = env \
PALUDIS_EBUILD_DIR="`$(top_srcdir)/ebuild/utils/canonicalise $(top_srcdir)/ebuild/`" \
TOP_BUILD_DIR="`$(top_srcdir)/ebuild/utils/canonicalise $(top_builddir)/`" \
diff --git a/ebuild/utils/unmerge b/ebuild/utils/unmerge
deleted file mode 100755
index 66bb69d..0000000
--- a/ebuild/utils/unmerge
+++ /dev/null
@@ -1,128 +0,0 @@
-#!/bin/bash
-# vim: set sw=4 sts=4 et :
-
-# Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
-#
-# This file is part of the Paludis package manager. Paludis is free software;
-# you can redistribute it and/or modify it under the terms of the GNU General
-# Public License as published by the Free Software Foundation; either version
-# 2 of the License, or (at your option) any later version.
-#
-# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-# details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
-# Place, Suite 330, Boston, MA 02111-1307 USA
-
-source ${PALUDIS_EBUILD_DIR}/echo_functions.bash
-export PATH="$(${PALUDIS_EBUILD_DIR}/utils/canonicalise ${PALUDIS_EBUILD_DIR}/utils/ ):${PATH}"
-
-if [[ -z "${1}" ]] || [[ -z "${2}" ]] ; then
- echo "usage: ${0} from contents"
- exit 247
-fi
-
-shopt -s dotglob
-shopt -s nullglob
-
-ROOT=$(canonicalise "${1%+(/)}/" )
-export ROOT
-export contents=${2}
-
-if [[ ! -d ${ROOT} ]] ; then
- echo "${ROOT}: not a directory; aborting" >&2
- exit 247
-fi
-
-if [[ ! -f "${contents}" ]] ; then
- echo "${contents}: not a file; aborting" >&2
- exit 247
-fi
-
-sort -r -t ' ' -k 2 < "${contents}" | \
-while read entry ; do
- [[ -z "${entry}" ]] && continue
- items=( ${entry} )
- case ${items[0]} in
- dir)
- ;;
-
- sym)
- if ! [[ -L "${ROOT}/${items[1]}" ]] ; then
- echo "skip !type ${items[1]}"
- elif [[ $(readlink -- "${ROOT}/${items[1]}" ) != "${items[3]}" ]] ; then
- echo "skip !dest ${items[1]}"
- elif [[ $(getmtime -- "${ROOT}/${items[1]}" ) != "${items[4]}" ]] ; then
- echo "skip !time ${items[1]}"
- else
- echo "remove ${items[1]}"
- rm -f -- "${ROOT}/${items[1]}"
- fi
- ;;
-
- obj)
- if ! [[ -f "${ROOT}/${items[1]}" ]] ; then
- echo "skip !type ${items[1]}"
- elif [[ $(md5sum -- "${ROOT}/${items[1]}" | cut -d' ' -f1 ) != "${items[2]}" ]] ; then
- echo "skip !md5 ${items[1]}"
- elif [[ $(getmtime -- "${ROOT}/${items[1]}" ) != "${items[3]}" ]] ; then
- echo "skip !time ${items[1]}"
- else
- cfgpro=
- for c in ${CONFIG_PROTECT}; do
- if [[ ${items[1]} == "${c%/}"/* ]]; then
- cfgpro="yes"
- for cm in ${CONFIG_PROTECT_MASK}; do
- if [[ ${items[1]} == "${cm%/}"/* ]]; then
- cfgpro=
- fi
- done
- fi
- done
- if [[ -n ${cfgpro} ]]; then
- echo "cfgpro ${items[1]}"
- else
- echo "remove ${items[1]}"
- rm -f "${ROOT}/${items[1]}"
- fi
- fi
- ;;
-
- misc)
- if [[ -f "${ROOT}/${items[1]}" ]] ; then
- echo "skip !type ${items[1]}"
- elif [[ $(getmtime -- "${ROOT}/${items[1]}" ) != "${items[2]}" ]] ; then
- echo "skip !time ${items[1]}"
- else
- echo "remove ${items[1]}"
- rm -f "${ROOT}/${items[1]}"
- fi
- ;;
-
- *)
- die "Unknown VDB entry kind '${kind}'"
- ;;
- esac
-done
-
-sort -r -t ' ' -k 2 < "${contents}" | \
-while read entry ; do
- [[ -z "${entry}" ]] && continue
- items=( ${entry} )
- case ${items[0]} in
- dir)
- if ! [[ -d "${ROOT}/${items[1]}" ]] ; then
- echo "skip !type ${items[1]}"
- elif [[ $(echo "${ROOT}/${items[1]}"/* ) != "${ROOT}/${items[1]}/*" ]] ; then
- echo "skip !empty ${items[1]}"
- else
- echo "remove ${items[1]}"
- rm -fr -- "${ROOT}/${items[1]}"
- fi
- ;;
- esac
-done
-
diff --git a/ebuild/utils/unmerge.cc b/ebuild/utils/unmerge.cc
new file mode 100644
index 0000000..2b74347
--- /dev/null
+++ b/ebuild/utils/unmerge.cc
@@ -0,0 +1,234 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/pstream.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/tokeniser.hh>
+
+#include <algorithm>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <iterator>
+#include <string>
+#include <deque>
+#include <vector>
+
+#include <cstdlib>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+using namespace paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::ifstream;
+
+namespace
+{
+ int exit_status;
+
+ struct Failure
+ {
+ std::string message;
+
+ Failure(const std::string & m) :
+ message(m)
+ {
+ };
+ };
+
+ template <typename Iter_>
+ void unmerge_contents(const FSEntry & root, const Iter_ begin, const Iter_ end)
+ {
+ using std::istreambuf_iterator;
+
+ for (Iter_ cur(begin) ; cur != end ; ++cur)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*cur, std::back_inserter(tokens));
+ if (tokens.empty())
+ continue;
+
+ if ("obj" == tokens.at(0))
+ {
+ if (tokens.size() != 4)
+ {
+ Log::get_instance()->message(ll_warning, "Malformed VDB entry '" + *cur + "'");
+ exit_status |= 4;
+ }
+ else if (! (root / tokens.at(1)).is_regular_file())
+ cout << "--- [!type] " << tokens.at(1) << endl;
+ else if (stringify((root / tokens.at(1)).mtime()) != tokens.at(3))
+ cout << "--- [!time] " << tokens.at(1) << endl;
+ else
+ {
+ PStream md5command(getenv_or_error("PALUDIS_EBUILD_DIR") +
+ "/digests/domd5 '" + stringify(root / tokens.at(1)) + "'");
+ std::string md5((istreambuf_iterator<char>(md5command)), istreambuf_iterator<char>());
+ if (0 != md5command.exit_status())
+ {
+ Log::get_instance()->message(ll_warning, "Couldn't get md5 for '" +
+ stringify(root / tokens.at(1)) + "'");
+ cout << "--- [!md5?] " << tokens.at(1) << endl;
+ }
+ else if (strip_trailing(md5, "\n") != tokens.at(2))
+ cout << "--- [!md5 ] " << tokens.at(1) << endl;
+ else
+ {
+ cout << "<<< " << tokens.at(1) << endl;
+ (root / tokens.at(1)).unlink();
+ }
+ }
+ }
+ else if ("sym" == tokens.at(0))
+ {
+ if (tokens.size() != 5)
+ {
+ Log::get_instance()->message(ll_warning, "Malformed VDB entry '" + *cur + "'");
+ exit_status |= 4;
+ }
+ else if (! (root / tokens.at(1)).is_symbolic_link())
+ cout << "--- [!type] " << tokens.at(1) << endl;
+ else if (stringify((root / tokens.at(1)).mtime()) != tokens.at(4))
+ cout << "--- [!time] " << tokens.at(1) << endl;
+ else if ((root / tokens.at(1)).readlink() != tokens.at(3))
+ cout << "--- [!dest] " << tokens.at(1) << endl;
+ else
+ {
+ cout << "<<< " << tokens.at(1) << endl;
+ (root / tokens.at(1)).unlink();
+ }
+ }
+ else if ("misc" == tokens.at(0))
+ {
+
+ }
+ else if ("dir" == tokens.at(0))
+ /* nothing */ ;
+ else
+ {
+ Log::get_instance()->message(ll_warning, "Skipping unknown VDB entry '" + *cur + "'");
+ exit_status |= 2;
+ }
+ }
+ }
+
+ template <typename Iter_>
+ void unmerge_directories(const FSEntry & root, const Iter_ begin, const Iter_ end)
+ {
+ using std::istreambuf_iterator;
+
+ for (Iter_ cur(begin) ; cur != end ; ++cur)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*cur, std::back_inserter(tokens));
+ if (tokens.empty())
+ continue;
+
+ if ("dir" == tokens.at(0))
+ {
+ if (tokens.size() != 2)
+ {
+ Log::get_instance()->message(ll_warning, "Malformed VDB entry '" + *cur + "'");
+ exit_status |= 8;
+ }
+ else if (! (root / tokens.at(1)).is_directory())
+ cout << "--- [!type] " << tokens.at(1) << endl;
+ else if (DirIterator((root / tokens.at(1)), false) != DirIterator())
+ cout << "--- [!empt] " << tokens.at(1) << endl;
+ else
+ {
+ cout << "<<< " << tokens.at(1) << endl;
+ (root / tokens.at(1)).rmdir();
+ }
+ }
+ }
+ }
+}
+
+int
+main(int argc, char * argv[])
+{
+ Context context("In main program:");
+ exit_status = 0;
+ try
+ {
+ if (argc != 3)
+ throw Failure("Usage: " + stringify(argv[0]) + " root contents");
+
+ Log::get_instance()->set_program_name(argv[0]);
+ std::string log_level(getenv_with_default("PALUDIS_EBUILD_LOG_LEVEL", "qa"));
+
+ if (log_level == "debug")
+ Log::get_instance()->set_log_level(ll_debug);
+ else if (log_level == "qa")
+ Log::get_instance()->set_log_level(ll_qa);
+ else if (log_level == "warning")
+ Log::get_instance()->set_log_level(ll_warning);
+ else if (log_level == "silent")
+ Log::get_instance()->set_log_level(ll_silent);
+ else
+ throw Failure("bad value for log level");
+
+ FSEntry root(argv[1]), contents(argv[2]);
+
+ if (! ((root = root.realpath())).is_directory())
+ throw Failure(stringify(argv[1]) + ": not a directory");
+
+ ifstream contents_file(stringify(contents).c_str());
+ if (! contents_file)
+ throw Failure(stringify(contents) + ": not readable");
+
+ std::deque<std::string> lines;
+ std::string line;
+ while (std::getline(contents_file, line))
+ lines.push_back(line);
+
+ unmerge_contents(root, lines.begin(), lines.end());
+ unmerge_directories(root, lines.rbegin(), lines.rend());
+ return exit_status;
+ }
+ catch (const Failure & f)
+ {
+ cerr << argv[0] << ": fatal error: " << f.message << endl;
+ return EXIT_FAILURE;
+ }
+ catch (const Exception & e)
+ {
+ cerr << argv[0] << ": fatal error:" << endl
+ << " * " << e.backtrace("\n * ") << e.message()
+ << " (" << e.what() << ")" << endl;
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception & e)
+ {
+ cerr << argv[0] << ": fatal error: " << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+}
+
+
diff --git a/ebuild/utils/unmerge_TEST.bash b/ebuild/utils/unmerge_TEST.bash
index 31b8f82..4a168da 100644
--- a/ebuild/utils/unmerge_TEST.bash
+++ b/ebuild/utils/unmerge_TEST.bash
@@ -23,7 +23,7 @@ unmerge_empty_TEST()
"unmerge_TEST_dir/empty_contents" 1>/dev/null
test_return_code
- ${PALUDIS_EBUILD_DIR}/utils/unmerge "unmerge_TEST_dir/empty_dst" \
+ ${TOP_BUILD_DIR}/ebuild/utils/unmerge "unmerge_TEST_dir/empty_dst" \
"unmerge_TEST_dir/empty_contents" 1>/dev/null
test_return_code
@@ -51,7 +51,7 @@ unmerge_files_TEST()
done
test_equality "$ok" "yes"
- ${PALUDIS_EBUILD_DIR}/utils/unmerge "unmerge_TEST_dir/files_dst" \
+ ${TOP_BUILD_DIR}/ebuild/utils/unmerge "unmerge_TEST_dir/files_dst" \
"unmerge_TEST_dir/files_contents" 1>/dev/null
test_return_code