如何使用IBM RAD ant管理多项目依赖项(定向非循环路径)?

时间:2013-05-17 14:57:48

标签: ant ibm-rad

我正在开发一个ant脚本来构建使用IBM RAD 7.5开发的java prject。

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

问题是psf文件中列出的项目没有按项目依赖项排序,编译时失败,因为依赖项不正确。

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

这里是问题的详细说明: 项目依赖性如下: 1)项目A取决于B和D. 2)项目B取决于C 3)项目E取决于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处失败,因为A需要首先构建B和D.

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

C
B
D
A
F
E

但这很难维护,因为psf文件中有200多个项目,而且它们正在不断变化。

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

1 个答案:

答案 0 :(得分:0)

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

  1. 将psf文件读入列表,psf文件是xml文件,并且 项目名称在标签中。
  2. 对于每个项目     列表,转到项目源代码并读取.project文件和     .classpath文件,这两个文件包含依赖项目。     对于.project文件(xml),从标签中获取项目名称,     对于.classpath文件。获取属性kind ='src'
  3. 的行
  4. 现在你有了[source] - > [dependened_project_list],实现了一个 有向无环图。(见附件)
  5. 将[source] - > [dependened_project]加载到AdjecentListDigraph中, 调用topoSort()返回依赖项。
  6. 生成一个新的有序psf文件。

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

    '''使用有向非循环路径计算依赖关系''' class Vertex:     def init (self,name):         self._name = name         self.visited = True

    class InValidDigraphError(RuntimeError):     def init (self,arg):         self.args = arg

    类AdjecentListDigraph:     '''代表相邻列表'''

    的有向图
    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  
        '''
    

    print'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和compute中加载每个项目的依赖项 有向无环路径。

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

    算法是:     1)阅读     2)调用readProjectDependency(project_name) “”” import os,xml.dom.minidom 来自utils.setting导入配置

    类ProjectsLoader:

    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