【问题标题】:Apache Ivy: Dependency Ivy FIlesApache Ivy:依赖 Ivy 文件
【发布时间】:2011-11-13 21:11:06
【问题描述】:

关于 Apache Ivy 的三个快速问题:

(1) 在我们的项目中,我们使用了 100 多个“通用”JAR(log4j、junit、commons-cli 等)。我们是否必须为所有这些文件编写 ivy.xml(“模块描述符”)文件,还是我可以在 ibiblio(或其他)repo 中找到通用文件?强迫您的用户为每个依赖项编写自己的 ivy 文件对我来说听起来非常残忍和不寻常。

(2) 特定 JAR 是否需要 ivy 文件,或者 Ivy 在 repo 中查找没有相应 ivy 文件的依赖项时是否有默认值?

(3) 是否可以将我所有的依赖项放在一个文件夹(repo)中并定义 1 个 ivy.xml 文件,在其中配置所有依赖项?

感谢您的帮助!

【问题讨论】:

    标签: apache ant ivy


    【解决方案1】:

    (1) Ivy 文件不必列出每个 jar。一些 jars 是其他 jars 的依赖项,并由 ivy 从存储库中自动提取。没有可用的默认值。对于一个新项目,我通常会生成我的第一个 ivy 文件(请参阅附加的 ant2ivy 脚本)

    (2) 仅当 jar 具有依赖项时,ivy 存储库中才需要 ivy 文件。话虽如此,拥有一个是很好的做法。我个人作弊并使用像 Nexus 这样的 Maven 存储库管理器来存储我的 jar。

    (3) 您可以使用文件系统解析器在设置文件中创建本地存储库,如下所示:

    <ivysettings>
      <settings defaultResolver='maven-repos' />
      <resolvers>
        <chain name='maven-repos'>
          <ibiblio name='central' m2compatible='true' />
          <ibiblio name='spring-external' m2compatible='true' root='http://repository.springsource.com/maven/bundles/external' />
        </chain>
        <filesystem name='local'>
          <artifact pattern='/home/mark/tmp/petclinic/build/jars/[artifact]' />
        </filesystem>
      </resolvers>
      <modules>
        <module organisation='NA' name='mylibrary1.jar' resolver='local' />
        <module organisation='NA' name='mylibrary2.jar' resolver='local' />
        ..
      </modules>
    </ivysettings>
    

    当与模块声明结合使用时,这可以在您的 ivy.xml 文件中实现以下功能:

       <dependency org='NA' name='mylibrary1.jar' rev='NA' />
       <dependency org='NA' name='mylibrary2.jar' rev='NA' />
    

    所有其他依赖项都从 Maven 存储库中检索。

    如果你遵循我附加的 ant2ivy 脚本的逻辑,你会看到我使用这个策略来处理我无法使用 Sonatype 的存储库 REST API 识别的罐子

    ant2ivy 脚本

    这是一个粗略且现成的 groovy 脚本,它执行对 Sonatypes 存储库的查找以识别指定目录中的 jars

    //
    // Dependencies
    // ============
    
    import groovy.xml.MarkupBuilder
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    @Grapes([
        @Grab(group='org.slf4j', module='slf4j-simple', version='1.6.2') 
    ])
    
    //
    // Classes
    // =======
    
    class Ant2Ivy {
    
        Logger log = LoggerFactory.getLogger(this.class.name);
        String groupId
        String artifactId
        String repoUrl
    
        Ant2Ivy(groupId, artifactId) {
            this(groupId, artifactId, "http://repository.sonatype.org")
        }
    
        Ant2Ivy(groupId, artifactId, repoUrl) {
            this.groupId = groupId
            this.artifactId = artifactId
            this.repoUrl = repoUrl
    
            log.debug "groupId: {}, artifactId: {}", groupId, artifactId
        }
    
        //
        // Given a directory, find all jar and search Nexus
        // based on the file's checksum
        //
        // Return a data structure containing the GAV coordinates of each jar
        //
        def search(File inputDir) {
            def results = [:]
            results["found"] = []
            results["missing"] = []
    
            log.info "Searching: {} ...", repoUrl
    
            def ant = new AntBuilder()
            ant.fileset(id:"jars", dir:inputDir.absolutePath, includes:"**/*.jar")
    
            ant.project.references.jars.each {
                def jar = new File(inputDir, it.name)
    
                // Checksum URL
                ant.checksum(file:jar.absolutePath, algorithm:"SHA1", property:jar.name)
    
                def searchUrl = "${repoUrl}/service/local/data_index?sha1=${ant.project.properties[jar.name]}"
                log.debug "SearchUrl: {}, File: {}", searchUrl, jar.name
    
                // Search for the first result
                def searchResults = new XmlParser().parseText(searchUrl.toURL().text)
                def artifact = searchResults.data.artifact[0]
    
                if (artifact) {
                    log.debug "Found: {}", jar.name
                    results["found"].add([file:jar.name, groupId:artifact.groupId.text(), artifactId:artifact.artifactId.text(), version:artifact.version.text()])
                }
                else {
                    log.warn "Not Found: {}", jar.name
                    results["missing"].add([file:jar.name, fileObj:jar])
                }
            }
    
            return results
        }
    
        //
        // Given an input direcory, search for the GAV coordinates 
        // and use this information to write two XML files:
        //
        // ivy.xml          Contains the ivy dependency declarations
        // ivysettings.xml  Resolver configuration
        //
        def generate(File inputDir, File outputDir) {
            outputDir.mkdir()
    
            def antFile = new File(outputDir, "build.xml")
            def ivyFile = new File(outputDir, "ivy.xml")
            def ivySettingsFile = new File(outputDir, "ivysettings.xml")
            def localRepo = new File(outputDir, "jars")
            def results = search(inputDir)
    
            //
            // Generate the ant build file
            //
            log.info "Generating ant file: {} ...", antFile.absolutePath
            def antContent = new MarkupBuilder(antFile.newPrintWriter())
    
            antContent.project(name: "Sample ivy builde", default:"resolve", "xmlns:ivy":"antlib:org.apache.ivy.ant" ) {
                target(name:"resolve") {
                    "ivy:resolve"()
                }
                target(name:"clean") {
                    "ivy:cleancache"()
                }
            }
    
            // 
            // Generate the ivy file
            //
            log.info "Generating ivy file: {} ...", ivyFile.absolutePath
            def ivyConfig = new MarkupBuilder(ivyFile.newPrintWriter())
    
            ivyConfig."ivy-module"(version:"2.0") {
                info(organisation:this.groupId, module:this.artifactId) 
                configurations(defaultconfmapping:"default")
                dependencies() {
                    results.found.each {
                        dependency(org:it.groupId, name:it.artifactId, rev:it.version, conf:"default->master")
                    }
                    results.missing.each {
                        dependency(org:"NA", name:it.file, rev:"NA")
                    }
                }
            }
    
            // 
            // Generate the ivy settings file
            //
            log.info "Generating ivy settings file: {} ...", ivySettingsFile.absolutePath
            def ivySettings = new MarkupBuilder(ivySettingsFile.newPrintWriter())
            def ant = new AntBuilder()
    
            ivySettings.ivysettings() {
                settings(defaultResolver:"maven-repos") 
                resolvers() {
                    chain(name:"maven-repos") {
                        // TODO: Make this list of Maven repos configurable
                        ibiblio(name:"central", m2compatible:"true")
                        ibiblio(name:"spring-external", m2compatible:"true", root:"http://repository.springsource.com/maven/bundles/external")
                    }
                    if (results.missing.size() > 0) {
                        filesystem(name:"local") {
                            artifact(pattern:"${localRepo.absolutePath}/[artifact]")
                        }
                    }
                }
                if (results.missing.size() > 0) {
                    modules() {
                        results.missing.each {
                            module(organisation:"NA", name:it.file, resolver:"local")
                            ant.copy(file:it.fileObj.absolutePath, tofile:"${localRepo.absolutePath}/${it.file}")
                        }
                    }
                }
            }
        }
    }
    
    // 
    // Main program
    // ============
    def cli = new CliBuilder(usage: 'ant2ivy')
    cli.with {
        h longOpt: 'help', 'Show usage information'
        g longOpt: 'groupid',    args: 1, 'Module groupid', required: true
        a longOpt: 'artifactid', args: 1, 'Module artifactid', required: true
        s longOpt: 'sourcedir',  args: 1, 'Source directory containing jars', required: true
        t longOpt: 'targetdir',  args: 1, 'Target directory where write ivy build files', required: true
    }
    
    def options = cli.parse(args)
    if (!options) {
        return
    }
    
    if (options.help) {
        cli.usage()
    }
    
    // 
    // Generate ivy configuration
    //
    def ant2ivy = new Ant2Ivy(options.groupid, options.artifactid)
    ant2ivy.generate(new File(options.sourcedir), new File(options.targetdir))
    

    脚本运行如下:

    groovy ant2ivy.groovy -g com.hello -a test -s targetdir/WEB-INF/lib -t build
    

    当针对 petclinic 样本运行时,它会生成以下文件

    build/build.xml
    build/ivy.xml
    build/ivysettings.xml
    build/jars/..
    ..
    

    jars 目录包含那些无法在 Maven 存储库中找到的库。

    【讨论】:

      猜你喜欢
      • 2019-06-30
      • 2019-03-17
      • 1970-01-01
      • 2016-11-20
      • 1970-01-01
      • 2013-09-08
      • 2011-05-14
      • 2014-06-06
      • 2013-06-30
      相关资源
      最近更新 更多