Android repo 魔法

來源:互聯網
上載者:User
文章目錄
  • Shell script or python?
  • Bootstrap 和真正的 repo
  • Repo bootstrap 指令碼調用 init 只完成第一階段的初始化
  • 第二階段的 repo init
  • Related Posts

本文轉載自:http://www.worldhello.net/2010/08/31/1915.html

本文是repo的進階說明,講述repo的實現原理,一般可以不用理會。

Android repo 魔法Android 為企業提供一個新的市場,無論大企業,小企業都是處於同一個起跑線上。研究 Android 尤其是 Android 系統核心或者是驅動的開發,首先需要做的就是本地複製建立一套 Android 版本庫管理機制。Android 使用 Git 作為代碼管理工具,開發了 Gerrit 進行代碼審核以便更好的對代碼進行集中式管理,還開發了 Repo 命令列工具,對 Git 部分命令封裝,將 百多個 Git 庫有效進行組織。要想複製和管理這百多個 Git 庫,還真不是一件簡單的事情。在研究
Repo 的過程中,發現很多文檔在 Google Group 上,非“翻牆”不可看。非法的事情咱不幹,直接閱讀 repo 的代碼吧。

建立本地 Android 版本庫鏡像的思路

如果瞭解了 Repo 的實現,參考 《Using Repo and Git》 , 建立一個本地的 android 版本庫鏡像還是不難的:

  • 下載 repo bootstrap 指令碼

    $ curl http://android.git.kernel.org/repo >~/bin/repo$ chmod a+x ~/bin/repo$ export PATH=$PATH:~/bin
  • 提供 --mirror 參數調用 repo init ,建立 git 版本庫複製
    $ repo init -u git://android.git.kernel.org/platform/manifest.git --mirror
    • 使用 --morror 則下一步和源同步的時候,本地按照源的版本庫組織方式進行組織,否則會按照 manifest.xml 指定的方式重新組織並檢出到本地
  • 開始和源同步
    $ repo sync
  • 修改 manifest ,修改 git 庫地址,指向本地的 git 伺服器
    • 修改 platform/manifest.git 庫中現有的 xml 檔案,或者建立一個新的 xml 檔案
    • 將 git 的地址改為本地地址,提交並 push
  • 本地 repo 鏡像建立完畢之後,就可以在執行 repo init 時,使用本地更改後的 manifest 庫,之後執行 repo sync 就是基於本地版本庫進行同步了。
  • 也可以改造 repo,使得不必為 repo 工具初始化,也在本網完成操作...
Repo init 幹了些什嗎?

實際上,得到客戶使用 repo 的資訊後,首先下載 repo 執行指令碼開始研究。

curl http://android.git.kernel.org/repo >~/bin/repo

難道只有 600 行的 python 代碼嗎?要是這樣應該很簡單的呀。可以看下來,卻發現遠非如此。

Shell script or python?

首先 repo 指令碼使用了一個魔法:從指令碼第一行的 shebang 來看應該是 shell 指令碼,但是滿眼卻都是 python 文法,怎麼回事?

 1 #!/bin/sh 2 3 ## repo default configuration 4 ## 5 REPO_URL='git://android.git.kernel.org/tools/repo.git' 6 REPO_REV='stable' 7 8 # Copyright (C) 2008 Google Inc.   ...22 magic='--calling-python-from-/bin/sh--'23 """exec" python -E "$0" "$@" """#$magic"24 if __name__ == '__main__':25   import sys26   if sys.argv[-1] == '#%s' % magic:27     del sys.argv[-1]28 del magic

魔法就在第 23 行,巧妙的通過 python 三引號字串寫出了一個能被 python 和 shell script 都能理解的代碼,以此為界,代碼由 Shell 指令碼進入了 Python 的世界。

Bootstrap 和真正的 repo

通過 curl 下載的的 repo 並非完整的 repo 指令碼,只是一個 bootstrap。當 repo 執行時,會負責下載完整的 repo 代碼,並將控制權轉移給真正的 repo。通過 main 函數,可以看到 repo 啟動並執行開始,就試圖發現本地真正的完整的 repo 代碼,以便移交控制權:

544 def main(orig_args):545   main, dir = _FindRepo()586   try:587     os.execv(main, me)

其中 545 行的 _FindRepo() 會在目前的目錄開始向上遞迴尋找 ".repo/repo/main.py",如果找到則移交控制權(587行)。

Repo bootstrap 指令碼調用 init 只完成第一階段的初始化

Repo 的 bootstrap 指令碼只支援兩個命令 help 和 init,而 init 也只完成 repo 版本庫複製(即安裝 repo 完整工具),之後就轉移控制權。在 Repo bootstrap 執行 init 可以提供很多參數,但實際上第一階段初始化,只用到兩個參數(而且都有預設值)

  • 參數:--repo-url=URLrepo 工具本身的 git 庫地址。預設為:git://android.git.kernel.org/tools/repo.git
  • 參數:--repo-branch=REVISION使用 repo 的版本庫,即 repo git 庫的分支或者裡程碑名稱。預設為 stable
第二階段的 repo init

執行第二階段的 repo init,控制權已經移交給剛剛複製出來的 repo git 庫的指令碼。Repo git 庫被複製/檢出到執行 repo init 命令目前的目錄下的 .repo/repo 子目錄中,主要的執行指令碼為 .repo/repo/main.py。main.py 接著執行 repo init 命令。Repo 的程式碼群組織的非常好,在 .repo/repo/subcmds/ 子目錄下,是各個 repo 命令的處理指令碼。repo init 的第二階段指令碼正是由 .repo/repo/subcmds/init.py
負責執行的。第二階段主要完成:

  • 複製由 -u 參數提供的 manifest Git 庫,如複製 android 庫時:

    $ repo init -u git://android.git.kernel.org/platform/manifest.git
  • 如果不提供 -b REVISION 或者 --manifest-branch=REVISION參數,則檢出 manifest Git 庫的 master 分支
  • 如果不提供 -m NAME.xml 或者 --manifest-name=NAME.xml 參數,則使用預設值 default.xml
  • 如果提供 --mirror 參數,則後續同步操作會有相應的體現
Repo start 幹了些什嗎?

Android 源碼網站在介紹 repo 的使用模型中,有一個圖片: http://source.android.com/images/git-repo-1.png , 介紹了 repo 的使用流程。其中 "repo start" 是緊接著 "repo sync" 後的第一個動作。那麼這個動作是幹什麼的呢?得益於 repo 對 git 操作的封裝,"repo start" 命令的處理代碼只有區區 68 行。

 37   def Execute(self, opt, args): 41     nb = args[0] 47     projects = [] 48     if not opt.all: 49       projects = args[1:] 54     all = self.GetProjects(projects) 57     for project in all: 59       if not project.StartBranch(nb): 60         err.append(project)

看到第 59 行了麼,就是對 repo 同步下來的項目的多個 Git 版本庫,逐一執行 project.StartBranch 操作。 nb 是 repo start 的第一個參數,即分支名稱。關於 StartBranch 的代碼,在 project.py 中:

 857   def StartBranch(self, name): 858     """Create a new branch off the manifest's revision. 859     """ 894     if GitCommand(self, 895                   ['checkout', '-b', branch.name, revid], 896                   capture_stdout = True, 897                   capture_stderr = True).Wait() == 0: 898       branch.Save() 899       return True

原來如此, repo start <branch_name> 就是逐一為各個版本庫建立工作分支,以便在此分支下進行工作。讀者可以按圖索驥,找到 repo 各個命令的實現,破解心中的疑惑。

Related Posts
Git中文本地化 28 Feb 2012 1 Comment 和 5 Reactions
Gitolite 管理員自訂命令 30 Nov 2011 4 Comments 和 0 Reactions
Gitolite 萬用字元版本庫自訂授權 30 Nov 2011 0 Comments 和 0 Reactions

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.