diff options
| author | Raman Tenneti <rtenneti@google.com> | 2021-02-22 16:54:56 -0800 |
|---|---|---|
| committer | Raman Tenneti <rtenneti@google.com> | 2021-02-25 20:45:26 +0000 |
| commit | ceba2ddc1333dbd53b559bde2b79d09d2082f3dc (patch) | |
| tree | 91c9b2513f0b2984237b1eba47dd59adb780bedf /git_superproject.py | |
| parent | 45ad1541c5cd20e2947edae76264b40413b3fd8d (diff) | |
| download | git-repo-ceba2ddc1333dbd53b559bde2b79d09d2082f3dc.tar.gz | |
sync: superproject - support for switching hosts and switching branches.
+ superproject will be fetched into a directory with the name
“<remote name>-superproject.git” instead of the current
“superproject.git” folder.
+ Deleted _Clone method and added _Init method.
+ _Init method will do “git init --bare <remote>-superproject.git”.
It will create the folder and set up a bare repository in
<remote>-superproject.git folder.
+ _Fetch method, will pass <remote url>, <branch> arguments.
Moved the --filter argument from “git clone” to “git fetch”.
_Fetch method will execute the following command to fetch
superproject. Added --no-tags argument.
master: git fetch <remote url> --force --no-tags --filter blob:none
branch: git fetch <remote url> --force --no-tags --filter blob:none \
<branch>:<branch>
+ Performance improvements for aosp-master
++ repo init performance improved from 35 seconds to 17 seconds.
++ repo init --use-superproject is around 5 to 7 secsonds slower.
++ repo sync --use-superproject is around 3 to 4 minutes faster.
Tested the code with the following commands.
$ ./run_tests -v
Tested the sync code by using repo_dev alias and pointing to this CL.
$ time repo_dev init -u sso://android.git.corp.google.com/platform/manifest -b master --partial-clone --clone-filter=blob:limit=10M --repo-rev=main --use-superproject
...
real 0m20.648s
user 0m8.046s
sys 0m3.271s
+ Without superproject
$ time repo init -u sso://android.git.corp.google.com/platform/manifest -b master --partial-clone --clone-filter=blob:limit=10M --repo-rev=main
real 0m13.078s
user 0m9.783s
sys 0m2.528s
$ time repo_dev sync -c -j32 --use-superproject
...
real 15m7.072s
user 110m7.216s
sys 20m17.559s
+ Without superproject
$ time repo sync -c -j32
...
real 19m25.644s
user 91m56.331s
sys 20m59.170s
Bug: [google internal] b/180492484
Bug: [google internal] b/179470886
Bug: [google internal] b/180124069
Bug: https://crbug.com/gerrit/13709
Bug: https://crbug.com/gerrit/13707
Change-Id: Ib04bd7f1e25ceb75532643e58ad0129300ba3299
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/297702
Reviewed-by: Mike Frysinger <vapier@google.com>
Tested-by: Raman Tenneti <rtenneti@google.com>
Diffstat (limited to 'git_superproject.py')
| -rw-r--r-- | git_superproject.py | 70 |
1 files changed, 32 insertions, 38 deletions
diff --git a/git_superproject.py b/git_superproject.py index 471dadc4..a09edc15 100644 --- a/git_superproject.py +++ b/git_superproject.py | |||
| @@ -22,13 +22,13 @@ Examples: | |||
| 22 | project_commit_ids = superproject.UpdateProjectsRevisionId(projects) | 22 | project_commit_ids = superproject.UpdateProjectsRevisionId(projects) |
| 23 | """ | 23 | """ |
| 24 | 24 | ||
| 25 | import hashlib | ||
| 25 | import os | 26 | import os |
| 26 | import sys | 27 | import sys |
| 27 | 28 | ||
| 28 | from error import BUG_REPORT_URL | 29 | from error import BUG_REPORT_URL |
| 29 | from git_command import GitCommand | 30 | from git_command import GitCommand |
| 30 | from git_refs import R_HEADS | 31 | from git_refs import R_HEADS |
| 31 | import platform_utils | ||
| 32 | 32 | ||
| 33 | _SUPERPROJECT_GIT_NAME = 'superproject.git' | 33 | _SUPERPROJECT_GIT_NAME = 'superproject.git' |
| 34 | _SUPERPROJECT_MANIFEST_NAME = 'superproject_override.xml' | 34 | _SUPERPROJECT_MANIFEST_NAME = 'superproject_override.xml' |
| @@ -37,9 +37,9 @@ _SUPERPROJECT_MANIFEST_NAME = 'superproject_override.xml' | |||
| 37 | class Superproject(object): | 37 | class Superproject(object): |
| 38 | """Get commit ids from superproject. | 38 | """Get commit ids from superproject. |
| 39 | 39 | ||
| 40 | It does a 'git clone' of superproject and 'git ls-tree' to get list of commit ids | 40 | Initializes a local copy of a superproject for the manifest. This allows |
| 41 | for all projects. It contains project_commit_ids which is a dictionary with | 41 | lookup of commit ids for all projects. It contains _project_commit_ids which |
| 42 | project/commit id entries. | 42 | is a dictionary with project/commit id entries. |
| 43 | """ | 43 | """ |
| 44 | def __init__(self, manifest, repodir, superproject_dir='exp-superproject'): | 44 | def __init__(self, manifest, repodir, superproject_dir='exp-superproject'): |
| 45 | """Initializes superproject. | 45 | """Initializes superproject. |
| @@ -58,8 +58,12 @@ class Superproject(object): | |||
| 58 | self._superproject_path = os.path.join(self._repodir, superproject_dir) | 58 | self._superproject_path = os.path.join(self._repodir, superproject_dir) |
| 59 | self._manifest_path = os.path.join(self._superproject_path, | 59 | self._manifest_path = os.path.join(self._superproject_path, |
| 60 | _SUPERPROJECT_MANIFEST_NAME) | 60 | _SUPERPROJECT_MANIFEST_NAME) |
| 61 | self._work_git = os.path.join(self._superproject_path, | 61 | git_name = '' |
| 62 | _SUPERPROJECT_GIT_NAME) | 62 | if self._manifest.superproject: |
| 63 | remote_name = self._manifest.superproject['remote'].name | ||
| 64 | git_name = hashlib.md5(remote_name.encode('utf8')).hexdigest() + '-' | ||
| 65 | self._work_git_name = git_name + _SUPERPROJECT_GIT_NAME | ||
| 66 | self._work_git = os.path.join(self._superproject_path, self._work_git_name) | ||
| 63 | 67 | ||
| 64 | @property | 68 | @property |
| 65 | def project_commit_ids(self): | 69 | def project_commit_ids(self): |
| @@ -77,20 +81,15 @@ class Superproject(object): | |||
| 77 | branch = branch[len(R_HEADS):] | 81 | branch = branch[len(R_HEADS):] |
| 78 | return branch | 82 | return branch |
| 79 | 83 | ||
| 80 | def _Clone(self, url): | 84 | def _Init(self): |
| 81 | """Do a 'git clone' for the given url. | 85 | """Sets up a local Git repository to get a copy of a superproject. |
| 82 | |||
| 83 | Args: | ||
| 84 | url: superproject's url to be passed to git clone. | ||
| 85 | 86 | ||
| 86 | Returns: | 87 | Returns: |
| 87 | True if git clone is successful, or False. | 88 | True if initialization is successful, or False. |
| 88 | """ | 89 | """ |
| 89 | if not os.path.exists(self._superproject_path): | 90 | if not os.path.exists(self._superproject_path): |
| 90 | os.mkdir(self._superproject_path) | 91 | os.mkdir(self._superproject_path) |
| 91 | cmd = ['clone', url, '--filter', 'blob:none', '--bare'] | 92 | cmd = ['init', '--bare', self._work_git_name] |
| 92 | if self._branch: | ||
| 93 | cmd += ['--branch', self._branch] | ||
| 94 | p = GitCommand(None, | 93 | p = GitCommand(None, |
| 95 | cmd, | 94 | cmd, |
| 96 | cwd=self._superproject_path, | 95 | cwd=self._superproject_path, |
| @@ -98,24 +97,27 @@ class Superproject(object): | |||
| 98 | capture_stderr=True) | 97 | capture_stderr=True) |
| 99 | retval = p.Wait() | 98 | retval = p.Wait() |
| 100 | if retval: | 99 | if retval: |
| 101 | # `git clone` is documented to produce an exit status of `128` if | 100 | print('repo: error: git init call failed with return code: %r, stderr: %r' % |
| 102 | # the requested url or branch are not present in the configuration. | ||
| 103 | print('repo: error: git clone call failed with return code: %r, stderr: %r' % | ||
| 104 | (retval, p.stderr), file=sys.stderr) | 101 | (retval, p.stderr), file=sys.stderr) |
| 105 | return False | 102 | return False |
| 106 | return True | 103 | return True |
| 107 | 104 | ||
| 108 | def _Fetch(self): | 105 | def _Fetch(self, url): |
| 109 | """Do a 'git fetch' to to fetch the latest content. | 106 | """Fetches a local copy of a superproject for the manifest based on url. |
| 107 | |||
| 108 | Args: | ||
| 109 | url: superproject's url. | ||
| 110 | 110 | ||
| 111 | Returns: | 111 | Returns: |
| 112 | True if 'git fetch' is successful, or False. | 112 | True if fetch is successful, or False. |
| 113 | """ | 113 | """ |
| 114 | if not os.path.exists(self._work_git): | 114 | if not os.path.exists(self._work_git): |
| 115 | print('git fetch missing drectory: %s' % self._work_git, | 115 | print('git fetch missing drectory: %s' % self._work_git, |
| 116 | file=sys.stderr) | 116 | file=sys.stderr) |
| 117 | return False | 117 | return False |
| 118 | cmd = ['fetch', 'origin', '+refs/heads/*:refs/heads/*', '--prune'] | 118 | cmd = ['fetch', url, '--force', '--no-tags', '--filter', 'blob:none'] |
| 119 | if self._branch: | ||
| 120 | cmd += [self._branch + ':' + self._branch] | ||
| 119 | p = GitCommand(None, | 121 | p = GitCommand(None, |
| 120 | cmd, | 122 | cmd, |
| 121 | cwd=self._work_git, | 123 | cwd=self._work_git, |
| @@ -129,7 +131,7 @@ class Superproject(object): | |||
| 129 | return True | 131 | return True |
| 130 | 132 | ||
| 131 | def _LsTree(self): | 133 | def _LsTree(self): |
| 132 | """Returns the data from 'git ls-tree ...'. | 134 | """Gets the commit ids for all projects. |
| 133 | 135 | ||
| 134 | Works only in git repositories. | 136 | Works only in git repositories. |
| 135 | 137 | ||
| @@ -153,14 +155,12 @@ class Superproject(object): | |||
| 153 | if retval == 0: | 155 | if retval == 0: |
| 154 | data = p.stdout | 156 | data = p.stdout |
| 155 | else: | 157 | else: |
| 156 | # `git clone` is documented to produce an exit status of `128` if | ||
| 157 | # the requested url or branch are not present in the configuration. | ||
| 158 | print('repo: error: git ls-tree call failed with return code: %r, stderr: %r' % ( | 158 | print('repo: error: git ls-tree call failed with return code: %r, stderr: %r' % ( |
| 159 | retval, p.stderr), file=sys.stderr) | 159 | retval, p.stderr), file=sys.stderr) |
| 160 | return data | 160 | return data |
| 161 | 161 | ||
| 162 | def Sync(self): | 162 | def Sync(self): |
| 163 | """Sync superproject either by git clone/fetch. | 163 | """Gets a local copy of a superproject for the manifest. |
| 164 | 164 | ||
| 165 | Returns: | 165 | Returns: |
| 166 | True if sync of superproject is successful, or False. | 166 | True if sync of superproject is successful, or False. |
| @@ -179,17 +179,10 @@ class Superproject(object): | |||
| 179 | file=sys.stderr) | 179 | file=sys.stderr) |
| 180 | return False | 180 | return False |
| 181 | 181 | ||
| 182 | do_clone = True | 182 | if not self._Init(): |
| 183 | if os.path.exists(self._superproject_path): | 183 | return False |
| 184 | if not self._Fetch(): | 184 | if not self._Fetch(url): |
| 185 | # If fetch fails due to a corrupted git directory, then do a git clone. | 185 | return False |
| 186 | platform_utils.rmtree(self._superproject_path) | ||
| 187 | else: | ||
| 188 | do_clone = False | ||
| 189 | if do_clone: | ||
| 190 | if not self._Clone(url): | ||
| 191 | print('error: git clone failed for url: %s' % url, file=sys.stderr) | ||
| 192 | return False | ||
| 193 | return True | 186 | return True |
| 194 | 187 | ||
| 195 | def _GetAllProjectsCommitIds(self): | 188 | def _GetAllProjectsCommitIds(self): |
| @@ -203,7 +196,8 @@ class Superproject(object): | |||
| 203 | 196 | ||
| 204 | data = self._LsTree() | 197 | data = self._LsTree() |
| 205 | if not data: | 198 | if not data: |
| 206 | print('error: git ls-tree failed for superproject', file=sys.stderr) | 199 | print('error: git ls-tree failed to return data for superproject', |
| 200 | file=sys.stderr) | ||
| 207 | return None | 201 | return None |
| 208 | 202 | ||
| 209 | # Parse lines like the following to select lines starting with '160000' and | 203 | # Parse lines like the following to select lines starting with '160000' and |
