2013-05-17 27 views
1

我正在研究一个ant脚本来构建用IBM RAD 7.5开发的java程序。如何用IBM RAD ant管理多项目依赖项(定向非循环路径)?

脚本正在调用IBM RAD ant extenstion API。我正在使用Task将项目集文件(*。psf)加载到内存中,并调用Task来编译projectSetImport中列出的项目。

问题是psf文件中列出的项目没有按项目依赖关系进行排序,编译时由于依赖关系不正确而失败。

是否有任何API或方法自动管理依赖项? Iam处理的psf文件相当大,每个文件中有200多个项目,并且它正在不断变化(例如,某些项目被删除,每周添加一些新项目)

这里是对问题的详细描述: 该项目的依赖是这样的: 1)项目A依赖于B和D 2)项目B依赖基于C 3)项目Ë由F

A -> B -> C 
A -> D 
E-> F 

的sample.psf文件只是列出所有的项目:

A 
B 
C 
D 
E 
F 

加载sample.psf,其中有一个项目列表[A,B,C,D,E,F] 构建项目列表 构建失败,因为A需要先构建B和D.

我目前的解决方案是手动重建sample.psf, sample.psf文件:

C 
B 
D 
A 
F 
E 

但是这是很难维持的,因为有一个PSF文件200多个项目,他们constanly改变。

攻击此问题的一种方法是编写解析器来读取每个项目的.project文件,依赖项目列在“projects”标记中。然后实现定向非循环路径算法来重新排序依赖关系。这种做法可能会过度杀人。这在构建IBM Java项目的团队中必定是一个常见问题,是否有解决方案?

回答

0

最后,我写了一些python代码来计算依赖关系。我下面列出的逻辑:

  1. 读取PSF文件到列表中,PSF文件是一个XML文件,并 项目名称为标签。
  2. 对于 列表中的每个项目,转到项目源代码并读取.project文件和 .classpath文件,这两个文件包含依赖项目。 .project文件(xml),从标签获取项目名称, .classpath文件。取得与属性种类= 'SRC'
  3. 现在你有[源]行 - > [dependened_project_list],实现 向非循环图(参见所附的代码)
  4. 负载[源] - > [dependened_project]在AdjecentListDigraph中,并调用topoSort()以返回依赖关系。
  5. 生成一个新的有序psf文件。

    /////////////////////// dap_graph.py///////////////////////////// 
    # -*- coding: utf-8 -*- 
    

    '' '' 类顶点 '向非循环路径计算依赖使用': DEF 初始化(个体,名称): self._name =名 self.visited =真

    类InValidDigraphError(RuntimeError): DEF 初始化(个体,ARG): self.args = ARG

    类Adje centListDigraph: '' '代表由相邻列表中的向图' ''

    def __init__(self): 
        '''use a table to store edges, 
        the key is the vertex name, value is vertex list 
        ''' 
        self._edge_table = {} 
        self._vertex_name_set = set() 
    
    def __addVertex(self, vertex_name): 
        self._vertex_name_set.add(vertex_name) 
    
    def addEdge(self, start_vertex, end_vertex): 
        if not self._edge_table.has_key(start_vertex._name): 
         self._edge_table[start_vertex._name] = [] 
        self._edge_table[start_vertex._name].append(end_vertex) 
        # populate vertex set 
        self.__addVertex(start_vertex._name) 
        self.__addVertex(end_vertex._name) 
    
    def getNextLeaf(self, vertex_name_set, edge_table): 
        '''pick up a vertex which has no end vertex. return vertex.name. 
        algorithm: 
        for v in vertex_set: 
         get vertexes not in edge_table.keys() 
         then get vertex whose end_vertex is empty 
        ''' 
    

    打印 'TODO:验证这是一个连接树'

    leaf_set = vertex_name_set - set(edge_table.keys()) 
        if len(leaf_set) == 0: 
         if len(edge_table) > 0: 
          raise InValidDigraphError("Error: Cyclic directed graph") 
        else: 
         vertex_name = leaf_set.pop() 
         vertex_name_set.remove(vertex_name) 
         # remove any occurrence of vertext_name in edge_table 
         for key, vertex_list in edge_table.items(): 
          if vertex_name in vertex_list: 
           vertex_list.remove(vertex_name) 
          # remove the vertex who has no end vertex from edge_table 
          if len(vertex_list) == 0: 
           del edge_table[key] 
         return vertex_name 
    
    def topoSort(self): 
        '''topological sort, return list of vertex. Throw error if it is 
        a cyclic graph''' 
        sorted_vertex = [] 
        edge_table = self.dumpEdges() 
        vertex_name_set = set(self.dumpVertexes()) 
    
        while len(vertex_name_set) > 0: 
         next_vertex = self.getNextLeaf(vertex_name_set, edge_table) 
         sorted_vertex.append(next_vertex) 
        return sorted_vertex 
    
    def dumpEdges(self): 
        '''return the _edge_list for debugging''' 
        edge_table = {} 
        for key in self._edge_table: 
         if not edge_table.has_key(key): 
          edge_table[key] = [] 
         edge_table[key] = [v._name for v in self._edge_table[key]] 
        return edge_table 
    
    def dumpVertexes(self): 
        return self._vertex_name_set 
    
    //////////////////////projects_loader.py/////////////////////// 
    

    - - 编码:UTF-8 - -

    ''' 该模块将加载来自psf的每个项目的相关性,并计算有向非循环路径。

    依赖被加载到地图结构如下: dependency_map { “project_A”:设置(A1,A2,A3), “A1:组(B1,B2,B3)}

    的算法是: 1)读 2)调用readProjectDependency(PROJECT_NAME) ''” 进口OS,从utils.setting导入配置

    类ProjectsLoader xml.dom.minidom :

    def __init__(self, application_name): 
        self.dependency_map = {} 
        self.source_dir = configuration.get('Build', 'base.dir') 
        self.application_name = application_name 
        self.src_filter_list = configuration.getCollection('psf',\ 
                     'src.filter.list') 
    
    def loadDependenciesFromProjects(self, project_list): 
        for project_name in project_list: 
         self.readProjectDependency(project_name) 
    
    def readProjectDependency(self, project_name): 
        project_path = self.source_dir + '\\' + self.application_name + '\\'\ 
         + project_name 
        project_file_path = os.path.join(project_path,'.project') 
        projects_from_project_file = self.readProjectFile(project_file_path) 
    
        classpath_file_path = os.path.join(project_path,'.classpath') 
        projects_from_classpath_file = self.\ 
         readClasspathFile(classpath_file_path) 
    
        projects = (projects_from_project_file | projects_from_classpath_file) 
        if self.dependency_map.has_key(project_name): 
         self.dependency_map[project_name] |= projects 
        else: 
         self.dependency_map[project_name] = projects 
    
    def loadDependencyByProjectName(self, project_name): 
        project_path = self.source_dir + '\\' + self.application_name + '\\'\ 
         + project_name 
        project_file_path = os.path.join(project_path,'.project') 
        projects_from_project_file = self.readProjectFile(project_file_path) 
    
        classpath_file_path = os.path.join(project_path,'.classpath') 
        projects_from_classpath_file = self.\ 
         readClasspathFile(classpath_file_path) 
    
        projects = list(set(projects_from_project_file\ 
             + projects_from_classpath_file)) 
        self.dependency_map[project_name] = projects 
        for project in projects: 
         self.loadDependencyByProjectName(project) 
    
    def readProjectFile(self, project_file_path): 
        DOMTree = xml.dom.minidom.parse(project_file_path) 
        projects = DOMTree.documentElement.getElementsByTagName('project') 
        return set([project.childNodes[0].data for project in projects]) 
    
    def readClasspathFile(self, classpath_file_path): 
        dependency_projects = set([]) 
        if os.path.isfile(classpath_file_path): 
         DOMTree = xml.dom.minidom.parse(classpath_file_path) 
         projects = DOMTree.documentElement.\ 
          getElementsByTagName('classpathentry') 
         for project in projects: 
          if project.hasAttribute('kind') and project.getAttribute\ 
           ('kind') == 'src' and project.hasAttribute('path') and \ 
           project.getAttribute('path') not in self.src_filter_list: 
            project_name = project.getAttribute('path').lstrip('/') 
            dependency_projects.add(project_name) 
    
        return dependency_projects 
    
    def getDependencyMap(self): 
        return self.dependency_map 
    
相关问题