def __init__(self, path, rev, repos, pool=None, parent_root=None): self.fs_ptr = repos.fs_ptr self.scope = repos.scope self.pool = Pool(pool) pool = self.pool() self._scoped_path_utf8 = _to_svn(pool, self.scope, path) if parent_root: self.root = parent_root else: self.root = fs.revision_root(self.fs_ptr, rev, pool) node_type = fs.check_path(self.root, self._scoped_path_utf8, pool) if not node_type in _kindmap: raise NoSuchNode(path, rev) cp_utf8 = fs.node_created_path(self.root, self._scoped_path_utf8, pool) cp = _from_svn(cp_utf8) cr = fs.node_created_rev(self.root, self._scoped_path_utf8, pool) # Note: `cp` differs from `path` if the last change was a copy, # In that case, `path` doesn't even exist at `cr`. # The only guarantees are: # * this node exists at (path,rev) # * the node existed at (created_path,created_rev) # Also, `cp` might well be out of the scope of the repository, # in this case, we _don't_ use the ''create'' information. if _is_path_within_scope(self.scope, cp): self.created_rev = cr self.created_path = _path_within_scope(self.scope, cp) else: self.created_rev, self.created_path = rev, path # TODO: check node id Node.__init__(self, repos, path, rev, _kindmap[node_type])
def __init__(self, git, path, rev, tree_ls_info=None): self.git = git self.sha = rev self.perm = None self.data_len = None kind = Node.DIRECTORY p = path.strip('/') if p != "": if tree_ls_info == None or tree_ls_info == "": tree_ls_info = git.tree_ls(rev, p) if tree_ls_info != []: [tree_ls_info] = tree_ls_info else: tree_ls_info = None if tree_ls_info is None: raise NoSuchNode(path, rev) (self.perm, k, self.sha, fn) = tree_ls_info rev = self.git.last_change(rev, p) if k == 'tree': pass elif k == 'blob': kind = Node.FILE else: self.log.debug("kind is " + k) Node.__init__(self, path, rev, kind) self.created_path = path self.created_rev = rev
def _get_kind(self): if self._node.isDirectory: return Node.DIRECTORY elif self._node.isFile: return Node.FILE else: raise NoSuchNode(self._nodePath.path, self._nodePath.rev)
def _get_node(path, rev=None): if path == 'foo': return Mock(path=path, rev=rev, isfile=False, is_viewable=lambda resource: True) elif path == 'missing/file': raise NoSuchNode(path, rev) else: return Mock(path=path, rev=rev, isfile=True, is_viewable=lambda resource: True)
def _init_path(self, log, path): kind = None if path in self.manifest: # then it's a file kind = Node.FILE file_n = self.manifest[path] log_rev = self.repos.repo.file(path).linkrev(file_n) node = log.node(log_rev) else: # it will be a directory if there are matching entries dir = path and path + '/' or '' entries = {} newest = -1 for file in self.manifest.keys(): if file.startswith(dir): entry = file[len(dir):].split('/', 1)[0] entries[entry] = 1 if path: # small optimization: we skip this for root node file_n = self.manifest[file] log_rev = self.repos.repo.file(file).linkrev(file_n) newest = max(log_rev, newest) if entries: kind = Node.DIRECTORY self.entries = entries.keys() if newest >= 0: node = log.node(newest) else: # ... as it's the youngest anyway node = log.tip() if not kind: if log.tip() == nullid: # empty repository kind = Node.DIRECTORY self.entries = [] node = nullid else: raise NoSuchNode(path, self.repos.hg_display(self.n)) self.time = self.repos.hg_time(log.read(node)[2]) rev = self.repos.hg_display(node) Node.__init__(self, path, rev, kind) self.created_path = path self.created_rev = rev self.data = None
def get_changes(self, old_path, old_rev, new_path, new_rev, ignore_ancestry=0): """Determine differences between two arbitrary pairs of paths and revisions. (wraps ``repos.svn_repos_dir_delta``) """ old_node = new_node = None old_rev = self.normalize_rev(old_rev) new_rev = self.normalize_rev(new_rev) if self.has_node(old_path, old_rev): old_node = self.get_node(old_path, old_rev) else: raise NoSuchNode(old_path, old_rev, 'The Base for Diff is invalid') if self.has_node(new_path, new_rev): new_node = self.get_node(new_path, new_rev) else: raise NoSuchNode(new_path, new_rev, 'The Target for Diff is invalid') if new_node.kind != old_node.kind: raise TracError(_('Diff mismatch: Base is a %(oldnode)s ' '(%(oldpath)s in revision %(oldrev)s) and ' 'Target is a %(newnode)s (%(newpath)s in ' 'revision %(newrev)s).', oldnode=old_node.kind, oldpath=old_path, oldrev=old_rev, newnode=new_node.kind, newpath=new_path, newrev=new_rev)) subpool = Pool(self.pool) if new_node.isdir: editor = DiffChangeEditor() e_ptr, e_baton = delta.make_editor(editor, subpool()) old_root = fs.revision_root(self.fs_ptr, old_rev, subpool()) new_root = fs.revision_root(self.fs_ptr, new_rev, subpool()) def authz_cb(root, path, pool): return 1 text_deltas = 0 # as this is anyway re-done in Diff.py... entry_props = 0 # "... typically used only for working copy updates" repos.svn_repos_dir_delta(old_root, _to_svn(subpool(), self.scope, old_path), '', new_root, _to_svn(subpool(), self.scope, new_path), e_ptr, e_baton, authz_cb, text_deltas, 1, # directory entry_props, ignore_ancestry, subpool()) # sort deltas by path before creating `SubversionNode`s to reduce # memory usage (#10978) deltas = sorted(((_from_svn(path), kind, change) for path, kind, change in editor.deltas), key=lambda entry: entry[0]) for path, kind, change in deltas: old_node = new_node = None if change != Changeset.ADD: old_node = self.get_node(posixpath.join(old_path, path), old_rev) if change != Changeset.DELETE: new_node = self.get_node(posixpath.join(new_path, path), new_rev) else: kind = _kindmap[fs.check_path(old_root, _to_svn(subpool(), self.scope, old_node.path), subpool())] yield (old_node, new_node, kind, change) else: old_root = fs.revision_root(self.fs_ptr, old_rev, subpool()) new_root = fs.revision_root(self.fs_ptr, new_rev, subpool()) if fs.contents_changed(old_root, _to_svn(subpool(), self.scope, old_path), new_root, _to_svn(subpool(), self.scope, new_path), subpool()): yield (old_node, new_node, Node.FILE, Changeset.EDIT)
def get_changes(self, old_path, old_rev, new_path, new_rev, ignore_ancestry=0): old_node = new_node = None old_rev = self.normalize_rev(old_rev) new_rev = self.normalize_rev(new_rev) if self.has_node(old_path, old_rev): old_node = self.get_node(old_path, old_rev) else: raise NoSuchNode(old_path, old_rev, 'The Base for Diff is invalid') if self.has_node(new_path, new_rev): new_node = self.get_node(new_path, new_rev) else: raise NoSuchNode(new_path, new_rev, 'The Target for Diff is invalid') if new_node.kind != old_node.kind: raise TracError('Diff mismatch: Base is a %s (%s in revision %s) ' 'and Target is a %s (%s in revision %s).' \ % (old_node.kind, old_path, old_rev, new_node.kind, new_path, new_rev)) subpool = Pool(self.pool) if new_node.isdir: editor = DiffChangeEditor() e_ptr, e_baton = delta.make_editor(editor, subpool()) old_root = fs.revision_root(self.fs_ptr, old_rev, subpool()) new_root = fs.revision_root(self.fs_ptr, new_rev, subpool()) def authz_cb(root, path, pool): return 1 text_deltas = 0 # as this is anyway re-done in Diff.py... entry_props = 0 # "... typically used only for working copy updates" repos.svn_repos_dir_delta( old_root, _to_svn(self.scope + old_path), '', new_root, _to_svn(self.scope + new_path), e_ptr, e_baton, authz_cb, text_deltas, 1, # directory entry_props, ignore_ancestry, subpool()) for path, kind, change in editor.deltas: path = _from_svn(path) old_node = new_node = None if change != Changeset.ADD: old_node = self.get_node(posixpath.join(old_path, path), old_rev) if change != Changeset.DELETE: new_node = self.get_node(posixpath.join(new_path, path), new_rev) else: kind = _kindmap[fs.check_path( old_root, _to_svn(self.scope, old_node.path), subpool())] yield (old_node, new_node, kind, change) else: old_root = fs.revision_root(self.fs_ptr, old_rev, subpool()) new_root = fs.revision_root(self.fs_ptr, new_rev, subpool()) if fs.contents_changed(old_root, _to_svn(self.scope, old_path), new_root, _to_svn(self.scope, new_path), subpool()): yield (old_node, new_node, Node.FILE, Changeset.EDIT)
def get_history(self, limit=None): self._log.debug('PerforceNode.get_history(%r %s)' % (limit, self._nodePath.fullPath)) if self._node.isFile: # Force population of the filelog history for efficiency from p4trac.repos import _P4FileLogOutputConsumer output = _P4FileLogOutputConsumer(self._repos) if limit is None: self._repos._connection.run('filelog', '-i', '-l', self._repos.fromUnicode( self._nodePath.fullPath), output=output) else: self._repos._connection.run('filelog', '-i', '-l', '-m', str(limit), self._repos.fromUnicode( self._nodePath.fullPath), output=output) from p4trac.repos import NodePath currentNode = self._node i = 0 while i < limit and currentNode is not None: if currentNode.action in [u'add', u'branch', u'import']: if currentNode.integrations: nodePath, how = currentNode.integrations[0] # TODO: Detect whether the copy was really a move yield (normalisePath(currentNode.nodePath.path), currentNode.change, Changeset.COPY) currentNode = self._repos.getNode(nodePath) else: yield (normalisePath(currentNode.nodePath.path), currentNode.change, Changeset.ADD) if currentNode.fileRevision > 1: # Get the previous revision nodePath = NodePath( currentNode.nodePath.path, '#%i' % (currentNode.fileRevision - 1)) currentNode = self._repos.getNode(nodePath) else: currentNode = None elif currentNode.action in [u'edit', u'integrate']: nextNode = None if currentNode.integrations: nodePath, how = currentNode.integrations[0] if how == 'copy': yield (normalisePath(currentNode.nodePath.path), currentNode.change, Changeset.COPY) nextNode = self._repos.getNode(nodePath) else: yield (normalisePath(currentNode.nodePath.path), currentNode.change, Changeset.EDIT) else: yield (normalisePath(currentNode.nodePath.path), currentNode.change, Changeset.EDIT) if nextNode is None: if currentNode.fileRevision > 1: currentNode = self._repos.getNode( NodePath( currentNode.nodePath.path, '#%i' % (currentNode.fileRevision - 1))) else: currentNode = None else: currentNode = nextNode elif currentNode.action in [u'delete']: yield (normalisePath(currentNode.nodePath.path), currentNode.change, Changeset.DELETE) if currentNode.fileRevision > 1: currentNode = self._repos.getNode( NodePath(currentNode.nodePath.path, '#%i' % (currentNode.fileRevision - 1))) else: currentNode = None i += 1 elif self._node.isDirectory: # List all changelists that have affected this directory from p4trac.repos import _P4ChangesOutputConsumer output = _P4ChangesOutputConsumer(self._repos) if self._nodePath.isRoot: queryPath = '@<=%s' % self._nodePath.rev[1:] else: queryPath = '%s/...@<=%s' % (self._nodePath.path, self._nodePath.rev[1:]) if limit is None: self._repos._connection.run('changes', '-l', '-s', 'submitted', self._repos.fromUnicode(queryPath), output=output) else: self._repos._connection.run('changes', '-l', '-s', 'submitted', '-m', str(limit), self._repos.fromUnicode(queryPath), output=output) if output.errors: raise PerforceError(output.errors) changes = output.changes # And describe the contents of those changelists from p4trac.repos import _P4DescribeOutputConsumer output = _P4DescribeOutputConsumer(self._repos) self._repos._connection.run('describe', '-s', output=output, *[str(c) for c in changes]) from p4trac.repos import NodePath for i in xrange(len(changes)): change = changes[i] nodePath = NodePath(self._nodePath.path, change) if i < len(changes) - 1: prevChange = changes[i + 1] else: prevChange = change - 1 prevNodePath = NodePath(self._nodePath.path, prevChange) node = self._repos.getNode(nodePath) prevNode = self._repos.getNode(prevNodePath) if node.isDirectory: if prevNode.isDirectory: yield (normalisePath(self._nodePath.path), change, Changeset.EDIT) else: yield (normalisePath(self._nodePath.path), change, Changeset.ADD) elif prevNode.isDirectory: yield (normalisePath(self._nodePath.path), change, Changeset.DELETE) else: raise NoSuchNode(self._nodePath.path, self._nodePath.rev)