diff options
Diffstat (limited to 'manifest_xml.py')
-rw-r--r-- | manifest_xml.py | 331 |
1 files changed, 243 insertions, 88 deletions
diff --git a/manifest_xml.py b/manifest_xml.py index 1d02f9d4..26cc14f6 100644 --- a/manifest_xml.py +++ b/manifest_xml.py | |||
@@ -13,53 +13,75 @@ | |||
13 | # See the License for the specific language governing permissions and | 13 | # See the License for the specific language governing permissions and |
14 | # limitations under the License. | 14 | # limitations under the License. |
15 | 15 | ||
16 | import itertools | ||
16 | import os | 17 | import os |
18 | import re | ||
17 | import sys | 19 | import sys |
20 | import urlparse | ||
18 | import xml.dom.minidom | 21 | import xml.dom.minidom |
19 | 22 | ||
20 | from git_config import GitConfig | 23 | from git_config import GitConfig, IsId |
21 | from git_config import IsId | 24 | from project import RemoteSpec, Project, MetaProject, R_HEADS, HEAD |
22 | from manifest import Manifest | ||
23 | from project import RemoteSpec | ||
24 | from project import Project | ||
25 | from project import MetaProject | ||
26 | from project import R_HEADS | ||
27 | from project import HEAD | ||
28 | from error import ManifestParseError | 25 | from error import ManifestParseError |
29 | 26 | ||
30 | MANIFEST_FILE_NAME = 'manifest.xml' | 27 | MANIFEST_FILE_NAME = 'manifest.xml' |
31 | LOCAL_MANIFEST_NAME = 'local_manifest.xml' | 28 | LOCAL_MANIFEST_NAME = 'local_manifest.xml' |
32 | R_M = 'refs/remotes/m/' | 29 | |
30 | urlparse.uses_relative.extend(['ssh', 'git']) | ||
31 | urlparse.uses_netloc.extend(['ssh', 'git']) | ||
33 | 32 | ||
34 | class _Default(object): | 33 | class _Default(object): |
35 | """Project defaults within the manifest.""" | 34 | """Project defaults within the manifest.""" |
36 | 35 | ||
37 | revisionExpr = None | 36 | revisionExpr = None |
38 | remote = None | 37 | remote = None |
38 | sync_j = 1 | ||
39 | sync_c = False | ||
39 | 40 | ||
40 | class _XmlRemote(object): | 41 | class _XmlRemote(object): |
41 | def __init__(self, | 42 | def __init__(self, |
42 | name, | 43 | name, |
44 | alias=None, | ||
43 | fetch=None, | 45 | fetch=None, |
46 | manifestUrl=None, | ||
44 | review=None): | 47 | review=None): |
45 | self.name = name | 48 | self.name = name |
46 | self.fetchUrl = fetch | 49 | self.fetchUrl = fetch |
50 | self.manifestUrl = manifestUrl | ||
51 | self.remoteAlias = alias | ||
47 | self.reviewUrl = review | 52 | self.reviewUrl = review |
53 | self.resolvedFetchUrl = self._resolveFetchUrl() | ||
54 | |||
55 | def _resolveFetchUrl(self): | ||
56 | url = self.fetchUrl.rstrip('/') | ||
57 | manifestUrl = self.manifestUrl.rstrip('/') | ||
58 | # urljoin will get confused if there is no scheme in the base url | ||
59 | # ie, if manifestUrl is of the form <hostname:port> | ||
60 | if manifestUrl.find(':') != manifestUrl.find('/') - 1: | ||
61 | manifestUrl = 'gopher://' + manifestUrl | ||
62 | url = urlparse.urljoin(manifestUrl, url) | ||
63 | return re.sub(r'^gopher://', '', url) | ||
48 | 64 | ||
49 | def ToRemoteSpec(self, projectName): | 65 | def ToRemoteSpec(self, projectName): |
50 | url = self.fetchUrl | 66 | url = self.resolvedFetchUrl.rstrip('/') + '/' + projectName |
51 | while url.endswith('/'): | 67 | remoteName = self.name |
52 | url = url[:-1] | 68 | if self.remoteAlias: |
53 | url += '/%s.git' % projectName | 69 | remoteName = self.remoteAlias |
54 | return RemoteSpec(self.name, url, self.reviewUrl) | 70 | return RemoteSpec(remoteName, url, self.reviewUrl) |
55 | 71 | ||
56 | class XmlManifest(Manifest): | 72 | class XmlManifest(object): |
57 | """manages the repo configuration file""" | 73 | """manages the repo configuration file""" |
58 | 74 | ||
59 | def __init__(self, repodir): | 75 | def __init__(self, repodir): |
60 | Manifest.__init__(self, repodir) | 76 | self.repodir = os.path.abspath(repodir) |
77 | self.topdir = os.path.dirname(self.repodir) | ||
78 | self.manifestFile = os.path.join(self.repodir, MANIFEST_FILE_NAME) | ||
79 | self.globalConfig = GitConfig.ForUser() | ||
80 | |||
81 | self.repoProject = MetaProject(self, 'repo', | ||
82 | gitdir = os.path.join(repodir, 'repo/.git'), | ||
83 | worktree = os.path.join(repodir, 'repo')) | ||
61 | 84 | ||
62 | self._manifestFile = os.path.join(repodir, MANIFEST_FILE_NAME) | ||
63 | self.manifestProject = MetaProject(self, 'manifests', | 85 | self.manifestProject = MetaProject(self, 'manifests', |
64 | gitdir = os.path.join(repodir, 'manifests.git'), | 86 | gitdir = os.path.join(repodir, 'manifests.git'), |
65 | worktree = os.path.join(repodir, 'manifests')) | 87 | worktree = os.path.join(repodir, 'manifests')) |
@@ -73,13 +95,13 @@ class XmlManifest(Manifest): | |||
73 | if not os.path.isfile(path): | 95 | if not os.path.isfile(path): |
74 | raise ManifestParseError('manifest %s not found' % name) | 96 | raise ManifestParseError('manifest %s not found' % name) |
75 | 97 | ||
76 | old = self._manifestFile | 98 | old = self.manifestFile |
77 | try: | 99 | try: |
78 | self._manifestFile = path | 100 | self.manifestFile = path |
79 | self._Unload() | 101 | self._Unload() |
80 | self._Load() | 102 | self._Load() |
81 | finally: | 103 | finally: |
82 | self._manifestFile = old | 104 | self.manifestFile = old |
83 | 105 | ||
84 | def Link(self, name): | 106 | def Link(self, name): |
85 | """Update the repo metadata to use a different manifest. | 107 | """Update the repo metadata to use a different manifest. |
@@ -87,9 +109,9 @@ class XmlManifest(Manifest): | |||
87 | self.Override(name) | 109 | self.Override(name) |
88 | 110 | ||
89 | try: | 111 | try: |
90 | if os.path.exists(self._manifestFile): | 112 | if os.path.exists(self.manifestFile): |
91 | os.remove(self._manifestFile) | 113 | os.remove(self.manifestFile) |
92 | os.symlink('manifests/%s' % name, self._manifestFile) | 114 | os.symlink('manifests/%s' % name, self.manifestFile) |
93 | except OSError, e: | 115 | except OSError, e: |
94 | raise ManifestParseError('cannot link manifest %s' % name) | 116 | raise ManifestParseError('cannot link manifest %s' % name) |
95 | 117 | ||
@@ -104,6 +126,13 @@ class XmlManifest(Manifest): | |||
104 | def Save(self, fd, peg_rev=False): | 126 | def Save(self, fd, peg_rev=False): |
105 | """Write the current manifest out to the given file descriptor. | 127 | """Write the current manifest out to the given file descriptor. |
106 | """ | 128 | """ |
129 | mp = self.manifestProject | ||
130 | |||
131 | groups = mp.config.GetString('manifest.groups') | ||
132 | if not groups: | ||
133 | groups = 'default' | ||
134 | groups = [x for x in re.split(r'[,\s]+', groups) if x] | ||
135 | |||
107 | doc = xml.dom.minidom.Document() | 136 | doc = xml.dom.minidom.Document() |
108 | root = doc.createElement('manifest') | 137 | root = doc.createElement('manifest') |
109 | doc.appendChild(root) | 138 | doc.appendChild(root) |
@@ -134,6 +163,12 @@ class XmlManifest(Manifest): | |||
134 | if d.revisionExpr: | 163 | if d.revisionExpr: |
135 | have_default = True | 164 | have_default = True |
136 | e.setAttribute('revision', d.revisionExpr) | 165 | e.setAttribute('revision', d.revisionExpr) |
166 | if d.sync_j > 1: | ||
167 | have_default = True | ||
168 | e.setAttribute('sync-j', '%d' % d.sync_j) | ||
169 | if d.sync_c: | ||
170 | have_default = True | ||
171 | e.setAttribute('sync-c', 'true') | ||
137 | if have_default: | 172 | if have_default: |
138 | root.appendChild(e) | 173 | root.appendChild(e) |
139 | root.appendChild(doc.createTextNode('')) | 174 | root.appendChild(doc.createTextNode('')) |
@@ -149,6 +184,10 @@ class XmlManifest(Manifest): | |||
149 | 184 | ||
150 | for p in sort_projects: | 185 | for p in sort_projects: |
151 | p = self.projects[p] | 186 | p = self.projects[p] |
187 | |||
188 | if not p.MatchesGroups(groups): | ||
189 | continue | ||
190 | |||
152 | e = doc.createElement('project') | 191 | e = doc.createElement('project') |
153 | root.appendChild(e) | 192 | root.appendChild(e) |
154 | e.setAttribute('name', p.name) | 193 | e.setAttribute('name', p.name) |
@@ -172,6 +211,29 @@ class XmlManifest(Manifest): | |||
172 | ce.setAttribute('dest', c.dest) | 211 | ce.setAttribute('dest', c.dest) |
173 | e.appendChild(ce) | 212 | e.appendChild(ce) |
174 | 213 | ||
214 | default_groups = ['default', 'name:%s' % p.name, 'path:%s' % p.relpath] | ||
215 | egroups = [g for g in p.groups if g not in default_groups] | ||
216 | if egroups: | ||
217 | e.setAttribute('groups', ','.join(egroups)) | ||
218 | |||
219 | for a in p.annotations: | ||
220 | if a.keep == "true": | ||
221 | ae = doc.createElement('annotation') | ||
222 | ae.setAttribute('name', a.name) | ||
223 | ae.setAttribute('value', a.value) | ||
224 | e.appendChild(ae) | ||
225 | |||
226 | if p.sync_c: | ||
227 | e.setAttribute('sync-c', 'true') | ||
228 | |||
229 | if self._repo_hooks_project: | ||
230 | root.appendChild(doc.createTextNode('')) | ||
231 | e = doc.createElement('repo-hooks') | ||
232 | e.setAttribute('in-project', self._repo_hooks_project.name) | ||
233 | e.setAttribute('enabled-list', | ||
234 | ' '.join(self._repo_hooks_project.enabled_repo_hooks)) | ||
235 | root.appendChild(e) | ||
236 | |||
175 | doc.writexml(fd, '', ' ', '\n', 'UTF-8') | 237 | doc.writexml(fd, '', ' ', '\n', 'UTF-8') |
176 | 238 | ||
177 | @property | 239 | @property |
@@ -190,6 +252,11 @@ class XmlManifest(Manifest): | |||
190 | return self._default | 252 | return self._default |
191 | 253 | ||
192 | @property | 254 | @property |
255 | def repo_hooks_project(self): | ||
256 | self._Load() | ||
257 | return self._repo_hooks_project | ||
258 | |||
259 | @property | ||
193 | def notice(self): | 260 | def notice(self): |
194 | self._Load() | 261 | self._Load() |
195 | return self._notice | 262 | return self._notice |
@@ -199,21 +266,16 @@ class XmlManifest(Manifest): | |||
199 | self._Load() | 266 | self._Load() |
200 | return self._manifest_server | 267 | return self._manifest_server |
201 | 268 | ||
202 | def InitBranch(self): | 269 | @property |
203 | m = self.manifestProject | 270 | def IsMirror(self): |
204 | if m.CurrentBranch is None: | 271 | return self.manifestProject.config.GetBoolean('repo.mirror') |
205 | return m.StartBranch('default') | ||
206 | return True | ||
207 | |||
208 | def SetMRefs(self, project): | ||
209 | if self.branch: | ||
210 | project._InitAnyMRef(R_M + self.branch) | ||
211 | 272 | ||
212 | def _Unload(self): | 273 | def _Unload(self): |
213 | self._loaded = False | 274 | self._loaded = False |
214 | self._projects = {} | 275 | self._projects = {} |
215 | self._remotes = {} | 276 | self._remotes = {} |
216 | self._default = None | 277 | self._default = None |
278 | self._repo_hooks_project = None | ||
217 | self._notice = None | 279 | self._notice = None |
218 | self.branch = None | 280 | self.branch = None |
219 | self._manifest_server = None | 281 | self._manifest_server = None |
@@ -221,24 +283,20 @@ class XmlManifest(Manifest): | |||
221 | def _Load(self): | 283 | def _Load(self): |
222 | if not self._loaded: | 284 | if not self._loaded: |
223 | m = self.manifestProject | 285 | m = self.manifestProject |
224 | b = m.GetBranch(m.CurrentBranch) | 286 | b = m.GetBranch(m.CurrentBranch).merge |
225 | if b.remote and b.remote.name: | ||
226 | m.remote.name = b.remote.name | ||
227 | b = b.merge | ||
228 | if b is not None and b.startswith(R_HEADS): | 287 | if b is not None and b.startswith(R_HEADS): |
229 | b = b[len(R_HEADS):] | 288 | b = b[len(R_HEADS):] |
230 | self.branch = b | 289 | self.branch = b |
231 | 290 | ||
232 | self._ParseManifest(True) | 291 | nodes = [] |
292 | nodes.append(self._ParseManifestXml(self.manifestFile, | ||
293 | self.manifestProject.worktree)) | ||
233 | 294 | ||
234 | local = os.path.join(self.repodir, LOCAL_MANIFEST_NAME) | 295 | local = os.path.join(self.repodir, LOCAL_MANIFEST_NAME) |
235 | if os.path.exists(local): | 296 | if os.path.exists(local): |
236 | try: | 297 | nodes.append(self._ParseManifestXml(local, self.repodir)) |
237 | real = self._manifestFile | 298 | |
238 | self._manifestFile = local | 299 | self._ParseManifest(nodes) |
239 | self._ParseManifest(False) | ||
240 | finally: | ||
241 | self._manifestFile = real | ||
242 | 300 | ||
243 | if self.IsMirror: | 301 | if self.IsMirror: |
244 | self._AddMetaProjectMirror(self.repoProject) | 302 | self._AddMetaProjectMirror(self.repoProject) |
@@ -246,73 +304,117 @@ class XmlManifest(Manifest): | |||
246 | 304 | ||
247 | self._loaded = True | 305 | self._loaded = True |
248 | 306 | ||
249 | def _ParseManifest(self, is_root_file): | 307 | def _ParseManifestXml(self, path, include_root): |
250 | root = xml.dom.minidom.parse(self._manifestFile) | 308 | root = xml.dom.minidom.parse(path) |
251 | if not root or not root.childNodes: | 309 | if not root or not root.childNodes: |
252 | raise ManifestParseError, \ | 310 | raise ManifestParseError("no root node in %s" % (path,)) |
253 | "no root node in %s" % \ | ||
254 | self._manifestFile | ||
255 | 311 | ||
256 | config = root.childNodes[0] | 312 | config = root.childNodes[0] |
257 | if config.nodeName != 'manifest': | 313 | if config.nodeName != 'manifest': |
258 | raise ManifestParseError, \ | 314 | raise ManifestParseError("no <manifest> in %s" % (path,)) |
259 | "no <manifest> in %s" % \ | ||
260 | self._manifestFile | ||
261 | 315 | ||
316 | nodes = [] | ||
262 | for node in config.childNodes: | 317 | for node in config.childNodes: |
263 | if node.nodeName == 'remove-project': | 318 | if node.nodeName == 'include': |
264 | name = self._reqatt(node, 'name') | 319 | name = self._reqatt(node, 'name') |
265 | try: | 320 | fp = os.path.join(include_root, name) |
266 | del self._projects[name] | 321 | if not os.path.isfile(fp): |
267 | except KeyError: | 322 | raise ManifestParseError, \ |
268 | raise ManifestParseError, \ | 323 | "include %s doesn't exist or isn't a file" % \ |
269 | 'project %s not found' % \ | 324 | (name,) |
270 | (name) | 325 | try: |
326 | nodes.extend(self._ParseManifestXml(fp, include_root)) | ||
327 | # should isolate this to the exact exception, but that's | ||
328 | # tricky. actual parsing implementation may vary. | ||
329 | except (KeyboardInterrupt, RuntimeError, SystemExit): | ||
330 | raise | ||
331 | except Exception, e: | ||
332 | raise ManifestParseError( | ||
333 | "failed parsing included manifest %s: %s", (name, e)) | ||
334 | else: | ||
335 | nodes.append(node) | ||
336 | return nodes | ||
271 | 337 | ||
272 | for node in config.childNodes: | 338 | def _ParseManifest(self, node_list): |
339 | for node in itertools.chain(*node_list): | ||
273 | if node.nodeName == 'remote': | 340 | if node.nodeName == 'remote': |
274 | remote = self._ParseRemote(node) | 341 | remote = self._ParseRemote(node) |
275 | if self._remotes.get(remote.name): | 342 | if self._remotes.get(remote.name): |
276 | raise ManifestParseError, \ | 343 | raise ManifestParseError( |
277 | 'duplicate remote %s in %s' % \ | 344 | 'duplicate remote %s in %s' % |
278 | (remote.name, self._manifestFile) | 345 | (remote.name, self.manifestFile)) |
279 | self._remotes[remote.name] = remote | 346 | self._remotes[remote.name] = remote |
280 | 347 | ||
281 | for node in config.childNodes: | 348 | for node in itertools.chain(*node_list): |
282 | if node.nodeName == 'default': | 349 | if node.nodeName == 'default': |
283 | if self._default is not None: | 350 | if self._default is not None: |
284 | raise ManifestParseError, \ | 351 | raise ManifestParseError( |
285 | 'duplicate default in %s' % \ | 352 | 'duplicate default in %s' % |
286 | (self._manifestFile) | 353 | (self.manifestFile)) |
287 | self._default = self._ParseDefault(node) | 354 | self._default = self._ParseDefault(node) |
288 | if self._default is None: | 355 | if self._default is None: |
289 | self._default = _Default() | 356 | self._default = _Default() |
290 | 357 | ||
291 | for node in config.childNodes: | 358 | for node in itertools.chain(*node_list): |
292 | if node.nodeName == 'notice': | 359 | if node.nodeName == 'notice': |
293 | if self._notice is not None: | 360 | if self._notice is not None: |
294 | raise ManifestParseError, \ | 361 | raise ManifestParseError( |
295 | 'duplicate notice in %s' % \ | 362 | 'duplicate notice in %s' % |
296 | (self.manifestFile) | 363 | (self.manifestFile)) |
297 | self._notice = self._ParseNotice(node) | 364 | self._notice = self._ParseNotice(node) |
298 | 365 | ||
299 | for node in config.childNodes: | 366 | for node in itertools.chain(*node_list): |
300 | if node.nodeName == 'manifest-server': | 367 | if node.nodeName == 'manifest-server': |
301 | url = self._reqatt(node, 'url') | 368 | url = self._reqatt(node, 'url') |
302 | if self._manifest_server is not None: | 369 | if self._manifest_server is not None: |
303 | raise ManifestParseError, \ | 370 | raise ManifestParseError( |
304 | 'duplicate manifest-server in %s' % \ | 371 | 'duplicate manifest-server in %s' % |
305 | (self.manifestFile) | 372 | (self.manifestFile)) |
306 | self._manifest_server = url | 373 | self._manifest_server = url |
307 | 374 | ||
308 | for node in config.childNodes: | 375 | for node in itertools.chain(*node_list): |
309 | if node.nodeName == 'project': | 376 | if node.nodeName == 'project': |
310 | project = self._ParseProject(node) | 377 | project = self._ParseProject(node) |
311 | if self._projects.get(project.name): | 378 | if self._projects.get(project.name): |
312 | raise ManifestParseError, \ | 379 | raise ManifestParseError( |
313 | 'duplicate project %s in %s' % \ | 380 | 'duplicate project %s in %s' % |
314 | (project.name, self._manifestFile) | 381 | (project.name, self.manifestFile)) |
315 | self._projects[project.name] = project | 382 | self._projects[project.name] = project |
383 | if node.nodeName == 'repo-hooks': | ||
384 | # Get the name of the project and the (space-separated) list of enabled. | ||
385 | repo_hooks_project = self._reqatt(node, 'in-project') | ||
386 | enabled_repo_hooks = self._reqatt(node, 'enabled-list').split() | ||
387 | |||
388 | # Only one project can be the hooks project | ||
389 | if self._repo_hooks_project is not None: | ||
390 | raise ManifestParseError( | ||
391 | 'duplicate repo-hooks in %s' % | ||
392 | (self.manifestFile)) | ||
393 | |||
394 | # Store a reference to the Project. | ||
395 | try: | ||
396 | self._repo_hooks_project = self._projects[repo_hooks_project] | ||
397 | except KeyError: | ||
398 | raise ManifestParseError( | ||
399 | 'project %s not found for repo-hooks' % | ||
400 | (repo_hooks_project)) | ||
401 | |||
402 | # Store the enabled hooks in the Project object. | ||
403 | self._repo_hooks_project.enabled_repo_hooks = enabled_repo_hooks | ||
404 | if node.nodeName == 'remove-project': | ||
405 | name = self._reqatt(node, 'name') | ||
406 | try: | ||
407 | del self._projects[name] | ||
408 | except KeyError: | ||
409 | raise ManifestParseError( | ||
410 | 'project %s not found' % | ||
411 | (name)) | ||
412 | |||
413 | # If the manifest removes the hooks project, treat it as if it deleted | ||
414 | # the repo-hooks element too. | ||
415 | if self._repo_hooks_project and (self._repo_hooks_project.name == name): | ||
416 | self._repo_hooks_project = None | ||
417 | |||
316 | 418 | ||
317 | def _AddMetaProjectMirror(self, m): | 419 | def _AddMetaProjectMirror(self, m): |
318 | name = None | 420 | name = None |
@@ -321,7 +423,7 @@ class XmlManifest(Manifest): | |||
321 | raise ManifestParseError, 'refusing to mirror %s' % m_url | 423 | raise ManifestParseError, 'refusing to mirror %s' % m_url |
322 | 424 | ||
323 | if self._default and self._default.remote: | 425 | if self._default and self._default.remote: |
324 | url = self._default.remote.fetchUrl | 426 | url = self._default.remote.resolvedFetchUrl |
325 | if not url.endswith('/'): | 427 | if not url.endswith('/'): |
326 | url += '/' | 428 | url += '/' |
327 | if m_url.startswith(url): | 429 | if m_url.startswith(url): |
@@ -330,7 +432,8 @@ class XmlManifest(Manifest): | |||
330 | 432 | ||
331 | if name is None: | 433 | if name is None: |
332 | s = m_url.rindex('/') + 1 | 434 | s = m_url.rindex('/') + 1 |
333 | remote = _XmlRemote('origin', m_url[:s]) | 435 | manifestUrl = self.manifestProject.config.GetString('remote.origin.url') |
436 | remote = _XmlRemote('origin', fetch=m_url[:s], manifestUrl=manifestUrl) | ||
334 | name = m_url[s:] | 437 | name = m_url[s:] |
335 | 438 | ||
336 | if name.endswith('.git'): | 439 | if name.endswith('.git'): |
@@ -354,11 +457,15 @@ class XmlManifest(Manifest): | |||
354 | reads a <remote> element from the manifest file | 457 | reads a <remote> element from the manifest file |
355 | """ | 458 | """ |
356 | name = self._reqatt(node, 'name') | 459 | name = self._reqatt(node, 'name') |
460 | alias = node.getAttribute('alias') | ||
461 | if alias == '': | ||
462 | alias = None | ||
357 | fetch = self._reqatt(node, 'fetch') | 463 | fetch = self._reqatt(node, 'fetch') |
358 | review = node.getAttribute('review') | 464 | review = node.getAttribute('review') |
359 | if review == '': | 465 | if review == '': |
360 | review = None | 466 | review = None |
361 | return _XmlRemote(name, fetch, review) | 467 | manifestUrl = self.manifestProject.config.GetString('remote.origin.url') |
468 | return _XmlRemote(name, alias, fetch, manifestUrl, review) | ||
362 | 469 | ||
363 | def _ParseDefault(self, node): | 470 | def _ParseDefault(self, node): |
364 | """ | 471 | """ |
@@ -369,6 +476,18 @@ class XmlManifest(Manifest): | |||
369 | d.revisionExpr = node.getAttribute('revision') | 476 | d.revisionExpr = node.getAttribute('revision') |
370 | if d.revisionExpr == '': | 477 | if d.revisionExpr == '': |
371 | d.revisionExpr = None | 478 | d.revisionExpr = None |
479 | |||
480 | sync_j = node.getAttribute('sync-j') | ||
481 | if sync_j == '' or sync_j is None: | ||
482 | d.sync_j = 1 | ||
483 | else: | ||
484 | d.sync_j = int(sync_j) | ||
485 | |||
486 | sync_c = node.getAttribute('sync-c') | ||
487 | if not sync_c: | ||
488 | d.sync_c = False | ||
489 | else: | ||
490 | d.sync_c = sync_c.lower() in ("yes", "true", "1") | ||
372 | return d | 491 | return d |
373 | 492 | ||
374 | def _ParseNotice(self, node): | 493 | def _ParseNotice(self, node): |
@@ -422,7 +541,7 @@ class XmlManifest(Manifest): | |||
422 | if remote is None: | 541 | if remote is None: |
423 | raise ManifestParseError, \ | 542 | raise ManifestParseError, \ |
424 | "no remote for project %s within %s" % \ | 543 | "no remote for project %s within %s" % \ |
425 | (name, self._manifestFile) | 544 | (name, self.manifestFile) |
426 | 545 | ||
427 | revisionExpr = node.getAttribute('revision') | 546 | revisionExpr = node.getAttribute('revision') |
428 | if not revisionExpr: | 547 | if not revisionExpr: |
@@ -430,7 +549,7 @@ class XmlManifest(Manifest): | |||
430 | if not revisionExpr: | 549 | if not revisionExpr: |
431 | raise ManifestParseError, \ | 550 | raise ManifestParseError, \ |
432 | "no revision for project %s within %s" % \ | 551 | "no revision for project %s within %s" % \ |
433 | (name, self._manifestFile) | 552 | (name, self.manifestFile) |
434 | 553 | ||
435 | path = node.getAttribute('path') | 554 | path = node.getAttribute('path') |
436 | if not path: | 555 | if not path: |
@@ -438,7 +557,27 @@ class XmlManifest(Manifest): | |||
438 | if path.startswith('/'): | 557 | if path.startswith('/'): |
439 | raise ManifestParseError, \ | 558 | raise ManifestParseError, \ |
440 | "project %s path cannot be absolute in %s" % \ | 559 | "project %s path cannot be absolute in %s" % \ |
441 | (name, self._manifestFile) | 560 | (name, self.manifestFile) |
561 | |||
562 | rebase = node.getAttribute('rebase') | ||
563 | if not rebase: | ||
564 | rebase = True | ||
565 | else: | ||
566 | rebase = rebase.lower() in ("yes", "true", "1") | ||
567 | |||
568 | sync_c = node.getAttribute('sync-c') | ||
569 | if not sync_c: | ||
570 | sync_c = False | ||
571 | else: | ||
572 | sync_c = sync_c.lower() in ("yes", "true", "1") | ||
573 | |||
574 | groups = '' | ||
575 | if node.hasAttribute('groups'): | ||
576 | groups = node.getAttribute('groups') | ||
577 | groups = [x for x in re.split('[,\s]+', groups) if x] | ||
578 | |||
579 | default_groups = ['default', 'name:%s' % name, 'path:%s' % path] | ||
580 | groups.extend(set(default_groups).difference(groups)) | ||
442 | 581 | ||
443 | if self.IsMirror: | 582 | if self.IsMirror: |
444 | relpath = None | 583 | relpath = None |
@@ -455,11 +594,16 @@ class XmlManifest(Manifest): | |||
455 | worktree = worktree, | 594 | worktree = worktree, |
456 | relpath = path, | 595 | relpath = path, |
457 | revisionExpr = revisionExpr, | 596 | revisionExpr = revisionExpr, |
458 | revisionId = None) | 597 | revisionId = None, |
598 | rebase = rebase, | ||
599 | groups = groups, | ||
600 | sync_c = sync_c) | ||
459 | 601 | ||
460 | for n in node.childNodes: | 602 | for n in node.childNodes: |
461 | if n.nodeName == 'copyfile': | 603 | if n.nodeName == 'copyfile': |
462 | self._ParseCopyFile(project, n) | 604 | self._ParseCopyFile(project, n) |
605 | if n.nodeName == 'annotation': | ||
606 | self._ParseAnnotation(project, n) | ||
463 | 607 | ||
464 | return project | 608 | return project |
465 | 609 | ||
@@ -471,6 +615,17 @@ class XmlManifest(Manifest): | |||
471 | # dest is relative to the top of the tree | 615 | # dest is relative to the top of the tree |
472 | project.AddCopyFile(src, dest, os.path.join(self.topdir, dest)) | 616 | project.AddCopyFile(src, dest, os.path.join(self.topdir, dest)) |
473 | 617 | ||
618 | def _ParseAnnotation(self, project, node): | ||
619 | name = self._reqatt(node, 'name') | ||
620 | value = self._reqatt(node, 'value') | ||
621 | try: | ||
622 | keep = self._reqatt(node, 'keep').lower() | ||
623 | except ManifestParseError: | ||
624 | keep = "true" | ||
625 | if keep != "true" and keep != "false": | ||
626 | raise ManifestParseError, "optional \"keep\" attribute must be \"true\" or \"false\"" | ||
627 | project.AddAnnotation(name, value, keep) | ||
628 | |||
474 | def _get_remote(self, node): | 629 | def _get_remote(self, node): |
475 | name = node.getAttribute('remote') | 630 | name = node.getAttribute('remote') |
476 | if not name: | 631 | if not name: |
@@ -480,7 +635,7 @@ class XmlManifest(Manifest): | |||
480 | if not v: | 635 | if not v: |
481 | raise ManifestParseError, \ | 636 | raise ManifestParseError, \ |
482 | "remote %s not defined in %s" % \ | 637 | "remote %s not defined in %s" % \ |
483 | (name, self._manifestFile) | 638 | (name, self.manifestFile) |
484 | return v | 639 | return v |
485 | 640 | ||
486 | def _reqatt(self, node, attname): | 641 | def _reqatt(self, node, attname): |
@@ -491,5 +646,5 @@ class XmlManifest(Manifest): | |||
491 | if not v: | 646 | if not v: |
492 | raise ManifestParseError, \ | 647 | raise ManifestParseError, \ |
493 | "no %s in <%s> within %s" % \ | 648 | "no %s in <%s> within %s" % \ |
494 | (attname, node.nodeName, self._manifestFile) | 649 | (attname, node.nodeName, self.manifestFile) |
495 | return v | 650 | return v |