第六十四章. 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 repositories。
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.

Publication对象描述了要创建的发布内容的结构和配置。Publications是通过任务发布到仓库的,发布对象的配置明确地决定了要发布的内容。一个项目的所有publications都会在PublishingExtension.getPublications()容器中定义,每一个publication在项目中都具有唯一名称。
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集合里。这个publications决定了实际要发布的工件,以及在关联的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

将 Gradle 项目发布到 Ivy 库的最简单方法是指定要发布的 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 将处理 organisation,module 和 revision 的任何有效 Unicode 字符 (以及工件名称,扩展名和 classifier)。唯一明确禁止的是“ \”,“/”和以及所有的 ISO 控制字符。这些提供的值w会在发布过程的早期进行验证。
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”插件提供了一个钩子以允许这样的修改。
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 依赖描述符中,而这个钩子能让你对生成的描述符的任何方面进行修改。例如,你可以将依赖的版本范围替换为生成构建的实际版本。
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”钩子来修改描述符中的这些值。
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 构建中发布多个模块会很有用。一个例子是为你的库发布一个单独的 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 '1.1'

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

如果一个项目定义了多个发布,那么 Gradle 会将每个发布都发布到定义的仓库中。每个发布都必须x给定如上所述的唯一标识。
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«发布名称»PublicationTo«仓库名称»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