web-dev-qa-db-ja.com

オフライン開発用のGradleリポジトリを構築する

私は、インターネット接続またはMaven/Ivyサーバー(Nexusなど)をインストールする機能がない地域で開発されたパーツを含むソフトウェアのGradleビルドシステムの実装に取り​​組んでいます。これらの環境での開発をサポートするために、「オフラインワークスペース」の生成を可能にするGradleプラグインをまとめています。

私は当初、プロジェクトの各構成の解決をトリガーして(すべての依存関係のダウンロードをトリガーして)、この構成を実装しました。次に、各構成の依存関係ツリー全体を走査し、依存関係のローカルキャッシュコピーをオフラインワークスペースにコピーしました。 (コピー操作ごとにコピータスクが生成されました。)これらのJARは、flatDirリポジトリを使用して参照されます。

この実装は、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)。依存関係を適切に指定するためのPOMファイルがないため、すべての推移的な依存関係を明示的にリストするようにbuild.gradleファイルを変更する必要があるため、このアプローチは全体的にややハックに感じられます。

より洗練されたアプローチは、すべての依存関係(POMファイル、ソースJAR、javadoc JARなどを含む)のローカルMavenリポジトリを構築し、mavenLocal()リポジトリタイプを使用するようです。残念ながら、この操作を実行するためにアーティファクト解決をトリガーする必要がない場合に、これを適切に行う方法がわかりません。

$ USER_HOME/.gradleディレクトリ全体を圧縮するだけではなく、完全なアーティファクトダウンロードを簡単にパッケージ化できる方法はありますか?

18
Chris Lieb

オフラインでビルドするには、必要な依存関係をすべて提供する必要があります。ここでのオプションの1つは、これらのjarをバージョン管理にコミットすることです。難しいのは、これらの依存関係をすべて収集することです。そのため、2つのモード(オンラインとオフライン)で動作する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を使用してオフラインでビルドできます。

13
wonder.mice

以前、私は同様のソリューションを使用していましたが、「私の」コピースクリプトはpythonではなくgroovyで実行されていました。

数週間前に別のアプローチを検出しました: ivypotプラグイン があります。これで、「外部」スクリプトを使用する必要がなくなりました。プラグインは、すべての依存関係をivyリポジトリであるローカルディレクトリにコピーできます。

テストプロジェクトは github で見つかります。必要に応じて、英語のREADMEを提供できます。

4
user959232

最も簡単な解決策は、依存関係キャッシュディレクトリ全体をスナップショットすることです:~/.gradle

ただし、いくつかの課題があります。

  1. かなりの量のディスク容量が必要になります
  2. 何千ものファイルが含まれます(手動で操作するのは難しい)
  3. これはキャッシュではなくリポジトリなので、Gradleは 永続的に保持する義務がない です。

上記の項目2と3に対処するには、Gradleのキャッシュクリーニングデーモンを無効にし、エラーを回避するために Git (およびバックアップコピー)を使用することをお勧めします: " オフラインで使用できるキャッシュバージョンがありませんモード "。完全に読み込まれた依存関係キャッシュがある場合(--offlineビルドが機能している場合)、キャッシュをバージョン管理にコミットして、後で必要に応じて復元できるようにします(たとえば、git stashを使用してすべての変更を破棄します)。 。


~/.gradleフォルダーは、プロジェクト管理またはバックアップを簡素化する場合、ファイルシステム内の別の場所へのシンボリックリンクとして機能します。 --project-cache-dir を使用することで、このスキームを改善できる場合もありますが、まだ試していません。


Gradleキャッシュ管理は、安定したオフライン開発の目標に積極的に取り組んでいるため、これにはいくつかの手動リポジトリ管理が含まれます-でも、実行を続けるのに役立つはずです。

0
nobar