summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2005-08-17 19:00:39 (GMT)
committerSteven Knight <knight@baldmt.com>2005-08-17 19:00:39 (GMT)
commitd8075b1a39a6d29bf2724e02a7b27dc35f794b70 (patch)
treedb3f38fb056dd425a3c21fa50b374724c950c692
parentc5eb97dd2c58dc4b93bbe6682631d57febdd96bc (diff)
downloadSCons-d8075b1a39a6d29bf2724e02a7b27dc35f794b70.zip
SCons-d8075b1a39a6d29bf2724e02a7b27dc35f794b70.tar.gz
SCons-d8075b1a39a6d29bf2724e02a7b27dc35f794b70.tar.bz2
Update test infrastructure and ae2cvs utility to latest. Fix runtest.py's swallowing of interrupts. Update various tests.
-rw-r--r--SConstruct4
-rw-r--r--bin/ae2cvs166
-rw-r--r--etc/TestCmd.py174
-rw-r--r--etc/TestCommon.py8
-rw-r--r--runtest.py52
-rw-r--r--test/Fortran/F90PATH.py1
-rw-r--r--test/Options.py18
-rw-r--r--test/Options/PackageOption.py2
-rw-r--r--test/Options/PathOption.py36
-rw-r--r--test/Perforce/Perforce.py30
-rw-r--r--test/RCS/diskcheck.py4
11 files changed, 349 insertions, 146 deletions
diff --git a/SConstruct b/SConstruct
index be557ef..c4c99b3 100644
--- a/SConstruct
+++ b/SConstruct
@@ -247,6 +247,10 @@ def SCons_revision(target, source, env):
revbuilder = Builder(action = Action(SCons_revision,
varlist=['COPYRIGHT', 'VERSION']))
+# When copying local files from a Repository (Aegis),
+# just make copies, don't symlink them.
+SetOption('duplicate', 'copy')
+
env = Environment(
ENV = ENV,
diff --git a/bin/ae2cvs b/bin/ae2cvs
index fd40b41..e7cb22b 100644
--- a/bin/ae2cvs
+++ b/bin/ae2cvs
@@ -1,12 +1,14 @@
#! /usr/bin/env perl
+
+$revision = "src/ae2cvs.pl 0.04.D001 2005/08/14 15:13:36 knight";
+
+$copyright = "Copyright 2001, 2002, 2003, 2004, 2005 Steven Knight.";
+
#
-# Copyright 2001, 2002, 2003 Steven Knight. All rights reserved. This program
-# is free software; you can redistribute and/or modify under the
-# same terms as Perl itself.
+# All rights reserved. This program is free software; you can
+# redistribute and/or modify under the same terms as Perl itself.
#
-$revision = "src/ae2cvs.pl 0.D002 2001/10/03 09:36:49 software";
-
use strict;
use File::Find;
use File::Spec;
@@ -15,15 +17,24 @@ use Pod::Usage ();
use vars qw( @add_list @args @cleanup @copy_list @libraries
@mkdir_list @remove_list
%seen_dir
- $ae_copy $aedir $aedist $cnum $commit $common $cvsmod
+ $ae_copy $aedir $aedist
+ $cnum $comment $commit $common $copyright
+ $cvs_command $cvsmod $cvsroot
$delta $description $exec $help $indent $infile
- $proj $pwd $quiet
+ $proj $pwd $quiet $revision
$summary $usedir $usepath );
$aedist = 1;
+$cvsroot = undef;
$exec = undef;
$indent = "";
+sub version {
+ print "ae2cvs: $revision\n";
+ print "$copyright\n";
+ exit 0;
+}
+
{
use Getopt::Long;
@@ -33,6 +44,7 @@ $indent = "";
"aedist" => sub { $aedist = 1 },
"aegis" => sub { $aedist = 0 },
"change=i" => \$cnum,
+ "d=s" => \$cvsroot,
"file=s" => \$infile,
"help|?" => \$help,
"library=s" => \@libraries,
@@ -41,6 +53,7 @@ $indent = "";
"project=s" => \$proj,
"quiet" => \$quiet,
"usedir=s" => \$usedir,
+ "v|version" => \&version,
"x|execute" => sub { $exec++ if ! defined $exec || $exec != 0 },
"X|EXECUTE" => sub { $exec = 2 if ! defined $exec || $exec != 0 },
);
@@ -50,6 +63,8 @@ $indent = "";
$exec = 0 if ! defined $exec;
}
+$cvs_command = $cvsroot ? "cvs -d $cvsroot -Q" : "cvs -Q";
+
#
# Wrap up the $quiet logic in one place.
#
@@ -116,6 +131,59 @@ sub filter {
}
#
+# Parse a change description, in both 'aegis -l cd" and "aedist" formats.
+#
+# Returns an array containing the project name, the change number
+# (if any), the delta number (if any), the SUMMARY, the DESCRIPTION
+# and the lines describing the files in the change.
+#
+sub parse_change {
+ my $output = shift;
+
+ my ($p, $c, $d, $c_or_d, $sum, $desc, $filesection, @flines);
+
+ # The project name line comes after NAME in "aegis -l cd" format,
+ # and PROJECT in "aedist" format. In both cases, the project name
+ # and the change/delta name are separated a comma.
+ ($p = $output) =~ s/(?:NAME|PROJECT)\n([^\n]*)\n.*/$1/ms;
+ ($p, $c_or_d) = (split(/,/, $p));
+
+ # In "aegis -l cd" format, the project name actually comes after
+ # the string "Project" and is itself enclosed in double quotes.
+ $p =~ s/Project "([^"]*)"/$1/;
+
+ # The change or delta string was the right-hand side of the comma.
+ # "aegis -l cd" format spells it "Change 123." or "Delta 123." while
+ # "aedist" format spells it "change 123."
+ if ($c_or_d =~ /\s*[Cc]hange (\d+).*/) { $c = $1 };
+ if ($c_or_d =~ /\s*[Dd]elta (\d+).*/) { $d = $1 };
+
+ # The SUMMARY line is always followed the DESCRIPTION section.
+ # It seems to always be a single line, but we grab everything in
+ # between just in case.
+ ($sum = $output) =~ s/.*\nSUMMARY\n//ms;
+ $sum =~ s/\nDESCRIPTION\n.*//ms;
+
+ # The DESCRIPTION section is followed ARCHITECTURE in "aegis -l cd"
+ # format and by CAUSE in "aedist" format. Explicitly under it if the
+ # string is only "none," which means they didn't supply a description.
+ ($desc = $output) =~ s/.*\nDESCRIPTION\n//ms;
+ $desc =~ s/\n(ARCHITECTURE|CAUSE)\n.*//ms;
+ chomp($desc);
+ if ($desc eq "none" || $desc eq "none\n") { $desc = undef }
+
+ # The FILES section is followed by HISTORY in "aegis -l cd" format.
+ # It seems to be the last section in "aedist" format, but stripping
+ # a non-existent HISTORY section doesn't hurt.
+ ($filesection = $output) =~ s/.*\nFILES\n//ms;
+ $filesection =~ s/\nHISTORY\n.*//ms;
+
+ @flines = split(/\n/, $filesection);
+
+ ($p, $c, $d, $sum, $desc, \@flines)
+}
+
+#
#
#
$pwd = Cwd::cwd();
@@ -144,15 +212,12 @@ if ($aedist) {
}
my $output = filter("aedist -l -unf", $contents);
+ my ($p, $c, $d, $s, $desc, $fl) = parse_change($output);
- my $filesection;
- if (! defined $proj) {
- ($proj = $output) =~ s/PROJECT\n([^\n]*)\n.*/$1/ms;
- }
- ($summary = $output) =~ s/.*\nSUMMARY\n([^\n]*)\n.*/$1/ms;
- ($description = $output) =~ s/.*\nDESCRIPTION\n([^\n]*)\nCAUSE\n.*/$1/ms;
- ($filesection = $output) =~ s/.*\nFILES\n//ms;
- @filelines = split(/\n/, $filesection);
+ $proj = $p if ! defined $proj;
+ $summary = $s;
+ $description = $desc;
+ @filelines = @$fl;
if (! $exec) {
printit qq(MYTMP="/tmp/ae2cvs-ae.\$\$"\n),
@@ -181,9 +246,10 @@ if ($aedist) {
}
$ae_copy = sub {
- my $dest = shift;
- my $source = File::Spec->catfile($aedir, "src", $dest);
- execute(qq(cp $source $dest));
+ foreach my $dest (@_) {
+ my $source = File::Spec->catfile($aedir, "src", $dest);
+ execute(qq(cp $source $dest));
+ }
}
} else {
$cnum = $ENV{AEGIS_CHANGE} if ! defined $cnum;
@@ -192,24 +258,21 @@ if ($aedist) {
$common = "-lib " . join(" -lib ", @libraries) if @libraries;
$common = "$common -proj $proj" if $proj;
- foreach (`aegis -l ph -unf $common`) {
- chomp;
- if (/^(\d+) .{24} $cnum\s*(.*)/) {
- $delta = $1;
- $summary = $2;
- last;
- }
- }
+ my $output = `aegis -l cd $cnum -unf $common`;
+ my ($p, $c, $d, $s, $desc, $fl) = parse_change($output);
+
+ $delta = $d;
+ $summary = $s;
+ $description = $desc;
+ @filelines = @$fl;
+
if (! $delta) {
- print STDERR "ae2cvs: No change $cnum for project $proj.\n";
- exit 1;
+ print STDERR "ae2cvs: No delta number, exiting.\n";
+ exit 1;
}
- @filelines = `aegis -l cf -unf -c $cnum $common`;
-
$ae_copy = sub {
- my $file = shift;
- execute(qq(aegis -cp -ind -delta $delta $common $file));
+ execute(qq(aegis -cp -ind -delta $delta $common @_));
}
}
@@ -229,7 +292,7 @@ if (! File::Spec->file_name_is_absolute($usepath)) {
if (! -d File::Spec->catfile($usedir, "CVS")) {
$cvsmod = (split(/\./, $proj))[0] if ! defined $cvsmod;
- execute(qq(cvs -Q co $cvsmod));
+ execute(qq($cvs_command co $cvsmod));
_chdir($cvsmod);
@@ -288,7 +351,7 @@ if (@mkdir_list) {
$indent = " ";
}
_mkdir($_);
- execute(qq(cvs -Q add $_));
+ execute(qq($cvs_command add $_));
if (! $exec) {
$indent = "";
printit qq(fi\n);
@@ -300,21 +363,21 @@ if (@mkdir_list) {
}
# Copy in any files in the change, before we try to "cvs add" them.
-for (@copy_list) {
- $ae_copy->($_);
-}
+$ae_copy->(@copy_list) if @copy_list;
if (@add_list) {
- execute(qq(cvs -Q add @add_list));
+ execute(qq($cvs_command add @add_list));
}
if (@remove_list) {
execute(qq(rm -f @remove_list));
- execute(qq(cvs -Q remove @remove_list));
+ execute(qq($cvs_command remove @remove_list));
}
# Last, commit the whole bunch.
-$commit = qq(cvs -Q commit -m "$summary" .);
+$comment = $summary;
+$comment .= "\n" . $description if $description;
+$commit = qq($cvs_command commit -m '$comment' .);
if ($exec == 1) {
printit qq(# Execute the following to commit the changes:\n),
qq(# $commit\n);
@@ -352,12 +415,13 @@ ae2cvs - convert an Aegis change set to CVS commands
=head1 SYNOPSIS
-ae2cvs [-aedist|-aegis] [-c change] [-f file] [-l lib]
- [-m module] [-n] [-p proj] [-q] [-u dir] [-x] [-X]
+ae2cvs [-aedist|-aegis] [-c change] [-d cvs_root] [-f file] [-l lib]
+ [-m module] [-n] [-p proj] [-q] [-u dir] [-v] [-x] [-X]
-aedist use aedist format from input (default)
-aegis query aegis repository directly
-c change change number
+ -d cvs_root CVS root directory
-f file read aedist from file ('-' == stdin)
-l lib Aegis library directory
-m module CVS module
@@ -365,6 +429,7 @@ ae2cvs [-aedist|-aegis] [-c change] [-f file] [-l lib]
-p proj project name
-q quiet, don't print commands
-u dir use dir for CVS checkin
+ -v print version string and exit
-x execute the commands, but don't commit;
two or more -x options commit changes
-X execute the commands and commit changes
@@ -408,6 +473,14 @@ Specify the Aegis change number to be used.
The value of the C<AEGIS_CHANGE> environment variable
is used by default.
+=item -d cvsroot
+
+Specify the CVS root directory to be used.
+This option is passed explicitly to each executed C<cvs> command.
+The default behavior is to omit any C<-d> options
+and let the executed C<cvs> commands use the
+C<CVSROOT> environment variable as they normally would.
+
=item -f file
Reads the aedist change set from the specified C<file>,
@@ -447,6 +520,10 @@ Use the already checked-out CVS tree that exists at C<dir>
for the checkins and commits.
The default is to use a separately-created temporary directory.
+=item -v
+
+Print the version string and exit.
+
=item -x
Execute the commands to bring the CVS repository up to date,
@@ -489,16 +566,13 @@ the time, though, so this needs more investigation.
=head1 TODO
-Add support for the CVS -d option to allow use of a specified
-CVS repository.
-
Add an explicit test for using ae2cvs in the Aegis
integrate_pass_notify_command field to support fully keeping a
repository in sync automatically.
=head1 COPYRIGHT
-Copyright 2001, 2002, 2003 Steven Knight.
+Copyright 2001, 2002, 2003, 2004, 2005 Steven Knight.
=head1 SEE ALSO
diff --git a/etc/TestCmd.py b/etc/TestCmd.py
index e12aa4c..79ec8dc 100644
--- a/etc/TestCmd.py
+++ b/etc/TestCmd.py
@@ -175,8 +175,8 @@ version.
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
__author__ = "Steven Knight <knight at baldmt dot com>"
-__revision__ = "TestCmd.py 0.13.D002 2004/11/20 08:34:16 knight"
-__version__ = "0.13"
+__revision__ = "TestCmd.py 0.15.D001 2005/08/16 17:14:33 knight"
+__version__ = "0.15"
import os
import os.path
@@ -241,14 +241,21 @@ _Cleanup = []
def _clean():
global _Cleanup
- list = _Cleanup[:]
- _Cleanup = []
- list.reverse()
- for test in list:
+ cleanlist = filter(None, _Cleanup)
+ del _Cleanup[:]
+ cleanlist.reverse()
+ for test in cleanlist:
test.cleanup()
sys.exitfunc = _clean
+class Collector:
+ def __init__(self, top):
+ self.entries = [top]
+ def __call__(self, arg, dirname, names):
+ pathjoin = lambda n, d=dirname: os.path.join(d, n)
+ self.entries.extend(map(pathjoin, names))
+
def _caller(tblist, skip):
string = ""
arr = []
@@ -417,7 +424,7 @@ else:
if os.path.isfile(f):
try:
st = os.stat(f)
- except:
+ except OSError:
continue
if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
return f
@@ -634,25 +641,27 @@ class TestCmd:
if self.verbose:
sys.stderr.write("chdir(" + chdir + ")\n")
os.chdir(chdir)
- cmd = None
if program:
if not os.path.isabs(program):
program = os.path.join(self._cwd, program)
- cmd = escape_cmd(program)
- if interpreter:
- cmd = interpreter + " " + cmd
else:
- cmd = escape_cmd(self.program)
- if self.interpreter:
- cmd = self.interpreter + " " + cmd
+ program = self.program
+ if not interpreter:
+ interpreter = self.interpreter
+ cmd = [program]
+ if interpreter:
+ cmd = [interpreter] + cmd
if arguments:
- cmd = cmd + " " + arguments
+ if type(arguments) == type(''):
+ arguments = string.split(arguments)
+ cmd.extend(arguments)
+ cmd_string = string.join(cmd, ' ')
if self.verbose:
- sys.stderr.write(cmd + "\n")
+ sys.stderr.write(cmd_string + "\n")
try:
p = popen2.Popen3(cmd, 1)
except AttributeError:
- (tochild, fromchild, childerr) = os.popen3(cmd)
+ (tochild, fromchild, childerr) = os.popen3(cmd_string)
if stdin:
if is_List(stdin):
for line in stdin:
@@ -748,7 +757,7 @@ class TestCmd:
new = os.path.join(self.workdir, sub)
try:
os.mkdir(new)
- except:
+ except OSError:
pass
else:
count = count + 1
@@ -837,37 +846,124 @@ class TestCmd:
"""
return apply(os.path.join, (self.workdir,) + tuple(args))
- def writable(self, top, write):
+ def readable(self, top, read=1):
+ """Make the specified directory tree readable (read == 1)
+ or not (read == None).
+ """
+
+ if read:
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0400))
+ else:
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0400))
+
+ if os.path.isfile(top):
+ # If it's a file, that's easy, just chmod it.
+ do_chmod(top)
+ elif read:
+ # It's a directory and we're trying to turn on read
+ # permission, so it's also pretty easy, just chmod the
+ # directory and then chmod every entry on our walk down the
+ # tree. Because os.path.walk() is top-down, we'll enable
+ # read permission on any directories that have it disabled
+ # before os.path.walk() tries to list their contents.
+ do_chmod(top)
+
+ def chmod_entries(arg, dirname, names, do_chmod=do_chmod):
+ pathnames = map(lambda n, d=dirname: os.path.join(d, n),
+ names)
+ map(lambda p, do=do_chmod: do(p), pathnames)
+
+ os.path.walk(top, chmod_entries, None)
+ else:
+ # It's a directory and we're trying to turn off read
+ # permission, which means we have to chmod the directoreis
+ # in the tree bottom-up, lest disabling read permission from
+ # the top down get in the way of being able to get at lower
+ # parts of the tree. But os.path.walk() visits things top
+ # down, so we just use an object to collect a list of all
+ # of the entries in the tree, reverse the list, and then
+ # chmod the reversed (bottom-up) list.
+ col = Collector(top)
+ os.path.walk(top, col, None)
+ col.entries.reverse()
+ map(lambda d, do=do_chmod: do(d), col.entries)
+
+ def writable(self, top, write=1):
"""Make the specified directory tree writable (write == 1)
or not (write == None).
"""
- def _walk_chmod(arg, dirname, names):
- st = os.stat(dirname)
- os.chmod(dirname, arg(st[stat.ST_MODE]))
- for name in names:
- n = os.path.join(dirname, name)
- st = os.stat(n)
- os.chmod(n, arg(st[stat.ST_MODE]))
+ if write:
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0200))
+ else:
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0200))
- def _mode_writable(mode):
- return stat.S_IMODE(mode|0200)
+ if os.path.isfile(top):
+ do_chmod(top)
+ else:
+ col = Collector(top)
+ os.path.walk(top, col, None)
+ map(lambda d, do=do_chmod: do(d), col.entries)
- def _mode_non_writable(mode):
- return stat.S_IMODE(mode&~0200)
+ def executable(self, top, execute=1):
+ """Make the specified directory tree executable (execute == 1)
+ or not (execute == None).
+ """
- if write:
- f = _mode_writable
+ if execute:
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0100))
else:
- f = _mode_non_writable
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0100))
+
if os.path.isfile(top):
- st = os.stat(top)
- os.chmod(top, f(st[stat.ST_MODE]))
+ # If it's a file, that's easy, just chmod it.
+ do_chmod(top)
+ elif execute:
+ # It's a directory and we're trying to turn on execute
+ # permission, so it's also pretty easy, just chmod the
+ # directory and then chmod every entry on our walk down the
+ # tree. Because os.path.walk() is top-down, we'll enable
+ # execute permission on any directories that have it disabled
+ # before os.path.walk() tries to list their contents.
+ do_chmod(top)
+
+ def chmod_entries(arg, dirname, names, do_chmod=do_chmod):
+ pathnames = map(lambda n, d=dirname: os.path.join(d, n),
+ names)
+ map(lambda p, do=do_chmod: do(p), pathnames)
+
+ os.path.walk(top, chmod_entries, None)
else:
- try:
- os.path.walk(top, _walk_chmod, f)
- except:
- pass # ignore any problems changing modes
+ # It's a directory and we're trying to turn off execute
+ # permission, which means we have to chmod the directories
+ # in the tree bottom-up, lest disabling execute permission from
+ # the top down get in the way of being able to get at lower
+ # parts of the tree. But os.path.walk() visits things top
+ # down, so we just use an object to collect a list of all
+ # of the entries in the tree, reverse the list, and then
+ # chmod the reversed (bottom-up) list.
+ col = Collector(top)
+ os.path.walk(top, col, None)
+ col.entries.reverse()
+ map(lambda d, do=do_chmod: do(d), col.entries)
def write(self, file, content, mode = 'wb'):
"""Writes the specified content text (second argument) to the
diff --git a/etc/TestCommon.py b/etc/TestCommon.py
index ae57f0c..af3c8a8 100644
--- a/etc/TestCommon.py
+++ b/etc/TestCommon.py
@@ -80,8 +80,8 @@ The TestCommon module also provides the following variables
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
__author__ = "Steven Knight <knight at baldmt dot com>"
-__revision__ = "TestCommon.py 0.13.D001 2004/11/20 08:30:40 knight"
-__version__ = "0.13"
+__revision__ = "TestCommon.py 0.14.D001 2005/08/15 23:02:35 knight"
+__version__ = "0.14"
import os
import os.path
@@ -262,6 +262,8 @@ class TestCommon(TestCmd):
file_contents = self.read(file, mode)
try:
self.fail_test(not self.match(file_contents, expect))
+ except KeyboardInterrupt:
+ raise
except:
print "Unexpected contents of `%s'" % file
print "EXPECTED contents ======"
@@ -338,6 +340,8 @@ class TestCommon(TestCmd):
match = self.match
try:
apply(TestCmd.run, [self], kw)
+ except KeyboardInterrupt:
+ raise
except:
print "STDOUT ============"
print self.stdout()
diff --git a/runtest.py b/runtest.py
index 7f36479..b409ce5 100644
--- a/runtest.py
+++ b/runtest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
#
# runtest.py - wrapper script for running SCons tests
#
@@ -206,6 +206,31 @@ else:
sp.append(cwd)
+#
+_ws = re.compile('\s')
+
+def escape(s):
+ if _ws.search(s):
+ s = '"' + s + '"'
+ return s
+
+# Set up lowest-common-denominator spawning of a process on both Windows
+# and non-Windows systems that works all the way back to Python 1.5.2.
+try:
+ os.spawnv
+except AttributeError:
+ def spawn_it(command_args):
+ pid = os.fork()
+ if pid == 0:
+ os.execv(command_args[0], command_args)
+ else:
+ pid, status = os.waitpid(pid, 0)
+ return status >> 8
+else:
+ def spawn_it(command_args):
+ command_args = map(escape, command_args)
+ return os.spawnv(os.P_WAIT, command_args[0], command_args)
+
class Base:
def __init__(self, path, spe=None):
self.path = path
@@ -220,9 +245,7 @@ class Base:
class SystemExecutor(Base):
def execute(self):
- s = os.system(self.command)
- if s >= 256:
- s = s / 256
+ s = spawn_it(self.command_args)
self.status = s
if s < 0 or s > 2:
sys.stdout.write("Unexpected exit status %d\n" % s)
@@ -232,7 +255,7 @@ try:
except AttributeError:
class PopenExecutor(Base):
def execute(self):
- (tochild, fromchild, childerr) = os.popen3(self.command)
+ (tochild, fromchild, childerr) = os.popen3(self.command_str)
tochild.close()
self.stdout = fromchild.read()
self.stderr = childerr.read()
@@ -243,7 +266,7 @@ except AttributeError:
else:
class PopenExecutor(Base):
def execute(self):
- p = popen2.Popen3(self.command, 1)
+ p = popen2.Popen3(self.command_str, 1)
p.tochild.close()
self.stdout = p.fromchild.read()
self.stderr = p.childerr.read()
@@ -264,7 +287,7 @@ class XML(PopenExecutor):
def write(self, f):
f.write(' <test>\n')
f.write(' <file_name>%s</file_name>\n' % self.path)
- f.write(' <command_line>%s</command_line>\n' % self.command)
+ f.write(' <command_line>%s</command_line>\n' % self.command_str)
f.write(' <exit_status>%s</exit_status>\n' % self.status)
f.write(' <stdout>%s</stdout>\n' % self.stdout)
f.write(' <stderr>%s</stderr>\n' % self.stderr)
@@ -468,17 +491,14 @@ class Unbuffered:
sys.stdout = Unbuffered(sys.stdout)
-_ws = re.compile('\s')
-
-def escape(s):
- if _ws.search(s):
- s = '"' + s + '"'
- return s
-
for t in tests:
- t.command = string.join(map(escape, [python, debug, t.abspath]), " ")
+ t.command_args = [python]
+ if debug:
+ t.command_args.append(debug)
+ t.command_args.append(t.abspath)
+ t.command_str = string.join(map(escape, t.command_args), " ")
if printcommand:
- sys.stdout.write(t.command + "\n")
+ sys.stdout.write(t.command_str + "\n")
t.execute()
passed = filter(lambda t: t.status == 0, tests)
diff --git a/test/Fortran/F90PATH.py b/test/Fortran/F90PATH.py
index 87ddda1..f1fac46 100644
--- a/test/Fortran/F90PATH.py
+++ b/test/Fortran/F90PATH.py
@@ -26,6 +26,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
import os.path
+import string
import sys
import TestSCons
diff --git a/test/Options.py b/test/Options.py
index ecd9aa4..bd827d1 100644
--- a/test/Options.py
+++ b/test/Options.py
@@ -114,19 +114,19 @@ def check(expect):
test.run()
check(['0', '1', cc, string.strip(ccflags + ' -g'), 'v', 'v'])
-test.run(arguments='"RELEASE_BUILD=1"')
+test.run(arguments='RELEASE_BUILD=1')
check(['1', '1', cc, string.strip(ccflags + ' -O -g'), 'v', 'v'])
-test.run(arguments='"RELEASE_BUILD=1" "DEBUG_BUILD=0"')
+test.run(arguments='RELEASE_BUILD=1 DEBUG_BUILD=0')
check(['1', '0', cc, string.strip(ccflags + ' -O'), 'v', 'v'])
-test.run(arguments='"CC=not_a_c_compiler"')
+test.run(arguments='CC=not_a_c_compiler')
check(['0', '1', 'not_a_c_compiler', string.strip(ccflags + ' -g'), 'v', 'v'])
-test.run(arguments='"UNDECLARED=foo"')
+test.run(arguments='UNDECLARED=foo')
check(['0', '1', cc, string.strip(ccflags + ' -g'), 'v', 'v'])
-test.run(arguments='"CCFLAGS=--taco"')
+test.run(arguments='CCFLAGS=--taco')
check(['0', '1', cc, string.strip(ccflags + ' -g'), 'v', 'v'])
test.write('custom.py', """
@@ -137,7 +137,7 @@ RELEASE_BUILD=1
test.run()
check(['1', '0', cc, string.strip(ccflags + ' -O'), 'v', 'v'])
-test.run(arguments='"DEBUG_BUILD=1"')
+test.run(arguments='DEBUG_BUILD=1')
check(['1', '1', cc, string.strip(ccflags + ' -O -g'), 'v', 'v'])
test.run(arguments='-h',
@@ -217,7 +217,7 @@ check(['1','0'])
checkSave('options.saved', { 'RELEASE_BUILD':1, 'DEBUG_BUILD':0})
# Override with command line arguments
-test.run(arguments='"DEBUG_BUILD=3"')
+test.run(arguments='DEBUG_BUILD=3')
check(['1','3'])
checkSave('options.saved', {'RELEASE_BUILD':1, 'DEBUG_BUILD':3})
@@ -265,12 +265,12 @@ check(['0','1'])
checkSave('options.saved', {})
# Now specify one option the same as default and make sure it doesn't write out
-test.run(arguments='"DEBUG_BUILD=1"')
+test.run(arguments='DEBUG_BUILD=1')
check(['0','1'])
checkSave('options.saved', {})
# Now specify same option non-default and make sure only it is written out
-test.run(arguments='"DEBUG_BUILD=0" "LISTOPTION_TEST=a,b"')
+test.run(arguments='DEBUG_BUILD=0 LISTOPTION_TEST=a,b')
check(['0','0'])
checkSave('options.saved',{'DEBUG_BUILD':0, 'LISTOPTION_TEST':'a,b'})
diff --git a/test/Options/PackageOption.py b/test/Options/PackageOption.py
index ca8944d..cc520f7 100644
--- a/test/Options/PackageOption.py
+++ b/test/Options/PackageOption.py
@@ -62,7 +62,7 @@ test.run()
check(['1'])
test.run(arguments='x11=no'); check(['0'])
test.run(arguments='x11=0'); check(['0'])
-test.run(arguments='"x11=%s"' % test.workpath()); check([test.workpath()])
+test.run(arguments=['x11=%s' % test.workpath()]); check([test.workpath()])
test.run(arguments='x11=/non/existing/path/',
stderr = """
diff --git a/test/Options/PathOption.py b/test/Options/PathOption.py
index 55f95c5..d15f39b 100644
--- a/test/Options/PathOption.py
+++ b/test/Options/PathOption.py
@@ -74,27 +74,27 @@ check([qtpath, os.path.join('$qtdir', 'lib'), libpath])
qtpath = os.path.join(workpath, 'qt')
libpath = os.path.join(qtpath, 'lib')
-test.run(arguments='"qtdir=%s"' % qtpath)
+test.run(arguments=['qtdir=%s' % qtpath])
check([qtpath, os.path.join('$qtdir', 'lib'), libpath])
qtpath = workpath
libpath = os.path.join(qtpath, 'nolib')
-test.run(arguments='"qt_libraries=%s"' % libpath)
+test.run(arguments=['qt_libraries=%s' % libpath])
check([qtpath, libpath, libpath])
qtpath = os.path.join(workpath, 'qt')
libpath = os.path.join(workpath, 'nolib')
-test.run(arguments='"qtdir=%s" "qt_libraries=%s"' % (qtpath, libpath))
+test.run(arguments=['qtdir=%s' % qtpath, 'qt_libraries=%s' % libpath])
check([qtpath, libpath, libpath])
qtpath = os.path.join(workpath, 'non', 'existing', 'path')
-test.run(arguments='"qtdir=%s"' % qtpath,
+test.run(arguments=['qtdir=%s' % qtpath],
stderr = """
scons: *** Path for option qtdir does not exist: %s
File "SConstruct", line 12, in ?
""" % qtpath, status=2)
-test.run(arguments='"qt_libraries=%s"' % qtpath,
+test.run(arguments=['qt_libraries=%s' % qtpath],
stderr = """
scons: *** Path for option qt_libraries does not exist: %s
File "SConstruct", line 12, in ?
@@ -132,16 +132,16 @@ Default(env.Alias('dummy', None))
test.run()
check([default_subdir])
-test.run(arguments='"X=%s"' % existing_file)
+test.run(arguments=['X=%s' % existing_file])
check([existing_file])
-test.run(arguments='"X=%s"' % non_existing_file)
+test.run(arguments=['X=%s' % non_existing_file])
check([non_existing_file])
-test.run(arguments='"X=%s"' % existing_subdir)
+test.run(arguments=['X=%s' % existing_subdir])
check([existing_subdir])
-test.run(arguments='"X=%s"' % non_existing_subdir)
+test.run(arguments=['X=%s' % non_existing_subdir])
check([non_existing_subdir])
test.must_not_exist(non_existing_file)
@@ -173,17 +173,17 @@ test.write(default_file, "default_file\n")
test.run()
check([default_file])
-test.run(arguments='"X=%s"' % existing_subdir,
+test.run(arguments=['X=%s' % existing_subdir],
status=2,
stderr="""
scons: *** File path for option X is a directory: %s
File "SConstruct", line 6, in ?
""" % existing_subdir)
-test.run(arguments='"X=%s"' % existing_file)
+test.run(arguments=['X=%s' % existing_file])
check([existing_file])
-test.run(arguments='"X=%s"' % non_existing_file,
+test.run(arguments=['X=%s' % non_existing_file],
status=2,
stderr="""
scons: *** File path for option X does not exist: %s
@@ -216,17 +216,17 @@ test.subdir(default_subdir)
test.run()
check([default_subdir])
-test.run(arguments='"X=%s"' % existing_file,
+test.run(arguments=['X=%s' % existing_file],
status=2,
stderr="""
scons: *** Directory path for option X is a file: %s
File "SConstruct", line 6, in ?
""" % existing_file)
-test.run(arguments='"X=%s"' % existing_subdir)
+test.run(arguments=['X=%s' % existing_subdir])
check([existing_subdir])
-test.run(arguments='"X=%s"' % non_existing_subdir,
+test.run(arguments=['X=%s' % non_existing_subdir],
status=2,
stderr="""
scons: *** Directory path for option X does not exist: %s
@@ -251,17 +251,17 @@ Default(env.Alias('dummy', None))
test.run()
check([default_subdir])
-test.run(arguments='"X=%s"' % existing_file,
+test.run(arguments=['X=%s' % existing_file],
status=2,
stderr="""
scons: *** Path for option X is a file, not a directory: %s
File "SConstruct", line 6, in ?
""" % existing_file)
-test.run(arguments='"X=%s"' % existing_subdir)
+test.run(arguments=['X=%s' % existing_subdir])
check([existing_subdir])
-test.run(arguments='"X=%s"' % non_existing_subdir)
+test.run(arguments=['X=%s' % non_existing_subdir])
check([non_existing_subdir])
test.must_exist(non_existing_subdir)
diff --git a/test/Perforce/Perforce.py b/test/Perforce/Perforce.py
index 891acc3..5d41f8f 100644
--- a/test/Perforce/Perforce.py
+++ b/test/Perforce/Perforce.py
@@ -59,7 +59,8 @@ except TestSCons.TestFailed:
pass # it's okay if this fails...it will fail if the depot is clear already.
# Set up a perforce depot for testing.
-test.write("depotspec","""# A Perforce Depot Specification.
+depotspec = """\
+# A Perforce Depot Specification.
Depot: testme
Owner: %s
@@ -74,13 +75,14 @@ Type: local
Address: subdir
Map: testme/...
-""" % user)
+""" % user
-test.run(program=p4, arguments='-p 1666 depot -i < depotspec')
+test.run(program=p4, arguments='-p 1666 depot -i', stdin = depotspec)
# Now set up 2 clients, one to check in some files, and one to
# do the building.
-clientspec = """# A Perforce Client Specification.
+clientspec = """\
+# A Perforce Client Specification.
Client: %s
Owner: %s
@@ -104,13 +106,11 @@ clientspec1 = clientspec % ("testclient1", user, host, test.workpath('import'),
"//testme/foo/...", "testclient1")
clientspec2 = clientspec % ("testclient2", user, host, test.workpath('work'),
"//testme/...", "testclient2")
-test.write("testclient1", clientspec1)
-test.write("testclient2", clientspec2)
test.subdir('import', ['import', 'sub'], 'work')
-test.run(program=p4, arguments = '-p 1666 client -i < testclient1')
-test.run(program=p4, arguments = '-p 1666 client -i < testclient2')
+test.run(program=p4, arguments = '-p 1666 client -i', stdin=clientspec1)
+test.run(program=p4, arguments = '-p 1666 client -i', stdin=clientspec2)
test.write(['import', 'aaa.in'], "import/aaa.in\n")
test.write(['import', 'bbb.in'], "import/bbb.in\n")
@@ -130,11 +130,13 @@ test.write(['import', 'sub', 'fff.in'], "import/sub/fff.in\n")
# Perforce uses the PWD environment variable in preference to the actual cwd
os.environ["PWD"] = test.workpath('import')
-paths = map(os.path.normpath, [ 'sub/ddd.in', 'sub/eee.in', 'sub/fff.in', 'sub/SConscript' ])
-args = '-p 1666 -c testclient1 add -t binary *.in %s' % string.join(paths)
+paths = [ 'aaa.in', 'bbb.in', 'ccc.in',
+ 'sub/ddd.in', 'sub/eee.in', 'sub/fff.in', 'sub/SConscript' ]
+paths = map(os.path.normpath, paths)
+args = '-p 1666 -c testclient1 add -t binary %s' % string.join(paths)
test.run(program=p4, chdir='import', arguments=args)
-test.write('changespec', """
+changespec = """
Change: new
Client: testclient1
@@ -154,9 +156,11 @@ Files:
//testme/foo/sub/ddd.in # add
//testme/foo/sub/eee.in # add
//testme/foo/sub/fff.in # add
-""" % user)
+""" % user
-test.run(program=p4, arguments='-p 1666 -c testclient1 submit -i < changespec')
+test.run(program=p4,
+ arguments='-p 1666 -c testclient1 submit -i',
+ stdin=changespec)
test.write(['work', 'SConstruct'], """
def cat(env, source, target):
diff --git a/test/RCS/diskcheck.py b/test/RCS/diskcheck.py
index 4a93edf..8af2545 100644
--- a/test/RCS/diskcheck.py
+++ b/test/RCS/diskcheck.py
@@ -117,10 +117,10 @@ test.write(['sub', 'eee.in'], "checked-out sub/eee.in\n")
expect = """\
-scons: warning: Ignoring missing SConscript 'sub/SConscript'
+scons: warning: Ignoring missing SConscript '%s'
File "SConstruct", line 23, in ?
scons: *** Source `aaa.in' not found, needed by target `aaa.out'. Stop.
-"""
+""" % os.path.join('sub', 'SConscript')
test.run(status=2, stderr=expect)