Searching code with Sourcegraph

Ben Hoyt

Sourcegraphでコードを検索する

原文は Ben Hoyt により に公開されました。 このブログを購読する

Sourcegraphは、大規模なコードベースを検索し、探索するためのツールだ。このツールには正規表現検索をはじめ、言語を意識した比較的新しい手法である「structural search(構造的検索)」など、さまざまな検索手法が用意されている。ツールのオープンソースのコアには、コード検索や定義へのジャンプなどの「code intelligence(コードインテリジェンス)」機能が備わっており、開発者が複数のリポジトリにまたがるコードベースを理解する助けとなる。Sourcegraphのコード検索ツールは、マウスオーバーで関数やメソッドのドキュメントを表示したり、定義へ素早くジャンプしたり、特定の識別子への参照をすべて見つけたりすることを可能にする。

Sourcegraphサーバーは主にGoで書かれており、コア部分はApache License 2.0で公開されている。さまざまな「enterprise(エンタープライズ)」向け拡張機能はプロプライエタリなライセンスで提供される。Sourcegraphを開発する企業は毎月新バージョンをリリースしており、最新リリース(3.18)ではC++サポートが改善され、3.17リリースではより高速で正確なコード検索やANDおよびOR検索演算子のサポートが追加された。

コード検索

Sourcegraphの主要な機能は、1つまたは複数のリポジトリを横断してコードを検索できることだ。数百のリポジトリを検索する場合でも、結果は通常1〜2秒で返ってくる。デフォルトのクエリ形式はリテラル検索で、"foo bar"のような検索文字列に引用符まで含めて完全一致する。検索バーの右側にある.*アイコンをクリックすると正規表現検索に切り替わり、どちらの検索モードでも(Aaアイコンをクリックすることで)大文字と小文字を区別する検索が可能だ。

[Sourcegraphの検索]

[]アイコンは「structural search(構造的検索)」に切り替えるためのもので、Sourcegraphに勤めるRijnard van Tonderが自身のCombyプロジェクト向けに作成した検索構文だ。構造的検索は言語を意識しており、ネストした式や複数行にわたる文を正規表現よりも適切に扱うことができる。構造的検索のクエリは、潜在的なバグやコードの簡素化が可能な箇所を見つけるためによく使われる。例えば、次のようなクエリがある。

    fmt.Sprintf(":[str]")

これは、単一の引数が単なる文字列リテラルである場合に、fmt.Sprintf()の呼び出しを削除できる箇所を見つけるものだ。

ドキュメントには、Sourcegraphのインストール環境が実行するさまざまなプロセスを示すアーキテクチャ図が掲載されている。また、「検索クエリのライフサイクル」についてより詳細に説明した資料もある。フロントエンドはまず、クエリ内のrepo:フィルタを探して、どのリポジトリを検索すべきかを判断する。サーバーはリポジトリのリストを、他のほとんどのSourcegraphのメタデータとともにPostgreSQLデータベースに保存しており、Gitリポジトリは通常どおりクローンされてファイルシステムに保存される。

次にサーバーは、(検索クエリで特定のリビジョンが指定されている場合はそのリビジョンについて)どのリポジトリがインデックス化されているか、されていないかを判断する。リポジトリのインデックス化と、インデックスを用いた検索のいずれも、Goで書かれたトライグラムベースのコード検索ライブラリであるzoektによって処理される。(トライグラムを使ったコード検索に興味がある人は、GoのテックリードであるRuss Coxによる記事が参考になるだろう。)

インデックス化されていないリポジトリのリビジョンは、別の「searcher」プロセスによって処理される(このプロセスはKubernetes経由で水平スケーラブルだ)。このプロセスはSourcegraphサーバー(すなわちgitserver)からリポジトリのzipアーカイブを取得し、その中のファイルを順に走査して、正規表現検索の場合はGoのregexpパッケージ、構造的検索の場合はCombyライブラリを使ってマッチングを行う。デフォルトではリポジトリのデフォルトブランチのみがインデックス化されるが、Sourcegraph 3.18ではデフォルト以外のブランチをインデックス化する機能が追加された

コードインテリジェンス

Sourcegraphの2つ目の主な機能は、同社が「code intelligence(コードインテリジェンス)」と呼ぶものだ。カーソル位置にある変数や関数の定義へ移動したり、その参照をすべて見つけたりする機能である。デフォルトでは、これらの機能は「コードをAST[抽象構文木]にパースするのではなく、検索ベースのヒューリスティクス」を用いているが、私が試した限りではヒューリスティクスの精度はかなり高いようだ。このツールはC、Python、Goの定義を問題なく見つけ、Pythonでは動的に割り当てられた定義さえも見つけることができた(例えば、私のscandirプロジェクトにおいて、代入や再代入されたscandir_pythonという名前の定義へジャンプできた)。

より最近では、SourcegraphはMicrosoftのLanguage Server Index Format(LSIF)を用いて、より高精度なコード検索機能(検索ヒューリスティクスではなく言語固有の構文木を利用するもの)を実装した。LSIFは、言語ツールのためにインデクサが抽出したデータを保存するために使われるJSONベースのファイル形式だ。Sourcegraphは、複数の言語向けのLSIFインデクサを作成または保守しており、GoC/C++Python(いずれもMITライセンス)が含まれる。現在、SourcegraphにおけるLSIFサポートはオプトインであり、ドキュメントによれば「高速かつ高精度なコードインテリジェンスを提供するが、定期的に生成してSourcegraphインスタンスにアップロードする必要がある」とされている。Sourcegraphの推奨はコミットごとにLSIFデータを生成してアップロードすることだが、開発者は頻度を落として定期的にインデックスを作成するジョブを設定することもできる。

コードインテリジェンスのクエリは3つのタイプに分けられる。ホバークエリ(シンボルに関連付けられたドキュメントを取得して「ホバーテキスト」として表示するもの)、定義へのジャンプのクエリ、参照検索のクエリである。利用可能な場合は高精度なLSIF情報が使われ、そうでない場合はSourcegraphはCtagsと検索を組み合わせた「ファジーな」結果を返すようにフォールバックする。

オープンソース?

Sourcegraphのライセンス形態はオープンコアだが、その提供方法はやや異例だ。プロプライエタリなコードを含むすべてのソースが単一のパブリックリポジトリに置かれているが、enterprise/およびweb/src/enterprise/ディレクトリ配下のコードはSourcegraph Enterprise licenseの対象となり、それ以外のコードはApacheライセンスの下で提供される。Sourcegraphが提供するビルド済みのDockerイメージには、「Sourcegraph Enterpriseへのスムーズなアップグレードパスを提供するため」にエンタープライズコードが含まれているが、リポジトリには完全にオープンソースのイメージをビルドするビルドスクリプトも用意されている。エンタープライズコードには10人を超えるユーザーを許可しないチェックが含まれているが、オープンソースビルドにはそれは含まれない。全体として、オープンソース版のビルドとインストールはあまり文書化されておらず、セットアップスクリプトもいくつかの手順が欠けている可能性がある — 明らかに二級市民扱いだと感じられる。

Sourcegraph社(企業)は、誰でもさまざまなコードホスティングサービス上の「トップ」パブリックリポジトリを検索できるホスト版のシステムを運営している。このホスト版で「トップ」がどのように定義されているのか、あるいは正確にどのリポジトリがインデックス化されているのかは不明だが、利用可能な機能を示す良いデモとなっている。同社の料金ページには、エンタープライズ版に限定される機能が列挙されており、Campaignsという複数リポジトリにまたがるリファクタリングツール、複数のコードホストのサポート、カスタムブランディング、ライブトレーニングセッションなどが含まれる。

セットアップ

インストール手順のドキュメントに示されているとおり、docker-compose方式を使えばビルド済みのSourcegraphイメージのインストールは迅速だった。起動して実行できるようになるまで数分かかり、設定にもさらに数分かかった。私はローカルマシンで実行していたため、https対応のインターネット公開ドメインを(一時的に)提供するためにngrokトンネルを使用した(実行自体にこれは必須ではないが、提供しておくと一部の機能がより適切に動作する)。さらに手軽なワンコマンドでのDockerインストール方法も問題なく動作したが、こちらは小中規模の本番デプロイにも推奨されており単なるローカルテスト用ではないため、やや現実的に思えるdocker-compose方式を試すことにした。より大規模で高可用性が求められるデプロイについては、SourcegraphはKubernetesクラスタへのデプロイを推奨している。

セットアップに必要な設定はほとんどなかった。管理者ユーザーの作成と、システムをコードホストに向けることだけだ(私の場合は、SourcegraphがGitHub上のパブリックおよびプライベートリポジトリにアクセスできるようにGitHubのアクセストークンを作成する必要があった)。アクセストークンを追加するとすぐに、Sourcegraphはリポジトリのクローンとインデックス作成を開始した。数分後には検索可能な状態になった。このシステムはセルフホスティング向けに最適化されている。おそらく同社は、少数のテストユーザー向けに開発者が簡単にセットアップできるようにし(そして10ユーザーを超えたら課金を求めるように)したいのだろう。

人によっては躊躇するかもしれない「機能」の一つに、Sourcegraphが「pings」と呼ぶものがある。デフォルトでは、このツールは「製品チームとカスタマーチームを支援するため」に、約30分ごとにhttps://sourcegraph.com/.api/updates.comPOSTリクエストを送信する。この「重要なテレメトリ」には「サイトを最初にインストールした人のメールアドレス」や「既存のユーザーアカウントの総数」が含まれており、おそらく10ユーザーの閾値に達した際に企業側がインストーラーに連絡してエンタープライズ版の支払いを促すためのものだ。これを無効にするにはソースコードを修正するしかない(pingのコードはオープンソースのコア部分にあるため、この行をコメントアウトすれば無効にできる)。デフォルトでは、システムは一部の製品機能について集計された利用情報も送信するが、これはDisableNonCriticalTelemetry設定変数を設定することでオフにできる。Sourcegraphの名誉のために言えば、同社は「pingの理念」について率直に説明しており、ソースコードやファイル名、具体的な検索クエリを送信することは決してないと明言している。

ブラウザおよびエディタとの統合

検索サーバーとウェブUIに加えて、SourcegraphはGitHubやGitLabなどのホストを閲覧する際にその機能を利用できるようにするChromeおよびFirefox向けのブラウザ拡張機能を提供している。例えば、GitHubでプルリクエストをレビューする際に、Sourcegraph拡張機能をインストールした開発者は、定義へ素早くジャンプしたり、すべての参照を見つけたり、特定のインターフェースの実装を確認したりできる。2019年6月時点でGitHubにも同様の機能があり、独自のsemanticライブラリを使用しているが、Sourcegraphのブラウザ拡張機能の方がより高機能に見える(例えば、関数やメソッドだけでなく構造体のフィールドも見つけることができる)。Sourcegraphのブラウザ拡張機能は、可能な限り開発者をgithub.comに留めようとするが、一部のリンクや定義についてはSourcegraphインスタンスのURLに遷移する。

Sourcegraphはまた、4つの人気エディタ(Visual Studio Code、Atom、IntelliJ、Sublime Text)向けにエディタ統合も提供している。これらのプラグインにより、開発者は現在のファイルをSourcegraphで開いたり、選択したテキストをSourcegraphで検索したりできる(プラグインは結果をブラウザで開く)。ブラウザ拡張機能とエディタプラグインは、Sourcegraphの原則の1つである「最終的には、開発者が使うすべてのツールをつなぐプラットフォームになりたい」という考えに合致している。

まとめ

Sourcegraphの開発自体もかなりオープンで、今後の3.19および3.20リリースに向けたトラッキング用のissueや、作成途中のロードマップが公開されている。「OpenGrokとの同等性」をはじめとする、コア(検索とコードインテリジェンス)に対する多くの改善が計画されていることに加え、同社はクラウド提供の強化やCampaigns機能の大幅な改善にも取り組んでいるようだ。

Sourcegraphは、特に大規模なコードベースや大きな開発チームにとって有用な、よく設計されたシステムのようだ。実際、ドキュメントではこのツールが小規模なチームには適さない可能性が示唆されている。「Sourcegraphは、より大きなコードベースやチーム(15人以上の開発者)で作業する開発者にとってより有用である」。サポートが不十分なオープンソースビルドや、外部へ連絡する「pings」に抵抗を感じる人もいるかもしれない。しかし、一部の人々はオープンソース版を使い続け、動作させることに成功しているようだ。

この記事は「muse-spark-1.2-contributor」を使用して翻訳されました。

コメント