Add explicit return to main
[mspang/inapt.git] / inapt.cc
index 71af2d1..ff41649 100644 (file)
--- a/inapt.cc
+++ b/inapt.cc
@@ -18,7 +18,7 @@
 
 #include "inapt.h"
 #include "util.h"
-#include "acqprogress.h"
+#include "contrib/acqprogress.h"
 
 char *prog = NULL;
 
@@ -67,11 +67,8 @@ bool run_install(pkgCacheFile &cache) {
 
   bool Failed = false;
   for (pkgAcquire::ItemIterator i = Fetcher.ItemsBegin(); i != Fetcher.ItemsEnd(); i++) {
-     if ((*i)->Status != pkgAcquire::Item::StatDone || (*i)->Complete != true) {
-         fprintf(stderr,("Failed to fetch %s  %s\n"),(*i)->DescURI().c_str(),
-                 (*i)->ErrorText.c_str());
+     if ((*i)->Status != pkgAcquire::Item::StatDone || (*i)->Complete != true)
          Failed = true;
-     }
   }
 
   if (Failed)
@@ -105,9 +102,29 @@ static void usage() {
     exit(2);
 }
 
-static bool test_macro(const char *macro, std::set<std::string> *defines) {
-    return (*macro != '!' && defines->find(macro) != defines->end())
-            || (*macro == '!' && defines->find(macro + 1) == defines->end());
+static bool test_profile(const char *profile, std::set<std::string> *defines) {
+    return (*profile != '!' && defines->find(profile) != defines->end())
+            || (*profile == '!' && defines->find(profile + 1) == defines->end());
+}
+
+static bool test_anyprofile(std::string &profile, std::set<std::string> *defines) {
+    char *s = xstrdup(profile.c_str());
+    const char *c = strtok(s, "/");
+
+    if (test_profile(c, defines)) {
+        free(s);
+        return true;
+    }
+
+    while ((c = strtok(NULL, "/")) != NULL) {
+        if (test_profile(c, defines)) {
+            free(s);
+            return true;
+        }
+    }
+
+    free(s);
+    return false;
 }
 
 static pkgCache::PkgIterator eval_pkg(inapt_package *package, pkgCacheFile &cache) {
@@ -152,8 +169,7 @@ static pkgCache::PkgIterator eval_pkg(inapt_package *package, pkgCacheFile &cach
             std::vector<std::string>::iterator i = package->alternates.begin();
             std::string message = *(i++);
             while (i != package->alternates.end()) {
-                message.append(", ");
-                message.append(*(i++));
+                message.append(", ").append(*(i++));
             }
             _error->Error("%s:%d: No alternative available: %s", package->filename, package->linenum, message.c_str());
         }
@@ -162,10 +178,10 @@ static pkgCache::PkgIterator eval_pkg(inapt_package *package, pkgCacheFile &cach
     return pkg;
 }
 
-static bool test_macros(vector<std::string> *macros, std::set<std::string> *defines) {
+static bool test_profiles(vector<std::string> *profiles, std::set<std::string> *defines) {
     bool ok = true;
-    for (vector<std::string>::iterator j = macros->begin(); j < macros->end(); j++) {
-        if (!test_macro((*j).c_str(), defines)) {
+    for (vector<std::string>::iterator j = profiles->begin(); j < profiles->end(); j++) {
+        if (!test_anyprofile(*j, defines)) {
             ok = false;
             break;
         }
@@ -175,7 +191,7 @@ static bool test_macros(vector<std::string> *macros, std::set<std::string> *defi
 
 static void eval_action(inapt_action *action, std::set<std::string> *defines, std::vector<inapt_package *> *final_actions) {
     for (vector<inapt_package *>::iterator i = action->packages.begin(); i < action->packages.end(); i++) {
-        if (test_macros(&(*i)->predicates, defines))
+        if (test_profiles(&(*i)->predicates, defines))
             final_actions->push_back(*i);
     }
 }
@@ -185,11 +201,11 @@ static void eval_block(inapt_block *block, std::set<std::string> *defines, std::
         return;
 
     for (vector<inapt_action *>::iterator i = block->actions.begin(); i < block->actions.end(); i++)
-        if (test_macros(&(*i)->predicates, defines))
+        if (test_profiles(&(*i)->predicates, defines))
             eval_action(*i, defines, final_actions);
 
     for (vector<inapt_conditional *>::iterator i = block->children.begin(); i < block->children.end(); i++) {
-        if (test_macro((*i)->condition, defines))
+        if (test_profiles(&(*i)->predicates, defines))
             eval_block((*i)->then_block, defines, final_actions);
         else
             eval_block((*i)->else_block, defines, final_actions);
@@ -201,12 +217,12 @@ static void eval_profiles(inapt_block *block, std::set<std::string> *defines) {
         return;
 
     for (vector<inapt_profiles *>::iterator i = block->profiles.begin(); i < block->profiles.end(); i++)
-        if (test_macros(&(*i)->predicates, defines))
+        if (test_profiles(&(*i)->predicates, defines))
             for (vector<std::string>::iterator j = (*i)->profiles.begin(); j != (*i)->profiles.end(); j++)
                 defines->insert(*j);
 
     for (vector<inapt_conditional *>::iterator i = block->children.begin(); i < block->children.end(); i++) {
-        if (test_macro((*i)->condition, defines))
+        if (test_profiles(&(*i)->predicates, defines))
             eval_profiles((*i)->then_block, defines);
         else
             eval_profiles((*i)->else_block, defines);
@@ -235,14 +251,40 @@ static void dump_actions(pkgCacheFile &cache) {
     }
 }
 
+static bool sanity_check(std::vector<inapt_package *> *final_actions, pkgCacheFile &cache) {
+    bool okay = true;
+    std::map<std::string, inapt_package *> packages;
+
+    for (vector<inapt_package *>::iterator i = final_actions->begin(); i != final_actions->end(); i++) {
+        if (packages.find((*i)->pkg.Name()) != packages.end()) {
+            inapt_package *first = packages[(*i)->pkg.Name()];
+            inapt_package *current = *i;
+            _error->Error("Multiple directives for package %s at %s:%d and %s:%d",
+                    (*i)->pkg.Name(), first->filename, first->linenum, current->filename, current->linenum);
+            debug("foo %s", (*i)->pkg.Name());
+            okay = false;
+            continue;
+        }
+        packages[(*i)->pkg.Name()] = *i;
+    }
+
+    for (pkgCache::PkgIterator i = cache->PkgBegin(); !i.end(); i++) {
+        if (cache[i].Delete() && (i->Flags & pkgCache::Flag::Essential || i->Flags & pkgCache::Flag::Important)) {
+            _error->Error("Removing essential package %s", i.Name());
+            okay = false;
+        }
+    }
+
+    return okay;
+}
+
 static void show_breakage(pkgCacheFile &cache) {
-    fprintf(stderr, "fatal: Unable to solve dependencies\n");
-    fprintf(stderr, "The following packages are broken:");
+    std::string broken;
     for (pkgCache::PkgIterator i = cache->PkgBegin(); !i.end(); i++)
         if (cache[i].NowBroken() || cache[i].InstBroken())
-            fprintf(stderr, " %s", i.Name());
-    fprintf(stderr, "\n");
-    exit(1);
+            broken.append(" ").append(i.Name());
+
+    _error->Error("Broken packages:%s", broken.c_str());
 }
 
 static void exec_actions(std::vector<inapt_package *> *final_actions) {
@@ -322,13 +364,18 @@ static void exec_actions(std::vector<inapt_package *> *final_actions) {
             fix.Protect((*i)->pkg);
         fix.Resolve();
 
-        if (cache->BrokenCount())
+        if (cache->BrokenCount()) {
             show_breakage(cache);
+            return;
+        }
     }
 
     cache->MarkAndSweep();
     run_autoremove(cache);
 
+    if (!sanity_check(final_actions, cache))
+        return;
+
     if (_config->FindB("Inapt::Simulate", false)) {
         pkgSimulate PM (cache);
         PM.DoInstall(-1);
@@ -375,8 +422,6 @@ static void set_option(char *opt) {
     std::string option (opt, eq - opt);
     std::string value (eq + 1);
 
-    debug("setting '%s'='%s'", option.c_str(), value.c_str());
-
     _config->Set(option, value);
 }
 
@@ -401,7 +446,7 @@ int main(int argc, char *argv[]) {
                 _config->Set("Inapt::Purge", true);
                 break;
             case 'd':
-                debug_enabled = true;
+                debug_level++;
                 break;
             case 'o':
                 set_option(optarg);
@@ -432,4 +477,6 @@ int main(int argc, char *argv[]) {
        _error->DumpErrors();
         exit(1);
     }
+
+    return 0;
 }