Add an option to make non-determinism non-fatal
That is, when build-repeat > 0, and the output of two rounds differ, then print a warning rather than fail the build. This is primarily to let Hydra check reproducibility of all packages.
This commit is contained in:
		
							parent
							
								
									ceeedb58d2
								
							
						
					
					
						commit
						8bdf83f936
					
				
					 2 changed files with 24 additions and 11 deletions
				
			
		|  | @ -1272,6 +1272,8 @@ void DerivationGoal::inputsRealised() | ||||||
|        build hook. */ |        build hook. */ | ||||||
|     state = &DerivationGoal::tryToBuild; |     state = &DerivationGoal::tryToBuild; | ||||||
|     worker.wakeUp(shared_from_this()); |     worker.wakeUp(shared_from_this()); | ||||||
|  | 
 | ||||||
|  |     result = BuildResult(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -1421,6 +1423,8 @@ void DerivationGoal::buildDone() | ||||||
| 
 | 
 | ||||||
|     debug(format("builder process for ‘%1%’ finished") % drvPath); |     debug(format("builder process for ‘%1%’ finished") % drvPath); | ||||||
| 
 | 
 | ||||||
|  |     result.timesBuilt++; | ||||||
|  | 
 | ||||||
|     /* So the child is gone now. */ |     /* So the child is gone now. */ | ||||||
|     worker.childTerminated(this); |     worker.childTerminated(this); | ||||||
| 
 | 
 | ||||||
|  | @ -2909,17 +2913,15 @@ void DerivationGoal::registerOutputs() | ||||||
|         assert(prevInfos.size() == infos.size()); |         assert(prevInfos.size() == infos.size()); | ||||||
|         for (auto i = prevInfos.begin(), j = infos.begin(); i != prevInfos.end(); ++i, ++j) |         for (auto i = prevInfos.begin(), j = infos.begin(); i != prevInfos.end(); ++i, ++j) | ||||||
|             if (!(*i == *j)) { |             if (!(*i == *j)) { | ||||||
|  |                 result.isNonDeterministic = true; | ||||||
|                 Path prev = i->path + checkSuffix; |                 Path prev = i->path + checkSuffix; | ||||||
|                 if (pathExists(prev)) |                 auto msg = pathExists(prev) | ||||||
|                     throw NotDeterministic( |                     ? fmt("output ‘%1%’ of ‘%2%’ differs from ‘%3%’ from previous round", i->path, drvPath, prev) | ||||||
|                         format("output ‘%1%’ of ‘%2%’ differs from ‘%3%’ from previous round") |                     : fmt("output ‘%1%’ of ‘%2%’ differs from previous round", i->path, drvPath); | ||||||
|                         % i->path % drvPath % prev); |                 if (settings.get("enforce-determinism", true)) | ||||||
|                 else |                     throw NotDeterministic(msg); | ||||||
|                     throw NotDeterministic( |                 printError(msg); | ||||||
|                         format("output ‘%1%’ of ‘%2%’ differs from previous round") |  | ||||||
|                         % i->path % drvPath); |  | ||||||
|             } |             } | ||||||
|         abort(); // shouldn't happen
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (settings.keepFailed) { |     if (settings.keepFailed) { | ||||||
|  | @ -2932,7 +2934,6 @@ void DerivationGoal::registerOutputs() | ||||||
|                     throw SysError(format("renaming ‘%1%’ to ‘%2%’") % i.second.path % dst); |                     throw SysError(format("renaming ‘%1%’ to ‘%2%’") % i.second.path % dst); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (curRound < nrRounds) { |     if (curRound < nrRounds) { | ||||||
|  | @ -3792,12 +3793,13 @@ void LocalStore::buildPaths(const PathSet & drvPaths, BuildMode buildMode) | ||||||
|     worker.run(goals); |     worker.run(goals); | ||||||
| 
 | 
 | ||||||
|     PathSet failed; |     PathSet failed; | ||||||
|     for (auto & i : goals) |     for (auto & i : goals) { | ||||||
|         if (i->getExitCode() != Goal::ecSuccess) { |         if (i->getExitCode() != Goal::ecSuccess) { | ||||||
|             DerivationGoal * i2 = dynamic_cast<DerivationGoal *>(i.get()); |             DerivationGoal * i2 = dynamic_cast<DerivationGoal *>(i.get()); | ||||||
|             if (i2) failed.insert(i2->getDrvPath()); |             if (i2) failed.insert(i2->getDrvPath()); | ||||||
|             else failed.insert(dynamic_cast<SubstitutionGoal *>(i.get())->getStorePath()); |             else failed.insert(dynamic_cast<SubstitutionGoal *>(i.get())->getStorePath()); | ||||||
|         } |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     if (!failed.empty()) |     if (!failed.empty()) | ||||||
|         throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed)); |         throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed)); | ||||||
|  |  | ||||||
|  | @ -208,7 +208,18 @@ struct BuildResult | ||||||
|         NotDeterministic, |         NotDeterministic, | ||||||
|     } status = MiscFailure; |     } status = MiscFailure; | ||||||
|     std::string errorMsg; |     std::string errorMsg; | ||||||
|  | 
 | ||||||
|  |     /* How many times this build was performed. */ | ||||||
|  |     unsigned int timesBuilt = 0; | ||||||
|  | 
 | ||||||
|  |     /* If timesBuilt > 1, whether some builds did not produce the same
 | ||||||
|  |        result. (Note that 'isNonDeterministic = false' does not mean | ||||||
|  |        the build is deterministic, just that we don't have evidence of | ||||||
|  |        non-determinism.) */ | ||||||
|  |     bool isNonDeterministic = false; | ||||||
|  | 
 | ||||||
|     //time_t startTime = 0, stopTime = 0;
 |     //time_t startTime = 0, stopTime = 0;
 | ||||||
|  | 
 | ||||||
|     bool success() { |     bool success() { | ||||||
|         return status == Built || status == Substituted || status == AlreadyValid; |         return status == Built || status == Substituted || status == AlreadyValid; | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue