(クレジット写真:Nathan Youngman)
はじめに、すべてのノイズが発生する理由と、Goに最初に高度な依存関係マネージャーがなかった理由を理解しましょう。
依存関係管理とは何ですか?
「高度な」依存関係マネージャーの意味と、それが解決すべきタスク。 結局のところ、Goには単純な依存関係管理があります。
Goには、標準の「go get」コマンドがあります。これは、Githubなどのプロジェクトの名前を示すのに十分であるため、プロジェクトコードがインストール、コンパイルされ、すぐに使用できます。 「Go get」は常にmasterブランチから最新バージョンをダウンロードします。オープンソースライブラリの一般的なコンセンサスは、いかなる場合でも後方互換性を壊さないことです。 これはFAQに書かれており、サードパーティライブラリのほとんどの場合、このルールは尊重されています。
あなたは、以前の経験に応じて、このアイデアを芽で拒否するか、すぐにこのスキームが実行不可能になると予想することができますが、これまでのところ、Go 1が3年間存在した後、このスキームは機能し、大企業の生産でも使用されています最初はオープンソースのエコシステム向けに設計されていますが。 私はこれを言います-これは、開発者が取り組む準備ができている複雑さとリスクの比率の問題です。
しかし、オープンソースの世界から商業開発の世界へと移行すると、特定のリビジョンのコードが常にコンパイルされ、同じ結果を生成し、外部要因に依存しないことを保証する必要がすぐに生じます。 外部要因は、互換性の破壊、サードパーティライブラリの変更、インターネットの切断またはGithubの崩壊など、新しいものとして理解できます。
この問題は2つの方法で解決されます。多くの場合、コードベースにサードパーティのコードを含めて、 バージョン管理の依存関係とベンダー 管理を組み合わせます。 1つ目は、サードパーティライブラリへの新しいコミットがビルドを壊さないようにすることを可能にし、2つ目は、インターネットがクラッシュしても、アセンブリに必要なすべてのコードがローカルでアセンブリに利用できることを保証します。
実際、これは高度な依存関係管理とは何かという質問に対する答えです。これは、依存関係のバージョニングと自動販売に必要なすべてを含むツールです。
なぜこれはGoではないのですか?
簡単な答えは、みんなを幸せにするのは大変だからです。 それほど難しくはありません-実際の業務で発生するすべてのケースに適した最も便利なツールを作成することは不可能です。
Goの作者は当初、タスクの複雑さを認識し、すべての人に解決策を課すことを正直に拒否し、オプションを提案しました。 この質問は公式のFAQに明記されており、答えは次のとおりです。
バージョニングは、特に大規模なコードベースではかなり複雑な原因であり、さまざまな状況の規模で、誰にとっても十分に機能するソリューションを知りません。
結構です、同意します。
さらに、よくある質問では、Googleがこの問題をどのように、どのように解決し、どのように解決するかについての推奨事項を提供しています(ここでも、「私たちにふさわしいものはあなたにふさわしくないかもしれない」) また、「完璧なソリューション」があれば、コミュニティはすべてのカードを手元に用意し、Goの標準として作成して提供します。
実践が示しているように、ここに皆のための普遍的なソリューションはありません。 しかし、さまざまな機会に対する解決策の動物園と問題の絶え間ない議論は、Goでの高度な依存関係管理についての議論を終わらせるものについて、かなり良いコンセンサスを導きました。
問題を解決しようとする試みの簡単な歴史。
ソリューションの動物園全体は、バージョン管理、自動販売、またはその両方の問題を解決するユーティリティに帰着します。 ソリューションの範囲は広いです-GOPATHとgit-self-modulesの置き換えによる単純なMakefile-cから、インポートでのパスの書き換えと、最も人気のあるGodepです。
しかし、それらはすべて、本質的に標準のgo getおよびgo buildコマンドのラッパーです。 そして、それが主な矛盾の原因でした。 go get / buildを使用する際のワークフローは、オープンソースプロジェクトを作成している場合に最適です。すべてがシンプルで便利です。 ただし、オープンソースの活動とまったく交わらない別の作業ドラフトを作成している場合、バージョン管理/販売のすべてのソリューションはかかとの痛みになり、特定のアメニティを奪い、複雑さを増します。 両方のシナリオを混在させようとすると、事態はさらに混乱します。
これら2つの主な異なる開発シナリオ(オープンソースプロジェクトとプライベートクローズドプロジェクト)の認識により、シナリオごとに異なるソリューションが必要であるという認識に至りました。 そして、少し前まで、 Dave Cheney (Goの寄稿者の1人であり、一般に高貴なGoポピュラライザー)は、これら2つのシナリオを明確に分離し、2番目のシナリオを別個に作成することを提案しました。 「コード」と「依存関係」が明確に分離されたプロジェクト指向のソースツリーを使用します。
gb-プロジェクトベースのビルドツール
gbの基礎となる主なポイント:
- 標準のgo get / build / testを置き換える個別のユーティリティ
- ディレクトリ構造がすべてを決定します
- 特別な記述ファイルはありません
- コードの変更なし(インポートの書き換えを含む)
- コードを「プロジェクト」と「依存関係」に明確に分離
「標準のgo get / build / testを置き換える」というフレーズが怖い場合は、これは通常の反応です:)実際、gbのプロジェクトは標準のgo build / testで完全に安全に使用できますが、gb buildでは、パッケージ化されたパッケージ。
順番に。
標準のgo get / build / testに代わる別のユーティリティ
これはまさにそのとおりであり、作業システムに別のコマンドを入力する必要があります。 これは単純に行われます:
go get github.com/constabulary/gb/...
ディレクトリ構造がすべてを決定します
「すべて」とは、gbがこのプロジェクトで作業できるという事実を意味します。 ここのルールは単純です-ディレクトリにsrc /フォルダーが必要です。 これで、GBの使用を開始できます。
多くの場合、Goが1つのプロジェクトのみに使用される場合、「プロジェクトごとのGOPATH」アプローチが推奨されます。実際、GOPATHをこのプロジェクトへのパスに変更して作業するように求められます。 gbは、システムのGOPATHに触れることなく、同様のものを実装します。 詳細は以下をご覧ください。
特別な説明ファイルはありません
最新のプロジェクトは、すでにさまざまなマニフェストと説明を含む多数の.dotファイルで構成されています。 別のこのようなファイルは、プロジェクトをビルドするために必要でした-それは多すぎて、Goスタイルではありません。
コード変更なし
プロジェクトコードは、常に記述されたままです。 ' import“ github.com/user/pkg”-> import“ vendor / github.com / user / pkg”というスタイルのインポートの書き換えはありません。
コードを「プロジェクト」と「依存関係」に明確に分離
ディレクトリ構造のセクションに戻ると、gbはsrc /のすべてをプロジェクトのコードとして扱います。 すべての依存パッケージはvendor /ディレクトリにインストールされ、そこからgbでビルドするときにコードが取得されます。
使用例
ツールを理解する最良の方法は、ツールを使用することです。
最初に、新しいプロジェクト〜/ demoprojectを作成します。 / tmpであっても、ディレクトリは関係ありません。 gbを使用する場合、標準のGOPATH全般を忘れることがあります。
mkdir ~/demoproject && cd !$ mkdir -p src/myserver cat > src/myserver/main.go <<END package main import ( "github.com/labstack/echo" "net/http" ) func hello(c *echo.Context) error { return c.String(http.StatusOK, "Hello, World!\n") } func main() { e := echo.New() e.Get("/", hello) e.Run(":1323") } END
これまでのプロジェクトツリーは次のようになります。
$ tree $(pwd) /Users/user/demoproject └── src └── myserver └── main.go
次のコマンドを使用してビルドを実行します。
$ gb build
gb buildは、依存関係( github.com/labstack/echo )が見つからなかったことを示すエラーを与えるはずです:
FATAL command "build" failed: failed to resolve import path "myserver": cannot find package "github.com/labstack/echo" in any of: /usr/local/go/src/github.com/labstack/echo (from $GOROOT) /Users/user/demoproject/src/github.com/labstack/echo (from $GOPATH) /Users/user/demoproject/vendor/src/github.com/labstack/echo
注意深く見ると、gbはまずGOROOT(stdlibパッケージがあるため)で依存パッケージを探し、次にこのプロジェクト(demoproject / src)で定義されているGOPATHで、最後にdemoproject / vendorで依存パッケージを探すことがわかります。 。 パッケージがまだどこにも存在しないため、エラーが発生します。 ベンダーの手でパッケージをプルできます(そして.gitフォルダーを削除することを忘れないでください)が、gbには次の機能があります: gb vendor
$ gb vendor fetch github.com/labstack/echo Cloning into '/var/folders/qp/6bvmky410dn8p1yhn3b19yxr0000gn/T/gb-vendor-097548747'... remote: Counting objects: 1531, done. remote: Compressing objects: 100% (45/45), done. remote: Total 1531 (delta 12), reused 0 (delta 0), pack-reused 1482 Receiving objects: 100% (1531/1531), 317.40 KiB | 191.00 KiB/s, done. Resolving deltas: 100% (911/911), done. Checking connectivity... done.
プロジェクトディレクトリの構造を確認します。
$ tree -L 6 $(pwd) /Users/user/demoproject ├── src │ └── myserver │ └── main.go └── vendor ├── manifest └── src └── github.com └── labstack └── echo ├── LICENSE ├── README.md ├── context.go ├── context_test.go ├── echo.go ├── echo_test.go ├── examples ├── group.go ├── group_test.go ├── middleware ├── response.go ├── response_test.go ├── router.go ├── router_test.go └── website 10 directories, 14 files
マニフェストファイルには、依存関係バージョンに関するすべての情報が含まれています。
$猫ベンダー/マニフェスト
{ "version": 0, "dependencies": [ { "importpath": "github.com/labstack/echo", "repository": "https://github.com/labstack/echo", "revision": "1ac5425ec48d1301d35a5b9a520326d8fca7e036", "branch": "master" } ] }
残りの依存関係についてgbベンダーフェッチを繰り返し、コードの収集を試みます。
$ gb build github.com/bradfitz/http2/hpack github.com/labstack/gommon/color github.com/mattn/go-colorable golang.org/x/net/websocket github.com/bradfitz/http2 github.com/labstack/echo myserver $ tree bin/ bin/ └── myserver 0 directories, 1 file
bin /ディレクトリ内の1つのGOPATHで作業する通常のシナリオのように、バイナリが配置されます。
これで、ディレクトリ全体をバージョン管理システムに安全に追加できます。ここでは、プロジェクトの所有者として、バージョン管理のみを残すか、すべての依存関係をベンダー化するか、すべてを終了するか、バージョンを手動で管理するかを決定します。 あなたの手の中には選択の自由があります。
- バージョン管理のみ:ベンダー/ srcを.gitignoreに追加
- ベンダーのみ:ベンダー/マニフェストを.gitignoreに追加します
- およびバージョン管理と自動販売:.gitignoreを変更せずに残す
バージョン管理のみの場合、チームの開発者は、リポジトリをマシンにクローンした後、次を実行する必要があります。
$ gb vendor update -all
プロジェクトを構築するための1-in-1依存関係ツリーを取得します。
一般に、この説明は、バージョン管理と自動販売の問題を解決する作業の原則とgbのアプローチを理解するのに十分なはずです。
あとがき
gbプロジェクトはまだコミュニティによる開発と採用の初期段階ですが、後者の反応と強力なサポートから判断すると、これは非常に優れたソリューションです。
プロジェクトにはトラッカーで多くの未解決の問題がありますが、それらはすぐに終了し、プロジェクトは活発に開発されています。
使用のまだ素晴らしい個人的な経験によると-クロスプラットフォームのアセンブリにはまだ困難があります。 それ以外の場合、飛行はこれまでのところ正常です。
参照資料
公式ウェブサイト: getgb.io
Githubリポジトリ: github.com/constabulary/gb
著者によるブログ投稿: dave.cheney.net/2015/06/09/gb-a-project-based-build-tool-for-the-go-programming-language
設計根拠: getgb.io/rationale
動作理論: getgb.io/theory