2015-02-10 29 views
16

我正在为一部分软件实施Gradle构建系统,该软件具有在没有Internet连接的区域开发的部件或者安装Maven/Ivy服务器(如Nexus)的能力。为了支持这些环境中的开发,我将放置一个允许生成“离线工作区”的Gradle插件。构建用于离线开发的Gradle存储库

我最初通过触发项目中每个配置的解析(触发所有依赖项的下载),然后遍历每个配置的整个依赖关系树,并将依赖项的本地缓存副本复制到离线工作区。 (为每个复制操作生成一个复制任务。)然后使用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)。总而言之,这种方法感觉相当冒险,因为它还要求我修改build.gradle文件以显式列出所有传递依赖项,因为没有可用的POM文件来正确指定依赖项。

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

有没有更好的方式,我可以实现完整的工件下载到一个易于打包的方式,而不仅仅是压缩我的整个$ USER_HOME/.gradle目录?

回答

9

要进行脱机构建,您需要以某种方式提供所有必需的依赖关系。这里的选项之一就是将这些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缓存和文物复制到本地Maven回购位于dependencies文件夹中。

#!/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 --offlinegradle离线构建。

3

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

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

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

+1

英文自述会好的 – Cesar 2017-11-03 21:47:10

+0

这个ivypot插件很酷。但它不能解决我的问题。我只需要缓存来自私有存储库的一组有限的依赖项。我不需要缓存所有内容。 因此,我需要搜索另一个类似的插件,或者在此插件代码中实现该功能。 – kinORnirvana 2017-11-09 10:46:49