diff options
-rw-r--r-- | manifest_xml.py | 14 | ||||
-rw-r--r-- | project.py | 9 | ||||
-rw-r--r-- | subcmds/abandon.py | 71 | ||||
-rw-r--r-- | subcmds/status.py | 12 | ||||
-rw-r--r-- | subcmds/sync.py | 22 |
5 files changed, 88 insertions, 40 deletions
diff --git a/manifest_xml.py b/manifest_xml.py index 9c882af6..0859e1fb 100644 --- a/manifest_xml.py +++ b/manifest_xml.py | |||
@@ -40,8 +40,18 @@ LOCAL_MANIFEST_NAME = 'local_manifest.xml' | |||
40 | LOCAL_MANIFESTS_DIR_NAME = 'local_manifests' | 40 | LOCAL_MANIFESTS_DIR_NAME = 'local_manifests' |
41 | 41 | ||
42 | # urljoin gets confused if the scheme is not known. | 42 | # urljoin gets confused if the scheme is not known. |
43 | urllib.parse.uses_relative.extend(['ssh', 'git', 'persistent-https', 'rpc']) | 43 | urllib.parse.uses_relative.extend([ |
44 | urllib.parse.uses_netloc.extend(['ssh', 'git', 'persistent-https', 'rpc']) | 44 | 'ssh', |
45 | 'git', | ||
46 | 'persistent-https', | ||
47 | 'sso', | ||
48 | 'rpc']) | ||
49 | urllib.parse.uses_netloc.extend([ | ||
50 | 'ssh', | ||
51 | 'git', | ||
52 | 'persistent-https', | ||
53 | 'sso', | ||
54 | 'rpc']) | ||
45 | 55 | ||
46 | class _Default(object): | 56 | class _Default(object): |
47 | """Project defaults within the manifest.""" | 57 | """Project defaults within the manifest.""" |
@@ -911,11 +911,13 @@ class Project(object): | |||
911 | else: | 911 | else: |
912 | return False | 912 | return False |
913 | 913 | ||
914 | def PrintWorkTreeStatus(self, output_redir=None): | 914 | def PrintWorkTreeStatus(self, output_redir=None, quiet=False): |
915 | """Prints the status of the repository to stdout. | 915 | """Prints the status of the repository to stdout. |
916 | 916 | ||
917 | Args: | 917 | Args: |
918 | output: If specified, redirect the output to this object. | 918 | output: If specified, redirect the output to this object. |
919 | quiet: If True then only print the project name. Do not print | ||
920 | the modified files, branch name, etc. | ||
919 | """ | 921 | """ |
920 | if not os.path.isdir(self.worktree): | 922 | if not os.path.isdir(self.worktree): |
921 | if output_redir is None: | 923 | if output_redir is None: |
@@ -941,6 +943,10 @@ class Project(object): | |||
941 | out.redirect(output_redir) | 943 | out.redirect(output_redir) |
942 | out.project('project %-40s', self.relpath + '/ ') | 944 | out.project('project %-40s', self.relpath + '/ ') |
943 | 945 | ||
946 | if quiet: | ||
947 | out.nl() | ||
948 | return 'DIRTY' | ||
949 | |||
944 | branch = self.CurrentBranch | 950 | branch = self.CurrentBranch |
945 | if branch is None: | 951 | if branch is None: |
946 | out.nobranch('(*** NO BRANCH ***)') | 952 | out.nobranch('(*** NO BRANCH ***)') |
@@ -2394,6 +2400,7 @@ class Project(object): | |||
2394 | src = os.path.realpath(os.path.join(srcdir, name)) | 2400 | src = os.path.realpath(os.path.join(srcdir, name)) |
2395 | # Fail if the links are pointing to the wrong place | 2401 | # Fail if the links are pointing to the wrong place |
2396 | if src != dst: | 2402 | if src != dst: |
2403 | _error('%s is different in %s vs %s', name, destdir, srcdir) | ||
2397 | raise GitError('--force-sync not enabled; cannot overwrite a local ' | 2404 | raise GitError('--force-sync not enabled; cannot overwrite a local ' |
2398 | 'work tree. If you\'re comfortable with the ' | 2405 | 'work tree. If you\'re comfortable with the ' |
2399 | 'possibility of losing the work tree\'s git metadata,' | 2406 | 'possibility of losing the work tree\'s git metadata,' |
diff --git a/subcmds/abandon.py b/subcmds/abandon.py index b94ccdd3..6f78da74 100644 --- a/subcmds/abandon.py +++ b/subcmds/abandon.py | |||
@@ -16,6 +16,7 @@ | |||
16 | from __future__ import print_function | 16 | from __future__ import print_function |
17 | import sys | 17 | import sys |
18 | from command import Command | 18 | from command import Command |
19 | from collections import defaultdict | ||
19 | from git_command import git | 20 | from git_command import git |
20 | from progress import Progress | 21 | from progress import Progress |
21 | 22 | ||
@@ -23,49 +24,75 @@ class Abandon(Command): | |||
23 | common = True | 24 | common = True |
24 | helpSummary = "Permanently abandon a development branch" | 25 | helpSummary = "Permanently abandon a development branch" |
25 | helpUsage = """ | 26 | helpUsage = """ |
26 | %prog <branchname> [<project>...] | 27 | %prog [--all | <branchname>] [<project>...] |
27 | 28 | ||
28 | This subcommand permanently abandons a development branch by | 29 | This subcommand permanently abandons a development branch by |
29 | deleting it (and all its history) from your local repository. | 30 | deleting it (and all its history) from your local repository. |
30 | 31 | ||
31 | It is equivalent to "git branch -D <branchname>". | 32 | It is equivalent to "git branch -D <branchname>". |
32 | """ | 33 | """ |
34 | def _Options(self, p): | ||
35 | p.add_option('--all', | ||
36 | dest='all', action='store_true', | ||
37 | help='delete all branches in all projects') | ||
33 | 38 | ||
34 | def Execute(self, opt, args): | 39 | def Execute(self, opt, args): |
35 | if not args: | 40 | if not opt.all and not args: |
36 | self.Usage() | 41 | self.Usage() |
37 | 42 | ||
38 | nb = args[0] | 43 | if not opt.all: |
39 | if not git.check_ref_format('heads/%s' % nb): | 44 | nb = args[0] |
40 | print("error: '%s' is not a valid name" % nb, file=sys.stderr) | 45 | if not git.check_ref_format('heads/%s' % nb): |
41 | sys.exit(1) | 46 | print("error: '%s' is not a valid name" % nb, file=sys.stderr) |
47 | sys.exit(1) | ||
48 | else: | ||
49 | args.insert(0,None) | ||
50 | nb = "'All local branches'" | ||
42 | 51 | ||
43 | nb = args[0] | 52 | err = defaultdict(list) |
44 | err = [] | 53 | success = defaultdict(list) |
45 | success = [] | ||
46 | all_projects = self.GetProjects(args[1:]) | 54 | all_projects = self.GetProjects(args[1:]) |
47 | 55 | ||
48 | pm = Progress('Abandon %s' % nb, len(all_projects)) | 56 | pm = Progress('Abandon %s' % nb, len(all_projects)) |
49 | for project in all_projects: | 57 | for project in all_projects: |
50 | pm.update() | 58 | pm.update() |
51 | 59 | ||
52 | status = project.AbandonBranch(nb) | 60 | if opt.all: |
53 | if status is not None: | 61 | branches = project.GetBranches().keys() |
54 | if status: | 62 | else: |
55 | success.append(project) | 63 | branches = [nb] |
56 | else: | 64 | |
57 | err.append(project) | 65 | for name in branches: |
66 | status = project.AbandonBranch(name) | ||
67 | if status is not None: | ||
68 | if status: | ||
69 | success[name].append(project) | ||
70 | else: | ||
71 | err[name].append(project) | ||
58 | pm.end() | 72 | pm.end() |
59 | 73 | ||
74 | width = 25 | ||
75 | for name in branches: | ||
76 | if width < len(name): | ||
77 | width = len(name) | ||
78 | |||
60 | if err: | 79 | if err: |
61 | for p in err: | 80 | for br in err.keys(): |
62 | print("error: %s/: cannot abandon %s" % (p.relpath, nb), | 81 | err_msg = "error: cannot abandon %s" %br |
63 | file=sys.stderr) | 82 | print(err_msg, file=sys.stderr) |
83 | for proj in err[br]: | ||
84 | print(' '*len(err_msg) + " | %s" % p.relpath, file=sys.stderr) | ||
64 | sys.exit(1) | 85 | sys.exit(1) |
65 | elif not success: | 86 | elif not success: |
66 | print('error: no project has branch %s' % nb, file=sys.stderr) | 87 | print('error: no project has local branch(es) : %s' % nb, |
88 | file=sys.stderr) | ||
67 | sys.exit(1) | 89 | sys.exit(1) |
68 | else: | 90 | else: |
69 | print('Abandoned in %d project(s):\n %s' | 91 | print('Abandoned branches:', file=sys.stderr) |
70 | % (len(success), '\n '.join(p.relpath for p in success)), | 92 | for br in success.keys(): |
71 | file=sys.stderr) | 93 | if len(all_projects) > 1 and len(all_projects) == len(success[br]): |
94 | result = "all project" | ||
95 | else: | ||
96 | result = "%s" % ( | ||
97 | ('\n'+' '*width + '| ').join(p.relpath for p in success[br])) | ||
98 | print("%s%s| %s\n" % (br,' '*(width-len(br)), result),file=sys.stderr) | ||
diff --git a/subcmds/status.py b/subcmds/status.py index 38c229b1..60e26ff4 100644 --- a/subcmds/status.py +++ b/subcmds/status.py | |||
@@ -89,8 +89,10 @@ the following meanings: | |||
89 | p.add_option('-o', '--orphans', | 89 | p.add_option('-o', '--orphans', |
90 | dest='orphans', action='store_true', | 90 | dest='orphans', action='store_true', |
91 | help="include objects in working directory outside of repo projects") | 91 | help="include objects in working directory outside of repo projects") |
92 | p.add_option('-q', '--quiet', action='store_true', | ||
93 | help="only print the name of modified projects") | ||
92 | 94 | ||
93 | def _StatusHelper(self, project, clean_counter, sem): | 95 | def _StatusHelper(self, project, clean_counter, sem, quiet): |
94 | """Obtains the status for a specific project. | 96 | """Obtains the status for a specific project. |
95 | 97 | ||
96 | Obtains the status for a project, redirecting the output to | 98 | Obtains the status for a project, redirecting the output to |
@@ -104,7 +106,7 @@ the following meanings: | |||
104 | output: Where to output the status. | 106 | output: Where to output the status. |
105 | """ | 107 | """ |
106 | try: | 108 | try: |
107 | state = project.PrintWorkTreeStatus() | 109 | state = project.PrintWorkTreeStatus(quiet=quiet) |
108 | if state == 'CLEAN': | 110 | if state == 'CLEAN': |
109 | next(clean_counter) | 111 | next(clean_counter) |
110 | finally: | 112 | finally: |
@@ -132,7 +134,7 @@ the following meanings: | |||
132 | 134 | ||
133 | if opt.jobs == 1: | 135 | if opt.jobs == 1: |
134 | for project in all_projects: | 136 | for project in all_projects: |
135 | state = project.PrintWorkTreeStatus() | 137 | state = project.PrintWorkTreeStatus(quiet=opt.quiet) |
136 | if state == 'CLEAN': | 138 | if state == 'CLEAN': |
137 | next(counter) | 139 | next(counter) |
138 | else: | 140 | else: |
@@ -142,13 +144,13 @@ the following meanings: | |||
142 | sem.acquire() | 144 | sem.acquire() |
143 | 145 | ||
144 | t = _threading.Thread(target=self._StatusHelper, | 146 | t = _threading.Thread(target=self._StatusHelper, |
145 | args=(project, counter, sem)) | 147 | args=(project, counter, sem, opt.quiet)) |
146 | threads.append(t) | 148 | threads.append(t) |
147 | t.daemon = True | 149 | t.daemon = True |
148 | t.start() | 150 | t.start() |
149 | for t in threads: | 151 | for t in threads: |
150 | t.join() | 152 | t.join() |
151 | if len(all_projects) == next(counter): | 153 | if not opt.quiet and len(all_projects) == next(counter): |
152 | print('nothing to commit (working directory clean)') | 154 | print('nothing to commit (working directory clean)') |
153 | 155 | ||
154 | if opt.orphans: | 156 | if opt.orphans: |
diff --git a/subcmds/sync.py b/subcmds/sync.py index 7ba9ebfc..bbb166c0 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
@@ -255,7 +255,7 @@ later is required to fix a server side protocol bug. | |||
255 | dest='repo_upgraded', action='store_true', | 255 | dest='repo_upgraded', action='store_true', |
256 | help=SUPPRESS_HELP) | 256 | help=SUPPRESS_HELP) |
257 | 257 | ||
258 | def _FetchProjectList(self, opt, projects, *args, **kwargs): | 258 | def _FetchProjectList(self, opt, projects, sem, *args, **kwargs): |
259 | """Main function of the fetch threads when jobs are > 1. | 259 | """Main function of the fetch threads when jobs are > 1. |
260 | 260 | ||
261 | Delegates most of the work to _FetchHelper. | 261 | Delegates most of the work to _FetchHelper. |
@@ -263,15 +263,20 @@ later is required to fix a server side protocol bug. | |||
263 | Args: | 263 | Args: |
264 | opt: Program options returned from optparse. See _Options(). | 264 | opt: Program options returned from optparse. See _Options(). |
265 | projects: Projects to fetch. | 265 | projects: Projects to fetch. |
266 | sem: We'll release() this semaphore when we exit so that another thread | ||
267 | can be started up. | ||
266 | *args, **kwargs: Remaining arguments to pass to _FetchHelper. See the | 268 | *args, **kwargs: Remaining arguments to pass to _FetchHelper. See the |
267 | _FetchHelper docstring for details. | 269 | _FetchHelper docstring for details. |
268 | """ | 270 | """ |
269 | for project in projects: | 271 | try: |
270 | success = self._FetchHelper(opt, project, *args, **kwargs) | 272 | for project in projects: |
271 | if not success and not opt.force_broken: | 273 | success = self._FetchHelper(opt, project, *args, **kwargs) |
272 | break | 274 | if not success and not opt.force_broken: |
275 | break | ||
276 | finally: | ||
277 | sem.release() | ||
273 | 278 | ||
274 | def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event): | 279 | def _FetchHelper(self, opt, project, lock, fetched, pm, err_event): |
275 | """Fetch git objects for a single project. | 280 | """Fetch git objects for a single project. |
276 | 281 | ||
277 | Args: | 282 | Args: |
@@ -283,8 +288,6 @@ later is required to fix a server side protocol bug. | |||
283 | (with our lock held). | 288 | (with our lock held). |
284 | pm: Instance of a Project object. We will call pm.update() (with our | 289 | pm: Instance of a Project object. We will call pm.update() (with our |
285 | lock held). | 290 | lock held). |
286 | sem: We'll release() this semaphore when we exit so that another thread | ||
287 | can be started up. | ||
288 | err_event: We'll set this event in the case of an error (after printing | 291 | err_event: We'll set this event in the case of an error (after printing |
289 | out info about the error). | 292 | out info about the error). |
290 | 293 | ||
@@ -340,7 +343,6 @@ later is required to fix a server side protocol bug. | |||
340 | finally: | 343 | finally: |
341 | if did_lock: | 344 | if did_lock: |
342 | lock.release() | 345 | lock.release() |
343 | sem.release() | ||
344 | 346 | ||
345 | return success | 347 | return success |
346 | 348 | ||
@@ -365,10 +367,10 @@ later is required to fix a server side protocol bug. | |||
365 | sem.acquire() | 367 | sem.acquire() |
366 | kwargs = dict(opt=opt, | 368 | kwargs = dict(opt=opt, |
367 | projects=project_list, | 369 | projects=project_list, |
370 | sem=sem, | ||
368 | lock=lock, | 371 | lock=lock, |
369 | fetched=fetched, | 372 | fetched=fetched, |
370 | pm=pm, | 373 | pm=pm, |
371 | sem=sem, | ||
372 | err_event=err_event) | 374 | err_event=err_event) |
373 | if self.jobs > 1: | 375 | if self.jobs > 1: |
374 | t = _threading.Thread(target = self._FetchProjectList, | 376 | t = _threading.Thread(target = self._FetchProjectList, |