cc8290deb604d9424f8a157abe1608d8bc68efe2
[scons.git] / SConstruct
1 #
2 # SConstruct file to build scons packages during development.
3 #
4
5 #
6 # Copyright (c) 2001, 2002 Steven Knight
7 #
8 # Permission is hereby granted, free of charge, to any person obtaining
9 # a copy of this software and associated documentation files (the
10 # "Software"), to deal in the Software without restriction, including
11 # without limitation the rights to use, copy, modify, merge, publish,
12 # distribute, sublicense, and/or sell copies of the Software, and to
13 # permit persons to whom the Software is furnished to do so, subject to
14 # the following conditions:
15 #
16 # The above copyright notice and this permission notice shall be included
17 # in all copies or substantial portions of the Software.
18 #
19 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
20 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
21 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 #
27
28 import distutils.util
29 import os
30 import os.path
31 import stat
32 import string
33 import sys
34 import time
35
36 project = 'scons'
37 default_version = '0.08'
38
39 Default('.')
40
41 #
42 # An internal "whereis" routine to figure out if we have a
43 # given program available.  Put it in the "cons::" package
44 # so subsidiary Conscript files can get at it easily, too.
45 #
46
47 def whereis(file):
48     for dir in string.split(os.environ['PATH'], os.pathsep):
49         f = os.path.join(dir, file)
50         if os.path.isfile(f):
51             try:
52                 st = os.stat(f)
53             except:
54                 continue
55             if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
56                 return f
57     return None
58
59 #
60 # We let the presence or absence of various utilities determine
61 # whether or not we bother to build certain pieces of things.
62 # This will allow people to still do SCons work even if they
63 # don't have Aegis or RPM installed, for example.
64 #
65 aegis = whereis('aegis')
66 aesub = whereis('aesub')
67 dh_builddeb = whereis('dh_builddeb')
68 fakeroot = whereis('fakeroot')
69 gzip = whereis('gzip')
70 rpm = whereis('rpm')
71 unzip = whereis('unzip')
72 zip = whereis('zip')
73
74 #
75 # Now grab the information that we "build" into the files (using sed).
76 #
77 try:
78     date = ARGUMENTS['date']
79 except:
80     date = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(time.time()))
81     
82 if ARGUMENTS.has_key('developer'):
83     developer = ARGUMENTS['developer']
84 elif os.environ.has_key('USERNAME'):
85     developer = os.environ['USERNAME']
86 elif os.environ.has_key('LOGNAME'):
87     developer = os.environ['LOGNAME']
88 elif os.environ.has_key('USER'):
89     developer = os.environ['USER']
90
91 try:
92     revision = ARGUMENTS['version']
93 except:
94     if aesub:
95         revision = os.popen(aesub + " \\$version", "r").read()[:-1]
96     else:
97         revision = default_version
98
99 a = string.split(revision, '.')
100 arr = [a[0]]
101 for s in a[1:]:
102     if len(s) == 1:
103         s = '0' + s
104     arr.append(s)
105 revision = string.join(arr, '.')
106
107 # Here's how we'd turn the calculated $revision into our package $version.
108 # This makes it difficult to coordinate with other files (debian/changelog
109 # and rpm/scons.spec) that hard-code the version number, so just go with
110 # the flow for now and hard code it here, too.
111 #if len(arr) >= 2:
112 #    arr = arr[:-1]
113 #def xxx(str):
114 #    if str[0] == 'C' or str[0] == 'D':
115 #        str = str[1:]
116 #    while len(str) > 2 and str[0] == '0':
117 #        str = str[1:]
118 #    return str
119 #arr = map(lambda x, xxx=xxx: xxx(x), arr)
120 #version = string.join(arr, '.')
121 version = default_version
122
123 try:
124     change = ARGUMENTS['change']
125 except:
126     if aesub:
127         change = os.popen(aesub + " \\$change", "r").read()[:-1]
128     else:
129         change = default_version
130
131 python_ver = sys.version[0:3]
132
133 platform = distutils.util.get_platform()
134
135 ENV = { 'PATH' : os.environ['PATH'] }
136 for key in ['AEGIS_PROJECT', 'PYTHONPATH']:
137     if os.environ.has_key(key):
138         ENV[key] = os.environ[key]
139
140 lib_project = os.path.join("lib", project)
141
142 unpack_tar_gz_dir = os.path.join(os.getcwd(), "build", "unpack-tar-gz")
143
144 unpack_zip_dir = os.path.join(os.getcwd(), "build", "unpack-zip")
145
146 test_tar_gz_dir = os.path.join(os.getcwd(), "build", "test-tar-gz")
147 test_src_tar_gz_dir = os.path.join(os.getcwd(), "build", "test-src-tar-gz")
148
149 test_zip_dir = os.path.join(os.getcwd(), "build", "test-zip")
150 test_src_zip_dir = os.path.join(os.getcwd(), "build", "test-src-zip")
151
152 test_rpm_dir = os.path.join(os.getcwd(), "build", "test-rpm")
153
154 test_deb_dir = os.path.join(os.getcwd(), "build", "test-deb")
155
156 if platform == "win32":
157     tar_hflag = ''
158     python_project_subinst_dir = None
159     project_script_subinst_dir = 'Scripts'
160 else:
161     tar_hflag = 'h'
162     python_project_subinst_dir = lib_project
163     project_script_subinst_dir = 'bin'
164
165
166 zcat = 'gzip -d -c'
167     
168 #
169 # Figure out if we can handle .zip files.
170 #
171 try:
172     import zipfile
173
174     def zipit(env, target, source):
175         print "Zipping %s:" % str(target[0])
176         def visit(arg, dirname, names):
177             for name in names:
178                 path = os.path.join(dirname, name)
179                 if os.path.isfile(path):
180                     arg.write(path)
181         zf = zipfile.ZipFile(str(target[0]), 'w')
182         os.chdir('build')
183         os.path.walk(env['PSV'], visit, zf)
184         os.chdir('..')
185         zf.close()
186
187     def unzipit(env, target, source):
188         print "Unzipping %s:" % str(source[0])
189         zf = zipfile.ZipFile(str(source[0]), 'r')
190         for name in zf.namelist():
191             dest = os.path.join(env['UNPACK_ZIP_DIR'], name)
192             dir = os.path.dirname(dest)
193             try:
194                 os.makedirs(dir)
195             except:
196                 pass
197             print dest,name
198             # if the file exists, then delete it before writing
199             # to it so that we don't end up trying to write to a symlink:
200             if os.path.isfile(dest) or os.path.islink(dest):
201                 os.unlink(dest)
202             if not os.path.isdir(dest):
203                 open(dest, 'w').write(zf.read(name))
204
205 except:
206     if unzip and zip:
207         zipit = "cd build && $ZIP $ZIPFLAGS dist/${TARGET.file} $PSV"
208         unzipit = "$UNZIP $UNZIPFLAGS $SOURCES"
209
210 def SCons_revision(target, source, env):
211     """Interpolate specific values from the environment into a file.
212     
213     This is used to copy files into a tree that gets packaged up
214     into the source file package.
215     """
216     t = str(target[0])
217     s = str(source[0])
218     # Note:  We don't use $VERSION from the environment so that
219     # this routine will change when the version number changes
220     # and things will get rebuilt properly.
221     global version
222     print "SCons_revision() < %s > %s" % (s, t)
223     inf = open(s, 'rb')
224     outf = open(t, 'wb')
225     for line in inf.readlines():
226         # Note:  We construct the __*__ substitution strings here
227         # so that they don't get replaced when this file gets
228         # copied into the tree for packaging.
229         line = string.replace(line, '_' + '_DATE__', env['DATE'])
230         line = string.replace(line, '_' + '_DEVELOPER__', env['DEVELOPER'])
231         line = string.replace(line, '_' + '_FILE__', s)
232         line = string.replace(line, '_' + '_REVISION__', env['REVISION'])
233         line = string.replace(line, '_' + '_VERSION__', version)
234         outf.write(line)
235     inf.close()
236     outf.close()
237     os.chmod(t, os.stat(s)[0])
238
239 revbuilder = Builder(name = 'SCons_revision', action = SCons_revision)
240
241 env = Environment(
242                    ENV                 = ENV,
243  
244                    DATE                = date,
245                    DEVELOPER           = developer,
246                    REVISION            = revision,
247                    VERSION             = version,
248                    DH_COMPAT           = 2,
249
250                    TAR_HFLAG           = tar_hflag,
251
252                    ZIP                 = zip,
253                    ZIPFLAGS            = '-r',
254                    UNZIP               = unzip,
255                    UNZIPFLAGS          = '-o -d $UNPACK_ZIP_DIR',
256
257                    ZCAT                = zcat,
258
259                    TEST_DEB_DIR        = test_deb_dir,
260                    TEST_RPM_DIR        = test_rpm_dir,
261                    TEST_SRC_TAR_GZ_DIR = test_src_tar_gz_dir,
262                    TEST_SRC_ZIP_DIR    = test_src_zip_dir,
263                    TEST_TAR_GZ_DIR     = test_tar_gz_dir,
264                    TEST_ZIP_DIR        = test_zip_dir,
265
266                    UNPACK_TAR_GZ_DIR   = unpack_tar_gz_dir,
267                    UNPACK_ZIP_DIR      = unpack_zip_dir,
268
269                    BUILDERS            = [ revbuilder ],
270                  )
271
272 #
273 # Define SCons packages.
274 #
275 # In the original, more complicated packaging scheme, we were going
276 # to have separate packages for:
277 #
278 #       python-scons    only the build engine
279 #       scons-script    only the script
280 #       scons           the script plus the build engine
281 #
282 # We're now only delivering a single "scons" package, but this is still
283 # "built" as two sub-packages (the build engine and the script), so
284 # the definitions remain here, even though we're not using them for
285 # separate packages.
286 #
287
288 python_scons = {
289         'pkg'           : 'python-' + project,
290         'src_subdir'    : 'engine',
291         'inst_subdir'   : os.path.join('lib', 'python1.5', 'site-packages'),
292
293         'debian_deps'   : [
294                             'debian/changelog',
295                             'debian/control',
296                             'debian/copyright',
297                             'debian/dirs',
298                             'debian/docs',
299                             'debian/postinst',
300                             'debian/prerm',
301                             'debian/rules',
302                           ],
303
304         'files'         : [ 'LICENSE.txt',
305                             'README.txt',
306                             'setup.cfg',
307                             'setup.py',
308                           ],
309
310         'filemap'       : {
311                             'LICENSE.txt' : '../LICENSE.txt'
312                           },
313 }
314
315 #
316 # The original packaging scheme would have have required us to push
317 # the Python version number into the package name (python1.5-scons,
318 # python2.0-scons, etc.), which would have required a definition
319 # like the following.  Leave this here in case we ever decide to do
320 # this in the future, but note that this would require some modification
321 # to src/engine/setup.py before it would really work.
322 #
323 #python2_scons = {
324 #        'pkg'          : 'python2-' + project,
325 #        'src_subdir'   : 'engine',
326 #        'inst_subdir'  : os.path.join('lib', 'python2.1', 'site-packages'),
327 #
328 #        'debian_deps'  : [
329 #                            'debian/changelog',
330 #                            'debian/control',
331 #                            'debian/copyright',
332 #                            'debian/dirs',
333 #                            'debian/docs',
334 #                            'debian/postinst',
335 #                            'debian/prerm',
336 #                            'debian/rules',
337 #                          ],
338 #
339 #        'files'        : [
340 #                            'LICENSE.txt',
341 #                            'README.txt',
342 #                            'setup.cfg',
343 #                            'setup.py',
344 #                          ],
345 #        'filemap'      : {
346 #                            'LICENSE.txt' : '../LICENSE.txt',
347 #                          },
348 #}
349 #
350
351 scons_script = {
352         'pkg'           : project + '-script',
353         'src_subdir'    : 'script',
354         'inst_subdir'   : 'bin',
355
356         'debian_deps'   : [
357                             'debian/changelog',
358                             'debian/control',
359                             'debian/copyright',
360                             'debian/dirs',
361                             'debian/docs',
362                             'debian/postinst',
363                             'debian/prerm',
364                             'debian/rules',
365                           ],
366
367         'files'         : [
368                             'LICENSE.txt',
369                             'README.txt',
370                             'setup.cfg',
371                             'setup.py',
372                           ],
373
374         'filemap'       : {
375                             'LICENSE.txt' : '../LICENSE.txt',
376                             'scons'       : 'scons.py',
377                            }
378 }
379
380 scons = {
381         'pkg'           : project,
382
383         'debian_deps'   : [ 
384                             'debian/changelog',
385                             'debian/control',
386                             'debian/copyright',
387                             'debian/dirs',
388                             'debian/docs',
389                             'debian/postinst',
390                             'debian/prerm',
391                             'debian/rules',
392                           ],
393
394         'files'         : [ 
395                             'CHANGES.txt',
396                             'LICENSE.txt',
397                             'README.txt',
398                             'RELEASE.txt',
399                             'os_spawnv_fix.diff',
400                             'scons.1',
401                             'script/scons.bat',
402                             'setup.cfg',
403                             'setup.py',
404                           ],
405
406         'filemap'       : {
407                             'scons.1' : '../doc/man/scons.1',
408                           },
409
410         'subpkgs'       : [ python_scons, scons_script ],
411
412         'subinst_dirs'  : {
413                              'python-' + project : python_project_subinst_dir,
414                              project + '-script' : project_script_subinst_dir,
415                            },
416 }
417
418 src_deps = []
419 src_files = []
420
421 for p in [ scons ]:
422     #
423     # Initialize variables with the right directories for this package.
424     #
425     pkg = p['pkg']
426     pkg_version = "%s-%s" % (pkg, version)
427
428     src = 'src'
429     if p.has_key('src_subdir'):
430         src = os.path.join(src, p['src_subdir'])
431
432     build = os.path.join('build', pkg)
433
434     tar_gz = os.path.join(build, 'dist', "%s.tar.gz" % pkg_version)
435     platform_tar_gz = os.path.join(build,
436                                    'dist',
437                                    "%s.%s.tar.gz" % (pkg_version, platform))
438     zip = os.path.join(build, 'dist', "%s.zip" % pkg_version)
439     platform_zip = os.path.join(build,
440                                 'dist',
441                                 "%s.%s.zip" % (pkg_version, platform))
442     win32_exe = os.path.join(build, 'dist', "%s.win32.exe" % pkg_version)
443
444     #
445     # Update the environment with the relevant information
446     # for this package.
447     #
448     # We can get away with calling setup.py using a directory path
449     # like this because we put a preamble in it that will chdir()
450     # to the directory in which setup.py exists.
451     #
452     env.Update(PKG = pkg,
453                PKG_VERSION = pkg_version,
454                SETUP_PY = os.path.join(build, 'setup.py'))
455
456     #
457     # Read up the list of source files from our MANIFEST.in.
458     # This list should *not* include LICENSE.txt, MANIFEST,
459     # README.txt, or setup.py.  Make a copy of the list for the
460     # destination files.
461     #
462     src_files = map(lambda x: x[:-1],
463                     open(os.path.join(src, 'MANIFEST.in')).readlines())
464     dst_files = src_files[:]
465
466     MANIFEST_in_list = []
467
468     if p.has_key('subpkgs'):
469         #
470         # This package includes some sub-packages.  Read up their
471         # MANIFEST.in files, and add them to our source and destination
472         # file lists, modifying them as appropriate to add the
473         # specified subdirs.
474         #
475         for sp in p['subpkgs']:
476             ssubdir = sp['src_subdir']
477             isubdir = p['subinst_dirs'][sp['pkg']]
478             MANIFEST_in = os.path.join(src, ssubdir, 'MANIFEST.in')
479             MANIFEST_in_list.append(MANIFEST_in)
480             f = map(lambda x: x[:-1], open(MANIFEST_in).readlines())
481             src_files.extend(map(lambda x, s=ssubdir: os.path.join(s, x), f))
482             if isubdir:
483                 f = map(lambda x, i=isubdir: os.path.join(i, x), f)
484             dst_files.extend(f)
485             for k in sp['filemap'].keys():
486                 f = sp['filemap'][k]
487                 if f:
488                     k = os.path.join(sp['src_subdir'], k)
489                     p['filemap'][k] = os.path.join(sp['src_subdir'], f)
490
491     #
492     # Now that we have the "normal" source files, add those files
493     # that are standard for each distribution.  Note that we don't
494     # add these to dst_files, because they don't get installed.
495     # And we still have the MANIFEST to add.
496     #
497     src_files.extend(p['files'])
498
499     #
500     # Now run everything in src_file through the sed command we
501     # concocted to expand __FILE__, __VERSION__, etc.
502     #
503     for b in src_files:
504         s = p['filemap'].get(b, b)
505         env.SCons_revision(os.path.join(build, b), os.path.join(src, s))
506
507     #
508     # NOW, finally, we can create the MANIFEST, which we do
509     # by having Python spit out the contents of the src_files
510     # array we've carefully created.  After we've added
511     # MANIFEST itself to the array, of course.
512     #
513     src_files.append("MANIFEST")
514     MANIFEST_in_list.append(os.path.join(src, 'MANIFEST.in'))
515
516     def copy(target, source, **kw):
517         global src_files
518         src_files.sort()
519         f = open(str(target[0]), 'wb')
520         for file in src_files:
521             f.write(file + "\n")
522         f.close()
523         return 0
524     env.Command(os.path.join(build, 'MANIFEST'), MANIFEST_in_list, copy)
525
526     #
527     # Now go through and arrange to create whatever packages we can.
528     #
529     build_src_files = map(lambda x, b=build: os.path.join(b, x), src_files)
530
531     distutils_formats = []
532
533     distutils_targets = [ win32_exe ]
534
535     install_targets = distutils_targets[:]
536
537     if gzip:
538
539         distutils_formats.append('gztar')
540
541         src_deps.append(tar_gz)
542
543         distutils_targets.extend([ tar_gz, platform_tar_gz ])
544         install_targets.extend([ tar_gz, platform_tar_gz ])
545
546         #
547         # Unpack the tar.gz archive created by the distutils into
548         # build/unpack-tar-gz/scons-{version}.
549         #
550         # We'd like to replace the last three lines with the following:
551         #
552         #       tar zxf $SOURCES -C $UNPACK_TAR_GZ_DIR
553         #
554         # but that gives heartburn to Cygwin's tar, so work around it
555         # with separate zcat-tar-rm commands.
556         #
557         unpack_tar_gz_files = map(lambda x, u=unpack_tar_gz_dir, pv=pkg_version:
558                                          os.path.join(u, pv, x),
559                                   src_files)
560         env.Command(unpack_tar_gz_files, tar_gz, [
561                     "rm -rf %s" % os.path.join(unpack_tar_gz_dir, pkg_version),
562                     "$ZCAT $SOURCES > .temp",
563                     "tar xf .temp -C $UNPACK_TAR_GZ_DIR",
564                     "rm -f .temp",
565         ])
566     
567         #
568         # Run setup.py in the unpacked subdirectory to "install" everything
569         # into our build/test subdirectory.  The runtest.py script will set
570         # PYTHONPATH so that the tests only look under build/test-{package},
571         # and under etc (for the testing modules TestCmd.py, TestSCons.py,
572         # and unittest.py).  This makes sure that our tests pass with what
573         # we really packaged, not because of something hanging around in
574         # the development directory.
575         #
576         # We can get away with calling setup.py using a directory path
577         # like this because we put a preamble in it that will chdir()
578         # to the directory in which setup.py exists.
579         #
580         dfiles = map(lambda x, d=test_tar_gz_dir: os.path.join(d, x), dst_files)
581         env.Command(dfiles, unpack_tar_gz_files, [
582             "rm -rf %s" % os.path.join(unpack_tar_gz_dir, pkg_version, 'build'),
583             "rm -rf $TEST_TAR_GZ_DIR",
584             "python %s install --prefix=$TEST_TAR_GZ_DIR" % \
585                 os.path.join(unpack_tar_gz_dir, pkg_version, 'setup.py'),
586         ])
587
588     if zipit:
589
590         distutils_formats.append('zip')
591
592         src_deps.append(zip)
593
594         distutils_targets.extend([ zip, platform_zip ])
595         install_targets.extend([ zip, platform_zip ])
596
597         #
598         # Unpack the zip archive created by the distutils into
599         # build/unpack-zip/scons-{version}.
600         #
601         unpack_zip_files = map(lambda x, u=unpack_zip_dir, pv=pkg_version:
602                                       os.path.join(u, pv, x),
603                                src_files)
604
605         env.Command(unpack_zip_files, zip, unzipit)
606
607         #
608         # Run setup.py in the unpacked subdirectory to "install" everything
609         # into our build/test subdirectory.  The runtest.py script will set
610         # PYTHONPATH so that the tests only look under build/test-{package},
611         # and under etc (for the testing modules TestCmd.py, TestSCons.py,
612         # and unittest.py).  This makes sure that our tests pass with what
613         # we really packaged, not because of something hanging around in
614         # the development directory.
615         #
616         # We can get away with calling setup.py using a directory path
617         # like this because we put a preamble in it that will chdir()
618         # to the directory in which setup.py exists.
619         #
620         dfiles = map(lambda x, d=test_zip_dir: os.path.join(d, x), dst_files)
621         env.Command(dfiles, unpack_zip_files, [
622             "rm -rf %s" % os.path.join(unpack_zip_dir, pkg_version, 'build'),
623             "rm -rf $TEST_ZIP_DIR",
624             "python %s install --prefix=$TEST_ZIP_DIR" % \
625                 os.path.join(unpack_zip_dir, pkg_version, 'setup.py'),
626         ])
627
628     if rpm:
629         topdir = os.path.join(os.getcwd(), build, 'build',
630                               'bdist.' + platform, 'rpm')
631
632         BUILDdir = os.path.join(topdir, 'BUILD', pkg + '-' + version)
633         RPMSdir = os.path.join(topdir, 'RPMS', 'noarch')
634         SOURCESdir = os.path.join(topdir, 'SOURCES')
635         SPECSdir = os.path.join(topdir, 'SPECS')
636         SRPMSdir = os.path.join(topdir, 'SRPMS')
637
638         specfile = os.path.join(SPECSdir, "%s-1.spec" % pkg_version)
639         sourcefile = os.path.join(SOURCESdir, "%s.tar.gz" % pkg_version);
640         rpm = os.path.join(RPMSdir, "%s-1.noarch.rpm" % pkg_version)
641         src_rpm = os.path.join(SRPMSdir, "%s-1.src.rpm" % pkg_version)
642
643         env.InstallAs(specfile, os.path.join('rpm', "%s.spec" % pkg))
644         env.InstallAs(sourcefile, tar_gz)
645
646         targets = [ rpm, src_rpm ]
647         cmd = "rpm --define '_topdir $(%s$)' -ba $SOURCES" % topdir
648         if not os.path.isdir(BUILDdir):
649             cmd = ("$( mkdir -p %s; $)" % BUILDdir) + cmd
650         env.Command(targets, specfile, cmd)
651         env.Depends(targets, sourcefile)
652
653         install_targets.extend(targets)
654
655         dfiles = map(lambda x, d=test_rpm_dir: os.path.join(d, 'usr', x),
656                      dst_files)
657         env.Command(dfiles,
658                     rpm,
659                     "rpm2cpio $SOURCES | (cd $TEST_RPM_DIR && cpio -id)")
660
661     if dh_builddeb and fakeroot:
662         # Our Debian packaging builds directly into build/dist,
663         # so we don't need to add the .debs to install_targets.
664         deb = os.path.join('build', 'dist', "%s_%s-1_all.deb" % (pkg, version))
665         for d in p['debian_deps']:
666             b = env.SCons_revision(os.path.join(build, d), d)
667             env.Depends(deb, b)
668         env.Command(deb, build_src_files, [
669             "cd %s && fakeroot make -f debian/rules PYTHON=python BUILDDEB_OPTIONS=--destdir=../../build/dist binary" % build,
670                     ])
671
672         old = os.path.join('lib', 'scons', '')
673         new = os.path.join('lib', 'python2.1', 'site-packages', '')
674         def xxx(s, old=old, new=new):
675             if s[:len(old)] == old:
676                 s = new + s[len(old):]
677             return os.path.join('usr', s)
678         dfiles = map(lambda x, t=test_deb_dir: os.path.join(t, x),
679                      map(xxx, dst_files))
680         env.Command(dfiles,
681                     deb,
682                     "dpkg --fsys-tarfile $SOURCES | (cd $TEST_DEB_DIR && tar -xf -)")
683
684     #
685     # Use the Python distutils to generate the appropriate packages.
686     #
687     commands = [
688         "rm -rf %s" % os.path.join(build, 'build', 'lib'),
689         "rm -rf %s" % os.path.join(build, 'build', 'scripts'),
690     ]
691
692     if distutils_formats:
693         commands.append("rm -rf %s" % os.path.join(build,
694                                                    'build',
695                                                    'bdist.' + platform,
696                                                    'dumb'))
697         for format in distutils_formats:
698             commands.append("python $SETUP_PY bdist_dumb -f %s" % format)
699
700         commands.append("python $SETUP_PY sdist --formats=%s" %  \
701                             string.join(distutils_formats, ','))
702
703     commands.append("python $SETUP_PY bdist_wininst")
704
705     env.Command(distutils_targets, build_src_files, commands)
706
707     #
708     # And, lastly, install the appropriate packages in the
709     # appropriate subdirectory.
710     #
711     env.Install(os.path.join('build', 'dist'), install_targets)
712
713 #
714 #
715 #
716 Export('env')
717
718 SConscript('etc/SConscript')
719
720 #
721 # Documentation.
722 #
723 BuildDir('build/doc', 'doc')
724
725 Export('env', 'whereis')
726
727 SConscript('build/doc/SConscript')
728
729 #
730 # If we're running in the actual Aegis project, pack up a complete
731 # source archive from the project files and files in the change,
732 # so we can share it with helpful developers who don't use Aegis.
733 #
734
735 if change:
736     df = []
737     cmd = "aegis -list -unf -c %s cf 2>/dev/null" % change
738     for line in map(lambda x: x[:-1], os.popen(cmd, "r").readlines()):
739         a = string.split(line)
740         if a[1] == "remove":
741             df.append(a[-1])
742
743     cmd = "aegis -list -terse pf 2>/dev/null"
744     pf = map(lambda x: x[:-1], os.popen(cmd, "r").readlines())
745     cmd = "aegis -list -terse cf 2>/dev/null"
746     cf = map(lambda x: x[:-1], os.popen(cmd, "r").readlines())
747     u = {}
748     for f in pf + cf:
749         u[f] = 1
750     for f in df:
751         del u[f]
752     sfiles = filter(lambda x: x[-9:] != '.aeignore' and x[-9:] != '.sconsign',
753                     u.keys())
754
755     if sfiles:
756         ps = "%s-src" % project
757         psv = "%s-%s" % (ps, version)
758         b_ps = os.path.join('build', ps)
759         b_psv = os.path.join('build', psv)
760         b_psv_stamp = b_psv + '-stamp'
761
762         src_tar_gz = os.path.join('build', 'dist', '%s.tar.gz' % psv)
763         src_zip = os.path.join('build', 'dist', '%s.zip' % psv)
764
765         for file in sfiles:
766             env.SCons_revision(os.path.join(b_ps, file), file)
767
768         b_ps_files = map(lambda x, d=b_ps: os.path.join(d, x), sfiles)
769         cmds = [
770             "rm -rf %s" % b_psv,
771             "cp -rp %s %s" % (b_ps, b_psv),
772             "find %s -name .sconsign -exec rm {} \\;" % b_psv,
773             "touch $TARGET",
774         ]
775
776         env.Command(b_psv_stamp, src_deps + b_ps_files, cmds)
777
778         if gzip:
779
780             env.Command(src_tar_gz, b_psv_stamp,
781                         "tar cz${TAR_HFLAG} -f $TARGET -C build %s" % psv)
782     
783             #
784             # Unpack the archive into build/unpack/scons-{version}.
785             #
786             unpack_tar_gz_files = map(lambda x, u=unpack_tar_gz_dir, psv=psv:
787                                              os.path.join(u, psv, x),
788                                       sfiles)
789     
790             #
791             # We'd like to replace the last three lines with the following:
792             #
793             #   tar zxf $SOURCES -C $UNPACK_TAR_GZ_DIR
794             #
795             # but that gives heartburn to Cygwin's tar, so work around it
796             # with separate zcat-tar-rm commands.
797             env.Command(unpack_tar_gz_files, src_tar_gz, [
798                 "rm -rf %s" % os.path.join(unpack_tar_gz_dir, psv),
799                 "$ZCAT $SOURCES > .temp",
800                 "tar xf .temp -C $UNPACK_TAR_GZ_DIR",
801                 "rm -f .temp",
802             ])
803     
804             #
805             # Run setup.py in the unpacked subdirectory to "install" everything
806             # into our build/test subdirectory.  The runtest.py script will set
807             # PYTHONPATH so that the tests only look under build/test-{package},
808             # and under etc (for the testing modules TestCmd.py, TestSCons.py,
809             # and unittest.py).  This makes sure that our tests pass with what
810             # we really packaged, not because of something hanging around in
811             # the development directory.
812             #
813             # We can get away with calling setup.py using a directory path
814             # like this because we put a preamble in it that will chdir()
815             # to the directory in which setup.py exists.
816             #
817             dfiles = map(lambda x, d=test_src_tar_gz_dir: os.path.join(d, x),
818                             dst_files)
819             ENV = env.Dictionary('ENV')
820             ENV['SCONS_LIB_DIR'] = os.path.join(unpack_tar_gz_dir, psv, 'src', 'engine')
821             ENV['USERNAME'] = developer
822             env.Copy(ENV = ENV).Command(dfiles, unpack_tar_gz_files, [
823                 "rm -rf %s" % os.path.join(unpack_tar_gz_dir,
824                                            psv,
825                                            'build',
826                                            'scons',
827                                            'build'),
828                 "rm -rf $TEST_SRC_TAR_GZ_DIR",
829                 "cd %s && python %s %s" % \
830                     (os.path.join(unpack_tar_gz_dir, psv),
831                      os.path.join('src', 'script', 'scons.py'),
832                      os.path.join('build', 'scons')),
833                 "python %s install --prefix=$TEST_SRC_TAR_GZ_DIR" % \
834                     os.path.join(unpack_tar_gz_dir,
835                                  psv,
836                                  'build',
837                                  'scons',
838                                  'setup.py'),
839             ])
840
841         if zipit:
842
843             env.Copy(PSV = psv).Command(src_zip, b_psv_stamp, zipit)
844     
845             #
846             # Unpack the archive into build/unpack/scons-{version}.
847             #
848             unpack_zip_files = map(lambda x, u=unpack_zip_dir, psv=psv:
849                                              os.path.join(u, psv, x),
850                                       sfiles)
851     
852             env.Command(unpack_zip_files, src_zip, unzipit)
853     
854             #
855             # Run setup.py in the unpacked subdirectory to "install" everything
856             # into our build/test subdirectory.  The runtest.py script will set
857             # PYTHONPATH so that the tests only look under build/test-{package},
858             # and under etc (for the testing modules TestCmd.py, TestSCons.py,
859             # and unittest.py).  This makes sure that our tests pass with what
860             # we really packaged, not because of something hanging around in
861             # the development directory.
862             #
863             # We can get away with calling setup.py using a directory path
864             # like this because we put a preamble in it that will chdir()
865             # to the directory in which setup.py exists.
866             #
867             dfiles = map(lambda x, d=test_src_zip_dir: os.path.join(d, x),
868                             dst_files)
869             ENV = env.Dictionary('ENV')
870             ENV['SCONS_LIB_DIR'] = os.path.join(unpack_zip_dir, psv, 'src', 'engine')
871             ENV['USERNAME'] = developer
872             env.Copy(ENV = ENV).Command(dfiles, unpack_zip_files, [
873                 "rm -rf %s" % os.path.join(unpack_zip_dir,
874                                            psv,
875                                            'build',
876                                            'scons',
877                                            'build'),
878                 "rm -rf $TEST_SRC_ZIP_DIR",
879                 "cd %s && python %s %s" % \
880                     (os.path.join(unpack_zip_dir, psv),
881                      os.path.join('src', 'script', 'scons.py'),
882                      os.path.join('build', 'scons')),
883                 "python %s install --prefix=$TEST_SRC_ZIP_DIR" % \
884                     os.path.join(unpack_zip_dir,
885                                  psv,
886                                  'build',
887                                  'scons',
888                                  'setup.py'),
889             ])