summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--git_config.py12
-rw-r--r--git_refs.py11
-rw-r--r--progress.py12
-rw-r--r--project.py25
-rw-r--r--subcmds/download.py5
-rw-r--r--subcmds/init.py2
-rw-r--r--subcmds/stage.py4
-rw-r--r--subcmds/start.py10
-rw-r--r--subcmds/sync.py10
-rw-r--r--subcmds/upload.py20
10 files changed, 76 insertions, 35 deletions
diff --git a/git_config.py b/git_config.py
index e00f6be2..8c247394 100644
--- a/git_config.py
+++ b/git_config.py
@@ -50,16 +50,24 @@ else:
50from git_command import GitCommand 50from git_command import GitCommand
51from git_command import ssh_sock 51from git_command import ssh_sock
52from git_command import terminate_ssh_clients 52from git_command import terminate_ssh_clients
53from git_refs import R_CHANGES, R_HEADS, R_TAGS
53 54
54R_HEADS = 'refs/heads/'
55R_TAGS = 'refs/tags/'
56ID_RE = re.compile(r'^[0-9a-f]{40}$') 55ID_RE = re.compile(r'^[0-9a-f]{40}$')
57 56
58REVIEW_CACHE = dict() 57REVIEW_CACHE = dict()
59 58
59def IsChange(rev):
60 return rev.startswith(R_CHANGES)
61
60def IsId(rev): 62def IsId(rev):
61 return ID_RE.match(rev) 63 return ID_RE.match(rev)
62 64
65def IsTag(rev):
66 return rev.startswith(R_TAGS)
67
68def IsImmutable(rev):
69 return IsChange(rev) or IsId(rev) or IsTag(rev)
70
63def _key(name): 71def _key(name):
64 parts = name.split('.') 72 parts = name.split('.')
65 if len(parts) < 2: 73 if len(parts) < 2:
diff --git a/git_refs.py b/git_refs.py
index 3c266061..58c838a6 100644
--- a/git_refs.py
+++ b/git_refs.py
@@ -16,11 +16,12 @@
16import os 16import os
17from trace import Trace 17from trace import Trace
18 18
19HEAD = 'HEAD' 19HEAD = 'HEAD'
20R_HEADS = 'refs/heads/' 20R_CHANGES = 'refs/changes/'
21R_TAGS = 'refs/tags/' 21R_HEADS = 'refs/heads/'
22R_PUB = 'refs/published/' 22R_TAGS = 'refs/tags/'
23R_M = 'refs/remotes/m/' 23R_PUB = 'refs/published/'
24R_M = 'refs/remotes/m/'
24 25
25 26
26class GitRefs(object): 27class GitRefs(object):
diff --git a/progress.py b/progress.py
index d948654f..0dd5d1a8 100644
--- a/progress.py
+++ b/progress.py
@@ -21,7 +21,8 @@ from trace import IsTrace
21_NOT_TTY = not os.isatty(2) 21_NOT_TTY = not os.isatty(2)
22 22
23class Progress(object): 23class Progress(object):
24 def __init__(self, title, total=0, units=''): 24 def __init__(self, title, total=0, units='', print_newline=False,
25 always_print_percentage=False):
25 self._title = title 26 self._title = title
26 self._total = total 27 self._total = total
27 self._done = 0 28 self._done = 0
@@ -29,6 +30,8 @@ class Progress(object):
29 self._start = time() 30 self._start = time()
30 self._show = False 31 self._show = False
31 self._units = units 32 self._units = units
33 self._print_newline = print_newline
34 self._always_print_percentage = always_print_percentage
32 35
33 def update(self, inc=1): 36 def update(self, inc=1):
34 self._done += inc 37 self._done += inc
@@ -50,13 +53,14 @@ class Progress(object):
50 else: 53 else:
51 p = (100 * self._done) / self._total 54 p = (100 * self._done) / self._total
52 55
53 if self._lastp != p: 56 if self._lastp != p or self._always_print_percentage:
54 self._lastp = p 57 self._lastp = p
55 sys.stderr.write('\r%s: %3d%% (%d%s/%d%s) ' % ( 58 sys.stderr.write('\r%s: %3d%% (%d%s/%d%s)%s' % (
56 self._title, 59 self._title,
57 p, 60 p,
58 self._done, self._units, 61 self._done, self._units,
59 self._total, self._units)) 62 self._total, self._units,
63 "\n" if self._print_newline else ""))
60 sys.stderr.flush() 64 sys.stderr.flush()
61 65
62 def end(self): 66 def end(self):
diff --git a/project.py b/project.py
index e8de4842..e700d16a 100644
--- a/project.py
+++ b/project.py
@@ -177,11 +177,15 @@ class ReviewableBranch(object):
177 def UploadForReview(self, people, 177 def UploadForReview(self, people,
178 auto_topic=False, 178 auto_topic=False,
179 draft=False, 179 draft=False,
180 private=False,
181 wip=False,
180 dest_branch=None): 182 dest_branch=None):
181 self.project.UploadForReview(self.name, 183 self.project.UploadForReview(self.name,
182 people, 184 people,
183 auto_topic=auto_topic, 185 auto_topic=auto_topic,
184 draft=draft, 186 draft=draft,
187 private=private,
188 wip=wip,
185 dest_branch=dest_branch) 189 dest_branch=dest_branch)
186 190
187 def GetPublishedRefs(self): 191 def GetPublishedRefs(self):
@@ -1108,6 +1112,8 @@ class Project(object):
1108 people=([], []), 1112 people=([], []),
1109 auto_topic=False, 1113 auto_topic=False,
1110 draft=False, 1114 draft=False,
1115 private=False,
1116 wip=False,
1111 dest_branch=None): 1117 dest_branch=None):
1112 """Uploads the named branch for code review. 1118 """Uploads the named branch for code review.
1113 """ 1119 """
@@ -1159,9 +1165,14 @@ class Project(object):
1159 dest_branch) 1165 dest_branch)
1160 if auto_topic: 1166 if auto_topic:
1161 ref_spec = ref_spec + '/' + branch.name 1167 ref_spec = ref_spec + '/' + branch.name
1168
1162 if not url.startswith('ssh://'): 1169 if not url.startswith('ssh://'):
1163 rp = ['r=%s' % p for p in people[0]] + \ 1170 rp = ['r=%s' % p for p in people[0]] + \
1164 ['cc=%s' % p for p in people[1]] 1171 ['cc=%s' % p for p in people[1]]
1172 if private:
1173 rp = rp + ['private']
1174 if wip:
1175 rp = rp + ['wip']
1165 if rp: 1176 if rp:
1166 ref_spec = ref_spec + '%' + ','.join(rp) 1177 ref_spec = ref_spec + '%' + ','.join(rp)
1167 cmd.append(ref_spec) 1178 cmd.append(ref_spec)
@@ -1275,7 +1286,7 @@ class Project(object):
1275 1286
1276 need_to_fetch = not (optimized_fetch and 1287 need_to_fetch = not (optimized_fetch and
1277 (ID_RE.match(self.revisionExpr) and 1288 (ID_RE.match(self.revisionExpr) and
1278 self._CheckForSha1())) 1289 self._CheckForImmutableRevision()))
1279 if (need_to_fetch and 1290 if (need_to_fetch and
1280 not self._RemoteFetch(initial=is_new, quiet=quiet, alt_dir=alt_dir, 1291 not self._RemoteFetch(initial=is_new, quiet=quiet, alt_dir=alt_dir,
1281 current_branch_only=current_branch_only, 1292 current_branch_only=current_branch_only,
@@ -1885,7 +1896,7 @@ class Project(object):
1885 1896
1886 1897
1887# Direct Git Commands ## 1898# Direct Git Commands ##
1888 def _CheckForSha1(self): 1899 def _CheckForImmutableRevision(self):
1889 try: 1900 try:
1890 # if revision (sha or tag) is not present then following function 1901 # if revision (sha or tag) is not present then following function
1891 # throws an error. 1902 # throws an error.
@@ -1939,7 +1950,9 @@ class Project(object):
1939 tag_name = self.revisionExpr[len(R_TAGS):] 1950 tag_name = self.revisionExpr[len(R_TAGS):]
1940 1951
1941 if is_sha1 or tag_name is not None: 1952 if is_sha1 or tag_name is not None:
1942 if self._CheckForSha1(): 1953 if self._CheckForImmutableRevision():
1954 print('Skipped fetching project %s (already have persistent ref)'
1955 % self.name)
1943 return True 1956 return True
1944 if is_sha1 and not depth: 1957 if is_sha1 and not depth:
1945 # When syncing a specific commit and --depth is not set: 1958 # When syncing a specific commit and --depth is not set:
@@ -2095,7 +2108,7 @@ class Project(object):
2095 # We just synced the upstream given branch; verify we 2108 # We just synced the upstream given branch; verify we
2096 # got what we wanted, else trigger a second run of all 2109 # got what we wanted, else trigger a second run of all
2097 # refs. 2110 # refs.
2098 if not self._CheckForSha1(): 2111 if not self._CheckForImmutableRevision():
2099 if current_branch_only and depth: 2112 if current_branch_only and depth:
2100 # Sync the current branch only with depth set to None 2113 # Sync the current branch only with depth set to None
2101 return self._RemoteFetch(name=name, 2114 return self._RemoteFetch(name=name,
@@ -2961,14 +2974,14 @@ class MetaProject(Project):
2961 self.revisionExpr = base 2974 self.revisionExpr = base
2962 self.revisionId = None 2975 self.revisionId = None
2963 2976
2964 def MetaBranchSwitch(self): 2977 def MetaBranchSwitch(self, submodules=False):
2965 """ Prepare MetaProject for manifest branch switch 2978 """ Prepare MetaProject for manifest branch switch
2966 """ 2979 """
2967 2980
2968 # detach and delete manifest branch, allowing a new 2981 # detach and delete manifest branch, allowing a new
2969 # branch to take over 2982 # branch to take over
2970 syncbuf = SyncBuffer(self.config, detach_head=True) 2983 syncbuf = SyncBuffer(self.config, detach_head=True)
2971 self.Sync_LocalHalf(syncbuf) 2984 self.Sync_LocalHalf(syncbuf, submodules=submodules)
2972 syncbuf.Finish() 2985 syncbuf.Finish()
2973 2986
2974 return GitCommand(self, 2987 return GitCommand(self,
diff --git a/subcmds/download.py b/subcmds/download.py
index a029462e..e1010aa2 100644
--- a/subcmds/download.py
+++ b/subcmds/download.py
@@ -26,11 +26,12 @@ class Download(Command):
26 common = True 26 common = True
27 helpSummary = "Download and checkout a change" 27 helpSummary = "Download and checkout a change"
28 helpUsage = """ 28 helpUsage = """
29%prog {project change[/patchset]}... 29%prog {[project] change[/patchset]}...
30""" 30"""
31 helpDescription = """ 31 helpDescription = """
32The '%prog' command downloads a change from the review system and 32The '%prog' command downloads a change from the review system and
33makes it available in your project's local working directory. 33makes it available in your project's local working directory.
34If no project is specified try to use current directory as a project.
34""" 35"""
35 36
36 def _Options(self, p): 37 def _Options(self, p):
@@ -55,7 +56,7 @@ makes it available in your project's local working directory.
55 m = CHANGE_RE.match(a) 56 m = CHANGE_RE.match(a)
56 if m: 57 if m:
57 if not project: 58 if not project:
58 self.Usage() 59 project = self.GetProjects(".")[0]
59 chg_id = int(m.group(1)) 60 chg_id = int(m.group(1))
60 if m.group(2): 61 if m.group(2):
61 ps_id = int(m.group(2)) 62 ps_id = int(m.group(2))
diff --git a/subcmds/init.py b/subcmds/init.py
index e6470916..eeddca06 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -256,7 +256,7 @@ to update the working directory files.
256 sys.exit(1) 256 sys.exit(1)
257 257
258 if opt.manifest_branch: 258 if opt.manifest_branch:
259 m.MetaBranchSwitch() 259 m.MetaBranchSwitch(submodules=opt.submodules)
260 260
261 syncbuf = SyncBuffer(m.config) 261 syncbuf = SyncBuffer(m.config)
262 m.Sync_LocalHalf(syncbuf, submodules=opt.submodules) 262 m.Sync_LocalHalf(syncbuf, submodules=opt.submodules)
diff --git a/subcmds/stage.py b/subcmds/stage.py
index 28849764..9d354268 100644
--- a/subcmds/stage.py
+++ b/subcmds/stage.py
@@ -60,8 +60,8 @@ The '%prog' command stages files to prepare the next commit.
60 out.nl() 60 out.nl()
61 61
62 for i in range(len(all_projects)): 62 for i in range(len(all_projects)):
63 p = all_projects[i] 63 project = all_projects[i]
64 out.write('%3d: %s', i + 1, p.relpath + '/') 64 out.write('%3d: %s', i + 1, project.relpath + '/')
65 out.nl() 65 out.nl()
66 out.nl() 66 out.nl()
67 67
diff --git a/subcmds/start.py b/subcmds/start.py
index 290b6897..c3ec303e 100644
--- a/subcmds/start.py
+++ b/subcmds/start.py
@@ -18,7 +18,7 @@ import os
18import sys 18import sys
19 19
20from command import Command 20from command import Command
21from git_config import IsId 21from git_config import IsImmutable
22from git_command import git 22from git_command import git
23import gitc_utils 23import gitc_utils
24from progress import Progress 24from progress import Progress
@@ -96,11 +96,11 @@ revision specified in the manifest.
96 project.Sync_LocalHalf(sync_buf) 96 project.Sync_LocalHalf(sync_buf)
97 project.revisionId = gitc_project.old_revision 97 project.revisionId = gitc_project.old_revision
98 98
99 # If the current revision is a specific SHA1 then we can't push back 99 # If the current revision is immutable, such as a SHA1, a tag or
100 # to it; so substitute with dest_branch if defined, or with manifest 100 # a change, then we can't push back to it. Substitute with
101 # default revision instead. 101 # dest_branch, if defined; or with manifest default revision instead.
102 branch_merge = '' 102 branch_merge = ''
103 if IsId(project.revisionExpr): 103 if IsImmutable(project.revisionExpr):
104 if project.dest_branch: 104 if project.dest_branch:
105 branch_merge = project.dest_branch 105 branch_merge = project.dest_branch
106 else: 106 else:
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 797fc403..b88c596d 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -356,7 +356,9 @@ later is required to fix a server side protocol bug.
356 def _Fetch(self, projects, opt): 356 def _Fetch(self, projects, opt):
357 fetched = set() 357 fetched = set()
358 lock = _threading.Lock() 358 lock = _threading.Lock()
359 pm = Progress('Fetching projects', len(projects)) 359 pm = Progress('Fetching projects', len(projects),
360 print_newline=not(opt.quiet),
361 always_print_percentage=opt.quiet)
360 362
361 objdir_project_map = dict() 363 objdir_project_map = dict()
362 for project in projects: 364 for project in projects:
@@ -393,7 +395,7 @@ later is required to fix a server side protocol bug.
393 t.join() 395 t.join()
394 396
395 # If we saw an error, exit with code 1 so that other scripts can check. 397 # If we saw an error, exit with code 1 so that other scripts can check.
396 if err_event.isSet(): 398 if err_event.isSet() and not opt.force_broken:
397 print('\nerror: Exited sync due to fetch errors', file=sys.stderr) 399 print('\nerror: Exited sync due to fetch errors', file=sys.stderr)
398 sys.exit(1) 400 sys.exit(1)
399 401
@@ -779,8 +781,8 @@ later is required to fix a server side protocol bug.
779 # generate a new args list to represent the opened projects. 781 # generate a new args list to represent the opened projects.
780 # TODO: make this more reliable -- if there's a project name/path overlap, 782 # TODO: make this more reliable -- if there's a project name/path overlap,
781 # this may choose the wrong project. 783 # this may choose the wrong project.
782 args = [os.path.relpath(self.manifest.paths[p].worktree, os.getcwd()) 784 args = [os.path.relpath(self.manifest.paths[path].worktree, os.getcwd())
783 for p in opened_projects] 785 for path in opened_projects]
784 if not args: 786 if not args:
785 return 787 return
786 all_projects = self.GetProjects(args, 788 all_projects = self.GetProjects(args,
diff --git a/subcmds/upload.py b/subcmds/upload.py
index 1172dadc..61b18bc2 100644
--- a/subcmds/upload.py
+++ b/subcmds/upload.py
@@ -154,6 +154,12 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
154 p.add_option('-d', '--draft', 154 p.add_option('-d', '--draft',
155 action='store_true', dest='draft', default=False, 155 action='store_true', dest='draft', default=False,
156 help='If specified, upload as a draft.') 156 help='If specified, upload as a draft.')
157 p.add_option('-p', '--private',
158 action='store_true', dest='private', default=False,
159 help='If specified, upload as a private change.')
160 p.add_option('-w', '--wip',
161 action='store_true', dest='wip', default=False,
162 help='If specified, upload as a work-in-progress change.')
157 p.add_option('-D', '--destination', '--dest', 163 p.add_option('-D', '--destination', '--dest',
158 type='string', action='store', dest='dest_branch', 164 type='string', action='store', dest='dest_branch',
159 metavar='BRANCH', 165 metavar='BRANCH',
@@ -198,7 +204,8 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
198 commit_list = branch.commits 204 commit_list = branch.commits
199 205
200 destination = opt.dest_branch or project.dest_branch or project.revisionExpr 206 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
201 print('Upload project %s/ to remote branch %s:' % (project.relpath, destination)) 207 print('Upload project %s/ to remote branch %s%s:' %
208 (project.relpath, destination, ' (draft)' if opt.draft else ''))
202 print(' branch %s (%2d commit%s, %s):' % ( 209 print(' branch %s (%2d commit%s, %s):' % (
203 name, 210 name,
204 len(commit_list), 211 len(commit_list),
@@ -377,7 +384,12 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
377 branch.uploaded = False 384 branch.uploaded = False
378 continue 385 continue
379 386
380 branch.UploadForReview(people, auto_topic=opt.auto_topic, draft=opt.draft, dest_branch=destination) 387 branch.UploadForReview(people,
388 auto_topic=opt.auto_topic,
389 draft=opt.draft,
390 private=opt.private,
391 wip=opt.wip,
392 dest_branch=destination)
381 branch.uploaded = True 393 branch.uploaded = True
382 except UploadError as e: 394 except UploadError as e:
383 branch.error = e 395 branch.error = e
@@ -463,8 +475,8 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
463 self.manifest.topdir, 475 self.manifest.topdir,
464 self.manifest.manifestProject.GetRemote('origin').url, 476 self.manifest.manifestProject.GetRemote('origin').url,
465 abort_if_user_denies=True) 477 abort_if_user_denies=True)
466 pending_proj_names = [project.name for (project, avail) in pending] 478 pending_proj_names = [project.name for (project, available) in pending]
467 pending_worktrees = [project.worktree for (project, avail) in pending] 479 pending_worktrees = [project.worktree for (project, available) in pending]
468 try: 480 try:
469 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names, 481 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
470 worktree_list=pending_worktrees) 482 worktree_list=pending_worktrees)