From 0f79c7d75479953041f5018e6938a78eda4c2497 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Sun, 16 Mar 2008 14:35:32 +0000 Subject: [PATCH] Make waf dist much more efficient. --- wscript | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/wscript b/wscript index 66b779a0b..e61682644 100644 --- a/wscript +++ b/wscript @@ -458,3 +458,117 @@ def lcov_report(): finally: os.chdir("..") + + + +## +## The default WAF DistDir implementation is rather slow, because it +## first copies everything and only later removes unwanted files and +## directories; this means that it needless copies the full build dir +## and the .hg repository tree. Here we provide a replacement DistDir +## implementation that is more efficient. +## +import Scripting +from Scripting import g_dist_exts, g_excludes, BLDDIR +import Utils +import os + +def copytree(src, dst, symlinks=False, excludes=(), build_dir=None): + """Recursively copy a directory tree using copy2(). + + The destination directory must not already exist. + If exception(s) occur, an Error is raised with a list of reasons. + + If the optional symlinks flag is true, symbolic links in the + source tree result in symbolic links in the destination tree; if + it is false, the contents of the files pointed to by symbolic + links are copied. + + XXX Consider this example code rather than the ultimate tool. + + Note: this is a modified version of shutil.copytree from python + 2.5.2 library; modified for WAF purposes to exclude dot dirs and + another list of files. + """ + names = os.listdir(src) + os.makedirs(dst) + errors = [] + for name in names: + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + try: + if symlinks and os.path.islink(srcname): + linkto = os.readlink(srcname) + os.symlink(linkto, dstname) + elif os.path.isdir(srcname): + if name in excludes: + continue + elif name.startswith('.') or name.startswith(',,') or name.startswith('++'): + continue + elif name == build_dir: + continue + else: + ## build_dir is not passed into the recursive + ## copytree, but that is intentional; it is a + ## directory name valid only at the top level. + copytree(srcname, dstname, symlinks, excludes) + else: + ends = name.endswith + to_remove = False + if name.startswith('.') or name.startswith('++'): + to_remove = True + else: + for x in g_dist_exts: + if ends(x): + to_remove = True + break + if not to_remove: + shutil.copy2(srcname, dstname) + # XXX What about devices, sockets etc.? + except (IOError, os.error), why: + errors.append((srcname, dstname, str(why))) + # catch the Error from the recursive copytree so that we can + # continue with other files + except shutil.Error, err: + errors.extend(err.args[0]) + try: + shutil.copystat(src, dst) + except WindowsError: + # can't copy file access times on Windows + pass + except OSError, why: + errors.extend((src, dst, str(why))) + if errors: + raise shutil.Error, errors + + +def DistDir(appname, version): + "make a distribution directory with all the sources in it" + import shutil + + # Our temporary folder where to put our files + TMPFOLDER=appname+'-'+version + + # Remove an old package directory + if os.path.exists(TMPFOLDER): shutil.rmtree(TMPFOLDER) + + global g_dist_exts, g_excludes + + # Remove the Build dir + build_dir = getattr(Utils.g_module, BLDDIR, None) + + # Copy everything into the new folder + copytree('.', TMPFOLDER, excludes=g_excludes, build_dir=build_dir) + + # TODO undocumented hook + dist_hook = getattr(Utils.g_module, 'dist_hook', None) + if dist_hook: + os.chdir(TMPFOLDER) + try: + dist_hook() + finally: + # go back to the root directory + os.chdir('..') + return TMPFOLDER + +Scripting.DistDir = DistDir