diff options
Diffstat (limited to '0.8.0/paludis/tasks')
-rw-r--r-- | 0.8.0/paludis/tasks/Makefile.am | 32 | ||||
-rw-r--r-- | 0.8.0/paludis/tasks/install_task.cc | 378 | ||||
-rw-r--r-- | 0.8.0/paludis/tasks/install_task.hh | 139 | ||||
-rw-r--r-- | 0.8.0/paludis/tasks/sync_task.cc | 104 | ||||
-rw-r--r-- | 0.8.0/paludis/tasks/sync_task.hh | 79 | ||||
-rw-r--r-- | 0.8.0/paludis/tasks/uninstall_task.cc | 206 | ||||
-rw-r--r-- | 0.8.0/paludis/tasks/uninstall_task.hh | 133 |
7 files changed, 1071 insertions, 0 deletions
diff --git a/0.8.0/paludis/tasks/Makefile.am b/0.8.0/paludis/tasks/Makefile.am new file mode 100644 index 000000000..07ce51b9c --- /dev/null +++ b/0.8.0/paludis/tasks/Makefile.am @@ -0,0 +1,32 @@ +CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda +MAINTAINERCLEANFILES = Makefile.in +AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@ @PALUDIS_CXXFLAGS_VISIBILITY@ +DEFS= \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DLIBEXECDIR=\"$(libexecdir)\" \ + -DDATADIR=\"$(datadir)\" +SUBDIRS = . + +TESTS = + +TESTS_ENVIRONMENT = env \ + PALUDIS_EBUILD_DIR="$(top_srcdir)/ebuild/" \ + PALUDIS_SKIP_CONFIG="yes" \ + TEST_SCRIPT_DIR="$(srcdir)/" \ + bash $(top_srcdir)/test/run_test.sh + +check_PROGRAMS = $(TESTS) +check_SCRIPTS = + +lib_LIBRARIES = libpaludistasks.a +paludis_tasks_includedir = $(includedir)/paludis/tasks +paludis_tasks_include_HEADERS = \ + install_task.hh \ + uninstall_task.hh \ + sync_task.hh + +libpaludistasks_a_SOURCES = $(paludis_tasks_include_HEADERS) \ + install_task.cc \ + uninstall_task.cc \ + sync_task.cc + diff --git a/0.8.0/paludis/tasks/install_task.cc b/0.8.0/paludis/tasks/install_task.cc new file mode 100644 index 000000000..f05e946dd --- /dev/null +++ b/0.8.0/paludis/tasks/install_task.cc @@ -0,0 +1,378 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 "install_task.hh" +#include <paludis/dep_atom.hh> +#include <paludis/portage_dep_parser.hh> +#include <paludis/util/collection_concrete.hh> +#include <list> + +using namespace paludis; + +namespace paludis +{ + template<> + struct Implementation<InstallTask> : + InternalCounted<Implementation<InstallTask> > + { + Environment * const env; + DepList dep_list; + DepList::Iterator current_dep_list_entry; + InstallOptions install_options; + + std::list<std::string> raw_targets; + AllDepAtom::Pointer targets; + + bool pretend; + bool preserve_world; + + bool had_set_targets; + bool had_package_targets; + + Implementation<InstallTask>(Environment * const e, const DepListOptions & o) : + env(e), + dep_list(e, o), + current_dep_list_entry(dep_list.begin()), + install_options(false, false), + targets(new AllDepAtom), + pretend(false), + preserve_world(false), + had_set_targets(false), + had_package_targets(false) + { + } + }; +} + +MultipleSetTargetsSpecified::MultipleSetTargetsSpecified() throw () : + Exception("More than one set target was specified") +{ +} + +HadBothPackageAndSetTargets::HadBothPackageAndSetTargets() throw () : + Exception("Both package and set targets were specified") +{ +} + +InstallTask::InstallTask(Environment * const env, const DepListOptions & options) : + PrivateImplementationPattern<InstallTask>(new Implementation<InstallTask>(env, options)) +{ +} + +InstallTask::~InstallTask() +{ +} + +void +InstallTask::add_target(const std::string & target) +{ + Context context("When adding install target '" + target + "':"); + + DepAtom::Pointer s(0); + + if ((target != "insecurity") && ((s = ((_imp->env->package_set(target)))))) + { + if (_imp->had_set_targets) + throw MultipleSetTargetsSpecified(); + + if (_imp->had_package_targets) + throw HadBothPackageAndSetTargets(); + + _imp->had_set_targets = true; + _imp->dep_list.options.target_type = dl_target_set; + _imp->targets->add_child(s); + } + else + { + if (_imp->had_set_targets) + throw HadBothPackageAndSetTargets(); + + _imp->had_package_targets = true; + _imp->dep_list.options.target_type = dl_target_package; + + if (std::string::npos != target.find('/')) + _imp->targets->add_child(PortageDepParser::parse(target)); + else + _imp->targets->add_child(DepAtom::Pointer(new PackageDepAtom( + _imp->env->package_database()->fetch_unique_qualified_package_name( + PackageNamePart(target))))); + } + + _imp->raw_targets.push_back(target); +} + +namespace +{ + struct WorldCallbacks : + public Environment::WorldCallbacks + { + InstallTask * const t; + + WorldCallbacks(InstallTask * const tt) : + t(tt) + { + } + + virtual void add_callback(const PackageDepAtom * a) + { + t->on_update_world(*a); + } + + virtual void skip_callback(const PackageDepAtom * a, + const std::string & s) + { + t->on_update_world_skip(*a, s); + } + }; +} + +void +InstallTask::execute() +{ + Context context("When executing install task:"); + + /* build up our dep list */ + on_build_deplist_pre(); + _imp->dep_list.add(_imp->targets); + on_build_deplist_post(); + + /* we're about to display our task list */ + if (_imp->pretend) + _imp->env->perform_hook(Hook("install_pretend_pre")("TARGETS", join(_imp->raw_targets.begin(), + _imp->raw_targets.end(), " "))); + + on_display_merge_list_pre(); + + /* display our task list */ + for (DepList::Iterator dep(_imp->dep_list.begin()), dep_end(_imp->dep_list.end()) ; + dep != dep_end ; ++dep) + { + _imp->current_dep_list_entry = dep; + on_display_merge_list_entry(*dep); + } + + /* we're done displaying our task list */ + on_display_merge_list_post(); + + if (_imp->pretend) + { + _imp->env->perform_hook(Hook("install_pretend_post")("TARGETS", join( + _imp->raw_targets.begin(), _imp->raw_targets.end(), " "))); + return; + } + + /* we're about to fetch / install the entire list */ + if (_imp->install_options.fetch_only) + { + _imp->env->perform_hook(Hook("fetch_all_pre")("TARGETS", join( + _imp->raw_targets.begin(), _imp->raw_targets.end(), " "))); + on_fetch_all_pre(); + } + else + { + _imp->env->perform_hook(Hook("install_all_pre")("TARGETS", join( + _imp->raw_targets.begin(), _imp->raw_targets.end(), " "))); + on_install_all_pre(); + } + + /* fetch / install our entire list */ + for (DepList::Iterator dep(_imp->dep_list.begin()), dep_end(_imp->dep_list.end()) ; + dep != dep_end ; ++dep) + { + if (dep->already_installed) + continue; + _imp->current_dep_list_entry = dep; + + std::string cpvr(stringify(dep->package.name) + "-" + + stringify(dep->package.version) + "::" + + stringify(dep->package.repository)); + + /* we're about to fetch / install one item */ + if (_imp->install_options.fetch_only) + { + _imp->env->perform_hook(Hook("fetch_pre")("TARGET", cpvr)); + on_fetch_pre(*dep); + } + else + { + _imp->env->perform_hook(Hook("install_pre")("TARGET", cpvr)); + on_install_pre(*dep); + } + + /* fetch / install one item */ + const RepositoryInstallableInterface * const installable_interface( + _imp->env->package_database()->fetch_repository(dep->package.repository)-> + installable_interface); + if (! installable_interface) + throw InternalError(PALUDIS_HERE, "Trying to install from a non-installable repository"); + + try + { + installable_interface->install(dep->package.name, dep->package.version, _imp->install_options); + } + catch (const PackageInstallActionError & e) + { + _imp->env->perform_hook(Hook("install_fail")("TARGET", cpvr)("MESSAGE", e.message())); + throw; + } + + /* we've fetched / installed one item */ + if (_imp->install_options.fetch_only) + { + on_fetch_post(*dep); + _imp->env->perform_hook(Hook("fetch_post")("TARGET", cpvr)); + } + else + { + on_install_post(*dep); + _imp->env->perform_hook(Hook("install_post")("TARGET", cpvr)); + } + + if (_imp->install_options.fetch_only) + continue; + + /* figure out whether we need to unmerge (clean) anything */ + on_build_cleanlist_pre(*dep); + + // manually invalidate any installed repos, they're probably + // wrong now + for (PackageDatabase::RepositoryIterator r(_imp->env->package_database()->begin_repositories()), + r_end(_imp->env->package_database()->end_repositories()) ; r != r_end ; ++r) + if ((*r)->installed_interface) + (*r)->invalidate(); + + // look for packages with the same name in the same slot + PackageDatabaseEntryCollection::Pointer collision_list(_imp->env->package_database()->query( + PackageDepAtom::Pointer(new PackageDepAtom( + stringify(dep->package.name) + ":" + + stringify(dep->metadata->slot))), + is_installed_only)); + + // don't clean the thing we just installed + PackageDatabaseEntryCollection::Concrete clean_list; + for (PackageDatabaseEntryCollection::Iterator c(collision_list->begin()), + c_end(collision_list->end()) ; c != c_end ; ++c) + if (dep->package.version != c->version) + clean_list.insert(*c); + + on_build_cleanlist_post(*dep); + + /* ok, we have the cleanlist. we're about to clean */ + _imp->env->perform_hook(Hook("uninstall_all_pre")("TARGETS", join( + clean_list.begin(), clean_list.end(), " "))); + on_clean_all_pre(*dep, clean_list); + + for (PackageDatabaseEntryCollection::Iterator c(clean_list.begin()), + c_end(clean_list.end()) ; c != c_end ; ++c) + { + /* clean one item */ + _imp->env->perform_hook(Hook("uninstall_pre")("TARGET", stringify(*c))); + on_clean_pre(*dep, *c); + + const RepositoryUninstallableInterface * const uninstall_interface( + _imp->env->package_database()->fetch_repository(c->repository)-> + uninstallable_interface); + if (! uninstall_interface) + throw InternalError(PALUDIS_HERE, "Trying to uninstall from a non-uninstallable repo"); + + try + { + uninstall_interface->uninstall(c->name, c->version, _imp->install_options); + } + catch (const PackageUninstallActionError & e) + { + _imp->env->perform_hook(Hook("uninstall_fail")("TARGET", stringify(*c))("MESSAGE", e.message())); + throw; + } + + on_clean_post(*dep, *c); + _imp->env->perform_hook(Hook("uninstall_post")("TARGET", stringify(*c))); + } + + /* we're done cleaning */ + _imp->env->perform_hook(Hook("uninstall_all_post")("TARGETS", join( + clean_list.begin(), clean_list.end(), " "))); + on_clean_all_post(*dep, clean_list); + } + + /* update world */ + if ((! _imp->had_set_targets) && (! _imp->install_options.fetch_only)) + { + if (! _imp->preserve_world) + { + on_update_world_pre(); + WorldCallbacks w(this); + _imp->env->add_appropriate_to_world(_imp->targets, &w); + on_update_world_post(); + } + else + on_preserve_world(); + } + + /* we've fetched / installed the entire list */ + if (_imp->install_options.fetch_only) + { + on_fetch_all_post(); + _imp->env->perform_hook(Hook("fetch_all_post")("TARGETS", join( + _imp->raw_targets.begin(), _imp->raw_targets.end(), " "))); + } + else + { + on_install_all_post(); + _imp->env->perform_hook(Hook("install_all_post")("TARGETS", join( + _imp->raw_targets.begin(), _imp->raw_targets.end(), " "))); + } +} + +const DepList & +InstallTask::dep_list() const +{ + return _imp->dep_list; +} + +DepList::Iterator +InstallTask::current_dep_list_entry() const +{ + return _imp->current_dep_list_entry; +} + +void +InstallTask::set_no_config_protect(const bool value) +{ + _imp->install_options.no_config_protect = value; +} + +void +InstallTask::set_fetch_only(const bool value) +{ + _imp->install_options.fetch_only = value; +} + +void +InstallTask::set_pretend(const bool value) +{ + _imp->pretend = value; +} + +void +InstallTask::set_preserve_world(const bool value) +{ + _imp->preserve_world = value; +} + diff --git a/0.8.0/paludis/tasks/install_task.hh b/0.8.0/paludis/tasks/install_task.hh new file mode 100644 index 000000000..34a4cd335 --- /dev/null +++ b/0.8.0/paludis/tasks/install_task.hh @@ -0,0 +1,139 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 + */ + +#ifndef PALUDIS_GUARD_PALUDIS_TASKS_INSTALL_TASK_HH +#define PALUDIS_GUARD_PALUDIS_TASKS_INSTALL_TASK_HH 1 + +#include <paludis/util/instantiation_policy.hh> +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/dep_list.hh> + +namespace paludis +{ + class Environment; + + class PALUDIS_VISIBLE MultipleSetTargetsSpecified : + public Exception + { + public: + MultipleSetTargetsSpecified() throw (); + }; + + class PALUDIS_VISIBLE HadBothPackageAndSetTargets : + public Exception + { + public: + HadBothPackageAndSetTargets() throw (); + }; + + class PALUDIS_VISIBLE InstallTask : + PrivateImplementationPattern<InstallTask>, + InstantiationPolicy<InstallTask, instantiation_method::NonCopyableTag> + { + protected: + ///\name Basic operations + ///\{ + + InstallTask(Environment * const env, const DepListOptions & options); + + ///\} + + public: + ///\name Basic operations + ///\{ + + virtual ~InstallTask(); + + ///\} + + ///\name DepList and Install behaviour options + ///\{ + + void set_no_config_protect(const bool value); + void set_fetch_only(const bool value); + void set_pretend(const bool value); + void set_preserve_world(const bool value); + + ///\} + + ///\name Add targets + ///\{ + + void add_target(const std::string &); + + ///\} + + ///\name Event callbacks + ///\{ + + virtual void on_build_deplist_pre() = 0; + virtual void on_build_deplist_post() = 0; + + virtual void on_build_cleanlist_pre(const DepListEntry &) = 0; + virtual void on_build_cleanlist_post(const DepListEntry &) = 0; + + virtual void on_display_merge_list_pre() = 0; + virtual void on_display_merge_list_post() = 0; + virtual void on_display_merge_list_entry(const DepListEntry &) = 0; + + virtual void on_fetch_all_pre() = 0; + virtual void on_fetch_pre(const DepListEntry &) = 0; + virtual void on_fetch_post(const DepListEntry &) = 0; + virtual void on_fetch_all_post() = 0; + + virtual void on_install_all_pre() = 0; + virtual void on_install_pre(const DepListEntry &) = 0; + virtual void on_install_post(const DepListEntry &) = 0; + virtual void on_install_all_post() = 0; + + virtual void on_clean_all_pre(const DepListEntry &, + const PackageDatabaseEntryCollection &) = 0; + virtual void on_clean_pre(const DepListEntry &, + const PackageDatabaseEntry &) = 0; + virtual void on_clean_post(const DepListEntry &, + const PackageDatabaseEntry &) = 0; + virtual void on_clean_all_post(const DepListEntry &, + const PackageDatabaseEntryCollection &) = 0; + + virtual void on_update_world_pre() = 0; + virtual void on_update_world(const PackageDepAtom &) = 0; + virtual void on_update_world_skip(const PackageDepAtom &, const std::string &) = 0; + virtual void on_update_world_post() = 0; + virtual void on_preserve_world() = 0; + + ///\} + + /** + * Run the task. + */ + void execute(); + + /** + * Fetch our deplist. + */ + const DepList & dep_list() const; + + /** + * Fetch our current deplist entry. + */ + DepList::Iterator current_dep_list_entry() const; + }; +} + +#endif diff --git a/0.8.0/paludis/tasks/sync_task.cc b/0.8.0/paludis/tasks/sync_task.cc new file mode 100644 index 000000000..f3f0a9586 --- /dev/null +++ b/0.8.0/paludis/tasks/sync_task.cc @@ -0,0 +1,104 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 "sync_task.hh" +#include <paludis/environment.hh> +#include <paludis/syncer.hh> +#include <list> + +using namespace paludis; + +namespace paludis +{ + template<> + struct Implementation<SyncTask> : + InternalCounted<Implementation<SyncTask> > + { + Environment * const env; + std::list<RepositoryName> targets; + + Implementation(Environment * const e) : + env(e) + { + } + }; +} + +SyncTask::SyncTask(Environment * const env) : + PrivateImplementationPattern<SyncTask>(new Implementation<SyncTask>(env)) +{ +} + +SyncTask::~SyncTask() +{ +} + +void +SyncTask::add_target(const std::string & t) +{ + Context context("When adding sync target '" + t + "':"); + _imp->targets.push_back(RepositoryName(t)); +} + +void +SyncTask::execute() +{ + Context context("When executing sync task:"); + + if (_imp->targets.empty()) + for (PackageDatabase::RepositoryIterator r(_imp->env->package_database()->begin_repositories()), + r_end(_imp->env->package_database()->end_repositories()) ; r != r_end ; ++r) + _imp->targets.push_back((*r)->name()); + + _imp->env->perform_hook(Hook("sync_all_pre")("TARGETS", join(_imp->targets.begin(), + _imp->targets.end(), " "))); + on_sync_all_pre(); + + for (std::list<RepositoryName>::const_iterator r(_imp->targets.begin()), r_end(_imp->targets.end()) ; + r != r_end ; ++r) + { + Context context_local("When syncing repository '" + stringify(*r) + "':"); + + _imp->env->perform_hook(Hook("sync_pre")("TARGET", stringify(*r))); + on_sync_pre(*r); + + try + { + Repository::ConstPointer rr(_imp->env->package_database()->fetch_repository(*r)); + + if (rr->syncable_interface && rr->syncable_interface->sync()) + on_sync_succeed(*r); + else + on_sync_skip(*r); + } + catch (const SyncFailedError & e) + { + _imp->env->perform_hook(Hook("sync_fail")("TARGET", stringify(*r))); + on_sync_fail(*r, e); + } + + on_sync_post(*r); + _imp->env->perform_hook(Hook("sync_post")("TARGET", stringify(*r))); + } + + on_sync_all_post(); + _imp->env->perform_hook(Hook("sync_all_post")("TARGETS", join(_imp->targets.begin(), + _imp->targets.end(), " "))); +} + diff --git a/0.8.0/paludis/tasks/sync_task.hh b/0.8.0/paludis/tasks/sync_task.hh new file mode 100644 index 000000000..baedfd76c --- /dev/null +++ b/0.8.0/paludis/tasks/sync_task.hh @@ -0,0 +1,79 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 + */ + +#ifndef PALUDIS_GUARD_PALUDIS_TASKS_SYNC_TASK_HH +#define PALUDIS_GUARD_PALUDIS_TASKS_SYNC_TASK_HH 1 + +#include <paludis/util/instantiation_policy.hh> +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/dep_list.hh> + +namespace paludis +{ + class Environment; + class SyncFailedError; + + class PALUDIS_VISIBLE SyncTask : + PrivateImplementationPattern<SyncTask>, + InstantiationPolicy<SyncTask, instantiation_method::NonCopyableTag> + { + protected: + ///\name Basic operations + ///\{ + + SyncTask(Environment * const env); + + ///\} + + public: + ///\name Basic operations + ///\{ + + virtual ~SyncTask(); + + ///\} + + ///\name Add targets + ///\{ + + void add_target(const std::string &); + + ///\} + + ///\name Event callbacks + ///\{ + + virtual void on_sync_all_pre() = 0; + virtual void on_sync_pre(const RepositoryName &) = 0; + virtual void on_sync_post(const RepositoryName &) = 0; + virtual void on_sync_skip(const RepositoryName &) = 0; + virtual void on_sync_fail(const RepositoryName &, const SyncFailedError &) = 0; + virtual void on_sync_succeed(const RepositoryName &) = 0; + virtual void on_sync_all_post() = 0; + + ///\} + + /** + * Run the task. + */ + void execute(); + }; +} + +#endif diff --git a/0.8.0/paludis/tasks/uninstall_task.cc b/0.8.0/paludis/tasks/uninstall_task.cc new file mode 100644 index 000000000..6770c75d9 --- /dev/null +++ b/0.8.0/paludis/tasks/uninstall_task.cc @@ -0,0 +1,206 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 "uninstall_task.hh" +#include <paludis/environment.hh> +#include <paludis/util/collection_concrete.hh> +#include <list> + +using namespace paludis; + +namespace paludis +{ + template<> + struct Implementation<UninstallTask> : + InternalCounted<Implementation<UninstallTask> > + { + Environment * const env; + InstallOptions install_options; + + std::list<std::string> raw_targets; + std::list<PackageDepAtom::Pointer> targets; + + bool pretend; + bool preserve_world; + + Implementation<UninstallTask>(Environment * const e) : + env(e), + install_options(false, false), + pretend(false), + preserve_world(false) + { + } + }; +} + +UninstallTask::UninstallTask(Environment * const e) : + PrivateImplementationPattern<UninstallTask>(new Implementation<UninstallTask>(e)) +{ +} + +UninstallTask::~UninstallTask() +{ +} + +void +UninstallTask::set_pretend(const bool v) +{ + _imp->pretend = v; +} + +void +UninstallTask::set_no_config_protect(const bool v) +{ + _imp->install_options.no_config_protect = v; +} + +void +UninstallTask::set_preserve_world(const bool v) +{ + _imp->preserve_world = v; +} + +void +UninstallTask::add_target(const std::string & target) +{ + Context context("When adding uninstall target '" + target + "':"); + + /* we might have a dep atom, but we might just have a simple package name + * without a category. either should work. */ + if (std::string::npos != target.find('/')) + _imp->targets.push_back(PackageDepAtom::Pointer(new PackageDepAtom(target))); + else + _imp->targets.push_back(PackageDepAtom::Pointer(new PackageDepAtom( + _imp->env->package_database()->fetch_unique_qualified_package_name( + PackageNamePart(target))))); + + _imp->raw_targets.push_back(target); +} + +namespace +{ + struct WorldCallbacks : + public Environment::WorldCallbacks + { + UninstallTask * const t; + + WorldCallbacks(UninstallTask * const tt) : + t(tt) + { + } + + virtual void remove_callback(const PackageDepAtom * a) + { + t->on_update_world(*a); + } + }; +} + +void +UninstallTask::execute() +{ + Context context("When executing install task:"); + + on_build_unmergelist_pre(); + + PackageDatabaseEntryCollection::Pointer unmerge(new PackageDatabaseEntryCollection::Concrete); + for (std::list<PackageDepAtom::Pointer>::const_iterator t(_imp->targets.begin()), + t_end(_imp->targets.end()) ; t != t_end ; ++t) + { + PackageDatabaseEntryCollection::ConstPointer r(_imp->env->package_database()->query( + *t, is_installed_only)); + if (r->empty()) + throw NoSuchPackageError(stringify(**t)); + else if (r->size() > 1) + throw AmbiguousUnmergeTargetError(stringify(**t), r); + else + unmerge->insert(*r->begin()); + } + + on_build_unmergelist_post(); + + on_display_unmerge_list_pre(); + + for (PackageDatabaseEntryCollection::Iterator i(unmerge->begin()), + i_end(unmerge->end()) ; i != i_end ; ++i) + on_display_unmerge_list_entry(*i); + + on_display_unmerge_list_post(); + + if (_imp->pretend) + return; + + if (_imp->preserve_world) + on_preserve_world(); + else + { + on_update_world_pre(); + + AllDepAtom::Pointer all(new AllDepAtom); + for (std::list<PackageDepAtom::Pointer>::const_iterator t(_imp->targets.begin()), + t_end(_imp->targets.end()) ; t != t_end ; ++t) + all->add_child(*t); + + WorldCallbacks w(this); + _imp->env->remove_appropriate_from_world(all, &w); + + on_update_world_post(); + } + + _imp->env->perform_hook(Hook("uninstall_all_pre")("TARGETS", join(unmerge->begin(), unmerge->end(), " "))); + on_uninstall_all_pre(); + + for (PackageDatabaseEntryCollection::Iterator i(unmerge->begin()), + i_end(unmerge->end()) ; i != i_end ; ++i) + { + std::string cpvr(stringify(i->name) + "-" + + stringify(i->version) + "::" + + stringify(i->repository)); + + _imp->env->perform_hook(Hook("uninstall_pre")("TARGET", cpvr)); + on_uninstall_pre(*i); + + const RepositoryUninstallableInterface * const uninstall_interface( + _imp->env->package_database()->fetch_repository(i->repository)-> + uninstallable_interface); + if (! uninstall_interface) + throw InternalError(PALUDIS_HERE, "Trying to uninstall from a non-uninstallable repo"); + + try + { + uninstall_interface->uninstall(i->name, i->version, _imp->install_options); + } + catch (const PackageUninstallActionError & e) + { + _imp->env->perform_hook(Hook("uninstall_fail")("TARGET", cpvr)("MESSAGE", e.message())); + throw; + } + + on_uninstall_post(*i); + _imp->env->perform_hook(Hook("uninstall_post")("TARGET", cpvr)); + } + + on_uninstall_all_post(); + _imp->env->perform_hook(Hook("uninstall_all_post")("TARGETS", join(unmerge->begin(), unmerge->end(), " "))); +} + +AmbiguousUnmergeTargetError::~AmbiguousUnmergeTargetError() throw () +{ +} + diff --git a/0.8.0/paludis/tasks/uninstall_task.hh b/0.8.0/paludis/tasks/uninstall_task.hh new file mode 100644 index 000000000..5820bcabd --- /dev/null +++ b/0.8.0/paludis/tasks/uninstall_task.hh @@ -0,0 +1,133 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 + */ + +#ifndef PALUDIS_GUARD_PALUDIS_TASKS_UNINSTALL_TASK_HH +#define PALUDIS_GUARD_PALUDIS_TASKS_UNINSTALL_TASK_HH 1 + +#include <paludis/dep_atom.hh> +#include <paludis/package_database_entry.hh> +#include <paludis/util/instantiation_policy.hh> +#include <paludis/util/private_implementation_pattern.hh> + +namespace paludis +{ + class Environment; + + class PALUDIS_VISIBLE AmbiguousUnmergeTargetError : + public Exception + { + private: + const std::string _t; + const PackageDatabaseEntryCollection::ConstPointer _p; + + public: + AmbiguousUnmergeTargetError(const std::string & our_target, + const PackageDatabaseEntryCollection::ConstPointer matches) throw () : + Exception("Ambiguous unmerge target '" + our_target + "'"), + _t(our_target), + _p(matches) + { + } + + ~AmbiguousUnmergeTargetError() throw (); + + typedef PackageDatabaseEntryCollection::Iterator Iterator; + + Iterator begin() const + { + return _p->begin(); + } + + Iterator end() const + { + return _p->end(); + } + + const std::string & target() const + { + return _t; + } + }; + + class PALUDIS_VISIBLE UninstallTask : + PrivateImplementationPattern<UninstallTask>, + InstantiationPolicy<UninstallTask, instantiation_method::NonCopyableTag> + { + protected: + ///\name Basic operations + ///\{ + + UninstallTask(Environment * const env); + + ///\} + + public: + ///\name Basic operations + ///\{ + + virtual ~UninstallTask(); + + ///\} + + ///\name Behaviour options + ///\{ + + void set_no_config_protect(const bool value); + void set_pretend(const bool value); + void set_preserve_world(const bool value); + + ///\} + + ///\name Add targets + ///\{ + + void add_target(const std::string &); + + ///\} + + ///\name Event callbacks + ///\{ + + virtual void on_build_unmergelist_pre() = 0; + virtual void on_build_unmergelist_post() = 0; + + virtual void on_display_unmerge_list_pre() = 0; + virtual void on_display_unmerge_list_post() = 0; + virtual void on_display_unmerge_list_entry(const PackageDatabaseEntry &) = 0; + + virtual void on_uninstall_all_pre() = 0; + virtual void on_uninstall_pre(const PackageDatabaseEntry &) = 0; + virtual void on_uninstall_post(const PackageDatabaseEntry &) = 0; + virtual void on_uninstall_all_post() = 0; + + virtual void on_update_world_pre() = 0; + virtual void on_update_world(const PackageDepAtom &) = 0; + virtual void on_update_world_post() = 0; + virtual void on_preserve_world() = 0; + + ///\} + + /** + * Run the task. + */ + void execute(); + }; +} + +#endif |