LTP GCOV extension - code coverage report
Current view: directory - src/nix-store - main.cc
Test: app.info
Date: 2006-10-11 Instrumented lines: 355
Code covered: 94.1 % Executed lines: 334

       1                 : #include <iostream>
       2                 : #include <algorithm>
       3                 : 
       4                 : #include "globals.hh"
       5                 : #include "build.hh"
       6                 : #include "misc.hh"
       7                 : #include "gc.hh"
       8                 : #include "archive.hh"
       9                 : #include "shared.hh"
      10                 : #include "dotgraph.hh"
      11                 : #include "store.hh"
      12                 : #include "db.hh"
      13                 : #include "util.hh"
      14                 : #include "help.txt.hh"
      15                 : 
      16                 : 
      17                 : using namespace nix;
      18                 : using std::cin;
      19                 : using std::cout;
      20                 : 
      21                 : 
      22                 : typedef void (* Operation) (Strings opFlags, Strings opArgs);
      23                 : 
      24                 : 
      25                 : void printHelp()
      26               1 : {
      27               1 :     cout << string((char *) helpText, sizeof helpText);
      28                 : }
      29                 : 
      30                 : 
      31             336 : static Path gcRoot;
      32                 : static int rootNr = 0;
      33                 : static bool indirectRoot = false;
      34                 : 
      35                 : 
      36                 : static Path fixPath(Path path)
      37              78 : {
      38              78 :     SwitchToOriginalUser sw;
      39              78 :     path = absPath(path);
      40              79 :     while (!isInStore(path)) {
      41               1 :         if (!isLink(path)) break;
      42               1 :         string target = readLink(path);
      43               1 :         path = absPath(target, dirOf(path));
      44                 :     }
      45              78 :     return toStorePath(path);
      46                 : }
      47                 : 
      48                 : 
      49                 : /* Realisation the given path.  For a derivation that means build it;
      50                 :    for other paths it means ensure their validity. */
      51                 : static Path realisePath(const Path & path)
      52              38 : {
      53              38 :     if (isDerivation(path)) {
      54           42337 :         PathSet paths;
      55              37 :         paths.insert(path);
      56              37 :         buildDerivations(paths);
      57           62266 :         Path outPath = findOutput(derivationFromPath(path), "out");
      58                 :         
      59              36 :         if (gcRoot == "")
      60              35 :             printGCWarning();
      61                 :         else
      62               1 :             outPath = addPermRoot(outPath,
      63                 :                 makeRootName(gcRoot, rootNr),
      64                 :                 indirectRoot);
      65                 :         
      66              36 :         return outPath;
      67                 :     } else {
      68               1 :         ensurePath(path);
      69               1 :         return path;
      70                 :     }
      71                 : }
      72                 : 
      73                 : 
      74                 : /* Realise the given paths. */
      75                 : static void opRealise(Strings opFlags, Strings opArgs)
      76              22 : {
      77           18366 :     if (!opFlags.empty()) throw UsageError("unknown flag");
      78                 : 
      79              56 :     for (Strings::iterator i = opArgs.begin();
      80                 :          i != opArgs.end(); ++i)
      81              34 :         *i = fixPath(*i);
      82                 :             
      83              22 :     if (opArgs.size() > 1) {
      84               2 :         PathSet drvPaths;
      85              16 :         for (Strings::iterator i = opArgs.begin();
      86                 :              i != opArgs.end(); ++i)
      87              14 :             if (isDerivation(*i))
      88              14 :                 drvPaths.insert(*i);
      89               2 :         buildDerivations(drvPaths);
      90                 :     }
      91                 : 
      92              55 :     for (Strings::iterator i = opArgs.begin();
      93                 :          i != opArgs.end(); ++i)
      94              34 :         cout << format("%1%\n") % realisePath(*i);
      95                 : }
      96                 : 
      97                 : 
      98                 : /* Add files to the Nix store and print the resulting paths. */
      99                 : static void opAdd(Strings opFlags, Strings opArgs)
     100               1 : {
     101               1 :     if (!opFlags.empty()) throw UsageError("unknown flag");
     102                 : 
     103               2 :     for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); ++i)
     104               1 :         cout << format("%1%\n") % addToStore(*i);
     105                 : }
     106                 : 
     107                 : 
     108                 : /* Preload the output of a fixed-output derivation into the Nix
     109                 :    store. */
     110                 : static void opAddFixed(Strings opFlags, Strings opArgs)
     111              12 : {
     112              12 :     bool recursive = false;
     113                 :     
     114              12 :     for (Strings::iterator i = opFlags.begin();
     115                 :          i != opFlags.end(); ++i)
     116               0 :         if (*i == "--recursive") recursive = true;
     117               0 :         else throw UsageError(format("unknown flag `%1%'") % *i);
     118                 : 
     119              12 :     if (opArgs.empty())
     120               0 :         throw UsageError("first argument must be hash algorithm");
     121                 :     
     122              12 :     string hashAlgo = opArgs.front();
     123              12 :     opArgs.pop_front();
     124                 : 
     125              24 :     for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); ++i)
     126              12 :         cout << format("%1%\n") % addToStoreFixed(recursive, hashAlgo, *i);
     127                 : }
     128                 : 
     129                 : 
     130                 : /* Hack to support caching in `nix-prefetch-url'. */
     131                 : static void opPrintFixedPath(Strings opFlags, Strings opArgs)
     132              12 : {
     133              12 :     bool recursive = false;
     134                 :     
     135              12 :     for (Strings::iterator i = opFlags.begin();
     136                 :          i != opFlags.end(); ++i)
     137               0 :         if (*i == "--recursive") recursive = true;
     138               0 :         else throw UsageError(format("unknown flag `%1%'") % *i);
     139                 : 
     140              12 :     Strings::iterator i = opArgs.begin();
     141              12 :     string hashAlgo = *i++;
     142              12 :     string hash = *i++;
     143              12 :     string name = *i++;
     144                 : 
     145              12 :     HashType ht(parseHashType(hashAlgo));
     146                 :     Hash h = hash.size() == Hash(ht).hashSize * 2
     147                 :         ? parseHash(ht, hash)
     148              12 :         : parseHash32(ht, hash);
     149                 :     
     150              12 :     cout << format("%1%\n") %
     151                 :         makeFixedOutputPath(recursive, hashAlgo, h, name);
     152                 : }
     153                 : 
     154                 : 
     155                 : /* Place in `paths' the set of paths that are required to `realise'
     156                 :    the given store path, i.e., all paths necessary for valid
     157                 :    deployment of the path.  For a derivation, this is the union of
     158                 :    requisites of the inputs, plus the derivation; for other store
     159                 :    paths, it is the set of paths in the FS closure of the path.  If
     160                 :    `includeOutputs' is true, include the requisites of the output
     161                 :    paths of derivations as well.
     162                 : 
     163                 :    Note that this function can be used to implement three different
     164                 :    deployment policies:
     165                 : 
     166                 :    - Source deployment (when called on a derivation).
     167                 :    - Binary deployment (when called on an output path).
     168                 :    - Source/binary deployment (when called on a derivation with
     169                 :      `includeOutputs' set to true).
     170                 : */
     171                 : static void storePathRequisites(const Path & storePath,
     172                 :     bool includeOutputs, PathSet & paths)
     173               2 : {
     174               2 :     computeFSClosure(storePath, paths);
     175                 : 
     176               2 :     if (includeOutputs) {
     177               9 :         for (PathSet::iterator i = paths.begin();
     178                 :              i != paths.end(); ++i)
     179               8 :             if (isDerivation(*i)) {
     180               3 :                 Derivation drv = derivationFromPath(*i);
     181               6 :                 for (DerivationOutputs::iterator j = drv.outputs.begin();
     182                 :                      j != drv.outputs.end(); ++j)
     183               3 :                     if (isValidPath(j->second.path))
     184               3 :                         computeFSClosure(j->second.path, paths);
     185                 :             }
     186                 :     }
     187                 : }
     188                 : 
     189                 : 
     190                 : static Path maybeUseOutput(const Path & storePath, bool useOutput, bool forceRealise)
     191              15 : {
     192              15 :     if (forceRealise) realisePath(storePath);
     193              15 :     if (useOutput && isDerivation(storePath)) {
     194               1 :         Derivation drv = derivationFromPath(storePath);
     195               1 :         return findOutput(drv, "out");
     196                 :     }
     197              14 :     else return storePath;
     198                 : }
     199                 : 
     200                 : 
     201                 : static void printPathSet(const PathSet & paths)
     202              12 : {
     203              32 :     for (PathSet::iterator i = paths.begin(); 
     204                 :          i != paths.end(); ++i)
     205              20 :         cout << format("%s\n") % *i;
     206                 : }
     207                 : 
     208                 : 
     209                 : /* Some code to print a tree representation of a derivation dependency
     210                 :    graph.  Topological sorting is used to keep the tree relatively
     211                 :    flat. */
     212                 : 
     213             336 : const string treeConn = "+---";
     214             336 : const string treeLine = "|   ";
     215             336 : const string treeNull = "    ";
     216                 : 
     217                 : 
     218                 : static void dfsVisit(const PathSet & paths, const Path & path,
     219                 :     PathSet & visited, Paths & sorted)
     220               8 : {
     221               8 :     if (visited.find(path) != visited.end()) return;
     222               7 :     visited.insert(path);
     223                 :     
     224               7 :     PathSet closure;
     225               7 :     computeFSClosure(path, closure);
     226                 :     
     227              17 :     for (PathSet::iterator i = closure.begin();
     228                 :          i != closure.end(); ++i)
     229              10 :         if (*i != path && paths.find(*i) != paths.end())
     230               1 :             dfsVisit(paths, *i, visited, sorted);
     231                 : 
     232               7 :     sorted.push_front(path);
     233                 : }
     234                 : 
     235                 : 
     236                 : static Paths topoSort(const PathSet & paths)
     237               8 : {
     238               8 :     Paths sorted;
     239               8 :     PathSet visited;
     240              15 :     for (PathSet::const_iterator i = paths.begin(); i != paths.end(); ++i)
     241               7 :         dfsVisit(paths, *i, visited, sorted);
     242               8 :     return sorted;
     243                 : }
     244                 : 
     245                 : 
     246                 : static void printTree(const Path & path,
     247                 :     const string & firstPad, const string & tailPad, PathSet & done)
     248               9 : {
     249               9 :     if (done.find(path) != done.end()) {
     250               1 :         cout << format("%1%%2% [...]\n") % firstPad % path;
     251               1 :         return;
     252                 :     }
     253               8 :     done.insert(path);
     254                 : 
     255               8 :     cout << format("%1%%2%\n") % firstPad % path;
     256                 : 
     257               8 :     PathSet references;
     258               8 :     queryReferences(noTxn, path, references);
     259                 :     
     260                 : #if 0     
     261                 :     for (PathSet::iterator i = drv.inputSrcs.begin();
     262                 :          i != drv.inputSrcs.end(); ++i)
     263                 :         cout << format("%1%%2%\n") % (tailPad + treeConn) % *i;
     264                 : #endif    
     265                 : 
     266                 :     /* Topologically sort under the relation A < B iff A \in
     267                 :        closure(B).  That is, if derivation A is an (possibly indirect)
     268                 :        input of B, then A is printed first.  This has the effect of
     269                 :        flattening the tree, preventing deeply nested structures.  */
     270               8 :     Paths sorted = topoSort(references);
     271               8 :     reverse(sorted.begin(), sorted.end());
     272                 : 
     273              15 :     for (Paths::iterator i = sorted.begin(); i != sorted.end(); ++i) {
     274               7 :         Paths::iterator j = i; ++j;
     275               7 :         printTree(*i, tailPad + treeConn,
     276                 :             j == sorted.end() ? tailPad + treeNull : tailPad + treeLine,
     277                 :             done);
     278                 :     }
     279                 : }
     280                 : 
     281                 : 
     282                 : /* Perform various sorts of queries. */
     283                 : static void opQuery(Strings opFlags, Strings opArgs)
     284              41 : {
     285                 :     enum { qOutputs, qRequisites, qReferences, qReferrers
     286                 :          , qReferrersClosure, qDeriver, qBinding, qHash
     287              41 :          , qTree, qGraph } query = qOutputs;
     288              41 :     bool useOutput = false;
     289              41 :     bool includeOutputs = false;
     290              41 :     bool forceRealise = false;
     291              41 :     string bindingName;
     292                 : 
     293              79 :     for (Strings::iterator i = opFlags.begin();
     294                 :          i != opFlags.end(); ++i)
     295              38 :         if (*i == "--outputs") query = qOutputs;
     296              38 :         else if (*i == "--requisites" || *i == "-R") query = qRequisites;
     297              36 :         else if (*i == "--references") query = qReferences;
     298              27 :         else if (*i == "--referrers" || *i == "--referers") query = qReferrers;
     299              27 :         else if (*i == "--referrers-closure" || *i == "--referers-closure") query = qReferrersClosure;
     300              26 :         else if (*i == "--deriver" || *i == "-d") query = qDeriver;
     301              13 :         else if (*i == "--binding" || *i == "-b") {
     302               1 :             if (opArgs.size() == 0)
     303               0 :                 throw UsageError("expected binding name");
     304               1 :             bindingName = opArgs.front();
     305               1 :             opArgs.pop_front();
     306               1 :             query = qBinding;
     307                 :         }
     308              12 :         else if (*i == "--hash") query = qHash;
     309              11 :         else if (*i == "--tree") query = qTree;
     310               9 :         else if (*i == "--graph") query = qGraph;
     311               7 :         else if (*i == "--use-output" || *i == "-u") useOutput = true;
     312               5 :         else if (*i == "--force-realise" || *i == "-f") forceRealise = true;
     313               1 :         else if (*i == "--include-outputs") includeOutputs = true;
     314               0 :         else throw UsageError(format("unknown flag `%1%'") % *i);
     315                 : 
     316              41 :     switch (query) {
     317                 :         
     318                 :         case qOutputs: {
     319              20 :             for (Strings::iterator i = opArgs.begin();
     320                 :                  i != opArgs.end(); ++i)
     321                 :             {
     322              10 :                 *i = fixPath(*i);
     323              10 :                 if (forceRealise) realisePath(*i);
     324              10 :                 Derivation drv = derivationFromPath(*i);
     325              10 :                 cout << format("%1%\n") % findOutput(drv, "out");
     326                 :             }
     327              12 :             break;
     328                 :         }
     329                 : 
     330                 :         case qRequisites:
     331                 :         case qReferences:
     332                 :         case qReferrers:
     333                 :         case qReferrersClosure: {
     334              12 :             PathSet paths;
     335              24 :             for (Strings::iterator i = opArgs.begin();
     336                 :                  i != opArgs.end(); ++i)
     337                 :             {
     338              12 :                 Path path = maybeUseOutput(fixPath(*i), useOutput, forceRealise);
     339              12 :                 if (query == qRequisites)
     340               2 :                     storePathRequisites(path, includeOutputs, paths);
     341              10 :                 else if (query == qReferences) queryReferences(noTxn, path, paths);
     342               1 :                 else if (query == qReferrers) queryReferrers(noTxn, path,  paths);
     343               1 :                 else if (query == qReferrersClosure) computeFSClosure(path, paths, true);
     344                 :             }
     345              12 :             printPathSet(paths);
     346              12 :             break;
     347                 :         }
     348                 : 
     349                 :         case qDeriver:
     350              26 :             for (Strings::iterator i = opArgs.begin();
     351                 :                  i != opArgs.end(); ++i)
     352                 :             {
     353              13 :                 Path deriver = queryDeriver(noTxn, fixPath(*i));
     354              13 :                 cout << format("%1%\n") %
     355                 :                     (deriver == "" ? "unknown-deriver" : deriver);
     356                 :             }
     357               1 :             break;
     358                 : 
     359                 :         case qBinding:
     360               2 :             for (Strings::iterator i = opArgs.begin();
     361                 :                  i != opArgs.end(); ++i)
     362                 :             {
     363               1 :                 *i = fixPath(*i);
     364               1 :                 Derivation drv = derivationFromPath(*i);
     365               1 :                 StringPairs::iterator j = drv.env.find(bindingName);
     366               1 :                 if (j == drv.env.end())
     367               0 :                     throw Error(format("derivation `%1%' has no environment binding named `%2%'")
     368                 :                         % *i % bindingName);
     369               1 :                 cout << format("%1%\n") % j->second;
     370                 :             }
     371               1 :             break;
     372                 : 
     373                 :         case qHash:
     374               2 :             for (Strings::iterator i = opArgs.begin();
     375                 :                  i != opArgs.end(); ++i)
     376                 :             {
     377               1 :                 Path path = maybeUseOutput(fixPath(*i), useOutput, forceRealise);
     378               1 :                 Hash hash = queryPathHash(path);
     379               1 :                 assert(hash.type == htSHA256);
     380               1 :                 cout << format("sha256:%1%\n") % printHash32(hash);
     381                 :             }
     382               2 :             break;
     383                 : 
     384                 :         case qTree: {
     385               2 :             PathSet done;
     386               4 :             for (Strings::iterator i = opArgs.begin();
     387                 :                  i != opArgs.end(); ++i)
     388               2 :                 printTree(fixPath(*i), "", "", done);
     389               2 :             break;
     390                 :         }
     391                 :             
     392                 :         case qGraph: {
     393               2 :             PathSet roots;
     394               4 :             for (Strings::iterator i = opArgs.begin();
     395                 :                  i != opArgs.end(); ++i)
     396               2 :                 roots.insert(maybeUseOutput(fixPath(*i), useOutput, forceRealise));
     397               2 :             printDotGraph(roots);
     398               2 :             break;
     399                 :         }
     400                 : 
     401                 :         default:
     402               0 :             abort();
     403                 :     }
     404                 : }
     405                 : 
     406                 : 
     407                 : static void opRegisterSubstitutes(Strings opFlags, Strings opArgs)
     408               8 : {
     409               8 :     if (!opFlags.empty()) throw UsageError("unknown flag");
     410               8 :     if (!opArgs.empty()) throw UsageError("no arguments expected");
     411                 : 
     412               8 :     Transaction txn;
     413               8 :     createStoreTransaction(txn);
     414                 : 
     415              48 :     while (1) {
     416              48 :         Path srcPath;
     417            1356 :         Substitute sub;
     418              48 :         PathSet references;
     419              48 :         getline(cin, srcPath);
     420              48 :         if (cin.eof()) break;
     421              40 :         getline(cin, sub.deriver);
     422              40 :         getline(cin, sub.program);
     423              40 :         string s; int n;
     424              40 :         getline(cin, s);
     425              40 :         if (!string2Int(s, n)) throw Error("number expected");
     426              49 :         while (n--) {
     427               9 :             getline(cin, s);
     428               9 :             sub.args.push_back(s);
     429                 :         }
     430              40 :         getline(cin, s);
     431              40 :         if (!string2Int(s, n)) throw Error("number expected");
     432              68 :         while (n--) {
     433              28 :             getline(cin, s);
     434              28 :             references.insert(s);
     435                 :         }
     436              40 :         if (!cin || cin.eof()) throw Error("missing input");
     437              40 :         registerSubstitute(txn, srcPath, sub);
     438              40 :         setReferences(txn, srcPath, references);
     439                 :     }
     440                 : 
     441               8 :     txn.commit();
     442                 : }
     443                 : 
     444                 : 
     445                 : static void opClearSubstitutes(Strings opFlags, Strings opArgs)
     446               1 : {
     447               1 :     if (!opFlags.empty()) throw UsageError("unknown flag");
     448               1 :     if (!opArgs.empty())
     449               0 :         throw UsageError("no arguments expected");
     450                 : 
     451               1 :     clearSubstitutes();
     452                 : }
     453                 : 
     454                 : 
     455                 : static void opRegisterValidity(Strings opFlags, Strings opArgs)
     456               2 : {
     457               2 :     if (!opFlags.empty()) throw UsageError("unknown flag");
     458               2 :     if (!opArgs.empty()) throw UsageError("no arguments expected");
     459                 : 
     460             140 :     ValidPathInfos infos;
     461                 :     
     462            2503 :     while (1) {
     463           17919 :         ValidPathInfo info;
     464            2503 :         getline(cin, info.path);
     465            2503 :         if (cin.eof()) break;
     466            2501 :         getline(cin, info.deriver);
     467            2501 :         string s; int n;
     468            2501 :         getline(cin, s);
     469            2501 :         if (!string2Int(s, n)) throw Error("number expected");
     470            5001 :         while (n--) {
     471            2500 :             getline(cin, s);
     472            2500 :             info.references.insert(s);
     473                 :         }
     474            2501 :         if (!cin || cin.eof()) throw Error("missing input");
     475            2501 :         if (!isValidPath(info.path)) {
     476                 :             /* !!! races */
     477            2501 :             canonicalisePathMetaData(info.path);
     478            2501 :             info.hash = hashPath(htSHA256, info.path);
     479            2501 :             infos.push_back(info);
     480                 :         }
     481                 :     }
     482                 : 
     483               2 :     Transaction txn;
     484               2 :     createStoreTransaction(txn);
     485               2 :     registerValidPaths(txn, infos);
     486               2 :     txn.commit();
     487                 : }
     488                 : 
     489                 : 
     490                 : static void opCheckValidity(Strings opFlags, Strings opArgs)
     491              24 : {
     492              24 :     if (!opFlags.empty()) throw UsageError("unknown flag");
     493                 : 
     494              24 :     for (Strings::iterator i = opArgs.begin();
     495                 :          i != opArgs.end(); ++i)
     496              24 :         if (!isValidPath(*i))
     497              24 :             throw Error(format("path `%1%' is not valid") % *i);
     498                 : }
     499                 : 
     500                 : 
     501                 : struct PrintFreed 
     502                 : {
     503                 :     bool show, dryRun;
     504                 :     unsigned long long bytesFreed;
     505                 :     PrintFreed(bool show, bool dryRun)
     506              36 :         : show(show), dryRun(dryRun), bytesFreed(0) { }
     507                 :     ~PrintFreed() 
     508              36 :     {
     509              18 :         if (show)
     510              16 :             cout << format(
     511                 :                 (dryRun
     512                 :                     ? "%d bytes would be freed (%.2f MiB)\n"
     513                 :                     : "%d bytes freed (%.2f MiB)\n"))
     514                 :                 % bytesFreed % (bytesFreed / (1024.0 * 1024.0));
     515                 :     }
     516                 : };
     517                 : 
     518                 : 
     519                 : static void opGC(Strings opFlags, Strings opArgs)
     520              15 : {
     521              15 :     GCAction action = gcDeleteDead;
     522                 :     
     523                 :     /* Do what? */
     524              20 :     for (Strings::iterator i = opFlags.begin();
     525                 :          i != opFlags.end(); ++i)
     526               5 :         if (*i == "--print-roots") action = gcReturnRoots;
     527               4 :         else if (*i == "--print-live") action = gcReturnLive;
     528               3 :         else if (*i == "--print-dead") action = gcReturnDead;
     529               0 :         else if (*i == "--delete") action = gcDeleteDead;
     530               0 :         else throw UsageError(format("bad sub-operation `%1%' in GC") % *i);
     531                 : 
     532              15 :     PathSet result;
     533                 :     PrintFreed freed(action == gcDeleteDead || action == gcReturnDead,
     534              15 :         action == gcReturnDead);
     535              15 :     collectGarbage(action, PathSet(), false, result, freed.bytesFreed);
     536                 : 
     537              15 :     if (action != gcDeleteDead) {
     538             197 :         for (PathSet::iterator i = result.begin(); i != result.end(); ++i)
     539             192 :             cout << *i << std::endl;
     540                 :     }
     541                 : }
     542                 : 
     543                 : 
     544                 : /* Remove paths from the Nix store if possible (i.e., if they do not
     545                 :    have any remaining referrers and are not reachable from any GC
     546                 :    roots). */
     547                 : static void opDelete(Strings opFlags, Strings opArgs)
     548               3 : {
     549               3 :     bool ignoreLiveness = false;
     550                 :     
     551               3 :     for (Strings::iterator i = opFlags.begin();
     552                 :          i != opFlags.end(); ++i)
     553               0 :         if (*i == "--ignore-liveness") ignoreLiveness = true;
     554               0 :         else throw UsageError(format("unknown flag `%1%'") % *i);
     555                 : 
     556               3 :     PathSet pathsToDelete;
     557               6 :     for (Strings::iterator i = opArgs.begin();
     558                 :          i != opArgs.end(); ++i)
     559               3 :         pathsToDelete.insert(fixPath(*i));
     560                 :     
     561               3 :     PathSet dummy;
     562               3 :     PrintFreed freed(true, false);
     563               3 :     collectGarbage(gcDeleteSpecific, pathsToDelete, ignoreLiveness,
     564                 :         dummy, freed.bytesFreed);
     565                 : }
     566                 : 
     567                 : 
     568                 : /* A sink that writes dump output to stdout. */
     569                 : struct StdoutSink : DumpSink
     570                 : {
     571                 :     virtual void operator ()
     572                 :         (const unsigned char * data, unsigned int len)
     573             342 :     {
     574             342 :         writeFull(STDOUT_FILENO, data, len);
     575                 :     }
     576                 : };
     577                 : 
     578                 : 
     579                 : /* Dump a path as a Nix archive.  The archive is written to standard
     580                 :    output. */
     581                 : static void opDump(Strings opFlags, Strings opArgs)
     582               9 : {
     583               9 :     if (!opFlags.empty()) throw UsageError("unknown flag");
     584               9 :     if (opArgs.size() != 1) throw UsageError("only one argument allowed");
     585                 : 
     586            5257 :     StdoutSink sink;
     587               9 :     string path = *opArgs.begin();
     588               9 :     dumpPath(path, sink);
     589                 : }
     590                 : 
     591                 : 
     592                 : /* A source that read restore intput to stdin. */
     593                 : struct StdinSource : RestoreSource
     594                 : {
     595                 :     virtual void operator () (unsigned char * data, unsigned int len)
     596             636 :     {
     597             636 :         readFull(STDIN_FILENO, data, len);
     598                 :     }
     599                 : };
     600                 : 
     601                 : 
     602                 : /* Restore a value from a Nix archive.  The archive is read from
     603                 :    standard input. */
     604                 : static void opRestore(Strings opFlags, Strings opArgs)
     605              12 : {
     606              12 :     if (!opFlags.empty()) throw UsageError("unknown flag");
     607              12 :     if (opArgs.size() != 1) throw UsageError("only one argument allowed");
     608                 : 
     609             110 :     StdinSource source;
     610              12 :     restorePath(*opArgs.begin(), source);
     611                 : }
     612                 : 
     613                 : 
     614                 : /* Initialise the Nix databases. */
     615                 : static void opInit(Strings opFlags, Strings opArgs)
     616               4 : {
     617               4 :     if (!opFlags.empty()) throw UsageError("unknown flag");
     618               4 :     if (!opArgs.empty())
     619               0 :         throw UsageError("no arguments expected");
     620               4 :     initDB();
     621                 : }
     622                 : 
     623                 : 
     624                 : /* Verify the consistency of the Nix environment. */
     625                 : static void opVerify(Strings opFlags, Strings opArgs)
     626               1 : {
     627               1 :     if (!opArgs.empty())
     628               0 :         throw UsageError("no arguments expected");
     629                 : 
     630               1 :     bool checkContents = false;
     631                 :     
     632               1 :     for (Strings::iterator i = opFlags.begin();
     633                 :          i != opFlags.end(); ++i)
     634               0 :         if (*i == "--check-contents") checkContents = true;
     635               0 :         else throw UsageError(format("unknown flag `%1%'") % *i);
     636                 :     
     637               1 :     verifyStore(checkContents);
     638                 : }
     639                 : 
     640                 : 
     641                 : /* Scan the arguments; find the operation, set global flags, put all
     642                 :    other flags in a list, and put all other arguments in another
     643                 :    list. */
     644                 : void run(Strings args)
     645             167 : {
     646             167 :     Strings opFlags, opArgs;
     647             167 :     Operation op = 0;
     648                 : 
     649             564 :     for (Strings::iterator i = args.begin(); i != args.end(); ) {
     650             397 :         string arg = *i++;
     651                 : 
     652             397 :         Operation oldOp = op;
     653                 : 
     654             397 :         if (arg == "--realise" || arg == "-r")
     655              22 :             op = opRealise;
     656             375 :         else if (arg == "--add" || arg == "-A")
     657               1 :             op = opAdd;
     658             374 :         else if (arg == "--add-fixed")
     659              12 :             op = opAddFixed;
     660             362 :         else if (arg == "--print-fixed-path")
     661              12 :             op = opPrintFixedPath;
     662             350 :         else if (arg == "--delete")
     663               3 :             op = opDelete;
     664             347 :         else if (arg == "--query" || arg == "-q")
     665              41 :             op = opQuery;
     666             306 :         else if (arg == "--register-substitutes")
     667               8 :             op = opRegisterSubstitutes;
     668             298 :         else if (arg == "--clear-substitutes")
     669               1 :             op = opClearSubstitutes;
     670             297 :         else if (arg == "--register-validity")
     671               2 :             op = opRegisterValidity;
     672             295 :         else if (arg == "--check-validity")
     673              24 :             op = opCheckValidity;
     674             271 :         else if (arg == "--gc")
     675              15 :             op = opGC;
     676             256 :         else if (arg == "--dump")
     677               9 :             op = opDump;
     678             247 :         else if (arg == "--restore")
     679              12 :             op = opRestore;
     680             235 :         else if (arg == "--init")
     681               4 :             op = opInit;
     682             231 :         else if (arg == "--verify")
     683               1 :             op = opVerify;
     684             230 :         else if (arg == "--add-root") {
     685               1 :             if (i == args.end())
     686               0 :                 throw UsageError("`--add-root requires an argument");
     687               1 :             gcRoot = absPath(*i++);
     688                 :         }
     689             229 :         else if (arg == "--indirect")
     690               1 :             indirectRoot = true;
     691             228 :         else if (arg[0] == '-')
     692              43 :             opFlags.push_back(arg);
     693                 :         else
     694             185 :             opArgs.push_back(arg);
     695                 : 
     696             397 :         if (oldOp && oldOp != op)
     697               0 :             throw UsageError("only one operation may be specified");
     698                 :     }
     699                 : 
     700             167 :     if (!op) throw UsageError("no operation specified");
     701                 : 
     702             167 :     if (op != opDump && op != opRestore) /* !!! hack */
     703             146 :         openDB(op != opGC);
     704                 : 
     705             167 :     op(opFlags, opArgs);
     706                 : }
     707                 : 
     708                 : 
     709             336 : string programId = "nix-store";

Generated by: LTP GCOV extension version 1.1