* Reject a build if there is a cycle among the outputs. This is
necessary because existing code assumes that the references graph is acyclic.
This commit is contained in:
		
							parent
							
								
									254b3399ba
								
							
						
					
					
						commit
						b1004f40f7
					
				
					 4 changed files with 24 additions and 9 deletions
				
			
		|  | @ -278,10 +278,6 @@ public: | |||
| }; | ||||
| 
 | ||||
| 
 | ||||
| MakeError(SubstError, Error) | ||||
| MakeError(BuildError, Error) /* denotes a permanent build failure */ | ||||
| 
 | ||||
| 
 | ||||
| //////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -1982,7 +1978,8 @@ void DerivationGoal::computeClosure() | |||
|     } | ||||
| 
 | ||||
|     /* Register each output path as valid, and register the sets of
 | ||||
|        paths referenced by each of them. */ | ||||
|        paths referenced by each of them.  If there are cycles in the | ||||
|        outputs, this will fail. */ | ||||
|     ValidPathInfos infos; | ||||
|     foreach (DerivationOutputs::iterator, i, drv.outputs) { | ||||
|         ValidPathInfo info; | ||||
|  |  | |||
|  | @ -372,8 +372,13 @@ static void addAdditionalRoots(StoreAPI & store, PathSet & roots) | |||
| 
 | ||||
| 
 | ||||
| static void dfsVisit(StoreAPI & store, const PathSet & paths, | ||||
|     const Path & path, PathSet & visited, Paths & sorted) | ||||
|     const Path & path, PathSet & visited, Paths & sorted, | ||||
|     PathSet & parents) | ||||
| { | ||||
|     if (parents.find(path) != parents.end()) | ||||
|         throw BuildError(format("cycle detected in the references of `%1%'") % path); | ||||
|     parents.insert(path); | ||||
|      | ||||
|     if (visited.find(path) != visited.end()) return; | ||||
|     visited.insert(path); | ||||
|      | ||||
|  | @ -385,18 +390,19 @@ static void dfsVisit(StoreAPI & store, const PathSet & paths, | |||
|         /* Don't traverse into paths that don't exist.  That can
 | ||||
|            happen due to substitutes for non-existent paths. */ | ||||
|         if (*i != path && paths.find(*i) != paths.end()) | ||||
|             dfsVisit(store, paths, *i, visited, sorted); | ||||
|             dfsVisit(store, paths, *i, visited, sorted, parents); | ||||
| 
 | ||||
|     sorted.push_front(path); | ||||
|     parents.erase(path); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Paths topoSortPaths(StoreAPI & store, const PathSet & paths) | ||||
| { | ||||
|     Paths sorted; | ||||
|     PathSet visited; | ||||
|     PathSet visited, parents; | ||||
|     foreach (PathSet::const_iterator, i, paths) | ||||
|         dfsVisit(store, paths, *i, visited, sorted); | ||||
|         dfsVisit(store, paths, *i, visited, sorted, parents); | ||||
|     return sorted; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -966,12 +966,14 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos) | |||
|     while (1) { | ||||
|         try { | ||||
|             SQLiteTxn txn(db); | ||||
|             PathSet paths; | ||||
|      | ||||
|             foreach (ValidPathInfos::const_iterator, i, infos) { | ||||
|                 assert(i->hash.type == htSHA256); | ||||
|                 /* !!! Maybe the registration info should be updated if the
 | ||||
|                    path is already valid. */ | ||||
|                 if (!isValidPath(i->path)) addValidPath(*i); | ||||
|                 paths.insert(i->path); | ||||
|             } | ||||
| 
 | ||||
|             foreach (ValidPathInfos::const_iterator, i, infos) { | ||||
|  | @ -980,6 +982,12 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos) | |||
|                     addReference(referrer, queryValidPathId(*j)); | ||||
|             } | ||||
| 
 | ||||
|             /* Do a topological sort of the paths.  This will throw an
 | ||||
|                error if a cycle is detected and roll back the | ||||
|                transaction.  Cycles can only occur when a derivation | ||||
|                has multiple outputs. */ | ||||
|             topoSortPaths(*this, paths); | ||||
| 
 | ||||
|             txn.commit(); | ||||
|             break; | ||||
|         } catch (SQLiteBusy & e) { | ||||
|  |  | |||
|  | @ -349,6 +349,10 @@ void exportPaths(StoreAPI & store, const Paths & paths, | |||
|     bool sign, Sink & sink); | ||||
| 
 | ||||
| 
 | ||||
| MakeError(SubstError, Error) | ||||
| MakeError(BuildError, Error) /* denotes a permanent build failure */ | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue