summaryrefslogtreecommitdiffstats
path: root/git_superproject.py
diff options
context:
space:
mode:
authorRaman Tenneti <rtenneti@google.com>2021-02-22 16:54:56 -0800
committerRaman Tenneti <rtenneti@google.com>2021-02-25 20:45:26 +0000
commitceba2ddc1333dbd53b559bde2b79d09d2082f3dc (patch)
tree91c9b2513f0b2984237b1eba47dd59adb780bedf /git_superproject.py
parent45ad1541c5cd20e2947edae76264b40413b3fd8d (diff)
downloadgit-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.py70
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
25import hashlib
25import os 26import os
26import sys 27import sys
27 28
28from error import BUG_REPORT_URL 29from error import BUG_REPORT_URL
29from git_command import GitCommand 30from git_command import GitCommand
30from git_refs import R_HEADS 31from git_refs import R_HEADS
31import 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'
37class Superproject(object): 37class 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