See example_dep_label.cc for labels. See example_dep_spec.cc for specs.
/* vim: set sw=4 sts=4 et foldmethod=syntax : */ /** \file * * Example \ref example_dep_tree.cc "example_dep_tree.cc" . * * \ingroup g_dep_spec */ /** \example example_dep_tree.cc * * This example demonstrates how to handle dependency specs. It looks through * all installed packages, and picks out any package whose dependencies include * 'app-arch/unzip', or whose fetchable files includes any with a '.zip' * extension. * * See \ref example_dep_label.cc "example_dep_label.cc" for labels. * See \ref example_dep_spec.cc "example_dep_spec.cc" for specs. */ #include <paludis/paludis.hh> #include "example_command_line.hh" #include <iostream> #include <iomanip> #include <algorithm> #include <cstdlib> #include <list> #include <map> #include <set> using namespace paludis; using namespace examples; using std::cout; using std::endl; using std::setw; using std::left; /* We use this map to store accumulated results. The first item in the pair * is whether we see a dependency, the second whether we see an extension. */ typedef std::map<std::string, std::pair<bool, bool> > ResultsMap; namespace { /* This visitor handles collection of packages with interesting * dependencies. We use the ConstVisitor<>::VisitConstSequence helper mixin * for AllDepSpec and AnyDepSpec, rather than explicitly visiting all the * children manually. */ class DependenciesCollector : public ConstVisitor<DependencySpecTree>, public ConstVisitor<DependencySpecTree>::VisitConstSequence<DependenciesCollector, AllDepSpec>, public ConstVisitor<DependencySpecTree>::VisitConstSequence<DependenciesCollector, AnyDepSpec> { private: const std::tr1::shared_ptr<const Environment> _env; const std::tr1::shared_ptr<const PackageID> _id; ResultsMap & _results; std::set<SetName> _recursing_sets; public: DependenciesCollector( const std::tr1::shared_ptr<const Environment> & e, const std::tr1::shared_ptr<const PackageID> & i, ResultsMap & r) : _env(e), _id(i), _results(r) { } using ConstVisitor<DependencySpecTree>::VisitConstSequence<DependenciesCollector, AllDepSpec>::visit_sequence; using ConstVisitor<DependencySpecTree>::VisitConstSequence<DependenciesCollector, AnyDepSpec>::visit_sequence; void visit_sequence(const ConditionalDepSpec & u, DependencySpecTree::ConstSequenceIterator cur, DependencySpecTree::ConstSequenceIterator end) { /* Was this use flag enabled (or, if we're inverse, disabled) * when we built this package? */ if (u.condition_met()) std::for_each(cur, end, accept_visitor(*this)); } void visit_leaf(const PackageDepSpec & spec) { /* spec.package_ptr() may return a zero pointer if it's a * wildcarded dep. */ if (spec.package_ptr() && *spec.package_ptr() == QualifiedPackageName("app-arch/unzip")) _results[stringify(*_id)].first = true; } void visit_leaf(const NamedSetDepSpec & spec) { /* For named set specs, we visit the set. */ std::tr1::shared_ptr<const SetSpecTree::ConstItem> set(_env->set(spec.name())); /* First complication: we might have a name referring to a set * that doesn't exist. */ if (! set) { Log::get_instance()->message("example_set.unknown_set", ll_warning, lc_context) << "Unknown set '" << spec << "'"; return; } /* Second complication: we need to handle sets that contain * themselves. Although this shouldn't happen, user-defined * sets can be made to include themselves, possibly with * other sets inbetween (a includes b includes a). */ if (! _recursing_sets.insert(spec.name()).second) { Log::get_instance()->message("example_set.recursive_set", ll_warning, lc_context) << "Recursively defined set '" << spec << "'"; return; } /* Now that we have the set, we can handle it simply by * visiting it. */ set->accept(*this); _recursing_sets.erase(spec.name()); } void visit_leaf(const BlockDepSpec &) { /* Not interested */ } void visit_leaf(const DependencyLabelsDepSpec &) { /* Not interested */ } }; /* This visitor handles collection of packages with interesting * filenames. Again, we use the ConstVisitor<>::VisitConstSequence helper mixin * for AllDepSpec (AnyDepSpec is not allowed in a FetchableURISpecTree). */ class FileExtensionsCollector : public ConstVisitor<FetchableURISpecTree>, public ConstVisitor<FetchableURISpecTree>::VisitConstSequence<FileExtensionsCollector, AllDepSpec> { private: const std::tr1::shared_ptr<const Environment> _env; const std::tr1::shared_ptr<const PackageID> _id; ResultsMap & _results; public: FileExtensionsCollector( const std::tr1::shared_ptr<const Environment> & e, const std::tr1::shared_ptr<const PackageID> & i, ResultsMap & r) : _env(e), _id(i), _results(r) { } using ConstVisitor<FetchableURISpecTree>::VisitConstSequence<FileExtensionsCollector, AllDepSpec>::visit_sequence; void visit_sequence(const ConditionalDepSpec & u, FetchableURISpecTree::ConstSequenceIterator cur, FetchableURISpecTree::ConstSequenceIterator end) { /* Was the condition met when we built this package? */ if (u.condition_met()) std::for_each(cur, end, accept_visitor(*this)); } void visit_leaf(const FetchableURIDepSpec & spec) { /* We need to be careful not to assume that the filename has * an extension. */ std::string::size_type p(spec.filename().rfind('.')); if ((std::string::npos != p) && (".zip" == spec.filename().substr(p))) _results[stringify(*_id)].second = true; } void visit_leaf(const URILabelsDepSpec &) { /* Not interested */ } }; } int main(int argc, char * argv[]) { try { CommandLine::get_instance()->run(argc, argv, "example_dep_tree", "EXAMPLE_DEP_TREE_OPTIONS", "EXAMPLE_DEP_TREE_CMDLINE"); /* We start with an Environment, respecting the user's '--environment' choice. */ std::tr1::shared_ptr<Environment> env(EnvironmentFactory::get_instance()->create( CommandLine::get_instance()->a_environment.argument())); /* Fetch package IDs for all installed packages. */ std::tr1::shared_ptr<const PackageIDSequence> ids((*env)[selection::AllVersionsSorted( generator::All() | filter::SupportsAction<InstalledAction>())]); ResultsMap results; /* For each ID: */ for (PackageIDSet::ConstIterator i(ids->begin()), i_end(ids->end()) ; i != i_end ; ++i) { /* Ignore old-style virtuals. */ if ((*i)->virtual_for_key()) continue; /* Insert a default result for this ID */ results[stringify(**i)] = std::make_pair(false, false); /* Create a visitor that collects 'app-arch/unzip' dependencies. */ DependenciesCollector dependencies_collector(env, *i, results); /* IDs can potentially have four dependency-related keys. Each of * these keys may return a zero pointer. If it doesn't, visit its * value with our collector. */ if ((*i)->build_dependencies_key()) (*i)->build_dependencies_key()->value()->accept(dependencies_collector); if ((*i)->run_dependencies_key()) (*i)->run_dependencies_key()->value()->accept(dependencies_collector); if ((*i)->post_dependencies_key()) (*i)->post_dependencies_key()->value()->accept(dependencies_collector); if ((*i)->suggested_dependencies_key()) (*i)->suggested_dependencies_key()->value()->accept(dependencies_collector); /* Create a visitor that collects '.zip' file extenstions. */ FileExtensionsCollector extensions_collector(env, *i, results); /* Again, we check for a zero pointer and visit otherwise: */ if ((*i)->fetches_key()) (*i)->fetches_key()->value()->accept(extensions_collector); } /* Display our results */ cout << left << setw(60) << "Package" << "| " << left << setw(4) << "Dep" << "| " << "Ext" << endl; cout << std::string(60, '-') << "+" << std::string(5, '-') << "+" << std::string(5, '-') << endl; for (ResultsMap::const_iterator r(results.begin()), r_end(results.end()) ; r != r_end ; ++r) cout << left << setw(60) << r->first << "| " << left << setw(4) << (r->second.first ? "yes" : "no") << "| " << left << setw(4) << (r->second.second ? "yes" : "no") << endl; cout << endl; } catch (const Exception & e) { /* Paludis exceptions can provide a handy human-readable backtrace and * an explanation message. Where possible, these should be displayed. */ cout << endl; cout << "Unhandled exception:" << endl << " * " << e.backtrace("\n * ") << e.message() << " (" << e.what() << ")" << endl; return EXIT_FAILURE; } catch (const std::exception & e) { cout << endl; cout << "Unhandled exception:" << endl << " * " << e.what() << endl; return EXIT_FAILURE; } catch (...) { cout << endl; cout << "Unhandled exception:" << endl << " * Unknown exception type. Ouch..." << endl; return EXIT_FAILURE; } return EXIT_SUCCESS; }
1.5.5