implement personal reference
diff --git a/main.py b/main.py
index 72fb39b..db4f02d 100755
--- a/main.py
+++ b/main.py
@@ -79,6 +79,11 @@
dest='show_version', action='store_true',
help='display this version of repo')
+group = global_options.add_option_group('mtk customization options')
+group.add_option('--local-cache',
+ dest='local_cache',
+ help='personal reference location')
+
class _Repo(object):
def __init__(self, repodir):
self.repodir = repodir
@@ -121,7 +126,7 @@
return 1
cmd.repodir = self.repodir
- cmd.manifest = XmlManifest(cmd.repodir)
+ cmd.manifest = XmlManifest(cmd.repodir, gopts.local_cache)
Editor.globalConfig = cmd.manifest.globalConfig
if not isinstance(cmd, MirrorSafeCommand) and cmd.manifest.IsMirror:
diff --git a/manifest_xml.py b/manifest_xml.py
index e2f58e6..94c6864 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -106,7 +106,9 @@
class XmlManifest(object):
"""manages the repo configuration file"""
- def __init__(self, repodir):
+ def __init__(self, repodir, localcache=None):
+ self.localcache = None
+ if localcache: self.localcache = os.path.abspath(localcache)
self.repodir = os.path.abspath(repodir)
self.topdir = os.path.dirname(self.repodir)
self.manifestFile = os.path.join(self.repodir, MANIFEST_FILE_NAME)
@@ -738,9 +740,9 @@
groups = [x for x in re.split(r'[,\s]+', groups) if x]
if parent is None:
- relpath, worktree, gitdir, objdir = self.GetProjectPaths(name, path)
+ relpath, worktree, gitdir, objdir, localcache = self.GetProjectPaths(name, path)
else:
- relpath, worktree, gitdir, objdir = \
+ relpath, worktree, gitdir, objdir, localcache = \
self.GetSubprojectPaths(parent, name, path)
default_groups = ['all', 'name:%s' % name, 'path:%s' % relpath]
@@ -766,7 +768,8 @@
clone_depth = clone_depth,
upstream = upstream,
parent = parent,
- dest_branch = dest_branch)
+ dest_branch = dest_branch,
+ localcache = localcache)
for n in node.childNodes:
if n.nodeName == 'copyfile':
@@ -790,7 +793,10 @@
worktree = os.path.join(self.topdir, path).replace('\\', '/')
gitdir = os.path.join(self.repodir, 'projects', '%s.git' % path)
objdir = os.path.join(self.repodir, 'project-objects', '%s.git' % name)
- return relpath, worktree, gitdir, objdir
+ localcache = None
+ if self.localcache:
+ localcache = os.path.join(self.localcache, '%s.git' % name)
+ return relpath, worktree, gitdir, objdir, localcache
def GetProjectsWithName(self, name):
return self._projects.get(name, [])
@@ -812,7 +818,10 @@
worktree = None
else:
worktree = os.path.join(parent.worktree, path).replace('\\', '/')
- return relpath, worktree, gitdir, objdir
+ localcache = None
+ if self.localcache:
+ localcache = os.path.join(parent.localcache, 'subproject-caches', '%s.git' % name)
+ return relpath, worktree, gitdir, objdir, localcache
def _ParseCopyFile(self, project, node):
src = self._reqatt(node, 'src')
diff --git a/project.py b/project.py
index f43bcc5..e4ed7d0 100644
--- a/project.py
+++ b/project.py
@@ -525,7 +525,8 @@
upstream = None,
parent = None,
is_derived = False,
- dest_branch = None):
+ dest_branch = None,
+ localcache = None):
"""Init a Project object.
Args:
@@ -597,6 +598,10 @@
# This will be filled in if a project is later identified to be the
# project containing repo hooks.
self.enabled_repo_hooks = []
+ self.localcache = None
+ if localcache:
+ self.localcache = localcache.replace('\\', '/')
+ self.bare_cache = self._GitGetByExec(self, bare=True, gitdir=localcache)
@property
def Derived(self):
@@ -1350,6 +1355,14 @@
## Branch Management ##
+ def CleanCache(self, name):
+ refs = GitRefs(self.localcache).all
+
+ try:
+ self.bare_cache.DeleteRef(name)
+ except:
+ raise
+ return True
def StartBranch(self, name):
"""Create a new branch off the manifest's revision.
@@ -1702,6 +1715,52 @@
if command.Wait() != 0:
raise GitError('git archive %s: %s' % (self.name, command.stderr))
+ def _UpdateCache(self, name, ssh_proxy, tag_name, is_sha1):
+ if not name:
+ name = self.remote.name
+
+ remote = self.GetRemote(name)
+ cmd = ['fetch']
+ depth = None
+ if not self.manifest.IsMirror:
+ if self.clone_depth:
+ depth = self.clone_depth
+ else:
+ depth = self.manifest.manifestProject.config.GetString('repo.depth')
+ if depth:
+ cmd.append('--depth=%s' % depth)
+ cmd.append('--no-tags')
+ cmd.append('--quiet')
+ cmd.append('--update-head-ok')
+ cmd.append(remote.url)
+
+ if tag_name is not None:
+ cmd.append('tag')
+ cmd.append(tag_name)
+ else:
+ branch = self.revisionExpr
+ if is_sha1:
+ branch = self.upstream
+ if branch.startswith(R_HEADS):
+ branch = branch[len(R_HEADS):]
+ cmd.append(str((u'+refs/heads/%s:' % branch) + remote.ToLocal('refs/heads/%s' % branch)))
+ else:
+ cmd.append(str((u'+%s:' % branch) + remote.ToLocal(branch)))
+
+ for _i in range(2):
+ ret = GitCommand(self, cmd, bare=True, ssh_proxy=ssh_proxy, gitdir=self.localcache).Wait()
+ if ret == 0:
+ ok = True
+ break
+ elif ret == 128:
+ # Exit code 128 means "couldn't find the ref you asked for"; if we're in sha1
+ # mode, we just tried sync'ing from the upstream field; it doesn't exist, thus
+ # abort the optimization attempt and do a full sync.
+ break
+ time.sleep(random.randint(30, 45))
+ if ok and depth:
+ os.remove('%s/shallow' % self.localcache)
+
def _RemoteFetch(self, name=None,
current_branch_only=False,
initial=False,
@@ -1746,6 +1805,12 @@
if remote.PreConnectFetch():
ssh_proxy = True
+ try:
+ if self.localcache and not depth:
+ self._UpdateCache(name, ssh_proxy, tag_name, is_sha1)
+ except Exception as e:
+ print("update cache failed. %s" % traceback.format_exc(), file=sys.stderr)
+
if initial:
if alt_dir and 'objects' == os.path.basename(alt_dir):
ref_dir = os.path.dirname(alt_dir)
@@ -2044,6 +2109,10 @@
def _InitGitDir(self, mirror_git=None):
if not os.path.exists(self.gitdir):
+ if self.localcache and not os.path.exists(self.localcache):
+ os.makedirs(self.localcache)
+ self.bare_cache.init()
+
# Initialize the bare repository, which contains all of the objects.
if not os.path.exists(self.objdir):
os.makedirs(self.objdir)
@@ -2076,6 +2145,10 @@
if ref_dir:
_lwrite(os.path.join(self.gitdir, 'objects/info/alternates'),
os.path.join(ref_dir, 'objects') + '\n')
+ elif self.localcache:
+ _lwrite(os.path.join(self.gitdir, 'objects/info/alternates'),
+ os.path.join(self.localcache, 'objects') + '\n')
+
self._UpdateHooks()
diff --git a/repo b/repo
index b8c414b..83ab888 100755
--- a/repo
+++ b/repo
@@ -2,8 +2,9 @@
## repo default configuration
##
-REPO_URL = 'https://gerrit.googlesource.com/git-repo'
-REPO_REV = 'stable'
+REPO_URL = 'ssh://mtksgt08:29418/git-repo'
+REPO_REV = 'mediatek/dev'
+LOCAL_CACHE = '{user_home}/.git-objects'
# Copyright (C) 2008 Google Inc.
#
@@ -216,6 +217,13 @@
dest='config_name', action="store_true", default=False,
help='Always prompt for name/e-mail')
+#MTK
+group = init_optparse.add_option_group('mtk customization options')
+group.add_option('--local-cache',
+ dest='local_cache',
+ help='personal reference location')
+
+
class CloneFailure(Exception):
"""Indicate the remote clone of repo itself failed.
"""
@@ -757,6 +765,11 @@
'--wrapper-version=%s' % ver_str,
'--wrapper-path=%s' % wrapper_path,
'--']
+
+ if LOCAL_CACHE:
+ cache = LOCAL_CACHE.format(user_home=os.environ['HOME'])
+ orig_args.insert(0, '--local-cache=%s' % cache)
+
me.extend(orig_args)
me.extend(extra_args)
try:
diff --git a/subcmds/clean.py b/subcmds/clean.py
new file mode 100644
index 0000000..c50f5a4
--- /dev/null
+++ b/subcmds/clean.py
@@ -0,0 +1,127 @@
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import print_function
+import sys
+from command import Command
+from progress import Progress
+from git_command import GIT, git_require
+from git_refs import GitRefs
+
+try:
+ import threading as _threading
+except ImportError:
+ import dummy_threading as _threading
+
+try:
+ import multiprocessing
+except ImportError:
+ multiprocessing = None
+
+class Clean(Command):
+ common = True
+ helpSummary = "Delete a branch from personal reference"
+ helpUsage = """
+%prog <branchname> [<project>...]
+"""
+ helpDescription = """
+The '%prog' command remove an existing branch and run git gc
+to make more space from personal reference
+"""
+
+ def Execute(self, opt, args):
+ if not args:
+ self.Usage()
+
+ nb = args[0]
+ err = []
+ success = []
+ all_projects = self.GetProjects(args[1:])
+
+ pm = Progress('Remove %s' % nb, len(all_projects))
+ for project in all_projects:
+ pm.update()
+
+ status = project.CleanCache('refs/remotes/%s' % nb)
+ if status is not None:
+ if status:
+ success.append(project)
+ else:
+ err.append(project)
+ pm.end()
+
+ if err:
+ for p in err:
+ print("error: %s/: cannot clean cache %s" % (p.localcache, nb),
+ file=sys.stderr)
+ sys.exit(1)
+ elif not success:
+ print('error: no project has branch %s' % nb, file=sys.stderr)
+ sys.exit(1)
+
+ self._GCProjects(all_projects)
+
+ def _GCProjects(self, projects):
+ gitdirs = {}
+ for project in projects:
+ gitdirs[project.gitdir] = project.bare_cache
+
+ has_dash_c = git_require((1, 7, 2))
+ if multiprocessing and has_dash_c:
+ cpu_count = multiprocessing.cpu_count()
+ else:
+ cpu_count = 1
+ jobs = cpu_count
+
+ if jobs < 2:
+ for bare_git in gitdirs.values():
+ bare_git.gc('--prune=all')
+ return
+
+ config = {'pack.threads': cpu_count / jobs if cpu_count > jobs else 1}
+
+ threads = set()
+ sem = _threading.Semaphore(jobs)
+ err_event = _threading.Event()
+
+ def GC(bare_git):
+ try:
+ try:
+ bare_git.gc('--prune=all', config=config)
+ except GitError:
+ err_event.set()
+ except:
+ err_event.set()
+ raise
+ finally:
+ sem.release()
+
+ for bare_git in gitdirs.values():
+ if err_event.isSet():
+ break
+ sem.acquire()
+ t = _threading.Thread(target=GC, args=(bare_git,))
+ t.daemon = True
+ threads.add(t)
+ t.start()
+
+ for t in threads:
+ t.join()
+
+ if err_event.isSet():
+ print('\nerror: Exited clean up due to gc errors', file=sys.stderr)
+ sys.exit(1)
+
+
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 96908f4..f9133be 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -211,6 +211,10 @@
dest='smart_tag', action='store',
help='smart sync using manifest from a known tag')
+ p.add_option('--force-current-branch-only-off',
+ dest='force_current_branch_only', action='store_false', default=True,
+ help='turn off force fetch only current branch from server')
+
g = p.add_option_group('repo Version options')
g.add_option('--no-repo-verify',
dest='no_repo_verify', action='store_true',
@@ -270,7 +274,7 @@
start = time.time()
success = project.Sync_NetworkHalf(
quiet=opt.quiet,
- current_branch_only=opt.current_branch_only,
+ current_branch_only=True if opt.force_current_branch_only else opt.current_branch_only,
clone_bundle=not opt.no_clone_bundle,
no_tags=opt.no_tags, archive=self.manifest.IsArchive)
self._fetch_times.Set(project, time.time() - start)
@@ -613,7 +617,7 @@
if not opt.local_only:
mp.Sync_NetworkHalf(quiet=opt.quiet,
- current_branch_only=opt.current_branch_only,
+ current_branch_only=True if opt.force_current_branch_only else opt.current_branch_only,
no_tags=opt.no_tags)
if mp.HasChanges: