trivial typo in man page
[scons.git] / bin / time-scons.py
index 90c69851251ef16f6a398c8d56c9deaab6b5dfe2..78d26e542fea95852c66fb206a31ebacbbc04437 100644 (file)
@@ -33,11 +33,12 @@ import xml.sax.handler
 SubversionURL = 'http://scons.tigris.org/svn/scons'
 
 
-# This is the earliest revision when the TimeSCons scripts collected
-# "real," stable timings.  If we're timing a revision prior to this,
-# we'll forcibly update the TimeSCons pieces of the tree to this revision
-# to collect consistent timings for earlier revisions.
-TimeSCons_revision = 4547
+# This is the baseline revision when the TimeSCons scripts first
+# stabilized and collected "real," consistent timings.  If we're timing
+# a revision prior to this, we'll forcibly update the TimeSCons pieces
+# of the tree to this revision to collect consistent timings for earlier
+# revisions.
+TimeSCons_revision = 4569
 
 # The pieces of the TimeSCons infrastructure that are necessary to
 # produce consistent timings, even when the rest of the tree is from
@@ -149,10 +150,11 @@ class CommandRunner:
 
         Returns the exit status of the first failed command, or 0 on success.
         """
+        status = 0
         for command in command_list:
-            status = self.run(command, **kw)
-            if status:
-                return status
+            s = self.run(command, **kw)
+            if s and status == 0:
+                status = s
         return 0
 
 
@@ -182,14 +184,14 @@ def get_svn_revisions(branch, revisions=None):
     return sorted(handler.revisions)
 
 
-def script_commands(script):
+def prepare_commands():
     """
-    Returns a list of the commands to be executed to test the specified
-    TimeSCons script.  This involves building SCons (specifically the
-    'tar-gz' Alias that creates and unpacks a SCons .tar.gz package,
-    in order to have the *.py files compiled to *.pyc) after first
-    removing the build directory, and then actually calling runtest.py
-    to run the timing script.
+    Returns a list of the commands to be executed to prepare the tree
+    for testing.  This involves building SCons, specifically the
+    build/scons subdirectory where our packaging build is staged,
+    and then running setup.py to create a local installed copy
+    with compiled *.pyc files.  The build directory gets removed
+    first.
     """
     commands = []
     if os.path.exists('build'):
@@ -197,14 +199,18 @@ def script_commands(script):
             ['mv', 'build', 'build.OLD'],
             ['rm', '-rf', 'build.OLD'],
         ])
-    commands.extend([
-        [sys.executable, 'bootstrap.py', 'tar-gz'],
-        # --noqmtest is necessary for the log to contain the
-        # actual scons output (which qmtest normally swallows).
-        [sys.executable, 'runtest.py', '--noqmtest', '-p', 'tar-gz', script],
-    ])
+    commands.append([sys.executable, 'bootstrap.py', 'build/scons'])
+    commands.append([sys.executable,
+                     'build/scons/setup.py',
+                     'install',
+                     '--prefix=' + os.path.abspath('build/usr')])
     return commands
 
+def script_command(script):
+    """Returns the command to actually invoke the specified timing
+    script using our "built" scons."""
+    return [sys.executable, 'runtest.py', '-x', 'build/usr/bin/scons', script]
+
 def do_revisions(cr, opts, branch, revisions, scripts):
     """
     Time the SCons branch specified scripts through a list of revisions.
@@ -215,10 +221,20 @@ def do_revisions(cr, opts, branch, revisions, scripts):
     stdout = sys.stdout
     stderr = sys.stderr
 
+    status = 0
+
+    if opts.logsdir and not opts.no_exec and len(scripts) > 1:
+        for script in scripts:
+            subdir = os.path.basename(os.path.dirname(script))
+            logsubdir = os.path.join(opts.origin, opts.logsdir, subdir)
+            if not os.path.exists(logsubdir):
+                os.makedirs(logsubdir)
+
     for this_revision in revisions:
 
-        if opts.logfiles:
-            log_file = os.path.join(opts.origin, '%s.log' % this_revision)
+        if opts.logsdir and not opts.no_exec:
+            log_name = '%s.log' % this_revision
+            log_file = os.path.join(opts.origin, opts.logsdir, log_name)
             stdout = open(log_file, 'w')
             stderr = None
 
@@ -230,30 +246,60 @@ def do_revisions(cr, opts, branch, revisions, scripts):
             commands.append(['svn', 'up', '-q', '-r', str(TimeSCons_revision)]
                             + TimeSCons_pieces)
 
+        commands.extend(prepare_commands())
+
+        s = cr.run_list(commands, stdout=stdout, stderr=stderr)
+        if s:
+            if status == 0:
+                status = s
+            continue
+
         for script in scripts:
-            commands.extend(script_commands(script))
+            if opts.logsdir and not opts.no_exec and len(scripts) > 1:
+                subdir = os.path.basename(os.path.dirname(script))
+                lf = os.path.join(opts.origin, opts.logsdir, subdir, log_name)
+                out = open(lf, 'w')
+                err = None
+            else:
+                out = stdout
+                err = stderr
+            s = cr.run(script_command(script), stdout=out, stderr=err)
+            if s and status == 0:
+                status = s
+            if out not in (sys.stdout, None):
+                out.close()
+                out = None
 
         if int(this_revision) < int(TimeSCons_revision):
             # "Revert" the pieces that we previously updated to the
             # TimeSCons_revision, so the update to the next revision
             # works cleanly.
-            commands.append(['svn', 'up', '-q', '-r', str(this_revision)]
-                            + TimeSCons_pieces)
+            command = (['svn', 'up', '-q', '-r', str(this_revision)]
+                       + TimeSCons_pieces)
+            s = cr.run(command, stdout=stdout, stderr=stderr)
+            if s:
+                if status == 0:
+                    status = s
+                continue
+
+        if stdout not in (sys.stdout, None):
+            stdout.close()
+            stdout = None
 
-        status = cr.run_list(commands, stdout=stdout, stderr=stderr)
-        if status:
-            return status
+    return status
 
-    return 0
+Usage = """\
+time-scons.py [-hnq] [-r REVISION ...] [--branch BRANCH]
+              [--logsdir DIR] [--svn] SCRIPT ..."""
 
 def main(argv=None):
     if argv is None:
         argv = sys.argv
 
-    parser = optparse.OptionParser(usage="time-scons.py [-hnq] [-r REVISION ...] [--branch BRANCH] [--svn] SCRIPT ...")
+    parser = optparse.OptionParser(usage=Usage)
     parser.add_option("--branch", metavar="BRANCH", default="trunk",
                       help="time revision on BRANCH")
-    parser.add_option("--logfiles", action="store_true",
+    parser.add_option("--logsdir", metavar="DIR", default='.',
                       help="generate separate log files for each revision")
     parser.add_option("-n", "--no-exec", action="store_true",
                       help="no execute, just print the command line")
@@ -279,9 +325,14 @@ def main(argv=None):
 
     if opts.svn:
         revisions = get_svn_revisions(branch, opts.revision)
-    else:
+    elif opts.revision:
         # TODO(sgk):  parse this for SVN-style revision strings
-        revisions = opts.revision
+        revisions = [opts.revision]
+    else:
+        revisions = None
+
+    if opts.logsdir and not os.path.exists(opts.logsdir):
+        os.makedirs(opts.logsdir)
 
     if revisions:
         opts.origin = os.getcwd()
@@ -293,11 +344,9 @@ def main(argv=None):
             os.chdir(opts.origin)
             shutil.rmtree(tempdir)
     else:
-        for script in scripts:
-            commands = script_commands(script)
-            status = cr.run_list(commands, stdout=sys.stdout, stderr=sys.stderr)
-            if status:
-                return status
+        commands = prepare_commands()
+        commands.extend([ script_command(script) for script in scripts ])
+        status = cr.run_list(commands, stdout=sys.stdout, stderr=sys.stderr)
 
     return status