[インデックス 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/cron
URLを呼び出すようにスケジュールされており、これにより定期的にすべての外部パッケージの週次インストール数が更新されます。
これらの変更により、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.go
Source 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)