summaryrefslogtreecommitdiffstats
path: root/SConstruct
diff options
context:
space:
mode:
Diffstat (limited to 'SConstruct')
-rw-r--r--SConstruct597
1 files changed, 597 insertions, 0 deletions
diff --git a/SConstruct b/SConstruct
new file mode 100644
index 0000000..67d3e64
--- /dev/null
+++ b/SConstruct
@@ -0,0 +1,597 @@
+#
+# SConstruct file to build scons during development.
+#
+# THIS IS NOT READY YET. DO NOT TRY TO BUILD SCons WITH ITSELF YET.
+#
+
+#
+# Copyright (c) 2001 Steven Knight
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+import distutils.util
+import os
+import os.path
+import stat
+import string
+import sys
+import time
+
+project = 'scons'
+
+#Default('.') # XXX Uncomment this when we're really ready
+
+#
+# An internal "whereis" routine to figure out if we have a
+# given program available. Put it in the "cons::" package
+# so subsidiary Conscript files can get at it easily, too.
+#
+
+def whereis(file):
+ for dir in string.split(os.environ['PATH'], os.pathsep):
+ f = os.path.join(dir, file)
+ try:
+ st = os.stat(f)
+ except:
+ continue
+ if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
+ return f
+ return None
+
+#
+# We let the presence or absence of various utilities determine
+# whether or not we bother to build certain pieces of things.
+# This will allow people to still do SCons work even if they
+# don't have Aegis or RPM installed, for example.
+#
+aegis = whereis('aegis')
+aesub = whereis('aesub')
+rpm = whereis('rpm')
+dh_builddeb = whereis('dh_builddeb')
+fakeroot = whereis('fakeroot')
+
+# My installation on Red Hat doesn't like any debhelper version
+# beyond 2, so let's use 2 as the default on any non-Debian build.
+if os.path.isfile('/etc/debian_version'):
+ dh_compat = 3
+else:
+ dh_compat = 2
+
+#
+ARG = {} # XXX Remove this when we support command-line arguments
+#
+# Now grab the information that we "build" into the files (using sed).
+#
+try:
+ date = ARG['date']
+except:
+ date = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(time.time()))
+
+if ARG.has_key('developer'):
+ developer = ARG['developer']
+elif os.environ.has_key('USERNAME'):
+ developer = os.environ['USERNAME']
+elif os.environ.has_key('LOGNAME'):
+ developer = os.environ['LOGNAME']
+elif os.environ.has_key('USER'):
+ developer = os.environ['USER']
+
+try:
+ revision = ARG['version']
+except:
+ if aesub:
+ revision = os.popen(aesub + " \\$version", "r").read()[:-1]
+ else:
+ revision = '0.04'
+
+a = string.split(revision, '.')
+arr = [a[0]]
+for s in a[1:]:
+ if len(s) == 1:
+ s = '0' + s
+ arr.append(s)
+revision = string.join(arr, '.')
+
+# Here's how we'd turn the calculated $revision into our package $version.
+# This makes it difficult to coordinate with other files (debian/changelog
+# and rpm/scons.spec) that hard-code the version number, so just go with
+# the flow for now and hard code it here, too.
+#if len(arr) >= 2:
+# arr = arr[:-1]
+#def xxx(str):
+# if str[0] == 'C' or str[0] == 'D':
+# str = str[1:]
+# while len(str) > 2 and str[0] == '0':
+# str = str[1:]
+# return str
+#arr = map(lambda x, xxx=xxx: xxx(x), arr)
+#version = string.join(arr, '.')
+version = '0.04'
+
+try:
+ change = ARG['change']
+except:
+ if aesub:
+ change = os.popen(aesub + " \\$change", "r").read()[:-1]
+ else:
+ change = '0.04'
+
+python_ver = sys.version[0:3]
+
+platform = distutils.util.get_platform()
+
+if platform == "win32":
+ archsuffix = "zip"
+else:
+ archsuffix = "tar.gz"
+
+test1_dir = os.path.join(os.getcwd(), "build", "test1")
+test2_dir = os.path.join(os.getcwd(), "build", "test2")
+
+lib_project = os.path.join("lib", project)
+
+# Originally, we were going to package the build engine in a
+# private SCons library that contained the version number, so
+# we could easily have multiple side-by-side versions of SCons
+# installed. Keep this around in case we ever want to go back
+# to that scheme. Note that this also requires changes to
+# runtest.py and src/setup.py.
+#lib_project = os.path.join("lib", project + '-' + version)
+
+test1_lib_dir = os.path.join(test1_dir, lib_project)
+
+test2_lib_dir = os.path.join(test2_dir,
+ "lib",
+ "python" + python_ver,
+ "site-packages")
+
+unpack_dir = os.path.join(os.getcwd(), "build", "unpack")
+
+env = Environment(
+ ENV = {
+ 'AEGIS_PROJECT' : os.environ['AEGIS_PROJECT'],
+ 'PATH' : os.environ['PATH'],
+ },
+ TEST1_LIB_DIR = test1_lib_dir,
+ TEST2_LIB_DIR = test2_lib_dir,
+
+ DATE = date,
+ DEVELOPER = developer,
+ REVISION = revision,
+ VERSION = version,
+ DH_COMPAT = dh_compat,
+
+ SED = 'sed',
+ SEDFLAGS = "$( -e 's+__DATE__+$DATE+' $)" + \
+ " -e 's+__DEVELOPER__+$DEVELOPER+'" + \
+ " -e 's+__FILE__+$SOURCES'+" + \
+ " -e 's+__REVISION__+$REVISION'+" + \
+ " -e 's+__VERSION__+$VERSION'+",
+ SEDCOM = '$SED $SEDFLAGS $SOURCES > $TARGET',
+ )
+
+#
+# Define SCons packages.
+#
+# In the original, more complicated packaging scheme, we were going
+# to have separate packages for:
+#
+# python-scons only the build engine
+# scons-script only the script
+# scons the script plus the build engine
+#
+# We're now only delivering a single "scons" package, but this is still
+# "built" as two sub-packages (the build engine and the script), so
+# the definitions remain here, even though we're not using them for
+# separate packages.
+#
+
+python_scons = {
+ 'pkg' : 'python-' + project,
+ 'src_subdir' : 'engine',
+ 'inst_subdir' : os.path.join('lib', 'python1.5', 'site-packages'),
+ 'prefix' : test2_dir,
+
+ 'debian_deps' : [ 'debian/rules debian/control',
+ 'debian/changelog debian/copyright',
+ 'debian/python-scons.postinst',
+ 'debian/python-scons.prerm',
+ ],
+
+ 'files' : [ 'LICENSE.txt',
+ 'README.txt',
+ 'setup.cfg',
+ 'setup.py',
+ ],
+
+ 'filemap' : {
+ 'LICENSE.txt' : '../LICENSE.txt'
+ },
+}
+
+#
+# The original packaging scheme would have have required us to push
+# the Python version number into the package name (python1.5-scons,
+# python2.0-scons, etc.), which would have required a definition
+# like the following. Leave this here in case we ever decide to do
+# this in the future, but note that this would require some modification
+# to src/engine/setup.py before it would really work.
+#
+#python2_scons = {
+# 'pkg' : 'python2-' + project,
+# 'src_subdir' : 'engine',
+# 'inst_subdir' : os.path.join('lib', 'python2.1', 'site-packages'),
+# 'prefix' : test2_dir,
+#
+# 'debian_deps' : [ 'debian/rules debian/control',
+# 'debian/changelog debian/copyright',
+# 'debian/python2-scons.postinst',
+# 'debian/python2-scons.prerm',
+# ],
+#
+# 'files' : [
+# 'LICENSE.txt',
+# 'README.txt',
+# 'setup.cfg',
+# 'setup.py',
+# ],
+# 'filemap' : {
+# 'LICENSE.txt' : '../LICENSE.txt',
+# },
+#}
+#
+
+scons_script = {
+ 'pkg' : project + '-script',
+ 'src_subdir' : 'script',
+ 'inst_subdir' : 'bin',
+ 'prefix' : test2_dir,
+
+ 'debian_deps' : [ 'debian/rules debian/control',
+ 'debian/changelog debian/copyright',
+ 'debian/python-scons.postinst',
+ 'debian/python-scons.prerm',
+ ],
+
+ 'files' : [
+ 'LICENSE.txt',
+ 'README.txt',
+ 'setup.cfg',
+ 'setup.py',
+ ],
+
+ 'filemap' : {
+ 'LICENSE.txt' : '../LICENSE.txt',
+ 'scons' : 'scons.py',
+ }
+}
+
+scons = {
+ 'pkg' : project,
+ #'inst_subdir' : None,
+ 'prefix' : test1_dir,
+
+ 'debian_deps' : [
+ 'debian/rules debian/control',
+ 'debian/changelog debian/copyright',
+ 'debian/scons.postinst',
+ 'debian/scons.prerm',
+ ],
+
+ 'files' : [
+ 'CHANGES.txt',
+ 'LICENSE.txt',
+ 'README.txt',
+ 'RELEASE.txt',
+ 'os_spawnv_fix.diff',
+ 'scons.1',
+ 'script/scons.bat',
+ 'setup.cfg',
+ 'setup.py',
+ ],
+
+ 'filemap' : {
+ 'scons.1' : '../doc/man/scons.1',
+ },
+
+ 'subpkgs' : [ python_scons, scons_script ],
+
+ 'subinst_dirs' : {
+ 'python-' + project : lib_project,
+ project + '-script' : 'bin',
+ },
+}
+
+src_deps = []
+
+for p in [ scons ]:
+ #
+ # Initialize variables with the right directories for this package.
+ #
+ pkg = p['pkg']
+
+ src = 'src'
+ try:
+ src = os.path.join(src, p['src_subdir'])
+ except KeyError:
+ pass
+
+ build = os.path.join('build', pkg)
+
+ prefix = p['prefix']
+ install = prefix
+ try:
+ install = os.path.join(install, p['inst_subdir'])
+ except KeyError:
+ pass
+
+ #
+ # Read up the list of source files from our MANIFEST.in.
+ # This list should *not* include LICENSE.txt, MANIFEST,
+ # README.txt, or setup.py. Make a copy of the list for the
+ # destination files.
+ #
+ src_files = map(lambda x: x[:-1],
+ open(os.path.join(src, 'MANIFEST.in')).readlines())
+ dst_files = map(lambda x: os.path.join(install, x), src_files)
+
+ if p.has_key('subpkgs'):
+ #
+ # This package includes some sub-packages. Read up their
+ # MANIFEST.in files, and add them to our source and destination
+ # file lists, modifying them as appropriate to add the
+ # specified subdirs.
+ #
+ for sp in p['subpkgs']:
+ ssubdir = sp['src_subdir']
+ isubdir = p['subinst_dirs'][sp['pkg']]
+ f = map(lambda x: x[:-1],
+ open(os.path.join(src, ssubdir, 'MANIFEST.in')).readlines())
+ src_files.extend(map(lambda x, s=sp['src_subdir']:
+ os.path.join(s, x),
+ f))
+ dst_files.extend(map(lambda x, i=install, s=isubdir:
+ os.path.join(i, s, x),
+ f))
+ for k in sp['filemap'].keys():
+ f = sp['filemap'][k]
+ if f:
+ k = os.path.join(sp['src_subdir'], k)
+ p['filemap'][k] = os.path.join(sp['src_subdir'], f)
+
+ #
+ # Now that we have the "normal" source files, add those files
+ # that are standard for each distribution. Note that we don't
+ # add these to dst_files, because they don't get installed.
+ # And we still have the MANIFEST to add.
+ #
+ src_files.extend(p['files'])
+
+ #
+ # Now run everything in src_file through the sed command we
+ # concocted to expand __FILE__, __VERSION__, etc.
+ #
+ for b in src_files:
+ try:
+ s = p['filemap'][b]
+ except KeyError:
+ pass
+ env.Command(os.path.join(build, b),
+ os.path.join(src, s),
+ "$SEDCOM")
+
+ #
+ # NOW, finally, we can create the MANIFEST, which we do
+ # by having Perl spit out the contents of the @src_files
+ # array we've carefully created. After we've added
+ # MANIFEST itself to the array, of course.
+ #
+ src_files.append("MANIFEST")
+ def copy(src, dest):
+ open(dest, 'wb').write(open(src, 'rb').read())
+ return 0
+ env.Command(os.path.join(build, 'MANIFEST'),
+ os.path.join(src, 'MANIFEST.in'),
+ copy)
+
+ #
+ # Use the Python distutils to generate the packages.
+ #
+ archive = os.path.join(build,
+ 'dist',
+ "%s-%s.%s" % (pkg, version, archsuffix))
+
+ src_deps.append(archive)
+
+ build_targets = [
+ os.path.join(build, 'dist', "%s-%s.%s.%s" % (pkg, version, platform, archsuffix)),
+ archive,
+ os.path.join(build, 'dist', "%s-%s.win32.exe" % (pkg, version)),
+ ]
+ install_targets = build_targets
+
+ # We can get away with calling setup.py using a directory path
+ # like this because we put a preamble in it that will chdir()
+ # to the directory in which setup.py exists.
+ bdist_dirs = [
+ os.path.join(build, 'build', 'lib'),
+ os.path.join(build, 'build', 'scripts'),
+ ]
+ setup_py = os.path.join(build, 'setup.py')
+ commands = [
+ "rm -rf %s && python %s bdist" %
+ (string.join(map(lambda x: str(x), bdist_dirs)), setup_py),
+ "python %s sdist" % setup_py,
+ "python %s bdist_wininst" % setup_py,
+ ]
+
+ if rpm:
+ topdir = os.path.join(os.getcwd(), build, 'build',
+ 'bdist.' + platform, 'rpm')
+
+ BUILDdir = os.path.join(topdir, 'BUILD', pkg + '-' + version)
+ RPMSdir = os.path.join(topdir, 'RPMS', 'noarch')
+ SOURCESdir = os.path.join(topdir, 'SOURCES')
+ SPECSdir = os.path.join(topdir, 'SPECS')
+ SRPMSdir = os.path.join(topdir, 'SRPMS')
+
+ specfile = os.path.join(SPECSdir, "%s-%s-1.spec" % (pkg, version))
+ sourcefile = os.path.join(SOURCESdir, "%s-%s.%s" % (pkg, version, archsuffix));
+ rpm = os.path.join(RPMSdir, "%s-%s-1.noarch.rpm" % (pkg, version))
+ src_rpm = os.path.join(SRPMSdir, "%s-%s-1.src.rpm" % (pkg, version))
+
+ env.InstallAs(specfile, os.path.join('rpm', "%s.spec" % pkg))
+ env.InstallAs(sourcefile, archive)
+
+ targets = [ rpm, src_rpm ]
+ cmd = "rpm --define '_topdir %s' -ba $TARGET" % topdir
+ if os.path.isdir(BUILDdir):
+ cmd = "mkdir -p " + BUILDdir + "; " + cmd
+ env.Command(targets, specfile, cmd)
+ env.Depends(targets, sourcefile)
+
+ install_targets.extend(targets)
+
+ build_src_files = map(lambda x, b=build: os.path.join(b, x), src_files)
+
+ if dh_builddeb and fakeroot:
+ # Debian builds directly into build/dist, so we don't
+ # need to add the .debs to the install_targets.
+ deb = os.path.join('build', 'dist', "%s_%s-1.all.deb" % (pkg, version))
+ env.Command(deb, build_src_files, [
+ "fakeroot make -f debian/rules VERSION=$VERSION DH_COMPAT=$DH_COMPAT ENVOKED_BY_CONSTRUCT=1 binary-%s" % pkg,
+ "env DH_COMPAT=$DH_COMPAT dh_clean"
+ ])
+ env.Depends(deb, p['debian_deps'])
+
+
+ #
+ # Now set up creation and installation of the packages.
+ #
+ env.Command(build_targets, build_src_files, commands)
+ env.Install(os.path.join('build', 'dist'), install_targets)
+
+ #
+ # Unpack the archive created by the distutils into build/unpack.
+ #
+ d = os.path.join(unpack_dir, "%s-%s" % (pkg, version))
+ unpack_files = map(lambda x, d=d: os.path.join(d, x), src_files)
+
+ # We'd like to replace the last three lines with the following:
+ #
+ # tar zxf %< -C $unpack_dir
+ #
+ # but that gives heartburn to Cygwin's tar, so work around it
+ # with separate zcat-tar-rm commands.
+ env.Command(unpack_files, archive, [
+ "rm -rf " + os.path.join(unpack_dir, '%s-%s' % (pkg, version)),
+ "zcat $SOURCES > .temp",
+ "tar xf .temp -C %s" % unpack_dir,
+ "rm -f .temp",
+ ])
+
+ #
+ # Run setup.py in the unpacked subdirectory to "install" everything
+ # into our build/test subdirectory. Auxiliary modules that we need
+ # (TestCmd.py, TestSCons.py, unittest.py) will be copied in by
+ # etc/Conscript. The runtest.py script will set PYTHONPATH so that
+ # the tests only look under build/test. This makes sure that our
+ # tests pass with what we really packaged, not because of something
+ # hanging around in the development directory.
+ #
+ # We can get away with calling setup.py using a directory path
+ # like this because we put a preamble in it that will chdir()
+ # to the directory in which setup.py exists.
+ env.Command(dst_files, unpack_files, [
+ "rm -rf %s" % install,
+ "python %s install --prefix=%s" % (os.path.join(unpack_dir,
+ '%s-%s' % (pkg, version),
+ 'setup.py'),
+ prefix
+ ),
+ ])
+
+#
+# Arrange for supporting packages to be installed in the test directories.
+#
+Export('env', 'whereis')
+
+SConscript('etc/SConscript')
+
+#
+# Documentation.
+#
+BuildDir('build/doc', 'doc')
+
+SConscript('build/doc/SConscript');
+
+
+#
+# If we're running in the actual Aegis project, pack up a complete
+# source archive from the project files and files in the change,
+# so we can share it with helpful developers who don't use Aegis.
+#
+# First, lie and say that we've seen any files removed by this
+# change, so they don't get added to the source files list
+# that goes into the archive.
+#
+
+if change:
+ df = []
+ cmd = "aegis -list -unf -c %s cf 2>/dev/null" % change
+ for line in map(lambda x: x[:-1], os.popen(cmd, "r").readlines()):
+ a = string.split(line)
+ if a[1] == "remove":
+ df.append(a[3])
+
+ cmd = "aegis -list -terse pf 2>/dev/null"
+ pf = map(lambda x: x[:-1], os.popen(cmd, "r").readlines())
+ cmd = "aegis -list -terse cf 2>/dev/null"
+ cf = map(lambda x: x[:-1], os.popen(cmd, "r").readlines())
+ u = {}
+ for f in pf + cf:
+ u[f] = 1
+ for f in df:
+ del u[f]
+ src_files = filter(lambda x: x[-9:] != '.aeignore' and x[-7:] != '.consign',
+ u.keys())
+
+ if src_files:
+ ps = "%s-src" % project
+ psv = "%s-src-%s" % (project, version)
+ b_ps = os.path.join('build', ps)
+ b_psv = os.path.join('build', psv)
+
+ for file in src_files:
+ env.Command(os.path.join(b_ps, file), file,
+ [ "$SEDCOM", "chmod --reference=$SOURCE $TARGET" ])
+
+ b_ps_files = map(lambda x, d=b_ps: os.path.join(d, x), src_files)
+ cmds = [
+ "rm -rf %s" % b_psv,
+ "cp -rp %s %s" % (b_ps, b_psv),
+ "find %s -name .consign -exec rm {} \\;" % b_psv,
+ "tar zcf $TARGET -C build %s" % psv,
+ ]
+ env.Command(os.path.join('build',
+ 'dist',
+ '%s-src-%s.tar.gz' % (project, version)),
+ src_deps + b_ps_files, cmds)