方案厂商给了一份 Android 源码,没有 manifest.git 文件,不支持 Repo。为了基于这份代码搭建支持 Repo 的镜像服务器,断断续续摸索了两个星期,总算 hacking 成功。

本文用到的主要知识:

  • shell script
  • git 指令

一、关于 Repo

基于 Android 源码的开发工作大多要用到 Git 和 Repo。

Repo 是基于 Git 的仓库管理工具,支持同时管理许多个 Git 仓库。因为 Android 源码包含了许多个 Git 仓库,使用 Repo 可以简化许多工作。比如,使用一个 Repo 命令,就可以从多个不同的仓库下载文件,同步到你的计算机上。

搭建支持 Repo 的 Android 源码镜像,主要步骤如下:

  1. 在服务器搭建 Git 托管服务器
  2. 在客户端安装配置好 Repo
  3. 在客户端创建 manifest/default.xml 并上传到 Git 服务器
  4. 将客户端 Android 源码上传到 Git 服务器
  5. 在其它获得 git 权限的客户端使用:Repo init; Repo sync

二、搭建 Git 服务器

搭建 Git 服务器这部分的内容相对独立,和 Repo 的关系不大,因此另外写了一篇文章:

在 ubuntu 搭建基于 Gitolite 的 Git 服务器

三、搭建 Repo 服务器的设备及要求

服务器 A:

  • IP 地址:192.168.1.101
  • 安装了 Gitolite
  • 将作为 Repo 服务器(这样称呼比较直观,但不知是否准备)

客户端 B:

  • IP 地址:192.168.1.102
  • 取得 A 的 Gitolite 的管理员身份(可以修改 gitolite-admin)
  • 存放了厂商给的 Android 源码 asop/,没有 manifest/default.xml 文件

以下的操作,除非有特别说明,都在客户端 B 执行。

四、安装 Repo

Repo 安装可以参考Installing Repo。主要步骤如下:

mkdir ~/bin
PATH=~/bin:$PATH
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo

因为特殊的国情。。。上述操作后 Repo 还是很难直接使用的。比如在 repo init 时,即使是科学上网,也无法连接上

REPO_URL = 'https://gerrit.googlesource.com/git-repo'

一个替代的方案是,使用清华的镜像。打开 ~/bin/repo,把里面的 REPO_URL 地址改为:

REPO_URL = https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/

这样就可以运行 repo 指令了。

五、认识 manifest/default.xml 文件

Android 源码里有上百个 git 项目,不同版本的源码项目各不相同,Repo 指令如何知道具体有哪些项目呢,答案就在 manifest/default.xml default.xml 记录了这些 git 项目的名称、路径等信息,通过它, Repo 就有迹可循。

了解 manifest/default.xml 最好的办法,就是从零搭建一个 Repo 服务器。

随便找台 Linux 操作系统的计算机,新建一个目录模拟 Repo 服务器:

mkdir /tmp/repo-server
cd /tmp/repo-server

/tmp/repo-server 目录创建若干个 git 仓库:

#创建 git 仓库 project_1
mkdir project_1 && cd project_1
git init;
touch p1.txt;
git add .;
git commit –m "initial commit"

cd..

#创建一个 git 仓库 project_2
mkdir project_2 && cd project_2
git init;
touch p2.txt;
git add .;
git commit –m "initial commit"

/tmp/repo-server 创建 manifest 仓库:

#创建 manifest 仓库
mkdir manifest && cd manifest
git init;
touch default.xml;

default.xml 加入以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote  name="test"
           fetch="." />
  <default revision="master"
           remote="test"
           sync-j="4" />
  <project path="project_1" name="project_1" />
  <project path="project_2" name="project_2" />
</manifest>

然后 commit 代码

git add .;
git commit –m "initial manifest"

这样,模拟 Repo 服务器就搭建完成了。

接着再建一个新的目录/tmp/repo-client/,模拟 Repo 客户端。在客户端目录里:

repo init –u /tmp/repo-server/manifest

如果一切正常,将会收到成功提示信息。这时候去查看该目录下的 .repo,就会发现有一个 manifest.xml,内容是克隆服务器的 default.xml 文件。

最后,使用 Repo 指令将多个 git 项目的代码一次性同步到客户端上:

repo sync

仔细揣摩 default.xml 文件的内容,你应该能理解这个 xml 文件的作用。

注意:以上试验,我在 centOS 测试成功,在 macOS 测试时,执行 repo init -u $LOCAL_ADDRESS 会报错,会要求最后一个参数是 url

六、从源码 aosp/ 找出所有 git 仓库

从厂商得到的 Android 源码 aosp/ 目录大致如下,

aosp
|- art
|- /abi
  |- cpp
|- /developers
  |- build
  |- demos
  |- samples
    |- /android
...

因为厂商不用 Repo 管理,所以源码里也没有 manifest/default.xml 文件。

幸好,仔细查看 aosp/ 之后发现,里面有些目录下有 .git/ 目录,说明它就是一个 git 项目。因此可以通过找出所有带 .git/ 目录的目录,来确定 aosp/ 有哪些 git 项目。代码如下:

find aosp/ -type d -name '.git' > git_projects.txt`

最终在这份 aosp/ 共找到 531 个 git 项目。

七、创建 default.xml 文件

得到 git_projects.txt 后,就可以据此创建 default.xml 文件。

git_projects.txt 每一行的内容是这样的:

aosp/prebuilts/devtools/.git

使用 bash 指令去掉最后开头的 aosp/ 和末尾的 /.git

cat git_projects.txt | cut -c 6- | sed 's/.....$//' > path.txt

得到每一行内容的格式如下:

prebuilts/devtools

生成 xml 文件的脚本 gen_xml.sh :

#!/bin/bash

echo -e "
<?xml hhhversion=\"1.0\" encoding=\"UTF-8\"?>
<manifest>
  <remote  name=\"aosp\"
           fetch=\".\"/>
  <default revision=\"master\"
           remote=\"aosp\"
           sync-j=\"4\" />" >>$1

while read line; do
	echo "<project path=\"$line\" name=\"$line\" />" >>$1
done
echo -e "\n</manifest>" >>$1

bash 指令创建 default.xml

cat path.txt | ./gen_xml.sh default.xml

得到的 default.xml 里,<project /> 示例如下:

<project path="prebuilts/devtools" name="prebuilts/devtools" />

八、在 Gitolite 初始化所有 asop/ 的 git 仓库

前提:客户端 B 可以修改服务器 A 的 gitolite-admin 项目,即管理 Gitolite 的项目

这里还要用到 git_projects.txt 文件。这次只要去掉每行末尾的 /.git

cat git_projects.txt | sed 's/.....$//'  > repo_path.txt

得到的每一行的格式如下:

aosp/prebuilts/devtools

编写 gen_server_repo.sh

#!/bin/bash

# 声明群组 @aosp_dev , 成员: jack, tom
@aosp_dev    =    jack tom

# 加上 manifest 仓库
echo -e "
repo aosp/manifest\n
     RW+    =    @aosp_dev\n" >>$1

while read line; do
	echo -e "repo $line \n     RW+    =    @aosp_dev\n" >>$1
done

bash 指令生成 aosp.conf 文件:

cat repo_path | ./gen_server_repo.sh  aosp.conf

gitolite-admin/conf/gitolite.conf 开头加入:

include "aosp.conf"

把更新的内容 push 到服务器 A ,gitolite 就会在相应目录(通常是 /home/git/repositories )初始化所有 aosp 的所有 git 仓库。

至此,aosp 的所有仓库已经在服务器 A 生成了,下一步就是把 aosp 的源码上传到服务器。

九、上传 manifest/default.xml 到服务器

把之前创建好 default.xml 文件上传到服务器的 aosp/manifest 仓库:

git clone git@192.168.1.101:aosp/manifest
cd manifest
#
# 把default.xml 文件放到 manifest/ 目录
#
git add .
git commit -m 'add default.xml'
git push

十、上传 aosp/ 源码到服务器

上传源码的 shell 脚本 push_aosp.sh:

#!/bin/bash

work_dir=$1

pwd=${PWD}
count=0

while read line; do
    echo $line
    count=$((count+1))
    line1=${line%%/*}
    if [ -z "$line" ]; then
        echo $work_dir not exist !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 1>&2
        continue
    fi
    if [ $(ls -A $pwd/$line | wc -l) -eq 0 ]; then
        echo $work_dir empty !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 1>&2
        continue
    fi
    workdir=$pwd/$line
    cd $workdir
        rm -rf .git
        git init .  1>&2
        git add . -f 1>&2
        { git commit -m "Initial commit" &&
            git push -f --set-upstream git@192.168.1.101:$line.git master
        } || {
            touch empty_file
            git add .
            git commit -m "添加一个空文件,消灭空仓库"
            git push -f --set-upstream git@192.168.1.101:$line.git master
            echo number:$count should be empty $line >> $HOME/log_$(date +%Y_%m_%d)
        }
	echo -e "number:$count \n"
    cd -
done

注意 push_aosp.sh 里的这段脚本:

{ git commit -m "Initial commit" &&
    git push -f --set-upstream git@192.168.1.101:$line.git master
} || {
    touch empty_file
    git add .
    git commit -m "添加一个空文件,消灭空仓库"
    git push -f --set-upstream git@192.168.1.101:$line.git master
    echo number:$count should be empty $line >> $HOME/log_$(date +%Y_%m_%d)
}

这其实是个变通办法。因为之前试过忽略空仓库,不做 push 。但代码上传到服务器后,客户端使用 repo sync 下载时,会出现 error: Exited sync due to fetch errors 错误,导致同步失败。

所以只好消灭所有空仓库。

这里还把所有加工过的空仓库记录到 $HOME/log_$(date +%Y_%m_%d) 文件里,作为备忘。

最后,把 repo_path.txtpush_aosp.sh 放在和源码 aosp/ 同一个目录里,然后执行:

cat repo_path.txt | ./push_aosp.sh

在我的例子里,源码大小有 22G ,上传花了 2 个多小时。

十一、其它客户端使用 Repo 服务器

源码成功上传到服务器 A 之后,其它客户端就可以下载使用了。假设客户端计算机 C 要使用,流程如下:

  1. C 先获得服务器 A 上的相关 repo 的权限,具体参考在 ubuntu 搭建基于 Gitolite 的 Git 服务器
  2. 安装 Repo ,具体参考上文第二节“安装 Repo”
  3. repo init -u git@192.168.1.101:aosp/manifest
  4. repo sync

 

转载https://blog.csdn.net/xiezhi123456/article/details/80030593

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐