📄 process_jam_log.cpp
字号:
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(); if ( argc <= 1 ) std::cout << "Usage: bjam [bjam-args] | process_jam_log [--echo] [--create-directories] [--v1|v2] [locate-root]\n" "locate-root - the same as the bjam ALL_LOCATE_TARGET\n" " parameter, if any. Default is boost-root.\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" ; set_boost_root(); boost_root.normalize(); if ( argc > 1 && std::strcmp( argv[1], "--echo" ) == 0 ) { echo = true; --argc; ++argv; } if (argc > 1 && std::strcmp( argv[1], "--create-directories" ) == 0 ) { create_dirs = true; --argc; ++argv; } if ( argc > 1 && std::strcmp( argv[1], "--v2" ) == 0 ) { boost_build_v2 = true; --argc; ++argv; } if ( argc > 1 && std::strcmp( argv[1], "--v1" ) == 0 ) { boost_build_v2 = false; --argc; ++argv; } if (argc > 1) { locate_root = fs::path( argv[1], fs::native ); if ( !locate_root.is_complete() ) locate_root = ( fs::initial_path() / locate_root ).normalize(); --argc; ++argv; } else { locate_root = boost_root; } 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; std::istream* input; if (argc > 1) { input = new std::ifstream(argv[1]); } else { input = &std::cin; } // 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. int line_num = 0; while ( std::getline( *input, line ) ) { ++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 ) { 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -