diff options
Diffstat (limited to 'subcmds')
| -rw-r--r-- | subcmds/branches.py | 2 | ||||
| -rw-r--r-- | subcmds/init.py | 21 | ||||
| -rw-r--r-- | subcmds/rebase.py | 3 | ||||
| -rw-r--r-- | subcmds/sync.py | 67 | ||||
| -rw-r--r-- | subcmds/upload.py | 15 |
5 files changed, 88 insertions, 20 deletions
diff --git a/subcmds/branches.py b/subcmds/branches.py index c2e7c4b9..f714c1e8 100644 --- a/subcmds/branches.py +++ b/subcmds/branches.py | |||
| @@ -139,7 +139,7 @@ is shown, then the branch appears in all projects. | |||
| 139 | if in_cnt < project_cnt: | 139 | if in_cnt < project_cnt: |
| 140 | fmt = out.write | 140 | fmt = out.write |
| 141 | paths = [] | 141 | paths = [] |
| 142 | if in_cnt < project_cnt - in_cnt: | 142 | if in_cnt < project_cnt - in_cnt: |
| 143 | in_type = 'in' | 143 | in_type = 'in' |
| 144 | for b in i.projects: | 144 | for b in i.projects: |
| 145 | paths.append(b.project.relpath) | 145 | paths.append(b.project.relpath) |
diff --git a/subcmds/init.py b/subcmds/init.py index a44fb7a9..b1fcb69c 100644 --- a/subcmds/init.py +++ b/subcmds/init.py | |||
| @@ -99,6 +99,10 @@ to update the working directory files. | |||
| 99 | g.add_option('--depth', type='int', default=None, | 99 | g.add_option('--depth', type='int', default=None, |
| 100 | dest='depth', | 100 | dest='depth', |
| 101 | help='create a shallow clone with given depth; see git clone') | 101 | help='create a shallow clone with given depth; see git clone') |
| 102 | g.add_option('--archive', | ||
| 103 | dest='archive', action='store_true', | ||
| 104 | help='checkout an archive instead of a git repository for ' | ||
| 105 | 'each project. See git archive.') | ||
| 102 | g.add_option('-g', '--groups', | 106 | g.add_option('-g', '--groups', |
| 103 | dest='groups', default='default', | 107 | dest='groups', default='default', |
| 104 | help='restrict manifest projects to ones with specified ' | 108 | help='restrict manifest projects to ones with specified ' |
| @@ -198,6 +202,16 @@ to update the working directory files. | |||
| 198 | if opt.reference: | 202 | if opt.reference: |
| 199 | m.config.SetString('repo.reference', opt.reference) | 203 | m.config.SetString('repo.reference', opt.reference) |
| 200 | 204 | ||
| 205 | if opt.archive: | ||
| 206 | if is_new: | ||
| 207 | m.config.SetString('repo.archive', 'true') | ||
| 208 | else: | ||
| 209 | print('fatal: --archive is only supported when initializing a new ' | ||
| 210 | 'workspace.', file=sys.stderr) | ||
| 211 | print('Either delete the .repo folder in this workspace, or initialize ' | ||
| 212 | 'in another location.', file=sys.stderr) | ||
| 213 | sys.exit(1) | ||
| 214 | |||
| 201 | if opt.mirror: | 215 | if opt.mirror: |
| 202 | if is_new: | 216 | if is_new: |
| 203 | m.config.SetString('repo.mirror', 'true') | 217 | m.config.SetString('repo.mirror', 'true') |
| @@ -366,6 +380,13 @@ to update the working directory files. | |||
| 366 | if opt.reference: | 380 | if opt.reference: |
| 367 | opt.reference = os.path.expanduser(opt.reference) | 381 | opt.reference = os.path.expanduser(opt.reference) |
| 368 | 382 | ||
| 383 | # Check this here, else manifest will be tagged "not new" and init won't be | ||
| 384 | # possible anymore without removing the .repo/manifests directory. | ||
| 385 | if opt.archive and opt.mirror: | ||
| 386 | print('fatal: --mirror and --archive cannot be used together.', | ||
| 387 | file=sys.stderr) | ||
| 388 | sys.exit(1) | ||
| 389 | |||
| 369 | self._SyncManifest(opt) | 390 | self._SyncManifest(opt) |
| 370 | self._LinkManifest(opt.manifest_name) | 391 | self._LinkManifest(opt.manifest_name) |
| 371 | 392 | ||
diff --git a/subcmds/rebase.py b/subcmds/rebase.py index b9a7774d..1bdc1f0b 100644 --- a/subcmds/rebase.py +++ b/subcmds/rebase.py | |||
| @@ -62,6 +62,9 @@ branch but need to incorporate new upstream changes "underneath" them. | |||
| 62 | if opt.interactive and not one_project: | 62 | if opt.interactive and not one_project: |
| 63 | print('error: interactive rebase not supported with multiple projects', | 63 | print('error: interactive rebase not supported with multiple projects', |
| 64 | file=sys.stderr) | 64 | file=sys.stderr) |
| 65 | if len(args) == 1: | ||
| 66 | print('note: project %s is mapped to more than one path' % (args[0],), | ||
| 67 | file=sys.stderr) | ||
| 65 | return -1 | 68 | return -1 |
| 66 | 69 | ||
| 67 | for project in all_projects: | 70 | for project in all_projects: |
diff --git a/subcmds/sync.py b/subcmds/sync.py index e9d52b7b..5e7385db 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
| @@ -219,9 +219,25 @@ later is required to fix a server side protocol bug. | |||
| 219 | dest='repo_upgraded', action='store_true', | 219 | dest='repo_upgraded', action='store_true', |
| 220 | help=SUPPRESS_HELP) | 220 | help=SUPPRESS_HELP) |
| 221 | 221 | ||
| 222 | def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event): | 222 | def _FetchProjectList(self, opt, projects, *args): |
| 223 | """Main function of the fetch threads when jobs are > 1. | 223 | """Main function of the fetch threads when jobs are > 1. |
| 224 | 224 | ||
| 225 | Delegates most of the work to _FetchHelper. | ||
| 226 | |||
| 227 | Args: | ||
| 228 | opt: Program options returned from optparse. See _Options(). | ||
| 229 | projects: Projects to fetch. | ||
| 230 | *args: Remaining arguments to pass to _FetchHelper. See the | ||
| 231 | _FetchHelper docstring for details. | ||
| 232 | """ | ||
| 233 | for project in projects: | ||
| 234 | success = self._FetchHelper(opt, project, *args) | ||
| 235 | if not success and not opt.force_broken: | ||
| 236 | break | ||
| 237 | |||
| 238 | def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event): | ||
| 239 | """Fetch git objects for a single project. | ||
| 240 | |||
| 225 | Args: | 241 | Args: |
| 226 | opt: Program options returned from optparse. See _Options(). | 242 | opt: Program options returned from optparse. See _Options(). |
| 227 | project: Project object for the project to fetch. | 243 | project: Project object for the project to fetch. |
| @@ -235,6 +251,9 @@ later is required to fix a server side protocol bug. | |||
| 235 | can be started up. | 251 | can be started up. |
| 236 | err_event: We'll set this event in the case of an error (after printing | 252 | err_event: We'll set this event in the case of an error (after printing |
| 237 | out info about the error). | 253 | out info about the error). |
| 254 | |||
| 255 | Returns: | ||
| 256 | Whether the fetch was successful. | ||
| 238 | """ | 257 | """ |
| 239 | # We'll set to true once we've locked the lock. | 258 | # We'll set to true once we've locked the lock. |
| 240 | did_lock = False | 259 | did_lock = False |
| @@ -253,7 +272,7 @@ later is required to fix a server side protocol bug. | |||
| 253 | quiet=opt.quiet, | 272 | quiet=opt.quiet, |
| 254 | current_branch_only=opt.current_branch_only, | 273 | current_branch_only=opt.current_branch_only, |
| 255 | clone_bundle=not opt.no_clone_bundle, | 274 | clone_bundle=not opt.no_clone_bundle, |
| 256 | no_tags=opt.no_tags) | 275 | no_tags=opt.no_tags, archive=self.manifest.IsArchive) |
| 257 | self._fetch_times.Set(project, time.time() - start) | 276 | self._fetch_times.Set(project, time.time() - start) |
| 258 | 277 | ||
| 259 | # Lock around all the rest of the code, since printing, updating a set | 278 | # Lock around all the rest of the code, since printing, updating a set |
| @@ -281,6 +300,8 @@ later is required to fix a server side protocol bug. | |||
| 281 | lock.release() | 300 | lock.release() |
| 282 | sem.release() | 301 | sem.release() |
| 283 | 302 | ||
| 303 | return success | ||
| 304 | |||
| 284 | def _Fetch(self, projects, opt): | 305 | def _Fetch(self, projects, opt): |
| 285 | fetched = set() | 306 | fetched = set() |
| 286 | pm = Progress('Fetching projects', len(projects)) | 307 | pm = Progress('Fetching projects', len(projects)) |
| @@ -294,7 +315,8 @@ later is required to fix a server side protocol bug. | |||
| 294 | quiet=opt.quiet, | 315 | quiet=opt.quiet, |
| 295 | current_branch_only=opt.current_branch_only, | 316 | current_branch_only=opt.current_branch_only, |
| 296 | clone_bundle=not opt.no_clone_bundle, | 317 | clone_bundle=not opt.no_clone_bundle, |
| 297 | no_tags=opt.no_tags): | 318 | no_tags=opt.no_tags, |
| 319 | archive=self.manifest.IsArchive): | ||
| 298 | fetched.add(project.gitdir) | 320 | fetched.add(project.gitdir) |
| 299 | else: | 321 | else: |
| 300 | print('error: Cannot fetch %s' % project.name, file=sys.stderr) | 322 | print('error: Cannot fetch %s' % project.name, file=sys.stderr) |
| @@ -303,20 +325,24 @@ later is required to fix a server side protocol bug. | |||
| 303 | else: | 325 | else: |
| 304 | sys.exit(1) | 326 | sys.exit(1) |
| 305 | else: | 327 | else: |
| 328 | objdir_project_map = dict() | ||
| 329 | for project in projects: | ||
| 330 | objdir_project_map.setdefault(project.objdir, []).append(project) | ||
| 331 | |||
| 306 | threads = set() | 332 | threads = set() |
| 307 | lock = _threading.Lock() | 333 | lock = _threading.Lock() |
| 308 | sem = _threading.Semaphore(self.jobs) | 334 | sem = _threading.Semaphore(self.jobs) |
| 309 | err_event = _threading.Event() | 335 | err_event = _threading.Event() |
| 310 | for project in projects: | 336 | for project_list in objdir_project_map.values(): |
| 311 | # Check for any errors before starting any new threads. | 337 | # Check for any errors before starting any new threads. |
| 312 | # ...we'll let existing threads finish, though. | 338 | # ...we'll let existing threads finish, though. |
| 313 | if err_event.isSet(): | 339 | if err_event.isSet(): |
| 314 | break | 340 | break |
| 315 | 341 | ||
| 316 | sem.acquire() | 342 | sem.acquire() |
| 317 | t = _threading.Thread(target = self._FetchHelper, | 343 | t = _threading.Thread(target = self._FetchProjectList, |
| 318 | args = (opt, | 344 | args = (opt, |
| 319 | project, | 345 | project_list, |
| 320 | lock, | 346 | lock, |
| 321 | fetched, | 347 | fetched, |
| 322 | pm, | 348 | pm, |
| @@ -338,10 +364,16 @@ later is required to fix a server side protocol bug. | |||
| 338 | pm.end() | 364 | pm.end() |
| 339 | self._fetch_times.Save() | 365 | self._fetch_times.Save() |
| 340 | 366 | ||
| 341 | self._GCProjects(projects) | 367 | if not self.manifest.IsArchive: |
| 368 | self._GCProjects(projects) | ||
| 369 | |||
| 342 | return fetched | 370 | return fetched |
| 343 | 371 | ||
| 344 | def _GCProjects(self, projects): | 372 | def _GCProjects(self, projects): |
| 373 | gitdirs = {} | ||
| 374 | for project in projects: | ||
| 375 | gitdirs[project.gitdir] = project.bare_git | ||
| 376 | |||
| 345 | has_dash_c = git_require((1, 7, 2)) | 377 | has_dash_c = git_require((1, 7, 2)) |
| 346 | if multiprocessing and has_dash_c: | 378 | if multiprocessing and has_dash_c: |
| 347 | cpu_count = multiprocessing.cpu_count() | 379 | cpu_count = multiprocessing.cpu_count() |
| @@ -350,8 +382,8 @@ later is required to fix a server side protocol bug. | |||
| 350 | jobs = min(self.jobs, cpu_count) | 382 | jobs = min(self.jobs, cpu_count) |
| 351 | 383 | ||
| 352 | if jobs < 2: | 384 | if jobs < 2: |
| 353 | for project in projects: | 385 | for bare_git in gitdirs.values(): |
| 354 | project.bare_git.gc('--auto') | 386 | bare_git.gc('--auto') |
| 355 | return | 387 | return |
| 356 | 388 | ||
| 357 | config = {'pack.threads': cpu_count / jobs if cpu_count > jobs else 1} | 389 | config = {'pack.threads': cpu_count / jobs if cpu_count > jobs else 1} |
| @@ -360,10 +392,10 @@ later is required to fix a server side protocol bug. | |||
| 360 | sem = _threading.Semaphore(jobs) | 392 | sem = _threading.Semaphore(jobs) |
| 361 | err_event = _threading.Event() | 393 | err_event = _threading.Event() |
| 362 | 394 | ||
| 363 | def GC(project): | 395 | def GC(bare_git): |
| 364 | try: | 396 | try: |
| 365 | try: | 397 | try: |
| 366 | project.bare_git.gc('--auto', config=config) | 398 | bare_git.gc('--auto', config=config) |
| 367 | except GitError: | 399 | except GitError: |
| 368 | err_event.set() | 400 | err_event.set() |
| 369 | except: | 401 | except: |
| @@ -372,11 +404,11 @@ later is required to fix a server side protocol bug. | |||
| 372 | finally: | 404 | finally: |
| 373 | sem.release() | 405 | sem.release() |
| 374 | 406 | ||
| 375 | for project in projects: | 407 | for bare_git in gitdirs.values(): |
| 376 | if err_event.isSet(): | 408 | if err_event.isSet(): |
| 377 | break | 409 | break |
| 378 | sem.acquire() | 410 | sem.acquire() |
| 379 | t = _threading.Thread(target=GC, args=(project,)) | 411 | t = _threading.Thread(target=GC, args=(bare_git,)) |
| 380 | t.daemon = True | 412 | t.daemon = True |
| 381 | threads.add(t) | 413 | threads.add(t) |
| 382 | t.start() | 414 | t.start() |
| @@ -416,12 +448,13 @@ later is required to fix a server side protocol bug. | |||
| 416 | if path not in new_project_paths: | 448 | if path not in new_project_paths: |
| 417 | # If the path has already been deleted, we don't need to do it | 449 | # If the path has already been deleted, we don't need to do it |
| 418 | if os.path.exists(self.manifest.topdir + '/' + path): | 450 | if os.path.exists(self.manifest.topdir + '/' + path): |
| 451 | gitdir = os.path.join(self.manifest.topdir, path, '.git') | ||
| 419 | project = Project( | 452 | project = Project( |
| 420 | manifest = self.manifest, | 453 | manifest = self.manifest, |
| 421 | name = path, | 454 | name = path, |
| 422 | remote = RemoteSpec('origin'), | 455 | remote = RemoteSpec('origin'), |
| 423 | gitdir = os.path.join(self.manifest.topdir, | 456 | gitdir = gitdir, |
| 424 | path, '.git'), | 457 | objdir = gitdir, |
| 425 | worktree = os.path.join(self.manifest.topdir, path), | 458 | worktree = os.path.join(self.manifest.topdir, path), |
| 426 | relpath = path, | 459 | relpath = path, |
| 427 | revisionExpr = 'HEAD', | 460 | revisionExpr = 'HEAD', |
| @@ -641,7 +674,7 @@ later is required to fix a server side protocol bug. | |||
| 641 | previously_missing_set = missing_set | 674 | previously_missing_set = missing_set |
| 642 | fetched.update(self._Fetch(missing, opt)) | 675 | fetched.update(self._Fetch(missing, opt)) |
| 643 | 676 | ||
| 644 | if self.manifest.IsMirror: | 677 | if self.manifest.IsMirror or self.manifest.IsArchive: |
| 645 | # bail out now, we have no working tree | 678 | # bail out now, we have no working tree |
| 646 | return | 679 | return |
| 647 | 680 | ||
| @@ -761,7 +794,7 @@ class _FetchTimes(object): | |||
| 761 | def _Load(self): | 794 | def _Load(self): |
| 762 | if self._times is None: | 795 | if self._times is None: |
| 763 | try: | 796 | try: |
| 764 | f = open(self._path) | 797 | f = open(self._path, 'rb') |
| 765 | except IOError: | 798 | except IOError: |
| 766 | self._times = {} | 799 | self._times = {} |
| 767 | return self._times | 800 | return self._times |
diff --git a/subcmds/upload.py b/subcmds/upload.py index 7f7585ae..526dcd57 100644 --- a/subcmds/upload.py +++ b/subcmds/upload.py | |||
| @@ -422,7 +422,16 @@ Gerrit Code Review: http://code.google.com/p/gerrit/ | |||
| 422 | for project in project_list: | 422 | for project in project_list: |
| 423 | if opt.current_branch: | 423 | if opt.current_branch: |
| 424 | cbr = project.CurrentBranch | 424 | cbr = project.CurrentBranch |
| 425 | avail = [project.GetUploadableBranch(cbr)] if cbr else None | 425 | up_branch = project.GetUploadableBranch(cbr) |
| 426 | if up_branch: | ||
| 427 | avail = [up_branch] | ||
| 428 | else: | ||
| 429 | avail = None | ||
| 430 | print('ERROR: Current branch (%s) not uploadable. ' | ||
| 431 | 'You may be able to type ' | ||
| 432 | '"git branch --set-upstream-to m/master" to fix ' | ||
| 433 | 'your branch.' % str(cbr), | ||
| 434 | file=sys.stderr) | ||
| 426 | else: | 435 | else: |
| 427 | avail = project.GetUploadableBranches(branch) | 436 | avail = project.GetUploadableBranches(branch) |
| 428 | if avail: | 437 | if avail: |
| @@ -432,8 +441,10 @@ Gerrit Code Review: http://code.google.com/p/gerrit/ | |||
| 432 | hook = RepoHook('pre-upload', self.manifest.repo_hooks_project, | 441 | hook = RepoHook('pre-upload', self.manifest.repo_hooks_project, |
| 433 | self.manifest.topdir, abort_if_user_denies=True) | 442 | self.manifest.topdir, abort_if_user_denies=True) |
| 434 | pending_proj_names = [project.name for (project, avail) in pending] | 443 | pending_proj_names = [project.name for (project, avail) in pending] |
| 444 | pending_worktrees = [project.worktree for (project, avail) in pending] | ||
| 435 | try: | 445 | try: |
| 436 | hook.Run(opt.allow_all_hooks, project_list=pending_proj_names) | 446 | hook.Run(opt.allow_all_hooks, project_list=pending_proj_names, |
| 447 | worktree_list=pending_worktrees) | ||
| 437 | except HookError as e: | 448 | except HookError as e: |
| 438 | print("ERROR: %s" % str(e), file=sys.stderr) | 449 | print("ERROR: %s" % str(e), file=sys.stderr) |
| 439 | return | 450 | return |
