diff options
Diffstat (limited to 'subcmds/start.py')
-rw-r--r-- | subcmds/start.py | 250 |
1 files changed, 139 insertions, 111 deletions
diff --git a/subcmds/start.py b/subcmds/start.py index 809df963..d7772b33 100644 --- a/subcmds/start.py +++ b/subcmds/start.py | |||
@@ -25,119 +25,147 @@ from project import SyncBuffer | |||
25 | 25 | ||
26 | 26 | ||
27 | class Start(Command): | 27 | class Start(Command): |
28 | COMMON = True | 28 | COMMON = True |
29 | helpSummary = "Start a new branch for development" | 29 | helpSummary = "Start a new branch for development" |
30 | helpUsage = """ | 30 | helpUsage = """ |
31 | %prog <newbranchname> [--all | <project>...] | 31 | %prog <newbranchname> [--all | <project>...] |
32 | """ | 32 | """ |
33 | helpDescription = """ | 33 | helpDescription = """ |
34 | '%prog' begins a new branch of development, starting from the | 34 | '%prog' begins a new branch of development, starting from the |
35 | revision specified in the manifest. | 35 | revision specified in the manifest. |
36 | """ | 36 | """ |
37 | PARALLEL_JOBS = DEFAULT_LOCAL_JOBS | 37 | PARALLEL_JOBS = DEFAULT_LOCAL_JOBS |
38 | 38 | ||
39 | def _Options(self, p): | 39 | def _Options(self, p): |
40 | p.add_option('--all', | 40 | p.add_option( |
41 | dest='all', action='store_true', | 41 | "--all", |
42 | help='begin branch in all projects') | 42 | dest="all", |
43 | p.add_option('-r', '--rev', '--revision', dest='revision', | 43 | action="store_true", |
44 | help='point branch at this revision instead of upstream') | 44 | help="begin branch in all projects", |
45 | p.add_option('--head', '--HEAD', | 45 | ) |
46 | dest='revision', action='store_const', const='HEAD', | 46 | p.add_option( |
47 | help='abbreviation for --rev HEAD') | 47 | "-r", |
48 | 48 | "--rev", | |
49 | def ValidateOptions(self, opt, args): | 49 | "--revision", |
50 | if not args: | 50 | dest="revision", |
51 | self.Usage() | 51 | help="point branch at this revision instead of upstream", |
52 | 52 | ) | |
53 | nb = args[0] | 53 | p.add_option( |
54 | if not git.check_ref_format('heads/%s' % nb): | 54 | "--head", |
55 | self.OptionParser.error("'%s' is not a valid name" % nb) | 55 | "--HEAD", |
56 | 56 | dest="revision", | |
57 | def _ExecuteOne(self, revision, nb, project): | 57 | action="store_const", |
58 | """Start one project.""" | 58 | const="HEAD", |
59 | # If the current revision is immutable, such as a SHA1, a tag or | 59 | help="abbreviation for --rev HEAD", |
60 | # a change, then we can't push back to it. Substitute with | 60 | ) |
61 | # dest_branch, if defined; or with manifest default revision instead. | 61 | |
62 | branch_merge = '' | 62 | def ValidateOptions(self, opt, args): |
63 | if IsImmutable(project.revisionExpr): | 63 | if not args: |
64 | if project.dest_branch: | 64 | self.Usage() |
65 | branch_merge = project.dest_branch | 65 | |
66 | else: | 66 | nb = args[0] |
67 | branch_merge = self.manifest.default.revisionExpr | 67 | if not git.check_ref_format("heads/%s" % nb): |
68 | 68 | self.OptionParser.error("'%s' is not a valid name" % nb) | |
69 | try: | 69 | |
70 | ret = project.StartBranch( | 70 | def _ExecuteOne(self, revision, nb, project): |
71 | nb, branch_merge=branch_merge, revision=revision) | 71 | """Start one project.""" |
72 | except Exception as e: | 72 | # If the current revision is immutable, such as a SHA1, a tag or |
73 | print('error: unable to checkout %s: %s' % (project.name, e), file=sys.stderr) | 73 | # a change, then we can't push back to it. Substitute with |
74 | ret = False | 74 | # dest_branch, if defined; or with manifest default revision instead. |
75 | return (ret, project) | 75 | branch_merge = "" |
76 | 76 | if IsImmutable(project.revisionExpr): | |
77 | def Execute(self, opt, args): | 77 | if project.dest_branch: |
78 | nb = args[0] | 78 | branch_merge = project.dest_branch |
79 | err = [] | 79 | else: |
80 | projects = [] | 80 | branch_merge = self.manifest.default.revisionExpr |
81 | if not opt.all: | 81 | |
82 | projects = args[1:] | 82 | try: |
83 | if len(projects) < 1: | 83 | ret = project.StartBranch( |
84 | projects = ['.'] # start it in the local project by default | 84 | nb, branch_merge=branch_merge, revision=revision |
85 | 85 | ) | |
86 | all_projects = self.GetProjects(projects, | 86 | except Exception as e: |
87 | missing_ok=bool(self.gitc_manifest), | 87 | print( |
88 | all_manifests=not opt.this_manifest_only) | 88 | "error: unable to checkout %s: %s" % (project.name, e), |
89 | 89 | file=sys.stderr, | |
90 | # This must happen after we find all_projects, since GetProjects may need | 90 | ) |
91 | # the local directory, which will disappear once we save the GITC manifest. | 91 | ret = False |
92 | if self.gitc_manifest: | 92 | return (ret, project) |
93 | gitc_projects = self.GetProjects(projects, manifest=self.gitc_manifest, | 93 | |
94 | missing_ok=True) | 94 | def Execute(self, opt, args): |
95 | for project in gitc_projects: | 95 | nb = args[0] |
96 | if project.old_revision: | 96 | err = [] |
97 | project.already_synced = True | 97 | projects = [] |
98 | else: | 98 | if not opt.all: |
99 | project.already_synced = False | 99 | projects = args[1:] |
100 | project.old_revision = project.revisionExpr | 100 | if len(projects) < 1: |
101 | project.revisionExpr = None | 101 | projects = ["."] # start it in the local project by default |
102 | # Save the GITC manifest. | 102 | |
103 | gitc_utils.save_manifest(self.gitc_manifest) | 103 | all_projects = self.GetProjects( |
104 | 104 | projects, | |
105 | # Make sure we have a valid CWD | 105 | missing_ok=bool(self.gitc_manifest), |
106 | if not os.path.exists(os.getcwd()): | 106 | all_manifests=not opt.this_manifest_only, |
107 | os.chdir(self.manifest.topdir) | 107 | ) |
108 | 108 | ||
109 | pm = Progress('Syncing %s' % nb, len(all_projects), quiet=opt.quiet) | 109 | # This must happen after we find all_projects, since GetProjects may |
110 | for project in all_projects: | 110 | # need the local directory, which will disappear once we save the GITC |
111 | gitc_project = self.gitc_manifest.paths[project.relpath] | 111 | # manifest. |
112 | # Sync projects that have not been opened. | 112 | if self.gitc_manifest: |
113 | if not gitc_project.already_synced: | 113 | gitc_projects = self.GetProjects( |
114 | proj_localdir = os.path.join(self.gitc_manifest.gitc_client_dir, | 114 | projects, manifest=self.gitc_manifest, missing_ok=True |
115 | project.relpath) | 115 | ) |
116 | project.worktree = proj_localdir | 116 | for project in gitc_projects: |
117 | if not os.path.exists(proj_localdir): | 117 | if project.old_revision: |
118 | os.makedirs(proj_localdir) | 118 | project.already_synced = True |
119 | project.Sync_NetworkHalf() | 119 | else: |
120 | sync_buf = SyncBuffer(self.manifest.manifestProject.config) | 120 | project.already_synced = False |
121 | project.Sync_LocalHalf(sync_buf) | 121 | project.old_revision = project.revisionExpr |
122 | project.revisionId = gitc_project.old_revision | 122 | project.revisionExpr = None |
123 | pm.update() | 123 | # Save the GITC manifest. |
124 | pm.end() | 124 | gitc_utils.save_manifest(self.gitc_manifest) |
125 | 125 | ||
126 | def _ProcessResults(_pool, pm, results): | 126 | # Make sure we have a valid CWD. |
127 | for (result, project) in results: | 127 | if not os.path.exists(os.getcwd()): |
128 | if not result: | 128 | os.chdir(self.manifest.topdir) |
129 | err.append(project) | 129 | |
130 | pm.update() | 130 | pm = Progress("Syncing %s" % nb, len(all_projects), quiet=opt.quiet) |
131 | 131 | for project in all_projects: | |
132 | self.ExecuteInParallel( | 132 | gitc_project = self.gitc_manifest.paths[project.relpath] |
133 | opt.jobs, | 133 | # Sync projects that have not been opened. |
134 | functools.partial(self._ExecuteOne, opt.revision, nb), | 134 | if not gitc_project.already_synced: |
135 | all_projects, | 135 | proj_localdir = os.path.join( |
136 | callback=_ProcessResults, | 136 | self.gitc_manifest.gitc_client_dir, project.relpath |
137 | output=Progress('Starting %s' % (nb,), len(all_projects), quiet=opt.quiet)) | 137 | ) |
138 | 138 | project.worktree = proj_localdir | |
139 | if err: | 139 | if not os.path.exists(proj_localdir): |
140 | for p in err: | 140 | os.makedirs(proj_localdir) |
141 | print("error: %s/: cannot start %s" % (p.RelPath(local=opt.this_manifest_only), nb), | 141 | project.Sync_NetworkHalf() |
142 | file=sys.stderr) | 142 | sync_buf = SyncBuffer(self.manifest.manifestProject.config) |
143 | sys.exit(1) | 143 | project.Sync_LocalHalf(sync_buf) |
144 | project.revisionId = gitc_project.old_revision | ||
145 | pm.update() | ||
146 | pm.end() | ||
147 | |||
148 | def _ProcessResults(_pool, pm, results): | ||
149 | for result, project in results: | ||
150 | if not result: | ||
151 | err.append(project) | ||
152 | pm.update() | ||
153 | |||
154 | self.ExecuteInParallel( | ||
155 | opt.jobs, | ||
156 | functools.partial(self._ExecuteOne, opt.revision, nb), | ||
157 | all_projects, | ||
158 | callback=_ProcessResults, | ||
159 | output=Progress( | ||
160 | "Starting %s" % (nb,), len(all_projects), quiet=opt.quiet | ||
161 | ), | ||
162 | ) | ||
163 | |||
164 | if err: | ||
165 | for p in err: | ||
166 | print( | ||
167 | "error: %s/: cannot start %s" | ||
168 | % (p.RelPath(local=opt.this_manifest_only), nb), | ||
169 | file=sys.stderr, | ||
170 | ) | ||
171 | sys.exit(1) | ||