LTP GCOV extension - code coverage report
Current view: directory - src/nix-store - nix-store.cc
Test: app.info
Date: 2008-11-20 Instrumented lines: 416
Code covered: 78.1 % Executed lines: 325

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

Generated by: LTP GCOV extension version 1.6