构建Gradle存储库以进行脱机开发

时间:2015-02-10 16:16:50

标签: gradle offline

我正在为一块软件实现一个Gradle构建系统,该软件包含在没有Internet连接或安装Maven / Ivy服务器(如Nexus)的区域内开发的部件。为了支持这些环境中的开发,我正在整理一个允许生成“离线工作区”的Gradle插件。

我最初通过触发项目中每个配置的解析(触发所有依赖项的下载),然后遍历每个配置的整个依赖关系树并将依赖关系的本地缓存副本复制到Offline Workspace来实现此功能。 (为每个复制操作生成了一个复制任务。)然后使用flatDir存储库引用这些JAR。

此实现使用afterEvaluate块执行其作业。虽然这在Gradle 2.0中运行良好,但它会在Gradle 2.2.1中触发弃用警告,因为触发分辨率在某种程度上被视为在已经解析后修改配置(Attempting to change configuration ':core:runtime' after it has been included in dependency resolution. This behaviour has been deprecated and is scheduled to be removed in Gradle 3.0)。总之,这种方法感觉相当hacky,因为它还要求我修改build.gradle文件以显式列出所有传递依赖项,因为没有可用于正确指定依赖项的POM文件。

更优雅的方法似乎是构建所有依赖项的本地Maven存储库(包括POM文件,源JAR,javadoc JAR等),然后只使用mavenLocal()存储库类型。不幸的是,我不确定如何正确地执行此操作,我不需要触发工件解析来执行此操作。

是否有更好的方法可以将完整的工件下载转换为易于打包的方式,而不仅仅是压缩整个$ USER_HOME / .gradle目录?

3 个答案:

答案 0 :(得分:12)

要进行脱机构建,您需要以某种方式提供所有必需的依赖项。这里的一个选项就是将这些jar提交到版本控制中。困难的部分是收集所有这些依赖项。为此,可以使用build.gradle文件,该文件可以在两种模式下运行(在线和离线):

buildscript {
    repositories {
        if ('allow' == System.properties['build.network_access']) {
            mavenCentral()
        } else {
            maven {
                url 'dependencies'
            }
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.2.0-beta2'
    }
}

要在离线模式下运行,请输入:

gradle --offline

并以在线模式运行:

gradle -Dbuild.network_access=allow

要收集所有依赖项,请使用此脚本,该脚本将在联机模式下运行gradle,获取依赖项以在${project_dir}/.gradle_home内缓存,并将工件复制到dependencies文件夹中的本地maven存储库。

#!/usr/bin/python

import sys
import os
import subprocess
import glob
import shutil

# Place this in build.gradle:
# repositories {
#     if ('allow' == System.properties['build.network_access']) {
#         mavenCentral()
#     } else {
#         maven { url 'dependencies' }
#     }
# }
def main(argv):
    project_dir = os.path.dirname(os.path.realpath(__file__))
    repo_dir = os.path.join(project_dir, "dependencies")
    temp_home = os.path.join(project_dir, ".gradle_home")
    if not os.path.isdir(temp_home):
        os.makedirs(temp_home)
    subprocess.call(["gradle", "-g", temp_home, "-Dbuild.network_access=allow"])
    cache_files = os.path.join(temp_home, "caches/modules-*/files-*")
    for cache_dir in glob.glob(cache_files):
        for cache_group_id in os.listdir(cache_dir):
            cache_group_dir = os.path.join(cache_dir, cache_group_id)
            repo_group_dir = os.path.join(repo_dir, cache_group_id.replace('.', '/'))
            for cache_artifact_id in os.listdir(cache_group_dir):
                cache_artifact_dir = os.path.join(cache_group_dir, cache_artifact_id)
                repo_artifact_dir = os.path.join(repo_group_dir, cache_artifact_id)
                for cache_version_id in os.listdir(cache_artifact_dir):
                    cache_version_dir = os.path.join(cache_artifact_dir, cache_version_id)
                    repo_version_dir = os.path.join(repo_artifact_dir, cache_version_id)
                    if not os.path.isdir(repo_version_dir):
                        os.makedirs(repo_version_dir)
                    cache_items = os.path.join(cache_version_dir, "*/*")
                    for cache_item in glob.glob(cache_items):
                        cache_item_name = os.path.basename(cache_item)
                        repo_item_path = os.path.join(repo_version_dir, cache_item_name)
                        print "%s:%s:%s (%s)" % (cache_group_id, cache_artifact_id, cache_version_id, cache_item_name)
                        shutil.copyfile(cache_item, repo_item_path)
    shutil.rmtree(temp_home)
    return 0

if __name__ == "__main__":
    sys.exit(main(sys.argv))

因此,在每次依赖项更改后,只需运行此脚本并在dependencies文件夹中提交更改。然后,您可以使用gradle --offline或仅gradle离线构建。

答案 1 :(得分:4)

在过去,我使用了类似的解决方案,但是我的#34;复制脚本是在groovy而不是python中完成的。

几周前我发现了另一种方法:ivypot plugin。现在你不必使用任何"外部"脚本,插件能够将所有依赖项复制到本地目录,这是一个常春藤回购。

可以找到测试项目on github。如果有需要,我可以提供英语自述文件。

答案 2 :(得分:0)

最直接的解决方案是对整个依赖项缓存目录进行快照:~/.gradle

尽管有一些挑战:

  1. 这将占用大量磁盘空间
  2. 它将包含数千个文件(难以手动操作)
  3. 由于这是一个缓存而不是存储库,因此Gradle为under no obligation to keep things permanently

要解决上面的项目2和3,我建议使用Git(以及备份副本)来帮助您克服Gradle的缓存清理守护程序并避免错误:“ no cached version available for offline mode”。当您具有完全填充的依赖项缓存(--offline构建正在运行)时,请将缓存提交到版本控制,以便以后可以在必要时进行还原(例如,使用git stash放弃所有更改)


如果~/.gradle文件夹可以简化项目管理或备份,则仍应作为指向文件系统其他位置的符号链接。通过使用--project-cache-dir,该方案可能还会有一些改进,但是我还没有尝试过。


这涉及到一些手动的存储库管理,因为 Gradle缓存管理正在积极地致力于稳定的离线开发目标-但它应该有助于保持运行。