summaryrefslogtreecommitdiff
path: root/buildtools/wafadmin/Scripting.py
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2012-01-04 00:31:27 +0100
committerJelmer Vernooij <jelmer@samba.org>2012-01-04 22:34:20 +0100
commit4f4bce5301ffd8c12aed1b108affa1a75feefb67 (patch)
tree1607accd70a2c37a9b996f7b42ec926b014cfe5b /buildtools/wafadmin/Scripting.py
parent1b45f2aed86dda9fda6e6bcf1c9c7cbdc471c18d (diff)
downloadsamba-4f4bce5301ffd8c12aed1b108affa1a75feefb67.tar.gz
samba-4f4bce5301ffd8c12aed1b108affa1a75feefb67.tar.bz2
samba-4f4bce5301ffd8c12aed1b108affa1a75feefb67.zip
Include waf as an extracted source directory, rather than as a one-in-a-file script.
Diffstat (limited to 'buildtools/wafadmin/Scripting.py')
-rw-r--r--buildtools/wafadmin/Scripting.py586
1 files changed, 586 insertions, 0 deletions
diff --git a/buildtools/wafadmin/Scripting.py b/buildtools/wafadmin/Scripting.py
new file mode 100644
index 0000000000..d975bd934d
--- /dev/null
+++ b/buildtools/wafadmin/Scripting.py
@@ -0,0 +1,586 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005 (ita)
+
+"Module called for configuring, compiling and installing targets"
+
+import os, sys, shutil, traceback, datetime, inspect, errno
+
+import Utils, Configure, Build, Logs, Options, Environment, Task
+from Logs import error, warn, info
+from Constants import *
+
+g_gz = 'bz2'
+commands = []
+
+def prepare_impl(t, cwd, ver, wafdir):
+ Options.tooldir = [t]
+ Options.launch_dir = cwd
+
+ # some command-line options can be processed immediately
+ if '--version' in sys.argv:
+ opt_obj = Options.Handler()
+ opt_obj.curdir = cwd
+ opt_obj.parse_args()
+ sys.exit(0)
+
+ # now find the wscript file
+ msg1 = 'Waf: Please run waf from a directory containing a file named "%s" or run distclean' % WSCRIPT_FILE
+
+ # in theory projects can be configured in an autotool-like manner:
+ # mkdir build && cd build && ../waf configure && ../waf
+ build_dir_override = None
+ candidate = None
+
+ lst = os.listdir(cwd)
+
+ search_for_candidate = True
+ if WSCRIPT_FILE in lst:
+ candidate = cwd
+
+ elif 'configure' in sys.argv and not WSCRIPT_BUILD_FILE in lst:
+ # autotool-like configuration
+ calldir = os.path.abspath(os.path.dirname(sys.argv[0]))
+ if WSCRIPT_FILE in os.listdir(calldir):
+ candidate = calldir
+ search_for_candidate = False
+ else:
+ error('arg[0] directory does not contain a wscript file')
+ sys.exit(1)
+ build_dir_override = cwd
+
+ # climb up to find a script if it is not found
+ while search_for_candidate:
+ if len(cwd) <= 3:
+ break # stop at / or c:
+ dirlst = os.listdir(cwd)
+ if WSCRIPT_FILE in dirlst:
+ candidate = cwd
+ if 'configure' in sys.argv and candidate:
+ break
+ if Options.lockfile in dirlst:
+ env = Environment.Environment()
+ try:
+ env.load(os.path.join(cwd, Options.lockfile))
+ except:
+ error('could not load %r' % Options.lockfile)
+ try:
+ os.stat(env['cwd'])
+ except:
+ candidate = cwd
+ else:
+ candidate = env['cwd']
+ break
+ cwd = os.path.dirname(cwd) # climb up
+
+ if not candidate:
+ # check if the user only wanted to display the help
+ if '-h' in sys.argv or '--help' in sys.argv:
+ warn('No wscript file found: the help message may be incomplete')
+ opt_obj = Options.Handler()
+ opt_obj.curdir = cwd
+ opt_obj.parse_args()
+ else:
+ error(msg1)
+ sys.exit(0)
+
+ # We have found wscript, but there is no guarantee that it is valid
+ try:
+ os.chdir(candidate)
+ except OSError:
+ raise Utils.WafError("the folder %r is unreadable" % candidate)
+
+ # define the main module containing the functions init, shutdown, ..
+ Utils.set_main_module(os.path.join(candidate, WSCRIPT_FILE))
+
+ if build_dir_override:
+ d = getattr(Utils.g_module, BLDDIR, None)
+ if d:
+ # test if user has set the blddir in wscript.
+ msg = ' Overriding build directory %s with %s' % (d, build_dir_override)
+ warn(msg)
+ Utils.g_module.blddir = build_dir_override
+
+ # bind a few methods and classes by default
+
+ def set_def(obj, name=''):
+ n = name or obj.__name__
+ if not n in Utils.g_module.__dict__:
+ setattr(Utils.g_module, n, obj)
+
+ for k in [dist, distclean, distcheck, clean, install, uninstall]:
+ set_def(k)
+
+ set_def(Configure.ConfigurationContext, 'configure_context')
+
+ for k in ['build', 'clean', 'install', 'uninstall']:
+ set_def(Build.BuildContext, k + '_context')
+
+ # now parse the options from the user wscript file
+ opt_obj = Options.Handler(Utils.g_module)
+ opt_obj.curdir = candidate
+ try:
+ f = Utils.g_module.set_options
+ except AttributeError:
+ pass
+ else:
+ opt_obj.sub_options([''])
+ opt_obj.parse_args()
+
+ if not 'init' in Utils.g_module.__dict__:
+ Utils.g_module.init = Utils.nada
+ if not 'shutdown' in Utils.g_module.__dict__:
+ Utils.g_module.shutdown = Utils.nada
+
+ main()
+
+def prepare(t, cwd, ver, wafdir):
+ if WAFVERSION != ver:
+ msg = 'Version mismatch: waf %s <> wafadmin %s (wafdir %s)' % (ver, WAFVERSION, wafdir)
+ print('\033[91mError: %s\033[0m' % msg)
+ sys.exit(1)
+
+ #"""
+ try:
+ prepare_impl(t, cwd, ver, wafdir)
+ except Utils.WafError, e:
+ error(str(e))
+ sys.exit(1)
+ except KeyboardInterrupt:
+ Utils.pprint('RED', 'Interrupted')
+ sys.exit(68)
+ """
+ import cProfile, pstats
+ cProfile.runctx("import Scripting; Scripting.prepare_impl(t, cwd, ver, wafdir)", {},
+ {'t': t, 'cwd':cwd, 'ver':ver, 'wafdir':wafdir},
+ 'profi.txt')
+ p = pstats.Stats('profi.txt')
+ p.sort_stats('time').print_stats(45)
+ #"""
+
+def main():
+ global commands
+ commands = Options.arg_line[:]
+
+ while commands:
+ x = commands.pop(0)
+
+ ini = datetime.datetime.now()
+ if x == 'configure':
+ fun = configure
+ elif x == 'build':
+ fun = build
+ else:
+ fun = getattr(Utils.g_module, x, None)
+
+ if not fun:
+ raise Utils.WscriptError('No such command %r' % x)
+
+ ctx = getattr(Utils.g_module, x + '_context', Utils.Context)()
+
+ if x in ['init', 'shutdown', 'dist', 'distclean', 'distcheck']:
+ # compatibility TODO remove in waf 1.6
+ try:
+ fun(ctx)
+ except TypeError:
+ fun()
+ else:
+ fun(ctx)
+
+ ela = ''
+ if not Options.options.progress_bar:
+ ela = ' (%s)' % Utils.get_elapsed_time(ini)
+
+ if x != 'init' and x != 'shutdown':
+ info('%r finished successfully%s' % (x, ela))
+
+ if not commands and x != 'shutdown':
+ commands.append('shutdown')
+
+def configure(conf):
+
+ src = getattr(Options.options, SRCDIR, None)
+ if not src: src = getattr(Utils.g_module, SRCDIR, None)
+ if not src: src = getattr(Utils.g_module, 'top', None)
+ if not src:
+ src = '.'
+ incomplete_src = 1
+ src = os.path.abspath(src)
+
+ bld = getattr(Options.options, BLDDIR, None)
+ if not bld: bld = getattr(Utils.g_module, BLDDIR, None)
+ if not bld: bld = getattr(Utils.g_module, 'out', None)
+ if not bld:
+ bld = 'build'
+ incomplete_bld = 1
+ if bld == '.':
+ raise Utils.WafError('Setting blddir="." may cause distclean problems')
+ bld = os.path.abspath(bld)
+
+ try: os.makedirs(bld)
+ except OSError: pass
+
+ # It is not possible to compile specific targets in the configuration
+ # this may cause configuration errors if autoconfig is set
+ targets = Options.options.compile_targets
+ Options.options.compile_targets = None
+ Options.is_install = False
+
+ conf.srcdir = src
+ conf.blddir = bld
+ conf.post_init()
+
+ if 'incomplete_src' in vars():
+ conf.check_message_1('Setting srcdir to')
+ conf.check_message_2(src)
+ if 'incomplete_bld' in vars():
+ conf.check_message_1('Setting blddir to')
+ conf.check_message_2(bld)
+
+ # calling to main wscript's configure()
+ conf.sub_config([''])
+
+ conf.store()
+
+ # this will write a configure lock so that subsequent builds will
+ # consider the current path as the root directory (see prepare_impl).
+ # to remove: use 'waf distclean'
+ env = Environment.Environment()
+ env[BLDDIR] = bld
+ env[SRCDIR] = src
+ env['argv'] = sys.argv
+ env['commands'] = Options.commands
+ env['options'] = Options.options.__dict__
+
+ # conf.hash & conf.files hold wscript files paths and hash
+ # (used only by Configure.autoconfig)
+ env['hash'] = conf.hash
+ env['files'] = conf.files
+ env['environ'] = dict(conf.environ)
+ env['cwd'] = os.path.split(Utils.g_module.root_path)[0]
+
+ if Utils.g_module.root_path != src:
+ # in case the source dir is somewhere else
+ env.store(os.path.join(src, Options.lockfile))
+
+ env.store(Options.lockfile)
+
+ Options.options.compile_targets = targets
+
+def clean(bld):
+ '''removes the build files'''
+ try:
+ proj = Environment.Environment(Options.lockfile)
+ except IOError:
+ raise Utils.WafError('Nothing to clean (project not configured)')
+
+ bld.load_dirs(proj[SRCDIR], proj[BLDDIR])
+ bld.load_envs()
+
+ bld.is_install = 0 # False
+
+ # read the scripts - and set the path to the wscript path (useful for srcdir='/foo/bar')
+ bld.add_subdirs([os.path.split(Utils.g_module.root_path)[0]])
+
+ try:
+ bld.clean()
+ finally:
+ bld.save()
+
+def check_configured(bld):
+ if not Configure.autoconfig:
+ return bld
+
+ conf_cls = getattr(Utils.g_module, 'configure_context', Utils.Context)
+ bld_cls = getattr(Utils.g_module, 'build_context', Utils.Context)
+
+ def reconf(proj):
+ back = (Options.commands, Options.options.__dict__, Logs.zones, Logs.verbose)
+
+ Options.commands = proj['commands']
+ Options.options.__dict__ = proj['options']
+ conf = conf_cls()
+ conf.environ = proj['environ']
+ configure(conf)
+
+ (Options.commands, Options.options.__dict__, Logs.zones, Logs.verbose) = back
+
+ try:
+ proj = Environment.Environment(Options.lockfile)
+ except IOError:
+ conf = conf_cls()
+ configure(conf)
+ else:
+ try:
+ bld = bld_cls()
+ bld.load_dirs(proj[SRCDIR], proj[BLDDIR])
+ bld.load_envs()
+ except Utils.WafError:
+ reconf(proj)
+ return bld_cls()
+
+ try:
+ proj = Environment.Environment(Options.lockfile)
+ except IOError:
+ raise Utils.WafError('Auto-config: project does not configure (bug)')
+
+ h = 0
+ try:
+ for file in proj['files']:
+ if file.endswith('configure'):
+ h = hash((h, Utils.readf(file)))
+ else:
+ mod = Utils.load_module(file)
+ h = hash((h, mod.waf_hash_val))
+ except (OSError, IOError):
+ warn('Reconfiguring the project: a file is unavailable')
+ reconf(proj)
+ else:
+ if (h != proj['hash']):
+ warn('Reconfiguring the project: the configuration has changed')
+ reconf(proj)
+
+ return bld_cls()
+
+def install(bld):
+ '''installs the build files'''
+ bld = check_configured(bld)
+
+ Options.commands['install'] = True
+ Options.commands['uninstall'] = False
+ Options.is_install = True
+
+ bld.is_install = INSTALL
+
+ build_impl(bld)
+ bld.install()
+
+def uninstall(bld):
+ '''removes the installed files'''
+ Options.commands['install'] = False
+ Options.commands['uninstall'] = True
+ Options.is_install = True
+
+ bld.is_install = UNINSTALL
+
+ try:
+ def runnable_status(self):
+ return SKIP_ME
+ setattr(Task.Task, 'runnable_status_back', Task.Task.runnable_status)
+ setattr(Task.Task, 'runnable_status', runnable_status)
+
+ build_impl(bld)
+ bld.install()
+ finally:
+ setattr(Task.Task, 'runnable_status', Task.Task.runnable_status_back)
+
+def build(bld):
+ bld = check_configured(bld)
+
+ Options.commands['install'] = False
+ Options.commands['uninstall'] = False
+ Options.is_install = False
+
+ bld.is_install = 0 # False
+
+ return build_impl(bld)
+
+def build_impl(bld):
+ # compile the project and/or install the files
+ try:
+ proj = Environment.Environment(Options.lockfile)
+ except IOError:
+ raise Utils.WafError("Project not configured (run 'waf configure' first)")
+
+ bld.load_dirs(proj[SRCDIR], proj[BLDDIR])
+ bld.load_envs()
+
+ info("Waf: Entering directory `%s'" % bld.bldnode.abspath())
+ bld.add_subdirs([os.path.split(Utils.g_module.root_path)[0]])
+
+ # execute something immediately before the build starts
+ bld.pre_build()
+
+ try:
+ bld.compile()
+ finally:
+ if Options.options.progress_bar: print('')
+ info("Waf: Leaving directory `%s'" % bld.bldnode.abspath())
+
+ # execute something immediately after a successful build
+ bld.post_build()
+
+ bld.install()
+
+excludes = '.bzr .bzrignore .git .gitignore .svn CVS .cvsignore .arch-ids {arch} SCCS BitKeeper .hg _MTN _darcs Makefile Makefile.in config.log .gitattributes .hgignore .hgtags'.split()
+dist_exts = '~ .rej .orig .pyc .pyo .bak .tar.bz2 tar.gz .zip .swp'.split()
+def dont_dist(name, src, build_dir):
+ global excludes, dist_exts
+
+ if (name.startswith(',,')
+ or name.startswith('++')
+ or name.startswith('.waf')
+ or (src == '.' and name == Options.lockfile)
+ or name in excludes
+ or name == build_dir
+ ):
+ return True
+
+ for ext in dist_exts:
+ if name.endswith(ext):
+ return True
+
+ return False
+
+# like shutil.copytree
+# exclude files and to raise exceptions immediately
+def copytree(src, dst, build_dir):
+ names = os.listdir(src)
+ os.makedirs(dst)
+ for name in names:
+ srcname = os.path.join(src, name)
+ dstname = os.path.join(dst, name)
+
+ if dont_dist(name, src, build_dir):
+ continue
+
+ if os.path.isdir(srcname):
+ copytree(srcname, dstname, build_dir)
+ else:
+ shutil.copy2(srcname, dstname)
+
+# TODO in waf 1.6, change this method if "srcdir == blddir" is allowed
+def distclean(ctx=None):
+ '''removes the build directory'''
+ global commands
+ lst = os.listdir('.')
+ for f in lst:
+ if f == Options.lockfile:
+ try:
+ proj = Environment.Environment(f)
+ except:
+ Logs.warn('could not read %r' % f)
+ continue
+
+ try:
+ shutil.rmtree(proj[BLDDIR])
+ except IOError:
+ pass
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ Logs.warn('project %r cannot be removed' % proj[BLDDIR])
+
+ try:
+ os.remove(f)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ Logs.warn('file %r cannot be removed' % f)
+
+ # remove the local waf cache
+ if not commands and f.startswith('.waf'):
+ shutil.rmtree(f, ignore_errors=True)
+
+# FIXME waf 1.6 a unique ctx parameter, and remove the optional appname and version
+def dist(appname='', version=''):
+ '''makes a tarball for redistributing the sources'''
+ # return return (distdirname, tarballname)
+ import tarfile
+
+ if not appname: appname = Utils.g_module.APPNAME
+ if not version: version = Utils.g_module.VERSION
+
+ tmp_folder = appname + '-' + version
+ if g_gz in ['gz', 'bz2']:
+ arch_name = tmp_folder + '.tar.' + g_gz
+ else:
+ arch_name = tmp_folder + '.' + 'zip'
+
+ # remove the previous dir
+ try:
+ shutil.rmtree(tmp_folder)
+ except (OSError, IOError):
+ pass
+
+ # remove the previous archive
+ try:
+ os.remove(arch_name)
+ except (OSError, IOError):
+ pass
+
+ # copy the files into the temporary folder
+ blddir = getattr(Utils.g_module, BLDDIR, None)
+ if not blddir:
+ blddir = getattr(Utils.g_module, 'out', None)
+ copytree('.', tmp_folder, blddir)
+
+ # undocumented hook for additional cleanup
+ dist_hook = getattr(Utils.g_module, 'dist_hook', None)
+ if dist_hook:
+ back = os.getcwd()
+ os.chdir(tmp_folder)
+ try:
+ dist_hook()
+ finally:
+ # go back to the root directory
+ os.chdir(back)
+
+ if g_gz in ['gz', 'bz2']:
+ tar = tarfile.open(arch_name, 'w:' + g_gz)
+ tar.add(tmp_folder)
+ tar.close()
+ else:
+ Utils.zip_folder(tmp_folder, arch_name, tmp_folder)
+
+ try: from hashlib import sha1 as sha
+ except ImportError: from sha import sha
+ try:
+ digest = " (sha=%r)" % sha(Utils.readf(arch_name)).hexdigest()
+ except:
+ digest = ''
+
+ info('New archive created: %s%s' % (arch_name, digest))
+
+ if os.path.exists(tmp_folder): shutil.rmtree(tmp_folder)
+ return arch_name
+
+# FIXME waf 1.6 a unique ctx parameter, and remove the optional appname and version
+def distcheck(appname='', version='', subdir=''):
+ '''checks if the sources compile (tarball from 'dist')'''
+ import tempfile, tarfile
+
+ if not appname: appname = Utils.g_module.APPNAME
+ if not version: version = Utils.g_module.VERSION
+
+ waf = os.path.abspath(sys.argv[0])
+ tarball = dist(appname, version)
+
+ path = appname + '-' + version
+
+ # remove any previous instance
+ if os.path.exists(path):
+ shutil.rmtree(path)
+
+ t = tarfile.open(tarball)
+ for x in t: t.extract(x)
+ t.close()
+
+ # build_path is the directory for the waf invocation
+ if subdir:
+ build_path = os.path.join(path, subdir)
+ else:
+ build_path = path
+
+ instdir = tempfile.mkdtemp('.inst', '%s-%s' % (appname, version))
+ ret = Utils.pproc.Popen([waf, 'configure', 'build', 'install', 'uninstall', '--destdir=' + instdir], cwd=build_path).wait()
+ if ret:
+ raise Utils.WafError('distcheck failed with code %i' % ret)
+
+ if os.path.exists(instdir):
+ raise Utils.WafError('distcheck succeeded, but files were left in %s' % instdir)
+
+ shutil.rmtree(path)
+
+# FIXME remove in Waf 1.6 (kept for compatibility)
+def add_subdir(dir, bld):
+ bld.recurse(dir, 'build')
+