Exheredludis/doc/api/cplusplus/examples/example_metadata_key.cc
2012-09-14 18:06:37 +01:00

323 lines
14 KiB
C++

/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/** \file
*
* Example \ref example_metadata_key.cc "example_metadata_key.cc" .
*
* \ingroup g_metadata_key
*/
/** \example example_metadata_key.cc
*
* This example demonstrates how to use MetadataKey. It displays all the
* metadata keys for a particular PackageID and all repositories.
*/
#include <paludis/paludis.hh>
#include <paludis/util/pretty_print.hh>
#include "example_command_line.hh"
#include <iostream>
#include <iomanip>
#include <set>
#include <cstdlib>
using namespace paludis;
using namespace examples;
using std::cout;
using std::endl;
using std::left;
using std::setw;
namespace
{
void show_key(const MetadataKey & key, const std::string & indent = "");
std::string stringify_string_pair(const std::pair<const std::string, std::string> & s)
{
if (s.first.empty())
return s.second;
else
return s.first + "=" + s.second;
}
/* We use this visitor to display extra information about a MetadataKey,
* depending upon its type. */
class MetadataKeyInformationVisitor
{
private:
/* Because of MetadataSectionKey, we can be called recursively. We add a level
* of indenting each time. */
std::string indent;
public:
MetadataKeyInformationVisitor(const std::string & i = "") :
indent(i)
{
}
void visit(const MetadataValueKey<std::string> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataValueKey<std::string>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.parse_value() << endl;
}
void visit(const MetadataValueKey<Slot> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataValueKey<SlotName>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.parse_value().raw_value() << endl;
}
void visit(const MetadataValueKey<long> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataValueKey<long>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.parse_value() << endl;
}
void visit(const MetadataValueKey<bool> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataValueKey<bool>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.parse_value() << endl;
}
void visit(const MetadataValueKey<FSPath> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataValueKey<FSPath>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.parse_value() << endl;
}
void visit(const MetadataValueKey<std::shared_ptr<const PackageID> > & key)
{
cout << indent << left << setw(30) << " Class:" << " " <<
"MetadataValueKey<std::shared_ptr<const PackageID> >" << endl;
cout << indent << left << setw(30) << " Value:" << " " << *key.parse_value() << endl;
}
void visit(const MetadataTimeKey & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataTimeKey" << endl;
cout << indent << left << setw(30) << " Value:" << " " << pretty_print_time(key.parse_value().seconds()) << endl;
}
void visit(const MetadataValueKey<std::shared_ptr<const Choices> > &)
{
cout << indent << left << setw(30) << " Class:" << " " <<
"MetadataValueKey<std::shared_ptr<const Choices> > " << endl;
/* We won't display the contents of the choices key here, since
* it has its own examples. */
}
void visit(const MetadataSpecTreeKey<PlainTextSpecTree> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataSpecTreeKey<PlainTextSpecTree>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.pretty_print_value(UnformattedPrettyPrinter(), { }) << endl;
}
void visit(const MetadataSpecTreeKey<RequiredUseSpecTree> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataSpecTreeKey<RequiredUseSpecTree>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.pretty_print_value(UnformattedPrettyPrinter(), { }) << endl;
}
void visit(const MetadataSpecTreeKey<LicenseSpecTree> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataSpecTreeKey<LicenseSpecTree>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.pretty_print_value(UnformattedPrettyPrinter(), { }) << endl;
}
void visit(const MetadataSpecTreeKey<SimpleURISpecTree> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataSpecTreeKey<SimpleURISpecTree>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.pretty_print_value(UnformattedPrettyPrinter(), { }) << endl;
}
void visit(const MetadataSpecTreeKey<DependencySpecTree> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataSpecTreeKey<DependencySpecTree>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.pretty_print_value(UnformattedPrettyPrinter(), { }) << endl;
}
void visit(const MetadataSpecTreeKey<FetchableURISpecTree> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataSpecTreeKey<FetchableURISpecTree>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.pretty_print_value(UnformattedPrettyPrinter(), { }) << endl;
cout << indent << left << setw(30) << " Initial label:" << " " << key.initial_label()->text() << endl;
}
void visit(const MetadataCollectionKey<KeywordNameSet> & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataCollectionKey<KeywordNameSet>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << key.pretty_print_value(UnformattedPrettyPrinter(), { }) << endl;
}
void visit(const MetadataCollectionKey<Set<std::string> > & key)
{
auto value(key.parse_value());
cout << indent << left << setw(30) << " Class:" << " " << "MetadataCollectionKey<Set<std::string> >" << endl;
cout << indent << left << setw(30) << " Value:" << " " << join(value->begin(), value->end(), " ") << endl;
}
void visit(const MetadataCollectionKey<Map<std::string, std::string> > & key)
{
auto value(key.parse_value());
cout << indent << left << setw(30) << " Class:" << " " << "MetadataCollectionKey<Map<std::string, std::string> >" << endl;
cout << indent << left << setw(30) << " Value:" << " " << join(value->begin(), value->end(), " ", stringify_string_pair) << endl;
}
void visit(const MetadataCollectionKey<Sequence<std::string> > & key)
{
auto value(key.parse_value());
cout << indent << left << setw(30) << " Class:" << " " << "MetadataCollectionKey<Sequence<std::string> >" << endl;
cout << indent << left << setw(30) << " Value:" << " " << join(value->begin(), value->end(), " ") << endl;
}
void visit(const MetadataCollectionKey<Maintainers> & key)
{
auto value(key.parse_value());
cout << indent << left << setw(30) << " Class:" << " " << "MetadataCollectionKey<Maintainers>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << join(value->begin(), value->end(), " ") << endl;
}
void visit(const MetadataCollectionKey<FSPathSequence> & key)
{
auto value(key.parse_value());
cout << indent << left << setw(30) << " Class:" << " " << "MetadataCollectionKey<FSPathSequence>" << endl;
cout << indent << left << setw(30) << " Value:" << " " << join(value->begin(), value->end(), " ") << endl;
}
void visit(const MetadataCollectionKey<PackageIDSequence> & key)
{
auto value(key.parse_value());
cout << indent << left << setw(30) << " Class:" << " " << "MetadataCollectionKey<PackageIDSequence>" << endl;
/* Slight trickery: a PackageIDSequence stores shared pointers
* to PackageID instances, so we need indirect_iterator to get
* an extra level of dereferencing. */
cout << indent << left << setw(30) << " Value:" << " " << join(indirect_iterator(value->begin()),
indirect_iterator(value->end()), " ") << endl;
}
void visit(const MetadataSectionKey & key)
{
cout << indent << left << setw(30) << " Class:" << " " << "MetadataSectionKey" << endl;
cout << indent << left << setw(30) << " Keys:" << endl;
/* A MetadataSectionKey contains other keys. */
for (MetadataSectionKey::MetadataConstIterator k(key.begin_metadata()), k_end(key.end_metadata()) ;
k != k_end ; ++k)
{
show_key(**k, indent + " ");
cout << endl;
}
}
};
/* Display as much as we can about a key. */
void show_key(const MetadataKey & key, const std::string & indent)
{
/* All MetadataKey instances have a raw name, a human readable
* name and a type. The type is a hint to clients as to whether
* the key should be displayed when outputting the package (for
* example, 'paludis --query' shows mkt_significant keys first,
* then mkt_normal keys, and doesn't show mkt_dependencies
* without '--show-deps', mkt_author without '--show-author'
* or mkt_internal without '--show-metadata'. */
cout << indent << left << setw(30) << " Raw name:" << " " << key.raw_name() << endl;
cout << indent << left << setw(30) << " Human name:" << " " << key.human_name() << endl;
cout << indent << left << setw(30) << " Type:" << " " << key.type() << endl;
/* To get any more information out of a MetadataKey we have to
* use a visitor. This lets us write type-safe handling code for
* the appropriate MetadataKey subclass without the need for any
* runtime type information queries. */
MetadataKeyInformationVisitor v(indent);
key.accept(v);
}
}
int main(int argc, char * argv[])
{
int exit_status(0);
try
{
CommandLine::get_instance()->run(argc, argv,
"example_metadata_key", "EXAMPLE_METADATA_KEY_OPTIONS", "EXAMPLE_METADATA_KEY_CMDLINE");
/* We start with an Environment, respecting the user's '--environment' choice. */
std::shared_ptr<Environment> env(EnvironmentFactory::get_instance()->create(
CommandLine::get_instance()->a_environment.argument()));
/* Fetch package IDs for 'sys-apps/paludis'. */
std::shared_ptr<const PackageIDSequence> ids((*env)[selection::AllVersionsSorted(
generator::Package(QualifiedPackageName("sys-apps/paludis")))]);
/* For each ID: */
for (PackageIDSequence::ConstIterator i(ids->begin()), i_end(ids->end()) ;
i != i_end ; ++i)
{
cout << **i << ":" << endl;
/* For each metadata key: */
for (PackageID::MetadataConstIterator k((*i)->begin_metadata()), k_end((*i)->end_metadata()) ;
k != k_end ; ++k)
{
/* Display it. Note that PackageID::MetadataConstIterator returns a std::shared_ptr
* to a key, so we dereference twice (or we could have used IndirectIterator). */
show_key(**k);
cout << endl;
}
cout << endl;
}
/* And for each repository: */
for (auto r(env->begin_repositories()), r_end(env->end_repositories()) ;
r != r_end ; ++r)
{
cout << (*r)->name() << ":" << endl;
/* For each metadata key: */
for (Repository::MetadataConstIterator k((*r)->begin_metadata()), k_end((*r)->end_metadata()) ;
k != k_end ; ++k)
{
/* Display it. Repository::MetadataConstIterator also returns a
* std::shared_ptr to the key. */
show_key(**k);
cout << 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_status;
}