Detailed analysis of Android source code warehouse and its management tool repo

Because software engineering needs continuous iterative development, it is necessary to version manage the source code. Android source code engineering (AOSP) is no exception. It uses git for version management. As a large open source project, AOSP is composed of many sub projects, so it can not be simply managed with GIT. It establishes its own code warehouse based on GIT and uses the tool repo for management. Sharp tools make good work. This paper analyzes AOSP code warehouse and its management tool repo in order to improve our daily development efficiency.

Android system source code scenario analysis - click to download

Modern code version management tools, SVN and git are the most popular. Svn is a centralized code management tool that requires a central server, while Git is a distributed code management tool. A central server is not required. No central server is required, which means that git can perform version management without a network. Therefore, from this point of view alone, Git is much more convenient than SVN. Of course, GIT has many different design concepts compared with SVN, but in general, Git is more and more popular, especially in the open source community. Don't you see, Linux uses git for version management, and GitHub, which is becoming more and more popular, also provides git code management services. This article does not intend to analyze the differences between GIT and SVN and the use of GIT, but it is strongly recommended that you first understand GIT and then look at the following contents. Here is a git Book Pro git, written by Scott Chacon, an employee of GitHub, which introduces the use and principle of git in great detail and clearly.

As mentioned earlier, AOSP is composed of many projects. For example, Android 4.2 contains 329 projects, and each project is an independent git warehouse. This means that if we want to create an AOSP branch for feature development, we need to create a corresponding branch for each sub project. Obviously, you can't manually create branches in each sub project. You must adopt an automatic way to deal with it. These automatic processing tasks are completed by repo tools. Of course, the automation of * * Repo tools is not only simple, but also can be done by looking at branch state, submitting code, updating code, and other basic Git operations.

The repo tool is actually composed of a series of Python scripts that complete their functions by calling git commands. Interestingly, the python scripts that make up the repo tool are also a git repository. This git warehouse is called repo warehouse in AOSP. Every time we execute the repo command, the repo warehouse will update itself.

We discussed the repo warehouse above, but in fact, when we execute the repo command, we want to operate AOSP. This requires the repo command to know which subprojects are included in AOSP, and what are the names and warehouse addresses of these subprojects. In other words, the repo command needs to know the GIT warehouse meta information of all AOSP subprojects. As we know, AOSP is also constantly changing in iterative method. For example, each version of AOSP may contain different subprojects. This means that another git repository is needed to manage the GIT repository meta information of all AOSP subprojects. This git warehouse is called manifest warehouse in AOSP.

So far, we have mentioned three types of GIT warehouses: repo warehouse, manifest warehouse and AOSP sub project warehouse. Repo warehouse can obtain the meta information of all AOSP sub project warehouses through the manifest warehouse. With this meta information, we can operate AOSP subprojects through Python scripts in the repo repository. So how did repo warehouse and manifest warehouse come from? The answer is obtained through an independent repo script, which is located on an official website of AOSP and can be downloaded through HTTP protocol.

Now, let's outline the picture of the whole AOSP through a diagram, which is composed of repo script, repo warehouse, manifest warehouse and AOSP sub project warehouse, as shown in Figure 1:

Figure 1 repo script, repo warehouse, manifest warehouse and AOSP sub project warehouse

Next, let's look at how the above script and warehouse come from.

1. Repo script

You can know from the official website that the repo script can be obtained through the following commands:

That is, you can use the curl tool to http://commondatastorage.googleapis.com/git-repo-downloads/repo Get it and save it in the file ~ / bin / repo. Since ~ / bin / repo is a python script, we give it executable permissions through the Chmod command so that we can run it through the repo command next.

2. Repo warehouse

After downloading the repo script, we need to install a repo warehouse through the following command:

This command actually contains two operations: installing the repo repository and the manifest repository. Among them, the address of the manifest warehouse is given by the parameters brought later by - U. In this section, we first analyze the installation process of repo warehouse, and then analyze the installation process of manifest warehouse in the next section 3.

Let's see how the repo script executes the repo init command:

_ Findrepo traverses upward from the current directory until it is based on the directory. If there is a. Repo / repo directory under a directory in the middle, and there is a main.py file in the. Repo / repo, it will be considered that the repo script is currently executed in AOSP. At this time, it will return the absolute path of the file main.py and the absolute path of the. Repo sub directory under the current search directory to the caller. In the above case, it actually means that the repo warehouse has been installed.

_ The implementation of findrepo is as follows:

_ Parsearguments is nothing more than parsing the parameters of repo to get the command to be executed and its corresponding parameters. For example, when we call "repo init - U" https://android.googlesource.com/platform/manifest ”It means that the command to be executed is init, and the parameter followed by this command is "- U https://android.googlesource.com/platform/manifest ”。 At the same time, if we call "repo sync", it means that the command to be executed is sync, and this command has no parameters.

_ Runself checks whether a repo warehouse exists in the directory where the repo script is located. If so, clone a new warehouse from the warehouse to the directory where the repo script is executed. In fact, it is to clone a new repo warehouse locally. If it does not exist, you need to clone a repo warehouse from the remote address to the local. The remote address is hard code, which is in the repo script.

_ The implementation of runself is as follows:

From here, we can see that if there is a repo warehouse in the directory where the repo script is located, the following conditions must be met:

(1) . there is a. Git directory; (2) . there is a main.py file; (3) . there is a GIT_ Config.py file; (4) . there is a project.py file; (5) . there is a subcmds directory.

The above directories and files are actually owned by a standard repo repository.

Let's go back to the main function. If called_ Repo from findrepo_ If the value of main is equal to null, it means that the repo warehouse has not been installed in the current directory. At this time, the parameters followed by repo can only be help or init. Otherwise, an error message will be displayed. If the parameter followed by repo is help, the help document of repo script will be printed out.

We focus on the case where the parameter followed by repo is init. Now look at the call_ Return value of runself my_ Whether Git is not equal to null. If it is not equal to empty, it means that there is a repo warehouse in the directory where the repo script is located. At this time, it is called_ Setdefaultsto sets the repo repository source to be cloned later.

_ The implementation of setdefaultsto is as follows:

If a repo repository does not exist in the directory where the repo script is located, it will be deleted by default https://gerrit.googlesource.com/git-repo Set as the repo warehouse source to be cloned, and the branch to be cloned is stable. Otherwise, the repo warehouse will be used as the cloning source, and the current branch of the repo warehouse will be used as the branch to be cloned.

From the previous analysis, we can know that when we execute the "repo init" command:

(1) If we only download a repo script from the Internet, when we execute the repo command, we will clone a repo warehouse remotely to the directory where the repo script is currently executed.

(2) If we download a repo script with a repo repository from the Internet, when we execute the repo command, we can clone a repo repository locally to the directory where the repo script is currently executed.

Let's continue to look at the implementation of the main function, which is called next_ Init installs a repo repository in the directory where the repo script is currently executed:

If we execute the Repo script without specifying the source address and branch of the Repo repository through --repo-url and --repo-branch, we use REPO_. URL and repo_ The source address and branch specified by Rev. From the previous analysis, we can know that repo_ URL and repo_ Rev either points to a remote address https://gerrit.googlesource.com/git-repo And branch stable, or point to the repo warehouse in the directory where the repo script is located and the current branch of the warehouse.

_ The init function continues to check whether a. Repo directory exists in the directory where the repo script is currently executed. If it doesn't exist, create a new one. Then, whether it is necessary to verify the GPG of the repo warehouse cloned later. If validation is required, it will be called_ After the Clone function is used to clone the Repo repository, call the Verify function to verify the GPG of the repo warehouse.

The key is the function_ Clone functions and_ The checkout function is called. The former is used to clone a warehouse from the place specified by the URL to the place specified by DST. In fact, it is cloned to the. / repo / repo directory under the current directory. The latter checks out the branch branch in the cloned warehouse.

Functions_ The implementation of clone is as follows:

This function first calls "git init" to initialize a git repository in the. Repo / repo subdirectory of the current directory, and then calls_ Setconfig function to set the URL information of the GIT warehouse. Then call_ Downloadbundle to check whether a clone.bundle file exists at the specified URL. If the clone.bundle file exists, it will be used as the Clone Source of the repo repository.

Functions_ The implementation of downloadbundle is as follows:

Bundle file is a mechanism provided by git to solve the problem that git warehouse cannot be cloned from remote address through git, SSH, HTTP and other network protocols. In short, we can use the "git bundle" command to create a bundle file in a git warehouse, and the bundle file will contain the submission history of the GIT warehouse. By copying the bundle file to another machine in other ways, you can use it as a local git repository without accessing the remote network.

Back to function_ In clone, if the corresponding clone.bundle file exists and can be successfully downloaded to the clone.bundle, then call the function_ Importbundle clones it as a source repository into a new repo repository. Functions_ The implementation of importbundle is as follows:

Combine_ Clone functions and_ As can be seen from the importbundle function, cloning the repo warehouse from the clone.bundle file and cloning the repo warehouse from the remote URL are through the function_ Fetch. The difference is to call the function_ The third parameter specified during fetch. The former is the path of a clone.bundle file that has been downloaded locally, and the latter is origin (indicating the name of the remote warehouse).

Functions_ The implementation of fetch is as follows:

Functions_ Fetch actually clones a new repo warehouse from the specified warehouse source to the. Repo / repo subdirectory of the current directory through "git fetch".

Note that the above only clones a repo warehouse, and then a branch needs to be checked out from the repo warehouse to work normally. A branch from the repo warehouse checkout is generated by calling a function_ Implemented by checkout:

The branch to be checked out is specified by the parameter branch. From the previous analysis, if there is a repo warehouse in the directory where the currently executed repo script is located, the parameter branch describes the branch from the current checkout of the warehouse. Otherwise, the parameter branch describes the "stable" branch cloned from the remote warehouse.

It should be noted that the branch from the warehouse checkout here is not implemented by using the "git checkout" command, but by the lower git command "git update ref". In fact, the "git checkout" command is also implemented through the "git update ref" command, but it is encapsulated at a higher level and easier to use. If we analyze the python script commands that make up the repo repository, we will find that they basically complete the GIT function through the underlying git commands.

3. Manifest warehouse

We will then analyze the execution of the following command:

As mentioned earlier, after installing the repo warehouse, this command will call the main.py script under the repo warehouse, and the corresponding file is. Repo / repo / main.py. The implementation of its entry function is as follows:

As can be seen from the previous analysis, the. Repo directory under the AOSP root directory is passed in through the parameter - repo dir. This is a hidden directory, which stores the repo warehouse, manifest warehouse and AOSP sub project warehouses. Functions_ Main first calls init_ SSH and init_ HTTP to initialize the network environment, and then call the one created earlier_ Member function of repo object_ Run to parse the command to be executed and execute the command.

_ Member function of repo class_ The implementation of run is as follows:

The commands that can be executed by the repo script are placed in the directory. Repo / repo / subcmds. Each Python file in the directory corresponds to a repo command. For example, "repo init" means that the command script to be executed is. Repo / repo / subcmds / init.py.

_ Member function of repo class_ Run is the first option in the parameters carried after repo, not the first option starting with "-". This option represents the command to be executed, and the name of the command is saved in the variable name. Then, according to the value of variable name_ Find the corresponding command module CMD in the member variable commands of the repo class, and specify the values of the member variables repodir and manifest of the command module CMD. The member variable repodir of the command module CMD describes the. Repo directory of AOSP. The member variable manifest points to an xmlmanifest object, which describes the repo warehouse and manifest warehouse of AOSP.

Let's look at the constructor of the xmlmanifest class, which is defined in the file. Repo / repo / XML_ In the manifest.py file:

Xmlmanifest describes the repo directory (repodir), AOSP root directory (TopDir) and manifest.xml file (manifestfile) of AOSP. In addition, two metaproject objects are used to describe the repo warehouse (repoproject) and manifest warehouse (manifestproject) of AOSP.

In AOSP, each sub project (or warehouse) is described by a project object. The project class is defined in the. Repo / repo / project.py file. It is used to encapsulate the basic git operations for each project, such as temporary storage, submission and update of the project. Its constructor is as follows:

See the notes for the meanings of the parameters of the project class constructor. For convenience of description, please describe them in Chinese:

revisionExpr、revisionId、rebase、groups、sync_ c、sync_ S and upstream: each project has a corresponding description in the. Repo / repo / manifest.xml file. The values of these attributes come from the description of themselves in the manifest.xml file. Refer to the. Repo / repo / docs / manifest-format.txt file for their meanings

Parent: parent item

is_ Derived: if a project contains sub modules (also a git warehouse), these sub modules will also be described by a project object

is_ The derived property is set to true

dest_ Branch: the branch used for code review

Here we will focus on the concepts of GIT warehouse directory and working directory of the project. Generally speaking, the GIT warehouse directory of a project (the default is. Git directory) is located under the working directory, but git supports storing the GIT warehouse directory and working directory of a project separately. In AOSP, the GIT directory (. GIT) of repo warehouse is located under the working directory (. Repo / repo). The GIT directory of manifest warehouse has two copies, one (. GIT) is located under the working directory (. Repo / manifests) and the other is located in the. Repo / manifests.git directory. The working directories and git directories of other AOSP sub items are stored separately, The working directory is located in the AOSP root directory and the GIT directory is located in the. Repo / repo / projects directory.

In addition, the working directory of each AOSP subproject also has a. Git directory, but this. Git directory is a symbolic link to the GIT directory corresponding to. Repo / repo / projects. In this way, we can execute the GIT command either in the working directory of the AOSP subproject or in its corresponding git directory. Generally speaking, commands to access the working directory (such as git status) need to be executed in the working directory, while commands that do not need to access the working directory (such as git log) can be executed in the GIT directory.

The project class has two member variables, work_ GIT and bare_ Git, they all point to a_ Gitgetbyexec object. Used to encapsulate the execution of GIT commands. The former will set the current directory as the working directory of the project when executing the GIT command, while the latter will not set the current directory, but will set the environment variable GIT_ The value of dir is set to the GIT directory of the project, that is, those directories under the. Repo / projects directory. In this way, the project class can execute git commands in the working directory or git directory as needed.

Back to the constructor of xmlmanifest class, because repo and manifest also belong to git warehouse, we also need to create a project object to describe them. However, because they are special git warehouses (GIT warehouses used to describe the meta information of AOSP subprojects), we use another object of type metaproject to describe them. The metaproject class is inherited from the project class and is defined in the project.py file, as shown below:

Since the metaproject class inherits from the project class, almost all their git operations can be completed through the project class. In fact, the difference between the metaproject class and the project class is not too great. It can be considered to be basically the same. Metaproject class is used to describe repo warehouse and manifest warehouse, mainly to emphasize that they are used to describe the meta information of AOSP sub project warehouse.

Back_ Member function of repo class_ In run, after creating the xmlmanifest object used to describe the repo warehouse and manifest warehouse, start executing the command represented by the option without a horizontal "-" following the repo script. In our scenario, this command is init. Its corresponding Python module is. Repo / repo / subcmds / init.py. The entry function is the member function execute defined in the init class of the module. Its implementation is as follows:

The member function execute of init class mainly calls the other two member functions_ Syncmanifest and_ Link manifest to clone the manifest repository.

Member function of init class_ The implementation of syncmanifest is as follows:

Member function of init class_ Syncmanifest does the following:

(1) . check whether the local manifest warehouse exists, that is, check whether the value of the member variable mexists used to describe the manifest warehouse metaproject object m is equal to true. If not, the manifest warehouse has not been installed locally. At this time, you need to call the member function of the metaproject object m_ Initgitdir to initialize a git repository in the. Repo / manifest directory.

(2) Sync calls the member function used to describe the manifest warehouse metaproject object M_ Network half to clone a new manifest repository from the remote repository to the local repository, or update the local manifest repository. The address of the remote warehouse is the URL specified through - u when executing the "repo init" command, i.e https://android.googlesource.com/platform/manifest 。

(3) . check whether the branch to be checked out in the manifest warehouse is specified by - B after the "repo init" command. If so, call the member function metabranchswitch used to describe the metaproject object m of the manifest warehouse to clean up so that you can check out to the specified branch next.

(4) Sync calls the member function used to describe the manifest warehouse metaproject object M_ Locahalf to perform the checkout branch. Note that the branch to be switched has been previously recorded in the member variable revisionexpr of the metaproject object M.

(5) if a new installation of the Manifest warehouse is executed before and the -b branch is not specified by the checkout option, then a default branch is checkout by default.

Next, we will mainly analyze the member functions of the metaproject class_ InitGitDir、Sync_ Networkhalf and sync_ Implementation of locahalf. These functions are actually implemented by the parent class project of metaproject. Therefore, let's analyze the member functions of project class_ InitGitDir、Sync_ Networkhalf and sync_ Implementation of locahalf.

Member function of project class_ The member function of initgitdir is implemented as follows:

Member function of project class_ Initgitdir first checks whether the GIT directory of the project already exists. If it does not exist, the GIT directory will be created first, and then the member variable bare will be called_ One described by Git_ The member function init of gitgetbyexec object initializes a git warehouse in this directory.

_ The member function init of gitgetbyexec class is through another member function__ getattr__ As follows:

As you can see from the notes_ Member function of gitgetbyexec class__ getattr__ A trick is used, which will_ The member function not implemented by gitgetbyexec class is obtained indirectly in the form of attribute, and the name of the member function not implemented is executed as a parameter of GIT. That is, when executed_ When gitgetbyexec. Init(), it is actually through the member function__ getattr__ A "git init" command was executed. This command is just used to initialize a git repository.

Let's look at the member function of the project class_ Implementation of networkhalf:

Member function of project class_ Networkhalf mainly performs the following operations:

(1) . check whether the corresponding git warehouse already exists locally. If it does not exist, another member function is called first_ Initgitdir to initialize the GIT repository.

(2) S. call another member function_ Remotefetch to update the local warehouse from the remote warehouse.

Member function of project class_ The implementation of remotefetch is as follows:

Member function of project class_ The core operation of remotefetch is to call the "git fetch" command to update the local warehouse from the remote warehouse.

Next, let's look at the member function of the metaproject class_ Implementation of locahalf:

Here we only analyze a relatively simple case, that is, the branch to be checked out is a clean branch, which has not been modified or set to track remote branches. This is the member function of the project class_ Remotefetch mainly performs the following operations:

(1) . call another member function getrevisionid to get the branch to be checked out and save it in the variable revid.

(2) . call the member variable work_ One described by Git_ Gethead, the member function of gitgetbyexec object, obtains the branch of the current checkout of the project, which only exists in the variable head.

(3) if checkout branch revid is to be checkout branch, what is there is nothing to do. Otherwise, proceed.

(4) . call another member function getbranch to obtain a branch object that describes the current branch.

(5) . if the value of the property localmerge of the above branch object is equal to none, which is the case we discussed, another member function will be called_ Checkout actually performs the operation of the checkout branch revid.

If the branch revid to be checked out is not a clean branch, that is, it is skipping the remote branch and has made local submissions, but these submissions have not been uploaded to the remote branch, some merge or rebase operations need to be performed. However, in any case, these operations are done through the standard git command.

Let's look at the member functions of the project class_ Implementation of checkout:

Member function of project class_ The implementation of checkout is very simple. It constructs a "git checkout" command through the gitcommand class to checkout the branch described by the parameter Rev.

At this point, we will transfer the manifest warehouse from the remote address https://android.googlesource.com/platform/manifest It is cloned locally, and the specified branch is checked out. Back to the member function execute of init class, it will call another member function next_ Linkmanifest to perform a symbolic link operation.

Member function of init class_ The implementation of linkmanifest is as follows:

The value of parameter name is generally equal to "default. XML", which represents the default.xml file in the manifest warehouse and the member function of init class_ Linkmanifest performs the symbolic link operation by calling the member function link of an xmlmanifest object described by the member variable manifest, which is defined in the file. Repo / repo / XML_ Manifest.py file. Its implementation is as follows:

The value of the member variable manifestfile of the xmlmanifest class is equal to $(AOSP) /. Repo / manifest.xml. It is symbolic linked to the $(AOSP) /. Repo / manifest / < name > file by calling os.symlink. In this way, no matter what the name of the XML file used to describe AOSP sub projects in the manifest warehouse is, it can be accessed uniformly through the $(AOSP) /. Repo / manifest.xml file.

As mentioned earlier, the name of the XML file used to describe AOSP subprojects in the manifest warehouse is default.xml by default. Its contents are as follows:

For a detailed description of the XML file, refer to the. Repo / repo / docs / manifest-format.txt file. In general, the XML contains four types of tags:

Remote: used to specify remote warehouse information. The attribute name describes the name of a remote warehouse. The attribute fetch is used as the leading edge of the project name. It is used when constructing the remote address of the project warehouse. The attribute review describes the server address used as code review.

Default: when the project tag does not specify the attribute of the default tag, the attribute listed in the default tag is used by default. The attribute revision describes the branch checked out by default. The attribute remote describes the remote warehouse name used by default. The name attribute value of the corresponding remote tag must be. The attribute sync-j describes the number of parallel tasks used when updating the project from the remote warehouse.

Project: each AOSP subproject has a projec tag to describe the meta information of the project. The attribute path describes the path of the project relative to the remote warehouse URL, and the attribute name describes the name of the project and the directory name relative to the AOSP root directory. For example, if the remote warehouse URL is https://android.googlesource.com/platform , the remote warehouse URL corresponding to AOSP subproject bionic is https://android.googlesource.com/platform/bionic , and its working directory is located in $(AOSP) / bionic.

Copyfile: as a sub label of the project, it means to copy the file updated from the remote warehouse to another specified file.

So far, we have analyzed and completed the cloning process of the manifest warehouse. On this basis, it is much easier for us to analyze the cloning process of AOSP subproject warehouse or various repo commands for AOSP subprojects.

4. AOSP sub project warehouse

After the repo init command is executed, we can continue to execute the repo sync command to clone or synchronize AOSP subprojects:

Similar to the repo init command, the execution process of the repo sync command is as follows:

1. The repo script finds the main.py file in the repo warehouse and executes its entry function_ Main;

2. Entry function of main.py file in repo warehouse_ Main call_ Member function of repo class_ Run parses the parameters passed in by the repo script;

3. _ Member function of repo class_ Run parses the parameters and finds that the command to be executed is sync, so it finds a file named sync.py in the subcmds directory and calls the member function execute of a class named sync defined in it;

4. The member function execute of the sync class parses the default.xml file of the manifest repository, and clones or synchronizes each AOSP sub project listed in the default.xml file.

In step 3, how is each Python file in the repo repository associated with a repo command? It turns out that there is one in the subcmds directory of the repo warehouse__ init__. Py file. Whenever subcmds is imported, the commands defined in it will be executed, as shown below:

__ init__. Py will list all Python files in the subcmds directory (except _init_. Py), find the corresponding class, then create an object of this class, and save the object in the global variable all with the file name as the keyword_ Commands. For example, for the sync.py file, its file name is sync after removing the suffix, and then capitalize the first letter of sync to get sync. That is, sync.py needs to define a sync class, and this class needs to inherit directly or indirectly from the command class. Command class has a member function execute, and its subclasses need to override it to realize their functions.

_ Member function of repo class_ Run is through the global variable all in the subcmds module_ Commands, and according to the first Repo parameter without the horizontal line, to find the corresponding Command object, and then call its member function Execute.

The member function execute of sync class is implemented as follows:

The execution process of the member function execute of sync class is as follows:

(1) . get the metaproject object MP used to describe the manifest warehouse.

(2) If the -- local only option is not specified when executing the repo sync command, the member function of the metaproject object MP is called_ Networkhalf downloads and updates the local manifest repository from the remote repository.

(3) If the mainifest repository has been updated, the member function of metaproject object MP will be called_ Local half to merge these updates to the local current branch.

(4) . call getprojects, a member function of sync's parent class command, to obtain the information of all AOSP subprojects defined by the default.xml file of the manifest repository, or the information of AOSP subprojects specified by the parameter args. The AOSP subproject information is described by the project object and saved in the variable all_ Projects.

(5) If the -- local only option is not specified when the repo sync command is executed, it is saved in the variable all_ AOSP subprojects in projects perform network updates, that is, download updates from the remote warehouse to the local warehouse by calling the member function of the sync class_ Fetch did it. Member function of sync class_ Fetch actually calls the member function sync of the project class_ Network half to download updates from the remote warehouse to the local warehouse.

(6) . since AOSP subprojects may contain submodules, you need to check whether they contain submodules after they are remotely updated. If there are sub modules and the -- fetch submodules option is specified when executing the repo sync script, you need to remotely update the sub modules of the AOSP sub project. When calling the member function getprojects of the parent class command of sync, if the parameter submodules_ If the value of OK is set to true, the resulting AOSP sub project list contains sub modules. By comparing the AOSP sub item list with the fetched AOSP sub item list, you can know which sub modules need to be updated. The sub modules to be updated are saved in the variable missing. Since the sub module is also described by the project class, we can call the member function of the sync class just like updating the AOSP sub project remotely_ Fetch to update their sub modules.

(7) . call the updateprojectlist member function of the sync class to update the project.list file in the $(AOSP) /. Repo directory$ (AOSP) /. Repo / project.list records the names of all AOSP subprojects since the last remote synchronization. After each remote synchronization in the future, the updateprojectlist member function of the sync class will use this file to check whether some AOSP subprojects have been deleted. If such AOSP subprojects exist and they have not been modified, their working directories will be deleted.

(8) So far, the member function of sync class has only downloaded the updates of the remote warehouse to the local AOSP subproject, but has not merged these updates to the local current branch. Therefore, it is necessary to call the member function of project class at this time_ Local half to perform the merge update operation.

As can be seen from the above steps, the core operation of init sync command is to collect the project objects corresponding to each AOSP sub project to be synchronized, and then call the member function sync of these project objects_ Netwokhalft and sync_ Synchronize with localhalf. About member functions of project class_ Netwokhalft and sync_ Localhalf, which we have analyzed when analyzing the cloning process of the manifest repository, is nothing more than completing its functions through basic git commands such as git fetch, GIT rebase or git merge.

What we have analyzed above is the cloning or synchronization process of AOSP sub project warehouse. In order to further deepen the understanding of repo warehouse, we will analyze another command repo start used to create topic on AOSP.

5. Create topic on AOSP

In Git's world, branch is a very core concept. Git encourages you to create a new branch when fixing bugs or developing new features. The cost of creating git branches is small and fast, so don't worry that creating git branches is a thankless thing, but use as many branches as possible.

Similarly, after downloading the AOSP code, if we need to modify it or add new functions, we should do it on the new branch. The repo repository provides a repo start command to create branches on AOSP, also known as topic. The usage of this command is as follows:

Parameter branch_ Name specifies the name of the new branch, followed by project_ List is optional. If project is specified_ List means to create branches only for specific AOSP subprojects. Otherwise, branches will be created for all AOSP subprojects.

According to our previous analysis of the repo sync command, when we execute the repo start command, the member function execute of the start class finally defined in the subcomds / start.py file of the repo warehouse will be called. Its implementation is as follows:

Parameter args [0] saves the name of the branch to be created, parameter args [1:] saves the list of AOSP sub project names to be created, and the member function execute of start class saves them in variables Nb and projects respectively.

The member function execute of the start class then calls the member function getprojects of the parent class Command and takes the variable projects as the parameter to obtain the list of all AOSP sub projects that need to create a new branch NB_ projects。 In all_ In projects, each AOSP subproject is described by a project object.

Finally, the member function execute of the start class traverses all_ Each project object in projects and call their member function startbranch to create a new branch.

The implementation of the member function startbranch of the project class is as follows:

The execution process of the member function startbranch of project class is as follows:

(1) . get the current branch head of the project by calling the member function gethead of the project class.

(2) All current branches of the project are saved in the member variable of the project class_ The member variable all of a gitrefs object described by Ref. If the branch name that you want to create is already a branch of the project, you can directly detect the branch through the GitCommand class by calling the GIT checkout command instead of creating a new branch. Otherwise, proceed.

(3) . create a branch object to describe the branch to be created. The member variable remote of the branch class describes the remote warehouse to be tracked by the branch, and the other member variable merge describes the branch of the remote warehouse to be tracked by the branch. The remote warehouse branch to be tracked is described by the default.xml file of the manifest warehouse and saved in the member variable revisionexpr of the project class.

(4) . call the member function getrevisionid of the project class to obtain the SHA1 value of the remote warehouse branch to be tracked by the project and save it in the variable revid.

(5) . since the remote warehouse branch to be tracked by the newly created branch name is revid, if the current branch head of the project happens to be the remote warehouse branch revid to be tracked by the project, it becomes very simple to create a new branch name. Just create a file with the name in the refs / heads subdirectory under the GIT directory (located in the. Repo / projects directory) of the project, And write the value of revid to this file to indicate that the new branch name is created based on the remote branch revid to be tracked. Such a simple git branch is created. However, we also need to modify the. Git / head file in the project working directory and write its contents as the path name of the file just created, so as to switch the current branch of the project to the newly created branch just now. From this process, we can see that creating a git branch is just creating a file containing a SHA1 value, so the cost is very small. If the current branch head of the project is not the remote warehouse branch revid to be tracked by the project, continue.

(6) . when it is executed here, it indicates that the branch we want to create does not exist, and we need to create the new branch based on a branch that is not the current branch. At this time, we need to call the GIT checkout command with - B option to complete the operation of creating a new branch. The parameter after option - B indicates which branch to create on. After the new branch is created, its files need to be copied to the working directory of the project.

So far, we have analyzed and completed the process of creating a new branch on AOSP, that is, the execution process of repo start command. For more repo commands, such as repo uplad, repo diff, and repo status, you can refer to the official documentation http://source.android.com/source/using-repo.html , their execution process is similar to the above analysis of repo sync and repo start, except that they execute other git commands. Interested partners try to analyze by themselves

The above is the whole content of this article. I hope it will be helpful to your study, and I hope you can support programming tips.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>