option processing:
authorMartin Vidner <mvidner@suse.cz>
Thu, 28 Sep 2006 20:10:10 +0000 (20:10 +0000)
committerMartin Vidner <mvidner@suse.cz>
Thu, 28 Sep 2006 20:10:10 +0000 (20:10 +0000)
- exit if bad option found
- fixed temporary-string-lifetime breakage
install, remove:
- switched from ResPool::setAdditionalFoo to
  PoolItem::status().setToBe[Un]installed, works now
- can specify resolvable type, not only package

tools/zmart/zmart-misc.cc
tools/zmart/zmart-misc.h
tools/zmart/zmart.cc
tools/zmart/zypper.cc

index 2ccf5e930dd114ebb00c0e80e85ff9e4ecdceb42..32d984d38a010889bf582396e85bbfa3decd515d 100644 (file)
@@ -1,9 +1,10 @@
 #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;
 
@@ -22,7 +23,7 @@ extern Settings gSettings;
 bool readBoolAnswer()
 {
   char c = 0;
-  int  count = 0;
+  //int  count = 0;
   while ( (c != 'y') && (c != 'Y') && (c != 'N') && (c != 'n') )
     cin >> c ;
       
@@ -32,27 +33,165 @@ bool readBoolAnswer()
     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()
index e34be7a372144d493ce4daaf0a287ca413e0a8bc..c36ede54482e5cc624b7f591661dfe882f21415f 100644 (file)
 
 #include <string>
 #include "zypp/Url.h"
+#include "zypp/ResObject.h"
 
 bool readBoolAnswer();
-void mark_package_for_install( const std::string &name );
-void mark_package_for_uninstall( const std::string &name );
+zypp::ResObject::Kind string_to_kind (const std::string &skind);
+void mark_for_install( const zypp::ResObject::Kind &kind,
+                      const std::string &name );
+void mark_for_uninstall( const zypp::ResObject::Kind &kind,
+                        const std::string &name );
 void show_summary();
 std::string calculate_token();
 void load_target();
index 1d63c380ba0ec8e5c40d089897618bac19a125fa..bd96abfc7ad3a3c3beec9ca76a183fc24a70b9ef 100644 (file)
@@ -239,7 +239,7 @@ int main(int argc, char **argv)
     
     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(zypp::ResTraits<zypp::Package>::kind, *it);
     }
     
     resolve();
index f60ac9a9224fcea54874b8b6545698ee6c3f9bbe..a701c5ede4cc1d5dfc24599b9a3c3aa433614e1c 100644 (file)
@@ -54,6 +54,7 @@ string longopts2optstring (const struct option *longopts) {
        optstring += "::";
     }
   }
+  //cerr << optstring << endl;
   return optstring;
 }
 
@@ -75,18 +76,19 @@ parsed_opts parse_options (int argc, char **argv,
   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 ':':
@@ -148,6 +150,8 @@ int main(int argc, char **argv)
   
   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
@@ -233,6 +237,26 @@ int main(int argc, char **argv)
       ;
 
   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[] = {
@@ -255,12 +279,15 @@ int main(int argc, char **argv)
       ;
   }
   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) {
@@ -413,14 +440,36 @@ int main(int argc, char **argv)
     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;
@@ -468,13 +517,13 @@ int main(int argc, char **argv)
          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;