summaryrefslogtreecommitdiff
path: root/tools/regression/src/library_status.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/regression/src/library_status.cpp')
-rw-r--r--tools/regression/src/library_status.cpp889
1 files changed, 0 insertions, 889 deletions
diff --git a/tools/regression/src/library_status.cpp b/tools/regression/src/library_status.cpp
deleted file mode 100644
index 3faa0f63c..000000000
--- a/tools/regression/src/library_status.cpp
+++ /dev/null
@@ -1,889 +0,0 @@
-// Generate Library Status HTML from jam regression test output -----------//
-
-// Copyright Bryce Lelbach 2011
-// Copyright Beman Dawes 2002-2011.
-
-// 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.
-
-//Note: This version of the original program builds a large table
-//which includes all build variations such as build/release, static/dynamic, etc.
-
-
-/*******************************************************************************
-
-This program was designed to work unchanged on all platforms and
-configurations. All output which is platform or configuration dependent
-is obtained from external sources such as the .xml file from
-process_jam_log execution, the tools/build/xxx-tools.jam files, or the
-output of the config_info tests.
-
-Please avoid adding platform or configuration dependencies during
-program maintenance.
-
-*******************************************************************************/
-
-#include <boost/filesystem/operations.hpp>
-#include <boost/filesystem/fstream.hpp>
-#include <boost/foreach.hpp>
-
-namespace fs = boost::filesystem;
-
-#include "detail/tiny_xml.hpp"
-namespace xml = boost::tiny_xml;
-
-#include <boost/iterator/transform_iterator.hpp>
-
-#include <cstdlib> // for abort, exit
-#include <string>
-#include <vector>
-#include <set>
-#include <utility> // for make_pair on STLPort
-#include <map>
-#include <algorithm> // max_element, find_if
-#include <iostream>
-#include <fstream>
-#include <ctime>
-#include <stdexcept>
-#include <cassert>
-#include <utility> // for pair
-
-using std::string;
-
-const string pass_msg( "Pass" );
-const string warn_msg( "<i>Warn</i>" );
-const string fail_msg( "<font color=\"#FF0000\"><i>Fail</i></font>" );
-const string missing_residue_msg( "<i>Missing</i>" );
-
-const std::size_t max_compile_msg_size = 10000;
-
-namespace
-{
- fs::path locate_root; // locate-root (AKA ALL_LOCATE_TARGET) complete path
- bool ignore_pass = false;
- bool no_warn = false;
- bool no_links = false;
-
- // transform pathname to something html can accept
- struct char_xlate {
- typedef char result_type;
- result_type operator()(char c) const{
- if(c == '/' || c == '\\')
- return '-';
- return c;
- }
- };
- typedef boost::transform_iterator<char_xlate, std::string::const_iterator> html_from_path;
-
- template<class I1, class I2>
- std::ostream & operator<<(
- std::ostream &os,
- std::pair<I1, I2> p
- ){
- while(p.first != p.second)
- os << *p.first++;
- return os;
- }
-
- struct col_node {
- int rows, cols;
- bool is_leaf;
- typedef std::pair<const std::string, col_node> subcolumn;
- typedef std::map<std::string, col_node> subcolumns_t;
- subcolumns_t m_subcolumns;
- bool operator<(const col_node &cn) const;
- col_node() :
- is_leaf(false)
- {}
- std::pair<int, int> get_spans();
- };
-
- std::pair<int, int> col_node::get_spans(){
- rows = 1;
- cols = 0;
- if(is_leaf){
- cols = 1;
- }
- if(! m_subcolumns.empty()){
- BOOST_FOREACH(
- subcolumn & s,
- m_subcolumns
- ){
- std::pair<int, int> spans;
- spans = s.second.get_spans();
- rows = (std::max)(rows, spans.first);
- cols += spans.second;
- }
- ++rows;
- }
- return std::make_pair(rows, cols);
- }
-
- void build_node_tree(const fs::path & dir_root, col_node & node){
- bool has_directories = false;
- bool has_files = false;
- BOOST_FOREACH(
- fs::directory_entry & d,
- std::make_pair(
- fs::directory_iterator(dir_root),
- fs::directory_iterator()
- )
- ){
- if(fs::is_directory(d)){
- has_directories = true;
- std::pair<col_node::subcolumns_t::iterator, bool> result
- = node.m_subcolumns.insert(
- std::make_pair(d.path().filename().string(), col_node())
- );
- build_node_tree(d, result.first->second);
- }
- else{
- has_files = true;
- }
- }
- if(has_directories && has_files)
- throw std::string("invalid bin directory structure");
- node.is_leaf = has_files;
- }
-
- fs::ofstream report;
- fs::ofstream links_file;
- string links_name;
-
- string specific_compiler; // if running on one toolset only
-
- const string empty_string;
-
- // extract object library name from target directory string ----------------//
-
- string extract_object_library_name( const string & s )
- {
- string t( s );
- string::size_type pos = t.find( "/build/" );
- if ( pos != string::npos ) pos += 7;
- else if ( (pos = t.find( "/test/" )) != string::npos ) pos += 6;
- else return "";
- return t.substr( pos, t.find( "/", pos ) - pos );
- }
-
- // find_element ------------------------------------------------------------//
-
- struct element_equal {
- const string & m_name;
- element_equal(const string & name) :
- m_name(name)
- {}
- bool operator()(const xml::element_ptr & xep) const {
- return xep.get()->name == m_name;
- }
- };
-
- xml::element_list::const_iterator find_element(
- const xml::element & root, const string & name
- ){
- return std::find_if(
- root.elements.begin(),
- root.elements.end(),
- element_equal(name)
- );
- }
-
- // element_content ---------------------------------------------------------//
- const string & element_content(
- const xml::element & root, const string & name
- ){
- xml::element_list::const_iterator itr;
- itr = find_element(root, name);
- if(root.elements.end() == itr)
- return empty_string;
- return (*itr)->content;
- }
-
- // attribute_value ----------------------------------------------------------//
-
- struct attribute_equal {
- const string & m_name;
- attribute_equal(const string & name) :
- m_name(name)
- {}
- bool operator()(const xml::attribute & a) const {
- return a.name == m_name;
- }
- };
-
- const string & attribute_value(
- const xml::element & element,
- const string & attribute_name
- ){
- xml::attribute_list::const_iterator itr;
- itr = std::find_if(
- element.attributes.begin(),
- element.attributes.end(),
- attribute_equal(attribute_name)
- );
- if(element.attributes.end() == itr){
- static const string empty_string;
- return empty_string;
- }
- return itr->value;
- }
-
- // generate_report ---------------------------------------------------------//
-
- // return 0 if nothing generated, 1 otherwise, except 2 if compiler msgs
- int generate_report(
- const xml::element & db,
- const std::string source_library_name,
- const string & test_type,
- const fs::path & target_dir,
- bool pass,
- bool always_show_run_output
- )
- {
- // compile msgs sometimes modified, so make a local copy
- string compile( ((pass && no_warn)
- ? empty_string : element_content( db, "compile" )) );
-
- const string & link( pass ? empty_string : element_content( db, "link" ) );
- const string & run( (pass && !always_show_run_output)
- ? empty_string : element_content( db, "run" ) );
- string lib( (pass ? empty_string : element_content( db, "lib" )) );
-
- // some compilers output the filename even if there are no errors or
- // warnings; detect this if one line of output and it contains no space.
- string::size_type pos = compile.find( '\n', 1 );
- if ( pos != string::npos && compile.size()-pos <= 2
- && compile.find( ' ' ) == string::npos ) compile.clear();
-
- if ( lib.empty()
- && (
- compile.empty() || test_type == "compile_fail"
- )
- && link.empty()
- && run.empty()
- )
- return 0;
-
- int result = 1; // some kind of msg for sure
-
- // limit compile message length
- if ( compile.size() > max_compile_msg_size )
- {
- compile.erase( max_compile_msg_size );
- compile += "...\n (remainder deleted because of excessive size)\n";
- }
-
- const string target_dir_string = target_dir.string();
-
- links_file << "<h2><a name=\"";
- links_file << std::make_pair(
- html_from_path(target_dir_string.begin()),
- html_from_path(target_dir_string.end())
- )
- << "\">"
- << std::make_pair(
- html_from_path(target_dir_string.begin()),
- html_from_path(target_dir_string.end())
- )
- ;
- links_file << "</a></h2>\n";;
-
- if ( !compile.empty() )
- {
- ++result;
- links_file << "<h3>Compiler output:</h3><pre>"
- << compile << "</pre>\n";
- }
- if ( !link.empty() )
- links_file << "<h3>Linker output:</h3><pre>" << link << "</pre>\n";
- if ( !run.empty() )
- links_file << "<h3>Run output:</h3><pre>" << run << "</pre>\n";
-
- // for an object library failure, generate a reference to the object
- // library failure message, and (once only) generate the object
- // library failure message itself
- static std::set< string > failed_lib_target_dirs; // only generate once
- if ( !lib.empty() )
- {
- if ( lib[0] == '\n' ) lib.erase( 0, 1 );
- string object_library_name( extract_object_library_name( lib ) );
-
- // changing the target directory naming scheme breaks
- // extract_object_library_name()
- assert( !object_library_name.empty() );
- if ( object_library_name.empty() )
- std::cerr << "Failed to extract object library name from " << lib << "\n";
-
- links_file << "<h3>Library build failure: </h3>\n"
- "See <a href=\"#"
- << source_library_name << "-"
- << object_library_name << "-"
- << std::make_pair(
- html_from_path(target_dir_string.begin()),
- html_from_path(target_dir_string.end())
- )
- << source_library_name << " - "
- << object_library_name << " - "
- << std::make_pair(
- html_from_path(target_dir_string.begin()),
- html_from_path(target_dir_string.end())
- )
- << "</a>";
- if ( failed_lib_target_dirs.find( lib ) == failed_lib_target_dirs.end() )
- {
- failed_lib_target_dirs.insert( lib );
- fs::path pth( locate_root / lib / "test_log.xml" );
- fs::ifstream file( pth );
- if ( file )
- {
- xml::element_ptr db = xml::parse( file, pth.string() );
- generate_report(
- *db,
- source_library_name,
- test_type,
- target_dir,
- false,
- false
- );
- }
- else
- {
- links_file << "<h2><a name=\""
- << object_library_name << "-"
- << std::make_pair(
- html_from_path(target_dir_string.begin()),
- html_from_path(target_dir_string.end())
- )
- << "\">"
- << object_library_name << " - "
- << std::make_pair(
- html_from_path(target_dir_string.begin()),
- html_from_path(target_dir_string.end())
- )
- << "</a></h2>\n"
- << "test_log.xml not found\n";
- }
- }
- }
- return result;
- }
-
- struct has_fail_result {
- //bool operator()(const boost::shared_ptr<const xml::element> e) const {
- bool operator()(const xml::element_ptr & e) const {
- return attribute_value(*e, "result") == "fail";
- }
- };
-
- // do_cell ---------------------------------------------------------------//
- bool do_cell(
- const fs::path & target_dir,
- const string & lib_name,
- const string & test_name,
- string & target,
- bool profile
- ){
- // return true if any results except pass_msg
- bool pass = false;
-
- fs::path xml_file_path( target_dir / "test_log.xml" );
- if ( !fs::exists( xml_file_path ) )
- {
- fs::path test_path = target_dir / (test_name + ".test");
- target += "<td align=\"right\">";
- target += fs::exists( test_path) ? pass_msg : fail_msg;
- target += "</td>";
- return true;
- }
-
-
- string test_type( "unknown" );
- bool always_show_run_output( false );
-
- fs::ifstream file( xml_file_path );
- xml::element_ptr dbp = xml::parse( file, xml_file_path.string() );
- const xml::element & db( *dbp );
-
- always_show_run_output
- = attribute_value( db, "show-run-output" ) == "true";
-
- // if we don't find any failures
- // mark it as a pass
- pass = (db.elements.end() == std::find_if(
- db.elements.begin(),
- db.elements.end(),
- has_fail_result()
- ));
-
- int anything_generated = 0;
- if (!no_links){
- anything_generated =
- generate_report(
- db,
- lib_name,
- test_type,
- target_dir,
- pass,
- always_show_run_output
- );
- }
-
- // generate the status table cell pass/warn/fail HTML
- target += "<td align=\"right\">";
- if ( anything_generated != 0 )
- {
- target += "<a href=\"";
- target += links_name;
- target += "#";
- const string target_dir_string = target_dir.string();
- std::copy(
- html_from_path(target_dir_string.begin()),
- html_from_path(target_dir_string.end()),
- std::back_inserter(target)
- );
- target += "\">";
- target += pass
- ? (anything_generated < 2 ? pass_msg : warn_msg)
- : fail_msg;
- target += "</a>";
- }
- else target += pass ? pass_msg : fail_msg;
-
- // if profiling
- if(profile && pass){
- // add link to profile
- target += " <a href=\"";
- target += (target_dir / "profile.txt").string();
- target += "\"><i>Profile</i></a>";
- }
- target += "</td>";
- return (anything_generated != 0) || !pass;
- }
-
- bool visit_node_tree(
- const col_node & node,
- fs::path dir_root,
- const string & lib_name,
- const string & test_name,
- string & target,
- bool profile
- ){
- bool retval = false;
- if(node.is_leaf){
- return do_cell(
- dir_root,
- lib_name,
- test_name,
- target,
- profile
- );
- }
- BOOST_FOREACH(
- const col_node::subcolumn & s,
- node.m_subcolumns
- ){
- fs::path subdir = dir_root / s.first;
- retval |= visit_node_tree(
- s.second,
- subdir,
- lib_name,
- test_name,
- target,
- s.first == "profile"
- );
- }
- return retval;
- }
-
- // emit results for each test
- void do_row(
- col_node test_node,
- const fs::path & test_dir,
- const string & lib_name,
- const string & test_name,
- string & target
- ){
- string::size_type row_start_pos = target.size();
-
- target += "<tr>";
-
- target += "<td>";
- //target += "<a href=\"" + url_prefix_dir_view + "/libs/" + lib_name + "\">";
- target += test_name;
- //target += "</a>";
- target += "</td>";
-
- bool no_warn_save = no_warn;
-
- // emit cells on this row
- bool anything_to_report = visit_node_tree(
- test_node,
- test_dir,
- lib_name,
- test_name,
- target,
- false
- );
-
- target += "</tr>";
-
- if ( ignore_pass
- && ! anything_to_report )
- target.erase( row_start_pos );
-
- no_warn = no_warn_save;
- }
-
- // do_table_body -----------------------------------------------------------//
-
- void do_table_body(
- col_node root_node,
- const string & lib_name,
- const fs::path & test_lib_dir
- ){
- // rows are held in a vector so they can be sorted, if desired.
- std::vector<string> results;
-
- BOOST_FOREACH(
- fs::directory_entry & d,
- std::make_pair(
- fs::directory_iterator(test_lib_dir),
- fs::directory_iterator()
- )
- ){
- if(! fs::is_directory(d))
- continue;
-
- // if the file name contains ".test"
- if(d.path().extension() != ".test")
- continue;
-
- string test_name = d.path().stem().string();
-
- results.push_back( std::string() );
- do_row(
- root_node, //*test_node_itr++,
- d, // test dir
- lib_name,
- test_name,
- results[results.size()-1]
- );
- }
-
- std::sort( results.begin(), results.end() );
-
- BOOST_FOREACH(string &s, results)
- report << s << "\n";
- }
-
- // column header-----------------------------------------------------------//
- int header_depth(const col_node & root){
- int max_depth = 1;
- BOOST_FOREACH(
- const col_node::subcolumn &s,
- root.m_subcolumns
- ){
- max_depth = (std::max)(max_depth, s.second.rows);
- }
- return max_depth;
- }
-
- void header_cell(int rows, int cols, const std::string & name){
- // add row cells
- report << "<td align=\"center\" " ;
- if(1 < cols)
- report << "colspan=\"" << cols << "\" " ;
- if(1 < rows)
- // span rows to the end the header
- report << "rowspan=\"" << rows << "\" " ;
- report << ">" ;
- report << name;
- report << "</td>\n";
- }
-
- void emit_column_headers(
- const col_node & node,
- int display_row,
- int current_row,
- int row_count
- ){
- if(current_row < display_row){
- if(! node.m_subcolumns.empty()){
- BOOST_FOREACH(
- const col_node::subcolumn &s,
- node.m_subcolumns
- ){
- emit_column_headers(
- s.second,
- display_row,
- current_row + 1,
- row_count
- );
- }
- }
- return;
- }
- /*
- if(node.is_leaf && ! node.m_subcolumns.empty()){
- header_cell(row_count - current_row, 1, std::string(""));
- }
- */
- BOOST_FOREACH(col_node::subcolumn s, node.m_subcolumns){
- if(1 == s.second.rows)
- header_cell(row_count - current_row, s.second.cols, s.first);
- else
- header_cell(1, s.second.cols, s.first);
- }
- }
-
- fs::path find_lib_test_dir(fs::path const& initial_path){
- // walk up from the path were we started until we find
- // bin or bin.v2
-
- fs::path test_lib_dir = initial_path;
- do{
- if(fs::is_directory( test_lib_dir / "bin.v2")){
- test_lib_dir /= "bin.v2";
- break;
- }
- if(fs::is_directory( test_lib_dir / "bin")){
- // v1 includes the word boost
- test_lib_dir /= "bin";
- if(fs::is_directory( test_lib_dir / "boost")){
- test_lib_dir /= "boost";
- }
- break;
- }
- }while(! test_lib_dir.empty());
-
- if(test_lib_dir.empty())
- throw std::string("binary path not found");
-
- return test_lib_dir;
- }
-
- string find_lib_name(fs::path lib_test_dir){
- // search the path backwards for the magic name "libs"
- fs::path::iterator e_itr = lib_test_dir.end();
- while(lib_test_dir.begin() != e_itr){
- if(*--e_itr == "libs")
- break;
- }
-
- // if its found
- if(lib_test_dir.begin() != e_itr){
- // use the whole path since the "libs"
- ++e_itr;
- }
- // otherwise, just use the last two components
- else{
- e_itr = lib_test_dir.end();
- if(e_itr != lib_test_dir.begin()){
- if(--e_itr != lib_test_dir.begin()){
- --e_itr;
- }
- }
- }
-
- fs::path library_name;
- while(lib_test_dir.end() != e_itr){
- library_name /= *e_itr++;
- }
- return library_name.string();
- }
-
- fs::path find_boost_root(fs::path initial_path){
- fs::path boost_root = initial_path;
- for(;;){
- if(fs::is_directory( boost_root / "boost")){
- break;
- }
- if(boost_root.empty())
- throw std::string("boost root not found");
- boost_root.remove_filename();
- }
-
- return boost_root;
- }
-
- // do_table ----------------------------------------------------------------//
- void do_table(const fs::path & lib_test_dir, const string & lib_name)
- {
- col_node root_node;
-
- BOOST_FOREACH(
- fs::directory_entry & d,
- std::make_pair(
- fs::directory_iterator(lib_test_dir),
- fs::directory_iterator()
- )
- ){
- if(! fs::is_directory(d))
- continue;
- fs::path p = d.path();
- if(p.extension() != ".test")
- continue;
- build_node_tree(d, root_node);
- }
-
- // visit directory nodes and record nodetree
- report << "<table border=\"1\" cellspacing=\"0\" cellpadding=\"5\">\n";
-
- // emit
- root_node.get_spans();
- int row_count = header_depth(root_node);
- report << "<tr>\n";
- report << "<td rowspan=\"" << row_count << "\">Test Name</td>\n";
-
- // emit column headers
- int row_index = 0;
- for(;;){
- emit_column_headers(root_node, row_index, 0, row_count);
- report << "</tr>" ;
- if(++row_index == row_count)
- break;
- report << "<tr>\n";
- }
-
- // now the rest of the table body
- do_table_body(root_node, lib_name, lib_test_dir);
-
- report << "</table>\n";
- }
-}// unnamed namespace
-
-// main --------------------------------------------------------------------//
-
-#define BOOST_NO_CPP_MAIN_SUCCESS_MESSAGE
-#include <boost/test/included/prg_exec_monitor.hpp>
-
-int cpp_main( int argc, char * argv[] ) // note name!
-{
- fs::path initial_path = fs::initial_path();
-
- while ( argc > 1 && *argv[1] == '-' )
- {
- if ( argc > 2 && std::strcmp( argv[1], "--compiler" ) == 0 )
- { specific_compiler = argv[2]; --argc; ++argv; }
- else if ( argc > 2 && std::strcmp( argv[1], "--locate-root" ) == 0 )
- { locate_root = fs::path( argv[2] ); --argc; ++argv; }
- else if ( std::strcmp( argv[1], "--ignore-pass" ) == 0 ) ignore_pass = true;
- else if ( std::strcmp( argv[1], "--no-warn" ) == 0 ) no_warn = true;
- else if ( std::strcmp( argv[1], "--v2" ) == 0 )
- {--argc; ++argv ;} // skip
- else if ( argc > 2 && std::strcmp( argv[1], "--jamfile" ) == 0)
- {--argc; ++argv;} // skip
- else { std::cerr << "Unknown option: " << argv[1] << "\n"; argc = 1; }
- --argc;
- ++argv;
- }
-
- if ( argc != 2 && argc != 3 )
- {
- std::cerr <<
- "Usage: library_status [options...] status-file [links-file]\n"
- " boost-root is the path to the boost tree root directory.\n"
- " status-file and links-file are paths to the output files.\n"
- " options: --compiler name Run for named compiler only\n"
- " --ignore-pass Do not report tests which pass all compilers\n"
- " --no-warn Warnings not reported if test passes\n"
- " --locate-root path Path to ALL_LOCATE_TARGET for bjam;\n"
- " default boost-root.\n"
- "Example: library_status --compiler gcc /boost-root cs.html cs-links.html\n"
- "Note: Only the leaf of the links-file path is\n"
- "used in status-file HTML links. Thus for browsing, status-file,\n"
- "links-file must be in the same directory.\n"
- ;
- return 1;
- }
-
- if(locate_root.empty())
- if(! fs::exists("bin") && ! fs::exists("bin.v2"))
- locate_root = find_boost_root(initial_path);
-
- report.open( fs::path( argv[1] ) );
- if ( !report )
- {
- std::cerr << "Could not open report output file: " << argv[2] << std::endl;
- return 1;
- }
-
- if ( argc == 3 )
- {
- fs::path links_path( argv[2] );
- links_name = links_path.filename().string();
- links_file.open( links_path );
- if ( !links_file )
- {
- std::cerr << "Could not open links output file: " << argv[3] << std::endl;
- return 1;
- }
- }
- else no_links = true;
-
- const string library_name = find_lib_name(initial_path);
-
- char run_date[128];
- std::time_t tod;
- std::time( &tod );
- std::strftime( run_date, sizeof(run_date),
- "%X UTC, %A %d %B %Y", std::gmtime( &tod ) );
-
- report
- << "<html>\n"
- << "<head>\n"
- << "<title>Boost Library Status Automatic Test</title>\n"
- << "</head>\n"
- << "<body bgcolor=\"#ffffff\" text=\"#000000\">\n"
- << "<table border=\"0\">\n"
- << "<h1>Library Status: " + library_name + "</h1>\n"
- << "<b>Run Date:</b> "
- << run_date
- << "\n<br>"
- ;
-
- report << "</td>\n</table>\n<br>\n";
-
- if ( !no_links )
- {
- links_file
- << "<html>\n"
- << "<head>\n"
- << "<title>Boost Library Status Error Log</title>\n"
- << "</head>\n"
- << "<body bgcolor=\"#ffffff\" text=\"#000000\">\n"
- << "<table border=\"0\">\n"
- << "<h1>Library Status: " + library_name + "</h1>\n"
- << "<b>Run Date:</b> "
- << run_date
- << "\n<br></table>\n<br>\n"
- ;
- }
-
- // detect whether in a a directory which looks like
- // bin/<library name>/test
- // or just
- // bin
- fs::path library_test_directory = find_lib_test_dir(locate_root);
- // if libs exists, drop down a couple of levels
- if(fs::is_directory( library_test_directory / "libs")){
- library_test_directory /= "libs";
- library_test_directory /= library_name;
- }
-
- do_table(library_test_directory, library_name);
-
- report << "</body>\n"
- "</html>\n"
- ;
-
- if ( !no_links )
- {
- links_file
- << "</body>\n"
- "</html>\n"
- ;
- }
- return 0;
-}