Ticket #7596: process_jam_log.2.diff

File process_jam_log.2.diff, 14.8 KB (added by Robert Ramey, 10 years ago)
  • process_jam_log.cpp

     
    2424#include <ctime>
    2525#include <cctype>   // for tolower
    2626#include <cstdlib>  // for exit
     27#include <algorithm> // find
    2728
    2829using std::string;
    2930namespace xml = boost::tiny_xml;
     
    4647  typedef std::map< string, test_info > test2info_map;  // key is test-name
    4748  test2info_map test2info;
    4849
    49   fs::path boost_root;
    50   fs::path locate_root; // ALL_LOCATE_TARGET (or boost_root if none)
     50  //  get_boost_root  --------------------------------------------------------//
    5151
    52   //  set_boost_root  --------------------------------------------------------//
    53 
    54   void set_boost_root()
     52  fs::path get_boost_root()
    5553  {
    56    
    57     boost_root = fs::initial_path();
     54    // figure out where Boost Root is.
     55    fs::path ipath = fs::initial_path();
    5856
    59     for(;;)
    60     {
    61       if ( fs::exists( boost_root / "libs" ) )
    62       {
    63         fs::current_path( fs::initial_path() ); // restore initial path
    64         return;
    65       }
    66       fs::current_path( ".." );
    67       if ( boost_root == fs::current_path() )
    68       {
    69         fs::current_path( fs::initial_path() ); // restore initial path
    70         std::cout <<
    71           "Abort: process_jam_log must be run from within a boost directory tree\n";
    72         std::exit(1);
    73       }
    74       boost_root = fs::current_path();
     57    // case I - running from within boost root directory
     58    if(fs::exists(ipath / "libs"))
     59        return ipath;
     60
     61    // cast II - we're running from within a  lower level boost directory
     62    // just return the the part from the root up to the "libs"
     63    while(ipath.end() != ipath.begin()){
     64        bool end = ipath.filename() == "libs";
     65        ipath.remove_filename();
     66        if(end)
     67            break;
    7568    }
     69
     70    return ipath;
    7671  }
    7772 
    7873 //  append_html  -------------------------------------------------------------//
     
    127122        : ""
    128123        ;
    129124  }
    130  
    131125
    132126//  split --------------------------------------------------------------------//
    133127
     
    143137    return result;
    144138  }
    145139
    146 
    147140//  extract a target directory path from a jam target string  ----------------//
    148141//  s may be relative to the initial_path:
    149142//    ..\..\..\libs\foo\build\bin\libfoo.lib\vc7\debug\runtime-link-dynamic\boo.obj
     
    155148  string target_directory( const string & s )
    156149  {
    157150    string temp( s );
     151    // convert all '\' to '/'
    158152    convert_path_separators( temp );
     153    // remove the last '/' and everything that follows
    159154    temp.erase( temp.find_last_of( "/" ) ); // remove leaf
     155
     156    // remove command to leave directory
    160157    temp = split( trim_left( temp ) ).back();
    161     if ( temp[0] == '.' ) temp.erase( 0, temp.find_first_not_of( "./" ) );
    162     else temp.erase( 0, locate_root.string().size()+1 );
    163158    if ( echo )
    164159        std::cout << "\ttarget_directory( \"" << s << "\") -> \"" << temp << "\"" << std::endl;
    165160    return temp;
     
    197192
    198193  // Take a path to a target directory of test, and
    199194  // returns library name corresponding to that path.
    200   string test_path_to_library_name( string const& path )
     195  string test_path_to_library_name( fs::path const& path )
    201196  {
    202     std::string result;
    203     string::size_type start_pos( path.find( "libs/" ) );
    204     if ( start_pos == string::npos ) {
    205       start_pos = path.find( "tools/" );
     197    fs::path::iterator const & end = path.end();
     198    fs::path::iterator const & begin = path.begin();
     199
     200    // The path format is ...libs/functional/hash/test/something.test/....           
     201    // So, the part between "libs" and "test/something.test" can be considered
     202    // as library name.
     203    fs::path::iterator library_name_begin = std::find(begin, end, "libs");
     204    if(end == library_name_begin)
     205        library_name_begin = std::find(begin, end, "tools");
     206
     207    // path doesn't include any markers for library name
     208    if(library_name_begin == end)
     209        return "";
     210
     211    ++library_name_begin;
     212    fs::path::iterator library_name_end = std::find(library_name_begin, end, "test");
     213    if(end == library_name_end){
     214        // look for and element with .test in it
     215        struct contains_dot_test {
     216            const std::string m_arg;
     217            contains_dot_test() :
     218                m_arg(".test")
     219            {}
     220            bool operator()(fs::path const & fname) const{
     221                // if file name includes .test return true
     222                std::string s = fname.string();
     223                return s.end() != std::search(
     224                    s.begin(),
     225                    s.end(),
     226                    m_arg.begin(),
     227                    m_arg.end()
     228                );
     229            }
     230        };
     231        library_name_end = std::find_if(library_name_begin, end, contains_dot_test());
    206232    }
     233    if(end == library_name_end)
     234        return "";
    207235
    208     if ( start_pos != string::npos )
    209     {
    210       // The path format is ...libs/functional/hash/test/something.test/....     
    211       // So, the part between "libs" and "test/something.test" can be considered
    212       // as library name. But, for some libraries tests are located too deep,
    213       // say numeric/ublas/test/test1 directory, and some libraries have tests
    214       // in several subdirectories (regex/example and regex/test). So, nested
    215       // directory may belong to several libraries.
     236    //But, for some libraries tests are located too deep,
     237    // say numeric/ublas/test/test1 directory, and some libraries have tests
     238    // in several subdirectories (regex/example and regex/test). So, nested
     239    // directory may belong to several libraries.
    216240
    217       // To disambituate, it's possible to place a 'sublibs' file in
    218       // a directory. It means that child directories are separate libraries.
    219       // It's still possible to have tests in the directory that has 'sublibs'
    220       // file.
     241    // To disambituate, it's possible to place a 'sublibs' file in
     242    // a directory. It means that child directories are separate libraries.
     243    // It's still possible to have tests in the directory that has 'sublibs'
     244    // file.
    221245
    222       std::string interesting;
    223       start_pos = path.find( '/', start_pos ) + 1;
    224       string::size_type end_pos( path.find( ".test/", start_pos ) );
    225       end_pos = path.rfind('/', end_pos);
    226       if (path.substr(end_pos - 5, 5) == "/test")
    227         interesting = path.substr( start_pos, end_pos - 5 - start_pos );
    228       else
    229         interesting = path.substr( start_pos, end_pos - start_pos );
     246    fs::path result;
    230247
    231       // Take slash separate elements until we have corresponding 'sublibs'.
    232       end_pos = 0;
    233       for(;;)
    234       {
     248    /*
     249    // I can't implement the code below for the case where the
     250    // source code is outside the boost root tree.  So comment it out here.
     251    // Take slash separate elements until we have corresponding 'sublibs'.
     252    end_pos = 0;
     253    for(;;)
     254    {
    235255        end_pos = interesting.find('/', end_pos);
    236256        if (end_pos == string::npos) {
    237           result = interesting;
    238           break;
     257            result = interesting;
     258            break;
    239259        }
    240260        result = interesting.substr(0, end_pos);
    241261
    242262        if ( fs::exists( ( boost_root / "libs" ) / result / "sublibs" ) )
    243263        {
    244           end_pos = end_pos + 1;
     264            end_pos = end_pos + 1;
    245265        }
    246266        else
    247           break;
    248       }
     267            break;
    249268    }
     269    */
     270    return result.string();
     271}
    250272
    251     return result;
    252   }
     273// Tries to find target name in the string 'msg', starting from
     274// position start.
     275// If found, extract the directory name from the target name and
     276// stores it in 'dir', and return the position after the target name.
     277// Otherwise, returns string::npos.
     278string::size_type parse_skipped_msg_aux(const string& msg,
     279                                      string::size_type start,
     280                                      string& dir)
     281  {
    253282
    254   // Tries to find target name in the string 'msg', starting from
    255   // position start.
    256   // If found, extract the directory name from the target name and
    257   // stores it in 'dir', and return the position after the target name.
    258   // Otherwise, returns string::npos.
    259   string::size_type parse_skipped_msg_aux(const string& msg,
    260                                           string::size_type start,
    261                                           string& dir)
    262   {
     283fs::path locate_root; // ALL_LOCATE_TARGET (or boost_root if none)
     284
    263285    dir.clear();
    264286    string::size_type start_pos = msg.find( '<', start );
    265287    if ( start_pos == string::npos ) return string::npos;
     
    327349  class test_log
    328350    : boost::noncopyable
    329351  {
    330     const string & m_target_directory;
     352    const fs::path m_target_directory;
    331353    xml::element_ptr m_root;
    332354  public:
    333     test_log( const string & target_directory,
     355    test_log( const fs::path & target_directory,
    334356              const string & test_name,
    335357              const string & toolset,
    336358              bool force_new_file )
     
    338360    {
    339361      if ( !force_new_file )
    340362      {
    341         fs::path pth( locate_root / target_directory / "test_log.xml" );
     363        //fs::path pth( locate_root / target_directory / "test_log.xml" );
     364        fs::path pth( target_directory / "test_log.xml" );
    342365        fs::ifstream file( pth  );
    343366        if ( file )   // existing file
    344367        {
     
    366389     
    367390      if ( info.type.empty() )
    368391      {
    369         if ( target_directory.find( ".lib/" ) != string::npos
    370           || target_directory.find( ".dll/" ) != string::npos
    371           || target_directory.find( ".so/" ) != string::npos
    372           || target_directory.find( ".dylib/" ) != string::npos
    373           || target_directory.find( "/build/" ) != string::npos
    374           )
    375         {
    376           info.type = "lib";
     392        struct contains_substring {
     393            const std::string m_arg;
     394            const std::string::const_iterator m_begin, m_end;
     395            contains_substring(const std::string & arg) :
     396                m_arg(arg),
     397                m_begin(m_arg.begin()),
     398                m_end(m_arg.end())
     399            {}
     400            bool operator()(fs::path const & fname) const{
     401                // if file name includes .test return true
     402                std::string s = fname.string();
     403                return s.end() != std::search(
     404                    s.begin(),
     405                    s.end(),
     406                    m_begin,
     407                    m_end
     408                );
     409            }
     410        };
     411        fs::path::iterator const begin = target_directory.begin();
     412        fs::path::iterator const end = target_directory.end();
     413
     414        if( end != std::find_if(begin, end, contains_substring(".lib"))
     415        || end != std::find_if(begin, end, contains_substring(".dll"))
     416        || end != std::find_if(begin, end, contains_substring(".so"))
     417        || end != std::find_if(begin, end, contains_substring(".dylib"))
     418        || end != std::find_if(begin, end, contains_substring("build"))
     419        ){
     420            info.type = "lib";
    377421        }
    378         else if ( target_directory.find( ".pyd/" ) != string::npos )
    379           info.type = "pyd";
     422        else
     423        if( end != std::find_if(begin, end, contains_substring(".pyd")) ){
     424            info.type = "pyd";
     425        }
    380426      }
    381427 
    382428      m_root.reset( new xml::element( "test-log" ) );
     
    389435      m_root->attributes.push_back(
    390436        xml::attribute( "test-program", info.file_path ) );
    391437      m_root->attributes.push_back(
    392         xml::attribute( "target-directory", target_directory ) );
     438        xml::attribute( "target-directory", target_directory.string() ) );
    393439      m_root->attributes.push_back(
    394440        xml::attribute( "toolset", toolset ) );
    395441      m_root->attributes.push_back(
     
    399445
    400446    ~test_log()
    401447    {
    402       fs::path pth( locate_root / m_target_directory / "test_log.xml" );
     448      //fs::path pth( locate_root / m_target_directory / "test_log.xml" );
     449      fs::path pth( m_target_directory / "test_log.xml" );
    403450      if ( create_dirs && !fs::exists( pth.branch_path() ) )
    404451          fs::create_directories( pth.branch_path() );
    405452      fs::ofstream file( pth );
     
    411458      else xml::write( *m_root, file );
    412459    }
    413460
    414     const string & target_directory() const { return m_target_directory; }
     461    const fs::path & target_directory() const { return m_target_directory; }
    415462
    416463    void remove_action( const string & action_name )
    417464    // no effect if action_name not found
     
    562609  // streams are implemented using standard C files.
    563610  std::ios::sync_with_stdio(false);
    564611
     612  fs::path locate_root; // ALL_LOCATE_TARGET (or boost_root if none)
     613
    565614  fs::initial_path();
    566615  std::istream* input = 0;
    567616
     
    615664        std::cout << "Abort: option --boost-root requires a directory argument\n";
    616665        std::exit(1);
    617666      }
     667      /*
    618668      boost_root = fs::path( argv[1] );
    619669      if ( !boost_root.is_complete() )
    620670        boost_root = ( fs::initial_path() / boost_root ).normalize();
    621      
     671      */
    622672      --argc; ++argv;
     673     
    623674    }
    624675    else if ( std::strcmp( argv[1], "--locate-root" ) == 0 )
    625676    {
     
    655706    }
    656707  }
    657708
     709  /*
    658710  if ( boost_root.empty() )
    659711  {
    660     set_boost_root();
     712    boost_root = get_boost_root();
     713    if(boost_root.empty()){
     714        std::cout <<
     715            "Abort: Failed to discover boost root\n";
     716        std::exit(1);
     717    }
    661718    boost_root.normalize();
    662719  }
     720  */
    663721
    664  
     722  /*
    665723  if ( locate_root.empty() )
    666724  {
    667725    locate_root = boost_root;
    668726  }
    669727  else if ( !locate_root.is_complete() )
    670728  {
    671     locate_root = ( fs::initial_path() / locate_root ).normalize();
    672   }   
     729    //locate_root = ( fs::initial_path() / locate_root ).normalize();
     730    locate_root = locate_root.normalize();
     731  }
    673732
     733  if(locate_root.empty())
     734    if(! fs::exists("bin"))
     735      locate_root = find_boost_root(fs::initial_path());
     736  */
     737
    674738  if ( input == 0 )
    675   {
    676739    input = &std::cin;
    677   }
    678740
    679   std::cout << "boost_root: " << boost_root.string() << '\n'
    680             << "locate_root: " << locate_root.string() << '\n';
     741  std::cout << "locate_root: " << locate_root.string() << '\n';
    681742
    682743  message_manager mgr;
    683744
     
    746807
    747808    // these actions represent both the start of a new action
    748809    // and the end of a failed action
    749     else if ( line_start.find( "C++-action" ) != string::npos
     810    else if (
     811        // bjam.log files sometimes contain the target.cpp and nothting else
     812        line_start.rfind( ".cpp") == string::npos &&
     813      (line_start.find( "C++-action" ) != string::npos
    750814      || line_start.find( "vc-C++" ) != string::npos
    751815      || line_start.find( "C-action" ) != string::npos
    752816      || line_start.find( "Cc-action" ) != string::npos
     
    762826           // .linkonce is present in gcc linker messages about
    763827           // unresolved symbols. We don't have to parse those
    764828           line_start.find( ".linkonce" ) == string::npos )
     829      )
    765830    )
    766831    {
    767832      //~ if ( !test2info.size() )