* nix-instantiate: return exit status 100 to denote a permanent build
failure. The build hook can use this to distinguish between transient and permanent failures on the remote side.
This commit is contained in:
		
							parent
							
								
									5833243c92
								
							
						
					
					
						commit
						d787285af9
					
				
					 5 changed files with 29 additions and 14 deletions
				
			
		|  | @ -240,13 +240,13 @@ my $buildFlags = "--max-silent-time $maxSilentTime --fallback --add-root $rootsD | ||||||
| # work on some platforms when connection sharing is used.) | # work on some platforms when connection sharing is used.) | ||||||
| pipe STDIN, DUMMY; # make sure we have a readable STDIN | pipe STDIN, DUMMY; # make sure we have a readable STDIN | ||||||
| if (system("ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) { | if (system("ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) { | ||||||
|     # If we couldn't run ssh or there was an ssh problem (indicated by |     # Note that if we get exit code 100 from `nix-store -r', it | ||||||
|     # exit code 255), then we return exit code 1; otherwise we assume |     # denotes a permanent build failure (as opposed to an SSH problem | ||||||
|     # that the builder failed, which we indicate to Nix using exit |     # or a temporary Nix problem).  We propagate this to the caller to | ||||||
|     # code 100.  It's important to distinguish between the two because |     # allow it to distinguish between transient and permanent | ||||||
|     # the first is a transient failure and the latter is permanent. |     # failures. | ||||||
|     my $res = $? == -1 || ($? >> 8) == 255 ? 1 : 100; |     my $res = $? >> 8; | ||||||
|     print STDERR "build of `$drvPath' on `$hostName' failed with exit code $?\n"; |     print STDERR "build of `$drvPath' on `$hostName' failed with exit code $res\n"; | ||||||
|     removeRoots; |     removeRoots; | ||||||
|     exit $res; |     exit $res; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -393,7 +393,7 @@ int main(int argc, char * * argv) | ||||||
|         printMsg(lvlError, format("error: %1%%2%") % (showTrace ? e.prefix() : "") % e.msg()); |         printMsg(lvlError, format("error: %1%%2%") % (showTrace ? e.prefix() : "") % e.msg()); | ||||||
|         if (e.prefix() != "" && !showTrace) |         if (e.prefix() != "" && !showTrace) | ||||||
|             printMsg(lvlError, "(use `--show-trace' to show detailed location information)"); |             printMsg(lvlError, "(use `--show-trace' to show detailed location information)"); | ||||||
|         return 1; |         return e.status; | ||||||
|     } catch (std::exception & e) { |     } catch (std::exception & e) { | ||||||
|         printMsg(lvlError, format("error: %1%") % e.what()); |         printMsg(lvlError, format("error: %1%") % e.what()); | ||||||
|         return 1; |         return 1; | ||||||
|  |  | ||||||
|  | @ -214,6 +214,10 @@ public: | ||||||
| 
 | 
 | ||||||
|     bool cacheFailure; |     bool cacheFailure; | ||||||
| 
 | 
 | ||||||
|  |     /* Set if at least one derivation had a BuildError (i.e. permanent
 | ||||||
|  |        failure). */ | ||||||
|  |     bool permanentFailure; | ||||||
|  | 
 | ||||||
|     LocalStore & store; |     LocalStore & store; | ||||||
| 
 | 
 | ||||||
|     boost::shared_ptr<HookInstance> hook; |     boost::shared_ptr<HookInstance> hook; | ||||||
|  | @ -267,6 +271,7 @@ public: | ||||||
|     /* Wait for input to become available. */ |     /* Wait for input to become available. */ | ||||||
|     void waitForInput(); |     void waitForInput(); | ||||||
| 
 | 
 | ||||||
|  |     unsigned int exitStatus(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -1185,6 +1190,7 @@ void DerivationGoal::tryToBuild() | ||||||
|         if (printBuildTrace) |         if (printBuildTrace) | ||||||
|             printMsg(lvlError, format("@ build-failed %1% %2% %3% %4%") |             printMsg(lvlError, format("@ build-failed %1% %2% %3% %4%") | ||||||
|                 % drvPath % drv.outputs["out"].path % 0 % e.msg()); |                 % drvPath % drv.outputs["out"].path % 0 % e.msg()); | ||||||
|  |         worker.permanentFailure = true; | ||||||
|         amDone(ecFailed); |         amDone(ecFailed); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  | @ -1321,6 +1327,7 @@ void DerivationGoal::buildDone() | ||||||
|             foreach (DerivationOutputs::iterator, i, drv.outputs) |             foreach (DerivationOutputs::iterator, i, drv.outputs) | ||||||
|                 worker.store.registerFailedPath(i->second.path); |                 worker.store.registerFailedPath(i->second.path); | ||||||
|          |          | ||||||
|  |         worker.permanentFailure = !hookError && !fixedOutput; | ||||||
|         amDone(ecFailed); |         amDone(ecFailed); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  | @ -2444,6 +2451,7 @@ Worker::Worker(LocalStore & store) | ||||||
|     nrLocalBuilds = 0; |     nrLocalBuilds = 0; | ||||||
|     lastWokenUp = 0; |     lastWokenUp = 0; | ||||||
|     cacheFailure = queryBoolSetting("build-cache-failure", false); |     cacheFailure = queryBoolSetting("build-cache-failure", false); | ||||||
|  |     permanentFailure = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -2770,6 +2778,11 @@ void Worker::waitForInput() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | unsigned int Worker::exitStatus() | ||||||
|  | { | ||||||
|  |     return permanentFailure ? 100 : 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| //////////////////////////////////////////////////////////////////////
 | //////////////////////////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
|  | @ -2796,7 +2809,7 @@ void LocalStore::buildDerivations(const PathSet & drvPaths) | ||||||
|         } |         } | ||||||
|              |              | ||||||
|     if (!failed.empty()) |     if (!failed.empty()) | ||||||
|         throw Error(format("build of %1% failed") % showPaths(failed)); |         throw Error(format("build of %1% failed") % showPaths(failed), worker.exitStatus()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -2812,7 +2825,7 @@ void LocalStore::ensurePath(const Path & path) | ||||||
|     worker.run(goals); |     worker.run(goals); | ||||||
| 
 | 
 | ||||||
|     if (goal->getExitCode() != Goal::ecSuccess) |     if (goal->getExitCode() != Goal::ecSuccess) | ||||||
|         throw Error(format("path `%1%' does not exist and cannot be created") % path); |         throw Error(format("path `%1%' does not exist and cannot be created") % path, worker.exitStatus()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|   |   | ||||||
|  |  | ||||||
|  | @ -29,7 +29,8 @@ protected: | ||||||
|     string prefix_; // used for location traces etc.
 |     string prefix_; // used for location traces etc.
 | ||||||
|     string err; |     string err; | ||||||
| public: | public: | ||||||
|     BaseError(const format & f); |     unsigned int status; // exit status
 | ||||||
|  |     BaseError(const format & f, unsigned int status = 1); | ||||||
|     ~BaseError() throw () { }; |     ~BaseError() throw () { }; | ||||||
|     const char * what() const throw () { return err.c_str(); } |     const char * what() const throw () { return err.c_str(); } | ||||||
|     const string & msg() const throw () { return err; } |     const string & msg() const throw () { return err; } | ||||||
|  | @ -41,7 +42,7 @@ public: | ||||||
|     class newClass : public superClass                  \ |     class newClass : public superClass                  \ | ||||||
|     {                                                   \ |     {                                                   \ | ||||||
|     public:                                             \ |     public:                                             \ | ||||||
|         newClass(const format & f) : superClass(f) { }; \ |         newClass(const format & f, unsigned int status = 1) : superClass(f, status) { }; \ | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
| MakeError(Error, BaseError) | MakeError(Error, BaseError) | ||||||
|  |  | ||||||
|  | @ -20,7 +20,8 @@ extern char * * environ; | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| BaseError::BaseError(const format & f) | BaseError::BaseError(const format & f, unsigned int status) | ||||||
|  |     : status(status) | ||||||
| { | { | ||||||
|     err = f.str(); |     err = f.str(); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue