Allow alternates to be listed for packages
authorMichael Spang <mspang@csclub.uwaterloo.ca>
Sun, 13 Dec 2009 11:12:13 +0000 (06:12 -0500)
committerMichael Spang <mspang@csclub.uwaterloo.ca>
Tue, 22 Dec 2009 03:11:49 +0000 (22:11 -0500)
This allows graceful handling of renamed packages.

Signed-off-by: Michael Spang <mspang@csclub.uwaterloo.ca>
inapt.cc
inapt.h
parser.rl

index 8f1089a..f2edb46 100644 (file)
--- a/inapt.cc
+++ b/inapt.cc
@@ -188,6 +188,61 @@ static bool test_macro(const char *macro, set<string> *defines) {
             || (*macro == '!' && defines->find(macro + 1) == defines->end());
 }
 
             || (*macro == '!' && defines->find(macro + 1) == defines->end());
 }
 
+static pkgCache::PkgIterator eval_pkg(inapt_action *action, pkgCacheFile &cachef) {
+    pkgCache::PkgIterator pkg;
+
+    pkgCache *cache = cachef;
+
+    if (!pkg.end()) fatal("omg"); /* TODO */
+
+    for (std::vector<std::string>::iterator i = action->alternates.begin(); i != action->alternates.end(); i++) {
+        pkg = cache->FindPkg(*i);
+
+        /* no such package */
+        if (pkg.end())
+            continue;
+
+        /* real package */
+        if (cachef[pkg].CandidateVer)
+            break;
+
+        /* virtual package */
+        if (pkg->ProvidesList) {
+            if (!pkg.ProvidesList()->NextProvides) {
+                pkgCache::PkgIterator tmp = pkg.ProvidesList().OwnerPkg();
+                if (action->action == inapt_action::INSTALL) {
+                    debug("selecting %s instead of %s", tmp.Name(), pkg.Name());
+                    pkg = tmp;
+                    break;
+                } else {
+                    debug("will not remove %s instead of virtual package %s", tmp.Name(), pkg.Name());
+                }
+            } else {
+                debug("%s is a virtual package", pkg.Name());
+            }
+        } else {
+            debug("%s is a virtual packages with no provides", pkg.Name());
+        }
+    }
+
+    if (pkg.end()) {
+        /* todo: report all errors at the end */
+        if (action->alternates.size() == 1) {
+            fatal("%s:%d: No such package: %s", action->filename, action->linenum, action->alternates[0].c_str());
+        } else {
+            std::vector<std::string>::iterator i = action->alternates.begin();
+            std::string message = *(i++);
+            while (i != action->alternates.end()) {
+                message.append(", ");
+                message.append(*(i++));
+            }
+            fatal("%s:%d: No alternative available: %s", action->filename, action->linenum, message.c_str());
+        }
+    }
+
+    return pkg;
+}
+
 static void eval_block(inapt_block *block, set<string> *defines, std::vector<inapt_action *> *final_actions) {
     if (!block)
         return;
 static void eval_block(inapt_block *block, set<string> *defines, std::vector<inapt_action *> *final_actions) {
     if (!block)
         return;
@@ -230,36 +285,15 @@ static void exec_actions(std::vector<inapt_action *> *final_actions) {
     pkgCache *cache = cachef;
     pkgDepCache *DCache = cachef;
 
     pkgCache *cache = cachef;
     pkgDepCache *DCache = cachef;
 
-    for (vector<inapt_action *>::iterator i = final_actions->begin(); i < final_actions->end(); i++) {
-        pkgCache::PkgIterator pkg = cache->FindPkg((*i)->package);
-        if (pkg.end())
-            fatal("%s:%d: No such package: %s", (*i)->filename, (*i)->linenum, (*i)->package);
-        (*i)->pkg = pkg;
-        if (!cachef[pkg].CandidateVer) {
-            if (pkg->ProvidesList) {
-                if (!pkg.ProvidesList()->NextProvides) {
-                    pkgCache::PkgIterator tmp = pkg.ProvidesList().OwnerPkg();
-                    if ((*i)->action == inapt_action::INSTALL) {
-                        debug("selecting %s instead of %s", tmp.Name(), pkg.Name());
-                        (*i)->pkg = tmp;
-                    } else {
-                        debug("will not remove %s instead of virtual package %s", tmp.Name(), pkg.Name());
-                    }
-                } else {
-                    fatal("%s is a virtual package", pkg.Name());
-                }
-            } else {
-                fatal("%s is a virtual packages with no provides", pkg.Name());
-            }
-        }
-    }
+    for (vector<inapt_action *>::iterator i = final_actions->begin(); i < final_actions->end(); i++)
+        (*i)->pkg = eval_pkg(*i, cachef);
 
     for (vector<inapt_action *>::iterator i = final_actions->begin(); i < final_actions->end(); i++) {
         pkgCache::PkgIterator j = (*i)->pkg;
         switch ((*i)->action) {
             case inapt_action::INSTALL:
                 if (!j.CurrentVer() || cachef[j].Delete()) {
 
     for (vector<inapt_action *>::iterator i = final_actions->begin(); i < final_actions->end(); i++) {
         pkgCache::PkgIterator j = (*i)->pkg;
         switch ((*i)->action) {
             case inapt_action::INSTALL:
                 if (!j.CurrentVer() || cachef[j].Delete()) {
-                    printf("preinstall %s %s:%d\n", (*i)->package, (*i)->filename, (*i)->linenum);
+                    printf("preinstall %s %s:%d\n", (*i)->pkg.Name(), (*i)->filename, (*i)->linenum);
                     DCache->MarkInstall(j, true);
                 }
                 break;
                     DCache->MarkInstall(j, true);
                 }
                 break;
@@ -275,13 +309,13 @@ static void exec_actions(std::vector<inapt_action *> *final_actions) {
         switch ((*i)->action) {
             case inapt_action::INSTALL:
                 if ((!j.CurrentVer() && !cachef[j].Install()) || cachef[j].Delete()) {
         switch ((*i)->action) {
             case inapt_action::INSTALL:
                 if ((!j.CurrentVer() && !cachef[j].Install()) || cachef[j].Delete()) {
-                    printf("install %s %s:%d\n", (*i)->package, (*i)->filename, (*i)->linenum);
+                    printf("install %s %s:%d\n", (*i)->pkg.Name(), (*i)->filename, (*i)->linenum);
                     DCache->MarkInstall(j, false);
                 }
                 break;
             case inapt_action::REMOVE:
                 if ((j.CurrentVer() && !cachef[j].Delete()) || cachef[j].Install()) {
                     DCache->MarkInstall(j, false);
                 }
                 break;
             case inapt_action::REMOVE:
                 if ((j.CurrentVer() && !cachef[j].Delete()) || cachef[j].Install()) {
-                    printf("remove %s %s:%d\n", (*i)->package, (*i)->filename, (*i)->linenum);
+                    printf("remove %s %s:%d\n", (*i)->pkg.Name(), (*i)->filename, (*i)->linenum);
                     DCache->MarkDelete(j, false);
                 }
                 break;
                     DCache->MarkDelete(j, false);
                 }
                 break;
@@ -318,9 +352,7 @@ static void exec_actions(std::vector<inapt_action *> *final_actions) {
     pkgProblemResolver fix (DCache);
 
     for (vector<inapt_action *>::iterator i = final_actions->begin(); i < final_actions->end(); i++)
     pkgProblemResolver fix (DCache);
 
     for (vector<inapt_action *>::iterator i = final_actions->begin(); i < final_actions->end(); i++)
-           fix.Protect(cache->FindPkg((*i)->package));
-    for (vector<inapt_action *>::iterator i = final_actions->begin(); i < final_actions->end(); i++)
-           fix.Protect(cache->FindPkg((*i)->package));
+           fix.Protect((*i)->pkg);
     fix.Resolve();
 
     fprintf(stderr, "\n");
     fix.Resolve();
 
     fprintf(stderr, "\n");
diff --git a/inapt.h b/inapt.h
index 3604050..a1a2cd6 100644 (file)
--- a/inapt.h
+++ b/inapt.h
@@ -4,7 +4,7 @@
 struct inapt_conditional;
 
 struct inapt_action {
 struct inapt_conditional;
 
 struct inapt_action {
-    const char *package;
+    std::vector<std::string> alternates;
     enum action_t { INSTALL, REMOVE, UNSET } action;
     const char *filename;
     int linenum;
     enum action_t { INSTALL, REMOVE, UNSET } action;
     const char *filename;
     int linenum;
index 6c38e5b..f7a5243 100644 (file)
--- a/parser.rl
+++ b/parser.rl
@@ -19,9 +19,14 @@ using namespace std;
 
     action strstart { ts = p; }
 
 
     action strstart { ts = p; }
 
-    action add_list {
+    action add_alternate {
+        std::string tmp (ts, p - ts); ts = 0;
+        alternates.push_back(tmp);
+    }
+
+    action add_action {
         inapt_action *tmp_action = new inapt_action;
         inapt_action *tmp_action = new inapt_action;
-        tmp_action->package = xstrndup(ts, p - ts); ts = 0;
+        tmp_action->alternates.swap(alternates);
         tmp_action->action = curaction;
         tmp_action->linenum = curline;
         tmp_action->filename = curfile;
         tmp_action->action = curaction;
         tmp_action->linenum = curline;
         tmp_action->filename = curfile;
@@ -107,7 +112,8 @@ using namespace std;
     package_name = ((lower | digit) (lower | digit | '+' | '-' | '.')+) >strstart;
     pkg_predicate = '@' macro >strstart %pkg_predicate whitespace+;
     cmd_predicate = '@' macro >strstart %cmd_predicate whitespace+;
     package_name = ((lower | digit) (lower | digit | '+' | '-' | '.')+) >strstart;
     pkg_predicate = '@' macro >strstart %pkg_predicate whitespace+;
     cmd_predicate = '@' macro >strstart %cmd_predicate whitespace+;
-    package_list = ((whitespace+ pkg_predicate? package_name)+ %add_list whitespace*);
+    package_alternates = package_name >strstart %add_alternate ('/' package_name >strstart %add_alternate)*;
+    package_list = ((whitespace+ pkg_predicate? package_alternates)+ %add_action whitespace*);
     cmd_install = ('install' @install package_list ';' @clear_cmd_predicate);
     cmd_remove = ('remove' @remove package_list ';' @clear_cmd_predicate);
     start_block = '{' @start_block;
     cmd_install = ('install' @install package_list ';' @clear_cmd_predicate);
     cmd_remove = ('remove' @remove package_list ';' @clear_cmd_predicate);
     start_block = '{' @start_block;
@@ -149,6 +155,7 @@ void parser(const char *filename, inapt_block *top_block)
 
     std::vector<inapt_block *> block_stack;
     std::vector<inapt_conditional *> conditional_stack;
 
     std::vector<inapt_block *> block_stack;
     std::vector<inapt_conditional *> conditional_stack;
+    std::vector<std::string> alternates;
     block_stack.push_back(top_block);
 
     int stack[MAXDEPTH];
     block_stack.push_back(top_block);
 
     int stack[MAXDEPTH];