#include <sstream>
-
+#include <boost/format.hpp>
#include "zmart.h"
#include "zmart-misc.h"
#include <zypp/Patch.h>
+#include <zypp/base/Algorithm.h>
using namespace zypp::detail;
bool readBoolAnswer()
{
char c = 0;
- int count = 0;
+ //int count = 0;
while ( (c != 'y') && (c != 'Y') && (c != 'N') && (c != 'n') )
cin >> c ;
return false;
}
-void mark_package_for_install( const std::string &name )
+// converts a user-supplied kind to a zypp kind object
+// returns an empty one if not recognized
+ResObject::Kind string_to_kind (const string &skind)
+{
+ ResObject::Kind empty;
+ string lskind = str::toLower (skind);
+ if (lskind == "package")
+ return ResTraits<Package>::kind;
+ if (lskind == "selection")
+ return ResTraits<Selection>::kind;
+ if (lskind == "pattern")
+ return ResTraits<Pattern>::kind;
+ if (lskind == "product")
+ return ResTraits<Product>::kind;
+ if (lskind == "patch")
+ return ResTraits<Patch>::kind;
+ if (lskind == "script")
+ return ResTraits<Script>::kind;
+ if (lskind == "message")
+ return ResTraits<Message>::kind;
+ if (lskind == "language")
+ return ResTraits<Language>::kind;
+ if (lskind == "atom")
+ return ResTraits<Atom>::kind;
+ if (lskind == "system")
+ return ResTraits<SystemResObject>::kind;
+ if (lskind == "srcpackage")
+ return ResTraits<SrcPackage>::kind;
+ // not recognized
+ return empty;
+}
+
+// copied from yast2-pkg-bindings:PkgModuleFunctions::DoProvideNameKind
+struct ProvideProcess
+{
+ PoolItem_Ref item;
+ ResStatus::TransactByValue whoWantsIt;
+ string version;
+ Arch _architecture;
+
+ ProvideProcess( Arch arch, const string &vers)
+ : whoWantsIt(zypp::ResStatus::USER)
+ , version(vers)
+ , _architecture( arch )
+ { }
+
+ bool operator()( const PoolItem& provider )
+ {
+ cerr_vv << "Considering " << provider << endl;
+ // 1. compatible arch
+ // 2. best arch
+ // 3. best edition
+
+ // check the version if it's specified
+ if (!version.empty() && version != provider->edition().asString()) {
+ cerr_vv << format ("Skipping version %s (requested: %s)")
+ % provider->edition().asString() % version << endl;
+ return true;
+ }
+
+ if (!provider.status().isInstalled()) {
+ // deselect the item if it's already selected,
+ // only one item should be selected
+ if (provider.status().isToBeInstalled()) {
+ cerr_vv << " Deselecting" << endl;
+ provider.status().resetTransact(whoWantsIt);
+ }
+
+ // regarding items which are installable only
+ if (!provider->arch().compatibleWith( _architecture )) {
+ cerr_vv << format ("provider %s has incompatible arch '%s'")
+ % provider->name() % provider->arch().asString() << endl;
+ }
+ else if (!item) {
+ cerr_vv << " First match" << endl;
+ item = provider;
+ }
+ else if (item->arch().compare( provider->arch() ) < 0) {
+ cerr_vv << " Better arch" << endl;
+ item = provider;
+ }
+ else if (item->edition().compare( provider->edition() ) < 0) {
+ cerr_vv << " Better edition" << endl;
+ item = provider;
+ }
+ }
+
+ return true;
+ }
+};
+
+
+// this does only resolvables with this _name_.
+// we could also act on _provides_
+// TODO edition, arch
+void mark_for_install( const ResObject::Kind &kind,
+ const std::string &name )
{
- // as documented in ResPool::setAdditionalFoo
- CapSet capset;
- capset.insert (CapFactory().parse( ResTraits<Package>::kind, name));
-
- // The user is setting this capablility
- ResPool::AdditionalCapSet aCapSet;
- aCapSet[ResStatus::USER] = capset;
- God->pool().setAdditionalRequire( aCapSet );
+ const ResPool &pool = God->pool();
+ // name and kind match:
+
+ ProvideProcess installer (God->architecture(), "" /*version*/);
+ cerr_vv << "Iterating over " << name << endl;
+ invokeOnEach( pool.byNameBegin( name ),
+ pool.byNameEnd( name ),
+ resfilter::ByKind( kind ),
+ zypp::functor::functorRef<bool,const zypp::PoolItem&> (installer)
+ );
+ cerr_vv << "... done" << endl;
+ if (!installer.item) {
+ cerr << "Not found" << endl;
+ return; //error?
+ }
+
+ bool result = installer.item.status().setToBeInstalled( zypp::ResStatus::USER );
+ if (!result) {
+ cerr << "Failed" << endl;
+ }
}
-void mark_package_for_uninstall( const std::string &name )
+struct DeleteProcess
{
- CapSet capset;
- capset.insert (CapFactory().parse( ResTraits<Package>::kind, name));
+ bool found;
+ DeleteProcess ()
+ : found(false)
+ { }
- // The user is setting this capablility
- ResPool::AdditionalCapSet aCapSet;
- aCapSet[ResStatus::USER] = capset;
- God->pool().setAdditionalConflict( aCapSet );
+ bool operator() ( const PoolItem& provider )
+ {
+ found = true;
+ cerr_vv << "Marking for deletion: " << provider << endl;
+ bool result = provider.status().setToBeUninstalled( zypp::ResStatus::USER );
+ if (!result) {
+ cerr << "Failed" << endl;
+ }
+ return true; // get all of them
+ }
+};
+
+// mark all matches
+void mark_for_uninstall( const ResObject::Kind &kind,
+ const std::string &name )
+{
+ const ResPool &pool = God->pool();
+ // name and kind match:
+
+ DeleteProcess deleter;
+ cerr_vv << "Iterating over " << name << endl;
+ invokeOnEach( pool.byNameBegin( name ),
+ pool.byNameEnd( name ),
+ functor::chain (resfilter::ByInstalled(),
+ resfilter::ByKind( kind )),
+ zypp::functor::functorRef<bool,const zypp::PoolItem&> (deleter)
+ );
+ cerr_vv << "... done" << endl;
+ if (!deleter.found) {
+ cerr << "Not found" << endl;
+ return; //error?
+ }
}
void show_summary()
optstring += "::";
}
}
+ //cerr << optstring << endl;
return optstring;
}
parsed_opts result;
opterr = 0; // we report errors on our own
int optc;
- const char *optstring = longopts2optstring (longopts).c_str ();
+ string optstring = longopts2optstring (longopts);
short2long_t short2long = make_short2long (longopts);
while (1) {
int option_index = 0;
- optc = getopt_long (argc, argv, optstring,
+ optc = getopt_long (argc, argv, optstring.c_str (),
longopts, &option_index);
if (optc == -1)
break; // options done
switch (optc) {
case '?':
+ result["_unknown"].push_back("");
cerr << "Unknown option " << argv[optind - 1] << endl;
break;
case ':':
bool help = false;
parsed_opts gopts = parse_options (argc, argv, global_options);
+ if (gopts.count("_unknown"))
+ return 1;
// Help is parsed by setting the help flag for a command, which may be empty
// $0 -h,--help
;
if (command == "install" || command == "in") {
+ static struct option install_options[] = {
+ {"catalog", required_argument, 0, 'c'},
+ {"type", required_argument, 0, 't'},
+ {0, 0, 0, 0}
+ };
+ specific_options = install_options;
+ specific_help = " Command options:\n"
+ "\t--catalog,-c\t\tOnly from this catalog (FIXME)\n"
+ "\t--type,-t\t\tType of resolvable (default: package)\n"
+ ;
+ }
+ else if (command == "remove" || command == "rm") {
+ static struct option remove_options[] = {
+ {"type", required_argument, 0, 't'},
+ {0, 0, 0, 0}
+ };
+ specific_options = remove_options;
+ specific_help = " Command options:\n"
+ "\t--type,-t\t\tType of resolvable (default: package)\n"
+ ;
}
else if (command == "service-add" || command == "sa") {
static struct option service_add_options[] = {
;
}
else {
+ cerr_vv << "No options declared for command " << command << endl;
// no options. or make this an exhaustive thing?
// cerr << "Unknown command" << endl;
// return 1;
}
parsed_opts copts = parse_options (argc, argv, specific_options);
+ if (copts.count("_unknown"))
+ return 1;
list<string> arguments;
if (optind < argc) {
return 0;
}
+ ResObject::Kind kind;
if (command == "install" || command == "in") {
+ if (help || arguments.size() < 1) {
+ cerr << "install [options] name...\n"
+ << specific_help
+ ;
+ return !help;
+ }
+
gData.packages_to_install = vector<string>(arguments.begin(), arguments.end());
}
if (command == "remove" || command == "rm") {
+ if (help || arguments.size() < 1) {
+ cerr << "remove [options] name...\n"
+ << specific_help
+ ;
+ return !help;
+ }
+
gData.packages_to_uninstall = vector<string>(arguments.begin(), arguments.end());
}
if (!gData.packages_to_install.empty() || !gData.packages_to_uninstall.empty()) {
+ string skind = copts.count("type")? copts["type"].front() : "package";
+ kind = string_to_kind (skind);
+ if (kind == ResObject::Kind ()) {
+ cerr << "Unknown resolvable type " << skind << endl;
+ return 1;
+ }
+
std::string previous_token;
SourceManager_Ptr manager;
cerr_v << "loading target" << endl;
load_target();
}
-
+
for ( vector<string>::const_iterator it = gData.packages_to_install.begin(); it != gData.packages_to_install.end(); ++it ) {
- mark_package_for_install(*it);
+ mark_for_install(kind, *it);
}
for ( vector<string>::const_iterator it = gData.packages_to_uninstall.begin(); it != gData.packages_to_uninstall.end(); ++it ) {
- mark_package_for_uninstall(*it);
+ mark_for_uninstall(kind, *it);
}
cerr_v << "resolving" << endl;