CacheDir.py.svn-base
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:8k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. #
  2. # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
  3. #
  4. # Permission is hereby granted, free of charge, to any person obtaining
  5. # a copy of this software and associated documentation files (the
  6. # "Software"), to deal in the Software without restriction, including
  7. # without limitation the rights to use, copy, modify, merge, publish,
  8. # distribute, sublicense, and/or sell copies of the Software, and to
  9. # permit persons to whom the Software is furnished to do so, subject to
  10. # the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included
  13. # in all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
  16. # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  17. # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. #
  23. __revision__ = "src/engine/SCons/CacheDir.py 3057 2008/06/09 22:21:00 knight"
  24. __doc__ = """
  25. CacheDir support
  26. """
  27. import os.path
  28. import stat
  29. import string
  30. import sys
  31. import SCons.Action
  32. cache_enabled = True
  33. cache_debug = False
  34. cache_force = False
  35. cache_show = False
  36. def CacheRetrieveFunc(target, source, env):
  37.     t = target[0]
  38.     fs = t.fs
  39.     cd = env.get_CacheDir()
  40.     cachedir, cachefile = cd.cachepath(t)
  41.     if not fs.exists(cachefile):
  42.         cd.CacheDebug('CacheRetrieve(%s):  %s not in cachen', t, cachefile)
  43.         return 1
  44.     cd.CacheDebug('CacheRetrieve(%s):  retrieving from %sn', t, cachefile)
  45.     if SCons.Action.execute_actions:
  46.         if fs.islink(cachefile):
  47.             fs.symlink(fs.readlink(cachefile), t.path)
  48.         else:
  49.             env.copy_from_cache(cachefile, t.path)
  50.         st = fs.stat(cachefile)
  51.         fs.chmod(t.path, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
  52.     return 0
  53. def CacheRetrieveString(target, source, env):
  54.     t = target[0]
  55.     fs = t.fs
  56.     cd = env.get_CacheDir()
  57.     cachedir, cachefile = cd.cachepath(t)
  58.     if t.fs.exists(cachefile):
  59.         return "Retrieved `%s' from cache" % t.path
  60.     return None
  61. CacheRetrieve = SCons.Action.Action(CacheRetrieveFunc, CacheRetrieveString)
  62. CacheRetrieveSilent = SCons.Action.Action(CacheRetrieveFunc, None)
  63. def CachePushFunc(target, source, env):
  64.     t = target[0]
  65.     if t.nocache:
  66.         return
  67.     fs = t.fs
  68.     cd = env.get_CacheDir()
  69.     cachedir, cachefile = cd.cachepath(t)
  70.     if fs.exists(cachefile):
  71.         # Don't bother copying it if it's already there.  Note that
  72.         # usually this "shouldn't happen" because if the file already
  73.         # existed in cache, we'd have retrieved the file from there,
  74.         # not built it.  This can happen, though, in a race, if some
  75.         # other person running the same build pushes their copy to
  76.         # the cache after we decide we need to build it but before our
  77.         # build completes.
  78.         cd.CacheDebug('CachePush(%s):  %s already exists in cachen', t, cachefile)
  79.         return
  80.     cd.CacheDebug('CachePush(%s):  pushing to %sn', t, cachefile)
  81.     tempfile = cachefile+'.tmp'+str(os.getpid())
  82.     errfmt = "Unable to copy %s to cache. Cache file is %s"
  83.     if not fs.isdir(cachedir):
  84.         try:
  85.             fs.makedirs(cachedir)
  86.         except EnvironmentError:
  87.             # We may have received an exception because another process
  88.             # has beaten us creating the directory.
  89.             if not fs.isdir(cachedir):
  90.                 msg = errfmt % (str(target), cachefile)
  91.                 raise SCons.Errors.EnvironmentError, msg
  92.     try:
  93.         if fs.islink(t.path):
  94.             fs.symlink(fs.readlink(t.path), tempfile)
  95.         else:
  96.             fs.copy2(t.path, tempfile)
  97.         fs.rename(tempfile, cachefile)
  98.         st = fs.stat(t.path)
  99.         fs.chmod(cachefile, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
  100.     except EnvironmentError:
  101.         # It's possible someone else tried writing the file at the
  102.         # same time we did, or else that there was some problem like
  103.         # the CacheDir being on a separate file system that's full.
  104.         # In any case, inability to push a file to cache doesn't affect
  105.         # the correctness of the build, so just print a warning.
  106.         msg = errfmt % (str(target), cachefile)
  107.         SCons.Warnings.warn(SCons.Warnings.CacheWriteErrorWarning, msg)
  108. CachePush = SCons.Action.Action(CachePushFunc, None)
  109. class CacheDir:
  110.     def __init__(self, path):
  111.         try:
  112.             import hashlib
  113.         except ImportError:
  114.             msg = "No hashlib or MD5 module available, CacheDir() not supported"
  115.             SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg)
  116.             self.path = None
  117.         else:
  118.             self.path = path
  119.         self.current_cache_debug = None
  120.         self.debugFP = None
  121.     def CacheDebug(self, fmt, target, cachefile):
  122.         if cache_debug != self.current_cache_debug:
  123.             if cache_debug == '-':
  124.                 self.debugFP = sys.stdout
  125.             elif cache_debug:
  126.                 self.debugFP = open(cache_debug, 'w')
  127.             else:
  128.                 self.debugFP = None
  129.             self.current_cache_debug = cache_debug
  130.         if self.debugFP:
  131.             self.debugFP.write(fmt % (target, os.path.split(cachefile)[1]))
  132.     def is_enabled(self):
  133.         return (cache_enabled and not self.path is None)
  134.     def cachepath(self, node):
  135.         """
  136.         """
  137.         if not self.is_enabled():
  138.             return None, None
  139.         sig = node.get_cachedir_bsig()
  140.         subdir = string.upper(sig[0])
  141.         dir = os.path.join(self.path, subdir)
  142.         return dir, os.path.join(dir, sig)
  143.     def retrieve(self, node):
  144.         """
  145.         This method is called from multiple threads in a parallel build,
  146.         so only do thread safe stuff here. Do thread unsafe stuff in
  147.         built().
  148.         Note that there's a special trick here with the execute flag
  149.         (one that's not normally done for other actions).  Basically
  150.         if the user requested a no_exec (-n) build, then
  151.         SCons.Action.execute_actions is set to 0 and when any action
  152.         is called, it does its showing but then just returns zero
  153.         instead of actually calling the action execution operation.
  154.         The problem for caching is that if the file does NOT exist in
  155.         cache then the CacheRetrieveString won't return anything to
  156.         show for the task, but the Action.__call__ won't call
  157.         CacheRetrieveFunc; instead it just returns zero, which makes
  158.         the code below think that the file *was* successfully
  159.         retrieved from the cache, therefore it doesn't do any
  160.         subsequent building.  However, the CacheRetrieveString didn't
  161.         print anything because it didn't actually exist in the cache,
  162.         and no more build actions will be performed, so the user just
  163.         sees nothing.  The fix is to tell Action.__call__ to always
  164.         execute the CacheRetrieveFunc and then have the latter
  165.         explicitly check SCons.Action.execute_actions itself.
  166.         """
  167.         if not self.is_enabled():
  168.             return False
  169.         retrieved = False
  170.         if cache_show:
  171.             if CacheRetrieveSilent(node, [], node.get_build_env(), execute=1) == 0:
  172.                 node.build(presub=0, execute=0)
  173.                 retrieved = 1
  174.         else:
  175.             if CacheRetrieve(node, [], node.get_build_env(), execute=1) == 0:
  176.                 retrieved = 1
  177.         if retrieved:
  178.             # Record build signature information, but don't
  179.             # push it out to cache.  (We just got it from there!)
  180.             node.set_state(SCons.Node.executed)
  181.             SCons.Node.Node.built(node)
  182.         return retrieved
  183.     def push(self, node):
  184.         if not self.is_enabled():
  185.             return
  186.         return CachePush(node, [], node.get_build_env())
  187.     def push_if_forced(self, node):
  188.         if cache_force:
  189.             return self.push(node)