第六十四章. 发布到Ivy(新)

Chapter 64. Ivy Publishing (new)

本章内容描述了一个新的 孵化中的 功能,是由“ivy-publish”插件提供的 Ivy 发布支持。最终这个新的发布支持的发布功能将会取代Upload任务的发布功能。
This chapter describes the new incubating Ivy publishing support provided by the “ivy-publish” plugin. Eventually this new publishing support will replace publishing via the Upload task.

如果你正在查找关于使用 Upload 任务的原始的Ivy发布支持的文档,请查阅 第五十一章, 发布构件
If you are looking for documentation on the original Ivy publishing support using the Upload task please see Chapter 51, Publishing artifacts.

本章内容主要描述了如何发布使用 Apache Ivy 格式的构建构件,通常是发布到一个用于其他构建或项目的消费的仓库。发布的内容是一个或多个在构建中创建的构件,以及一个描述了这些构件以及它们的依赖的Ivy 模块描述文件(通常是 ivy.xml)。
This chapter describes how to publish build artifacts in the Apache Ivy format, usually to a repository for consumption by other builds or projects. What is published is one or more artifacts created by the build, and an Ivy module descriptor (normally ivy.xml) that describes the artifacts and the dependencies of the artifacts, if any.

使用已发布的 Ivy 模块就可以在Gradle(参见 第五十章, 依赖管理)或其他了解Ivy 格式的工具中使用。
A published Ivy module can be consumed by Gradle (see Chapter 50, Dependency Management) and other tools that understand the Ivy format.

64.1. “ivy-publish”插件

64.1. The “ivy-publish” Plugin

这种使用 Ivy 格式发布的能力是由 “ivy-publish”插件提供的。
The ability to publish in the Ivy format is provided by the “ivy-publish” plugin.

publishing” 插件在project上创建了一个名为 “publishing”的 PublishingExtension类型的扩展。这个扩展提供了两个容器,一个叫publications,一个叫repositories。“ivy-publish”适用于IvyPublication publications 和 IvyArtifactRepository 仓库。
The “publishing” plugin creates an extension on the project named “publishing” of type PublishingExtension. This extension provides a container of named publications and a container of named repositories. The “ivy-publish” plugin works with IvyPublication publications and IvyArtifactRepository repositories.

示例 64.1. 应用“ivy-publish”插件 - Example 64.1. Applying the “ivy-publish” plugin

build.gradle

apply plugin: 'ivy-publish'

应用“ivy-publish”插件将会执行以下操作:
Applying the “ivy-publish” plugin does the following:

64.2. 发布

64.2. Publications

如果你不熟悉项目构件和配置,你应该读一下第五十一章,发布,里面对这些概念进行了介绍。这一章还介绍了使用另一种不同的机制的“发布构件”。这里描述的发布功能最终将取代那一功能。
If you are not familiar with project artifacts and configurations, you should read the Chapter 51, Publishing artifacts that introduces these concepts. This chapter also describes “publishing artifacts” using a different mechanism than what is described in this chapter. The publishing functionality described here will eventually supersede that functionality.

发布对象描述了要被创建的发布内容的结构和配置。publications是通过任务发布到仓库中的,并且发布对象的配置明确决定了会发布哪些内容。一个项目的所有publications会在 PublishingExtension.getPublications() 容器中定义。每一个发布
Publication objects describe the structure/configuration of a publication to be created. Publications are published to repositories via tasks, and the configuration of the publication object determines exactly what is published. All of the publications of a project are defined in the PublishingExtension.getPublications() container. Each publication has a unique name within the project.

为了能让“ivy-publish”插件起作用的,一个 IvyPublication 必须被添加到publications集里。这个publication决定了实际上哪些构件会被发布,以及在关联的Ivy模块描述文件中所包含的详细信息。通过添加组件,自定义构件,以及直接修改生成的模块描述文件,可以配置一个publication。
For the “ivy-publish” plugin to have any effect, a IvyPublication must be added to the set of publications. This publication determines which artifacts are actually published as well as the details included in the associated Ivy module descriptor file. A publication can be configured by adding components, customizing artifacts, and by modifying the generated module descriptor file directly.

64.2.1. 发布软件组件

64.2.1. Publishing a Software Component

向Ivy仓库发布一个Gradle项目的最简单的方式是指定一个要发布的 SoftwareComponent。目前可用于publication的组件都有:
The simplest way to publish a Gradle project to an Ivy repository is to specify a SoftwareComponent to publish. The components presently available for publication are:

表64.1. 软件组件 - Table 64.1. Software Components

名称
Name
提供者
Provided By
构件
Artifacts
依赖
Dependencies
java Java 插件
Java Plugin
生成的 jar 文件
Generated jar file
“runtime”配置的依赖
Dependencies from 'runtime' configuration
web War 插件
War Plugin
生成的 war 文件
Generated war file
没有依赖
No dependencies

在以下示例中,工件和运行时依赖都来自于由 Java Plugin 添加的 “java” 组件。
In the following example, artifacts and runtime dependencies are taken from the `java` component, which is added by the Java Plugin.

示例 64.2. 将一个 java 模块发布到 Ivy - Example 64.2. Publishing a java module to Ivy

build.gradle

publications {
        ivyJava(IvyPublication) {
            from components.java
        }
    }

64.2.2. 发布自定义构件

64.2.2. Publishing custom artifacts

我们还可以显式地配置要被包含在publication的构件。这些构件通常是以原始数据文件,或者是 AbstractArchiveTask的实例(如Jar, Zip)的方式来提供。
It is also possible to explicitly configure artifacts to be included in the publication. Artifacts are commonly supplied as raw files, or as instances of AbstractArchiveTask (e.g. Jar, Zip).

对于每个自定义的项目,在发布时可以指定nameextensiontypeclassifierconf的值。注意,每个构件必须有一个唯一的 name/classifier/extension 组合。
For each custom artifact, it is possible to specify the name, extension, type, classifier and conf values to use for publication. Note that each artifacts must have a unique name/classifier/extension combination.

如下所示配置自定义构件︰
Configure custom artifacts as follows:

示例64.3. 发布额外的构件到Ivy - Example 64.3. Publishing additional artifact to Ivy

build.gradle

task sourceJar(type: Jar) {
        from sourceSets.main.java
        classifier "source"
    }
    publishing {
        publications {
            ivy(IvyPublication) {
                from components.java
                artifact(sourceJar) {
                    type "source"
                    conf "runtime"
                }
            }
        }
    }

关于如何自定义构件的更详细的文档,请参阅IvyPublication
See IvyPublication for more detailed documentation on how artifacts can be customized.

64.2.3. 已发布的项目的标识值

64.2.3. Identity values for the published project

生成的Ivy模块描述符文件包含了用于标识该模块的<info>标记。默认标识的值取自以下这些项目属性︰
The generated Ivy module descriptor file contains an <info> tag that identifies the module. The default identity values are derived from the following project properties:

重写默认标识值是很简单︰只需要配置IvyPublication时指定organisationmodulerevision属性。
Overriding the default identity values is easy: simply specify the organisation, module or revision attributes when configuring the IvyPublication.

示例 64.4. 自定义发布标识 - Example 64.4. customizing the publication identity

build.gradle

publishing {
        publications {
            ivy(IvyPublication) {
                organisation 'org.gradle.sample'
                module 'project1-sample'
                revision '1.1'
                descriptor.status = 'milestone'

                from components.java
            }
        }
    }

某些存储库可能无法处理所有支持的字符。例如,当发布到 Windows 上的文件系统支持的存储库,“:”字符就不能用作标识符。

Gradle 将处理 organization, module 和 revision(以及 artifact 名称, extension 和 classifier)的任何有效的Unicode 字符。唯一明确禁止使用的是“\”,“/”以及所有的ISO控制字符。这些提供的值会在发布之前进行验证。
Gradle will handle any valid Unicode character for organisation, module and revision (as well as artifact name, extension and classifier). The only values that are explicitly prohibited are '\', '/' and any ISO control character. The supplied values are validated early in publication.

64.2.4. 修改生成的模块描述

64.2.4. Modifying the generated module descriptor

有时候,从项目信息生成的模块描述文件可能需要在发布之前进行一些调整。“ivy-publish”插件提供了一个hook以允许这一类的修改。
At times, the module descriptor file generated from the project information will need to be tweaked before publishing. The “ivy-publish” plugin provides a hook to allow such modification.

示例 64.5. 自定义模块描述符文件 - Example 64.5. Customizing the module descriptor file

build.gradle

publications {
        ivyCustom(IvyPublication) {
            descriptor.withXml {
                asNode().info[0].appendNode('description', 'A demonstration of ivy descriptor customization')
            }
        }
    }

在这个例子中,我们添加了一个“description”元素到生成的Ivy依赖描述符中,而这个hook,允许你去对这个生成的描述符的任何方面进行修改。例如,你可以使用一个用于产生构建的实际版本去替换一个依赖的版本范围。
In this example we are adding a 'description' element to the generated Ivy dependency descriptor, but this this hook, allows you to modify any aspect of the generated descriptor. For example, you could replace the version range for a dependency with the actual version used to produce the build.

相关的 API 参考文档,请参阅IvyModuleDescriptor.withXml()
See IvyModuleDescriptor.withXml() for the relevant API reference documentation.

如果有需要的话,你也可以修改所创建的描述符的几乎任何方面。这意味着,用这样的方式,可能会把这个描述符修改为不再是有效的Ivy模块描述符,所以必须谨慎使用这个功能。
It is possible to modify virtually any aspect of the created descriptor should you need to. This means that it is also possible to modify the descriptor in such a way that it is no longer a valid Ivy module descriptor, so care must be taken when using this feature.

已发布模块的标识符(organisation,module,revision)则是一个例外;不能使用“withXML”hook 来修改描述符中的这些值。
The identifier (organisation, module, revision) of the published module is an exception; these values cannot be modified in the descriptor using the `withXML` hook.

64.2.5. 发布多个模块

64.2.5. Publishing multiple modules

有时候从你的 Gradle 构建中发布多个模块会很有用,而不是创建一个单独的 Gradle 子项目。一个例子是为您的library 分别发布一个单独的 API 和它的实现的 jar。使用 Gradle 的话很简单︰
Sometimes it's useful to publish multiple modules from your Gradle build, without creating a separate Gradle subproject. An example is publishing a separate API and implementation jar for your library. With Gradle this is simple:

示例 64.6. 从一个单一的项目发布多个模块 - Example 64.6. Publishing multiple modules from a single project

build.gradle

task apiJar(type: Jar) {
        baseName "publishing-api"
        from sourceSets.main.output
        exclude '**/impl/**'
    }
    publishing {
        publications {
            impl(IvyPublication) {
                organisation 'org.gradle.sample.impl'
                module 'project2-impl'
                revision '2.3'

                from components.java
            }
            api(IvyPublication) {
                organisation 'org.gradle.sample'
                module 'project2-api'
                revision '2'
            }
        }
    }

如果一个项目定义了多个要发布的内容,Gradle 将把每一个都发布到定义的仓库。如上文所述,每个发布的内容都必须给定一个唯一的标识。
If a project defines multiple publications then Gradle will publish each of these to the defined repositories. Each publication must be given a unique identity as described above.

64.3. 仓库

64.3. Repositories

发布的内容都会被发布到仓库中用于发布的仓库是通过PublishingExtension.getRepositories()容器来定义的。
Publications are published to repositories. The repositories to publish to are defined by the PublishingExtension.getRepositories() container.

示例 64.7. 声明用于发布的仓库 - Example 64.7. Declaring repositories to publish to

build.gradle

repositories {
        ivy {
            url "$buildDir/repo" // change to point to your repo, e.g. http://my.org/repo
        }
    }

定义用于发布的仓库的DSL和定义用于查找依赖的仓库的DSL一样(RepositoryHandler)。然而,在Ivy发布的场景中,只有通过 ivy()方法创建的仓库才可以作为发布的指定地方。例如,你不能把一个 IvyPublication发布到一个Maven仓库中。
The DSL used to declare repositories for publishing is the same DSL that is used to declare repositories for dependencies (RepositoryHandler). However, in the context of Ivy publication only the repositories created by the ivy() methods can be used as publication destinations. You cannot publish an IvyPublication to a Maven repository for example.

64.4. 执行发布

64.4. Performing a publish

对每一个在 publishing.publicationspublishing.repositories 容器中分别组合的IvyPublicationIvyArtifactRepository,“ivy-publish” 插件自动为它们创建了一个 PublishToIvyRepository 任务。
The “ivy-publish” plugin automatically creates a PublishToIvyRepository task for each IvyPublication and IvyArtifactRepository combination in the publishing.publications and publishing.repositories containers respectively.

这个创建的任务使用“publish«PUBLICATION 名称»PublicationTo«REPOSITORY 名称»Repository”的方式来命名。因此,在下面的例子中,创建了一个 PublishToIvyRepository 任务,名字叫做“publishIvyJavaPublicationToIvyRepository”。
The created task is named using the pattern "publish«NAME OF PUBLICATION»PublicationTo«NAME OF REPOSITORY»Repository". So in this example a single PublishToIvyRepository task is be added, named 'publishIvyJavaPublicationToIvyRepository'.

示例 64.8. 选择要发布的特定出版物 - Example 64.8. Choosing a particular publication to publish

build.gradle

apply plugin: 'java'
apply plugin: 'ivy-publish'

group = 'org.gradle.sample'
version = '1.0'

publishing {
    publications {
        ivyJava(IvyPublication) {
            from components.java
        }
    }
    repositories {
        ivy {
            url "$buildDir/repo" // change to point to your repo, e.g. http://my.org/repo
        }
    }
}

gradle publishIvyJavaPublicationToIvyRepository的输出结果
Output of gradle publishIvyJavaPublicationToIvyRepository

> gradle publishIvyJavaPublicationToIvyRepository
:generateDescriptorFileForIvyJavaPublication
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
:publishIvyJavaPublicationToIvyRepository

BUILD SUCCESSFUL

Total time: 1 secs

64.4.1.  “publish” 生命周期任务

64.4.1. The “publish” lifecycle task

这个“publish插件(即“ivy-publish” 插件隐式应用的)添加了一个 叫做“publish”的生命周期任务,可以用于发布所有出版物到所有适用的仓库中。
The “publish” plugin (that the “ivy-publish” plugin implicitly applies) adds a lifecycle task that can be used to publish all publications to all applicable repositories named “publish”.

更具体而言,执行这个任务将会执行在项目中的所有 PublishToIvyRepository 任务。这通常是执行发布的最方便的方法。
In more concrete terms, executing this task will execute all PublishToIvyRepository tasks in the project. This is usually the most convenient way to perform a publish.

示例 64.9. 通过“publish”生命周期任务发布所有出版物 - Example 64.9. Publishing all publications via the “publish” lifecycle task

gradle publish的输出结果
Output of gradle publish

> gradle publish
:generateDescriptorFileForIvyJavaPublication
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
:publishIvyJavaPublicationToIvyRepository
:publish

BUILD SUCCESSFUL

Total time: 1 secs

64.5. 不发布的情况下生成Ivy模块的描述符文件

64.5. Generating the Ivy module descriptor file without publishing

有时候,我们会需要在不发布你的模块到Ivy仓库的情况下,生成Ivy模块描述符文件(通常是ivy.xml)。因为描述符文件的生成是由一个单独的任务执行的,所以这很容易做到。
At times it is useful to generate the Ivy module descriptor file (normally ivy.xml) without publishing your module to an Ivy repository. Since descriptor file generation is performed by a separate task, this is very easy to do.

ivy-publish”插件自动为每一个注册的 IvyPublication连接了一个GenerateIvyDescriptor 任务。这个任务被指定为一个基于发布的名称的名字:“generateDescriptorFileFor«发布名称»Publication”。因此,在上面的例子中,发布的名称叫“ivyJava”,那么这个任务的名称就会是“generateDescriptorFileForIvyJavaPublication”。
The “ivy-publish” plugin automatically wires in one GenerateIvyDescriptor task for each registered IvyPublication. This task is given a name based on the name of the publication: "generateDescriptorFileFor«NAME OF PUBLICATION»Publication". So in the example above where the publication is named "ivyJava", the task will be named "generateDescriptorFileForIvyJavaPublication".

你可以通过在生成任务上设置destination属性,指定生成的Ivy文件位置。默认情况下这个文件将会生成到build/publications/«发布名称»/ivy.xml
You can specify where the generated Ivy file will be located by setting the destination property on the generate task. By default this file is generated to build/publications/«NAME OF PUBLICATION»/ivy.xml.

示例 64.10. 生成Ivy模块描述符文件 - Example 64.10. Generating the Ivy module descriptor file

build.gradle

model {
    tasks.generateDescriptorFileForIvyCustomPublication {
        destination = file("$buildDir/generated-ivy.xml")
    }
}

gradle generateDescriptorFileForIvyCustomPublication的输出结果
Output of gradle generateDescriptorFileForIvyCustomPublication

> gradle generateDescriptorFileForIvyCustomPublication
:generateDescriptorFileForIvyCustomPublication

BUILD SUCCESSFUL

Total time: 1 secs

ivy-publish”插件利用了后期插件配置的一些实验性的支持,并且在配置发布扩展之前,不会构造GenerateIvyDescriptor任务。确保当你尝试访问GenerateIvyDescriptor任务时,发布插件已经配置好的最简单的方式是,将访问的代码放在publishing代码块中,如上面的例子中所示。
The “ivy-publish” plugin leverages some experimental support for late plugin configuration, and the GenerateIvyDescriptor task will not be constructed until the publishing extension is configured. The simplest way to ensure that the publishing plugin is configured when you attempt to access the GenerateIvyDescriptor task is to place the access inside a publishing block, as the example above demonstrates.

这同样适用于任何发布相关的任务的访问,像PublishToIvyRepository。这些任务应该从publishing代码块内引用。
The same applies to any attempt to access publication-specific tasks like PublishToIvyRepository. These tasks should be referenced from within a publishing block.

64.6. 完整的示例

64.6. Complete example

下面的例子演示了如何使用在多项目构建中进行发布。每个项目发布一个 java 组件,以及配置额外的源码构件。自定描述符,以包含每一个项目的项目描述。
The following example demonstrates publishing with a multi-project build. Each project publishes a java component and a configured additional source artifact. The descriptor file is customized to include the project description for each project.

示例 64.11. 发布一个 java 模块 - Example 64.11. Publishing a java module

build.gradle

subprojects {
    apply plugin: 'java'
    apply plugin: 'ivy-publish'

    version = '1.0'
    group = 'org.gradle.sample'

    repositories {
        mavenCentral()
    }
    task sourceJar(type: Jar) {
        from sourceSets.main.java
        classifier "source"
    }
}

project(":project1") {
    description = "The first project"

    dependencies {
       compile 'junit:junit:4.11', project(':project2')
    }
}

project(":project2") {
    description = "The second project"

    dependencies {
       compile 'commons-collections:commons-collections:3.1'
    }
}

subprojects {
    publishing {
        repositories {
            ivy {
                url "${rootProject.buildDir}/repo" // change to point to your repo, e.g. http://my.org/repo
            }
        }
        publications {
            ivy(IvyPublication) {
                from components.java
                artifact(sourceJar) {
                    type "source"
                    conf "runtime"
                }
                descriptor.withXml {
                    asNode().info[0].appendNode('description', description)
                }
            }
        }
    }
}

其结果是将为每个项目发表以下构件︰
The result is that the following artifacts will be published for each project:

  • Ivy 模块描述符文件︰ivy-1.0.xml
    The Ivy module descriptor file: ivy-1.0.xml.
  • Java 组件的主要“jar”构件︰project1-1.0.jar
    The primary “jar” artifact for the java component: project1-1.0.jar.
  • 已显式配置的源码“jar”构件︰project1-1.0-source.jar
    The source “jar” artifact that has been explicitly configured:project1-1.0-source.jar.

project1发布时,产生的模块描述符(即ivy.xml文件)将是……
When project1 is published, the module descriptor (i.e. the ivy.xml file) that is produced will look like…

注意:在这个例子的Ivy模块描述符中的«发布时间戳»将是描述符文件生成时的时间戳。
Note that the «PUBLICATION-TIME-STAMP» in this example Ivy module descriptor will be the timestamp of when the descriptor was generated.

示例 64.12. 生成 ivy.xml的示例 - Example 64.12. Example generated ivy.xml

output-ivy.xml


        
<ivy-module version="2.0">
  <info organisation="org.gradle.sample" module="project1" revision="1.0" status="integration" publication="«PUBLICATION-TIME-STAMP»">
    <description>The first project</description>
  </info>
  <configurations>
    <conf name="default" visibility="public" extends="runtime"/>
    <conf name="runtime" visibility="public"/>
  </configurations>
  <publications>
    <artifact name="project1" type="jar" ext="jar" conf="runtime"/>
    <artifact name="project1" type="source" ext="jar" conf="runtime" m:classifier="source" xmlns:m="http://ant.apache.org/ivy/maven"/>
  </publications>
  <dependencies>
    <dependency org="junit" name="junit" rev="4.11" conf="runtime-&gt;default"/>
    <dependency org="org.gradle.sample" name="project2" rev="1.0" conf="runtime-&gt;default"/>
  </dependencies>
</ivy-module>

64.7. 未来特性

64.7. Future features

ivy-publish”插件的功能,如上文所述是不完整的,因为这一功能仍然在孵化中。在即将到来的 Gradle 版本中,功能将会扩展到包括(但不仅限于)︰
The “ivy-publish” plugin functionality as described above is incomplete, as the feature is still incubating. Over the coming Gradle releases, the functionality will be expanded to include (but not limited to):

  • 方便定制的模块属性(moduleorganisation等)。
    Convenient customization of module attributes (module, organisation etc.)
  • module descriptor中方便依赖报告的自定义。
    Convenient customization of dependencies reported in module descriptor.
  • 每个项目的多个谨慎发布
    Multiple discreet publications per project