web-dev-qa-db-ja.com

自己完結型プロジェクト:GradleとMavenの依存関係をオフラインで

私はJavaプログラミングプロジェクトを、バージョン管理のファイルから完全にオフラインでビルドできるように、任意のマシンで、インストールの前提条件なしにセットアップできるようにしています。(唯一の例外:JDK)

Mavenについてはあまり知りませんが、現在Gradleを学んでいます。 Gradleとラッパーを使用しているビルドでは、gradle-wrapper.propertiesを変更して、distributionUrlがリモートURLではなく、プロジェクトのフォルダー内のファイルを指すようにしました。したがって、Gradle自体はすでに完了しています。

依存関係については、これは純粋な悪夢です。私はすでに、単一のJARまたはJARのコレクションを直接指すだけで管理しようとしましたが、ご存じのとおり、相互依存関係や推移的な依存関係があると、これは完全に混乱します。

基本的に私が欲しいのは、ローカルの依存関係キャッシュに別のディレクトリを使用するようにGradle/Mavenを(このプロジェクトのためだけに)構成することです-ユーザーアカウント、家で何をしても共有するディレクトリではありませんディレクトリではなく、その1つのプロジェクトでのみ使用されるプロジェクトフォルダー内のフォルダー(バージョンコントロールにチェックインすることもできる)。次に、Gradle/Mavenをオンラインモードで1回だけ取得し、ビルドを1回実行して、現在必要なすべての依存関係をプロジェクトフォルダー内のローカルキャッシュディレクトリ(コンテンツはVCに格納されます)にダウンロードし、オフラインモードにします。以降のすべてのビルド。

この1つのプロジェクトのためだけにローカルキャッシュパスを再構成する方法をまだ見つけていません(自分のbuild.gradleに入れることができるものでなければなりません)。誰かが私にリードを持っていますか?

編集:プロジェクトフォルダー内のこのローカルリポジトリを(単なるキャッシュではなく)「実際の」Mavenリポジトリにすることもできます。しかし、私が想像した1つの方法で手作業が必要になります。build.gradleで参照しているすべてのMavenリポジトリに対してプロキシリポジトリが設定されているSonatype Nexusのローカルコピーを開始します。ローカルのNexusを指すようにビルドスクリプトのリポジトリURLを変更し、ビルドを1回実行して、Nexusがdepをダウンロードして「通常の」Mavenリポジトリ構造の作業ディレクトリに配置するようにします。次に、その構造をプロジェクトフォルダー内のフォルダーにコピーし、ファイルをコピーしたフォルダーを指すようにbuildscript repo URLを変更します。かろうじて自動化できるかなり多くの作業。

6
Julian

さて、私は自分に合った方法を見つけました。それは自動化できます。

私は this snippet を見つけました。これにより、特定のプロジェクトの依存関係をMavenディレクトリ構造の任意のフォルダにコピーするGradleタスクを作成できます。私は 少し微調整する (リンクが壊れている)が必要だったので、1つの構成だけでなく、プロジェクトで定義されているすべての構成でも同じことが行われます。

私のビルドスクリプトは次のようになります。

_apply plugin: 'Java'

repositories {
    maven {
        url './dependencies-maven/'
    }
    mavenCentral()
    jcenter()
    // whatever other external repos your deps come from
}

dependencies {
    // ...
}

task offlineRepo (type:OfflineMavenRepository) {
    repoDir = new File(project.projectDir, 'dependencies-maven')
}
_

次に、offlineRepoタスクを1回起動するだけです。現在のプロジェクトのすべての依存関係がGradleのローカルキャッシュにダウンロードされ、プロジェクトディレクトリ(Mavenリポジトリ構造内)のサブフォルダーにコピーされます。次にこの状態でプロジェクトディレクトリを使用してビルドを実行すると、先ほど作成したローカルリポジトリが最初にクエリされ、すべてのdepが含まれている(含まれている必要がある)ため、Gradleのユーザーフォルダーキャッシュやウェブ。

この時点で、Gradleがインストールされているだけで、プロジェクトフォルダー全体を他のマシンに移動できます。追加のデータを取得するためにオンラインに接続することなく、ビルドを実行できます。

プロジェクトの依存関係を更新したり、新しい依存関係を追加したりする場合は、offlineRepoタスクをもう一度起動する必要があります。これにより、更新する依存関係の古いバージョンが削除されないことに注意してください。そのため、雑然としたリポジトリで終わりたくない場合は、ここで手動でクリーニングする必要があります。

これに加えて、Gradleラッパーもオフラインにして(元の質問で説明)、プロジェクトを完全にオフラインで構築できるようにしました。最小限の前提条件で、インターネット接続は不要で、Gradleのインストールも必要ありません。単なるJDK。

注:これを完全に空のダミープロジェクトに設定すると、Javaソースディレクトリと一部のサンプルJavaファイル、それ以外の場合、Gradleは一部のPOMのみをダウンロード/コピーしますが、対応するJARはダウンロードしません。

追加:調整されたスニペットは、プロジェクトの依存関係のみを処理します。ただし、buildscriptの依存関係であるカスタムプラグインを使用すると、スクリプトはそれを逃します。 build()メソッドにコードを追加する必要があります。

_for(Configuration configuration : project.buildscript.configurations.findAll())
{
    copyJars(configuration)
    copyPoms(configuration)
}
_

編集、2019年12月:3年後、ずっと賛成票が集まり、明確なリクエストが出された後、このトピックはまだ重要ではないようです。私だけに。

リンクの破損を回避するために、プロジェクトスケルトンセットアップの現在のバージョンをここに投稿します。

以下は、将来のプロジェクトディレクトリとなる空白のスレート/空のフォルダーから始めることを前提としています。ここで指定するすべてのパスは、プロジェクトのルートフォルダーを基準にしています。

  1. _gradle-wrapper.jar_を取得し、それを_/gradle/wrapper_に配置します。付随するgradlewおよび_gradlew.bat_実行スクリプトをプロジェクトのルートフォルダーに配置します。どこかにそれらがある場合は、それらを直接入手するか、Gradleをローカルシステムにインストールし、プロジェクトのルートフォルダーで_gradle wrapper_を実行してこれらのファイルを生成します。 (ラッパーjarとスクリプトを他の場所から入手できる場合は、Gradleをローカルにインストールする必要はありません。入手できない場合でも、これは1回限りのジョブです。ラッパーを配置すると、ローカルにインストールする必要がなくなります。 Gradleのインストール。)
  2. Gradleバイナリ配布パッケージ(_gradle-X.X-bin.Zip_のようなファイル名)をどこかから取得し、_/gradle/wrapper/_に配置します。
  3. 以下を含むように_/gradle/wrapper/gradle-wrapper.properties_を作成(または既存のものを変更)します。

    _distributionBase=PROJECT
    distributionPath=gradle/wrapper/dists
    zipStoreBase=PROJECT
    zipStorePath=gradle/wrapper/dists
    distributionUrl=./gradle-X.X-bin.Zip
    _

    distributionUrlで指定されたファイル名は、単なるプレースホルダーであり、実際のファイル名または手順2で使用したバイナリ配布パッケージと一致する必要があります。)(または、distributionBasezipStoreBaseを_GRADLE_USER_HOME_に設定して、プロジェクトのフォルダーに作成された一時ファイル。代わりにホームフォルダーに作成されます。)

  4. 特定の一時ファイルとディレクトリをバージョン管理から除外してください。私自身はGitを使用しているので、私のignore-fileの例はGit用です。別のバージョン管理システムを使用している場合は、必要に応じて調整します。

    _.gradle/
    gradle/wrapper/dists/
    build/
    buildSrc/.gradle
    buildSrc/build/
    _
  5. 次の内容のファイル_/buildSrc/src/main/groovy/buildutils/OfflineMavenRepository.groovy_を追加します(これは、上記にリンクされているbmuschkoのコードであり、提案されたすべての変更が適用されています)。

    _package buildutils
    
    import org.gradle.api.tasks.Input
    import org.gradle.api.tasks.Optional
    import org.gradle.api.tasks.OutputDirectory
    import org.gradle.api.tasks.TaskAction
    import org.gradle.api.DefaultTask
    import org.gradle.util.GFileUtils
    import org.gradle.api.artifacts.Configuration
    import org.gradle.api.artifacts.component.ModuleComponentIdentifier
    import org.gradle.maven.MavenModule
    import org.gradle.maven.MavenPomArtifact
    
    class OfflineMavenRepository extends DefaultTask {
        @OutputDirectory
        File repoDir = new File(project.projectDir, 'dependencies/maven')
    
        @TaskAction
        void build() {
            // Plugin/Buildscript dependencies
            for(Configuration configuration : project.buildscript.configurations.findAll())
            {
                copyJars(configuration)
                copyPoms(configuration)
            }
    
            // Normal dependencies
            for(Configuration configuration : project.configurations.findAll())
            {
                copyJars(configuration)
                copyPoms(configuration)
            }
        }
    
        private void copyJars(Configuration configuration) {
            configuration.resolvedConfiguration.resolvedArtifacts.each { artifact ->
                def moduleVersionId = artifact.moduleVersion.id
                File moduleDir = new File(repoDir, "${moduleVersionId.group.replace('.','/')}/${moduleVersionId.name}/${moduleVersionId.version}")
                GFileUtils.mkdirs(moduleDir)
                GFileUtils.copyFile(artifact.file, new File(moduleDir, artifact.file.name))
            }
        }
    
        private void copyPoms(Configuration configuration) {
            def componentIds = configuration.incoming.resolutionResult.allDependencies.collect { it.selected.id }
    
            def result = project.dependencies.createArtifactResolutionQuery()
                .forComponents(componentIds)
                .withArtifacts(MavenModule, MavenPomArtifact)
                .execute()
    
            for(component in result.resolvedComponents) {
                def componentId = component.id
    
                if(componentId instanceof ModuleComponentIdentifier) {
                    File moduleDir = new File(repoDir, "${componentId.group.replace('.','/')}/${componentId.module}/${componentId.version}")
                    GFileUtils.mkdirs(moduleDir)                
                    File pomFile = component.getArtifacts(MavenPomArtifact)[0].file
                    GFileUtils.copyFile(pomFile, new File(moduleDir, pomFile.name))
                }          
            }
        }
    }
    _
  6. 次のように_/build.gradle_スケルトンを作成します。

    _repositories {
        maven {
            url './dependencies/'
        }
    
        mavenLocal()
        mavenCentral()
        jcenter()
    }
    
    buildscript {
        repositories {
            maven {
                url './dependencies/'
            }
    
            mavenLocal()
            mavenCentral()
            jcenter()
        }
    }
    
    import buildutils.OfflineMavenRepository
    task offlineDependencies (type:OfflineMavenRepository) {
        repoDir = new File(project.projectDir, 'dependencies/')
    }
    _
  7. 追加のオンライン依存関係リポジトリ、依存関係、およびその他のビルドロジックを_build.gradle_に追加し、_./gradlew offlineDependencies_を実行します。これにより、_/dependencies/_内にフォルダー構造が作成され、すべての依存関係JARがダウンロードされて内部に配置されます。そこにファイルを取得するには、これを1回実行するだけで済みます。それらが配置されたら、プロジェクトの依存関係が変更された場合(つまり、追加の依存関係またはバージョンが変更された場合)にのみ、このコマンドを再度実行する必要があります。

  8. バージョン管理のすべてをチェックすれば、問題ないはずです。プロジェクトを構築するための唯一の要件は、機能するJava JDKです。Gradleはプロジェクトのディレクトリ内に含まれ(ラッパーを介して使用可能)、したがってすべてのMaven依存関係も同様です。).
3
Julian