2015-02-10 30 views
16

Pracuję nad wdrożeniem systemu kompilacji Gradle dla oprogramowania, które ma części opracowane w obszarze bez połączenia z Internetem lub możliwość zainstalowania serwera Maven/Ivy (takiego jak Nexus). Aby wspierać rozwój w tych środowiskach, przygotowuję wtyczkę Gradle, która umożliwia generowanie "Offline Workspace".Tworzenie repozytorium Gradle dla rozwoju offline

Pierwotnie zaimplementowałem tę funkcjonalność, wyzwalając rozdzielczość każdej konfiguracji w projekcie (uruchamiając pobieranie wszystkich zależności), a następnie przechodząc przez całe drzewo zależności każdej konfiguracji i kopiując lokalną kopię zależności do obszaru roboczego offline . (Zadanie kopiowania zostało wygenerowane dla każdej operacji kopiowania.) Do tych JARów odwoływałoby się użycie repozytorium flatDir.

Ta implementacja wykonywała swoje zadanie przy użyciu bloku AfterEvaluate. Mimo że działało to dobrze w Gradle 2.0, uruchamia ostrzeżenie o przestarzałości w Gradle 2.2.1, ponieważ wyzwalanie rozdzielczości jest jakoś widziane jako modyfikowanie konfiguracji po jej rozwiązaniu (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). Podsumowując, podejście to wydaje się dość hackowate, ponieważ wymaga również zmodyfikowania plików build.gradle, aby jawnie wylistować wszystkie zależności przechodnie, ponieważ nie istnieją żadne pliki POM, które mogłyby poprawnie określić zależności.

Bardziej eleganckie podejście wydaje się budować lokalne repozytorium Maven dla wszystkich zależności (w tym pliki POM, źródłowe pliki JAR, pliki JAR javadoc itp.), A następnie wystarczy użyć typu repozytorium mavenLocal(). Niestety, nie jestem pewien, jak to zrobić właściwie, gdy nie potrzebuję wyzwalać rozdzielczości artefaktów, aby wykonać tę operację.

Czy jest jakiś lepszy sposób, w jaki mogę uzyskać pełne pobieranie artefaktów w łatwy do spakowania sposób, niż po prostu skompresowanie całego katalogu $ USER_HOME/.gradle?

Odpowiedz

9

Aby mieć kompilację offline, musisz jakoś zapewnić wszystkie wymagane zależności. Jedną z opcji jest tylko zatwierdzenie tych słoików w kontroli wersji. Najtrudniejsze jest zebranie wszystkich tych zależności. Za to, że można mieć plik build.gradle że może działać w dwóch trybach (online i offline):

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' 
    } 
} 

do pracy w trybie offline Typ:

gradle --offline 

i uruchamianie w trybie on-line :

gradle -Dbuild.network_access=allow 

i zebrać wszystkie zależności użyć tego skryptu, który będzie działał w trybie on-line Gradle, sprowadzić zależności buforować wewnątrz ${project_dir}/.gradle_home artefakty i skopiować do lokalnego repo maven sitory w folderze 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)) 

Tak, po każdej zmianie zależności wystarczy uruchomić ten skrypt i dokonać zmian w dependencies folderu. Następnie możesz budować offline za pomocą gradle --offline lub po prostu gradle.

3

W przeszłości użyłem podobnego rozwiązania, chociaż "mój" skrypt kopiowania został wykonany w stylu groovy zamiast pythona.

Wykryłem inne podejście kilka tygodni temu: Jest ivypot plugin. Teraz nie musisz już używać żadnego "zewnętrznego" skryptu, wtyczka jest w stanie skopiować wszystkie zależności do lokalnego katalogu, który jest repo z bluszczem.

Projekt testowy można znaleźć on github.Mogę zapewnić angielską wersję README na wypadek, gdyby było na nią zapotrzebowanie.

+1

Angielski README będzie ok. – Cesar

+0

Ta wtyczka ivypot jest fajna. Ale to nie rozwiązuje mojego problemu. Potrzebuję buforować tylko ograniczony zestaw zależności, które pochodzą z prywatnego repozytorium. Nie muszę przechowywać w pamięci podręcznej wszystkiego. Muszę więc przeszukać inną podobną wtyczkę lub zaimplementować funkcję w tym kodzie wtyczki. – kinORnirvana