Boost logo

Boost-Commit :

From: dave_at_[hidden]
Date: 2007-12-07 14:44:27


Author: dave
Date: 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
New Revision: 41833
URL: http://svn.boost.org/trac/boost/changeset/41833

Log:
A large checkin (mea culpa)!

regression/src/failure_markup.py:
regression/src/bitten_reports.py:
regression/src/collect_and_upload_logs.py:
regression/src/run.py:
* factor Bitten reporting into a separate module
* Stop hacking the target ids to find source file paths; use a
  slightly more principled approach instead
* support the use of failure markup to ignore test failures

regression/src/test_results.py:
* readability/maintainability improvements:
  * replace tuple representation of build actions with instances of an
    Action class
  * Renamed various attributes to make them more meaningful
* stop hacking the target ids to find source file paths; use a
  slightly more principled approach instead
* add an extremely crude test of this module

regression/src/recipe.py:
* begin taking the toolsets from the slave.ini file

regression/src/regression.py:
* default to no logging at all
* support the use of failure markup to avoid running tests at all for
  particular toolset/library combinations, and to determine failure
  status for individual libraries
* Idiomatic string slitting and joining

build/v2/build-system.jam:
* represent project ids when XML dumping targets
* represent leaf targets ("sources") in the dumped XML dependency graph
* update action rule signatures to conform to the new protocol

build/v2/tools/testing.jam:
* group all XML-dumped tests under a <tests>...</tests> tag
* distinguish a test's human-readable name from its raw target name in XML
* record the project root for each dumped test

jam/test/test.jam:
jam/doc/bjam.qbk:
jam/doc/history.qbk:
jam/src/execnt.c:
jam/src/make1.c:
jam/src/jam.c:
jam/src/execcmd.h:
jam/src/variable.c:
jam/src/output.c:
jam/src/output.h:
jam/src/strings.c:
jam/src/build.bat:
jam/src/build.jam:
jam/src/execunix.c:
* Merged recent changes from trunk

Added:
   branches/bitten/tools/regression/src/bitten_reports.py (contents, props changed)
   branches/bitten/tools/regression/src/failure_markup.py (contents, props changed)
Text files modified:
   branches/bitten/tools/build/v2/build-system.jam | 88 ++++--
   branches/bitten/tools/build/v2/tools/testing.jam | 26 +
   branches/bitten/tools/jam/doc/bjam.qbk | 65 ++++
   branches/bitten/tools/jam/doc/history.qbk | 68 +++++
   branches/bitten/tools/jam/src/build.bat | 26 +
   branches/bitten/tools/jam/src/build.jam | 7
   branches/bitten/tools/jam/src/execcmd.h | 24 +
   branches/bitten/tools/jam/src/execnt.c | 44 ++
   branches/bitten/tools/jam/src/execunix.c | 13
   branches/bitten/tools/jam/src/jam.c | 20 -
   branches/bitten/tools/jam/src/make1.c | 85 +++--
   branches/bitten/tools/jam/src/output.c | 48 ++
   branches/bitten/tools/jam/src/output.h | 6
   branches/bitten/tools/jam/src/strings.c | 9
   branches/bitten/tools/jam/src/variable.c | 282 ++++++++++----------
   branches/bitten/tools/jam/test/test.jam | 2
   branches/bitten/tools/quickbook/doc/html/boostbook.css | 528 ----------------------------------------
   branches/bitten/tools/quickbook/doc/quickbook.qbk | 12
   branches/bitten/tools/regression/src/collect_and_upload_logs.py | 80 ------
   branches/bitten/tools/regression/src/recipe.py | 2
   branches/bitten/tools/regression/src/regression.py | 82 +++++
   branches/bitten/tools/regression/src/run.py | 2
   branches/bitten/tools/regression/src/test_results.py | 123 +++++----
   23 files changed, 692 insertions(+), 950 deletions(-)

Modified: branches/bitten/tools/build/v2/build-system.jam
==============================================================================
--- branches/bitten/tools/build/v2/build-system.jam (original)
+++ branches/bitten/tools/build/v2/build-system.jam 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -25,6 +25,7 @@
 import toolset ;
 import regex ;
 import path ;
+import project ;
 
 import builtin ;
 import make ;
@@ -497,9 +498,48 @@
     {
         local name = [ $(t).name ] ;
         local project = [ $(t).project ] ;
- local project-path = [ $(project).get location ] ;
+ local project-path = [ project.attribute [ $(project).project-module ] id ] ;
+ project-path ?= [ $(project).get location ] ;
         return $(project-path)//$(name) ;
     }
+
+ rule add-target-xml ( xml-file : t )
+ {
+ local name = [ full-target-name $(t) ] ;
+ local action = [ $(t).action ] ;
+ local dependency-xml ;
+ local leaves ;
+ if $(action)
+ {
+ local sources = [ $(action).sources ] ;
+ local dependencies ;
+ for local s in $(sources)
+ {
+ dependencies += [ $(s).actual-name ] ;
+ if ! [ $(s).action ] && ! $(s) in $(.all-sources)
+ {
+ .all-sources += $(s) ;
+ }
+ }
+ dependency-xml =
+ "$(nl) <dependencies>"
+ "$(nl) <dependency><![CDATA[$(dependencies)]]></dependency>"
+ "$(nl) </dependencies>"
+ ;
+ }
+
+ local directory = [ $(t).path ] ;
+ local jam-target = [ $(t).actual-name ] ;
+
+ .contents on $(xml-file) +=
+ "$(nl) <target>"
+ "$(nl) <name><![CDATA[$(name)]]></name>"
+ $(dependency-xml)
+ "$(nl) <directory><![CDATA[$(directory)]]></directory>"
+ "$(nl) <jam-target><![CDATA[$(jam-target)]]></jam-target>"
+ "$(nl) </target>"
+ ;
+ }
     # Generate an XML file containing build statistics for each
     # constituent
     rule out-xml ( xml-file : constituents * )
@@ -532,40 +572,18 @@
 
         for local t in [ virtual-target.all-targets ]
         {
- local action = [ $(t).action ] ;
- if $(action)
- {
- # If a target has no action, it has
- # no dependencies.
-
- local name = [ full-target-name $(t) ] ;
- local sources = [ $(action).sources ] ;
- local dependencies ;
- for local s in $(sources)
- {
- dependencies += [ $(s).actual-name ] ;
- }
-
- local path = [ $(t).path ] ;
- local jam-target = [ $(t).actual-name ] ;
-
- .contents on $(xml-file) +=
- "$(nl) <target>"
- "$(nl) <name><![CDATA[$(name)]]></name>"
- "$(nl) <dependencies>"
- "$(nl) <dependency><![CDATA[$(dependencies)]]></dependency>"
- "$(nl) </dependencies>"
- "$(nl) <path><![CDATA[$(path)]]></path>"
- "$(nl) <jam-target><![CDATA[$(jam-target)]]></jam-target>"
- "$(nl) </target>"
- ;
-
- }
+ add-target-xml $(xml-file) : $(t) ;
+ }
+
+ for local t in $(.all-sources)
+ {
+ add-target-xml $(xml-file) : $(t) ;
         }
+
         .contents on $(xml-file) +=
           "$(nl) </targets>"
             ;
-
+
         # Build $(xml-file) after $(constituents), regenerating it on
         # every bjam run even if a constituent action fails.
         INCLUDES $(xml-file) : $(constituents) ;
@@ -579,8 +597,8 @@
     # actions clause we would have to form a valid command line
     # containing the result of @(...) below (the name of the XML file).
     rule out-xml.generate-action (
- xml-file args * :
- status : user : system : command : output ? )
+ args * : xml-file :
+ command status start end user system : output ? )
     {
         local contents =
             [ on $(xml-file) return $(.header) $(.contents) $(.footer) ] ;
@@ -610,8 +628,8 @@
     # statistics about each actual target in a variable "on" the
     # --out-xml target.
     rule out-xml.collect (
- xml-file target :
- status : user : system : command : output ? )
+ xml-file : target :
+ command status start end user system : output ? )
     {
         local nl = "
 " ;

Modified: branches/bitten/tools/build/v2/tools/testing.jam
==============================================================================
--- branches/bitten/tools/build/v2/tools/testing.jam (original)
+++ branches/bitten/tools/build/v2/tools/testing.jam 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -166,10 +166,20 @@
 # produce some interesting information.
 rule dump-tests # ( project-module )
 {
+ local nl = "
+" ;
+ if $(.out-xml)
+ {
+ .contents on $(.out-xml) += "$(nl) <tests>" ;
+ }
     for local t in $(.all-tests)
     {
         dump-test $(t) ;
     }
+ if $(.out-xml)
+ {
+ .contents on $(.out-xml) += "$(nl) </tests>" ;
+ }
 }
 
 # Given a project location, compute the name of Boost library
@@ -205,6 +215,7 @@
 {
     local type = [ $(target).type ] ;
     local name = [ $(target).name ] ;
+ local pretty_name = $(name) ;
     local project = [ $(target).project ] ;
     
     local project-root = [ $(project).get project-root ] ;
@@ -212,7 +223,7 @@
         [ path.root [ $(project).get location ] [ path.pwd ] ] ] ;
     if $(library)
     {
- name = $(library)/$(name) ;
+ pretty_name = $(library)/$(name) ;
     }
         
     local sources = [ $(target).sources ] ;
@@ -230,7 +241,7 @@
               [ path.relative
                   $(location)
                   [ path.root $(project-root) [ path.pwd ] ] ] ;
- }
+ }
     }
           
     local r = [ $(target).requirements ] ;
@@ -241,13 +252,16 @@
     # test info to that XML file rather than dumping them to stdout.
     if $(.out-xml)
     {
+ local project-location = [ $(project).get location ] ;
         local nl = "
 " ;
         .contents on $(.out-xml) +=
- "$(nl) <test type=\"$(type)\" name=\"$(name)\">"
- "$(nl) <info><![CDATA[$(test-info)]]></info>"
- "$(nl) <source><![CDATA[$(source-files)]]></source>"
- "$(nl) </test>"
+ "$(nl) <test type=\"$(type)\" name=\"$(pretty_name)\">"
+ "$(nl) <rawname><![CDATA[$(name)]]></rawname>"
+ "$(nl) <project_root><![CDATA[$(project-root)]]></project_root>"
+ "$(nl) <info><![CDATA[$(test-info)]]></info>"
+ "$(nl) <source><![CDATA[$(source-files)]]></source>"
+ "$(nl) </test>"
             ;
     }
     else

Modified: branches/bitten/tools/jam/doc/bjam.qbk
==============================================================================
--- branches/bitten/tools/jam/doc/bjam.qbk (original)
+++ branches/bitten/tools/jam/doc/bjam.qbk 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -217,12 +217,14 @@
 
 [ [] []
     [[lines
- [line [@http://msdn.microsoft.com/visualc/ =vc8=]]
- [line Microsoft Visual C++ 8.x]
+ [line [@http://msdn.microsoft.com/visualc/ =vc8= and =vc9=]]
+ [line Microsoft Visual C++ 8.x and 9.x]
         ]]
     [Detection:
         [list
             [li =VCVARSALL.BAT= already configured]
+ [li =%VS90COMNTOOLS%= is present in environment]
+ [li Common install location: "=%ProgramFiles%\Microsoft Visual Studio 9="]
             [li =%VS80COMNTOOLS%= is present in environment]
             [li Common install location: "=%ProgramFiles%\Microsoft Visual Studio 8="]
             [li =CL.EXE= in =PATH=]
@@ -1315,6 +1317,17 @@
 
 [endsect]
 
+[section:atfile Generated File Expansion]
+
+During expansion of expressions =bjam= also looks for subexpressions of the form
+=@(filename:E=filecontents)= and replaces the expression with =filename= after
+creating the given file with the contents set to =filecontents=. This is useful
+for creating compiler response files, and other "internal" files. The expansion
+works both during parsing and action execution. Hence it is possible to create
+files during any of the three build phases.
+
+[endsect]
+
 [section:builtins Built-in Variables]
 
 This section discusses variables that have special meaning to =bjam=.
@@ -1387,7 +1400,7 @@
 [section Jam Version]
 
 [variablelist
-[[=JAMDATE=] [Time and date at =bjam= start-up.]]
+[[=JAMDATE=] [Time and date at =bjam= start-up as an ISO-8601 UTC value.]]
 [[=JAMUNAME=] [Ouput of uname(1) command (Unix only)]]
 [[=JAMVERSION=] [=bjam= version, currently ":version:"]]
 [[=JAM_VERSION=] [A predefined global variable with two elements indicates the version number of Boost Jam. Boost Jam versions start at "=03=" "=00=". Earlier versions of =Jam= do not automatically define =JAM_VERSION=.]]
@@ -1432,6 +1445,52 @@
 
 [endsect]
 
+[section:actionrule =__TIMING_RULE__= and =__ACTION_RULE__=]
+
+The =__TIMING_RULE__= and =__ACTION_RULE__= can be set to the name of a rule
+for =bjam= to call *after* an action completes for a target. They both give
+diagnostic information about the action that completed. For =__TIMING_RULE__=
+the rule is called as:
+
+ rule timing-rule ( args * : target : start end user system )
+
+And =__ACTION_RULE__= is called as:
+
+ rule action-rule ( args * : target : command status start end user system : output ? )
+
+The arguments for both are:
+
+[variablelist
+ [[[^args]]
+ [Any values following the rule name in the =__TIMING_RULE__= or =__ACTION_RULE__=
+ are passed along here.]]
+ [[[^target]]
+ [The =bjam= target that was built.]]
+ [[[^command]]
+ [The text of the executed command in the action body.]]
+ [[[^status]]
+ [The integer result of the executed command.]]
+ [[[^start]]
+ [The starting timestamp of the executed command as a ISO-8601 UTC value.]]
+ [[[^end]]
+ [The completion timestamp of the executed command as a ISO-8601 UTC value.]]
+ [[[^user]]
+ [The number of user CPU seconds the executed command spent as a floating
+ point value.]]
+ [[[^system]]
+ [The number of system CPU seconds the executed command spent as a floating
+ point value.]]
+ [[[^output]]
+ [The output of the command as a single string. The content of the output
+ reflects the use of the =-pX= option.]]
+]
+
+[note
+ If both variables are set for a target both are called, first =__TIMING_RULE__=
+ then =__ACTION_RULE__=. ]
+
+[endsect]
+
 [endsect]
 
 [endsect]

Modified: branches/bitten/tools/jam/doc/history.qbk
==============================================================================
--- branches/bitten/tools/jam/doc/history.qbk (original)
+++ branches/bitten/tools/jam/doc/history.qbk 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -1,5 +1,73 @@
 [variablelist
 
+[[3.1.16] [
+
+This is mostly a bug fix release.
+
+[list
+ [li Add support for detection and building with =vc9=.
+ -- ['John P.]
+ ]
+ [li Plug memory leak when closing out actions. Thanks to Martin Kortmann for finding this.
+ -- ['Rene R.]
+ ]
+ [li Various improvements to =__TIMING_RULE__= and =__ACTION_RULE__= target variable
+ hooks.
+ -- ['Rene R.]
+ ]
+ [li Change [^JAMDATE] to use common ISO date format.
+ -- ['Rene R.]
+ ]
+ [li Add test for result status values of simple actions, i.e. empty actions.
+ -- ['Rene R.]
+ ]
+ [li Fix buffer overrun bug in expanding [^@()] subexpressions.
+ -- ['Rene R.]
+ ]
+ [li Check empty string invariants, instead of assuming all strings are allocated.
+ And reset strings when they are freed.
+ -- ['Rene R.]
+ ]
+ [li Add [^OSPLAT=PARISC] for HP-UX PA-RISC.
+ -- ['Boris G.]
+ ]
+ [li Make quietly actions really quiet by not printing the command output. The
+ output for the quietly actions is still available through =__ACTION_RULE__=.
+ -- ['Rene R.]
+ ]
+ [li Switch intel-win32 to use static multi thread runtime since the single
+ thread static runtime is no longer available.
+ -- ['Rene R.]
+ ]
+ [li When setting =OSPLAT=, check =__ia64= macro.
+ -- ['Boris G.]
+ ]
+ [li Get the unix timing working correctly.
+ -- ['Noel B.]
+ ]
+ [li Add =-fno-strict-aliasing= to compilation with gcc. Which works around
+ GCC-4.2 crash problems.
+ -- ['Boris G.]
+ ]
+ [li Increased support for Python integration.
+ -- ['Vladimir P.], ['Daniel W.]
+ ]
+ [li Allow specifying options with quotes, i.e. [^--with-python=xyz], to work
+ around the CMD shell using [^=] as an argument separator.
+ -- ['Rene R.]
+ ]
+ [li Add values of variables specified with -s to .EVNRION
+ module, so that we can override environment on
+ command line.
+ -- ['Vladimir P.]
+ ]
+ [li Make NORMALIZE_PATH convert \\ to /.
+ -- ['Vladimir P.]
+ ]
+]
+
+]]
+
 [[3.1.15] [
 
 This release sees a variety of fixes for long standing Perforce/Jam problems. Most of

Modified: branches/bitten/tools/jam/src/build.bat
==============================================================================
--- branches/bitten/tools/jam/src/build.bat (original)
+++ branches/bitten/tools/jam/src/build.bat 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -67,6 +67,16 @@
 if "_%ProgramFiles%_" == "__" set ProgramFiles=C:\Program Files
 
 setlocal & endlocal
+if NOT "_%VS90COMNTOOLS%_" == "__" (
+ set "BOOST_JAM_TOOLSET=vc9"
+ set "BOOST_JAM_TOOLSET_ROOT=%VS90COMNTOOLS%..\..\VC\"
+ goto :eof)
+setlocal & endlocal
+if EXIST "%ProgramFiles%\Microsoft Visual Studio 9.0\VC\VCVARSALL.BAT" (
+ set "BOOST_JAM_TOOLSET=vc9"
+ set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio 9.0\VC\"
+ goto :eof)
+setlocal & endlocal
 if NOT "_%VS80COMNTOOLS%_" == "__" (
     set "BOOST_JAM_TOOLSET=vc8"
     set "BOOST_JAM_TOOLSET_ROOT=%VS80COMNTOOLS%..\..\VC\"
@@ -83,6 +93,7 @@
     goto :eof)
 setlocal & endlocal
 if NOT "_%VCINSTALLDIR%_" == "__" (
+ REM %VCINSTALLDIR% is also set for VC9 (and probably VC8)
     set "BOOST_JAM_TOOLSET=vc7"
     set "BOOST_JAM_TOOLSET_ROOT=%VCINSTALLDIR%\VC7\"
     goto :eof)
@@ -281,6 +292,21 @@
 set "BOOST_JAM_OPT_YYACC=/Febootstrap\yyacc0"
 set "_known_=1"
 :Skip_VC8
+if NOT "_%BOOST_JAM_TOOLSET%_" == "_vc9_" goto :Skip_VC9
+if NOT "_%VS90COMNTOOLS%_" == "__" (
+ set "BOOST_JAM_TOOLSET_ROOT=%VS90COMNTOOLS%..\..\VC\"
+ )
+if "_%VCINSTALLDIR%_" == "__" call :Call_If_Exists "%BOOST_JAM_TOOLSET_ROOT%VCVARSALL.BAT" %BOOST_JAM_ARGS%
+if NOT "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" (
+ if "_%VCINSTALLDIR%_" == "__" (
+ set "PATH=%BOOST_JAM_TOOLSET_ROOT%bin;%PATH%"
+ ) )
+set "BOOST_JAM_CC=cl /nologo /RTC1 /Zi /MTd /Fobootstrap/ /Fdbootstrap/ -DNT -DYYDEBUG -wd4996 kernel32.lib advapi32.lib user32.lib"
+set "BOOST_JAM_OPT_JAM=/Febootstrap\jam0"
+set "BOOST_JAM_OPT_MKJAMBASE=/Febootstrap\mkjambase0"
+set "BOOST_JAM_OPT_YYACC=/Febootstrap\yyacc0"
+set "_known_=1"
+:Skip_VC9
 if NOT "_%BOOST_JAM_TOOLSET%_" == "_borland_" goto :Skip_BORLAND
 if "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" (
     call :Test_Path bcc32.exe )

Modified: branches/bitten/tools/jam/src/build.jam
==============================================================================
--- branches/bitten/tools/jam/src/build.jam (original)
+++ branches/bitten/tools/jam/src/build.jam 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -317,6 +317,13 @@
     [ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ]
     -I$(--python-include) -I$(--extra-include)
     : kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ;
+## Microsoft Visual C++ 2008
+toolset vc9 cl : /Fe /Fe /Fd /Fo : -D
+ : /nologo
+ [ opt --release : /MT /O2 /Ob2 /Gy /GF /GA /wd4996 ]
+ [ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ]
+ -I$(--python-include) -I$(--extra-include)
+ : kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ;
 ## VMS/OpenVMS DEC C
 toolset vmsdecc cc : /OBJECT= : "/DEFINES=(" "," ")"
     : /STANDARD=VAXC /PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES

Modified: branches/bitten/tools/jam/src/execcmd.h
==============================================================================
--- branches/bitten/tools/jam/src/execcmd.h (original)
+++ branches/bitten/tools/jam/src/execcmd.h 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -10,23 +10,31 @@
  * 05/04/94 (seiwald) - async multiprocess interface
  */
 
+#ifndef EXECCMD_H
+#define EXECCMD_H
+
+#include <time.h>
+
 typedef struct timing_info
 {
- /* double elapsed; */ /* We don't know how to get this number on Unix */
     double system;
     double user;
+ time_t start;
+ time_t end;
 } timing_info;
 
 void execcmd(
- char *string,
- void (*func)( void *closure, int status, timing_info*, char *, char * ),
- void *closure,
- LIST *shell,
+ char *string,
+ void (*func)( void *closure, int status, timing_info*, char *, char * ),
+ void *closure,
+ LIST *shell,
         char *action,
         char *target);
 
 int execwait();
 
-# define EXEC_CMD_OK 0
-# define EXEC_CMD_FAIL 1
-# define EXEC_CMD_INTR 2
+# define EXEC_CMD_OK 0
+# define EXEC_CMD_FAIL 1
+# define EXEC_CMD_INTR 2
+
+#endif

Modified: branches/bitten/tools/jam/src/execnt.c
==============================================================================
--- branches/bitten/tools/jam/src/execnt.c (original)
+++ branches/bitten/tools/jam/src/execnt.c 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -21,6 +21,7 @@
 # include <assert.h>
 # include <ctype.h>
 # include <time.h>
+# include <math.h>
 
 # ifdef USE_EXECNT
 
@@ -538,6 +539,7 @@
         string_free(&cmdtab[i].target); string_new(&cmdtab[i].target);
         string_free(&cmdtab[i].command); string_new(&cmdtab[i].command);
         if (cmdtab[i].pi.hProcess) { CloseHandle(cmdtab[i].pi.hProcess); cmdtab[i].pi.hProcess = 0; }
+ if (cmdtab[i].pi.hThread) { CloseHandle(cmdtab[i].pi.hThread); cmdtab[i].pi.hThread = 0; }
         if (cmdtab[i].pipe_out[0]) { CloseHandle(cmdtab[i].pipe_out[0]); cmdtab[i].pipe_out[0] = 0; }
         if (cmdtab[i].pipe_out[1]) { CloseHandle(cmdtab[i].pipe_out[1]); cmdtab[i].pipe_out[1] = 0; }
         if (cmdtab[i].pipe_err[0]) { CloseHandle(cmdtab[i].pipe_err[0]); cmdtab[i].pipe_err[0] = 0; }
@@ -758,7 +760,35 @@
 /* Convert a FILETIME to a number of seconds */
 static double filetime_seconds(FILETIME t)
 {
- return t.dwHighDateTime * (double)(1UL << 31) * 2 + t.dwLowDateTime * 1.0e-7;
+ return t.dwHighDateTime * ((double)(1UL << 31) * 2.0 * 1.0e-7) + t.dwLowDateTime * 1.0e-7;
+}
+
+/* What should be a simple conversion, turns out to be horribly
+ complicated by the defficiencies of MSVC and the Win32 API. */
+static time_t filetime_dt(FILETIME t_utc)
+{
+ static int calc_time_diff = 1;
+ static double time_diff;
+ if ( calc_time_diff )
+ {
+ struct tm t0_;
+ FILETIME f0_local,f0_;
+ SYSTEMTIME s0_;
+ GetSystemTime(&s0_);
+ t0_.tm_year = s0_.wYear-1900;
+ t0_.tm_mon = s0_.wMonth-1;
+ t0_.tm_wday = s0_.wDayOfWeek;
+ t0_.tm_mday = s0_.wDay;
+ t0_.tm_hour = s0_.wHour;
+ t0_.tm_min = s0_.wMinute;
+ t0_.tm_sec = s0_.wSecond;
+ t0_.tm_isdst = 0;
+ SystemTimeToFileTime(&s0_,&f0_local);
+ LocalFileTimeToFileTime(&f0_local,&f0_);
+ time_diff = filetime_seconds(f0_)-((double)mktime(&t0_));
+ calc_time_diff = 0;
+ }
+ return ceil(filetime_seconds(t_utc)-time_diff);
 }
 
 static void record_times(HANDLE process, timing_info* time)
@@ -767,17 +797,11 @@
     
     if (GetProcessTimes(process, &creation, &exit, &kernel, &user))
     {
- /* Compute the elapsed time */
- #if 0 /* We don't know how to get this number on Unix */
- time->elapsed = filetime_seconds(
- add_FILETIME( exit, negate_FILETIME(creation) )
- );
- #endif
         time->system = filetime_seconds(kernel);
- time->user = filetime_seconds(user);
+ time->user = filetime_seconds(user);
+ time->start = filetime_dt(creation);
+ time->end = filetime_dt(exit);
     }
-
- /* CloseHandle((HANDLE)pid); */
 }
 
 #define IO_BUFFER_SIZE (16*1024)

Modified: branches/bitten/tools/jam/src/execunix.c
==============================================================================
--- branches/bitten/tools/jam/src/execunix.c (original)
+++ branches/bitten/tools/jam/src/execunix.c 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -85,6 +85,7 @@
     char *buffer[2]; /* buffer to hold stdout and stderr, if any */
     void (*func)( void *closure, int status, timing_info*, char *, char * );
     void *closure;
+ time_t start_dt; /* start of command timestamp */
 } cmdtab[ MAXJOBS ] = {{0}};
 
 /*
@@ -194,6 +195,8 @@
 
         /* Start the command */
 
+ cmdtab[ slot ].start_dt = time(0);
+
         if (0 < globs.timeout) {
             /*
              * handle hung processes by manually tracking elapsed
@@ -418,7 +421,7 @@
     int i, ret, fd_max;
     int pid, status, finished;
     int rstat;
- timing_info time;
+ timing_info time_info;
     fd_set fds;
     struct tms new_time;
 
@@ -491,8 +494,10 @@
 
                         times(&new_time);
 
- time.system = (double)(new_time.tms_cstime - old_time.tms_cstime) / CLOCKS_PER_SEC;
- time.user = (double)(new_time.tms_cutime - old_time.tms_cutime) / CLOCKS_PER_SEC;
+ time_info.system = (double)(new_time.tms_cstime - old_time.tms_cstime) / CLOCKS_PER_SEC;
+ time_info.user = (double)(new_time.tms_cutime - old_time.tms_cutime) / CLOCKS_PER_SEC;
+ time_info.start = cmdtab[i].start_dt;
+ time_info.end = time(0);
     
                         old_time = new_time;
 
@@ -508,7 +513,7 @@
                             rstat = EXEC_CMD_OK;
 
                         /* assume -p0 in effect so only pass buffer[0] containing merged output */
- (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat, &time, cmdtab[i].command, cmdtab[i].buffer[0] );
+ (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat, &time_info, cmdtab[i].command, cmdtab[i].buffer[0] );
 
                         BJAM_FREE(cmdtab[i].buffer[OUT]);
                         cmdtab[i].buffer[OUT] = 0;

Modified: branches/bitten/tools/jam/src/jam.c
==============================================================================
--- branches/bitten/tools/jam/src/jam.c (original)
+++ branches/bitten/tools/jam/src/jam.c 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -122,6 +122,7 @@
 # include "strings.h"
 # include "expand.h"
 # include "filesys.h"
+# include "output.h"
 
 /* Macintosh is "special" */
 
@@ -249,9 +250,8 @@
         printf( "-lx Limit actions to x number of seconds after which they are stopped.\n" );
         printf( "-n Don't actually execute the updating actions.\n" );
         printf( "-ox Write the updating actions to file x.\n" );
- printf( "-px x=0, pipes action stdout and stderr merged into action output.\n" );
- printf( "-q Quit quickly as soon as a target fails.\n" );
- printf( "-r Enable Dart results.\n" );
+ printf( "-px x=0, pipes action stdout and stderr merged into action output.\n" );
+ printf( "-q Quit quickly as soon as a target fails.\n" );
         printf( "-sx=y Set variable x=y, overriding environment.\n" );
         printf( "-tx Rebuild x, even if it is up-to-date.\n" );
         printf( "-v Print the version of jam and exit.\n" );
@@ -373,19 +373,7 @@
 
     /* Set JAMDATE first */
 
- {
- char *date;
- time_t clock;
- time( &clock );
- date = newstr( ctime( &clock ) );
-
- /* Trim newline from date */
-
- if( strlen( date ) == 25 )
- date[ 24 ] = 0;
-
- var_set( "JAMDATE", list_new( L0, newstr( date ) ), VAR_SET );
- }
+ var_set( "JAMDATE", list_new( L0, outf_time(time(0)) ), VAR_SET );
 
  
     var_set( "JAM_VERSION",

Modified: branches/bitten/tools/jam/src/make1.c
==============================================================================
--- branches/bitten/tools/jam/src/make1.c (original)
+++ branches/bitten/tools/jam/src/make1.c 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -664,16 +664,6 @@
         }
 }
 
-/* To l, append a 1-element list containing the string representation
- * of x
- */
-static void append_double_string( LOL *l, double x )
-{
- char buffer[50];
- sprintf(buffer, "%f", x);
- lol_add( l, list_new( L0, newstr( buffer ) ) );
-}
-
 /* Look up the __TIMING_RULE__ variable on the given target, and if
  * non-empty, invoke the rule it names, passing the given
  * timing_info
@@ -688,33 +678,37 @@
 
     if (timing_rule)
     {
- /* We'll prepend $(__TIMING_RULE__[2-]) to the first argument */
- LIST* initial_args = list_copy( L0, timing_rule->next );
-
+ /* rule timing-rule (
+ args * :
+ target :
+ start end user system ) */
+
         /* Prepare the argument list */
         FRAME frame[1];
         frame_init( frame );
 
- /* First argument is the name of the timed target */
- lol_add( frame->args, list_new( initial_args, target->name ) );
- append_double_string(frame->args, time->user);
- append_double_string(frame->args, time->system);
-
- if( lol_get( frame->args, 2 ) )
- evaluate_rule( timing_rule->string, frame );
-
+ /* args * :: $(__ACTION_RULE__[2-]) */
+ lol_add( frame->args, list_copy( L0, timing_rule->next ) );
+
+ /* target :: the name of the target */
+ lol_add( frame->args, list_new( L0, target->name ) );
+
+ /* start end user system :: info about the action command */
+ lol_add( frame->args,
+ list_new( list_new( list_new( list_new( L0,
+ outf_time(time->start) ),
+ outf_time(time->end) ),
+ outf_double(time->user) ),
+ outf_double(time->system) ) );
+
+ /* Call the rule. */
+ evaluate_rule( timing_rule->string, frame );
+
         /* Clean up */
         frame_free( frame );
     }
 }
 
-static void append_int_string(LOL *l, int x)
-{
- char buffer[50];
- sprintf(buffer, "%i", x);
- lol_add(l, list_new(L0, newstr(buffer)));
-}
-
 /* Look up the __ACTION_RULE__ variable on the given target, and if
  * non-empty, invoke the rule it names, passing the given info,
  * timing_info, executed command and command output
@@ -730,27 +724,40 @@
 
     if (action_rule)
     {
- /* We'll prepend $(__ACTION_RULE__[2-]) to the first argument */
- LIST* initial_args = list_copy( L0, action_rule->next );
-
+ /* rule action-rule (
+ args * :
+ target :
+ command status start end user system :
+ output ? ) */
+
         /* Prepare the argument list */
         FRAME frame[1];
         frame_init( frame );
 
- /* First argument is the name of the target */
- lol_add( frame->args, list_new( initial_args, target->name ) );
- append_int_string(frame->args, status);
- append_double_string(frame->args, time->user);
- append_double_string(frame->args, time->system);
- lol_add(frame->args, list_new(L0, newstr(executed_command)));
+ /* args * :: $(__ACTION_RULE__[2-]) */
+ lol_add( frame->args, list_copy( L0, action_rule->next ) );
+
+ /* target :: the name of the target */
+ lol_add( frame->args, list_new( L0, target->name ) );
+
+ /* command status start end user system :: info about the action command */
+ lol_add( frame->args,
+ list_new( list_new( list_new( list_new( list_new( list_new( L0,
+ newstr(executed_command) ),
+ outf_int(status) ),
+ outf_time(time->start) ),
+ outf_time(time->end) ),
+ outf_double(time->user) ),
+ outf_double(time->system) ) );
 
+ /* output ? :: the output of the action command */
         if (command_output)
             lol_add(frame->args, list_new(L0, newstr(command_output)));
         else
             lol_add(frame->args, L0);
 
- if( lol_get( frame->args, 2 ) )
- evaluate_rule( action_rule->string, frame );
+ /* Call the rule. */
+ evaluate_rule( action_rule->string, frame );
 
         /* Clean up */
         frame_free( frame );

Modified: branches/bitten/tools/jam/src/output.c
==============================================================================
--- branches/bitten/tools/jam/src/output.c (original)
+++ branches/bitten/tools/jam/src/output.c 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -6,6 +6,7 @@
 
 #include "jam.h"
 #include "output.h"
+#include "newstr.h"
 #include <stdio.h>
 
 #define bjam_out (stdout)
@@ -66,7 +67,7 @@
             if ( action )
             {
                 /* but only output for non-quietly actions */
- fprintf(bjam_out, "%d second time limit exceeded\n", globs.timeout);
+ fprintf(bjam_out, "%d second time limit exceeded\n", globs.timeout);
             }
             break;
         }
@@ -78,20 +79,43 @@
     if ( action )
     {
         /* but only output for non-quietly actions */
- if (0 != out_data &&
- ( globs.pipe_action & 1 /* STDOUT_FILENO */ ||
- globs.pipe_action == 0))
- {
- out_(out_data,bjam_out);
- }
- if (0 != err_data &&
- globs.pipe_action & 2 /* STDERR_FILENO */)
- {
- out_(err_data,bjam_err);
- }
+ if (0 != out_data &&
+ ( globs.pipe_action & 1 /* STDOUT_FILENO */ ||
+ globs.pipe_action == 0))
+ {
+ out_(out_data,bjam_out);
+ }
+ if (0 != err_data &&
+ globs.pipe_action & 2 /* STDERR_FILENO */)
+ {
+ out_(err_data,bjam_err);
+ }
     }
     
     fflush(bjam_out);
     fflush(bjam_err);
     fflush(globs.cmdout);
 }
+
+
+char * outf_int( int value )
+{
+ char buffer[50];
+ sprintf(buffer, "%i", value);
+ return newstr(buffer);
+}
+
+char * outf_double( double value )
+{
+ char buffer[50];
+ sprintf(buffer, "%f", value);
+ return newstr(buffer);
+}
+
+char * outf_time( time_t value )
+{
+ char buffer[50];
+ strftime(buffer,49,"%Y-%m-%d %H:%M:%SZ",gmtime(&value));
+ return newstr(buffer);
+}
+

Modified: branches/bitten/tools/jam/src/output.h
==============================================================================
--- branches/bitten/tools/jam/src/output.h (original)
+++ branches/bitten/tools/jam/src/output.h 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -7,6 +7,8 @@
 #ifndef BJAM_OUTPUT_H
 #define BJAM_OUTPUT_H
 
+#include <time.h>
+
 #define EXIT_OK 0
 #define EXIT_FAIL 1
 #define EXIT_TIMEOUT 2
@@ -20,4 +22,8 @@
     int exit_reason
     );
 
+char * outf_int( int value );
+char * outf_double( double value );
+char * outf_time( time_t value );
+
 #endif

Modified: branches/bitten/tools/jam/src/strings.c
==============================================================================
--- branches/bitten/tools/jam/src/strings.c (original)
+++ branches/bitten/tools/jam/src/strings.c 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -16,6 +16,14 @@
 static void assert_invariants( string* self )
 {
     int i;
+
+ if ( self->value == 0 )
+ {
+ assert( self->size == 0 );
+ assert( self->capacity == 0 );
+ assert( self->opt[0] == 0 );
+ return;
+ }
     
     assert( self->size < self->capacity );
     assert( ( self->capacity <= sizeof(self->opt) ) == ( self->value == self->opt ) );
@@ -49,6 +57,7 @@
     assert_invariants( s );
     if ( s->value != s->opt )
         BJAM_FREE( s->value );
+ string_new( s );
 }
 
 static void string_reserve_internal( string* self, size_t capacity )

Modified: branches/bitten/tools/jam/src/variable.c
==============================================================================
--- branches/bitten/tools/jam/src/variable.c (original)
+++ branches/bitten/tools/jam/src/variable.c 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -177,143 +177,147 @@
 
 int
 var_string(
- char *in,
- char *out,
- int outsize,
- LOL *lol )
+ char *in,
+ char *out,
+ int outsize,
+ LOL *lol )
 {
- char *out0 = out;
- char *oute = out + outsize - 1;
+ char *out0 = out;
+ char *oute = out + outsize - 1;
 
- while( *in )
- {
- char *lastword;
- int dollar = 0;
+ while( *in )
+ {
+ char *lastword;
+ int dollar = 0;
 
- /* Copy white space */
+ /* Copy white space */
 
- while( isspace( *in ) )
- {
- if( out >= oute )
- return -1;
+ while( isspace( *in ) )
+ {
+ if( out >= oute )
+ return -1;
 
- *out++ = *in++;
- }
+ *out++ = *in++;
+ }
 
- lastword = out;
+ lastword = out;
 
- /* Copy non-white space, watching for variables */
+ /* Copy non-white space, watching for variables */
 
- while( *in && !isspace( *in ) )
- {
- if( out >= oute )
- return -1;
+ while( *in && !isspace( *in ) )
+ {
+ if( out >= oute )
+ return -1;
 
- if( in[0] == '$' && in[1] == '(' )
- dollar++;
- #ifdef OPT_AT_FILES
- else if ( in[0] == '@' && in[1] == '(' )
+ if( in[0] == '$' && in[1] == '(' )
+ {
+ dollar++;
+ *out++ = *in++;
+ }
+ #ifdef OPT_AT_FILES
+ else if ( in[0] == '@' && in[1] == '(' )
+ {
+ int depth = 1;
+ char *ine = in + 2;
+ char *split = 0;
+
+ /* Scan the content of the response file @() section. */
+
+ while( *ine && depth > 0 )
                 {
- int depth = 1;
- char *ine = in + 2;
- char *split = 0;
-
- /* Scan the content of the response file @() section. */
-
- while( *ine && depth > 0 )
+ switch( *ine )
                     {
- switch( *ine )
+ case '(':
+ ++depth;
+ break;
+ case ')':
+ --depth;
+ break;
+ case ':':
+ if( depth == 1 && ine[1] == 'E' && ine[2] == '=' )
                         {
- case '(':
- ++depth;
- break;
- case ')':
- --depth;
- break;
- case ':':
- if( depth == 1 && ine[1] == 'E' && ine[2] == '=' )
- {
- split = ine;
- }
- break;
+ split = ine;
                         }
- ++ine;
+ break;
                     }
+ ++ine;
+ }
+
+ if (!split)
+ {
+ /* the @() reference doesn't match the @(foo:E=bar) format.
+ hence we leave it alone by copying directly to output. */
+ int l = 0;
+ if ( out+2 >= oute ) return -1;
+ *(out++) = '@';
+ *(out++) = '(';
+ l = var_string(in+2,out,oute-out,lol);
+ if ( l < 0 ) return -1;
+ out += l;
+ if ( out+1 >= oute ) return -1;
+ *(out++) = ')';
+ }
+
+ else if ( depth == 0 )
+ {
+ string file_name_v;
+ int file_name_l = 0;
+ const char * file_name_s = 0;
                     
- if (!split)
- {
- /* the @() reference doesn't match the @(foo:E=bar) format.
- hence we leave it alone by copying directly to output. */
- int l = 0;
- if ( out+2 >= oute ) return -1;
- *(out++) = '@';
- *(out++) = '(';
- l = var_string(in+2,out,oute-out,lol);
- if ( l < 0 ) return -1;
- out += l;
- if ( out+1 >= oute ) return -1;
- *(out++) = ')';
- in = ine;
- }
+ /* expand the temporary file name var inline */
+ #if 0
+ string_copy(&file_name_v,"$(");
+ string_append_range(&file_name_v,in+2,split);
+ string_push_back(&file_name_v,')');
+ #else
+ string_new(&file_name_v);
+ string_append_range(&file_name_v,in+2,split);
+ #endif
+ file_name_l = var_string(file_name_v.value,out,oute-out+1,lol);
+ string_free(&file_name_v);
+ if ( file_name_l < 0 ) return -1;
+ file_name_s = out;
                     
- else if ( depth == 0 )
+ /* for stdout/stderr we will create a temp file and generate
+ a command that outputs the content as needed. */
+ if ( strcmp( "STDOUT", out ) == 0 || strcmp( "STDERR", out ) == 0 )
                     {
- string file_name_v;
- int file_name_l = 0;
- const char * file_name_s = 0;
-
- /* expand the temporary file name var inline */
- #if 0
- string_copy(&file_name_v,"$(");
- string_append_range(&file_name_v,in+2,split);
- string_push_back(&file_name_v,')');
+ int err_redir = strcmp( "STDERR", out ) == 0;
+ out[0] = '\0';
+ file_name_s = path_tmpfile();
+ file_name_l = strlen(file_name_s);
+ #ifdef OS_NT
+ if ( (out+7+file_name_l+(err_redir?5:0)) >= oute ) return -1;
+ sprintf( out,"type \"%s\"%s",
+ file_name_s,
+ err_redir ? " 1>&2" : "" );
                         #else
- string_new(&file_name_v);
- string_append_range(&file_name_v,in+2,split);
+ if ( (out+6+file_name_l+(err_redir?5:0)) >= oute ) return -1;
+ sprintf( out,"cat \"%s\"%s",
+ file_name_s,
+ err_redir ? " 1>&2" : "" );
                         #endif
- file_name_l = var_string(file_name_v.value,out,oute-out+1,lol);
- string_free(&file_name_v);
- if ( file_name_l < 0 ) return -1;
- file_name_s = out;
-
- /* for stdout/stderr we will create a temp file and generate
- a command that outputs the content as needed. */
- if ( strcmp( "STDOUT", out ) == 0 || strcmp( "STDERR", out ) == 0 )
- {
- int err_redir = strcmp( "STDERR", out ) == 0;
- out[0] = '\0';
- file_name_s = path_tmpfile();
- file_name_l = strlen(file_name_s);
- #ifdef OS_NT
- if ( (out+7+file_name_l+(err_redir?5:0)) >= oute ) return -1;
- sprintf( out,"type \"%s\"%s",
- file_name_s,
- err_redir ? " 1>&2" : "" );
- #else
- if ( (out+6+file_name_l+(err_redir?5:0)) >= oute ) return -1;
- sprintf( out,"cat \"%s\"%s",
- file_name_s,
- err_redir ? " 1>&2" : "" );
- #endif
- /* we also make sure that the temp files created by this
- get nuked eventually. */
- file_remove_atexit( file_name_s );
- }
-
- /* expand the file value into the file reference */
- var_string_to_file( split+3, ine-split-4, file_name_s, lol );
-
- /* continue on with the expansion */
- out += strlen(out);
+ /* we also make sure that the temp files created by this
+ get nuked eventually. */
+ file_remove_atexit( file_name_s );
                     }
                     
- /* and continue with the parsing just past the @() reference */
- in = ine;
+ /* expand the file value into the file reference */
+ var_string_to_file( split+3, ine-split-4, file_name_s, lol );
+
+ /* continue on with the expansion */
+ out += strlen(out);
                 }
- #endif
-
- *out++ = *in++;
- }
+
+ /* and continue with the parsing just past the @() reference */
+ in = ine;
+ }
+ #endif
+ else
+ {
+ *out++ = *in++;
+ }
+ }
 
         /* Add zero to 'out' so that 'lastword' is correctly zero-terminated. */
         if (out >= oute)
@@ -321,40 +325,40 @@
         /* Don't increment, intentionally. */
         *out= '\0';
            
- /* If a variable encountered, expand it and and embed the */
- /* space-separated members of the list in the output. */
+ /* If a variable encountered, expand it and and embed the */
+ /* space-separated members of the list in the output. */
 
- if( dollar )
- {
- LIST *l;
+ if( dollar )
+ {
+ LIST *l;
 
- l = var_expand( L0, lastword, out, lol, 0 );
+ l = var_expand( L0, lastword, out, lol, 0 );
 
- out = lastword;
+ out = lastword;
 
- while ( l )
- {
- int so = strlen( l->string );
+ while ( l )
+ {
+ int so = strlen( l->string );
 
- if( out + so >= oute )
- return -1;
+ if( out + so >= oute )
+ return -1;
 
- strcpy( out, l->string );
- out += so;
- l = list_next( l );
- if ( l ) *out++ = ' ';
- }
+ strcpy( out, l->string );
+ out += so;
+ l = list_next( l );
+ if ( l ) *out++ = ' ';
+ }
 
- list_free( l );
- }
- }
+ list_free( l );
+ }
+ }
 
- if( out >= oute )
- return -1;
+ if( out >= oute )
+ return -1;
 
- *out++ = '\0';
+ *out++ = '\0';
 
- return out - out0;
+ return out - out0;
 }
 
 void var_string_to_file( const char * in, int insize, const char * out, LOL * lol )

Modified: branches/bitten/tools/jam/test/test.jam
==============================================================================
--- branches/bitten/tools/jam/test/test.jam (original)
+++ branches/bitten/tools/jam/test/test.jam 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -41,6 +41,8 @@
     }
 }
 
+include action_status.jam ;
+include actions_quietly.jam ;
 include builtin_shell.jam ;
 include builtin_w32_getregnames.jam ;
 include option_d2.jam ;

Modified: branches/bitten/tools/quickbook/doc/html/boostbook.css
==============================================================================
--- branches/bitten/tools/quickbook/doc/html/boostbook.css (original)
+++ branches/bitten/tools/quickbook/doc/html/boostbook.css 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -1,528 +0,0 @@
-/*=============================================================================
- Copyright (c) 2004 Joel de Guzman
- http://spirit.sourceforge.net/
-
- Use, modification and distribution is subject to the Boost Software
- License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- http://www.boost.org/LICENSE_1_0.txt)
-=============================================================================*/
-
-/*=============================================================================
- Body defaults
-=============================================================================*/
-
- body
- {
- margin: 1em;
- font-family: sans-serif;
- }
-
-/*=============================================================================
- Paragraphs
-=============================================================================*/
-
- p
- {
- text-align: left;
- font-size: 10pt;
- line-height: 1.15;
- }
-
-/*=============================================================================
- Program listings
-=============================================================================*/
-
- /* Code on paragraphs */
- p tt.computeroutput
- {
- font-size: 9pt;
- }
-
- pre.synopsis
- {
- font-size: 90%;
- margin: 1pc 4% 0pc 4%;
- padding: 0.5pc 0.5pc 0.5pc 0.5pc;
- }
-
- .programlisting,
- .screen
- {
- font-size: 9pt;
- display: block;
- margin: 1pc 4% 0pc 4%;
- padding: 0.5pc 0.5pc 0.5pc 0.5pc;
- }
-
- /* Program listings in tables don't get borders */
- td .programlisting,
- td .screen
- {
- margin: 0pc 0pc 0pc 0pc;
- padding: 0pc 0pc 0pc 0pc;
- }
-
-/*=============================================================================
- Headings
-=============================================================================*/
-
- h1, h2, h3, h4, h5, h6
- {
- text-align: left;
- margin: 1em 0em 0.5em 0em;
- font-weight: bold;
- }
-
- h1 { font: 140% }
- h2 { font: bold 140% }
- h3 { font: bold 130% }
- h4 { font: bold 120% }
- h5 { font: italic 110% }
- h6 { font: italic 100% }
-
- /* Top page titles */
- title,
- h1.title,
- h2.title
- h3.title,
- h4.title,
- h5.title,
- h6.title,
- .refentrytitle
- {
- font-weight: bold;
- margin-bottom: 1pc;
- }
-
- h1.title { font-size: 140% }
- h2.title { font-size: 140% }
- h3.title { font-size: 130% }
- h4.title { font-size: 120% }
- h5.title { font-size: 110% }
- h6.title { font-size: 100% }
-
- .section h1
- {
- margin: 0em 0em 0.5em 0em;
- font-size: 140%;
- }
-
- .section h2 { font-size: 140% }
- .section h3 { font-size: 130% }
- .section h4 { font-size: 120% }
- .section h5 { font-size: 110% }
- .section h6 { font-size: 100% }
-
- /* Code on titles */
- h1 tt.computeroutput { font-size: 140% }
- h2 tt.computeroutput { font-size: 140% }
- h3 tt.computeroutput { font-size: 130% }
- h4 tt.computeroutput { font-size: 120% }
- h5 tt.computeroutput { font-size: 110% }
- h6 tt.computeroutput { font-size: 100% }
-
-/*=============================================================================
- Author
-=============================================================================*/
-
- h3.author
- {
- font-size: 100%
- }
-
-/*=============================================================================
- Lists
-=============================================================================*/
-
- li
- {
- font-size: 10pt;
- line-height: 1.3;
- }
-
- /* Unordered lists */
- ul
- {
- text-align: left;
- }
-
- /* Ordered lists */
- ol
- {
- text-align: left;
- }
-
-/*=============================================================================
- Links
-=============================================================================*/
-
- a
- {
- text-decoration: none; /* no underline */
- }
-
- a:hover
- {
- text-decoration: underline;
- }
-
-/*=============================================================================
- Spirit style navigation
-=============================================================================*/
-
- .spirit-nav
- {
- text-align: right;
- }
-
- .spirit-nav a
- {
- color: white;
- padding-left: 0.5em;
- }
-
- .spirit-nav img
- {
- border-width: 0px;
- }
-
-/*=============================================================================
- Table of contents
-=============================================================================*/
-
- .toc
- {
- margin: 1pc 4% 0pc 4%;
- padding: 0.1pc 1pc 0.1pc 1pc;
- font-size: 80%;
- line-height: 1.15;
- }
-
- .boost-toc
- {
- float: right;
- padding: 0.5pc;
- }
-
-/*=============================================================================
- Tables
-=============================================================================*/
-
- .table-title,
- div.table p.title
- {
- margin-left: 4%;
- padding-right: 0.5em;
- padding-left: 0.5em;
- }
-
- .informaltable table,
- .table table
- {
- width: 92%;
- margin-left: 4%;
- margin-right: 4%;
- }
-
- div.informaltable table,
- div.table table
- {
- padding: 4px;
- }
-
- /* Table Cells */
- div.informaltable table tr td,
- div.table table tr td
- {
- padding: 0.5em;
- text-align: left;
- font-size: 9pt;
- }
-
- div.informaltable table tr th,
- div.table table tr th
- {
- padding: 0.5em 0.5em 0.5em 0.5em;
- border: 1pt solid white;
- font-size: 80%;
- }
-
-/*=============================================================================
- Blurbs
-=============================================================================*/
-
- div.note,
- div.tip,
- div.important,
- div.caution,
- div.warning,
- div.sidebar
- {
- font-size: 9pt; /* A little bit smaller than the main text */
- line-height: 1.2;
- display: block;
- margin: 1pc 4% 0pc 4%;
- padding: 0.5pc 0.5pc 0.0pc 0.5pc;
- }
-
- div.sidebar img
- {
- padding: 1pt;
- }
-
-/*=============================================================================
- Callouts
-=============================================================================*/
- .line_callout_bug img
- {
- float: left;
- position:relative;
- left: 4px;
- top: -12px;
- clear: left;
- margin-left:-22px;
- }
-
- .callout_bug img
- {
- }
-
-/*=============================================================================
- Variable Lists
-=============================================================================*/
-
- /* Make the terms in definition lists bold */
- div.variablelist dl dt,
- span.term
- {
- font-weight: bold;
- font-size: 10pt;
- }
-
- div.variablelist table tbody tr td
- {
- text-align: left;
- vertical-align: top;
- padding: 0em 2em 0em 0em;
- font-size: 10pt;
- margin: 0em 0em 0.5em 0em;
- line-height: 1;
- }
-
- div.variablelist dl dt
- {
- margin-bottom: 0.2em;
- }
-
- div.variablelist dl dd
- {
- margin: 0em 0em 0.5em 2em;
- font-size: 10pt;
- }
-
- div.variablelist table tbody tr td p,
- div.variablelist dl dd p
- {
- margin: 0em 0em 0.5em 0em;
- line-height: 1;
- }
-
-/*=============================================================================
- Misc
-=============================================================================*/
-
- /* Title of books and articles in bibliographies */
- span.title
- {
- font-style: italic;
- }
-
- span.underline
- {
- text-decoration: underline;
- }
-
- span.strikethrough
- {
- text-decoration: line-through;
- }
-
- /* Copyright, Legal Notice */
- div div.legalnotice p
- {
- text-align: left
- }
-
-/*=============================================================================
- Colors
-=============================================================================*/
-
- @media screen
- {
- /* Links */
- a
- {
- color: #005a9c;
- }
-
- a:visited
- {
- color: #9c5a9c;
- }
-
- h1 a, h2 a, h3 a, h4 a, h5 a, h6 a,
- h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover,
- h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited
- {
- text-decoration: none; /* no underline */
- color: #000000;
- }
-
- /* Syntax Highlighting */
- .keyword { color: #0000AA; }
- .identifier { color: #000000; }
- .special { color: #707070; }
- .preprocessor { color: #402080; }
- .char { color: teal; }
- .comment { color: #800000; }
- .string { color: teal; }
- .number { color: teal; }
- .white_bkd { background-color: #FFFFFF; }
- .dk_grey_bkd { background-color: #999999; }
-
- /* Copyright, Legal Notice */
- .copyright
- {
- color: #666666;
- font-size: small;
- }
-
- div div.legalnotice p
- {
- color: #666666;
- }
-
- /* Program listing */
- pre.synopsis
- {
- border: 1px solid #DCDCDC;
- }
-
- .programlisting,
- .screen
- {
- border: 1px solid #DCDCDC;
- }
-
- td .programlisting,
- td .screen
- {
- border: 0px solid #DCDCDC;
- }
-
- /* Blurbs */
- div.note,
- div.tip,
- div.important,
- div.caution,
- div.warning,
- div.sidebar
- {
- border: 1px solid #DCDCDC;
- }
-
- /* Table of contents */
- .toc
- {
- border: 1px solid #DCDCDC;
- }
-
- /* Tables */
- div.informaltable table tr td,
- div.table table tr td
- {
- border: 1px solid #DCDCDC;
- }
-
- div.informaltable table tr th,
- div.table table tr th
- {
- background-color: #F0F0F0;
- border: 1px solid #DCDCDC;
- }
-
- /* Misc */
- span.highlight
- {
- color: #00A000;
- }
- }
-
- @media print
- {
- /* Links */
- a
- {
- color: black;
- }
-
- a:visited
- {
- color: black;
- }
-
- .spirit-nav
- {
- display: none;
- }
-
- /* Program listing */
- pre.synopsis
- {
- border: 1px solid gray;
- }
-
- .programlisting,
- .screen
- {
- border: 1px solid gray;
- }
-
- td .programlisting,
- td .screen
- {
- border: 0px solid #DCDCDC;
- }
-
- /* Table of contents */
- .toc
- {
- border: 1px solid gray;
- }
-
- .informaltable table,
- .table table
- {
- border: 1px solid gray;
- border-collapse: collapse;
- }
-
- /* Tables */
- div.informaltable table tr td,
- div.table table tr td
- {
- border: 1px solid gray;
- }
-
- div.informaltable table tr th,
- div.table table tr th
- {
- border: 1px solid gray;
- }
-
- /* Misc */
- span.highlight
- {
- font-weight: bold;
- }
- }

Modified: branches/bitten/tools/quickbook/doc/quickbook.qbk
==============================================================================
--- branches/bitten/tools/quickbook/doc/quickbook.qbk (original)
+++ branches/bitten/tools/quickbook/doc/quickbook.qbk 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -2063,11 +2063,21 @@
     ;
 ]
 
+[heading Is there an easy way to convert BoostBook docs to QuickBook?]
+
+There's a stylesheet that allows Boostbook generated HTML to be viewed
+as quickbook source, see
+[@http://svn.boost.org/trac/boost/wiki/QuickbookSourceStylesheetProject],
+so it's then just a cut and paste job to convert the BoostBook to
+QuickBook (which IMO is a whole lot easier to edit and maintain).
+
+--John Maddock
+
 [endsect] [/faq]
 
 [section:ref Quick Reference]
 
-[cpp]
+[c++]
 
 [template ordered_list_sample[]
 [pre'''

Added: branches/bitten/tools/regression/src/bitten_reports.py
==============================================================================
--- (empty file)
+++ branches/bitten/tools/regression/src/bitten_reports.py 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -0,0 +1,113 @@
+# Copyright David Abrahams 2007. Distributed under the Boost
+# Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+import os.path
+import test_results
+
+try:
+ import xml.etree.cElementTree as ET
+except ImportError:
+ import elementtree.cElementTree as ET
+
+def indent(elem, level=0):
+ i = "\n" + level*" "
+ if len(elem):
+ if not elem.text or not elem.text.strip():
+ elem.text = i + " "
+ for elem in elem:
+ indent(elem, level+1)
+ if not elem.tail or not elem.tail.strip():
+ elem.tail = i
+ else:
+ if level and (not elem.tail or not elem.tail.strip()):
+ elem.tail = i
+
+def lib_subdir_and_test_name_from_target(target_name):
+ l = []
+ p = target_name.split('/')
+ for x in p[p.index('libs')+1:]:
+ if x.endswith('.test'):
+ return '/'.join(l), x[:-5]
+ l.append(x)
+ return None
+
+
+def create_bitten_reports(input_filename, failure_markup):
+ failed = False
+ results = test_results.TestResults(open(input_filename))
+
+ report = ET.Element('report', category='test',
+ generator="http://svn.boost.org/svn/boost/trunk/tools/"
+ "regression/src/bitten_reports.py")
+
+ for target, status, actions in results:
+ if status == 'skipped':
+ continue
+
+ subdir, fixture = lib_subdir_and_test_name_from_target(target)
+
+ if status == 'failed':
+ path = os.path.split(subdir)
+ if (path[-1] == 'test'):
+ lib_name = '/'.join(path[:-1])
+ else:
+ lib_name = subdir
+
+ l = failure_markup.libraries.get(lib_name)
+ if l:
+ a = actions[0]
+
+ toolset = a.properties['toolset']
+ toolset_version = a.properties['toolset-%s:version' % toolset]
+ if toolset_version:
+ toolset = '-'.join((toolset,toolset_version))
+ i = l.test_info(fixture, toolset)
+ if i:
+ print 'Marked', target, 'because of markup:', '\n'.join(
+ [ET.tostring(x) for x in i])
+ status = 'marked'
+ print 'report status:', (status == 'failed') and 'failure' or 'success'
+
+ if status == 'failed':
+ bitten_status = 'failure'
+ failed = True
+ else:
+ bitten_status = 'success'
+
+ test = ET.SubElement(
+ report, 'test', duration="0",
+ fixture=fixture,
+ name=fixture,
+ file='libs/%s/%s.cpp' % (subdir,fixture),
+ status=bitten_status)
+
+ if status is not 'success':
+ stdout = ET.SubElement(test, 'stdout')
+ stdout.text = '\n'.join([ ''.join((
+ '\n====== COMMAND ======\n',
+ a.command.strip(),
+ '\n====== BEGIN OUTPUT ======\n',
+ a.output, a.output[-1] != '\n' and '\n' or ''
+ '====== END OUTPUT ======\n'))
+ for a in actions ])
+
+ indent(report)
+
+ platform_report = ET.Element('report', category='platform')
+ platform = ET.SubElement(platform_report, 'platform')
+
+ platform.set('os', results.os[0])
+ platform.set('platform', results.os[1])
+ if results.os[2]:
+ platform.set('os-extra', results.os[2])
+ platform.set('jam-version', results.jam_version)
+ platform.set('command', results.command)
+ platform.set('timestamp', results.timestamp)
+
+ indent(platform_report)
+ return failed, ET.tostring(report, 'utf-8')
+
+if __name__ == '__main__':
+ from failure_markup import FailureMarkup
+ print create_bitten_reports('/tmp/results.xml', FailureMarkup(open('../../../boost/status/explicit-failures-markup.xml')))

Modified: branches/bitten/tools/regression/src/collect_and_upload_logs.py
==============================================================================
--- branches/bitten/tools/regression/src/collect_and_upload_logs.py (original)
+++ branches/bitten/tools/regression/src/collect_and_upload_logs.py 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -18,13 +18,6 @@
 import string
 import sys
 
-import test_results
-
-try:
- import xml.etree.cElementTree as ET
-except ImportError:
- import elementtree.cElementTree as ET
-
 def process_xml_file( input_file, output_file ):
     utils.log( 'Processing test log "%s"' % input_file )
     
@@ -88,79 +81,6 @@
         connection.putrequest('POST','http://%s%s' % (self.realhost,handler))
     def send_host(self, connection, host):
         connection.putheader('Host',self.realhost)
-
-def indent(elem, level=0):
- i = "\n" + level*" "
- if len(elem):
- if not elem.text or not elem.text.strip():
- elem.text = i + " "
- for elem in elem:
- indent(elem, level+1)
- if not elem.tail or not elem.tail.strip():
- elem.tail = i
- else:
- if level and (not elem.tail or not elem.tail.strip()):
- elem.tail = i
-
-def relpath(path, reldir):
- """Returns 'path' relative to 'reldir'."""
-
- # use normpath to ensure path separators are uniform
- path = os.path.normpath(path)
-
- # find length of reldir as prefix of path (or zero if it isn't)
- prelen = len(os.path.commonprefix((
- os.path.normcase(path),
- # add a separator to get correct prefix length
- # (normpath removes trailing separators)
- os.path.normcase(os.path.normpath(reldir)) + os.sep
- )))
- return path[prelen:]
-
-def filename_from_test(root, test):
- """Returns the source file for a test file, relative
- to `root`."""
-
- if test.endswith('.test'):
- test = ''.join((test[:-4], 'cpp'))
-
- return relpath(test, root)
-
-def create_bitten_reports(root, input_filename):
- results = test_results.TestResults(open(input_filename))
-
- report = ET.Element('report', category='test',
- generator="http://svn.boost.org/svn/boost/trunk/tools/"
- "regression/src/collect_and_upload_logs.py")
- for r in results:
- if r[1] == 'skipped':
- continue
-
- status = {'success': 'success', 'failed': 'failure'}.get(r[1])
- filename = filename_from_test(root, r[0])
- fixture = os.path.split(filename)[1]
-
- test = ET.SubElement(report, 'test', duration="0",
- fixture=fixture, name=fixture, file=filename, status=status)
- if r[1] == 'failed':
- stdout = ET.SubElement(test, 'stdout')
- output = r[2][0][2]
- stdout.text = output
- indent(report)
-
- platform_report = ET.Element('report', category='platform')
- platform = ET.SubElement(platform_report, 'platform')
-
- platform.set('os', results.os[0])
- platform.set('platform', results.os[1])
- if results.os[2]:
- platform.set('os-extra', results.os[2])
- platform.set('jam-version', results.jam_version)
- platform.set('command', results.command)
- platform.set('timestamp', results.timestamp)
-
- indent(platform_report)
- return ET.tostring(report, 'utf-8')
 
 def publish_test_logs(
     input_dirs,

Added: branches/bitten/tools/regression/src/failure_markup.py
==============================================================================
--- (empty file)
+++ branches/bitten/tools/regression/src/failure_markup.py 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -0,0 +1,175 @@
+# Copyright David Abrahams 2007. Distributed under the Boost
+# Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+import re
+try:
+ import xml.etree.cElementTree as ET
+except ImportError:
+ import elementtree.cElementTree as ET
+
+# Map glob patterns to regexps
+regexps = {}
+def _glob2regex(glob):
+ r = regexps.get(glob)
+ if r:
+ return r
+
+ r = re.compile(
+ '^%s$'
+ % '.*'.join([ re.escape(part) for part in glob.split('*') ]))
+
+ regexps[glob] = r
+ return r
+
+class Library(object):
+ def __init__(self, element):
+ self.element = element
+ self.tests = dict((t.attrib['name'],t) for t in element.findall('test'))
+
+ def unusable(self, toolset):
+ r = []
+
+ for u in self.element.findall('mark-unusable'):
+ for t in u.findall('toolset'):
+ if _glob2regex(t.attrib['name']).match(toolset):
+ r += u.findall('note') or ['no note given']
+ break
+
+ return r
+
+ def test_info(self, test, toolset):
+ r = []
+
+ test_element = self.tests.get(test, [])
+ for f in test_element:
+ found = False
+ for toolset_elt in f.findall('toolset'):
+ if _glob2regex(toolset_elt.attrib['name']).match(toolset):
+ found = True
+ break
+
+ if found:
+ r.append(test_element)
+
+ for f in self.element.findall('mark-expected-failures'):
+ matched = {'toolset':False,'test':False}
+ for e in f:
+ tag = e.tag
+ if e.tag != 'note':
+ if _glob2regex(e.attrib['name']).match(locals()[tag]):
+ matched[tag] = True
+ if not False in matched.itervalues():
+ r.append(f)
+ break
+
+ return r
+
+class FailureMarkup(object):
+ def __init__(self, stream):
+ self.markup = ET.parse(stream).getroot()
+
+ self.required_toolsets = set(
+ c.attrib['name'] for c in self.markup.findall('mark-toolset') if c.attrib['status'] == 'required')
+
+ self.libraries = dict(
+ (l.attrib['name'], Library(l)) for l in self.markup.findall('library'))
+
+ self.standard_notes = dict(
+ (c.attrib['id'],c) for c in self.markup.findall('note'))
+
+
+if __name__ == '__main__':
+ exemplar = r'''<?xml version="1.0" encoding="utf-8"?>
+<explicit-failures-markup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="explicit-failures.xsd">
+
+
+ <!-- /////////////// Toolsets /////////////// -->
+ <mark-toolset name="darwin-4.0.1" status="required"/>
+ <mark-toolset name="gcc-3.4.3_sunos" status="required"/>
+ <mark-toolset name="gcc-3_4_4_tru64" status="required"/>
+ <mark-toolset name="gcc-4.1.2_sunos_i86pc" status="required"/>
+ <!-- ... -->
+
+ <!-- /////////////// Libraries /////////////// -->
+
+ <!-- string_algo -->
+ <library name="algorithm/string">
+ <mark-unusable>
+ <toolset name="borland-5.5*"/>
+ <toolset name="msvc-7.1_stlport4"/>
+ <toolset name="iw-7_1-vc6"/>
+ <toolset name="gcc-2.95.3-stlport-4.5.3-linux"/>
+ <note author="P.Droba">
+ The compiler does not support features that are essential for the library.
+ </note>
+ </mark-unusable>
+
+ <!-- category is optional; can be something like "Native
+ compiler support" or "Corner-case tests" -->
+ <test name="regex" category="...">
+ <mark-failure>
+ <toolset name="borland-5.9*"/>
+ <toolset name="msvc-*"/>
+ <!-- date is optional; format appears to be one of
+
+ 14 Feb 06
+ 14 Feb 2006
+ 2006-02-14
+
+ -->
+
+ <note author="Andreas Huber" refid="0" date="..."/>
+ </mark-failure>
+ </test>
+
+ <!-- reason is optional; apparently can be "?" but nothing else is ever used. -->
+ <mark-expected-failures reason="...">
+ <test name="*_emulation"/>
+ <toolset name="msvc-6.5*"/>
+ <toolset name="msvc-7.0"/>
+ <toolset name="cw-8_*"/>
+ <note author="Arkadiy Vertleyb">
+ Emulation mode is not supported for this compiler.
+ </note>
+ </mark-expected-failures>
+
+ </library>
+
+ <!-- /////////////// Standard note definitions /////////////// -->
+
+ <note id="0">
+ This test fails only intermittently.
+ </note>
+
+ <note id="1">
+ The failure is caused by a problem in Boost code. The Boost developers are aware of
+ the problem and plan to fix it.
+ </note>
+
+</explicit-failures-markup>
+'''
+ import cStringIO
+ f = FailureMarkup(cStringIO.StringIO(exemplar))
+ for d in (
+ 'darwin-4.0.1', "gcc-3.4.3_sunos", "gcc-3_4_4_tru64",
+ "gcc-4.1.2_sunos_i86pc"):
+
+ assert d in f.required_toolsets
+
+ assert 'foo' not in f.libraries
+ assert 'algorithm/string' in f.libraries
+ l = f.libraries['algorithm/string']
+ assert l.unusable('borland-5.5.4')
+ assert not l.unusable('borland-5.6')
+ assert not l.test_info(test='foo', toolset='bar')
+ assert not l.test_info(test='regex', toolset='gcc')
+
+ info = l.test_info(test='regex', toolset='msvc-6.5')
+ assert len(info) == 1
+ assert info[0].tag == 'test'
+
+ assert not l.test_info(test='foobar_emulation', toolset='gcc')
+ info = l.test_info(test='foobar_emulation', toolset='msvc-6.5.1')
+ assert len(info) == 1
+ assert info[0].tag == 'mark-expected-failures'

Modified: branches/bitten/tools/regression/src/recipe.py
==============================================================================
--- branches/bitten/tools/regression/src/recipe.py (original)
+++ branches/bitten/tools/regression/src/recipe.py 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -185,7 +185,7 @@
   '''
 project_xml ='''
   <step id="%(id)s" description="Tests run in %(project_path)s" onerror="continue">
- <python:exec file="tools/regression/src/run.py" args="--incremental --library=%(project_path)s &quot;--bjam-options=${boost.bjam_options}&quot; --reflect-test-status --bitten-report=results/%(project_path)s.xml test-run create-bitten-report" />
+ <python:exec file="tools/regression/src/run.py" args="--incremental --library=%(project_path)s &quot;--bjam-options=${boost.bjam_options}&quot; &quot;--toolsets=${boost.toolsets}&quot; --reflect-test-status --bitten-report=results/%(project_path)s.xml test-run create-bitten-report" />
     <report category="test" file="results/%(project_path)s.xml" />
   </step>
 '''

Modified: branches/bitten/tools/regression/src/regression.py
==============================================================================
--- branches/bitten/tools/regression/src/regression.py (original)
+++ branches/bitten/tools/regression/src/regression.py 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -15,6 +15,7 @@
 import platform
 import sys
 import time
+from failure_markup import FailureMarkup
 
 #~ Place holder for xsl_reports/util module
 utils = None
@@ -127,7 +128,7 @@
         self.ftp_proxy=None
         self.dart_server=None
         self.bitten_report=None
- self.debug_level=0
+ self.debug_level=-1
         self.library=None
         self.mail=None
         self.smtp_login=None
@@ -142,6 +143,10 @@
         self.regression_root = root
         self.boost_root = os.path.join( self.regression_root, 'boost' )
         self.regression_results = os.path.join( self.regression_root, 'results')
+ markup_path = os.path.join(
+ self.boost_root, 'status', 'explicit-failures-markup.xml')
+ self.failure_markup = FailureMarkup(open(markup_path))
+
         self.tools_root = os.path.join( self.regression_root,'tools' )
         self.tools_bb_root = os.path.join( self.tools_root,'build', 'v2' )
         self.tools_bjam_root = os.path.join( self.tools_root,'jam', 'src' )
@@ -165,8 +170,18 @@
 
         if self.library:
             out_xml = os.path.join( *(self.library + '-x.xml').split('/') )
+ self.library_markup = self.failure_markup.libraries.get(self.library)
+
+ # The assumption is that most libraries' markup is not separated
+ # specifically by subdirectory (e.g. "libs/foo/test",
+ # "libs/foo/example",...). So if markup wasn't found we might try
+ # again.
+ libdir,subdir = os.path.split(self.library)
+ if subdir == 'test' and not self.library_markup:
+ self.library_markup = self.failure_markup.libraries.get(libdir)
         else:
             out_xml = 'test_results.xml'
+ self.library_markup = None
             
         self.out_xml = os.path.join(self.regression_results,out_xml)
             
@@ -293,15 +308,48 @@
         results_status = os.path.join( self.regression_results, 'status' )
         self.rmtree( results_libs )
         self.rmtree( results_status )
-
+
+ def toolsets_to_test(self):
+ """filter out any toolsets marked unusable"""
+ toolsets = set(self.toolsets.split(','))
+ if self.library_markup is not None:
+ unusable_toolsets = set()
+ unusability_reasons = set()
+
+ # Check for usability
+ for t in toolsets:
+ markup = self.library_markup.unusable(t)
+ if markup:
+ unusable_toolsets.add(t)
+ unusability_reasons |= set(markup)
+
+ if unusable_toolsets:
+ try:
+ import xml.etree.cElementTree as ET
+ except ImportError:
+ import elementtree.cElementTree as ET
+ print 'skipping build with toolsets:', ', '.join(unusable_toolsets)
+ print '\n'.join( [ ET.tostring(x) for x in unusability_reasons ] )
+ toolsets -= unusable_toolsets
+ return toolsets
+
     def command_test_run(self):
+ toolsets = self.toolsets_to_test()
+ build_target = '' # build all the tests
+
+ if not toolsets:
+ # Nothing left to test for this library; just build the output XML
+ # file.
+ build_target = self.out_xml
+
         self.import_utils()
         
         utils.makedirs( os.path.split(self.out_xml)[0] )
 
- test_cmd = '%s --dump-tests %s --out-xml=%s "--build-dir=%s">%s 2>&1' % (
- self.bjam_cmd( self.toolsets ),
+ test_cmd = '%s %s %s --out-xml=%s "--build-dir=%s" > "%s" 2>&1' % (
+ self.bjam_cmd( toolsets ),
             self.bjam_options,
+ build_target,
             self.out_xml,
             self.regression_results,
             self.dev_null
@@ -326,10 +374,17 @@
 
     def command_create_bitten_report(self):
         self.import_utils()
- from collect_and_upload_logs import create_bitten_reports
-
- report = create_bitten_reports(self.boost_root, self.out_xml)
+ from bitten_reports import create_bitten_reports
+
+ markup_path = os.path.join(
+ self.boost_root, 'status', 'explicit-failures-markup.xml')
+
+ markup = FailureMarkup(open(markup_path))
+ failed, report = create_bitten_reports(
+ self.out_xml, markup)
 
+ self.exit_status = failed and 1 or 0
+
         dir = os.path.split(self.bitten_report)[0]
         if not os.path.exists(dir):
             os.makedirs(dir)
@@ -446,10 +501,11 @@
         return platform.system()
 
     def log(self,message):
- sys.stdout.flush()
- sys.stderr.flush()
- sys.stderr.write( '# %s\n' % message )
- sys.stderr.flush()
+ if self.debug_level >= 0:
+ sys.stdout.flush()
+ sys.stderr.flush()
+ sys.stderr.write( '# %s\n' % message )
+ sys.stderr.flush()
 
     def rmtree(self,path):
         if os.path.exists( path ):
@@ -519,7 +575,7 @@
 
         if toolset is None:
             if self.toolsets is not None:
- toolset = string.split( self.toolsets, ',' )[0]
+ toolset = self.toolsets.split(',')[0]
             else:
                 toolset = tool[ 'default_toolset' ]
                 self.log( 'Warning: No bootstrap toolset for "%s" was specified.' % tool[ 'name' ] )
@@ -599,7 +655,7 @@
 
         if toolsets:
             import string
- cmd += ' ' + string.join(string.split( toolsets, ',' ), ' ' )
+ cmd += ' ' + string.join(toolsets, ' ' )
 
         return cmd
 

Modified: branches/bitten/tools/regression/src/run.py
==============================================================================
--- branches/bitten/tools/regression/src/run.py (original)
+++ branches/bitten/tools/regression/src/run.py 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -16,7 +16,7 @@
 root = os.getcwd()
 print '# Running regressions in %s...' % root
 
-script_sources = [ 'collect_and_upload_logs.py', 'regression.py' ]
+script_sources = [ 'bitten_reports.py', 'regression.py', 'test_results.py', 'failure_markup.py' ]
 script_local = os.path.join(root,'tools','regression','src')
 script_remote = 'http://svn.boost.org/svn/boost/branches/bitten/tools/regression/src'
 script_dir = os.path.join(root,'tools_regression_src')

Modified: branches/bitten/tools/regression/src/test_results.py
==============================================================================
--- branches/bitten/tools/regression/src/test_results.py (original)
+++ branches/bitten/tools/regression/src/test_results.py 2007-12-07 14:44:24 EST (Fri, 07 Dec 2007)
@@ -5,7 +5,6 @@
 
 import os.path
 import StringIO
-import re
 
 try:
     import xml.etree.cElementTree as ET
@@ -17,30 +16,53 @@
 except:
     from Sets import set
 
+class Action(object):
+ def __init__(self, jam_target, status, command, output, properties):
+ self.jam_target = jam_target.text
+ self.status = status
+ self.command = command.text
+ self.output = output is not None and output.text or ''
+ self.properties = {}
+ for p in properties or []:
+ self.properties[p.get('name')] = p.text
+
 class TestResults(object):
 
     def __init__(self, source):
         self.dependencies = {}
         self.dependents = {}
         self.tests = set()
- self.results = {}
+ self.actions = {}
+ self.target_name = {}
+ self.directory = {}
         if isinstance(source, basestring):
             source = StringIO.StringIO(source)
+
         self._read_xml(source)
 
+ # Find the set of targets that don't depend on anything else.
+ # This sounds as though it's coded backwards, but when you iterate
+ # through the "dependents" dictionary, you get the keys, which are all
+ # dependencies.
+ self.sources = set([ d for d in self.dependents if not d in
+ self.dependencies ])
+
     def _read_xml(self, source):
         i = iter(ET.iterparse(source, events=('start', 'end')))
         event, root = i.next()
 
+ # Parse until all targets have been seen and added below root
         for event, elem in i:
             if event == 'end' and elem.tag == 'targets':
                 break
 
+ # Presumably all this other information is required to appear before the
+ # end of the targets.
         self.jam_version = root.find('jam').get('version')
         self.os = root.find('os')
         self.os = self.os.get('name'), self.os.get('platform'), self.os.text
         self.timestamp = root.find('timestamp').text
- self.directory = root.find('directory').text
+ self.working_directory = root.find('directory').text
         self.command = root.find('command').text
 
         self._read_targets(elem)
@@ -50,66 +72,54 @@
     def _read_targets(self, targets):
         for target in targets:
             name = target.find('name').text
- path = target.find('path')
- if path is None:
+ directory = target.find('directory')
+
+ if directory is None:
                 continue
- path = path.text
+
             jam_target = target.find('jam-target').text
- jam_target = self._as_absolute_path(jam_target)
- self.dependencies[jam_target] = [self._as_absolute_path(d.text)
- for d in target.find('dependencies')]
- for d in self.dependencies[jam_target]:
- self.dependents.setdefault(d, []).append(jam_target)
+ self.directory[jam_target] = directory.text
+ self.target_name[jam_target] = name
+
+ dependencies = target.find('dependencies')
+ if dependencies is not None:
+ self.dependencies[jam_target] = [ d.text for d in dependencies]
+ for d in self.dependencies[jam_target]:
+ self.dependents.setdefault(d, []).append(jam_target)
+
             if jam_target.endswith('.test'):
                 self.tests.add(jam_target)
 
- gristed_re = re.compile('^<p([^>]+)>(.*)$')
-
- def _as_absolute_path(self, jam_target):
- m = self.gristed_re.match(jam_target)
- if m:
- result = os.path.join(self.directory, m.group(1), m.group(2))
- else:
- result = os.path.join(self.directory, jam_target)
- return os.path.normpath(result)
-
     def _read_actions(self, i):
         for event, elem in i:
             if event == 'end' and elem.tag == 'action':
- status = elem.get('status')
- target = elem.find('jam-target')
- command = elem.find('command')
- output = elem.find('output')
-
- if target is None:
- continue
-
- properties = {}
- for p in elem.find('properties') or []:
- properties[p.get('name')] = p.text
-
- name = self._as_absolute_path(target.text)
- self.results[name] = (status == '0', command.text,
- output is not None and output.text or '', properties)
+
+ jam_target = elem.find('jam-target')
+ self.actions[jam_target.text] = Action(
+ jam_target,
+ elem.get('status'),
+ elem.find('command'),
+ elem.find('output'),
+ elem.find('properties'))
+
                 elem.clear()
 
- def _follow_dependencies(self, target):
- if target in self.results:
- result = self.results[target]
- if not result[0]:
- return [(target, result[1], result[2], result[3])]
- else:
- return []
- else:
- dependencies = self.dependencies.get(target, None)
- if dependencies:
- result = []
- for d in self.dependencies.get(target, []):
- result.extend(self._follow_dependencies(d))
- return result
- return []
 
- # TOOD:
+ def _why_not_built(self, target):
+ action = self.actions.get(target)
+ if action:
+ # target's dependencies were built; target itself failed
+ return [action]
+ else:
+ # target's build action never started. Either target was already
+ # up-to-date and thus skipped, or one of its dependencies failed.
+ # Collect all failures of target's dependencies.
+ results = []
+ for d in self.dependencies.get(target, []):
+ results.extend( self._why_not_built(d) )
+ return results
+
+ # TODO:
     # Compute the duration of the tests. It's not entirely
     # clear what this should consist of. We should probably
     # add up all the durations for the different stages in
@@ -122,12 +132,17 @@
 
     def result(self):
         for test in self.tests:
- if test in self.results:
+ if test in self.actions:
                 yield (test, 'success', None)
             else:
- failures = self._follow_dependencies(test)
+ failures = self._why_not_built(test)
                 if failures:
                     yield (test, 'failed', failures)
                 else:
                     yield (test, 'skipped', None)
 
+if __name__ == '__main__':
+ r = TestResults(open('/tmp/results.xml'))
+ from pprint import pprint
+ for x in r:
+ pprint(x)


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk