diff options
Diffstat (limited to 'manifest_xml.py')
| -rw-r--r-- | manifest_xml.py | 250 |
1 files changed, 184 insertions, 66 deletions
diff --git a/manifest_xml.py b/manifest_xml.py index dd163bed..53f33537 100644 --- a/manifest_xml.py +++ b/manifest_xml.py | |||
| @@ -13,6 +13,7 @@ | |||
| 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 | from __future__ import print_function | ||
| 16 | import itertools | 17 | import itertools |
| 17 | import os | 18 | import os |
| 18 | import re | 19 | import re |
| @@ -27,6 +28,7 @@ from error import ManifestParseError | |||
| 27 | 28 | ||
| 28 | MANIFEST_FILE_NAME = 'manifest.xml' | 29 | MANIFEST_FILE_NAME = 'manifest.xml' |
| 29 | LOCAL_MANIFEST_NAME = 'local_manifest.xml' | 30 | LOCAL_MANIFEST_NAME = 'local_manifest.xml' |
| 31 | LOCAL_MANIFESTS_DIR_NAME = 'local_manifests' | ||
| 30 | 32 | ||
| 31 | urlparse.uses_relative.extend(['ssh', 'git']) | 33 | urlparse.uses_relative.extend(['ssh', 'git']) |
| 32 | urlparse.uses_netloc.extend(['ssh', 'git']) | 34 | urlparse.uses_netloc.extend(['ssh', 'git']) |
| @@ -38,6 +40,7 @@ class _Default(object): | |||
| 38 | remote = None | 40 | remote = None |
| 39 | sync_j = 1 | 41 | sync_j = 1 |
| 40 | sync_c = False | 42 | sync_c = False |
| 43 | sync_s = False | ||
| 41 | 44 | ||
| 42 | class _XmlRemote(object): | 45 | class _XmlRemote(object): |
| 43 | def __init__(self, | 46 | def __init__(self, |
| @@ -53,15 +56,28 @@ class _XmlRemote(object): | |||
| 53 | self.reviewUrl = review | 56 | self.reviewUrl = review |
| 54 | self.resolvedFetchUrl = self._resolveFetchUrl() | 57 | self.resolvedFetchUrl = self._resolveFetchUrl() |
| 55 | 58 | ||
| 59 | def __eq__(self, other): | ||
| 60 | return self.__dict__ == other.__dict__ | ||
| 61 | |||
| 62 | def __ne__(self, other): | ||
| 63 | return self.__dict__ != other.__dict__ | ||
| 64 | |||
| 56 | def _resolveFetchUrl(self): | 65 | def _resolveFetchUrl(self): |
| 57 | url = self.fetchUrl.rstrip('/') | 66 | url = self.fetchUrl.rstrip('/') |
| 58 | manifestUrl = self.manifestUrl.rstrip('/') | 67 | manifestUrl = self.manifestUrl.rstrip('/') |
| 68 | p = manifestUrl.startswith('persistent-http') | ||
| 69 | if p: | ||
| 70 | manifestUrl = manifestUrl[len('persistent-'):] | ||
| 71 | |||
| 59 | # urljoin will get confused if there is no scheme in the base url | 72 | # urljoin will get confused if there is no scheme in the base url |
| 60 | # ie, if manifestUrl is of the form <hostname:port> | 73 | # ie, if manifestUrl is of the form <hostname:port> |
| 61 | if manifestUrl.find(':') != manifestUrl.find('/') - 1: | 74 | if manifestUrl.find(':') != manifestUrl.find('/') - 1: |
| 62 | manifestUrl = 'gopher://' + manifestUrl | 75 | manifestUrl = 'gopher://' + manifestUrl |
| 63 | url = urlparse.urljoin(manifestUrl, url) | 76 | url = urlparse.urljoin(manifestUrl, url) |
| 64 | return re.sub(r'^gopher://', '', url) | 77 | url = re.sub(r'^gopher://', '', url) |
| 78 | if p: | ||
| 79 | url = 'persistent-' + url | ||
| 80 | return url | ||
| 65 | 81 | ||
| 66 | def ToRemoteSpec(self, projectName): | 82 | def ToRemoteSpec(self, projectName): |
| 67 | url = self.resolvedFetchUrl.rstrip('/') + '/' + projectName | 83 | url = self.resolvedFetchUrl.rstrip('/') + '/' + projectName |
| @@ -110,11 +126,11 @@ class XmlManifest(object): | |||
| 110 | self.Override(name) | 126 | self.Override(name) |
| 111 | 127 | ||
| 112 | try: | 128 | try: |
| 113 | if os.path.exists(self.manifestFile): | 129 | if os.path.lexists(self.manifestFile): |
| 114 | os.remove(self.manifestFile) | 130 | os.remove(self.manifestFile) |
| 115 | os.symlink('manifests/%s' % name, self.manifestFile) | 131 | os.symlink('manifests/%s' % name, self.manifestFile) |
| 116 | except OSError: | 132 | except OSError as e: |
| 117 | raise ManifestParseError('cannot link manifest %s' % name) | 133 | raise ManifestParseError('cannot link manifest %s: %s' % (name, str(e))) |
| 118 | 134 | ||
| 119 | def _RemoteToXml(self, r, doc, root): | 135 | def _RemoteToXml(self, r, doc, root): |
| 120 | e = doc.createElement('remote') | 136 | e = doc.createElement('remote') |
| @@ -130,9 +146,8 @@ class XmlManifest(object): | |||
| 130 | mp = self.manifestProject | 146 | mp = self.manifestProject |
| 131 | 147 | ||
| 132 | groups = mp.config.GetString('manifest.groups') | 148 | groups = mp.config.GetString('manifest.groups') |
| 133 | if not groups: | 149 | if groups: |
| 134 | groups = 'all' | 150 | groups = [x for x in re.split(r'[,\s]+', groups) if x] |
| 135 | groups = [x for x in re.split(r'[,\s]+', groups) if x] | ||
| 136 | 151 | ||
| 137 | doc = xml.dom.minidom.Document() | 152 | doc = xml.dom.minidom.Document() |
| 138 | root = doc.createElement('manifest') | 153 | root = doc.createElement('manifest') |
| @@ -170,6 +185,9 @@ class XmlManifest(object): | |||
| 170 | if d.sync_c: | 185 | if d.sync_c: |
| 171 | have_default = True | 186 | have_default = True |
| 172 | e.setAttribute('sync-c', 'true') | 187 | e.setAttribute('sync-c', 'true') |
| 188 | if d.sync_s: | ||
| 189 | have_default = True | ||
| 190 | e.setAttribute('sync-s', 'true') | ||
| 173 | if have_default: | 191 | if have_default: |
| 174 | root.appendChild(e) | 192 | root.appendChild(e) |
| 175 | root.appendChild(doc.createTextNode('')) | 193 | root.appendChild(doc.createTextNode('')) |
| @@ -180,20 +198,25 @@ class XmlManifest(object): | |||
| 180 | root.appendChild(e) | 198 | root.appendChild(e) |
| 181 | root.appendChild(doc.createTextNode('')) | 199 | root.appendChild(doc.createTextNode('')) |
| 182 | 200 | ||
| 183 | sort_projects = list(self.projects.keys()) | 201 | def output_projects(parent, parent_node, projects): |
| 184 | sort_projects.sort() | 202 | for p in projects: |
| 185 | 203 | output_project(parent, parent_node, self.projects[p]) | |
| 186 | for p in sort_projects: | ||
| 187 | p = self.projects[p] | ||
| 188 | 204 | ||
| 205 | def output_project(parent, parent_node, p): | ||
| 189 | if not p.MatchesGroups(groups): | 206 | if not p.MatchesGroups(groups): |
| 190 | continue | 207 | return |
| 208 | |||
| 209 | name = p.name | ||
| 210 | relpath = p.relpath | ||
| 211 | if parent: | ||
| 212 | name = self._UnjoinName(parent.name, name) | ||
| 213 | relpath = self._UnjoinRelpath(parent.relpath, relpath) | ||
| 191 | 214 | ||
| 192 | e = doc.createElement('project') | 215 | e = doc.createElement('project') |
| 193 | root.appendChild(e) | 216 | parent_node.appendChild(e) |
| 194 | e.setAttribute('name', p.name) | 217 | e.setAttribute('name', name) |
| 195 | if p.relpath != p.name: | 218 | if relpath != name: |
| 196 | e.setAttribute('path', p.relpath) | 219 | e.setAttribute('path', relpath) |
| 197 | if not d.remote or p.remote.name != d.remote.name: | 220 | if not d.remote or p.remote.name != d.remote.name: |
| 198 | e.setAttribute('remote', p.remote.name) | 221 | e.setAttribute('remote', p.remote.name) |
| 199 | if peg_rev: | 222 | if peg_rev: |
| @@ -231,6 +254,19 @@ class XmlManifest(object): | |||
| 231 | if p.sync_c: | 254 | if p.sync_c: |
| 232 | e.setAttribute('sync-c', 'true') | 255 | e.setAttribute('sync-c', 'true') |
| 233 | 256 | ||
| 257 | if p.sync_s: | ||
| 258 | e.setAttribute('sync-s', 'true') | ||
| 259 | |||
| 260 | if p.subprojects: | ||
| 261 | sort_projects = [subp.name for subp in p.subprojects] | ||
| 262 | sort_projects.sort() | ||
| 263 | output_projects(p, e, sort_projects) | ||
| 264 | |||
| 265 | sort_projects = [key for key in self.projects.keys() | ||
| 266 | if not self.projects[key].parent] | ||
| 267 | sort_projects.sort() | ||
| 268 | output_projects(None, root, sort_projects) | ||
| 269 | |||
| 234 | if self._repo_hooks_project: | 270 | if self._repo_hooks_project: |
| 235 | root.appendChild(doc.createTextNode('')) | 271 | root.appendChild(doc.createTextNode('')) |
| 236 | e = doc.createElement('repo-hooks') | 272 | e = doc.createElement('repo-hooks') |
| @@ -299,9 +335,30 @@ class XmlManifest(object): | |||
| 299 | 335 | ||
| 300 | local = os.path.join(self.repodir, LOCAL_MANIFEST_NAME) | 336 | local = os.path.join(self.repodir, LOCAL_MANIFEST_NAME) |
| 301 | if os.path.exists(local): | 337 | if os.path.exists(local): |
| 338 | print('warning: %s is deprecated; put local manifests in %s instead' | ||
| 339 | % (LOCAL_MANIFEST_NAME, LOCAL_MANIFESTS_DIR_NAME), | ||
| 340 | file=sys.stderr) | ||
| 302 | nodes.append(self._ParseManifestXml(local, self.repodir)) | 341 | nodes.append(self._ParseManifestXml(local, self.repodir)) |
| 303 | 342 | ||
| 304 | self._ParseManifest(nodes) | 343 | local_dir = os.path.abspath(os.path.join(self.repodir, LOCAL_MANIFESTS_DIR_NAME)) |
| 344 | try: | ||
| 345 | for local_file in sorted(os.listdir(local_dir)): | ||
| 346 | if local_file.endswith('.xml'): | ||
| 347 | try: | ||
| 348 | local = os.path.join(local_dir, local_file) | ||
| 349 | nodes.append(self._ParseManifestXml(local, self.repodir)) | ||
| 350 | except ManifestParseError as e: | ||
| 351 | print('%s' % str(e), file=sys.stderr) | ||
| 352 | except OSError: | ||
| 353 | pass | ||
| 354 | |||
| 355 | try: | ||
| 356 | self._ParseManifest(nodes) | ||
| 357 | except ManifestParseError as e: | ||
| 358 | # There was a problem parsing, unload ourselves in case they catch | ||
| 359 | # this error and try again later, we will show the correct error | ||
| 360 | self._Unload() | ||
| 361 | raise e | ||
| 305 | 362 | ||
| 306 | if self.IsMirror: | 363 | if self.IsMirror: |
| 307 | self._AddMetaProjectMirror(self.repoProject) | 364 | self._AddMetaProjectMirror(self.repoProject) |
| @@ -310,7 +367,11 @@ class XmlManifest(object): | |||
| 310 | self._loaded = True | 367 | self._loaded = True |
| 311 | 368 | ||
| 312 | def _ParseManifestXml(self, path, include_root): | 369 | def _ParseManifestXml(self, path, include_root): |
| 313 | root = xml.dom.minidom.parse(path) | 370 | try: |
| 371 | root = xml.dom.minidom.parse(path) | ||
| 372 | except (OSError, xml.parsers.expat.ExpatError) as e: | ||
| 373 | raise ManifestParseError("error parsing manifest %s: %s" % (path, e)) | ||
| 374 | |||
| 314 | if not root or not root.childNodes: | 375 | if not root or not root.childNodes: |
| 315 | raise ManifestParseError("no root node in %s" % (path,)) | 376 | raise ManifestParseError("no root node in %s" % (path,)) |
| 316 | 377 | ||
| @@ -323,35 +384,38 @@ class XmlManifest(object): | |||
| 323 | nodes = [] | 384 | nodes = [] |
| 324 | for node in manifest.childNodes: # pylint:disable=W0631 | 385 | for node in manifest.childNodes: # pylint:disable=W0631 |
| 325 | # We only get here if manifest is initialised | 386 | # We only get here if manifest is initialised |
| 326 | if node.nodeName == 'include': | 387 | if node.nodeName == 'include': |
| 327 | name = self._reqatt(node, 'name') | 388 | name = self._reqatt(node, 'name') |
| 328 | fp = os.path.join(include_root, name) | 389 | fp = os.path.join(include_root, name) |
| 329 | if not os.path.isfile(fp): | 390 | if not os.path.isfile(fp): |
| 330 | raise ManifestParseError, \ | 391 | raise ManifestParseError, \ |
| 331 | "include %s doesn't exist or isn't a file" % \ | 392 | "include %s doesn't exist or isn't a file" % \ |
| 332 | (name,) | 393 | (name,) |
| 333 | try: | 394 | try: |
| 334 | nodes.extend(self._ParseManifestXml(fp, include_root)) | 395 | nodes.extend(self._ParseManifestXml(fp, include_root)) |
| 335 | # should isolate this to the exact exception, but that's | 396 | # should isolate this to the exact exception, but that's |
| 336 | # tricky. actual parsing implementation may vary. | 397 | # tricky. actual parsing implementation may vary. |
| 337 | except (KeyboardInterrupt, RuntimeError, SystemExit): | 398 | except (KeyboardInterrupt, RuntimeError, SystemExit): |
| 338 | raise | 399 | raise |
| 339 | except Exception as e: | 400 | except Exception as e: |
| 340 | raise ManifestParseError( | 401 | raise ManifestParseError( |
| 341 | "failed parsing included manifest %s: %s", (name, e)) | 402 | "failed parsing included manifest %s: %s", (name, e)) |
| 342 | else: | 403 | else: |
| 343 | nodes.append(node) | 404 | nodes.append(node) |
| 344 | return nodes | 405 | return nodes |
| 345 | 406 | ||
| 346 | def _ParseManifest(self, node_list): | 407 | def _ParseManifest(self, node_list): |
| 347 | for node in itertools.chain(*node_list): | 408 | for node in itertools.chain(*node_list): |
| 348 | if node.nodeName == 'remote': | 409 | if node.nodeName == 'remote': |
| 349 | remote = self._ParseRemote(node) | 410 | remote = self._ParseRemote(node) |
| 350 | if self._remotes.get(remote.name): | 411 | if remote: |
| 351 | raise ManifestParseError( | 412 | if remote.name in self._remotes: |
| 352 | 'duplicate remote %s in %s' % | 413 | if remote != self._remotes[remote.name]: |
| 353 | (remote.name, self.manifestFile)) | 414 | raise ManifestParseError( |
| 354 | self._remotes[remote.name] = remote | 415 | 'remote %s already exists with different attributes' % |
| 416 | (remote.name)) | ||
| 417 | else: | ||
| 418 | self._remotes[remote.name] = remote | ||
| 355 | 419 | ||
| 356 | for node in itertools.chain(*node_list): | 420 | for node in itertools.chain(*node_list): |
| 357 | if node.nodeName == 'default': | 421 | if node.nodeName == 'default': |
| @@ -375,19 +439,24 @@ class XmlManifest(object): | |||
| 375 | if node.nodeName == 'manifest-server': | 439 | if node.nodeName == 'manifest-server': |
| 376 | url = self._reqatt(node, 'url') | 440 | url = self._reqatt(node, 'url') |
| 377 | if self._manifest_server is not None: | 441 | if self._manifest_server is not None: |
| 378 | raise ManifestParseError( | 442 | raise ManifestParseError( |
| 379 | 'duplicate manifest-server in %s' % | 443 | 'duplicate manifest-server in %s' % |
| 380 | (self.manifestFile)) | 444 | (self.manifestFile)) |
| 381 | self._manifest_server = url | 445 | self._manifest_server = url |
| 382 | 446 | ||
| 447 | def recursively_add_projects(project): | ||
| 448 | if self._projects.get(project.name): | ||
| 449 | raise ManifestParseError( | ||
| 450 | 'duplicate project %s in %s' % | ||
| 451 | (project.name, self.manifestFile)) | ||
| 452 | self._projects[project.name] = project | ||
| 453 | for subproject in project.subprojects: | ||
| 454 | recursively_add_projects(subproject) | ||
| 455 | |||
| 383 | for node in itertools.chain(*node_list): | 456 | for node in itertools.chain(*node_list): |
| 384 | if node.nodeName == 'project': | 457 | if node.nodeName == 'project': |
| 385 | project = self._ParseProject(node) | 458 | project = self._ParseProject(node) |
| 386 | if self._projects.get(project.name): | 459 | recursively_add_projects(project) |
| 387 | raise ManifestParseError( | ||
| 388 | 'duplicate project %s in %s' % | ||
| 389 | (project.name, self.manifestFile)) | ||
| 390 | self._projects[project.name] = project | ||
| 391 | if node.nodeName == 'repo-hooks': | 460 | if node.nodeName == 'repo-hooks': |
| 392 | # Get the name of the project and the (space-separated) list of enabled. | 461 | # Get the name of the project and the (space-separated) list of enabled. |
| 393 | repo_hooks_project = self._reqatt(node, 'in-project') | 462 | repo_hooks_project = self._reqatt(node, 'in-project') |
| @@ -414,9 +483,8 @@ class XmlManifest(object): | |||
| 414 | try: | 483 | try: |
| 415 | del self._projects[name] | 484 | del self._projects[name] |
| 416 | except KeyError: | 485 | except KeyError: |
| 417 | raise ManifestParseError( | 486 | raise ManifestParseError('remove-project element specifies non-existent ' |
| 418 | 'project %s not found' % | 487 | 'project: %s' % name) |
| 419 | (name)) | ||
| 420 | 488 | ||
| 421 | # If the manifest removes the hooks project, treat it as if it deleted | 489 | # If the manifest removes the hooks project, treat it as if it deleted |
| 422 | # the repo-hooks element too. | 490 | # the repo-hooks element too. |
| @@ -496,6 +564,12 @@ class XmlManifest(object): | |||
| 496 | d.sync_c = False | 564 | d.sync_c = False |
| 497 | else: | 565 | else: |
| 498 | d.sync_c = sync_c.lower() in ("yes", "true", "1") | 566 | d.sync_c = sync_c.lower() in ("yes", "true", "1") |
| 567 | |||
| 568 | sync_s = node.getAttribute('sync-s') | ||
| 569 | if not sync_s: | ||
| 570 | d.sync_s = False | ||
| 571 | else: | ||
| 572 | d.sync_s = sync_s.lower() in ("yes", "true", "1") | ||
| 499 | return d | 573 | return d |
| 500 | 574 | ||
| 501 | def _ParseNotice(self, node): | 575 | def _ParseNotice(self, node): |
| @@ -537,11 +611,19 @@ class XmlManifest(object): | |||
| 537 | 611 | ||
| 538 | return '\n'.join(cleanLines) | 612 | return '\n'.join(cleanLines) |
| 539 | 613 | ||
| 540 | def _ParseProject(self, node): | 614 | def _JoinName(self, parent_name, name): |
| 615 | return os.path.join(parent_name, name) | ||
| 616 | |||
| 617 | def _UnjoinName(self, parent_name, name): | ||
| 618 | return os.path.relpath(name, parent_name) | ||
| 619 | |||
| 620 | def _ParseProject(self, node, parent = None): | ||
| 541 | """ | 621 | """ |
| 542 | reads a <project> element from the manifest file | 622 | reads a <project> element from the manifest file |
| 543 | """ | 623 | """ |
| 544 | name = self._reqatt(node, 'name') | 624 | name = self._reqatt(node, 'name') |
| 625 | if parent: | ||
| 626 | name = self._JoinName(parent.name, name) | ||
| 545 | 627 | ||
| 546 | remote = self._get_remote(node) | 628 | remote = self._get_remote(node) |
| 547 | if remote is None: | 629 | if remote is None: |
| @@ -579,44 +661,80 @@ class XmlManifest(object): | |||
| 579 | else: | 661 | else: |
| 580 | sync_c = sync_c.lower() in ("yes", "true", "1") | 662 | sync_c = sync_c.lower() in ("yes", "true", "1") |
| 581 | 663 | ||
| 664 | sync_s = node.getAttribute('sync-s') | ||
| 665 | if not sync_s: | ||
| 666 | sync_s = self._default.sync_s | ||
| 667 | else: | ||
| 668 | sync_s = sync_s.lower() in ("yes", "true", "1") | ||
| 669 | |||
| 582 | upstream = node.getAttribute('upstream') | 670 | upstream = node.getAttribute('upstream') |
| 583 | 671 | ||
| 584 | groups = '' | 672 | groups = '' |
| 585 | if node.hasAttribute('groups'): | 673 | if node.hasAttribute('groups'): |
| 586 | groups = node.getAttribute('groups') | 674 | groups = node.getAttribute('groups') |
| 587 | groups = [x for x in re.split('[,\s]+', groups) if x] | 675 | groups = [x for x in re.split(r'[,\s]+', groups) if x] |
| 588 | |||
| 589 | default_groups = ['all', 'name:%s' % name, 'path:%s' % path] | ||
| 590 | groups.extend(set(default_groups).difference(groups)) | ||
| 591 | 676 | ||
| 592 | if self.IsMirror: | 677 | if parent is None: |
| 593 | worktree = None | 678 | relpath, worktree, gitdir = self.GetProjectPaths(name, path) |
| 594 | gitdir = os.path.join(self.topdir, '%s.git' % name) | ||
| 595 | else: | 679 | else: |
| 596 | worktree = os.path.join(self.topdir, path).replace('\\', '/') | 680 | relpath, worktree, gitdir = self.GetSubprojectPaths(parent, path) |
| 597 | gitdir = os.path.join(self.repodir, 'projects/%s.git' % path) | 681 | |
| 682 | default_groups = ['all', 'name:%s' % name, 'path:%s' % relpath] | ||
| 683 | groups.extend(set(default_groups).difference(groups)) | ||
| 598 | 684 | ||
| 599 | project = Project(manifest = self, | 685 | project = Project(manifest = self, |
| 600 | name = name, | 686 | name = name, |
| 601 | remote = remote.ToRemoteSpec(name), | 687 | remote = remote.ToRemoteSpec(name), |
| 602 | gitdir = gitdir, | 688 | gitdir = gitdir, |
| 603 | worktree = worktree, | 689 | worktree = worktree, |
| 604 | relpath = path, | 690 | relpath = relpath, |
| 605 | revisionExpr = revisionExpr, | 691 | revisionExpr = revisionExpr, |
| 606 | revisionId = None, | 692 | revisionId = None, |
| 607 | rebase = rebase, | 693 | rebase = rebase, |
| 608 | groups = groups, | 694 | groups = groups, |
| 609 | sync_c = sync_c, | 695 | sync_c = sync_c, |
| 610 | upstream = upstream) | 696 | sync_s = sync_s, |
| 697 | upstream = upstream, | ||
| 698 | parent = parent) | ||
| 611 | 699 | ||
| 612 | for n in node.childNodes: | 700 | for n in node.childNodes: |
| 613 | if n.nodeName == 'copyfile': | 701 | if n.nodeName == 'copyfile': |
| 614 | self._ParseCopyFile(project, n) | 702 | self._ParseCopyFile(project, n) |
| 615 | if n.nodeName == 'annotation': | 703 | if n.nodeName == 'annotation': |
| 616 | self._ParseAnnotation(project, n) | 704 | self._ParseAnnotation(project, n) |
| 705 | if n.nodeName == 'project': | ||
| 706 | project.subprojects.append(self._ParseProject(n, parent = project)) | ||
| 617 | 707 | ||
| 618 | return project | 708 | return project |
| 619 | 709 | ||
| 710 | def GetProjectPaths(self, name, path): | ||
| 711 | relpath = path | ||
| 712 | if self.IsMirror: | ||
| 713 | worktree = None | ||
| 714 | gitdir = os.path.join(self.topdir, '%s.git' % name) | ||
| 715 | else: | ||
| 716 | worktree = os.path.join(self.topdir, path).replace('\\', '/') | ||
| 717 | gitdir = os.path.join(self.repodir, 'projects', '%s.git' % path) | ||
| 718 | return relpath, worktree, gitdir | ||
| 719 | |||
| 720 | def GetSubprojectName(self, parent, submodule_path): | ||
| 721 | return os.path.join(parent.name, submodule_path) | ||
| 722 | |||
| 723 | def _JoinRelpath(self, parent_relpath, relpath): | ||
| 724 | return os.path.join(parent_relpath, relpath) | ||
| 725 | |||
| 726 | def _UnjoinRelpath(self, parent_relpath, relpath): | ||
| 727 | return os.path.relpath(relpath, parent_relpath) | ||
| 728 | |||
| 729 | def GetSubprojectPaths(self, parent, path): | ||
| 730 | relpath = self._JoinRelpath(parent.relpath, path) | ||
| 731 | gitdir = os.path.join(parent.gitdir, 'subprojects', '%s.git' % path) | ||
| 732 | if self.IsMirror: | ||
| 733 | worktree = None | ||
| 734 | else: | ||
| 735 | worktree = os.path.join(parent.worktree, path).replace('\\', '/') | ||
| 736 | return relpath, worktree, gitdir | ||
| 737 | |||
| 620 | def _ParseCopyFile(self, project, node): | 738 | def _ParseCopyFile(self, project, node): |
| 621 | src = self._reqatt(node, 'src') | 739 | src = self._reqatt(node, 'src') |
| 622 | dest = self._reqatt(node, 'dest') | 740 | dest = self._reqatt(node, 'dest') |
