25.6 建立Android代码库本地镜像

Android为企业提供一个新的市场,无论企业大小都处于同一个起跑线上。研究Android尤其是Android系统核心或驱动的开发,首先要做的就是通过本地克隆建立一套Android版本库管理机制。因为Android的代码库是那么庞杂,如果一个开发团队每个人都去执行repo init-u,再执行repo sync从Android服务器克隆版本库的话,多大的网络带宽恐怕都不够用。唯一的办法是在本地建立一个Android版本库的镜像。

建立本地镜像非常简单,就是在执行repo init-u初始化的时候,附带上—mirror参数。


$mkdir android-mirror-dir

$cd android-mirror-dir

$repo init—mirror-u git://android.git.kernel.org/platform/manifest.git


之后执行repo sync就可以从安装Android的Git服务器方式来组织版本库,创建一个Android版本库镜像了。

实际上附带了—mirror参数执行repo init-u命令,会在克隆的.repo/manifests.git下的config中记录配置信息:


[repo]

mirror=true


1.从Android的工作区到代码库镜像

在初始化repo工作区时,使用不带—mirror参数的repo init-u,并完成代码同步后,如果再次执行repo init并附带了—mirror参数,repo会报错退出:"fatal:—mirror not supported on existing client"。实际上—mirror参数只能对尚未初始化的repo工作区执行。

那么如果之前没有用镜像的方法同步Android版本库,难道要为创建代码库镜像再重新执行一次repo同步吗?要知道重新同步一份Android版本库是非常慢的。我就遇到了这个问题。

不过既然有manifest.xml文件,完全可以对工作区进行反向操作,将工作区转换为镜像服务器的结构。下面就是一个示例脚本,可以从本书在Github上的相关版本库[1]下载。这个脚本利用了已有的repo代码进行实现,所以看着很简洁。8-)

脚本work2mirror.py如下:


!/usr/bin/python

--coding:utf-8--

import os,sys,shutil

cwd=os.path.abspath(os.path.dirname(file))

repodir=os.path.join(cwd,'.repo')

S_repo='repo'

TRASHDIR='old_work_tree'

if not os.path.exists(os.path.join(repodir,S_repo)):

print>>sys.stderr,"Must run under repo work_dir root."

sys.exit(1)

sys.path.insert(0,os.path.join(repodir,S_repo))

from manifest_xml import XmlManifest

manifest=XmlManifest(repodir)

if manifest.IsMirror:

print>>sys.stderr,"Already mirror,exit."

sys.exit(1)

trash=os.path.join(cwd,TRASHDIR)

for project in manifest.projects.itervalues():

将旧的版本库路径移动到镜像模式下新的版本库路径

newgitdir=os.path.join(cwd,'%s.git' %project.name)

if os.path.exists(project.gitdir)and project.gitdir!=newgitdir:

if not os.path.exists(os.path.dirname(newgitdir)):

os.makedirs(os.path.dirname(newgitdir))

print "Rename%s to%s." %(project.gitdir,newgitdir)

os.rename(project.gitdir,newgitdir)

将工作区移动到待删除目录

if project.worktree and os.path.exists(project.worktree):

newworktree=os.path.join(trash,project.relpath)

if not os.path.exists(os.path.dirname(newworktree)):

os.makedirs(os.path.dirname(newworktree))

print "Move old worktree%s to%s." %(project.worktree,newworktree)

os.rename(project.worktree,newworktree)

if os.path.exists(os.path.join(newgitdir,'config')):

修改版本库的配置

os.chdir(newgitdir)

os.system("git config core.bare true")

os.system("git config remote.korg.fetch '+refs/heads/:refs/heads/' ")

删除remotes分支,因为作为版本库镜像不需要remote分支

if os.path.exists(os.path.join(newgitdir,'refs','remotes')):

print "Delete" +os.path.join(newgitdir,'refs','remotes')

shutil.rmtree(os.path.join(newgitdir,'refs','remotes'))

设置menifest为镜像

mp=manifest.manifestProject

mp.config.SetString('repo.mirror','true')


使用方法很简单,只要将脚本放在Android工作区下执行就可以了。执行完毕会将原有工作区的目录移动到old_work_tree子目录下,在确认原有工作区没有未提交的数据后,直接删除old_work_tree即可。


$python work2mirror.py


2.创建新的清单库,或者修改原有清单库

建立了Android代码库的本地镜像后,如果不对manifest清单版本库进行定制,在使用repo sync同步代码的时候,仍然使用Android官方的代码库同步代码,就会使得本地的镜像版本库形同虚设。解决办法是创建一个自己的manifest库,或者在原有清单库中建立一个分支加以修改。如果创建新的清单库,参考Android上游的manifest清单库进行创建。

[1]https://github.com/ossxp-com/gotgit/raw/master/download/ch25/work2mirror.py