proj_tree.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:16k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: proj_tree.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 18:31:29  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.3
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: proj_tree.cpp,v 1000.1 2004/06/01 18:31:29 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Viatcheslav Gorelenkov
  35.  *
  36.  */
  37. #include <ncbi_pch.hpp>
  38. #include <app/project_tree_builder/proj_tree.hpp>
  39. #include <app/project_tree_builder/proj_tree_builder.hpp>
  40. #include <app/project_tree_builder/proj_utils.hpp>
  41. #include <app/project_tree_builder/proj_builder_app.hpp>
  42. #include <algorithm>
  43. BEGIN_NCBI_SCOPE
  44. //-----------------------------------------------------------------------------
  45. CProjectItemsTree::CProjectItemsTree(void)
  46. {
  47.     Clear();
  48. }
  49. CProjectItemsTree::CProjectItemsTree(const string& root_src)
  50. {
  51.     Clear();
  52.     m_RootSrc = root_src;
  53. }
  54. CProjectItemsTree::CProjectItemsTree(const CProjectItemsTree& projects)
  55. {
  56.     SetFrom(projects);
  57. }
  58. CProjectItemsTree& 
  59. CProjectItemsTree::operator= (const CProjectItemsTree& projects)
  60. {
  61.     if (this != &projects) {
  62.         Clear();
  63.         SetFrom(projects);
  64.     }
  65.     return *this;
  66. }
  67. CProjectItemsTree::~CProjectItemsTree(void)
  68. {
  69.     Clear();
  70. }
  71. void CProjectItemsTree::Clear(void)
  72. {
  73.     m_RootSrc.erase();
  74.     m_Projects.clear();
  75. }
  76. void CProjectItemsTree::SetFrom(const CProjectItemsTree& projects)
  77. {
  78.     m_RootSrc  = projects.m_RootSrc;
  79.     m_Projects = projects.m_Projects;
  80. }
  81. void CProjectItemsTree::CreateFrom(const string& root_src,
  82.                                    const TFiles& makein, 
  83.                                    const TFiles& makelib, 
  84.                                    const TFiles& makeapp, 
  85.                                    const TFiles& makemsvc, 
  86.                                    CProjectItemsTree* tree)
  87. {
  88.     tree->m_Projects.clear();
  89.     tree->m_RootSrc = root_src;
  90.     ITERATE(TFiles, p, makein) {
  91.         const string& fc_path = p->first;
  92.         const CSimpleMakeFileContents& fc_makein = p->second;
  93.         string source_base_dir;
  94.         CDirEntry::SplitPath(fc_path, &source_base_dir);
  95.         SMakeProjectT::TMakeInInfoList list_info;
  96.         SMakeProjectT::AnalyzeMakeIn(fc_makein, &list_info);
  97.         ITERATE(SMakeProjectT::TMakeInInfoList, i, list_info) {
  98.             const SMakeProjectT::SMakeInInfo& info = *i;
  99.             //Iterate all project_name(s) from makefile.in 
  100.             ITERATE(list<string>, n, info.m_ProjNames) {
  101.                 //project id will be defined latter
  102.                 const string proj_name = *n;
  103.         
  104.                 string applib_mfilepath = 
  105.                     CDirEntry::ConcatPath(source_base_dir,
  106.                     SMakeProjectT::CreateMakeAppLibFileName(source_base_dir, 
  107.                                                             proj_name));
  108.                 if ( applib_mfilepath.empty() )
  109.                     continue;
  110.             
  111.                 if (info.m_Type == SMakeProjectT::SMakeInInfo::eApp) {
  112.                     SAsnProjectT::TAsnType asn_type = 
  113.                         SAsnProjectT::GetAsnProjectType(applib_mfilepath,
  114.                                                         makeapp,
  115.                                                         makelib);
  116.                     if (asn_type == SAsnProjectT::eMultiple) {
  117.                         SAsnProjectT::DoCreate(source_base_dir, 
  118.                                                proj_name, 
  119.                                                applib_mfilepath, 
  120.                                                makeapp, makelib, tree);
  121.                     } else {
  122.                         SAppProjectT::DoCreate(source_base_dir, 
  123.                                                proj_name, 
  124.                                                applib_mfilepath, 
  125.                                                makeapp, tree);
  126.                     }
  127.                 }
  128.                 else if (info.m_Type == SMakeProjectT::SMakeInInfo::eLib) {
  129.                     SAsnProjectT::TAsnType asn_type = 
  130.                         SAsnProjectT::GetAsnProjectType(applib_mfilepath,
  131.                                                         makeapp,
  132.                                                         makelib);
  133.                     if (asn_type == SAsnProjectT::eMultiple) {
  134.                         SAsnProjectT::DoCreate(source_base_dir, 
  135.                                                proj_name, 
  136.                                                applib_mfilepath, 
  137.                                                makeapp, makelib, tree);
  138.                     } else {
  139.                         SLibProjectT::DoCreate(source_base_dir, 
  140.                                                proj_name, 
  141.                                                applib_mfilepath, 
  142.                                                makelib, tree);
  143.                     }
  144.                 }
  145.                 else if (info.m_Type == SMakeProjectT::SMakeInInfo::eAsn) {
  146.                     SAsnProjectT::DoCreate(source_base_dir, 
  147.                                            proj_name, 
  148.                                            applib_mfilepath, 
  149.                                            makeapp, makelib, tree);
  150.                 }
  151.                 else if (info.m_Type == SMakeProjectT::SMakeInInfo::eMsvc) {
  152.                     SMsvcProjectT::DoCreate(source_base_dir,
  153.                                             proj_name,
  154.                                             applib_mfilepath,
  155.                                             makemsvc, tree);
  156.                 }
  157.             }
  158.         }
  159.     }
  160.     {{
  161.         // REQUIRES tags in Makefile.in(s)
  162.         ITERATE(TFiles, p, makein) {
  163.             string makein_dir;
  164.             CDirEntry::SplitPath(p->first, &makein_dir);
  165.             const CSimpleMakeFileContents& makein_contents = p->second;
  166.             NON_CONST_ITERATE(TProjects, n, tree->m_Projects) {
  167.                 CProjItem& project = n->second;
  168.                 if ( IsSubdir(makein_dir, project.m_SourcesBaseDir) ) {
  169.                     CSimpleMakeFileContents::TContents::const_iterator k = 
  170.                         makein_contents.m_Contents.find("REQUIRES");
  171.                     if ( k != makein_contents.m_Contents.end() ) {
  172.                         const list<string> requires = k->second;
  173.                         copy(requires.begin(), 
  174.                              requires.end(), 
  175.                              back_inserter(project.m_Requires));
  176.                         
  177.                         project.m_Requires.sort();
  178.                         project.m_Requires.unique();
  179.                     }
  180.                 }
  181.             }
  182.         }
  183.     }}
  184. }
  185. void CProjectItemsTree::GetInternalDepends(list<CProjKey>* depends) const
  186. {
  187.     depends->clear();
  188.     set<CProjKey> depends_set;
  189.     ITERATE(TProjects, p, m_Projects) {
  190.         const CProjItem& proj_item = p->second;
  191.         ITERATE(list<CProjKey>, n, proj_item.m_Depends) {
  192.             depends_set.insert(*n);
  193.         }
  194.     }
  195.     copy(depends_set.begin(), depends_set.end(), back_inserter(*depends));
  196. }
  197. void 
  198. CProjectItemsTree::GetExternalDepends(list<CProjKey>* external_depends) const
  199. {
  200.     external_depends->clear();
  201.     list<CProjKey> depends;
  202.     GetInternalDepends(&depends);
  203.     ITERATE(list<CProjKey>, p, depends) {
  204.         const CProjKey& depend_id = *p;
  205.         if (m_Projects.find(depend_id) == m_Projects.end())
  206.             external_depends->push_back(depend_id);
  207.     }
  208. }
  209. //-----------------------------------------------------------------------------
  210. void CCyclicDepends::FindCycles(const TProjects& tree,
  211.                                 TDependsCycles*  cycles)
  212. {
  213.     cycles->clear();
  214.     ITERATE(TProjects, p, tree) {
  215.         // Look throgh all projects in tree.
  216.         const CProjKey& project_id = p->first;
  217.         // If this proj_id was already reported in some cycle, 
  218.         // it's no need to test it again.
  219.         if ( !IsInAnyCycle(project_id, *cycles) ) {
  220.             // Analyze for cycles
  221.             AnalyzeProjItem(project_id, tree, cycles);
  222.         }
  223.     }
  224. }
  225. bool CCyclicDepends::IsInAnyCycle(const CProjKey&       proj_id,
  226.                                   const TDependsCycles& cycles)
  227. {
  228.     ITERATE(TDependsCycles, p, cycles) {
  229.         const TDependsChain& cycle = *p;
  230.         if (find(cycle.begin(), cycle.end(), proj_id) != cycle.end())
  231.             return true;
  232.     }
  233.     return false;
  234. }
  235. void CCyclicDepends::AnalyzeProjItem(const CProjKey&  proj_id,
  236.                                      const TProjects& tree,
  237.                                      TDependsCycles*  cycles)
  238. {
  239.     TProjects::const_iterator p = tree.find(proj_id);
  240.     if (p == tree.end()) {
  241.         LOG_POST( Error << "Unknown project: " << proj_id.Id() );
  242.         return;
  243.     }
  244.     
  245.     const CProjItem& project = p->second;
  246.     // No depends - no cycles
  247.     if ( project.m_Depends.empty() )
  248.         return;
  249.     TDependsChains chains;
  250.     ITERATE(list<CProjKey>, n, project.m_Depends) {
  251.         // Prepare initial state of depends chains
  252.         // one depend project in each chain
  253.         const CProjKey& depend_id = *n;
  254.         if ( !IsInAnyCycle(depend_id, *cycles) ) {
  255.             TDependsChain one_chain;
  256.             one_chain.push_back(depend_id);
  257.             chains.push_back(one_chain);
  258.         }
  259.     }
  260.     // Try to extend this chains
  261.     TDependsChain cycle_found;
  262.     bool cycles_found = ExtendChains(proj_id, tree, &chains, &cycle_found);
  263.     if ( cycles_found ) {
  264.         // Report chains as a cycles
  265.         cycles->insert(cycle_found);
  266.     }
  267. }
  268. bool CCyclicDepends::ExtendChains(const CProjKey&  proj_id, 
  269.                                   const TProjects& tree,
  270.                                   TDependsChains*  chains,
  271.                                   TDependsChain*   cycle_found)
  272. {
  273.     for (TDependsChains::iterator p = chains->begin(); 
  274.           p != chains->end();  ) {
  275.         // Iterate through all chains
  276.         TDependsChain& one_chain = *p;
  277.         // we'll consider last element.
  278.         const CProjKey& depend_id = one_chain.back();
  279.         TProjects::const_iterator n = tree.find(depend_id);
  280.         if (n == tree.end()) {
  281.             //LOG_POST( Error << "Unknown project: " << depend_id.Id() );
  282.             return false;
  283.         }
  284.         const CProjItem& depend_project = n->second;
  285.         if ( depend_project.m_Depends.empty() ) {
  286.             // If nobody depends from this project - remove this chain
  287.             p = chains->erase(p);
  288.         } else {
  289.             // We'll create new chains 
  290.             // by adding depend_project dependencies to old_chain
  291.             TDependsChain old_chain = one_chain;
  292.             p = chains->erase(p);
  293.             ITERATE(list<CProjKey>, k, depend_project.m_Depends) {
  294.                 const CProjKey& new_depend_id = *k;
  295.                 // add each new depends to the end of the old_chain.
  296.                 TDependsChain new_chain = old_chain;
  297.                 new_chain.push_back(new_depend_id);
  298.                 p = chains->insert(p, new_chain);
  299.                 ++p;
  300.             }
  301.         }
  302.     }
  303.     // No chains - no cycles
  304.     if ( chains->empty() )
  305.         return false;
  306.     // got cycles in chains - we done
  307.     if ( IsCyclic(proj_id, *chains, cycle_found) )
  308.         return true;
  309.     // otherwise - continue search.
  310.     return ExtendChains(proj_id, tree, chains, cycle_found);
  311. }
  312. bool CCyclicDepends::IsCyclic(const CProjKey&       proj_id, 
  313.                               const TDependsChains& chains,
  314.                               TDependsChain*        cycle_found)
  315. {
  316.     // First iteration - we'll try to find project to
  317.     // consider inside depends chains. If we found - we have a cycle.
  318.     ITERATE(TDependsChains, p, chains) {
  319.         const TDependsChain& one_chain = *p;
  320.         if (find(one_chain.begin(), 
  321.                  one_chain.end(), 
  322.                  proj_id) != one_chain.end()) {
  323.             *cycle_found = one_chain;
  324.             return true;
  325.         }
  326.     }
  327.     // We look into all chais
  328.     ITERATE(TDependsChains, p, chains) {
  329.         TDependsChain one_chain = *p;
  330.         // remember original size of chain
  331.         size_t orig_size = one_chain.size();
  332.         // remove all non-unique elements
  333.         one_chain.sort();
  334.         one_chain.unique();
  335.         // if size of the chain is altered - we have a cycle.
  336.         if (one_chain.size() != orig_size) {
  337.             *cycle_found = one_chain;
  338.             return true;
  339.         }
  340.     }
  341.     
  342.     // Got nothing - no cycles
  343.     return false;
  344. }
  345. //-----------------------------------------------------------------------------
  346. CProjectTreeFolders::CProjectTreeFolders(const CProjectItemsTree& tree)
  347. :m_RootParent("/", NULL)
  348. {
  349.     ITERATE(CProjectItemsTree::TProjects, p, tree.m_Projects) {
  350.         const CProjKey&  project_id = p->first;
  351.         const CProjItem& project    = p->second;
  352.         
  353.         TPath path;
  354.         CreatePath(GetApp().GetProjectTreeInfo().m_Src, 
  355.                    project.m_SourcesBaseDir, 
  356.                    &path);
  357.         SProjectTreeFolder* folder = FindOrCreateFolder(path);
  358.         folder->m_Name = path.back();
  359.         folder->m_Projects.insert(project_id);
  360.     }
  361. }
  362. SProjectTreeFolder* 
  363. CProjectTreeFolders::CreateFolder(SProjectTreeFolder* parent,
  364.                                   const string&       folder_name)
  365. {
  366.     m_Folders.push_back(SProjectTreeFolder(folder_name, parent));
  367.     SProjectTreeFolder* inserted = &(m_Folders.back());
  368.     parent->m_Siblings.insert
  369.         (SProjectTreeFolder::TSiblings::value_type(folder_name, inserted));
  370.     
  371.     return inserted;
  372. }
  373. SProjectTreeFolder* 
  374. CProjectTreeFolders::FindFolder(const TPath& path)
  375. {
  376.     SProjectTreeFolder& folder_i = m_RootParent;
  377.     ITERATE(TPath, p, path) {
  378.         const string& node = *p;
  379.         SProjectTreeFolder::TSiblings::iterator n = 
  380.             folder_i.m_Siblings.find(node);
  381.         if (n == folder_i.m_Siblings.end())
  382.             return NULL;
  383.         folder_i = *(n->second);
  384.     }
  385.     return &folder_i;
  386. }
  387. SProjectTreeFolder* 
  388. CProjectTreeFolders::FindOrCreateFolder(const TPath& path)
  389. {
  390.     SProjectTreeFolder* folder_i = &m_RootParent;
  391.     ITERATE(TPath, p, path) {
  392.         const string& node = *p;
  393.         SProjectTreeFolder::TSiblings::iterator n = folder_i->m_Siblings.find(node);
  394.         if (n == folder_i->m_Siblings.end()) {
  395.             folder_i = CreateFolder(folder_i, node);
  396.         } else {        
  397.             folder_i = n->second;
  398.         }
  399.     }
  400.     return folder_i;
  401. }
  402. void CProjectTreeFolders::CreatePath(const string& root_src_dir, 
  403.                                      const string& project_base_dir,
  404.                                      TPath*        path)
  405. {
  406.     path->clear();
  407.     
  408.     string rel_dir = 
  409.         CDirEntry::CreateRelativePath(root_src_dir, project_base_dir);
  410.     string sep(1, CDirEntry::GetPathSeparator());
  411.     NStr::Split(rel_dir, sep, *path);
  412. }
  413. END_NCBI_SCOPE
  414. /*
  415.  * ===========================================================================
  416.  * $Log: proj_tree.cpp,v $
  417.  * Revision 1000.1  2004/06/01 18:31:29  gouriano
  418.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.3
  419.  *
  420.  * Revision 1.3  2004/05/21 21:41:41  gorelenk
  421.  * Added PCH ncbi_pch.hpp
  422.  *
  423.  * Revision 1.2  2004/05/10 19:50:05  gorelenk
  424.  * Changed CProjectItemsTree::CreateFrom .
  425.  *
  426.  * Revision 1.1  2004/03/02 16:23:57  gorelenk
  427.  * Initial revision.
  428.  *
  429.  * ===========================================================================
  430.  */