第二章追加内容repo上传源码

This commit is contained in:
dqzg12300 2023-02-19 13:28:46 +08:00
parent e1891e02c9
commit d3ae77fbb5
2 changed files with 484 additions and 2 deletions

View File

@ -635,7 +635,489 @@ add_subdirectory(frameworks/native)
配置好cmake文件后使用clion打开项目选择刚刚配置好的`CMakeLists.txt`文件的目录`out/development/ide/clion/`。导入成功后,我们需要修改工程的根目录,`Tools->Cmake->Change Project Root`,然后选择源码根目录即可。
## 2.9 小结
## 2.9 git管理
TODO
虽然我们将源码导入idea中后已经可以正常的开始修改源码了。但是由于这是一个庞大的项目所以我们需要考虑到源码的管理便于我们随时能够查看自己的修改和切换不同的分支进行开发。否则这样一个巨大的项目一个月后再想要找齐当时修改的逻辑就非常困难了。如果你是个人开发并且修改的逻辑不是特别复杂或者是刚开始学习那么可以选择跳过这个部分直接修改源码即可。
首先我们需要对repo进行一定的了解在前文中有简单的介绍到repo是python脚本实现的并且实际是对git命令的封装用来管理大型项目关联多个子项目的。现在我们重新回顾一下下载android代码的过程。前文中我们使用repo进行初始化指定分支在完成初始化后会在当前目录生成一个.repo的目录首先我们查看目录中的manifest.xml文件内容如下。
~~~
<?xml version="1.0" encoding="UTF-8"?>
<!--
DO NOT EDIT THIS FILE! It is generated by repo and changes will be discarded.
If you want to use a different manifest, use `repo init -m <file>` instead.
If you want to customize your checkout by overriding manifest settings, use
the local_manifests/ directory instead.
For more information on repo manifests, check out:
https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
-->
<manifest>
<include name="default.xml" />
</manifest>
~~~
可以看到只是导入了default.xml文件。接着我们查看这个配置文件。
~~~
<manifest>
<remote name="aosp"
fetch=".."
review="https://android-review.googlesource.com/" />
<default revision="refs/tags/android-12.0.0_r3"
remote="aosp"
sync-j="4" />
<superproject name="platform/superproject" remote="aosp" revision="android-12.0.0_r3" />
<contactinfo bugurl="go/repo-bug" />
<project path="build/make" name="platform/build" groups="pdk" >
<copyfile src="core/root.mk" dest="Makefile" />
<linkfile src="CleanSpec.mk" dest="build/CleanSpec.mk" />
<linkfile src="buildspec.mk.default" dest="build/buildspec.mk.default" />
<linkfile src="core" dest="build/core" />
<linkfile src="envsetup.sh" dest="build/envsetup.sh" />
<linkfile src="target" dest="build/target" />
<linkfile src="tools" dest="build/tools" />
</project>
<project path="build/bazel" name="platform/build/bazel" groups="pdk" >
<linkfile src="bazel.WORKSPACE" dest="WORKSPACE" />
<linkfile src="bazel.sh" dest="tools/bazel" />
<linkfile src="bazel.BUILD" dest="BUILD" />
</project>
<project path="build/blueprint" name="platform/build/blueprint" groups="pdk,tradefed" />
<project path="build/pesto" name="platform/build/pesto" groups="pdk" />
<project path="build/soong" name="platform/build/soong" groups="pdk,tradefed" >
<linkfile src="root.bp" dest="Android.bp" />
<linkfile src="bootstrap.bash" dest="bootstrap.bash" />
</project>
<project path="art" name="platform/art" groups="pdk" />
<project path="bionic" name="platform/bionic" groups="pdk" />
.....
</manifest>
~~~
可以看到这个文件实际上是一份git仓库清单`repo init`初始化的过程就是下载git仓库清单文件以及下载repo工具的仓库。而`repo sync`步骤就是就是将清单文件中对应的子模块全部拉取下来。而default.xml中的元素主要为以下几种。
1、manifest根元素所有元素都要定义再根元素中
2、remotegit仓库的地址以及名称
3、default仓库默认的属性比如路径、分支、远程仓库名称
4、project子模块仓库的名称、路径、默认分支等信息
5、remove-project需要从清单中删除的仓库
6、copyfile同步代码时要复制的文件和目录
7、include导入另外一个清单文件比如我们觉得一个清单看起来太复杂可以根据目录分类存放
8、linkfile定义对应的文件或目录的软连接
在配置文件中我们可以看到有大量的project元素在这里我们先记下一个信息在project元素中的path指的是项目拉取到本地之后存放的路径而name才是指在git仓库中存放的路径。
清楚了使用repo同步代码的原理以及git清单中元素的作用后我们就可以开始搭建自己的Android源码远程仓库了。由于项目较大所以我们可以在本地搭建一个gitlab服务然后将项目上传至gitlab中进行管理如下是搭建gitlab服务的步骤。
~~~
// 安装gitlab服务的依赖
sudo apt-get update
sudo apt-get install -y curl openssh-server ca-certificates
sudo apt-get install -y postfix
// 信任gitlab的GPG公钥
curl https://packages.gitlab.com/gpg.key 2> /dev/null | sudo apt-key add - &>/dev/null
// 添加gitlab的源
vim /etc/apt/sources.list.d/gitlab-ce.list
// 加入下面的代码后保存
deb https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu xenial main
// 安装gitlab-ce
sudo apt-get update
sudo apt-get install gitlab-ce
// 执行配置
sudo gitlab-ctl reconfigure
// 启动gitlab
sudo gitlab-ctl start
~~~
接下来直接在浏览器中输入局域网ip来访问gitlab页面比如我的是`http://192.168.2.189/`。然后注册一个账号。在登录的时候出现了下面这个错误
~~~
Your account has been blocked. Please contact your GitLab administrator if you think this is an error.
~~~
这是因为注册的账号需要审批激活后才能使用。我们回到终端上通过下面的命令激活账号
~~~
// 进入gitlab的控制台
gitlab-rails console
// 查找刚刚注册的账号
user = User.find_by_email("myuser@example.com")
// 将状态设为激活
user.state = "active"
// 保存修改并退出
user.save
exit
~~~
到这里gitlab服务准备就绪登录账号后就可以创建aosp的子模块仓库了。
根据前面repo的介绍我们知道了源码一共是三个部分git-repo.git的工具仓库、manifests.git的子模块清单仓库、aosp源码子模块仓库。接下来我们将代码同步的流程分割为下面几个步骤。
1、参考.repo/manifests/default.xml配置修改为我们自己的gitlab地址并创建一个manifests.git仓库。
2、使用脚本批量创建子模块仓库
3、使用脚本批量同步子模块代码
4、使用自己的gitlab地址同步代码测试
由于我们一会需要创建大量的子模块仓库所以我们不可能在web页面上手动一个个的创建所以下面我们使用命令来创建一个manifests.git仓库。而命令创建仓库我们需要gitlab账号的Access Token。我们可以通过在web中登录账号点击右上角的用户图标选择Preferences来到用户设置页面然后进入Access Tokens栏目填写token名称以及勾选权限最后点击生成我生成的token为`27zctxyWZP9Txksenkxb`。流程见下图。
![image-20230216211544482](.\images\image-20230216211544482.png)
首选我们需要在gitlab中手动创建一个根目录的group我这里创建了一个android12_r3的组所有的子模块仓库都将在这个分组下。在gitlab页面中点击左上角Groups->your Groups。然后点击New group创建分组。成功创建后记录下这个分组的id比如我的根目录组id是6.
然后就可以使用curl命令通过token访问gitlab的api创建一个空白的仓库
~~~
// 创建一个名称为manifests的空白仓库namespace_id是根目录的分组id
curl --header "PRIVATE-TOKEN: 27zctxyWZP9Txksenkxb" \
--data "name=manifest&namespace_id=6" \
--request POST "http://192.168.2.189/api/v4/projects"
~~~
接下来修改配置并且将清单项目上传到gitlab中
~~~
// 创建项目目录
mkdir manifest && cd manifest
// 拷贝安卓源码中的git子模块清单文件
cp ~/android_src/aosp12/.repo/manifests/default.xml ./
//编辑清单
vim default.xml
//修改内容如下
<manifest>
// 修改name为orgin修改review为我们自己的服务器地址
<remote name="origin"
fetch=".."
review="http://192.168.2.189/" />
// 修改remote为上面定义的name
<default revision="master"
remote="origin"
sync-j="4" />
// 修改remote为上面定义的name
<superproject name="platform/superproject" remote="origin" revision="master" />
<contactinfo bugurl="go/repo-bug" />
.....
</manifest>
//保存上面的修改,然后提交到仓库
git init
git remote add origin git@192.168.2.189:android12_r3/manifest.git
git add . && git commit -m "init"
git push
~~~
准备好清单文件后接下来就需要准备所有子模块仓库了。首先我们得知道一共有哪些子模块需要上传而这个通过default.xml中的project元素很容易得到。我们可以编写一个python脚本来匹配出所有project中的path属性然后创建group和仓库。下面贴上一份网上找到读取default.xml自动创建所有仓库。
~~~python
#!/usr/bin/python3
import gitlab
import os
import re
import time
// 读取的配置文件
MANIFEST_XML = "default.xml"
ROOT = os.getcwd()
# gitlab中自己手动创建这个group
ROOT_GROUP = "android12_r3"
MANIFEST_XML_PATH_NAME_RE = re.compile(r"<project\s+path=\"(?P<path>[^\"]+)\"\s+name=\"(?P<name>[^\"]+)\"",
re.DOTALL)
# 修改成自己的gitlab服务地址以及账号的token
gl = gitlab.Gitlab('http://192.168.2.189/', private_token='27zctxyWZP9Txksenkxb')
manifest_xml_project_paths = []
# 加载default.xml。取出所有需要创建的子仓库需要验证一下这里的数量和你的project是否一致。
def parse_repo_manifest():
with open(os.path.join(ROOT, MANIFEST_XML), "rb") as strReader:
for line in strReader:
if line is not None and len(line) != 0:
this_temp_line = line.decode()
if line.find("path".encode(encoding="utf-8")):
s = MANIFEST_XML_PATH_NAME_RE.search(this_temp_line)
if s is not None:
manifest_xml_project_paths.append(s.group("name"))
print("manifest_xml_project_paths=" + str(manifest_xml_project_paths))
print("manifest_xml_project_paths len=" + str(len(manifest_xml_project_paths)))
# 创建组以及对应的子模块仓库
def create_group_and_project():
all_groups = gl.groups.list(all=True)
print("all_groups=" + str(all_groups))
group_parent = None
# 遍历所有组查找根组android12_r3是否存在
for g in all_groups:
if g.name == ROOT_GROUP:
group_parent = g
break
print("group parent=" + str(group_parent))
# 遍历所有子仓库路径
for path in manifest_xml_project_paths:
print("path=" + path)
paths = path.split("/")
print("paths=" + str(paths))
last_path_index = len(paths) - 1
group = group_parent
for index in range(0, last_path_index):
p = paths[index]
print("p=" + p)
# is the group exist
print("parent group=" + group.name)
try:
all_groups = group.subgroups.list(all=True)
except AttributeError:
all_groups = []
print("AttributeError: clear all subgroups")
# 遍历所有组,找当前子模块的组是否存在
is_group_exist = False
for g in all_groups:
if g.name == p:
is_group_exist = True
group = g
print("group exist=" + g.name)
break
if is_group_exist:
continue
# create subgroup
data = {
"name": p,
"path": p,
"parent_id": group.id
}
# 不存在则创建子模块所属的组
try:
group = gl.groups.create(data)
print("group create success name=" + p)
time.sleep(1)
except gitlab.exceptions.GitlabCreateError as e:
if e.response_code == 400:
print("group:" + p + " has already been created")
query_groups = gl.groups.list(all=True)
print("query_groups:" + str(query_groups))
for query_group in query_groups:
if query_group.name == p and query_group.parent_id == group.id:
group = query_group
print("update exit group:" + group.name)
break
# 创建子模块仓库,创建前先遍历是否仓库已存在
project = paths[last_path_index]
print("group project list group=" + group.name)
real_group = gl.groups.get(group.id, lazy=True)
all_projects = real_group.projects.list(all=True)
print("group all projects=" + str(all_projects))
is_project_exist = False
for p in all_projects:
if p.name == project:
is_project_exist = True
print("project exist=" + p.name)
break
if not is_project_exist:
print("create project=" + project)
gl.projects.create({'name': project, 'path': project, 'namespace_id': group.id})
print("project create success name=" + project)
time.sleep(1)
# 测试是否能成功创建
def test_create_project_with_dot_name():
# need use path field, if don't use path, GitLab url will replace "." to "_"
res=gl.projects.create({'name': "xxx.yy.xy", 'path': "xxx.yy.xy"})
print(res)
if __name__ == '__main__':
parse_repo_manifest()
create_group_and_project()
# test_create_project_with_dot_name()
~~~
子模块仓库建立完成,最后我们还需要将代码上传到对应的仓库中。同样参考网上找的上传代码,修改一部分细节,代码如下
~~~python
#!/usr/bin/python3
import os
import re,time
# 代码放在我们之前准备好的清单仓库中然后指定default.xml路径
MANIFEST_XML = "./manifests/default.xml"
ROOT = os.getcwd()
LOG_FILE_PATH = os.path.join(ROOT, "push.log")
# 匹配path
MANIFEST_XML_PATH_NAME_RE = re.compile(r"<project\s+path=\"(?P<path>[^\"]+)\"\s+name=\"(?P<name>[^\"]+)\"\s+",
re.DOTALL)
# 设置源码路径
SOURCE_CODE_ROOT = "/home/king/android_src/android12_r3/"
# 设置gitlab仓库的根目录分组
REMOTE = "git@192.168.2.189:android12_r3/"
manifest_xml_project_paths = []
# 读取配置文件中的所有子模块路径
def parse_repo_manifest():
with open(os.path.join(ROOT, MANIFEST_XML), "rb") as strReader:
for line in strReader:
if line is not None and len(line) != 0:
this_temp_line = line.decode()
if line.find("path".encode(encoding="utf-8")):
s = MANIFEST_XML_PATH_NAME_RE.search(this_temp_line)
if s is not None:
manifest_xml_project_paths.append(s.group("path"))
print("manifest_xml_project_paths=" + str(manifest_xml_project_paths))
print("manifest_xml_project_paths len=" + str(len(manifest_xml_project_paths)))
# 上传源码
def push_source_code_by_folder(str_writer):
# 遍历所有路径
for path in manifest_xml_project_paths:
print("path=" + path)
abs_path = SOURCE_CODE_ROOT + path
# 路径存在则进行上传
if os.path.exists(abs_path):
# change current work dir
os.chdir(abs_path + "/")
# 1\. delete .git & .gitignore folder
rm_git_cmd = "rm -rf .git"
rm_gitignore_cmd = "rm -rf .gitignore"
os.system(rm_git_cmd)
os.system(rm_gitignore_cmd)
# 2\. list dir
dir_data = os.listdir(os.getcwd())
cmd_list = []
print("changed cwd=" + os.getcwd())
if len(dir_data) == 0:
echo_cmd = "echo \"This is a empty repository.\" > ReadMe.md"
str_writer.write(f"empty repository:{abs_path}".encode() )
str_writer.write("\r\n".encode())
cmd_list.append(echo_cmd)
# 将所有上传命令组装好
git_init_cmd = "git init"
cmd_list.append(git_init_cmd)
git_remote_cmd = "git remote add origin " + REMOTE + path + ".git"
cmd_list.append(git_remote_cmd)
git_add_dot_cmd = "git add ."
cmd_list.append(git_add_dot_cmd)
git_commit_cmd = "git commit -m \"Initial commit\""
cmd_list.append(git_commit_cmd)
git_push_cmd = "git push -u origin master"
cmd_list.append(git_push_cmd)
# 执行上传命令
for cmd in cmd_list:
print("begin exec cmd=" + cmd)
os.system(cmd)
print("end exec cmd=" + cmd)
else:
print("abs_path=" + abs_path + " is not exist.")
str_writer.write(f"folder not exist:{abs_path}".encode() )
str_writer.write("\r\n".encode())
def wrapper_push_source_code_write_log():
with open(LOG_FILE_PATH, 'wb+') as strWriter:
push_source_code_by_folder(strWriter)
strWriter.close()
# def test_only_dot_git_folder():
# subdir_and_file = os.listdir(os.getcwd())
# print("subdir_and_file=" + str(subdir_and_file))
# with open(LOG_FILE_PATH, 'wb+') as strWriter:
# strWriter.write(str(subdir_and_file).encode())
# strWriter.write("\r\n".encode())
# strWriter.write(str(subdir_and_file).encode())
# strWriter.close()
if __name__ == '__main__':
parse_repo_manifest()
wrapper_push_source_code_write_log()
~~~
上传过程较慢等待所有仓库上传完成最后将git-repo工具子模块上传到我们的仓库。首先在gitlab中创建一个分组android-tools。然后在分组中手动创建一个仓库git-repo。然后从github下载一份git-repo的工具源码传到我们的gitlab。过程如下。
~~~
// 从github下载git-repo源码并上传到gitlab仓库
git clone https://github.com/GerritCodeReview/git-repo.git && cd git-repo
rm .git -rf
git init
git remote add origin git@192.2.189:android-tools/git-repo.git
git add .
git commit -m "init"
git push -u origin master
// 将这里的repo拿来使用
cp ./repo ~/bin/
PATH=~/bin:$PATH
~~~
终于一切准备就绪,那么开始拉取我们自己的代码吧。
~~~
// 创建存放源码的目录
mkdir myandroid12 && cd myandroid12
// 指定使用我们自己的仓库使用我们自己的git-repo
repo init -u git@192.168.2.189:android12_r3/manifest.git --repo-url=git@192.168.2.189:android-tools/git-repo.git --no-repo-verify
// 出现了下面的错误
repo: error: unable to resolve "stable"
fatal: double check your --repo-rev setting.
fatal: cloning the git-repo repository failed, will remove '.repo/repo'
// 然后我们修改使用master分支再重新执行上面的repo init命令
export REPO_REV=refs/heads/master
repo init -u git@192.168.2.189:android12_r3/manifest.git --repo-url=git@192.168.2.189:android-tools/git-repo.git --no-repo-verify
//同步代码
repo sync -j8
~~~
到这里就完成了gitlab源码管理android源码开发了。最后如何使用git提交和查看历史记录我就不在这里叙述了。
## 2.10 小结
在这一章里主要讲述了如何从零开始搭建一个编译Android源码的环境以及如何选择编译的版本和完整的编译Android源码并使用自己编译的内核然后将这个我们编译好的镜像尝试多种方式刷入测试手机中。为了后续开发和阅览代码的便利又讲述了如何使用Android Studio和Clion导入源码。最后为了便于长期维护和持续性的开发我们又搭建了gitlab+repo管理Android源码。终于将一切准备就绪了。那么接下来让我们在下一章开始解开Android源码神秘的面纱。
TODO 你看看这里是不是小结写的有点简单。看着应该怎么丰富一下。

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB