* Unify the treatment of sources copied to the store, and recursive
SHA-256 outputs of fixed-output derivations.  I.e. they now produce
  the same store path:
  $ nix-store --add x
  /nix/store/j2fq9qxvvxgqymvpszhs773ncci45xsj-x
  $ nix-store --add-fixed --recursive sha256 x
  /nix/store/j2fq9qxvvxgqymvpszhs773ncci45xsj-x
  the latter being the same as the path that a derivation
    derivation {
      name = "x";
      outputHashAlgo = "sha256";
      outputHashMode = "recursive";
      outputHash = "...";
      ...
    };
  produces.
  This does change the output path for such fixed-output derivations.
  Fortunately they are quite rare.  The most common use is fetchsvn
  calls with SHA-256 hashes.  (There are a handful of those is
  Nixpkgs, mostly unstable development packages.)
  
* Documented the computation of store paths (in store-api.cc).
			
			
This commit is contained in:
		
							parent
							
								
									09bc0c502c
								
							
						
					
					
						commit
						64519cfd65
					
				
					 12 changed files with 191 additions and 79 deletions
				
			
		|  | @ -215,6 +215,14 @@ static Expr prim_trace(EvalState & state, const ATermVector & args) | ||||||
|  *************************************************************/ |  *************************************************************/ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | static bool isFixedOutput(const Derivation & drv) | ||||||
|  | { | ||||||
|  |     return drv.outputs.size() == 1 && | ||||||
|  |         drv.outputs.begin()->first == "out" && | ||||||
|  |         drv.outputs.begin()->second.hash != ""; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /* Returns the hash of a derivation modulo fixed-output
 | /* Returns the hash of a derivation modulo fixed-output
 | ||||||
|    subderivations.  A fixed-output derivation is a derivation with one |    subderivations.  A fixed-output derivation is a derivation with one | ||||||
|    output (`out') for which an expected hash and hash algorithm are |    output (`out') for which an expected hash and hash algorithm are | ||||||
|  | @ -227,28 +235,24 @@ static Expr prim_trace(EvalState & state, const ATermVector & args) | ||||||
|    function, we do not want to rebuild everything depending on it |    function, we do not want to rebuild everything depending on it | ||||||
|    (after all, (the hash of) the file being downloaded is unchanged). |    (after all, (the hash of) the file being downloaded is unchanged). | ||||||
|    So the *output paths* should not change.  On the other hand, the |    So the *output paths* should not change.  On the other hand, the | ||||||
|    *derivation store expression paths* should change to reflect the |    *derivation paths* should change to reflect the new dependency | ||||||
|    new dependency graph. |    graph. | ||||||
| 
 | 
 | ||||||
|    That's what this function does: it returns a hash which is just the |    That's what this function does: it returns a hash which is just the | ||||||
|    of the derivation ATerm, except that any input store expression |    hash of the derivation ATerm, except that any input derivation | ||||||
|    paths have been replaced by the result of a recursive call to this |    paths have been replaced by the result of a recursive call to this | ||||||
|    function, and that for fixed-output derivations we return |    function, and that for fixed-output derivations we return a hash of | ||||||
|    (basically) its outputHash. */ |    its output path. */ | ||||||
| static Hash hashDerivationModulo(EvalState & state, Derivation drv) | static Hash hashDerivationModulo(EvalState & state, Derivation drv) | ||||||
| { | { | ||||||
|     /* Return a fixed hash for fixed-output derivations. */ |     /* Return a fixed hash for fixed-output derivations. */ | ||||||
|     if (drv.outputs.size() == 1) { |     if (isFixedOutput(drv)) { | ||||||
|         DerivationOutputs::const_iterator i = drv.outputs.begin(); |         DerivationOutputs::const_iterator i = drv.outputs.begin(); | ||||||
|         if (i->first == "out" && |  | ||||||
|             i->second.hash != "") |  | ||||||
|         { |  | ||||||
|         return hashString(htSHA256, "fixed:out:" |         return hashString(htSHA256, "fixed:out:" | ||||||
|             + i->second.hashAlgo + ":" |             + i->second.hashAlgo + ":" | ||||||
|             + i->second.hash + ":" |             + i->second.hash + ":" | ||||||
|             + i->second.path); |             + i->second.path); | ||||||
|     } |     } | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /* For other derivations, replace the inputs paths with recursive
 |     /* For other derivations, replace the inputs paths with recursive
 | ||||||
|        calls to this function.*/ |        calls to this function.*/ | ||||||
|  | @ -304,8 +308,7 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) | ||||||
|      |      | ||||||
|     PathSet context; |     PathSet context; | ||||||
| 
 | 
 | ||||||
|     string outputHash; |     string outputHash, outputHashAlgo; | ||||||
|     string outputHashAlgo; |  | ||||||
|     bool outputHashRecursive = false; |     bool outputHashRecursive = false; | ||||||
| 
 | 
 | ||||||
|     for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i) { |     for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i) { | ||||||
|  | @ -380,6 +383,7 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) | ||||||
|         throw EvalError("required attribute `system' missing"); |         throw EvalError("required attribute `system' missing"); | ||||||
| 
 | 
 | ||||||
|     /* If an output hash was given, check it. */ |     /* If an output hash was given, check it. */ | ||||||
|  |     Path outPath; | ||||||
|     if (outputHash == "") |     if (outputHash == "") | ||||||
|         outputHashAlgo = ""; |         outputHashAlgo = ""; | ||||||
|     else { |     else { | ||||||
|  | @ -398,6 +402,7 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) | ||||||
|                 % outputHash % outputHashAlgo); |                 % outputHash % outputHashAlgo); | ||||||
|         string s = outputHash; |         string s = outputHash; | ||||||
|         outputHash = printHash(h); |         outputHash = printHash(h); | ||||||
|  |         outPath = makeFixedOutputPath(outputHashRecursive, outputHashAlgo, h, drvName); | ||||||
|         if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo; |         if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -413,13 +418,12 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) | ||||||
|        have an empty value.  This ensures that changes in the set of |        have an empty value.  This ensures that changes in the set of | ||||||
|        output names do get reflected in the hash. */ |        output names do get reflected in the hash. */ | ||||||
|     drv.env["out"] = ""; |     drv.env["out"] = ""; | ||||||
|     drv.outputs["out"] = |     drv.outputs["out"] = DerivationOutput("", outputHashAlgo, outputHash); | ||||||
|         DerivationOutput("", outputHashAlgo, outputHash); |  | ||||||
|          |          | ||||||
|     /* Use the masked derivation expression to compute the output
 |     /* Use the masked derivation expression to compute the output
 | ||||||
|        path. */ |        path. */ | ||||||
|     Path outPath = makeStorePath("output:out", |     if (outPath == "") | ||||||
|         hashDerivationModulo(state, drv), drvName); |         outPath = makeStorePath("output:out", hashDerivationModulo(state, drv), drvName); | ||||||
| 
 | 
 | ||||||
|     /* Construct the final derivation store expression. */ |     /* Construct the final derivation store expression. */ | ||||||
|     drv.env["out"] = outPath; |     drv.env["out"] = outPath; | ||||||
|  | @ -632,8 +636,8 @@ static Expr prim_filterSource(EvalState & state, const ATermVector & args) | ||||||
|     FilterFromExpr filter(state, args[0]); |     FilterFromExpr filter(state, args[0]); | ||||||
| 
 | 
 | ||||||
|     Path dstPath = readOnlyMode |     Path dstPath = readOnlyMode | ||||||
|         ? computeStorePathForPath(path, false, false, "", filter).first |         ? computeStorePathForPath(path, true, "sha256", filter).first | ||||||
|         : store->addToStore(path, false, false, "", filter); |         : store->addToStore(path, true, "sha256", filter); | ||||||
| 
 | 
 | ||||||
|     return makeStr(dstPath, singleton<PathSet>(dstPath)); |     return makeStr(dstPath, singleton<PathSet>(dstPath)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -670,14 +670,14 @@ void LocalStore::invalidatePath(const Path & path) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Path LocalStore::addToStore(const Path & _srcPath, bool fixed, | Path LocalStore::addToStore(const Path & _srcPath, | ||||||
|     bool recursive, string hashAlgo, PathFilter & filter) |     bool recursive, string hashAlgo, PathFilter & filter) | ||||||
| { | { | ||||||
|     Path srcPath(absPath(_srcPath)); |     Path srcPath(absPath(_srcPath)); | ||||||
|     debug(format("adding `%1%' to the store") % srcPath); |     debug(format("adding `%1%' to the store") % srcPath); | ||||||
| 
 | 
 | ||||||
|     std::pair<Path, Hash> pr = |     std::pair<Path, Hash> pr = | ||||||
|         computeStorePathForPath(srcPath, fixed, recursive, hashAlgo, filter); |         computeStorePathForPath(srcPath, recursive, hashAlgo, filter); | ||||||
|     Path & dstPath(pr.first); |     Path & dstPath(pr.first); | ||||||
|     Hash & h(pr.second); |     Hash & h(pr.second); | ||||||
| 
 | 
 | ||||||
|  | @ -696,10 +696,13 @@ Path LocalStore::addToStore(const Path & _srcPath, bool fixed, | ||||||
| 
 | 
 | ||||||
|             copyPath(srcPath, dstPath, filter); |             copyPath(srcPath, dstPath, filter); | ||||||
| 
 | 
 | ||||||
|  |             /* !!! */ | ||||||
|  | #if 0            
 | ||||||
|             Hash h2 = hashPath(htSHA256, dstPath, filter); |             Hash h2 = hashPath(htSHA256, dstPath, filter); | ||||||
|             if (h != h2) |             if (h != h2) | ||||||
|                 throw Error(format("contents of `%1%' changed while copying it to `%2%' (%3% -> %4%)") |                 throw Error(format("contents of `%1%' changed while copying it to `%2%' (%3% -> %4%)") | ||||||
|                     % srcPath % dstPath % printHash(h) % printHash(h2)); |                     % srcPath % dstPath % printHash(h) % printHash(h2)); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|             canonicalisePathMetaData(dstPath); |             canonicalisePathMetaData(dstPath); | ||||||
|              |              | ||||||
|  | @ -713,10 +716,10 @@ Path LocalStore::addToStore(const Path & _srcPath, bool fixed, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Path LocalStore::addTextToStore(const string & suffix, const string & s, | Path LocalStore::addTextToStore(const string & name, const string & s, | ||||||
|     const PathSet & references) |     const PathSet & references) | ||||||
| { | { | ||||||
|     Path dstPath = computeStorePathForText(suffix, s, references); |     Path dstPath = computeStorePathForText(name, s, references); | ||||||
|      |      | ||||||
|     addTempRoot(dstPath); |     addTempRoot(dstPath); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -89,11 +89,11 @@ public: | ||||||
|     bool querySubstitutablePathInfo(const Path & substituter, |     bool querySubstitutablePathInfo(const Path & substituter, | ||||||
|         const Path & path, SubstitutablePathInfo & info); |         const Path & path, SubstitutablePathInfo & info); | ||||||
|      |      | ||||||
|     Path addToStore(const Path & srcPath, bool fixed = false, |     Path addToStore(const Path & srcPath, | ||||||
|         bool recursive = false, string hashAlgo = "", |         bool recursive = true, string hashAlgo = "sha256", | ||||||
|         PathFilter & filter = defaultPathFilter); |         PathFilter & filter = defaultPathFilter); | ||||||
| 
 | 
 | ||||||
|     Path addTextToStore(const string & suffix, const string & s, |     Path addTextToStore(const string & name, const string & s, | ||||||
|         const PathSet & references); |         const PathSet & references); | ||||||
| 
 | 
 | ||||||
|     void exportPath(const Path & path, bool sign, |     void exportPath(const Path & path, bool sign, | ||||||
|  |  | ||||||
|  | @ -278,14 +278,15 @@ Path RemoteStore::queryDeriver(const Path & path) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Path RemoteStore::addToStore(const Path & _srcPath, bool fixed, | Path RemoteStore::addToStore(const Path & _srcPath, | ||||||
|     bool recursive, string hashAlgo, PathFilter & filter) |     bool recursive, string hashAlgo, PathFilter & filter) | ||||||
| { | { | ||||||
|     Path srcPath(absPath(_srcPath)); |     Path srcPath(absPath(_srcPath)); | ||||||
|      |      | ||||||
|     writeInt(wopAddToStore, to); |     writeInt(wopAddToStore, to); | ||||||
|     writeString(baseNameOf(srcPath), to); |     writeString(baseNameOf(srcPath), to); | ||||||
|     writeInt(fixed ? 1 : 0, to); |     /* backwards compatibility hack */ | ||||||
|  |     writeInt((hashAlgo == "sha256" && recursive) ? 0 : 1, to); | ||||||
|     writeInt(recursive ? 1 : 0, to); |     writeInt(recursive ? 1 : 0, to); | ||||||
|     writeString(hashAlgo, to); |     writeString(hashAlgo, to); | ||||||
|     dumpPath(srcPath, to, filter); |     dumpPath(srcPath, to, filter); | ||||||
|  | @ -294,11 +295,11 @@ Path RemoteStore::addToStore(const Path & _srcPath, bool fixed, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Path RemoteStore::addTextToStore(const string & suffix, const string & s, | Path RemoteStore::addTextToStore(const string & name, const string & s, | ||||||
|     const PathSet & references) |     const PathSet & references) | ||||||
| { | { | ||||||
|     writeInt(wopAddTextToStore, to); |     writeInt(wopAddTextToStore, to); | ||||||
|     writeString(suffix, to); |     writeString(name, to); | ||||||
|     writeString(s, to); |     writeString(s, to); | ||||||
|     writeStringSet(references, to); |     writeStringSet(references, to); | ||||||
|      |      | ||||||
|  |  | ||||||
|  | @ -42,11 +42,11 @@ public: | ||||||
|     bool querySubstitutablePathInfo(const Path & path, |     bool querySubstitutablePathInfo(const Path & path, | ||||||
|         SubstitutablePathInfo & info); |         SubstitutablePathInfo & info); | ||||||
|      |      | ||||||
|     Path addToStore(const Path & srcPath, bool fixed = false, |     Path addToStore(const Path & srcPath, | ||||||
|         bool recursive = false, string hashAlgo = "", |         bool recursive = true, string hashAlgo = "sha256", | ||||||
|         PathFilter & filter = defaultPathFilter); |         PathFilter & filter = defaultPathFilter); | ||||||
| 
 | 
 | ||||||
|     Path addTextToStore(const string & suffix, const string & s, |     Path addTextToStore(const string & name, const string & s, | ||||||
|         const PathSet & references); |         const PathSet & references); | ||||||
| 
 | 
 | ||||||
|     void exportPath(const Path & path, bool sign, |     void exportPath(const Path & path, bool sign, | ||||||
|  |  | ||||||
|  | @ -99,55 +99,112 @@ void checkStoreName(const string & name) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | /* Store paths have the following form:
 | ||||||
|  | 
 | ||||||
|  |    <store>/<h>-<name> | ||||||
|  | 
 | ||||||
|  |    where | ||||||
|  | 
 | ||||||
|  |    <store> = the location of the Nix store, usually /nix/store | ||||||
|  |     | ||||||
|  |    <name> = a human readable name for the path, typically obtained | ||||||
|  |      from the name attribute of the derivation, or the name of the | ||||||
|  |      source file from which the store path is created | ||||||
|  |       | ||||||
|  |    <h> = base-32 representation of the first 160 bits of a SHA-256 | ||||||
|  |      hash of <s>; the hash part of the store name | ||||||
|  |       | ||||||
|  |    <s> = the string "<type>:sha256:<h2>:<store>:<name>"; | ||||||
|  |      note that it includes the location of the store as well as the | ||||||
|  |      name to make sure that changes to either of those are reflected | ||||||
|  |      in the hash (e.g. you won't get /nix/store/<h>-name1 and | ||||||
|  |      /nix/store/<h>-name2 with equal hash parts). | ||||||
|  |       | ||||||
|  |    <type> = one of: | ||||||
|  |      "text:<r1>:<r2>:...<rN>" | ||||||
|  |        for plain text files written to the store using | ||||||
|  |        addTextToStore(); <r1> ... <rN> are the references of the | ||||||
|  |        path. | ||||||
|  |      "source" | ||||||
|  |        for paths copied to the store using addToStore() when recursive | ||||||
|  |        = true and hashAlgo = "sha256" | ||||||
|  |      "output:out" | ||||||
|  |        for either the outputs created by derivations, OR paths copied | ||||||
|  |        to the store using addToStore() with recursive != true or | ||||||
|  |        hashAlgo != "sha256" (in that case "source" is used; it's | ||||||
|  |        silly, but it's done that way for compatibility). | ||||||
|  | 
 | ||||||
|  |    <h2> = base-16 representation of a SHA-256 hash of: | ||||||
|  |      if <type> = "text:...": | ||||||
|  |        the string written to the resulting store path | ||||||
|  |      if <type> = "source": | ||||||
|  |        the serialisation of the path from which this store path is | ||||||
|  |        copied, as returned by hashPath() | ||||||
|  |      if <type> = "output:out": | ||||||
|  |        for non-fixed derivation outputs: | ||||||
|  |          the derivation (see hashDerivationModulo() in | ||||||
|  |          primops.cc) | ||||||
|  |        for paths copied by addToStore() or produced by fixed-output | ||||||
|  |        derivations: | ||||||
|  |          the string "fixed:out:<rec><algo>:<hash>:", where | ||||||
|  |            <rec> = "r:" for recursive (path) hashes, or "" or flat | ||||||
|  |              (file) hashes | ||||||
|  |            <algo> = "md5", "sha1" or "sha256" | ||||||
|  |            <hash> = base-16 representation of the path or flat hash of | ||||||
|  |              the contents of the path (or expected contents of the | ||||||
|  |              path for fixed-output derivations) | ||||||
|  | 
 | ||||||
|  |    It would have been nicer to handle fixed-output derivations under | ||||||
|  |    "source", e.g. have something like "source:<rec><algo>", but we're | ||||||
|  |    stuck with this for now... | ||||||
|  | 
 | ||||||
|  |    The main reason for this way of computing names is to prevent name | ||||||
|  |    collisions (for security).  For instance, it shouldn't be feasible | ||||||
|  |    to come up with a derivation whose output path collides with the | ||||||
|  |    path for a copied source.  The former would have a <s> starting with | ||||||
|  |    "output:out:", while the latter would have a <2> starting with | ||||||
|  |    "source:". | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| Path makeStorePath(const string & type, | Path makeStorePath(const string & type, | ||||||
|     const Hash & hash, const string & suffix) |     const Hash & hash, const string & name) | ||||||
| { | { | ||||||
|     /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */ |     /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */ | ||||||
|     string s = type + ":sha256:" + printHash(hash) + ":" |     string s = type + ":sha256:" + printHash(hash) + ":" | ||||||
|         + nixStore + ":" + suffix; |         + nixStore + ":" + name; | ||||||
| 
 | 
 | ||||||
|     checkStoreName(suffix); |     checkStoreName(name); | ||||||
| 
 | 
 | ||||||
|     return nixStore + "/" |     return nixStore + "/" | ||||||
|         + printHash32(compressHash(hashString(htSHA256, s), 20)) |         + printHash32(compressHash(hashString(htSHA256, s), 20)) | ||||||
|         + "-" + suffix; |         + "-" + name; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Path makeFixedOutputPath(bool recursive, | Path makeFixedOutputPath(bool recursive, | ||||||
|     string hashAlgo, Hash hash, string name) |     string hashAlgo, Hash hash, string name) | ||||||
| { | { | ||||||
|     /* !!! copy/paste from primops.cc */ |     return hashAlgo == "sha256" && recursive | ||||||
|     Hash h = hashString(htSHA256, "fixed:out:" |         ? makeStorePath("source", hash, name) | ||||||
|         + (recursive ? (string) "r:" : "") + hashAlgo + ":" |         : makeStorePath("output:out", hashString(htSHA256, | ||||||
|         + printHash(hash) + ":" |                 "fixed:out:" + (recursive ? (string) "r:" : "") + hashAlgo + ":" + printHash(hash) + ":"), | ||||||
|         + ""); |             name); | ||||||
|     return makeStorePath("output:out", h, name); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath, | std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath, | ||||||
|     bool fixed, bool recursive, string hashAlgo, PathFilter & filter) |     bool recursive, string hashAlgo, PathFilter & filter) | ||||||
| { | { | ||||||
|     Hash h = hashPath(htSHA256, srcPath, filter); |  | ||||||
| 
 |  | ||||||
|     string baseName = baseNameOf(srcPath); |  | ||||||
| 
 |  | ||||||
|     Path dstPath; |  | ||||||
|      |  | ||||||
|     if (fixed) { |  | ||||||
|     HashType ht(parseHashType(hashAlgo)); |     HashType ht(parseHashType(hashAlgo)); | ||||||
|         Hash h2 = recursive ? hashPath(ht, srcPath, filter) : hashFile(ht, srcPath); |     Hash h = recursive ? hashPath(ht, srcPath, filter) : hashFile(ht, srcPath); | ||||||
|         dstPath = makeFixedOutputPath(recursive, hashAlgo, h2, baseName); |     string name = baseNameOf(srcPath); | ||||||
|     } |     Path dstPath = makeFixedOutputPath(recursive, hashAlgo, h, name); | ||||||
|          |  | ||||||
|     else dstPath = makeStorePath("source", h, baseName); |  | ||||||
| 
 |  | ||||||
|     return std::pair<Path, Hash>(dstPath, h); |     return std::pair<Path, Hash>(dstPath, h); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Path computeStorePathForText(const string & suffix, const string & s, | Path computeStorePathForText(const string & name, const string & s, | ||||||
|     const PathSet & references) |     const PathSet & references) | ||||||
| { | { | ||||||
|     Hash hash = hashString(htSHA256, s); |     Hash hash = hashString(htSHA256, s); | ||||||
|  | @ -159,7 +216,7 @@ Path computeStorePathForText(const string & suffix, const string & s, | ||||||
|         type += ":"; |         type += ":"; | ||||||
|         type += *i; |         type += *i; | ||||||
|     } |     } | ||||||
|     return makeStorePath(type, hash, suffix); |     return makeStorePath(type, hash, name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -173,13 +173,13 @@ public: | ||||||
|        derivation is pre-loaded into the Nix store.  The function |        derivation is pre-loaded into the Nix store.  The function | ||||||
|        object `filter' can be used to exclude files (see |        object `filter' can be used to exclude files (see | ||||||
|        libutil/archive.hh). */ |        libutil/archive.hh). */ | ||||||
|     virtual Path addToStore(const Path & srcPath, bool fixed = false, |     virtual Path addToStore(const Path & srcPath, | ||||||
|         bool recursive = false, string hashAlgo = "", |         bool recursive = true, string hashAlgo = "sha256", | ||||||
|         PathFilter & filter = defaultPathFilter) = 0; |         PathFilter & filter = defaultPathFilter) = 0; | ||||||
| 
 | 
 | ||||||
|     /* Like addToStore, but the contents written to the output path is
 |     /* Like addToStore, but the contents written to the output path is
 | ||||||
|        a regular file containing the given string. */ |        a regular file containing the given string. */ | ||||||
|     virtual Path addTextToStore(const string & suffix, const string & s, |     virtual Path addTextToStore(const string & name, const string & s, | ||||||
|         const PathSet & references) = 0; |         const PathSet & references) = 0; | ||||||
| 
 | 
 | ||||||
|     /* Export a store path, that is, create a NAR dump of the store
 |     /* Export a store path, that is, create a NAR dump of the store
 | ||||||
|  | @ -274,7 +274,7 @@ Path followLinksToStorePath(const Path & path); | ||||||
| 
 | 
 | ||||||
| /* Constructs a unique store path name. */ | /* Constructs a unique store path name. */ | ||||||
| Path makeStorePath(const string & type, | Path makeStorePath(const string & type, | ||||||
|     const Hash & hash, const string & suffix); |     const Hash & hash, const string & name); | ||||||
|      |      | ||||||
| Path makeFixedOutputPath(bool recursive, | Path makeFixedOutputPath(bool recursive, | ||||||
|     string hashAlgo, Hash hash, string name); |     string hashAlgo, Hash hash, string name); | ||||||
|  | @ -285,7 +285,7 @@ Path makeFixedOutputPath(bool recursive, | ||||||
|    Returns the store path and the cryptographic hash of the |    Returns the store path and the cryptographic hash of the | ||||||
|    contents of srcPath. */ |    contents of srcPath. */ | ||||||
| std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath, | std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath, | ||||||
|     bool fixed = false, bool recursive = false, string hashAlgo = "", |     bool recursive = true, string hashAlgo = "sha256", | ||||||
|     PathFilter & filter = defaultPathFilter); |     PathFilter & filter = defaultPathFilter); | ||||||
| 
 | 
 | ||||||
| /* Preparatory part of addTextToStore().
 | /* Preparatory part of addTextToStore().
 | ||||||
|  | @ -302,7 +302,7 @@ std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath, | ||||||
|    simply yield a different store path, so other users wouldn't be |    simply yield a different store path, so other users wouldn't be | ||||||
|    affected), but it has some backwards compatibility issues (the |    affected), but it has some backwards compatibility issues (the | ||||||
|    hashing scheme changes), so I'm not doing that for now. */ |    hashing scheme changes), so I'm not doing that for now. */ | ||||||
| Path computeStorePathForText(const string & suffix, const string & s, | Path computeStorePathForText(const string & name, const string & s, | ||||||
|     const PathSet & references); |     const PathSet & references); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -129,7 +129,7 @@ static void opAddFixed(Strings opFlags, Strings opArgs) | ||||||
|     opArgs.pop_front(); |     opArgs.pop_front(); | ||||||
| 
 | 
 | ||||||
|     for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); ++i) |     for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); ++i) | ||||||
|         cout << format("%1%\n") % store->addToStore(*i, true, recursive, hashAlgo); |         cout << format("%1%\n") % store->addToStore(*i, recursive, hashAlgo); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -151,6 +151,9 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs) | ||||||
|         if (*i == "--recursive") recursive = true; |         if (*i == "--recursive") recursive = true; | ||||||
|         else throw UsageError(format("unknown flag `%1%'") % *i); |         else throw UsageError(format("unknown flag `%1%'") % *i); | ||||||
| 
 | 
 | ||||||
|  |     if (opArgs.size() != 3) | ||||||
|  |         throw UsageError(format("`--print-fixed-path' requires three arguments")); | ||||||
|  |      | ||||||
|     Strings::iterator i = opArgs.begin(); |     Strings::iterator i = opArgs.begin(); | ||||||
|     string hashAlgo = *i++; |     string hashAlgo = *i++; | ||||||
|     string hash = *i++; |     string hash = *i++; | ||||||
|  |  | ||||||
|  | @ -290,7 +290,7 @@ static void performOp(unsigned int clientVersion, | ||||||
|     case wopAddToStore: { |     case wopAddToStore: { | ||||||
|         /* !!! uberquick hack */ |         /* !!! uberquick hack */ | ||||||
|         string baseName = readString(from); |         string baseName = readString(from); | ||||||
|         bool fixed = readInt(from) == 1; |         readInt(from); /* obsolete; was `fixed' flag */ | ||||||
|         bool recursive = readInt(from) == 1; |         bool recursive = readInt(from) == 1; | ||||||
|         string hashAlgo = readString(from); |         string hashAlgo = readString(from); | ||||||
|          |          | ||||||
|  | @ -300,7 +300,7 @@ static void performOp(unsigned int clientVersion, | ||||||
|         restorePath(tmp2, from); |         restorePath(tmp2, from); | ||||||
| 
 | 
 | ||||||
|         startWork(); |         startWork(); | ||||||
|         Path path = store->addToStore(tmp2, fixed, recursive, hashAlgo); |         Path path = store->addToStore(tmp2, recursive, hashAlgo); | ||||||
|         stopWork(); |         stopWork(); | ||||||
|          |          | ||||||
|         writeString(path, to); |         writeString(path, to); | ||||||
|  |  | ||||||
							
								
								
									
										27
									
								
								tests/add.sh
									
										
									
									
									
								
							
							
						
						
									
										27
									
								
								tests/add.sh
									
										
									
									
									
								
							|  | @ -1,13 +1,28 @@ | ||||||
| source common.sh | source common.sh | ||||||
| 
 | 
 | ||||||
| file=./add.sh | path1=$($nixstore --add ./dummy) | ||||||
|  | echo $path1 | ||||||
| 
 | 
 | ||||||
| path=$($nixstore --add $file) | path2=$($nixstore --add-fixed sha256 --recursive ./dummy) | ||||||
|  | echo $path2 | ||||||
| 
 | 
 | ||||||
| echo $path | if test "$path1" != "$path2"; then | ||||||
|  |     echo "nix-store --add and --add-fixed mismatch" | ||||||
|  |     exit 1 | ||||||
|  | fi     | ||||||
| 
 | 
 | ||||||
| hash=$($nixstore -q --hash $path) | path3=$($nixstore --add-fixed sha256 ./dummy) | ||||||
|  | echo $path3 | ||||||
|  | test "$path1" != "$path3" || exit 1 | ||||||
| 
 | 
 | ||||||
| echo $hash | path4=$($nixstore --add-fixed sha1 --recursive ./dummy) | ||||||
|  | echo $path4 | ||||||
|  | test "$path1" != "$path4" || exit 1 | ||||||
| 
 | 
 | ||||||
| test "$hash" = "sha256:$($nixhash --type sha256 --base32 $file)" | hash1=$($nixstore -q --hash $path1) | ||||||
|  | echo $hash1 | ||||||
|  | 
 | ||||||
|  | hash2=$($nixhash --type sha256 --base32 ./dummy) | ||||||
|  | echo $hash2 | ||||||
|  | 
 | ||||||
|  | test "$hash1" = "sha256:$hash2" | ||||||
|  |  | ||||||
|  | @ -20,7 +20,6 @@ rec { | ||||||
|     (f ./fixed.builder1.sh "flat" "sha1" "a0b65939670bc2c010f4d5d6a0b3e4e4590fb92b") |     (f ./fixed.builder1.sh "flat" "sha1" "a0b65939670bc2c010f4d5d6a0b3e4e4590fb92b") | ||||||
|     (f ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42") |     (f ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42") | ||||||
|     (f ./fixed.builder2.sh "recursive" "sha1" "vw46m23bizj4n8afrc0fj19wrp7mj3c0") |     (f ./fixed.builder2.sh "recursive" "sha1" "vw46m23bizj4n8afrc0fj19wrp7mj3c0") | ||||||
|     (f ./fixed.builder2.sh "recursive" "sha256" "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik") |  | ||||||
|   ]; |   ]; | ||||||
| 
 | 
 | ||||||
|   good2 = [ |   good2 = [ | ||||||
|  | @ -30,6 +29,9 @@ rec { | ||||||
|     (f ./fixed.builder2.sh "flat" "md5" "8ddd8be4b179a529afa5f2ffae4b9858") |     (f ./fixed.builder2.sh "flat" "md5" "8ddd8be4b179a529afa5f2ffae4b9858") | ||||||
|   ]; |   ]; | ||||||
| 
 | 
 | ||||||
|  |   sameAsAdd = | ||||||
|  |     f ./fixed.builder2.sh "recursive" "sha256" "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik"; | ||||||
|  | 
 | ||||||
|   bad = [ |   bad = [ | ||||||
|     (f ./fixed.builder1.sh "flat" "md5" "0ddd8be4b179a529afa5f2ffae4b9858") |     (f ./fixed.builder1.sh "flat" "md5" "0ddd8be4b179a529afa5f2ffae4b9858") | ||||||
|   ]; |   ]; | ||||||
|  |  | ||||||
|  | @ -34,3 +34,30 @@ clearStore | ||||||
| drvs=$($nixinstantiate fixed.nix -A parallelSame) | drvs=$($nixinstantiate fixed.nix -A parallelSame) | ||||||
| echo $drvs | echo $drvs | ||||||
| $nixstore -r $drvs -j2 | $nixstore -r $drvs -j2 | ||||||
|  | 
 | ||||||
|  | # Fixed-output derivations with a recursive SHA-256 hash should | ||||||
|  | # produce the same path as "nix-store --add". | ||||||
|  | echo 'testing sameAsAdd...' | ||||||
|  | drv=$($nixinstantiate fixed.nix -A sameAsAdd) | ||||||
|  | echo $drv | ||||||
|  | out=$($nixstore -r $drv) | ||||||
|  | echo $out | ||||||
|  | 
 | ||||||
|  | # This is what fixed.builder2 produces... | ||||||
|  | rm -rf $TEST_ROOT/fixed | ||||||
|  | mkdir $TEST_ROOT/fixed | ||||||
|  | mkdir $TEST_ROOT/fixed/bla | ||||||
|  | echo "Hello World!" > $TEST_ROOT/fixed/foo | ||||||
|  | ln -s foo $TEST_ROOT/fixed/bar | ||||||
|  | 
 | ||||||
|  | out2=$($nixstore --add $TEST_ROOT/fixed) | ||||||
|  | echo $out2 | ||||||
|  | test "$out" = "$out2" || exit 1 | ||||||
|  | 
 | ||||||
|  | out3=$($nixstore --add-fixed --recursive sha256 $TEST_ROOT/fixed) | ||||||
|  | echo $out3 | ||||||
|  | test "$out" = "$out3" || exit 1 | ||||||
|  | 
 | ||||||
|  | out4=$($nixstore --print-fixed-path --recursive sha256 "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik" fixed) | ||||||
|  | echo $out4 | ||||||
|  | test "$out" = "$out4" || exit 1 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue