example_dep_label.cc

This example demonstrates how to handle dependency labels. It produces a summary of distfiles for all installed packages, together with a notice of whether that distfile is fetch-restricted.

See example_dep_tree.cc for trees. See example_dep_spec.cc for specs.

/* vim: set sw=4 sts=4 et foldmethod=syntax : */

/** \file
 *
 * Example \ref example_dep_label.cc "example_dep_label.cc" .
 *
 * \ingroup g_dep_spec
 */

/** \example example_dep_label.cc
 *
 * This example demonstrates how to handle dependency labels. It produces a
 * summary of distfiles for all installed packages, together with a notice of
 * whether that distfile is fetch-restricted.
 *
 * See \ref example_dep_tree.cc "example_dep_tree.cc" for trees.
 * 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>

using namespace paludis;
using namespace examples;

using std::cout;
using std::endl;
using std::setw;
using std::left;

/* We store our results in a map from distfile name to whether it is fetch
 * restricted. */
typedef std::map<std::string, bool> ResultsMap;

namespace
{
    /* This visitor class is used to determine whether a label represents a
     * fetch restriction. */
    class IsLabelRestrictedVisitor
    {
        public:
            bool result;

            IsLabelRestrictedVisitor(const bool initial) :
                result(initial)
            {
            }

            void visit(const URIListedThenMirrorsLabel &)
            {
                result = false;
            }

            void visit(const URIListedOnlyLabel &)
            {
                result = false;
            }

            void visit(const URIMirrorsOnlyLabel &)
            {
                result = false;
            }

            void visit(const URIMirrorsThenListedLabel &)
            {
                result = false;
            }

            void visit(const URILocalMirrorsOnlyLabel &)
            {
                result = true;
            }

            void visit(const URIManualOnlyLabel &)
            {
                result = true;
            }
    };

    /* This visitor class collects src_uri entries and stores the result in
     * a provided map. Label statuses are handled by a stack. When we enter
     * a block (an AllDepSpec or a ConditionalDepSpec), we duplicate the top item
     * of the stack, since labels recurse into subblocks. When we encounter
     * a label, we replace the top item of the stack. */
    class DistfilesCollector
    {
        private:
            ResultsMap & _results;
            std::list<bool> _restricted;

        public:
            DistfilesCollector(ResultsMap & r, const bool initial) :
                _results(r)
            {
                _restricted.push_back(initial);
            }

            void visit(const FetchableURISpecTree::NodeType<AllDepSpec>::Type & node)
            {
                /* When we encounter an AllDepSpec, duplicate the top item of
                 * our restricted stack, and then recurse over all of its
                 * children, and then restore the stack. */
                _restricted.push_back(_restricted.back());
                std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
                _restricted.pop_back();
            }

            void visit(const FetchableURISpecTree::NodeType<ConditionalDepSpec>::Type & node)
            {
                /* Always recurse over a ConditionalDepSpec's children. In real world
                 * code, we would more likely check whether condition is met. */
                _restricted.push_back(_restricted.back());
                std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
                _restricted.pop_back();
            }

            void visit(const FetchableURISpecTree::NodeType<FetchableURIDepSpec>::Type & node)
            {
                /* When we encounter a FetchableURIDepSpec, store its distfile name.
                 * We handle 'a -> b' style specs by taking 'b' as the
                 * distfile name. */
                _results.insert(std::make_pair(node.spec()->filename(), _restricted.back()));
            }

            void visit(const FetchableURISpecTree::NodeType<URILabelsDepSpec>::Type & node)
            {
                /* Find out whether the label represents a fetch restriction.
                 * Change the top item of the stack as appropriate. Although
                 * a URILabelsDepSpec can contain multiple labels, only the last
                 * one is relevant. */
                IsLabelRestrictedVisitor v(_restricted.back());
                std::for_each(indirect_iterator(node.spec()->begin()), indirect_iterator(node.spec()->end()), accept_visitor(v));
                _restricted.back() = v.result;
            }
    };
}

int main(int argc, char * argv[])
{
    try
    {
        CommandLine::get_instance()->run(argc, argv,
                "example_dep_label", "EXAMPLE_DEP_LABEL_OPTIONS", "EXAMPLE_DEP_LABEL_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::AllVersionsUnsorted(
                    generator::All() | filter::SupportsAction<InstalledAction>())]);

        /* Store a map from distfile name to whether it is fetch restricted. */
        ResultsMap results;

        /* For each ID: */
        for (PackageIDSet::ConstIterator i(ids->begin()), i_end(ids->end()) ;
                i != i_end ; ++i)
        {
            /* If we don't have a fetches key, skip this package. All PackageID
             * _key() functions can potentially return zero pointers, so checking is
             * essential. */
            if (! (*i)->fetches_key())
                continue;

            /* We need to know whether the default label for this package's src_uri
             * is restricted. */
            IsLabelRestrictedVisitor is_initial_label_restricted(false);
            (*i)->fetches_key()->initial_label()->accept(is_initial_label_restricted);

            /* Create a visitor that will collect distfiles, and do the collecting. */
            DistfilesCollector collector(results, is_initial_label_restricted.result);
            (*i)->fetches_key()->value()->root()->accept(collector);
        }

        /* Display summary of results */
        cout << left << setw(59) << "Distfile Name" << "| " << "Fetch Restricted?" << endl;
        cout << std::string(59, '-') << "+" << std::string(18, '-') << endl;
        for (ResultsMap::const_iterator r(results.begin()), r_end(results.end()) ;
                r != r_end ; ++r)
            cout << left << setw(59) << r->first << "| " << (r->second ? "yes" : "no") << 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;
}



Generated on Mon Sep 21 10:36:07 2009 for paludis by  doxygen 1.5.4