http://scons.tigris.org/issues/show_bug.cgi?id=2329
[scons.git] / src / engine / SCons / Defaults.py
index 3cd47efe460738f39d75ec50e880e665d3d3f1b6..f532354dcf98670a17a8ae58dd26043e59d21725 100644 (file)
@@ -38,10 +38,10 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 import os
 import os.path
+import errno
 import shutil
 import stat
 import time
-import types
 import sys
 
 import SCons.Action
@@ -86,7 +86,7 @@ def DefaultEnvironment(*args, **kw):
     global _default_env
     if not _default_env:
         import SCons.Util
-        _default_env = apply(SCons.Environment.Environment, args, kw)
+        _default_env = SCons.Environment.Environment(*args, **kw)
         if SCons.Util.md5:
             _default_env.Decider('MD5')
         else:
@@ -157,19 +157,36 @@ LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
 # ways by creating ActionFactory instances.
 ActionFactory = SCons.Action.ActionFactory
 
-def chmod_func(path, mode):
-    return os.chmod(str(path), mode)
+def get_paths_str(dest):
+    # If dest is a list, we need to manually call str() on each element
+    if SCons.Util.is_List(dest):
+        elem_strs = []
+        for element in dest:
+            elem_strs.append('"' + str(element) + '"')
+        return '[' + ', '.join(elem_strs) + ']'
+    else:
+        return '"' + str(dest) + '"'
+
+def chmod_func(dest, mode):
+    SCons.Node.FS.invalidate_node_memos(dest)
+    if not SCons.Util.is_List(dest):
+        dest = [dest]
+    for element in dest:
+        os.chmod(str(element), mode)
 
-Chmod = ActionFactory(chmod_func,
-                      lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
+def chmod_strfunc(dest, mode):
+    return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode)
+
+Chmod = ActionFactory(chmod_func, chmod_strfunc)
 
 def copy_func(dest, src):
+    SCons.Node.FS.invalidate_node_memos(dest)
     if SCons.Util.is_List(src) and os.path.isdir(dest):
         for file in src:
-            shutil.copy(file, dest)
+            shutil.copy2(file, dest)
         return 0
     elif os.path.isfile(src):
-        return shutil.copy(src, dest)
+        return shutil.copy2(src, dest)
     else:
         return shutil.copytree(src, dest, 1)
 
@@ -177,40 +194,69 @@ Copy = ActionFactory(copy_func,
                      lambda dest, src: 'Copy("%s", "%s")' % (dest, src),
                      convert=str)
 
-def delete_func(entry, must_exist=0):
-    entry = str(entry)
-    if not must_exist and not os.path.exists(entry):
-        return None
-    if not os.path.exists(entry) or os.path.isfile(entry):
-        return os.unlink(entry)
-    else:
-        return shutil.rmtree(entry, 1)
+def delete_func(dest, must_exist=0):
+    SCons.Node.FS.invalidate_node_memos(dest)
+    if not SCons.Util.is_List(dest):
+        dest = [dest]
+    for entry in dest:
+        entry = str(entry)
+        if not must_exist and not os.path.exists(entry):
+            continue
+        if not os.path.exists(entry) or os.path.isfile(entry):
+            os.unlink(entry)
+            continue
+        else:
+            shutil.rmtree(entry, 1)
+            continue
 
-def delete_strfunc(entry, must_exist=0):
-    return 'Delete("%s")' % entry
+def delete_strfunc(dest, must_exist=0):
+    return 'Delete(%s)' % get_paths_str(dest)
 
 Delete = ActionFactory(delete_func, delete_strfunc)
 
-Mkdir = ActionFactory(os.makedirs,
-                      lambda dir: 'Mkdir("%s")' % dir,
-                      convert=str)
+def mkdir_func(dest):
+    SCons.Node.FS.invalidate_node_memos(dest)
+    if not SCons.Util.is_List(dest):
+        dest = [dest]
+    for entry in dest:
+        try:
+            os.makedirs(str(entry))
+        except os.error, e:
+            p = str(entry)
+            if (e[0] == errno.EEXIST or (sys.platform=='win32' and e[0]==183)) \
+                    and os.path.isdir(str(entry)):
+                pass            # not an error if already exists
+            else:
+                raise
+
+Mkdir = ActionFactory(mkdir_func,
+                      lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
+
+def move_func(dest, src):
+    SCons.Node.FS.invalidate_node_memos(dest)
+    SCons.Node.FS.invalidate_node_memos(src)
+    shutil.move(src, dest)
 
-Move = ActionFactory(lambda dest, src: os.rename(src, dest),
+Move = ActionFactory(move_func,
                      lambda dest, src: 'Move("%s", "%s")' % (dest, src),
                      convert=str)
 
-def touch_func(file):
-    file = str(file)
-    mtime = int(time.time())
-    if os.path.exists(file):
-        atime = os.path.getatime(file)
-    else:
-        open(file, 'w')
-        atime = mtime
-    return os.utime(file, (atime, mtime))
+def touch_func(dest):
+    SCons.Node.FS.invalidate_node_memos(dest)
+    if not SCons.Util.is_List(dest):
+        dest = [dest]
+    for file in dest:
+        file = str(file)
+        mtime = int(time.time())
+        if os.path.exists(file):
+            atime = os.path.getatime(file)
+        else:
+            open(file, 'w')
+            atime = mtime
+        os.utime(file, (atime, mtime))
 
 Touch = ActionFactory(touch_func,
-                      lambda file: 'Touch("%s")' % file)
+                      lambda file: 'Touch(%s)' % get_paths_str(file))
 
 # Internal utility functions
 
@@ -224,11 +270,8 @@ def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
     if not list:
         return list
 
-    if SCons.Util.is_List(list):
-        list = SCons.Util.flatten(list)
-
     l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
-    if not l is None:
+    if l is not None:
         list = l
 
     return _concat_ixes(prefix, list, suffix, env)
@@ -270,16 +313,16 @@ def _concat_ixes(prefix, list, suffix, env):
 
     return result
 
-def _stripixes(prefix, list, suffix, stripprefixes, stripsuffixes, env, c=None):
+def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
     """
-    This is a wrapper around _concat()/_concat_ixes() that checks for the
-    existence of prefixes or suffixes on list elements and strips them
+    This is a wrapper around _concat()/_concat_ixes() that checks for
+    the existence of prefixes or suffixes on list items and strips them
     where it finds them.  This is used by tools (like the GNU linker)
     that need to turn something like 'libfoo.a' into '-lfoo'.
     """
     
-    if not list:
-        return list
+    if not itms:
+        return itms
 
     if not callable(c):
         env_c = env['_concat']
@@ -292,21 +335,11 @@ def _stripixes(prefix, list, suffix, stripprefixes, stripsuffixes, env, c=None):
         else:
             c = _concat_ixes
     
-    if SCons.Util.is_List(list):
-        list = SCons.Util.flatten(list)
-
-    if SCons.Util.is_List(stripprefixes):
-        stripprefixes = map(env.subst, SCons.Util.flatten(stripprefixes))
-    else:
-        stripprefixes = [env.subst(stripprefixes)]
-
-    if SCons.Util.is_List(stripsuffixes):
-        stripsuffixes = map(env.subst, SCons.Util.flatten(stripsuffixes))
-    else:
-        stripsuffixes = [stripsuffixes]
+    stripprefixes = list(map(env.subst, SCons.Util.flatten(stripprefixes)))
+    stripsuffixes = list(map(env.subst, SCons.Util.flatten(stripsuffixes)))
 
     stripped = []
-    for l in SCons.PathList.PathList(list).subst_path(env, None, None):
+    for l in SCons.PathList.PathList(itms).subst_path(env, None, None):
         if isinstance(l, SCons.Node.FS.File):
             stripped.append(l)
             continue
@@ -332,14 +365,14 @@ def _stripixes(prefix, list, suffix, stripprefixes, stripsuffixes, env, c=None):
 
     return c(prefix, stripped, suffix, env)
 
-def _defines(prefix, defs, suffix, env, c=_concat_ixes):
-    """A wrapper around _concat_ixes that turns a list or string
-    into a list of C preprocessor command-line definitions.
+def processDefines(defs):
+    """process defines, resolving strings, lists, dictionaries, into a list of
+    strings
     """
     if SCons.Util.is_List(defs):
         l = []
         for d in defs:
-            if SCons.Util.is_List(d) or type(d) is types.TupleType:
+            if SCons.Util.is_List(d) or isinstance(d, tuple):
                 l.append(str(d[0]) + '=' + str(d[1]))
             else:
                 l.append(str(d))
@@ -351,17 +384,21 @@ def _defines(prefix, defs, suffix, env, c=_concat_ixes):
         # Consequently, we have to sort the keys to ensure a
         # consistent order...
         l = []
-        keys = defs.keys()
-        keys.sort()
-        for k in keys:
-            v = defs[k]
+        for k,v in sorted(defs.items()):
             if v is None:
                 l.append(str(k))
             else:
                 l.append(str(k) + '=' + str(v))
     else:
         l = [str(defs)]
-    return c(prefix, env.subst_path(l), suffix, env)
+    return l
+
+def _defines(prefix, defs, suffix, env, c=_concat_ixes):
+    """A wrapper around _concat_ixes that turns a list or string
+    into a list of C preprocessor command-line definitions.
+    """
+
+    return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
     
 class NullCmdGenerator:
     """This is a callable class that can be used in place of other
@@ -398,14 +435,17 @@ class Variable_Method_Caller:
         self.method = method
     def __call__(self, *args, **kw):
         try: 1/0
-        except ZeroDivisionError: frame = sys.exc_info()[2].tb_frame
+        except ZeroDivisionError: 
+            # Don't start iterating with the current stack-frame to
+            # prevent creating reference cycles (f_back is safe).
+            frame = sys.exc_info()[2].tb_frame.f_back
         variable = self.variable
         while frame:
-            if frame.f_locals.has_key(variable):
+            if variable in frame.f_locals:
                 v = frame.f_locals[variable]
                 if v:
                     method = getattr(v, self.method)
-                    return apply(method, args, kw)
+                    return method(*args, **kw)
             frame = frame.f_back
         return None
 
@@ -418,7 +458,7 @@ ConstructionEnvironment = {
     'DSUFFIXES'     : SCons.Tool.DSuffixes,
     'ENV'           : {},
     'IDLSUFFIXES'   : SCons.Tool.IDLSuffixes,
-    'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes,
+#    'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions
     '_concat'       : _concat,
     '_defines'      : _defines,
     '_stripixes'    : _stripixes,
@@ -432,3 +472,9 @@ ConstructionEnvironment = {
     'File'          : Variable_Method_Caller('TARGET', 'File'),
     'RDirs'         : Variable_Method_Caller('TARGET', 'RDirs'),
 }
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: