バックグラウンド
仕事では Gradle を使用してソフトウェア (Java/C++/MATLAB) を構築し、顧客ごとに構成ファイルのバリエーションをパッケージ化し、すべての最終的な集合インストールを組み立てます。
「顧客のバリエーション」の一部は、一連のコピー/レイヤー化ルールを持つ通常のディレクトリ構造であるため、必要に応じてバリエーション間で構成をできるだけ多く共有できます。
今日、私はここで再作成した作成済みリポジトリのような copyConfiguration タスクを使用してこれを実現します。各バリエーションは、「config」プロジェクト全体の個別のサブプロジェクトと見なされます。project.name 内のファイルを順番に (1, 2, project.name) コピーし、同じ名前のファイルを 1 または 2 から上書きします (2 対 1 の場合も同様です)。ターゲット ディレクトリを構築し、デプロイ用に圧縮します。この例では名前を作成しましたが、「コンポーネント」サブディレクトリ (aaa、bbb など) が 12 個ほどあり、サブプロジェクトが 10 ~ 15 個 (「orderToCopy」の最大長が約 5) あると考えてください。ファイル名は、異なるコンポーネントまたはサブプロジェクト間でグローバルに一意ではありません (そのため、'
問題点
毎週、次のリリースを受け取る顧客に基づいて、いくつかのバリエーションを再インストールします。現在、インストール プロセスは非常に手動で時間がかかります (通常、数百台のサーバーでは一晩中)。壊滅的な事態が発生しない限り、次のインストールまで構成のリリース ビルド全体を再ロールすることは避けています。すべてを再インストールせずに変更をオーバーレイできる社内の「パッチ アプライヤー」システムを使用して、やり遂げています。これらのパッチは、何を修正する必要があるかに基づいて手作業で作成されています。同じファイルが別の人によって複数回パッチされたり、誰かが同じ名前のファイルを間違った場所にコピーしたりすると、これは時々苦痛になります (たとえば、複数の log4j.properties がありますが、特定のディレクトリで正しいのは 1 つだけです)。
また、ある顧客のバリエーション (古いクライアント) が別の新しいバリエーション (新しいクライアント) と通信する必要がある状況もよくあります。これは通常、新しいクライアントを配信するときに、最後に配信された古いクライアント構成の上に上記と同様のパッチを作成することで処理されます。これらはお互いの上に構築されることがあり、すべてのパッチが手動で構築されるため (たとえば、このファイルをここにコピーする、このファイルの名前を変更するなど)、これはさらに苦痛でストレスの多いことです。分岐をサポートする VCS が登場する前は、これはもっとひどいものでした...
問題/望ましい目標は?
私はこれについて数ヶ月間断続的に考えてきましたが、良い解決策が見つかりません. 私ができるようにしたいのは、VCS (私たちの場合は git) からの情報または以前の情報 (アーティファクト、ビルド領域など) に依存して、特定の参照ポイントから各バリエーションのデルタ zip ファイルを作成することです。私のサンプル リポジトリでは、src/main/dist/aaa/2/fileA が変更された場合、理想的な世界では、サブプロジェクト 1 のデルタ パッチ zip は空になり、サブプロジェクト 2 の変更されたファイルのみが含まれます。
アイデア
完全なビルドを作成し、(Gradle コマンド ライン プロパティに基づいて) 前のビルドをダウンロードし、それを抽出してから、2 つの出力ディレクトリを比較してみました。 私はこれを機能させることができると思いますが、それは汚いようで、Gradleの外で機能します。 Mozilla で使用されているデルタ バイナリ パッチを紹介した後、Java 用の xdelta バイナリ diff ライブラリを見つけ、それを使用して概念実証を行いました。
他のアイデアはありますか?このようなことを行うためのより良い宣言的または慣用的なGradleの方法はありますか? これを簡単にするために copyConfiguration を作り直す方法があれば、私はアイデアを受け入れます。
放棄されたアイデア
git whatchanged を使用して変更されたファイルのリストを取得し、リストにないファイルを eachFile{} クロージャーで exclude() することができました。これは、「リーフ」ファイルが変更されている限り機能します。src/main/dist/aaa/2/fileA が変更された場合、aaa/1/fileA と aaa/subproject1/fileA を除外することになり、パッチ ビルドの内容が間違ってしまいます。これは、1 または 2 のファイルが現在使用されている場所の削除も処理しません (優先度の高いファイルが削除されたため)。何もインストールしないようにファイルのすべてのオカレンスを削除する場合もありますが、それは今のところ無視できるエッジ ケースだと思います。すべてのコーナーケースでこれを正しく行うのは非常に難しいように思われました。また、変更されたすべてのファイルのベース名を取得しようとしましたが、これは一般的なファイル名を過剰に選択し、パッチに含まれるファイルが多すぎます。たとえば、aaa/2/fileA が変更された場合、aaa/data/fileA と bbb/data/fileA を含む subproject1 のパッチをビルドすることになります (ファイルがないことが「正解」である場合)。パッチのzipには変更されていないファイルが含まれており、削除/移動を処理しなかったため、これは嫌いでした.私も考えましたが、まだ試していませんが、上記のようなことをしています。前のコミットにチェックアウトし、ビルドし、コミットにチェックアウトしてパッチをビルドし、Gradle のインクリメンタル ビルド機能にフックします。まだ Gradle 1.1 を使用しているため、その機能はまだ利用できません。これは苦痛で、Gradle を 2 回実行するスクリプトが必要でした。
読んでくれてありがとう!