diff options
Diffstat (limited to 'tools/regression/src/process_jam_log.cpp')
-rw-r--r-- | tools/regression/src/process_jam_log.cpp | 893 |
1 files changed, 0 insertions, 893 deletions
diff --git a/tools/regression/src/process_jam_log.cpp b/tools/regression/src/process_jam_log.cpp deleted file mode 100644 index 8f1b19b06..000000000 --- a/tools/regression/src/process_jam_log.cpp +++ /dev/null @@ -1,893 +0,0 @@ -// process jam regression test output into XML -----------------------------// - -// Copyright Beman Dawes 2002. 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) - -// See http://www.boost.org/tools/regression for documentation. - -#define BOOST_FILESYSTEM_VERSION 3 - -#include <boost/config/warning_disable.hpp> - -#include "detail/tiny_xml.hpp" -#include "boost/filesystem/operations.hpp" -#include "boost/filesystem/fstream.hpp" -#include "boost/filesystem/exception.hpp" -#include "boost/filesystem/convenience.hpp" - -#include <iostream> -#include <string> -#include <cstring> -#include <map> -#include <utility> // for make_pair -#include <ctime> -#include <cctype> // for tolower -#include <cstdlib> // for exit - -using std::string; -namespace xml = boost::tiny_xml; -namespace fs = boost::filesystem; - -// options - -static bool echo = false; -static bool create_dirs = false; -static bool boost_build_v2 = true; - -namespace -{ - struct test_info - { - string file_path; // relative boost-root - string type; - bool always_show_run_output; - }; - typedef std::map< string, test_info > test2info_map; // key is test-name - test2info_map test2info; - - fs::path boost_root; - fs::path locate_root; // ALL_LOCATE_TARGET (or boost_root if none) - - // set_boost_root --------------------------------------------------------// - - void set_boost_root() - { - - boost_root = fs::initial_path(); - - for(;;) - { - if ( fs::exists( boost_root / "libs" ) ) - { - fs::current_path( fs::initial_path() ); // restore initial path - return; - } - fs::current_path( ".." ); - if ( boost_root == fs::current_path() ) - { - fs::current_path( fs::initial_path() ); // restore initial path - std::cout << - "Abort: process_jam_log must be run from within a boost directory tree\n"; - std::exit(1); - } - boost_root = fs::current_path(); - } - } - - // append_html -------------------------------------------------------------// - - void append_html( const string & src, string & target ) - { - // there are a few lines we want to ignore - if ( src.find( "th target..." ) != string::npos - || src.find( "cc1plus.exe: warning: changing search order for system directory" ) != string::npos - || src.find( "cc1plus.exe: warning: as it has already been specified as a non-system directory" ) != string::npos - ) return; - - // on some platforms (e.g. tru64cxx) the following line is a real performance boost - target.reserve(src.size() * 2 + target.size()); - - for ( string::size_type pos = 0; pos < src.size(); ++pos ) - { - if ( src[pos] == '<' ) target += "<"; - else if ( src[pos] == '>' ) target += ">"; - else if ( src[pos] == '&' ) target += "&"; - else target += src[pos]; - } - } - - // timestamp ---------------------------------------------------------------// - - string timestamp() - { - char run_date[128]; - std::time_t tod; - std::time( &tod ); - std::strftime( run_date, sizeof(run_date), - "%Y-%m-%d %X UTC", std::gmtime( &tod ) ); - return string( run_date ); - } - -// convert path separators to forward slashes ------------------------------// - - void convert_path_separators( string & s ) - { - for ( string::iterator itr = s.begin(); itr != s.end(); ++itr ) - if ( *itr == '\\' || *itr == '!' ) *itr = '/'; - } - -// trim_left ----------------------------------------------------------------// - - std::string trim_left( std::string const& s ) - { - std::string::size_type const pos( s.find_first_not_of(' ') ); - return pos != std::string::npos - ? s.substr( pos, s.size() - pos + 1 ) - : "" - ; - } - - -// split --------------------------------------------------------------------// - - std::vector<std::string> split( std::string const& s ) - { - std::string::size_type const pos( s.find_first_of(' ') ); - std::vector<std::string> result( 1, s.substr( 0, pos ) ); - if ( pos == std::string::npos ) - return result; - - std::vector<std::string> const rest( split( trim_left( s.substr( pos, s.size() - pos + 1 ) ) ) ); - result.insert( result.end(), rest.begin(), rest.end() ); - return result; - } - - -// extract a target directory path from a jam target string ----------------// -// s may be relative to the initial_path: -// ..\..\..\libs\foo\build\bin\libfoo.lib\vc7\debug\runtime-link-dynamic\boo.obj -// s may be absolute: -// d:\myboost\libs\foo\build\bin\libfoo.lib\vc7\debug\runtime-link-dynamic\boo.obj -// return path is always relative to the boost directory tree: -// libs/foo/build/bin/libfs.lib/vc7/debug/runtime-link-dynamic - - string target_directory( const string & s ) - { - string temp( s ); - convert_path_separators( temp ); - temp.erase( temp.find_last_of( "/" ) ); // remove leaf - temp = split( trim_left( temp ) ).back(); - if ( temp[0] == '.' ) temp.erase( 0, temp.find_first_not_of( "./" ) ); - else temp.erase( 0, locate_root.string().size()+1 ); - if ( echo ) - std::cout << "\ttarget_directory( \"" << s << "\") -> \"" << temp << "\"" << std::endl; - return temp; - } - - string::size_type target_name_end( const string & s ) - { - string::size_type pos = s.find( ".test/" ); - if ( pos == string::npos ) pos = s.find( ".dll/" ); - if ( pos == string::npos ) pos = s.find( ".so/" ); - if ( pos == string::npos ) pos = s.find( ".lib/" ); - if ( pos == string::npos ) pos = s.find( ".pyd/" ); - if ( pos == string::npos ) pos = s.find( ".a/" ); - return pos; - } - - string toolset( const string & s ) - { - string::size_type pos = target_name_end( s ); - if ( pos == string::npos ) pos = s.find( "build/" ); - if ( pos == string::npos ) return ""; - pos = s.find( "/", pos ) + 1; - return s.substr( pos, s.find( "/", pos ) - pos ); - } - - string test_name( const string & s ) - { - string::size_type pos = target_name_end( s ); - if ( pos == string::npos ) return ""; - string::size_type pos_start = s.rfind( '/', pos ) + 1; - return s.substr( pos_start, - (s.find( ".test/" ) != string::npos - ? pos : s.find( "/", pos )) - pos_start ); - } - - // Take a path to a target directory of test, and - // returns library name corresponding to that path. - string test_path_to_library_name( string const& path ) - { - std::string result; - string::size_type start_pos( path.find( "libs/" ) ); - if ( start_pos == string::npos ) { - start_pos = path.find( "tools/" ); - } - - if ( start_pos != string::npos ) - { - // The path format is ...libs/functional/hash/test/something.test/.... - // So, the part between "libs" and "test/something.test" can be considered - // as library name. But, for some libraries tests are located too deep, - // say numeric/ublas/test/test1 directory, and some libraries have tests - // in several subdirectories (regex/example and regex/test). So, nested - // directory may belong to several libraries. - - // To disambituate, it's possible to place a 'sublibs' file in - // a directory. It means that child directories are separate libraries. - // It's still possible to have tests in the directory that has 'sublibs' - // file. - - std::string interesting; - start_pos = path.find( '/', start_pos ) + 1; - string::size_type end_pos( path.find( ".test/", start_pos ) ); - end_pos = path.rfind('/', end_pos); - if (path.substr(end_pos - 5, 5) == "/test") - interesting = path.substr( start_pos, end_pos - 5 - start_pos ); - else - interesting = path.substr( start_pos, end_pos - start_pos ); - - // Take slash separate elements until we have corresponding 'sublibs'. - end_pos = 0; - for(;;) - { - end_pos = interesting.find('/', end_pos); - if (end_pos == string::npos) { - result = interesting; - break; - } - result = interesting.substr(0, end_pos); - - if ( fs::exists( ( boost_root / "libs" ) / result / "sublibs" ) ) - { - end_pos = end_pos + 1; - } - else - break; - } - } - - return result; - } - - // Tries to find target name in the string 'msg', starting from - // position start. - // If found, extract the directory name from the target name and - // stores it in 'dir', and return the position after the target name. - // Otherwise, returns string::npos. - string::size_type parse_skipped_msg_aux(const string& msg, - string::size_type start, - string& dir) - { - dir.clear(); - string::size_type start_pos = msg.find( '<', start ); - if ( start_pos == string::npos ) return string::npos; - ++start_pos; - string::size_type end_pos = msg.find( '>', start_pos ); - dir += msg.substr( start_pos, end_pos - start_pos ); - if ( boost_build_v2 ) - { - // The first letter is a magic value indicating - // the type of grist. - convert_path_separators( dir ); - dir.erase( 0, 1 ); - // We need path from root, not from 'status' dir. - if (dir.find("../") == 0) - dir.erase(0,3); - else // dir is always relative to the boost directory tree - dir.erase( 0, locate_root.string().size()+1 ); - } - else - { - if ( dir[0] == '@' ) - { - // new style build path, rooted build tree - convert_path_separators( dir ); - dir.replace( 0, 1, "bin/" ); - } - else - { - // old style build path, integrated build tree - start_pos = dir.rfind( '!' ); - convert_path_separators( dir ); - string::size_type path_sep_pos = dir.find( '/', start_pos + 1 ); - if ( path_sep_pos != string::npos ) - dir.insert( path_sep_pos, "/bin" ); - else - { - // see http://article.gmane.org/gmane.comp.lib.boost.devel/146688; - // the following code assumes that: a) 'dir' is not empty, - // b) 'end_pos != string::npos' and c) 'msg' always ends with '...' - if ( dir[dir.size() - 1] == '@' ) - dir += "/" + msg.substr( end_pos + 1, msg.size() - end_pos - 1 - 3 ); - } - } - } - return end_pos; - } - - // the format of paths is really kinky, so convert to normal form - // first path is missing the leading "..\". - // first path is missing "\bin" after "status". - // second path is missing the leading "..\". - // second path is missing "\bin" after "build". - // second path uses "!" for some separators. - void parse_skipped_msg( const string & msg, - string & first_dir, string & second_dir ) - { - string::size_type pos = parse_skipped_msg_aux(msg, 0, first_dir); - if (pos == string::npos) - return; - parse_skipped_msg_aux(msg, pos, second_dir); - } - -// test_log hides database details -----------------------------------------// - - class test_log - : boost::noncopyable - { - const string & m_target_directory; - xml::element_ptr m_root; - public: - test_log( const string & target_directory, - const string & test_name, - const string & toolset, - bool force_new_file ) - : m_target_directory( target_directory ) - { - if ( !force_new_file ) - { - fs::path pth( locate_root / target_directory / "test_log.xml" ); - fs::ifstream file( pth ); - if ( file ) // existing file - { - try - { - m_root = xml::parse( file, pth.string() ); - return; - } - catch(...) - { - // unable to parse existing XML file, fall through - } - } - } - - string library_name( test_path_to_library_name( target_directory ) ); - - test_info info; - test2info_map::iterator itr( test2info.find( library_name + "/" + test_name ) ); - if ( itr != test2info.end() ) - info = itr->second; - - if ( !info.file_path.empty() ) - library_name = test_path_to_library_name( info.file_path ); - - if ( info.type.empty() ) - { - if ( target_directory.find( ".lib/" ) != string::npos - || target_directory.find( ".dll/" ) != string::npos - || target_directory.find( ".so/" ) != string::npos - || target_directory.find( ".dylib/" ) != string::npos - || target_directory.find( "/build/" ) != string::npos - ) - { - info.type = "lib"; - } - else if ( target_directory.find( ".pyd/" ) != string::npos ) - info.type = "pyd"; - } - - m_root.reset( new xml::element( "test-log" ) ); - m_root->attributes.push_back( - xml::attribute( "library", library_name ) ); - m_root->attributes.push_back( - xml::attribute( "test-name", test_name ) ); - m_root->attributes.push_back( - xml::attribute( "test-type", info.type ) ); - m_root->attributes.push_back( - xml::attribute( "test-program", info.file_path ) ); - m_root->attributes.push_back( - xml::attribute( "target-directory", target_directory ) ); - m_root->attributes.push_back( - xml::attribute( "toolset", toolset ) ); - m_root->attributes.push_back( - xml::attribute( "show-run-output", - info.always_show_run_output ? "true" : "false" ) ); - } - - ~test_log() - { - fs::path pth( locate_root / m_target_directory / "test_log.xml" ); - if ( create_dirs && !fs::exists( pth.branch_path() ) ) - fs::create_directories( pth.branch_path() ); - fs::ofstream file( pth ); - if ( !file ) - { - std::cout << "*****Warning - can't open output file: " - << pth.string() << "\n"; - } - else xml::write( *m_root, file ); - } - - const string & target_directory() const { return m_target_directory; } - - void remove_action( const string & action_name ) - // no effect if action_name not found - { - xml::element_list::iterator itr; - for ( itr = m_root->elements.begin(); - itr != m_root->elements.end() && (*itr)->name != action_name; - ++itr ) {} - if ( itr != m_root->elements.end() ) m_root->elements.erase( itr ); - } - - void add_action( const string & action_name, - const string & result, - const string & timestamp, - const string & content ) - { - remove_action( action_name ); - xml::element_ptr action( new xml::element(action_name) ); - m_root->elements.push_back( action ); - action->attributes.push_back( xml::attribute( "result", result ) ); - action->attributes.push_back( xml::attribute( "timestamp", timestamp ) ); - action->content = content; - } - }; - -// message_manager maps input messages into test_log actions ---------------// - - class message_manager - : boost::noncopyable - { - string m_action_name; // !empty() implies action pending - // IOW, a start_message awaits stop_message - string m_target_directory; - string m_test_name; - string m_toolset; - - bool m_note; // if true, run result set to "note" - // set false by start_message() - - // data needed to stop further compile action after a compile failure - // detected in the same target directory - string m_previous_target_directory; - bool m_compile_failed; - - public: - message_manager() : m_note(false) {} - ~message_manager() { /*assert( m_action_name.empty() );*/ } - - bool note() const { return m_note; } - void note( bool value ) { m_note = value; } - - void start_message( const string & action_name, - const string & target_directory, - const string & test_name, - const string & toolset, - const string & prior_content ) - { - assert( !target_directory.empty() ); - - if ( !m_action_name.empty() ) stop_message( prior_content ); - m_action_name = action_name; - m_target_directory = target_directory; - m_test_name = test_name; - m_toolset = toolset; - m_note = false; - - if ( m_previous_target_directory != target_directory ) - { - m_previous_target_directory = target_directory; - m_compile_failed = false; - } - } - - void stop_message( const string & content ) - { - if ( m_action_name.empty() ) return; - stop_message( m_action_name, m_target_directory, - "succeed", timestamp(), content ); - } - - void stop_message( const string & action_name, - const string & target_directory, - const string & result, - const string & timestamp, - const string & content ) - // the only valid action_names are "compile", "link", "run", "lib" - { - // My understanding of the jam output is that there should never be - // a stop_message that was not preceeded by a matching start_message. - // That understanding is built into message_manager code. - assert( m_action_name == action_name ); - assert( m_target_directory == target_directory ); - assert( result == "succeed" || result == "fail" ); - - // if test_log.xml entry needed - if ( !m_compile_failed - || action_name != "compile" - || m_previous_target_directory != target_directory ) - { - if ( action_name == "compile" - && result == "fail" ) m_compile_failed = true; - - test_log tl( target_directory, - m_test_name, m_toolset, action_name == "compile" ); - tl.remove_action( "lib" ); // always clear out lib residue - - // dependency removal - if ( action_name == "lib" ) - { - tl.remove_action( "compile" ); - tl.remove_action( "link" ); - tl.remove_action( "run" ); - } - else if ( action_name == "compile" ) - { - tl.remove_action( "link" ); - tl.remove_action( "run" ); - if ( result == "fail" ) m_compile_failed = true; - } - else if ( action_name == "link" ) - { - tl.remove_action( "run" ); - } - - // dependency removal won't work right with random names, so assert - else { assert( action_name == "run" ); } - - // add the "run" stop_message action - tl.add_action( action_name, - result == "succeed" && note() ? std::string("note") : result, - timestamp, content ); - } - - m_action_name = ""; // signal no pending action - m_previous_target_directory = target_directory; - } - }; -} - - -// main --------------------------------------------------------------------// - - -int main( int argc, char ** argv ) -{ - // Turn off synchronization with corresponding C standard library files. This - // gives a significant speed improvement on platforms where the standard C++ - // streams are implemented using standard C files. - std::ios::sync_with_stdio(false); - - fs::initial_path(); - std::istream* input = 0; - - if ( argc <= 1 ) - { - std::cout << "process_jam_log [--echo] [--create-directories] [--v1|--v2]\n" - " [--boost-root boost_root] [--locate-root locate_root]\n" - " [--input-file input_file]\n" - " [locate-root]\n" - "--echo - verbose diagnostic output.\n" - "--create-directories - if the directory for xml file doesn't exists - creates it.\n" - " usually used for processing logfile on different machine\n" - "--v2 - bjam version 2 used (default).\n" - "--v1 - bjam version 1 used.\n" - "--boost-root - the root of the boost installation being used. If not defined\n" - " assume to run from within it and discover it heuristically.\n" - "--locate-root - the same as the bjam ALL_LOCATE_TARGET\n" - " parameter, if any. Default is boost-root.\n" - "--input-file - the output of a bjam --dump-tests run. Default is std input.\n" - ; - return 1; - } - - while ( argc > 1 ) - { - if ( std::strcmp( argv[1], "--echo" ) == 0 ) - { - echo = true; - --argc; ++argv; - } - else if ( std::strcmp( argv[1], "--create-directories" ) == 0 ) - { - create_dirs = true; - --argc; ++argv; - } - else if ( std::strcmp( argv[1], "--v2" ) == 0 ) - { - boost_build_v2 = true; - --argc; ++argv; - } - else if ( std::strcmp( argv[1], "--v1" ) == 0 ) - { - boost_build_v2 = false; - --argc; ++argv; - } - else if ( std::strcmp( argv[1], "--boost-root" ) == 0 ) - { - --argc; ++argv; - if ( argc == 1 ) - { - std::cout << "Abort: option --boost-root requires a directory argument\n"; - std::exit(1); - } - boost_root = fs::path( argv[1] ); - if ( !boost_root.is_complete() ) - boost_root = ( fs::initial_path() / boost_root ).normalize(); - - --argc; ++argv; - } - else if ( std::strcmp( argv[1], "--locate-root" ) == 0 ) - { - --argc; ++argv; - if ( argc == 1 ) - { - std::cout << "Abort: option --locate-root requires a directory argument\n"; - std::exit(1); - } - locate_root = fs::path( argv[1] ); - --argc; ++argv; - } - else if ( std::strcmp( argv[1], "--input-file" ) == 0 ) - { - --argc; ++argv; - if ( argc == 1 ) - { - std::cout << "Abort: option --input-file requires a filename argument\n"; - std::exit(1); - } - input = new std::ifstream(argv[1]); - --argc; ++argv; - } - else if ( *argv[1] == '-' ) - { - std::cout << "Abort: unknown option; invoke with no arguments to see list of valid options\n"; - return 1; - } - else - { - locate_root = fs::path( argv[1] ); - --argc; ++argv; - } - } - - if ( boost_root.empty() ) - { - set_boost_root(); - boost_root.normalize(); - } - - - if ( locate_root.empty() ) - { - locate_root = boost_root; - } - else if ( !locate_root.is_complete() ) - { - locate_root = ( fs::initial_path() / locate_root ).normalize(); - } - - if ( input == 0 ) - { - input = &std::cin; - } - - std::cout << "boost_root: " << boost_root.string() << '\n' - << "locate_root: " << locate_root.string() << '\n'; - - message_manager mgr; - - string line; - string content; - bool capture_lines = false; - - // This loop looks at lines for certain signatures, and accordingly: - // * Calls start_message() to start capturing lines. (start_message() will - // automatically call stop_message() if needed.) - // * Calls stop_message() to stop capturing lines. - // * Capture lines if line capture on. - - static const int max_line_length = 8192; - int line_num = 0; - while ( std::getline( *input, line ) ) - { - if (max_line_length < line.size()) line = line.substr(0, max_line_length); - - ++line_num; - - std::vector<std::string> const line_parts( split( line ) ); - std::string const line_start( line_parts[0] != "...failed" - ? line_parts[0] - : line_parts[0] + " " + line_parts[1] - ); - - if ( echo ) - { - std::cout - << "line " << line_num << ": " << line << "\n" - << "\tline_start: " << line_start << "\n"; - } - - // create map of test-name to test-info - if ( line_start.find( "boost-test(" ) == 0 ) - { - string::size_type pos = line.find( '"' ); - string test_name( line.substr( pos+1, line.find( '"', pos+1)-pos-1 ) ); - test_info info; - info.always_show_run_output - = line.find( "\"always_show_run_output\"" ) != string::npos; - info.type = line.substr( 11, line.find( ')' )-11 ); - for (unsigned int i = 0; i!=info.type.size(); ++i ) - { info.type[i] = std::tolower( info.type[i] ); } - pos = line.find( ':' ); - // the rest of line is missing if bjam didn't know how to make target - if ( pos + 1 != line.size() ) - { - info.file_path = line.substr( pos+3, - line.find( "\"", pos+3 )-pos-3 ); - convert_path_separators( info.file_path ); - if ( info.file_path.find( "libs/libs/" ) == 0 ) info.file_path.erase( 0, 5 ); - if ( test_name.find( "/" ) == string::npos ) - test_name = "/" + test_name; - test2info.insert( std::make_pair( test_name, info ) ); - // std::cout << test_name << ", " << info.type << ", " << info.file_path << "\n"; - } - else - { - std::cout << "*****Warning - missing test path: " << line << "\n" - << " (Usually occurs when bjam doesn't know how to make a target)\n"; - } - continue; - } - - // these actions represent both the start of a new action - // and the end of a failed action - else if ( line_start.find( "C++-action" ) != string::npos - || line_start.find( "vc-C++" ) != string::npos - || line_start.find( "C-action" ) != string::npos - || line_start.find( "Cc-action" ) != string::npos - || line_start.find( "vc-Cc" ) != string::npos - || line_start.find( ".compile.") != string::npos - || line_start.find( "compile-") != string::npos - || line_start.find( "-compile") != string::npos - || line_start.find( "Link-action" ) != string::npos - || line_start.find( "vc-Link" ) != string::npos - || line_start.find( "Archive-action" ) != string::npos - || line_start.find( ".archive") != string::npos - || ( line_start.find( ".link") != string::npos && - // .linkonce is present in gcc linker messages about - // unresolved symbols. We don't have to parse those - line_start.find( ".linkonce" ) == string::npos ) - ) - { - //~ if ( !test2info.size() ) - //~ { - //~ std::cout << "*****Error - No \"boost-test\" lines encountered.\n" - //~ " (Usually occurs when bjam was envoked without the --dump-tests option\n" - //~ " or bjam was envoked in the wrong directory)\n"; - //~ return 1; - //~ } - - string action( ( line_start.find( "Link-action" ) != string::npos - || line_start.find( "vc-Link" ) != string::npos - || line_start.find( "Archive-action" ) != string::npos - || line_start.find( ".archive") != string::npos - || line_start.find( ".link") != string::npos - ) - ? "link" : "compile" - ); - - if ( line_start.find( "...failed " ) != string::npos ) - { - mgr.stop_message( action, target_directory( line ), - "fail", timestamp(), content ); - } - else - { - string target_dir( target_directory( line ) ); - mgr.start_message( action, target_dir, - test_name( target_dir ), toolset( target_dir ), content ); - } - content = "\n"; - capture_lines = true; - } - - // these actions are only used to stop the previous action - else if ( line_start.find( "-Archive" ) != string::npos - || line_start.find( "MkDir" ) == 0 - || line_start.find( "common.mkdir" ) == 0 ) - { - mgr.stop_message( content ); - content.clear(); - capture_lines = false; - } - - else if ( line_start.find( "execute-test" ) != string::npos - || line_start.find( "capture-output" ) != string::npos ) - { - if ( line_start.find( "...failed " ) != string::npos ) - { - mgr.stop_message( "run", target_directory( line ), - "fail", timestamp(), content ); - content = "\n"; - capture_lines = true; - } - else - { - string target_dir( target_directory( line ) ); - mgr.start_message( "run", target_dir, - test_name( target_dir ), toolset( target_dir ), content ); - - // contents of .output file for content - capture_lines = false; - content = "\n"; - fs::ifstream file( locate_root / target_dir - / (test_name(target_dir) + ".output") ); - if ( file ) - { - string ln; - while ( std::getline( file, ln ) ) - { - if ( ln.find( "<note>" ) != string::npos ) mgr.note( true ); - append_html( ln, content ); - content += "\n"; - } - } - } - } - - // bjam indicates some prior dependency failed by a "...skipped" message - else if ( line_start.find( "...skipped" ) != string::npos - && line.find( "<directory-grist>" ) == string::npos - ) - { - mgr.stop_message( content ); - content.clear(); - capture_lines = false; - - if ( line.find( " for lack of " ) != string::npos ) - { - capture_lines = ( line.find( ".run for lack of " ) == string::npos ); - - string target_dir; - string lib_dir; - - parse_skipped_msg( line, target_dir, lib_dir ); - - if ( target_dir != lib_dir ) // it's a lib problem - { - mgr.start_message( "lib", target_dir, - test_name( target_dir ), toolset( target_dir ), content ); - content = lib_dir; - mgr.stop_message( "lib", target_dir, "fail", timestamp(), content ); - content = "\n"; - } - } - - } - - else if ( line_start.find( "**passed**" ) != string::npos - || line_start.find( "failed-test-file" ) != string::npos - || line_start.find( "command-file-dump" ) != string::npos ) - { - mgr.stop_message( content ); - content = "\n"; - capture_lines = true; - } - - else if ( capture_lines ) // hang onto lines for possible later use - { - append_html( line, content );; - content += "\n"; - } - } - - mgr.stop_message( content ); - if (input != &std::cin) - delete input; - return 0; -} |