diff options
| -rw-r--r-- | git_config.py | 12 | ||||
| -rw-r--r-- | git_refs.py | 11 | ||||
| -rw-r--r-- | progress.py | 12 | ||||
| -rw-r--r-- | project.py | 25 | ||||
| -rw-r--r-- | subcmds/download.py | 5 | ||||
| -rw-r--r-- | subcmds/init.py | 2 | ||||
| -rw-r--r-- | subcmds/stage.py | 4 | ||||
| -rw-r--r-- | subcmds/start.py | 10 | ||||
| -rw-r--r-- | subcmds/sync.py | 10 | ||||
| -rw-r--r-- | subcmds/upload.py | 20 |
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: | |||
| 50 | from git_command import GitCommand | 50 | from git_command import GitCommand |
| 51 | from git_command import ssh_sock | 51 | from git_command import ssh_sock |
| 52 | from git_command import terminate_ssh_clients | 52 | from git_command import terminate_ssh_clients |
| 53 | from git_refs import R_CHANGES, R_HEADS, R_TAGS | ||
| 53 | 54 | ||
| 54 | R_HEADS = 'refs/heads/' | ||
| 55 | R_TAGS = 'refs/tags/' | ||
| 56 | ID_RE = re.compile(r'^[0-9a-f]{40}$') | 55 | ID_RE = re.compile(r'^[0-9a-f]{40}$') |
| 57 | 56 | ||
| 58 | REVIEW_CACHE = dict() | 57 | REVIEW_CACHE = dict() |
| 59 | 58 | ||
| 59 | def IsChange(rev): | ||
| 60 | return rev.startswith(R_CHANGES) | ||
| 61 | |||
| 60 | def IsId(rev): | 62 | def IsId(rev): |
| 61 | return ID_RE.match(rev) | 63 | return ID_RE.match(rev) |
| 62 | 64 | ||
| 65 | def IsTag(rev): | ||
| 66 | return rev.startswith(R_TAGS) | ||
| 67 | |||
| 68 | def IsImmutable(rev): | ||
| 69 | return IsChange(rev) or IsId(rev) or IsTag(rev) | ||
| 70 | |||
| 63 | def _key(name): | 71 | def _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 @@ | |||
| 16 | import os | 16 | import os |
| 17 | from trace import Trace | 17 | from trace import Trace |
| 18 | 18 | ||
| 19 | HEAD = 'HEAD' | 19 | HEAD = 'HEAD' |
| 20 | R_HEADS = 'refs/heads/' | 20 | R_CHANGES = 'refs/changes/' |
| 21 | R_TAGS = 'refs/tags/' | 21 | R_HEADS = 'refs/heads/' |
| 22 | R_PUB = 'refs/published/' | 22 | R_TAGS = 'refs/tags/' |
| 23 | R_M = 'refs/remotes/m/' | 23 | R_PUB = 'refs/published/' |
| 24 | R_M = 'refs/remotes/m/' | ||
| 24 | 25 | ||
| 25 | 26 | ||
| 26 | class GitRefs(object): | 27 | class 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 | ||
| 23 | class Progress(object): | 23 | class 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): |
| @@ -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 = """ |
| 32 | The '%prog' command downloads a change from the review system and | 32 | The '%prog' command downloads a change from the review system and |
| 33 | makes it available in your project's local working directory. | 33 | makes it available in your project's local working directory. |
| 34 | If 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 | |||
| 18 | import sys | 18 | import sys |
| 19 | 19 | ||
| 20 | from command import Command | 20 | from command import Command |
| 21 | from git_config import IsId | 21 | from git_config import IsImmutable |
| 22 | from git_command import git | 22 | from git_command import git |
| 23 | import gitc_utils | 23 | import gitc_utils |
| 24 | from progress import Progress | 24 | from 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) |
