@@ -308,6 +308,49 @@ def getIncludesContentHashForHashes(listOfHashes):
308308 return HashAlgorithm (',' .join (listOfHashes ).encode ()).hexdigest ()
309309
310310
311+ class GlobalSettings (object ):
312+ @staticmethod
313+ def getValue (settingName , defaultValue = None ):
314+ value = os .environ .get (settingName , None )
315+ if value is None : # compare to None to allow empty values
316+ value = GlobalSettings .__getFromCache (settingName )
317+ return value if value is not None else defaultValue
318+
319+ # serves as a cache to only read the config file once
320+ __settings = None
321+
322+ @staticmethod
323+ def __getFromCache (settingName ):
324+ if not GlobalSettings .__settings :
325+ GlobalSettings .__readFromFile ()
326+ return GlobalSettings .__settings .get (settingName , None )
327+
328+ @staticmethod
329+ def __readFromFile ():
330+ GlobalSettings .__settings = dict ()
331+
332+ # prefer config in current directory
333+ filename = os .path .join (os .getcwd (), "clcache.conf" )
334+
335+ # ..or in home directory..
336+ if not os .path .exists (filename ):
337+ filename = os .path .join (os .path .expanduser ("~" ), ".clcache" , "clcache.conf" )
338+
339+ # or in "sysconfdir" (%ALLUSERSPROFILE%)
340+ if not os .path .exists (filename ):
341+ dir = os .environ .get ('ALLUSERSPROFILE' , None )
342+ filename = os .path .join (dir if dir else "C:\\ Users" , ".clcache" , "clcache.conf" )
343+ try :
344+ with open (filename ) as f :
345+ for line in f .readlines ():
346+ kv = line .split ("=" )
347+ if len (kv ) != 2 or kv [0 ].startswith ("#" ):
348+ continue
349+ GlobalSettings .__settings [kv [0 ].strip ()] = kv [1 ].split ("#" )[0 ].strip ()
350+ except IOError :
351+ pass # only ignore file access errors (including not-existing path)
352+
353+
311354class CacheLock (object ):
312355 """ Implements a lock for the object cache which
313356 can be used in 'with' statements. """
@@ -359,7 +402,7 @@ def release(self):
359402
360403 @staticmethod
361404 def forPath (path ):
362- timeoutMs = int (os . environ . get ('CLCACHE_OBJECT_CACHE_TIMEOUT_MS' , 10 * 1000 ))
405+ timeoutMs = int (GlobalSettings . getValue ('CLCACHE_OBJECT_CACHE_TIMEOUT_MS' , 10 * 1000 ))
363406 lockName = path .replace (':' , '-' ).replace ('\\ ' , '-' )
364407 return CacheLock (lockName , timeoutMs )
365408
@@ -505,10 +548,8 @@ class CacheFileStrategy(object):
505548 def __init__ (self , cacheDirectory = None ):
506549 self .dir = cacheDirectory
507550 if not self .dir :
508- try :
509- self .dir = os .environ ["CLCACHE_DIR" ]
510- except KeyError :
511- self .dir = os .path .join (os .path .expanduser ("~" ), "clcache" )
551+ self .dir = GlobalSettings .getValue ("CLCACHE_DIR" ,
552+ os .path .join (os .path .expanduser ("~" ), "clcache" ))
512553
513554 manifestsRootDir = os .path .join (self .dir , "manifests" )
514555 ensureDirectoryExists (manifestsRootDir )
@@ -593,9 +634,10 @@ def clean(self, stats, maximumSize):
593634
594635class Cache (object ):
595636 def __init__ (self , cacheDirectory = None ):
596- if os .environ .get ("CLCACHE_MEMCACHED" ):
637+ memcached = GlobalSettings .getValue ("CLCACHE_MEMCACHED" )
638+ if memcached :
597639 from .storage import CacheFileWithMemcacheFallbackStrategy
598- self .strategy = CacheFileWithMemcacheFallbackStrategy (os . environ . get ( "CLCACHE_MEMCACHED" ) ,
640+ self .strategy = CacheFileWithMemcacheFallbackStrategy (memcached ,
599641 cacheDirectory = cacheDirectory )
600642 else :
601643 self .strategy = CacheFileStrategy (cacheDirectory = cacheDirectory )
@@ -900,7 +942,7 @@ def getCompilerHash(compilerBinary):
900942
901943
902944def getFileHashes (filePaths ):
903- if 'CLCACHE_SERVER' in os . environ :
945+ if GlobalSettings . getValue ( 'CLCACHE_SERVER' ) not in [ '0' , 'false' , 'False' ] :
904946 pipeName = r'\\.\pipe\clcache_srv'
905947 while True :
906948 try :
@@ -939,7 +981,7 @@ def getStringHash(dataString):
939981
940982
941983def expandBasedirPlaceholder (path ):
942- baseDir = normalizeBaseDir (os . environ . get ('CLCACHE_BASEDIR' ))
984+ baseDir = normalizeBaseDir (GlobalSettings . getValue ('CLCACHE_BASEDIR' ))
943985 if path .startswith (BASEDIR_REPLACEMENT ):
944986 if not baseDir :
945987 raise LogicException ('No CLCACHE_BASEDIR set, but found relative path ' + path )
@@ -949,7 +991,7 @@ def expandBasedirPlaceholder(path):
949991
950992
951993def collapseBasedirToPlaceholder (path ):
952- baseDir = normalizeBaseDir (os . environ . get ('CLCACHE_BASEDIR' ))
994+ baseDir = normalizeBaseDir (GlobalSettings . getValue ('CLCACHE_BASEDIR' ))
953995 if baseDir is None :
954996 return path
955997 else :
@@ -972,7 +1014,7 @@ def ensureDirectoryExists(path):
9721014def copyOrLink (srcFilePath , dstFilePath ):
9731015 ensureDirectoryExists (os .path .dirname (os .path .abspath (dstFilePath )))
9741016
975- if "CLCACHE_HARDLINK" in os . environ :
1017+ if GlobalSettings . getValue ( "CLCACHE_HARDLINK" ) not in [ '0' , 'false' , 'False' ] :
9761018 ret = windll .kernel32 .CreateHardLinkW (str (dstFilePath ), str (srcFilePath ), None )
9771019 if ret != 0 :
9781020 # Touch the time stamp of the new link so that the build system
@@ -998,11 +1040,10 @@ def myExecutablePath():
9981040
9991041
10001042def findCompilerBinary ():
1001- if "CLCACHE_CL" in os . environ :
1002- path = os . environ [ "CLCACHE_CL" ]
1043+ path = GlobalSettings . getValue ( "CLCACHE_CL" )
1044+ if path :
10031045 if os .path .basename (path ) == path :
10041046 path = which (path )
1005-
10061047 return path if os .path .exists (path ) else None
10071048
10081049 frozenByPy2Exe = hasattr (sys , "frozen" )
@@ -1020,7 +1061,7 @@ def findCompilerBinary():
10201061
10211062
10221063def printTraceStatement (msg : str ) -> None :
1023- if "CLCACHE_LOG" in os . environ :
1064+ if GlobalSettings . getValue ( "CLCACHE_LOG" ) not in [ '0' , 'false' , 'False' ] :
10241065 scriptDir = os .path .realpath (os .path .dirname (sys .argv [0 ]))
10251066 with OUTPUT_LOCK :
10261067 print (os .path .join (scriptDir , "clcache.py" ) + " " + msg )
@@ -1571,7 +1612,7 @@ def main():
15711612 printTraceStatement ("Found real compiler binary at '{0!s}'" .format (compiler ))
15721613 printTraceStatement ("Arguments we care about: '{}'" .format (sys .argv ))
15731614
1574- if "CLCACHE_DISABLE" in os . environ :
1615+ if GlobalSettings . getValue ( "CLCACHE_DISABLE" ) not in [ '0' , 'false' , 'False' ] :
15751616 return invokeRealCompiler (compiler , sys .argv [1 :])[0 ]
15761617 try :
15771618 return processCompileRequest (cache , compiler , sys .argv )
@@ -1671,7 +1712,7 @@ def processSingleSource(compiler, cmdLine, sourceFile, objectFile, environment):
16711712 assert objectFile is not None
16721713 cache = Cache ()
16731714
1674- if 'CLCACHE_NODIRECT' in os . environ :
1715+ if GlobalSettings . getValue ( 'CLCACHE_NODIRECT' ) not in [ '0' , 'false' , 'False' ] :
16751716 return processNoDirect (cache , objectFile , compiler , cmdLine , environment )
16761717 else :
16771718 return processDirect (cache , objectFile , compiler , cmdLine , sourceFile )
@@ -1770,7 +1811,7 @@ def ensureArtifactsExist(cache, cachekey, reason, objectFile, compilerResult, ex
17701811
17711812
17721813if __name__ == '__main__' :
1773- if 'CLCACHE_PROFILE' in os . environ :
1814+ if GlobalSettings . getValue ( 'CLCACHE_PROFILE' ) not in [ '0' , 'false' , 'False' ] :
17741815 INVOCATION_HASH = getStringHash (',' .join (sys .argv ))
17751816 cProfile .run ('main()' , filename = 'clcache-{}.prof' .format (INVOCATION_HASH ))
17761817 else :
0 commit comments