def _ParseManifestXml(self, path, include_root): try: root = xml.dom.minidom.parse(path) except (OSError, xml.parsers.expat.ExpatError) as e: raise ManifestParseError("error parsing manifest %s: %s" % (path, e)) if not root or not root.childNodes: raise ManifestParseError("no root node in %s" % (path, )) for manifest in root.childNodes: if manifest.nodeName == 'manifest': break else: raise ManifestParseError("no <manifest> in %s" % (path, )) nodes = [] for node in manifest.childNodes: # pylint:disable=W0631 # We only get here if manifest is initialised if node.nodeName == 'include': name = self._reqatt(node, 'name') fp = os.path.join(include_root, name) if not os.path.isfile(fp): raise ManifestParseError( "include %s doesn't exist or isn't a file" % (name, )) try: nodes.extend(self._ParseManifestXml(fp, include_root)) # should isolate this to the exact exception, but that's # tricky. actual parsing implementation may vary. except (KeyboardInterrupt, RuntimeError, SystemExit): raise except Exception as e: raise ManifestParseError( "failed parsing included manifest %s: %s", (name, e)) else: nodes.append(node) return nodes
def _ParseProject(self, name): gm = self._modules gr = self._review path = gm.GetString('submodule.%s.path' % name) if not path: path = name revId = self._GetRevisionId(path) if not revId: raise ManifestParseError( 'submodule "%s" has no revision at "%s"' \ % (name, path)) url = gm.GetString('submodule.%s.url' % name) if not url: url = name url = self._ResolveUrl(url) review = gr.GetString('review.%s.url' % name) if not review: review = gr.GetString('review.url') if not review: review = self._Remote().review remote = RemoteSpec(self._Remote().name, url, review) revExpr = gm.GetString('submodule.%s.revision' % name) if revExpr == '.': revExpr = self.branch if self.IsMirror: relpath = None worktree = None gitdir = os.path.join(self.topdir, '%s.git' % name) else: worktree = os.path.join(self.topdir, path) gitdir = os.path.join(self.repodir, 'projects/%s.git' % name) return Project(manifest=self, name=name, remote=remote, gitdir=gitdir, worktree=worktree, relpath=path, revisionExpr=revExpr, revisionId=revId)
def _AddMetaProjectMirror(self, m): name = None m_url = m.GetRemote(m.remote.name).url if m_url.endswith('/.git'): raise ManifestParseError('refusing to mirror %s' % m_url) if self._default and self._default.remote: url = self._default.remote.resolvedFetchUrl if not url.endswith('/'): url += '/' if m_url.startswith(url): remote = self._default.remote name = m_url[len(url):] if name is None: s = m_url.rindex('/') + 1 manifestUrl = self.manifestProject.config.GetString( 'remote.origin.url') remote = _XmlRemote('origin', fetch=m_url[:s], manifestUrl=manifestUrl) name = m_url[s:] if name.endswith('.git'): name = name[:-4] if name not in self._projects: m.PreSync() gitdir = os.path.join(self.topdir, '%s.git' % name) project = Project(manifest=self, name=name, remote=remote.ToRemoteSpec(name), gitdir=gitdir, objdir=gitdir, worktree=None, relpath=name or None, revisionExpr=m.revisionExpr, revisionId=None) self._projects[project.name] = [project] self._paths[project.relpath] = project
def _ParseDefault(self, node): """ reads a <default> element from the manifest file """ d = _Default() d.remote = self._get_remote(node) d.revisionExpr = node.getAttribute('revision') if d.revisionExpr == '': d.revisionExpr = None d.destBranchExpr = node.getAttribute('dest-branch') or None d.upstreamExpr = node.getAttribute('upstream') or None d.sync_j = XmlInt(node, 'sync-j', 1) if d.sync_j <= 0: raise ManifestParseError('%s: sync-j must be greater than 0, not "%s"' % (self.manifestFile, d.sync_j)) d.sync_c = XmlBool(node, 'sync-c', False) d.sync_s = XmlBool(node, 'sync-s', False) d.sync_tags = XmlBool(node, 'sync-tags', True) return d
def XmlInt(node, attr, default=None): """Determine integer value of |node|'s |attr|. Args: node: XML node whose attributes we access. attr: The attribute to access. default: If the attribute is not set (value is empty), then use this. Returns: The number if the attribute is a valid number. Raises: ManifestParseError: The number is invalid. """ value = node.getAttribute(attr) if not value: return default try: return int(value) except ValueError: raise ManifestParseError('manifest: invalid %s="%s" integer' % (attr, value))
def _ParseProject(self, node, parent=None, **extra_proj_attrs): """ reads a <project> element from the manifest file """ name = self._reqatt(node, 'name') if parent: name = self._JoinName(parent.name, name) remote = self._get_remote(node) if remote is None: remote = self._default.remote if remote is None: raise ManifestParseError("no remote for project %s within %s" % (name, self.manifestFile)) revisionExpr = node.getAttribute('revision') or remote.revision if not revisionExpr: revisionExpr = self._default.revisionExpr if not revisionExpr: raise ManifestParseError("no revision for project %s within %s" % (name, self.manifestFile)) path = node.getAttribute('path') if not path: path = name if path.startswith('/'): raise ManifestParseError( "project %s path cannot be absolute in %s" % (name, self.manifestFile)) rebase = XmlBool(node, 'rebase', True) sync_c = XmlBool(node, 'sync-c', False) sync_s = XmlBool(node, 'sync-s', self._default.sync_s) sync_tags = XmlBool(node, 'sync-tags', self._default.sync_tags) clone_depth = XmlInt(node, 'clone-depth') if clone_depth is not None and clone_depth <= 0: raise ManifestParseError( '%s: clone-depth must be greater than 0, not "%s"' % (self.manifestFile, clone_depth)) dest_branch = node.getAttribute( 'dest-branch') or self._default.destBranchExpr upstream = node.getAttribute('upstream') or self._default.upstreamExpr groups = '' if node.hasAttribute('groups'): groups = node.getAttribute('groups') groups = self._ParseGroups(groups) if parent is None: relpath, worktree, gitdir, objdir, use_git_worktrees = \ self.GetProjectPaths(name, path) else: use_git_worktrees = False relpath, worktree, gitdir, objdir = \ self.GetSubprojectPaths(parent, name, path) default_groups = ['all', 'name:%s' % name, 'path:%s' % relpath] groups.extend(set(default_groups).difference(groups)) if self.IsMirror and node.hasAttribute('force-path'): if XmlBool(node, 'force-path', False): gitdir = os.path.join(self.topdir, '%s.git' % path) project = Project(manifest=self, name=name, remote=remote.ToRemoteSpec(name), gitdir=gitdir, objdir=objdir, worktree=worktree, relpath=relpath, revisionExpr=revisionExpr, revisionId=None, rebase=rebase, groups=groups, sync_c=sync_c, sync_s=sync_s, sync_tags=sync_tags, clone_depth=clone_depth, upstream=upstream, parent=parent, dest_branch=dest_branch, use_git_worktrees=use_git_worktrees, **extra_proj_attrs) for n in node.childNodes: if n.nodeName == 'copyfile': self._ParseCopyFile(project, n) if n.nodeName == 'linkfile': self._ParseLinkFile(project, n) if n.nodeName == 'annotation': self._ParseAnnotation(project, n) if n.nodeName == 'project': project.subprojects.append( self._ParseProject(n, parent=project)) return project
def _ParseManifest(self, node_list): for node in itertools.chain(*node_list): if node.nodeName == 'remote': remote = self._ParseRemote(node) if remote: if remote.name in self._remotes: if remote != self._remotes[remote.name]: raise ManifestParseError( 'remote %s already exists with different attributes' % (remote.name)) else: self._remotes[remote.name] = remote for node in itertools.chain(*node_list): if node.nodeName == 'default': new_default = self._ParseDefault(node) if self._default is None: self._default = new_default elif new_default != self._default: raise ManifestParseError('duplicate default in %s' % (self.manifestFile)) if self._default is None: self._default = _Default() for node in itertools.chain(*node_list): if node.nodeName == 'notice': if self._notice is not None: raise ManifestParseError('duplicate notice in %s' % (self.manifestFile)) self._notice = self._ParseNotice(node) for node in itertools.chain(*node_list): if node.nodeName == 'manifest-server': url = self._reqatt(node, 'url') if self._manifest_server is not None: raise ManifestParseError( 'duplicate manifest-server in %s' % (self.manifestFile)) self._manifest_server = url def recursively_add_projects(project): projects = self._projects.setdefault(project.name, []) if project.relpath is None: raise ManifestParseError('missing path for %s in %s' % (project.name, self.manifestFile)) if project.relpath in self._paths: raise ManifestParseError('duplicate path %s in %s' % (project.relpath, self.manifestFile)) self._paths[project.relpath] = project projects.append(project) for subproject in project.subprojects: recursively_add_projects(subproject) for node in itertools.chain(*node_list): if node.nodeName == 'project': project = self._ParseProject(node) recursively_add_projects(project) if node.nodeName == 'extend-project': name = self._reqatt(node, 'name') if name not in self._projects: raise ManifestParseError( 'extend-project element specifies non-existent ' 'project: %s' % name) path = node.getAttribute('path') groups = node.getAttribute('groups') if groups: groups = self._ParseGroups(groups) revision = node.getAttribute('revision') remote = node.getAttribute('remote') if remote: remote = self._get_remote(node) for p in self._projects[name]: if path and p.relpath != path: continue if groups: p.groups.extend(groups) if revision: p.revisionExpr = revision if remote: p.remote = remote.ToRemoteSpec(name) if node.nodeName == 'repo-hooks': # Get the name of the project and the (space-separated) list of enabled. repo_hooks_project = self._reqatt(node, 'in-project') enabled_repo_hooks = self._reqatt(node, 'enabled-list').split() # Only one project can be the hooks project if self._repo_hooks_project is not None: raise ManifestParseError('duplicate repo-hooks in %s' % (self.manifestFile)) # Store a reference to the Project. try: repo_hooks_projects = self._projects[repo_hooks_project] except KeyError: raise ManifestParseError( 'project %s not found for repo-hooks' % (repo_hooks_project)) if len(repo_hooks_projects) != 1: raise ManifestParseError( 'internal error parsing repo-hooks in %s' % (self.manifestFile)) self._repo_hooks_project = repo_hooks_projects[0] # Store the enabled hooks in the Project object. self._repo_hooks_project.enabled_repo_hooks = enabled_repo_hooks if node.nodeName == 'remove-project': name = self._reqatt(node, 'name') if name not in self._projects: raise ManifestParseError( 'remove-project element specifies non-existent ' 'project: %s' % name) for p in self._projects[name]: del self._paths[p.relpath] del self._projects[name] # If the manifest removes the hooks project, treat it as if it deleted # the repo-hooks element too. if self._repo_hooks_project and (self._repo_hooks_project.name == name): self._repo_hooks_project = None
def _ParseProject(self, node, parent=None, **extra_proj_attrs): """ reads a <project> element from the manifest file """ name = self._reqatt(node, 'name') if parent: name = self._JoinName(parent.name, name) remote = self._get_remote(node) if remote is None: remote = self._default.remote if remote is None: raise ManifestParseError("no remote for project %s within %s" % (name, self.manifestFile)) revisionExpr = node.getAttribute('revision') or remote.revision if not revisionExpr: revisionExpr = self._default.revisionExpr if not revisionExpr: raise ManifestParseError("no revision for project %s within %s" % (name, self.manifestFile)) path = node.getAttribute('path') if not path: path = name if path.startswith('/'): raise ManifestParseError( "project %s path cannot be absolute in %s" % (name, self.manifestFile)) rebase = node.getAttribute('rebase') if not rebase: rebase = True else: rebase = rebase.lower() in ("yes", "true", "1") sync_c = node.getAttribute('sync-c') if not sync_c: sync_c = False else: sync_c = sync_c.lower() in ("yes", "true", "1") sync_s = node.getAttribute('sync-s') if not sync_s: sync_s = self._default.sync_s else: sync_s = sync_s.lower() in ("yes", "true", "1") clone_depth = node.getAttribute('clone-depth') if clone_depth: try: clone_depth = int(clone_depth) if clone_depth <= 0: raise ValueError() except ValueError: raise ManifestParseError('invalid clone-depth %s in %s' % (clone_depth, self.manifestFile)) dest_branch = node.getAttribute( 'dest-branch') or self._default.destBranchExpr upstream = node.getAttribute('upstream') groups = '' if node.hasAttribute('groups'): groups = node.getAttribute('groups') groups = self._ParseGroups(groups) if parent is None: relpath, worktree, gitdir, objdir = self.GetProjectPaths( name, path) else: relpath, worktree, gitdir, objdir = \ self.GetSubprojectPaths(parent, name, path) default_groups = ['all', 'name:%s' % name, 'path:%s' % relpath] groups.extend(set(default_groups).difference(groups)) if self.IsMirror and node.hasAttribute('force-path'): if node.getAttribute('force-path').lower() in ("yes", "true", "1"): gitdir = os.path.join(self.topdir, '%s.git' % path) project = Project(manifest=self, name=name, remote=remote.ToRemoteSpec(name), gitdir=gitdir, objdir=objdir, worktree=worktree, relpath=relpath, revisionExpr=revisionExpr, revisionId=None, rebase=rebase, groups=groups, sync_c=sync_c, sync_s=sync_s, clone_depth=clone_depth, upstream=upstream, parent=parent, dest_branch=dest_branch, **extra_proj_attrs) for n in node.childNodes: if n.nodeName == 'copyfile': self._ParseCopyFile(project, n) if n.nodeName == 'linkfile': self._ParseLinkFile(project, n) if n.nodeName == 'annotation': self._ParseAnnotation(project, n) if n.nodeName == 'project': project.subprojects.append( self._ParseProject(n, parent=project)) return project
def _ParseManifest(self, node_list): for node in itertools.chain(*node_list): if node.nodeName == 'remote': remote = self._ParseRemote(node) if remote: if remote.name in self._remotes: if remote != self._remotes[remote.name]: raise ManifestParseError( 'remote %s already exists with different attributes' % (remote.name)) else: self._remotes[remote.name] = remote for node in itertools.chain(*node_list): if node.nodeName == 'default': if self._default is not None: raise ManifestParseError('duplicate default in %s' % (self.manifestFile)) self._default = self._ParseDefault(node) if self._default is None: self._default = _Default() for node in itertools.chain(*node_list): if node.nodeName == 'notice': if self._notice is not None: raise ManifestParseError('duplicate notice in %s' % (self.manifestFile)) self._notice = self._ParseNotice(node) for node in itertools.chain(*node_list): if node.nodeName == 'manifest-server': url = self._reqatt(node, 'url') if self._manifest_server is not None: raise ManifestParseError( 'duplicate manifest-server in %s' % (self.manifestFile)) self._manifest_server = url def recursively_add_projects(project): if self._projects.get(project.name): raise ManifestParseError('duplicate project %s in %s' % (project.name, self.manifestFile)) self._projects[project.name] = project for subproject in project.subprojects: recursively_add_projects(subproject) for node in itertools.chain(*node_list): if node.nodeName == 'project': project = self._ParseProject(node) recursively_add_projects(project) if node.nodeName == 'repo-hooks': # Get the name of the project and the (space-separated) list of enabled. repo_hooks_project = self._reqatt(node, 'in-project') enabled_repo_hooks = self._reqatt(node, 'enabled-list').split() # Only one project can be the hooks project if self._repo_hooks_project is not None: raise ManifestParseError('duplicate repo-hooks in %s' % (self.manifestFile)) # Store a reference to the Project. try: self._repo_hooks_project = self._projects[ repo_hooks_project] except KeyError: raise ManifestParseError( 'project %s not found for repo-hooks' % (repo_hooks_project)) # Store the enabled hooks in the Project object. self._repo_hooks_project.enabled_repo_hooks = enabled_repo_hooks if node.nodeName == 'remove-project': name = self._reqatt(node, 'name') try: del self._projects[name] except KeyError: raise ManifestParseError( 'remove-project element specifies non-existent ' 'project: %s' % name) # If the manifest removes the hooks project, treat it as if it deleted # the repo-hooks element too. if self._repo_hooks_project and (self._repo_hooks_project.name == name): self._repo_hooks_project = None
def _ParseProject(self, node, parent=None): """ reads a <project> element from the manifest file """ name = self._reqatt(node, 'name') if parent: name = self._JoinName(parent.name, name) remote = self._get_remote(node) if remote is None: remote = self._default.remote if remote is None: raise ManifestParseError( \ "no remote for project %s within %s" % \ (name, self.manifestFile)) revisionExpr = node.getAttribute('revision') if not revisionExpr: revisionExpr = self._default.revisionExpr if not revisionExpr: raise ManifestParseError( \ "no revision for project %s within %s" % \ (name, self.manifestFile)) path = node.getAttribute('path') if not path: path = name if path.startswith('/'): raise ManifestParseError( \ "project %s path cannot be absolute in %s" % \ (name, self.manifestFile)) rebase = node.getAttribute('rebase') if not rebase: rebase = True else: rebase = rebase.lower() in ("yes", "true", "1") sync_c = node.getAttribute('sync-c') if not sync_c: sync_c = False else: sync_c = sync_c.lower() in ("yes", "true", "1") sync_s = node.getAttribute('sync-s') if not sync_s: sync_s = self._default.sync_s else: sync_s = sync_s.lower() in ("yes", "true", "1") upstream = node.getAttribute('upstream') groups = '' if node.hasAttribute('groups'): groups = node.getAttribute('groups') groups = [x for x in re.split(r'[,\s]+', groups) if x] if parent is None: relpath, worktree, gitdir = self.GetProjectPaths(name, path) else: relpath, worktree, gitdir = self.GetSubprojectPaths(parent, path) default_groups = ['all', 'name:%s' % name, 'path:%s' % relpath] groups.extend(set(default_groups).difference(groups)) project = Project(manifest=self, name=name, remote=remote.ToRemoteSpec(name), gitdir=gitdir, worktree=worktree, relpath=relpath, revisionExpr=revisionExpr, revisionId=None, rebase=rebase, groups=groups, sync_c=sync_c, sync_s=sync_s, upstream=upstream, parent=parent) for n in node.childNodes: if n.nodeName == 'copyfile': self._ParseCopyFile(project, n) if n.nodeName == 'annotation': self._ParseAnnotation(project, n) if n.nodeName == 'project': project.subprojects.append( self._ParseProject(n, parent=project)) return project
def _ParseManifest(self, is_root_file): root = xml.dom.minidom.parse(self.manifestFile) if not root or not root.childNodes: raise ManifestParseError("no root node in %s" % self.manifestFile) config = root.childNodes[0] if config.nodeName != 'manifest': raise ManifestParseError("no <manifest> in %s" % self.manifestFile) for node in config.childNodes: if node.nodeName == 'remove-project': name = self._reqatt(node, 'name') try: del self._projects[name] except KeyError: raise ManifestParseError('project %s not found' % (name)) # If the manifest removes the hooks project, treat it as if it deleted # the repo-hooks element too. if self._repo_hooks_project and (self._repo_hooks_project.name == name): self._repo_hooks_project = None for node in config.childNodes: if node.nodeName == 'remote': remote = self._ParseRemote(node) if self._remotes.get(remote.name): raise ManifestParseError('duplicate remote %s in %s' % (remote.name, self.manifestFile)) self._remotes[remote.name] = remote for node in config.childNodes: if node.nodeName == 'default': if self._default is not None: raise ManifestParseError('duplicate default in %s' % (self.manifestFile)) self._default = self._ParseDefault(node) if self._default is None: self._default = _Default() for node in config.childNodes: if node.nodeName == 'notice': if self._notice is not None: raise ManifestParseError('duplicate notice in %s' % (self.manifestFile)) self._notice = self._ParseNotice(node) for node in config.childNodes: if node.nodeName == 'manifest-server': url = self._reqatt(node, 'url') if self._manifest_server is not None: raise ManifestParseError( 'duplicate manifest-server in %s' % (self.manifestFile)) self._manifest_server = url for node in config.childNodes: if node.nodeName == 'project': project = self._ParseProject(node) if self._projects.get(project.name): raise ManifestParseError('duplicate project %s in %s' % (project.name, self.manifestFile)) self._projects[project.name] = project for node in config.childNodes: if node.nodeName == 'repo-hooks': # Get the name of the project and the (space-separated) list of enabled. repo_hooks_project = self._reqatt(node, 'in-project') enabled_repo_hooks = self._reqatt(node, 'enabled-list').split() # Only one project can be the hooks project if self._repo_hooks_project is not None: raise ManifestParseError('duplicate repo-hooks in %s' % (self.manifestFile)) # Store a reference to the Project. try: self._repo_hooks_project = self._projects[ repo_hooks_project] except KeyError: raise ManifestParseError( 'project %s not found for repo-hooks' % (repo_hooks_project)) # Store the enabled hooks in the Project object. self._repo_hooks_project.enabled_repo_hooks = enabled_repo_hooks