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 |
