[インデックス 12226] ファイルの概要
このコミットは、Go言語のダッシュボード(misc/dashboard)に、外部パッケージのインストール数を記録する機能を追加するものです。具体的には、Goパッケージのインストール数を追跡し、日次および週次の統計を収集・表示するための基盤を導入しています。これにより、どの外部パッケージがどれくらい利用されているかを把握できるようになります。
コミット
commit 8421390cb9ba9583af6369c7cc4786149058b131
Author: Andrew Gerrand <adg@golang.org>
Date: Mon Feb 27 15:25:41 2012 +1100
misc/dashboard: record install counts for external packages
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5699082
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8421390cb9ba9583af6369c7cc4786149058b131
元コミット内容
misc/dashboard: record install counts for external packages
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5699082
変更の背景
この変更の背景には、Go言語のエコシステムにおける外部パッケージの利用状況を可視化したいというニーズがあります。go getコマンドなどによってインストールされる外部パッケージの利用頻度を把握することは、Goコミュニティにとって重要な情報となります。例えば、どのパッケージが人気があるのか、時間の経過とともに利用状況がどのように変化しているのかなどを知ることで、開発者はより適切なパッケージ選択を行ったり、Go言語の進化の方向性を検討したりする上で役立ちます。
このコミットは、Goダッシュボードという既存のインフラストラクチャを活用し、パッケージのインストールイベントを捕捉し、その統計を永続的に記録するメカニズムを導入することで、この情報収集の課題を解決しようとしています。
前提知識の解説
このコミットを理解するためには、以下の技術や概念に関する知識が役立ちます。
- Go言語: Googleが開発したオープンソースのプログラミング言語。並行処理に強く、シンプルで効率的なコード記述が可能です。
- Goダッシュボード (Go Build Dashboard): Goプロジェクトのビルド、テスト、リリース状況を監視するためのウェブアプリケーション。Goの公式リポジトリの一部として提供されており、Goの様々なサブプロジェクトや外部パッケージの健全性を追跡しています。
- Google App Engine (GAE): Googleが提供するPaaS (Platform as a Service)。ウェブアプリケーションやモバイルバックエンドを構築・ホストするためのプラットフォームで、スケーラビリティやメンテナンスの容易さが特徴です。このダッシュボードアプリケーションはGAE上で動作しています。
- Google Cloud Datastore: Google Cloud Platformが提供するNoSQLドキュメントデータベース。GAEアプリケーションの永続データストアとしてよく利用されます。このコミットでは、パッケージのインストール数を保存するためにDatastoreが使用されています。
app.yaml: App Engineアプリケーションの設定ファイル。URLルーティング、ハンドラ、静的ファイルの設定などを定義します。cron.yaml: App EngineのCronサービスの設定ファイル。定期的に実行されるタスク(ジョブ)を定義します。go getコマンド: Go言語のパッケージ管理ツールの一部で、リモートリポジトリからGoパッケージをダウンロードし、インストールするために使用されます。このコミットで追跡される「インストール」は、このgo getコマンドによるものと推測されます。appengine/delayパッケージ: App Engineのタスクキューを利用して、非同期処理や遅延実行タスクを簡単に実装するためのGo言語パッケージ。このコミットでは、インストール数のインクリメントや週次集計の更新といった処理を非同期で実行するために使用されています。appengine/urlfetchパッケージ: App Engineアプリケーションから外部のHTTPリソースにアクセスするためのGo言語パッケージ。このコミットでは、外部パッケージのインポートパスが実際に存在するかどうかを検証するためにHTTPリクエストを送信する際に使用されています。- 正規表現 (Regular Expression): 文字列のパターンを記述するための強力なツール。このコミットでは、外部パッケージのインポートパスを検証するために正規表現が広く使われています。
- バージョン管理システム (VCS): Git, Mercurial, Subversionなどのコードの変更履歴を管理するシステム。Goのパッケージパスは、VCSのリポジトリ構造と密接に関連しています。
技術的詳細
このコミットは、Goダッシュボードに外部パッケージのインストール数を記録するための包括的なシステムを導入しています。主要な技術的変更点は以下の通りです。
-
Package構造体の拡張:misc/dashboard/app/build/build.go内のPackage構造体に、以下のフィールドが追加されました。Installs int: 全期間の総インストール数。InstallsByDay []string: 日ごとのインストール数を"yyyy-mm-dd,n"形式の文字列スライスで保持します。Datastoreに保存する際にインデックスを付けない(noindex)ことで、書き込み性能を向上させています。InstallsThisWeek int: 直近1週間のインストール数の合計。
-
インストール数増分ロジック (
IncrementInstalls):Package構造体にIncrementInstalls()メソッドが追加されました。このメソッドは、以下の処理を行います。dayCounts()ヘルパーメソッドを使用して、InstallsByDayから日ごとのカウントをマップに展開します。- 現在の日付のカウントをインクリメントします。
- 過去30日間のデータのみを保持し、それより古いデータは破棄します。
- 更新された日ごとのカウントを
InstallsByDayに再格納します。 - 総インストール数
Installsをインクリメントします。 UpdateInstallsThisWeek()を呼び出し、週次カウントを更新します。
-
週次インストール数更新ロジック (
UpdateInstallsThisWeek):Package構造体にUpdateInstallsThisWeek()メソッドが追加されました。このメソッドは、InstallsByDayのデータから直近7日間のインストール数を集計し、InstallsThisWeekフィールドを更新します。 -
日次カウントのマップ変換 (
dayCounts):Package構造体にdayCounts()ヘルパーメソッドが追加されました。これは、InstallsByDayの文字列スライス(例:"2012-02-27,10")をmap[string]int(日付文字列をキー、インストール数を値とするマップ)に変換します。 -
新しい
pkg.goファイルの導入:misc/dashboard/app/build/pkg.goという新しいファイルが追加されました。このファイルは、外部パッケージのインストール数を処理するための主要なロジックを含んでいます。installHandler:go toolからのリクエストを受け付け、特定のパッケージのインストール数をインクリメントする処理をdelay.Funcを使って非同期で実行します。これにより、リクエストの応答時間を短縮し、処理の信頼性を高めています。installCronHandler: Cronジョブから呼び出され、すべての外部パッケージの週次インストール数を更新する処理をdelay.Funcを使って非同期で実行します。install関数:delay.Funcによって遅延実行される実際のインストール数インクリメントロジック。validPath関数でパッケージパスの妥当性を検証します。- Datastoreトランザクション内で
Packageエンティティを取得し、存在しない場合は新規作成します。 IncrementInstalls()を呼び出してインストール数を更新し、Datastoreに保存します。
updateWeekly関数:delay.Funcによって遅延実行される週次カウント更新ロジック。- Datastoreトランザクション内で
Packageエンティティを取得し、UpdateInstallsThisWeek()を呼び出して週次カウントを更新し、Datastoreに保存します。
- Datastoreトランザクション内で
validPath関数: 与えられたインポートパスが有効なGoパッケージパスであるかを検証します。vcsPathsという定義済みのVCS(バージョン管理システム)パスのリストと正規表現を使用して、パスの形式をチェックします。check関数(例:googleCodeVCS,checkRoot)を使用して、実際にそのリポジトリが存在するかどうかをHTTPリクエスト(urlfetchを使用)で検証します。これにより、不正なパスや存在しないパッケージのカウントを防ぎます。
vcsPath構造体とvcsPaths変数: Goのcmd/go/vcs.goから派生したデータ構造で、Google Code, GitHub, Bitbucket, Launchpadなどの主要なVCSホスティングサービスのインポートパスのパターンと検証ロジックを定義しています。
-
app.yamlの変更: 新しいURLパス/installと/install/cronが追加されました。/installは、go toolからのインストール通知を受け付けるエンドポイントです。/install/cronは、Cronジョブから週次更新をトリガーするためのエンドポイントで、管理者のみがアクセス可能です。
-
cron.yamlの追加:cron.yamlファイルが新規追加され、update rolling package install countsという説明を持つCronジョブが定義されました。このジョブは、毎日/install/cronURLを呼び出すようにスケジュールされており、これにより定期的にすべての外部パッケージの週次インストール数が更新されます。
これらの変更により、Goダッシュボードは外部パッケージのインストールイベントを捕捉し、その統計を効率的かつ信頼性高く記録・集計できるようになりました。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は以下のファイルと、その中の主要な構造体・関数です。
-
misc/dashboard/app/app.yaml:- url: /(|commit|install|packages|result|tag|todo) script: _go_app - url: /(init|buildtest|key|_ah/queue/go/delay|install/cron) script: _go_app login: admin新しいエンドポイント
/installと/install/cronが追加されています。 -
misc/dashboard/app/build/build.go:Package構造体へのフィールド追加と、インストール数管理のためのメソッド追加。type Package struct { Name string Path string // (empty for the main Go tree) NextNum int // Num of the next head Commit Installs int // All-time total install count InstallsByDay []string `datastore:",noindex"` // "yyyy-mm-dd,n" InstallsThisWeek int // Rolling weekly count } // IncrementInstalls increments the total install count and today's install count. // Daily install counts for dates older than 30 days are discarded. func (p *Package) IncrementInstalls() { ... } // UpdateInstallsThisWeek updates the package's InstallsThisWeek field using data // from the InstallsByDay list. func (p *Package) UpdateInstallsThisWeek() { ... } // dayCounts explodes InstallsByDay into a map of dates to install counts. func (p *Package) dayCounts() map[string]int { ... } -
misc/dashboard/app/build/pkg.go(新規ファイル): インストール処理とパス検証の主要ロジック。func init() { http.HandleFunc("/install", installHandler) http.HandleFunc("/install/cron", installCronHandler) } func installHandler(w http.ResponseWriter, r *http.Request) { ... } func installCronHandler(w http.ResponseWriter, r *http.Request) { ... } var ( installLater = delay.Func("install", install) updateWeeklyLater = delay.Func("updateWeekly", updateWeekly) ) func install(c appengine.Context, path string) { ... } func updateWeekly(c appengine.Context, key *datastore.Key) { ... } func validPath(c appengine.Context, path string) bool { ... } type vcsPath struct { ... } var vcsPaths = []*vcsPath{ ... } func googleCodeVCS(c appengine.Context, match map[string]string) bool { ... } func checkRoot(c appengine.Context, match map[string]string) bool { ... } func checkURL(c appengine.Context, u string) bool { ... } -
misc/dashboard/app/cron.yaml(新規ファイル):cron: - description: update rolling package install counts url: /install/cron schedule: every 24 hours
コアとなるコードの解説
misc/dashboard/app/build/build.go
Package構造体: 外部パッケージのメタデータに加えて、Installs(総インストール数)、InstallsByDay(日ごとのインストール数履歴)、InstallsThisWeek(週次インストール数) という3つの新しいフィールドが追加されました。InstallsByDayがdatastore:",noindex"とマークされているのは、このフィールドが頻繁に更新される可能性があり、Datastoreのインデックス更新コストを避けるためです。IncrementInstalls()メソッド: このメソッドは、特定のパッケージのインストールイベントが発生した際に呼び出されます。まず、InstallsByDayのデータを解析して日ごとのカウントを更新し、過去30日間のデータのみを保持するように古いデータを削除します。その後、総インストール数と週次インストール数を更新します。このロジックにより、日次および週次の統計が自動的に維持されます。UpdateInstallsThisWeek()メソッド:InstallsByDayのデータに基づいて、直近7日間のインストール数を集計し、InstallsThisWeekフィールドを更新します。これは、Cronジョブによって定期的に呼び出されることを想定しています。dayCounts()メソッド:InstallsByDayの文字列スライスを、日付をキー、インストール数を値とするマップに変換するユーティリティ関数です。これにより、日ごとのカウントへのアクセスと更新が容易になります。
misc/dashboard/app/build/pkg.go
このファイルは、外部パッケージのインストール数を処理するための新しいモジュールです。
init()関数とHTTPハンドラ:/installと/install/cronという2つのHTTPエンドポイントを登録しています。/installは、go toolがパッケージをインストールした際に呼び出すことを想定しており、特定のパッケージのインストール数をインクリメントするトリガーとなります。/install/cronは、App EngineのCronサービスによって定期的に呼び出され、すべての外部パッケージの週次インストール数を更新するトリガーとなります。
delay.Funcの利用:installLaterとupdateWeeklyLaterは、appengine/delayパッケージを使用して定義された遅延実行関数です。これにより、HTTPリクエストの処理中に時間のかかるDatastore操作や外部HTTPリリクエストを実行する代わりに、それらの処理をタスクキューにオフロードし、非同期で実行することができます。これにより、ユーザーへの応答性を高め、リクエストタイムアウトを防ぎます。install(c appengine.Context, path string)関数: 実際のインストール数インクリメント処理を実行します。validPath()を呼び出して、提供されたパッケージパスが有効であることを確認します。- Datastoreトランザクション内で、指定されたパスの
Packageエンティティを取得します。エンティティが存在しない場合は新しく作成します。 p.IncrementInstalls()を呼び出して、パッケージのインストール数を更新します。- 更新された
PackageエンティティをDatastoreに保存します。トランザクションを使用することで、データの一貫性を保証しています。
updateWeekly(c appengine.Context, key *datastore.Key)関数: 特定のパッケージの週次インストール数を更新します。これもDatastoreトランザクション内で実行され、p.UpdateInstallsThisWeek()を呼び出して週次カウントを更新し、Datastoreに保存します。validPath(c appengine.Context, path string) bool関数: この関数は、与えられたpathが有効なGoパッケージのインポートパスであるかを検証する重要な役割を担っています。vcsPathsリストをイテレートし、パスが既知のVCSホスティングサービス(Google Code, GitHub, Bitbucket, Launchpadなど)のパターンに一致するかを正規表現でチェックします。- パターンに一致した場合、そのVCSパス定義に
check関数が指定されていれば、そのcheck関数を呼び出します。 check関数(例:googleCodeVCS,checkRoot)は、appengine/urlfetchを使用して、実際にそのインポートパスに対応するリモートリポジトリが存在するかどうかをHTTPリクエストで検証します。これにより、単なる正規表現の一致だけでなく、実在するパッケージのみがカウントされるようにしています。
vcsPath構造体とvcsPaths変数: Goのcmd/go/vcs.goから派生したもので、Goのgo getコマンドがどのようにインポートパスを解析し、対応するVCSリポジトリを特定するかというロジックを反映しています。これにより、ダッシュボード側でもgo getと同様のパス検証が可能になります。googleCodeVCS,checkRoot,checkURL関数: これらはvalidPathから呼び出されるヘルパー関数で、それぞれGoogle Code、GitHub/Bitbucket、および一般的なURLの存在をHTTPリクエストで検証します。checkURLは、HTTPステータスコードが2xxであることを確認することで、リソースの存在を判断します。
misc/dashboard/app/app.yaml
- 新しいURLハンドラ
/installと/install/cronが追加されました。これにより、App EngineがこれらのパスへのリクエストをGoアプリケーションの適切なハンドラにルーティングできるようになります。/install/cronにはlogin: adminが設定されており、管理者のみがアクセスできることを示しています。
misc/dashboard/app/cron.yaml
- 新しいCronジョブが定義されました。このジョブは毎日実行され、
/install/cronエンドポイントを呼び出すことで、すべての外部パッケージの週次インストール数の更新処理をトリガーします。
これらのコード変更により、Goダッシュボードは外部パッケージの利用状況を自動的に追跡し、統計情報を収集・表示する機能を持つことになります。
関連リンク
- https://golang.org/cl/5699082 (Go Code Reviewの変更リスト)
参考にした情報源リンク
- Google App Engine Documentation (Datastore, Task Queues, Cron Service, URL Fetch API)
- Go Build Dashboard Source Code (既存の
misc/dashboardの構造と機能理解のため) - Go
cmd/go/vcs.goSource Code (vcsPathの理解のため) - Go言語の公式ドキュメント (Go言語の基本的な概念と
go getコマンドについて) - 正規表現の一般的な情報源
- https://cloud.google.com/appengine/docs/standard/go/datastore/reference/rest/v1/projects.databases.documents (Google Cloud Datastore)
- https://cloud.google.com/appengine/docs/standard/go/taskqueue/push/creating-tasks (App Engine Task Queues)
- https://cloud.google.com/appengine/docs/standard/go/scheduling-jobs-with-cron (App Engine Cron Service)
- https://cloud.google.com/appengine/docs/standard/go/issue-http-requests (App Engine URL Fetch API)