2015-02-10 69 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