Repo Sync でストレージを節約するための Group 機能の使い方

背景

最近の AOSP は,対応するビルドホストもターゲットも増えたため,prebuilt バイナリの量が膨大になってきました.これが sync の時間を伸ばし,ビルドマシンのストレージを圧迫しています.

しかし,対応しないビルドホストやターゲットの prebuilt バイナリは,不要なわけです. 一部の Android 系プロジェクト (Android-x86 とか) では, manifest.xml を編集して,不要なプロジェクトを削除しています. しかし,ターゲットはさておき,ビルドホストは複数あったほうが開発者を増やすためには望ましいと言えます. また,AOSP の新しいリリースごとに manifest.xml の再編集を行うのは骨の折れる作業です.

このような状況を解消するために,repo には group という機能があります. 日本語のみならず,英語圏でも纏まって解説されている例は,ざっとググった限りでは無いようです.

manifest.xml

manifest.xml は,repo が引っ張ってくるプロジェクトの内容が記述されています. init の時に指定して,実体は {repo_root}/.repo/manifest.xml にあります. (細かいことを言うと,このファイルはシンボリックリンクですが,割愛します)

manifest.xml のプロジェクトには,こんな感じで groups という属性を付けられます.

1
2
  <project groups="pdk,darwin,mips" name="platform/prebuilts/gcc/darwin-x86/mips/mipsel-linux-android-4.8" path="prebuilts/gcc/darwin-x86/mips/mipsel-linux-android-4.8"/>
  <project groups="pdk,darwin,x86" name="platform/prebuilts/gcc/darwin-x86/x86/i686-linux-android-4.6" path="prebuilts/gcc/darwin-x86/x86/i686-linux-android-4.6"/>

この例は AOSP の manifest.xml から引用してきました.以降でも,この manifest.xml のコード片を引用します.

repo init の -g オプション

repo init には,あまり知られていないようですが,-g というオプションがあります. これは隠しオプションではありません. repo help init すると,解説がでてきます.

1
2
3
-g GROUP, --groups=GROUP
                    restrict manifest projects to ones with specified
                    group(s) [default|all|G1,G2,G3|G4,-G5,-G6]

このオプションの使い方が,本稿の核心です.

使い方は,判ってしまえば簡単です.-g には,引っ張ってきたいグループをカンマ区切りで指定します. ただし, 引っ張ってきたくないグループには – を接頭します

たとえば,私が Android-x86 の開発者であり,mips ターゲットの開発をする可能性が限りなく 0 だったとしましょう. その場合には,repo init を実行する際のグループ指定時に,mipsターゲットを無視する -mips を付加します.具体的には,-g 'default,-mips' とします.これだけです. このようなオプションで初期化された repo リポジトリでは,無効にされたプロジェクトは sync を行っても無視されるようになります. プロジェクト名を明示した sync を行おうとすると,下記のように例外が発生します.

1
2
3
4
5
6
7
8
9
10
11
12
13
$ repo sync platform/prebuilts/gcc/darwin-x86/mips/mipsel-linux-android-4.8
Traceback (most recent call last):
  File "/home/azureuser/repo/.repo/repo/main.py", line 418, in <module>
    _Main(sys.argv[1:])
  File "/home/azureuser/repo/.repo/repo/main.py", line 394, in _Main
    result = repo._Run(argv) or 0
  File "/home/azureuser/repo/.repo/repo/main.py", line 142, in _Run
    result = cmd.Execute(copts, cargs)
  File "/home/azureuser/repo/.repo/repo/subcmds/sync.py", line 606, in Execute
    submodules_ok=opt.fetch_submodules)
  File "/home/azureuser/repo/.repo/repo/command.py", line 180, in GetProjects
    raise InvalidProjectGroupsError(arg)
error.InvalidProjectGroupsError

AOSP のリポジトリは,いくつかの特殊な状況を除き,ビルドホストもターゲットも単一アーキテクチャでしょう.そんなときは,init 時のグループ指定をさらに厳密にできます. 例えば,Ubuntu Linux上で Android-x86 系のビルドをする際に,私が使っているグループ指定は, default,-arm,-mips,-darwin です.

応用

group 指定には,特殊なグループ all, default, notdefault などあります. これらを詳説すると,紙幅がいくらあっても足りませんので,本稿では割愛します. repo の実体は Python スクリプトなのでご自身で調べられるでしょうし,私自身も完全に理解できているわけではありませんので.

特殊なグループを除き,group には,お互いに衝突しない自由な名前を付けられます. Android 系以外のプロジェクトでも repo を使っているプロジェクトはあるようですが,そのようなプロジェクトでも group を活用することで,柔軟なプロジェクト運営が可能になるかもしれません.

注意事項

既に存在しているリポジトリに対して repo init を行う場合に -g オプションを指定すると,そのあとの sync から group 指定が有効になります. ただし,あとから無効にした場合,sync で pull はされてこなくなり,作業スペースからは削除されますが,ストレージ上には git リポジトリのクローンが残骸として残ります..repo/ 内のリポジトリを削除することでストレージの節約になりますが,バッドノウハウすぎるので,本稿では割愛します.変なことをしないで rm -fr .repo してから init し直すほうが無難です.

追伸

どなたか,repo の詳細を纏めて頂けないでしょうか.有償だとしても読みたいです. 知らない言語のコード読むの,疲れるのよ…