Android source deployed to the server, a total of seven parts.

  1. Software environment
  2. GitLab server deployment
  3. Repo Manifest. XML is generated
  4. GitLab position
  5. Git Push source code to the server
  6. Repo synchronizes source code
  7. Commit the modified code

First, software environment

Server system: Ubuntu 16.04

GitLab Software: GitLab Community Edition

Client system: Ubuntu 14.04

Git: Git 2.27.0

Second, GitLab server deployment

  1. Installation of Required Components
sudo apt-get update
sudo apt-get install -y curl openssh-server ca-certificates
sudo apt-get install -y postfix
Copy the code

When installing Postfix, use the left and right keys and Enter keys, and select an Internet Site from the drop-down list.

  1. Trust GitLab’s GPG public key
curl https://packages.gitlab.com/gpg.key 2> /dev/null | sudo apt-key add - &>/dev/null  
Copy the code
  1. Configuring a Mirror Path

If vim is not installed, install it first

vim /etc/apt/sources.list.d/gitlab-ce.list
Copy the code

Gitlab-ce. List:

deb https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu xenial main
Copy the code

If the gitlab-ce. List file does not exist, create it and grant permission to the root file.

touch /etc/apt/sources.list.d/gitlab-ce.list
chmod 777 /etc/apt/sources.list.d/gitlab-ce.list
Copy the code
  1. Install gitlab – ce
sudo apt-get update
sudo apt-get install gitlab-ce
Copy the code
  1. Perform the configuration
sudo gitlab-ctl reconfigure
Copy the code
  1. Start the GitLab
sudo gitlab-ctl start
Copy the code
  1. Modify external_url
sudo gedit /etc/gitlab/gitlab.rb 
Copy the code

Change the following path:

external_url 'http://gitlab.example.com'
Copy the code

The specific IP address should be changed to your server, for example, I use 192.168.50.10

External_url 'http://192.168.50.10'Copy the code

Be sure to reconfigure and run the configuration command again

sudo gitlab-ctl reconfigure 
Copy the code
  1. Visit your GitLab service

Open the browser on any computer in the same network segment only when the computers can communicate with each other. If VMS are used, set the network type to Bridge and configure VMS in the same network segment to communicate with each other.

Enter http://192.168.50.10 in the browser address bar (use your own URL instead).

You can then create user root, enter the password and confirm. Register other users and so on.

Repo manifest.xml generation

Why do I need to generate manifest.xml myself? If you have code that has been synchronized from unknown sources, or is provided by a solution vendor, or is not managed using a Repo, you may have changed the part of your code as a separate Git repository. So we need to generate manifest.xml from the existing source code.

Manifest.xml needs to be modified to keep the source repository equivalent to the manifest.xml repository.

Since.git is present in every repository in the source code, we need to count all.git. This is to find all the repositories and write them to manifest.xml so that we can manage them using the Repo.

  1. Find all Git repositories
find myandroid/ -type d -name '.git' > git_pro.txt
Copy the code

Open git_pro.txt and you’ll see the following line

. /home/snake/Share/art/.git ......Copy the code

Use the bash command to “nip things in the bud” (delete the prefix path /home/snake/Share/ and the suffix.git)

cat git_pro.txt | cut -c 18- | sed 's/..... $//' > path.txtCopy the code

The following path is obtained:

art
Copy the code

You then need to generate the manifest file.

gen_xml.sh

#! /bin/bashecho -e " <? The XML version = \ \ "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>" >>$1Copy the code

Run the script gen_xml.sh.

cat path.txt | ./gen_xml.sh default.xml
Copy the code

Default. XML reads as follows. This is the manifest.xml file we want.


      
<manifest>
  <remote  name="aosp"
           fetch=".."/>
  <default revision="master"
           remote="aosp"
           sync-j="4" />

  <project path="art" name="art" />
  <project path="abi/cpp" name="abi/cpp" />.</manifest>
Copy the code

The fetch is “…” I have placed the manifest repository under the android6newc group, as described below.

Revision master represents the trunk branch, which corresponds to the repository branch under the Android6Newc group.

The two are not configured correctly, and the REPO cannot synchronize the repository properly.

Fourth, GitLab warehouse construction

There are too many repositories in the source code to create one by one in the browser, so you need to automate this with the python-Gitlab library. Place default.xml in the same directory as the script and run it. Waiting for the completion of the warehouse, a bit time-consuming, maybe half an hour. If python-Gitlab is not installed, it can be installed with PIP.

The script contains the name of the parent group (Android6NewC), which needs to be created in the GitLab web page. To generate Tokens, go to GitLab Settings -> Access Tokens -> Add a Personal Access token.

AndroidSourceCodeGitlabManager.py

#! /usr/bin/python3

import gitlab
import os
import re
import time

MANIFEST_XML = "default.xml"
ROOT = os.getcwd()
ROOT_GROUP = "Android6NewC"
MANIFEST_XML_PATH_NAME_RE = re.compile(r"
      
       [^\"]+)\"\s+name=\"(? P
       
        [^\"]+)\"\s+/>"
       
      \s+path=\"(?>,
                                       re.DOTALL)

gl = gitlab.Gitlab('http://192.168.50.10/', private_token='xxxxxxx')

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 create_group_and_project() :
    all_groups = gl.groups.list(all=True)
    print("all_groups=" + str(all_groups))
    group_parent = None

    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 "_"
    gl.projects.create({'name': "xxx.yy.xy".'path': "xxx.yy.xy"})


if __name__ == '__main__':
    parse_repo_manifest()
    create_group_and_project()
Copy the code

The basic working principle of the script is relatively simple. It parses the project tag in default. XML to get path through regular expression, creates groups (including subgroups) according to path, and finally creates project.

When the script runs correctly, output looks like the following:

. path=external/mtd-utils paths=['external', 'mtd-utils'] p=external parent group=Android6NewC group exist=external group project list group=external group all projects=[...]  create project=mtd-utils project create success name=mtd-utils ...... Process finished with exit code 0Copy the code

After the script runs, take a look at the GitLab group page and generate the directory structure we need.

Git Push source code to server

Install Git first, then write an automatic commit script to commit the source code to the repository.

1. Install Git

Use the following command to install Git on Ubuntu 14.04 LTS

apt-get install git
Copy the code

If Git version 2.7.4 is displayed, the installation is successful.

git --version
Copy the code

Git globally configures the user name and mailbox

git config --global user.name "xxx"
git config --global user.email "xxx email address"
Copy the code

Generate the SSH key

ssh-keygen -t ed25519 -C "xxx email address"
Copy the code

The generated message is as follows. Sensitive information has been removed from the generated message. Your generated message will change.

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/captain/.ssh/id_ed25519):         
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/captain/.ssh/id_ed25519.
Your public key has been saved in /home/captain/.ssh/id_ed25519.pub.
The key fingerprint is:
xxxxxx xxx email address
The key's randomart image is:
+--[ED25519  256--+
|      =          |
|     x *         |
|    . x x        |
|   xo            |
|  * o = S o      |
| o = x o x       |
|  x o.4 .        |
|      x+         |
|     xx          |
+-----------------+
Copy the code

See the SSH key

cat /home/captain/.ssh/id_ed25519.pub
Copy the code

The following information is displayed

ssh-ed25519 AAAAC3NzaC1lZXXXXXXXXXXXXXXsULA48NC2f+oOLf5EoFSpn4 xxx email address
Copy the code

Add SSH key in GitLab. Paste the above key into Settings -> SSH Keys -> Add an SSH key.

Push is stored in the source folder project to the repository. Here is an example where the script actually wraps these commands.

CD existing_folder git init git remote add origin [email protected]: android6newc/build git git add. The git commit -m "Initial commit" git push -u origin masterCopy the code

Of course, because the code has been synchronized with Git before, so you need to delete. Git, use the rm command to delete.

rm -rf .git
Copy the code

2. Push the Manifest file to the GitLab server

Create the manifest Project under the Android6Newc group (android6newc). And push the client default.xml.

CD existing_folder git init git remote add origin [email protected]: android6newc/manifest git git add. The git commit -m "Initial commit" git push -u origin masterCopy the code

3. Automatically Push code to GitLab server

This requires the development of a script to execute, again in Python implementation, must be careful to switch to the working path, otherwise the pit, of course, the script has fixed the bug.

PushAndroidSourceCode2GitLab.py

#! /usr/bin/python3

import os
import re

MANIFEST_XML = "default.xml"
ROOT = os.getcwd()
LOG_FILE_PATH = os.path.join(ROOT, "push.log")

MANIFEST_XML_PATH_NAME_RE = re.compile(r"
      
       [^\"]+)\"\s+name=\"(? P
       
        [^\"]+)\"\s+/>"
       
      \s+path=\"(?>,
                                       re.DOTALL)
SOURCE_CODE_ROOT = "/home/captain/myandroid/"
REMOTE = [email protected]: android6newc "/"
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.popen(rm_git_cmd)
            os.popen(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("empty repository:" + abs_path)
                str_writer.write("\r\n")
                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.popen(cmd)
                print("end exec cmd=" + cmd)
        else:
            print("abs_path=" + abs_path + " is not exist.")
            str_writer.write("folder not exist:" + abs_path)
            str_writer.write("\r\n")


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))
        strWriter.write("\r\n")
        strWriter.write(str(subdir_and_file))
        strWriter.close()


if __name__ == '__main__':
    parse_repo_manifest()
    wrapper_push_source_code_write_log()
    # test_only_dot_git_folder()
Copy the code

Place default.xml in the same directory as the script and run it. At the end of the run, all the source code is synchronized to GitLab.

Repo synchronous source code

Since the source is deployed on a LAN, the LAN cannot access the Internet. So you also need to deploy the REPO to the server.

1. The REPO is deployed on the server

Clone a copy of the REPo to a computer with Internet access.

git clone https://github.com/GerritCodeReview/git-repo.git
Copy the code

Then wrap it up

tar cvf git-repo.tar git-repo/
Copy the code

Copy git-repo.tar to the Intranet PC and decompress it.

tar xvf git-repo.tar
Copy the code

Delete.git from git-repo/.

Create a Git-repo project under the Android-tools group. And push git-repo there.

CD existing_folder git init git remote add Origin [email protected]:android-tools/git-repo.git git add. git commit -m "add repo tool" git push -u origin masterCopy the code

2. Client repO synchronizes code

Locate the repo file in the git-repo path in the previous step. Place it under ~/bin, give execution permission, and add it to the environment variable PATH. This file can also be deployed on an HTTPD server to install the apache2 service.

sudo apt-get install apache2
Copy the code

Check whether the installation is successful.

sudo systemctl status apache2
Copy the code

Change the listening port, I changed it to 10086. We know that HTTP is on port 80 by default, but this port is already used by GitLab, so make room.

sudo vim /etc/apache2/ports.conf
Copy the code

Copy repo to the /var/www/html directory.

Restart the Apache2 service.

sudo service apache2 restart
Copy the code

Download the repo from the ~/bin/ directory.

The curl http://192.168.50.10:10086/repo > repoCopy the code

Modify permissions and add environment variables.

chmod a+x ~/bin/repo
export PATH=$PATH:~/bin
Copy the code

Now you can create a new folder to store the source code. Repo init first, then repo sync.

Repo init -u [email protected]: android6newc/manifest. Git - '08 - url = [email protected]: android - the tools/git - repo. The git --no-repo-verifyCopy the code

The.repo folder will be created in the current folder after init is successful. You can now run repo Sync to start synchronizing your code.

repo sync
Copy the code

To prevent it from popping up in the download, we use the following script, created first.

vim down.sh
Copy the code

Write the following:

#! /bin/sh repo sync while [ $? -ne 0 ] do repo sync doneCopy the code

Replace the repo sync command with this script.

chmod a+x down.sh
./down.sh
Copy the code

Make command can not be used when compiling because there is no Makefile. Copy the Makefile from the source directory. This file is very simple and includes build/core/main.mk.

### DO NOT EDIT THIS FILE ###
include build/core/main.mk
### DO NOT EDIT THIS FILE ###
Copy the code

Submit the modified code

Create a local branch for all repositories with an arbitrary branch name dev.

repo start dev --all
Copy the code

Submit code to remote.

git add .
git commit -m "xxx"
git push aosp dev
Copy the code

Git push < remote host name > < local branch name > will create a dev branch at the remote creation and request merge.

Git branch -a is the name of the remote repository.

Repo upload. (note the dot at the end) is not available because we have not configured the Gerrit server.

Alternatively, the code can be synchronized using the pull command.

git pull --rebase
Copy the code

Advanced usage

Repo forall -c XXX executes the commands specified by -c on all warehouses

repo forall -c git add .
repo forall -c git commit -m "xxx"
repo forall -c git pull --rebase
repo forall -c git push aosp dev
Copy the code

8. Records of errors encountered

1. The default. XML FETCH configuration is incorrect

The following figure is the result of a default.xml FETCH configuration error.

2. Short position and unsubmitted content

Fatal: Couldn’t find remote ref refs/heads/master fatal: Couldn’t find remote ref refs/heads/master fatal: Couldn’t find remote ref refs/heads/master

3. The Git version is old

git commit

Git: ‘Interpret – Trailers’ is not a Git command. See’ git –help ‘.

cannot insert change-id line in .git/COMMIT_EDITMSG

Update with the following command

sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git
Copy the code

4. The compilation file is missing

This is because some files were added to the.gitignore while git push was in the repository, but the problem is caused by ignoring that the configuration files don’t exactly match the files needed for the actual compilation. Delete this file directly from the script, corrected.

If you still fail to compile, it must be on the library, source repository some subfolders under the.gitignore, can be based on the error message will be the corresponding file on the library.

For example, the netlink/version.h header is missing.

external/libnl/include/netlink/netlink.h:29:29: fatal error: netlink/version.h: No such file or directory
 #include <netlink/version.h>
Copy the code

References:

  1. Blog.csdn.net/xiezhi12345…