@@ -124,6 +124,17 @@ def atomicWrite(fileName):
124124 os .replace (tempFileName , fileName )
125125
126126
127+ def getCachedCompilerConsoleOutput (path ):
128+ try :
129+ with open (path , 'rb' ) as f :
130+ return f .read ().decode (CACHE_COMPILER_OUTPUT_STORAGE_CODEC )
131+ except IOError :
132+ return ''
133+
134+ def setCachedCompilerConsoleOutput (path , output ):
135+ with open (path , 'wb' ) as f :
136+ f .write (output .encode (CACHE_COMPILER_OUTPUT_STORAGE_CODEC ))
137+
127138class IncludeNotFoundException (Exception ):
128139 pass
129140
@@ -354,6 +365,10 @@ def forPath(path):
354365
355366
356367class CompilerArtifactsSection (object ):
368+ OBJECT_FILE = 'object'
369+ STDOUT_FILE = 'output.txt'
370+ STDERR_FILE = 'stderr.txt'
371+
357372 def __init__ (self , compilerArtifactsSectionDir ):
358373 self .compilerArtifactsSectionDir = compilerArtifactsSectionDir
359374 self .lock = CacheLock .forPath (self .compilerArtifactsSectionDir )
@@ -365,40 +380,38 @@ def cacheEntries(self):
365380 return childDirectories (self .compilerArtifactsSectionDir , absolute = False )
366381
367382 def cachedObjectName (self , key ):
368- return os .path .join (self .cacheEntryDir (key ), "object" )
383+ return os .path .join (self .cacheEntryDir (key ), CompilerArtifactsSection . OBJECT_FILE )
369384
370385 def hasEntry (self , key ):
371386 return os .path .exists (self .cacheEntryDir (key ))
372387
373388 def setEntry (self , key , artifacts ):
374- ensureDirectoryExists (self .cacheEntryDir (key ))
389+ cacheEntryDir = self .cacheEntryDir (key )
390+ # Write new files to a temporary directory
391+ tempEntryDir = cacheEntryDir + '.new'
392+ # Remove any possible left-over in tempEntryDir from previous executions
393+ rmtree (tempEntryDir , ignore_errors = True )
394+ ensureDirectoryExists (tempEntryDir )
375395 if artifacts .objectFilePath is not None :
376- copyOrLink (artifacts .objectFilePath , self .cachedObjectName (key ))
377- self ._setCachedCompilerConsoleOutput (key , 'output.txt' , artifacts .stdout )
396+ copyOrLink (artifacts .objectFilePath ,
397+ os .path .join (tempEntryDir , CompilerArtifactsSection .OBJECT_FILE ))
398+ setCachedCompilerConsoleOutput (os .path .join (tempEntryDir , CompilerArtifactsSection .STDOUT_FILE ),
399+ artifacts .stdout )
378400 if artifacts .stderr != '' :
379- self ._setCachedCompilerConsoleOutput (key , 'stderr.txt' , artifacts .stderr )
401+ setCachedCompilerConsoleOutput (os .path .join (tempEntryDir , CompilerArtifactsSection .STDERR_FILE ),
402+ artifacts .stderr )
403+ # Replace the full cache entry atomically
404+ os .replace (tempEntryDir , cacheEntryDir )
380405
381406 def getEntry (self , key ):
382407 assert self .hasEntry (key )
408+ cacheEntryDir = self .cacheEntryDir (key )
383409 return CompilerArtifacts (
384- self . cachedObjectName ( key ),
385- self . _getCachedCompilerConsoleOutput ( key , 'output.txt' ),
386- self . _getCachedCompilerConsoleOutput ( key , 'stderr.txt' )
410+ os . path . join ( cacheEntryDir , CompilerArtifactsSection . OBJECT_FILE ),
411+ getCachedCompilerConsoleOutput ( os . path . join ( cacheEntryDir , CompilerArtifactsSection . STDOUT_FILE ) ),
412+ getCachedCompilerConsoleOutput ( os . path . join ( cacheEntryDir , CompilerArtifactsSection . STDERR_FILE ) )
387413 )
388414
389- def _getCachedCompilerConsoleOutput (self , key , fileName ):
390- try :
391- outputFilePath = os .path .join (self .cacheEntryDir (key ), fileName )
392- with open (outputFilePath , 'rb' ) as f :
393- return f .read ().decode (CACHE_COMPILER_OUTPUT_STORAGE_CODEC )
394- except IOError :
395- return ''
396-
397- def _setCachedCompilerConsoleOutput (self , key , fileName , output ):
398- outputFilePath = os .path .join (self .cacheEntryDir (key ), fileName )
399- with open (outputFilePath , 'wb' ) as f :
400- f .write (output .encode (CACHE_COMPILER_OUTPUT_STORAGE_CODEC ))
401-
402415
403416class CompilerArtifactsRepository (object ):
404417 def __init__ (self , compilerArtifactsRootDir ):
0 commit comments