def inner(pool, path, rev): repos_ptr = repos.svn_repos_open(path, pool) fs_ptr = repos.svn_repos_fs(repos_ptr) root = fs.revision_root(fs_ptr, rev, pool) base_rev = rev - 1 # get all changes editor = repos.RevisionChangeCollector(fs_ptr, rev, pool) e_ptr, e_baton = delta.make_editor(editor, pool) repos.svn_repos_replay(root, e_ptr, e_baton, pool) changelist = editor.changes.items() changelist.sort() base_root = fs.revision_root(fs_ptr, base_rev, pool) l = [] for filepath, change in changelist: d = {'path': filepath, 'info': ''} if change.path: if change.added: d['action'] = 'new' else: d['action'] = 'modify' differ = fs.FileDiff(base_root, change.path, root, filepath, pool, '-L \t(original) -L \t(new) -u'.split(' ')) d['info'] = differ.get_pipe().read() else: d['action'] = 'delete' l.append(d) return l
def _print_tree(self, e_factory, base_rev=None, pass_root=0): if base_rev is None: # a specific base rev was not provided. use the transaction base, # or the previous revision if self.txn_ptr: base_rev = fs.txn_base_revision(self.txn_ptr) else: base_rev = self.rev - 1 # get the current root if self.txn_ptr: root = fs.txn_root(self.txn_ptr) else: root = fs.revision_root(self.fs_ptr, self.rev) # the base of the comparison base_root = fs.revision_root(self.fs_ptr, base_rev) if pass_root: editor = e_factory(root, base_root) else: editor = e_factory() # construct the editor for printing these things out e_ptr, e_baton = delta.make_editor(editor) # compute the delta, printing as we go def authz_cb(root, path, pool): return 1 repos.dir_delta(base_root, '', '', root, '', e_ptr, e_baton, authz_cb, 0, 1, 0, 0)
def load(self, repo_path): repo_path = core.svn_path_canonicalize(repo_path) repos_ptr = repos.open(repo_path) fs_ptr = repos.fs(repos_ptr) rev = fs.youngest_rev(fs_ptr) base_root = fs.revision_root(fs_ptr, 0) root = fs.revision_root(fs_ptr, rev) hist = fs.node_history(root, self.root) while hist is not None: hist = fs.history_prev(hist,0) dummy,rev = fs.history_location(hist) d = fs.revision_prop(fs_ptr, rev, core.SVN_PROP_REVISION_DATE) author = fs.revision_prop(fs_ptr, rev, \ core.SVN_PROP_REVISION_AUTHOR) if author == 'svnadmin': continue self.last_author = author self.last_date = core.svn_time_from_cstring(d) / 1000000 self.last_rev = rev def authz_cb(root, path, pool): return 1 editor = SvnDumperEditor(self) e_ptr, e_baton = delta.make_editor(editor) repos.dir_delta(base_root, '', '', root, self.root, e_ptr, e_baton, authz_cb, 0, 1, 0, 0) break
def _print_tree(self, e_factory, rootpath='', base_rev=None, pass_root=0): # It no longer prints, it returns the editor made by e_factory which # contains the tree in a list. if base_rev is None: # a specific base rev was not provided. use the transaction base, # or the previous revision if self.txn_ptr: base_rev = fs.txn_base_revision(self.txn_ptr) else: base_rev = self.rev - 1 # get the current root if self.txn_ptr: root = fs.txn_root(self.txn_ptr, self.pool) else: root = fs.revision_root(self.fs_ptr, self.rev, self.pool) # the base of the comparison base_root = fs.revision_root(self.fs_ptr, base_rev, self.pool) if pass_root: editor = e_factory(root, base_root) else: editor = e_factory() # construct the editor for printing these things out e_ptr, e_baton = delta.make_editor(editor, self.pool) # compute the delta, printing as we go def authz_cb(root, path, pool): return 1 repos.dir_delta(base_root, '', '', root, rootpath.encode('utf-8'), e_ptr, e_baton, authz_cb, 0, 1, 0, 0, self.pool) return editor
def blame(path, filename, rev=None): annotresult = {} path = core.svn_path_canonicalize(path) repos_ptr = repos.open(path) fsob = repos.fs(repos_ptr) if rev is None: rev = fs.youngest_rev(fsob) filedata = '' for i in range(0, rev+1): root = fs.revision_root(fsob, i) if fs.check_path(root, filename) != core.svn_node_none: first = i break print("First revision is %d" % first) print("Last revision is %d" % rev) for i in range(first, rev+1): previousroot = root root = fs.revision_root(fsob, i) if i != first: if not fs.contents_changed(root, filename, previousroot, filename): continue file = fs.file_contents(root, filename) previousdata = filedata filedata = '' while True: data = core.svn_stream_read(file, CHUNK_SIZE) if not data: break filedata = filedata + data print("Current revision is %d" % i) diffresult = difflib.ndiff(previousdata.splitlines(1), filedata.splitlines(1)) # print ''.join(diffresult) k = 0 for j in diffresult: if j[0] == ' ': if k in annotresult: k = k + 1 continue else: annotresult[k] = (i, j[2:]) k = k + 1 continue elif j[0] == '?': continue annotresult[k] = (i, j[2:]) if j[0] != '-': k = k + 1 # print ''.join(diffresult) # print annotresult for x in range(len(annotresult.keys())): sys.stdout.write("Line %d (r%d):%s" % (x, annotresult[x][0], annotresult[x][1]))
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 test_unnamed_editor(self): """Test editor object without reference from interpreter""" # Check that the delta.Editor object has proper lifetime. Without # increment of the refcount in make_baton, the object was destroyed # immediately because the interpreter does not hold a reference to it. this_root = fs.revision_root(self.fs, self.rev) prev_root = fs.revision_root(self.fs, self.rev-1) e_ptr, e_baton = delta.make_editor(ChangeReceiver(this_root, prev_root)) repos.dir_delta(prev_root, '', '', this_root, '', e_ptr, e_baton, _authz_callback, 1, 1, 0, 0)
def test_dir_delta(self): """Test scope of dir_delta callbacks""" # Run dir_delta this_root = fs.revision_root(self.fs, self.rev) prev_root = fs.revision_root(self.fs, self.rev-1) editor = ChangeReceiver(this_root, prev_root) e_ptr, e_baton = delta.make_editor(editor) repos.dir_delta(prev_root, '', '', this_root, '', e_ptr, e_baton, _authz_callback, 1, 1, 0, 0) # Check results self.assertEqual(editor.textdeltas[0].new_data, "This is a test.\n") self.assertEqual(editor.textdeltas[1].new_data, "A test.\n") self.assertEqual(len(editor.textdeltas),2)
def get_copy_ancestry(self): """Retrieve the list of `(path,rev)` copy ancestors of this node. Most recent ancestor first. Each ancestor `(path, rev)` corresponds to the path and revision of the source at the time the copy or move operation was performed. """ ancestors = [] previous = (self._scoped_path_utf8, self.rev, self.root) while previous: (previous_path, previous_rev, previous_root) = previous previous = None root_path = fs.closest_copy(previous_root, previous_path) if root_path: (root, path) = root_path path = path.lstrip('/') rev = fs.revision_root_revision(root) relpath = None if path != previous_path: # `previous_path` is a subfolder of `path` and didn't # change since `path` was copied relpath = previous_path[len(path):].strip('/') copied_from = fs.copied_from(root, path) if copied_from: (rev, path) = copied_from path = path.lstrip('/') root = fs.revision_root(self.fs_ptr, rev, self.pool()) if relpath: path += '/' + relpath ui_path = _path_within_scope(self.scope, _from_svn(path)) if ui_path: ancestors.append((ui_path, rev)) previous = (path, rev, root) return ancestors
def _history(self, path, start, end, pool): """`path` is a unicode path in the scope. Generator yielding `(path, rev)` pairs, where `path` is an `unicode` object. Must start with `(path, created rev)`. (wraps ``fs.node_history``) """ path_utf8 = _to_svn(pool(), self.scope, path) if start < end: start, end = end, start if (start, end) == (1, 0): # only happens for empty repos return root = fs.revision_root(self.fs_ptr, start, pool()) # fs.node_history leaks when path doesn't exist (#6588) if fs.check_path(root, path_utf8, pool()) == core.svn_node_none: return tmp1 = Pool(pool) tmp2 = Pool(pool) history_ptr = fs.node_history(root, path_utf8, tmp1()) cross_copies = 1 while history_ptr: history_ptr = fs.history_prev(history_ptr, cross_copies, tmp2()) tmp1.clear() tmp1, tmp2 = tmp2, tmp1 if history_ptr: path_utf8, rev = fs.history_location(history_ptr, tmp2()) tmp2.clear() if rev < end: break path = _from_svn(path_utf8) yield path, rev del tmp1 del tmp2
def has_node(self, path, rev=None, pool=None): if not pool: pool = self.pool rev = self.normalize_rev(rev) rev_root = fs.revision_root(self.fs_ptr, rev, pool()) node_type = fs.check_path(rev_root, _to_svn(self.scope, path), pool()) return node_type in _kindmap
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 add_history(self, path, revision, pool): # If filtering, only add the path and revision to the histories # list if they were actually changed in this revision (where # change means the path itself was changed, or one of its parents # was copied). This is useful for omitting bubble-up directory # changes. if not self.oldest_rev: self.oldest_rev = revision else: assert(revision < self.oldest_rev) if not self.show_all_logs: rev_root = fs.revision_root(self.fs_ptr, revision) changed_paths = fs.paths_changed(rev_root) paths = changed_paths.keys() if path not in paths: # Look for a copied parent test_path = path found = 0 while 1: off = test_path.rfind('/') if off < 0: break test_path = test_path[0:off] if test_path in paths: copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, test_path) if copyfrom_rev >= 0 and copyfrom_path: found = 1 break if not found: return self.histories.append([revision, _cleanup_path(path)]) if self.limit and len(self.histories) == self.limit: raise core.SubversionException("", _SVN_ERR_CEASE_INVOCATION)
def add_history(self, path, revision, pool): # If filtering, only add the path and revision to the histories # list if they were actually changed in this revision (where # change means the path itself was changed, or one of its parents # was copied). This is useful for omitting bubble-up directory # changes. if not self.show_all_logs: rev_root = fs.revision_root(self.fs_ptr, revision, pool) changed_paths = fs.paths_changed(rev_root, pool) paths = changed_paths.keys() if path not in paths: # Look for a copied parent test_path = path found = 0 subpool = core.svn_pool_create(pool) while 1: core.svn_pool_clear(subpool) off = string.rfind(test_path, '/') if off < 0: break test_path = test_path[0:off] if test_path in paths: copyfrom_rev, copyfrom_path = \ fs.copied_from(rev_root, test_path, subpool) if copyfrom_rev >= 0 and copyfrom_path: found = 1 break core.svn_pool_destroy(subpool) if not found: return self.histories[revision] = _cleanup_path(path)
def _history(self, svn_path, start, end, pool): """`svn_path` must be a full scope path, UTF-8 encoded string. Generator yielding `(path, rev)` pairs, where `path` is an `unicode` object. Must start with `(path, created_rev)`. """ if start < end: start, end = end, start root = fs.revision_root(self.fs_ptr, start, pool()) tmp1 = Pool(pool) tmp2 = Pool(pool) history_ptr = fs.node_history(root, svn_path, tmp1()) cross_copies = 1 while history_ptr: history_ptr = fs.history_prev(history_ptr, cross_copies, tmp2()) tmp1.clear() tmp1, tmp2 = tmp2, tmp1 if history_ptr: path, rev = fs.history_location(history_ptr, tmp2()) tmp2.clear() if rev < end: break path = _from_svn(path) yield path, rev del tmp1 del tmp2
def __init__(self, path, rev, authz, scope, fs_ptr): self.authz = authz self.scope = scope if scope != '/': self.scoped_path = scope + path else: self.scoped_path = path self.fs_ptr = fs_ptr self._requested_rev = rev self.root = fs.revision_root(fs_ptr, rev) node_type = fs.check_path(self.root, self.scoped_path) if not node_type in _kindmap: raise TracError, "No node at %s in revision %s" % (path, rev) self.created_rev = fs.node_created_rev(self.root, self.scoped_path) self.created_path = fs.node_created_path(self.root, self.scoped_path) # Note: 'created_path' differs from 'path' if the last change was a copy, # and furthermore, 'path' might not exist at 'create_rev'. # The only guarantees are: # * this node exists at (path,rev) # * the node existed at (created_path,created_rev) # TODO: check node id self.rev = self.created_rev Node.__init__(self, path, self.rev, _kindmap[node_type])
def __init__(self, path, rev, repos, pool=None, parent=None): self.path = path self.repos = repos self.fs_ptr = repos.fs_ptr self.scope = repos.scope self._scoped_svn_path = _to_svn(self.scope, path) self.pool = Pool(pool) self._requested_rev = rev pool = self.pool() if parent and parent._requested_rev == self._requested_rev: self.root = parent.root else: self.root = fs.revision_root(self.fs_ptr, rev, self.pool()) node_type = fs.check_path(self.root, self._scoped_svn_path, pool) if not node_type in _kindmap: raise Exception('No such node') if _kindmap[node_type] == 'F': self.isdir = False self.isfile = True elif _kindmap[node_type] == 'D': self.isdir = True self.isfile = False cr = fs.node_created_rev(self.root, self._scoped_svn_path, pool) cp = fs.node_created_path(self.root, self._scoped_svn_path, pool) if _is_path_within_scope(self.scope, cp): self.created_rev = cr self.created_path = _path_within_scope(self.scope, _from_svn(cp)) else: self.created_rev, self.created_path = rev, path self.rev = self.created_rev
def _get_root(self, rev): try: return self.roots[rev] except KeyError: pass root = self.roots[rev] = _svnfs.revision_root(self.fs_ptr, rev) return root
def test_dir_delta(self): """Test scope of dir_delta callbacks""" # Run dir_delta this_root = fs.revision_root(self.fs, self.rev) prev_root = fs.revision_root(self.fs, self.rev-1) editor = ChangeReceiver(this_root, prev_root) e_ptr, e_baton = delta.make_editor(editor) repos.dir_delta(prev_root, '', '', this_root, '', e_ptr, e_baton, _authz_callback, 1, 1, 0, 0) # Check results. # Ignore the order in which the editor delivers the two sibling files. self.assertEqual(set([editor.textdeltas[0].new_data, editor.textdeltas[1].new_data]), set(["This is a test.\n", "A test.\n"])) self.assertEqual(len(editor.textdeltas), 2)
def putfile(fname, rpath, uname="", commitmsg=""): rpath = core.svn_path_canonicalize(rpath) repos_ptr = repos.open(rpath) fsob = repos.fs(repos_ptr) # open a transaction against HEAD rev = fs.youngest_rev(fsob) txn = repos.fs_begin_txn_for_commit(repos_ptr, rev, uname, commitmsg) root = fs.txn_root(txn) rev_root = fs.revision_root(fsob, rev) kind = fs.check_path(root, fname) if kind == core.svn_node_none: print("file '%s' does not exist, creating..." % fname) fs.make_file(root, fname) elif kind == core.svn_node_dir: print("File '%s' is a dir." % fname) return else: print("Updating file '%s'" % fname) handler, baton = fs.apply_textdelta(root, fname, None, None) ### it would be nice to get an svn_stream_t. for now, just load in the ### whole file and shove it into the FS. delta.svn_txdelta_send_string(open(fname, 'rb').read(), handler, baton) newrev = repos.fs_commit_txn(repos_ptr, txn) print("revision: %s" % newrev)
def get_node_id(pool, repos_path, path, revision): # Open the repository and filesystem. repos_ptr = repos.open(repos_path, pool) fs_ptr = repos.fs(repos_ptr) # Fetch the node revision ID of interest rev_root = fs.revision_root(fs_ptr, int(revision), pool) return fs.unparse_id(fs.node_id(rev_root, path, pool), pool)
def has_node(self, path, rev=None, pool=None): """Check if `path` exists at `rev` (or latest if unspecified)""" if not pool: pool = self.pool rev = self.normalize_rev(rev) rev_root = fs.revision_root(self.fs_ptr, rev, pool()) node_type = fs.check_path(rev_root, _to_svn(pool(), self.scope, path), pool()) return node_type in _kindmap
def test_diff_repos_paths_internal(self): """Test diffing of a repository path using the internal diff.""" # Test standard internal diff fdiff = fs.FileDiff(fs.revision_root(self.fs, self.commitedrev), "/trunk/UniTest.txt", None, None, diffoptions=None) diffp = fdiff.get_pipe() diffoutput = diffp.read().decode('utf8') self.assertTrue(diffoutput.find(u'-' + self.unistr) > 0)
def _log_helper(self, path, rev, lockinfo): rev_root = fs.revision_root(self.fs_ptr, rev) copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, path) date, author, msg, revprops, changes = self._revinfo(rev) if fs.is_file(rev_root, path): size = fs.file_length(rev_root, path) else: size = None return Revision(rev, date, author, msg, size, lockinfo, path, copyfrom_path and _cleanup_path(copyfrom_path), copyfrom_rev)
def check_po(pool, repos_path, txn): def authz_cb(root, path, pool): return 1 fs_ptr = repos.fs(repos.open(repos_path, pool)) txn_ptr = fs.open_txn(fs_ptr, txn, pool) txn_root = fs.txn_root(txn_ptr, pool) base_root = fs.revision_root(fs_ptr, fs.txn_base_revision(txn_ptr), pool) editor = ChangeReceiver(txn_root, base_root, pool) e_ptr, e_baton = delta.make_editor(editor, pool) repos.dir_delta(base_root, "", "", txn_root, "", e_ptr, e_baton, authz_cb, 0, 1, 0, 0, pool)
def __init__(self, path): """initialize an SVNShell object""" Cmd.__init__(self) path = core.svn_path_canonicalize(path) self.fs_ptr = repos.fs(repos.open(path)) self.is_rev = 1 self.rev = fs.youngest_rev(self.fs_ptr) self.txn = None self.root = fs.revision_root(self.fs_ptr, self.rev) self.path = "/" self._setup_prompt() self.cmdloop()
def dumpprops(path, filename='', rev=None): path = core.svn_path_canonicalize(path) repos_ptr = repos.open(path) fsob = repos.fs(repos_ptr) if rev is None: rev = fs.youngest_rev(fsob) root = fs.revision_root(fsob, rev) print_props(root, filename) if fs.is_dir(root, filename): walk_tree(root, filename)
def _check_history(self, path, revision): root = fs.revision_root(self.fs_ptr, revision) changes = fs.paths_changed(root) while 1: if changes.has_key(path): return 1 if path == '/': return 0 idx = string.rfind(path, '/') if idx != -1: path = path[:idx] else: return 0
def _check_history(self, path, revision): root = fs.revision_root(self.fs_ptr, revision) changes = fs.paths_changed(root) while True: if path in changes: return 1 if path == '/': return 0 idx = path.rfind('/') if idx != -1: path = path[:idx] else: return 0
def __init__(self, path, rev, txn): self.repo_root_path = core.svn_path_canonicalize(path) root_ptr = repos.open(self.repo_root_path) self.fs_ptr = repos.fs(root_ptr) # Set the revision/transaction if txn: self.txn_ptr = fs.open_txn(self.fs_ptr, txn) else: self.txn_ptr = None if rev is None: rev = fs.youngest_rev(self.fs_ptr) self.rev = rev # Set the root if self.txn_ptr: self.root = fs.txn_root(self.txn_ptr) else: self.root = fs.revision_root(self.fs_ptr, self.rev) # Set the base revision/transaction if self.txn_ptr: self.base_rev = fs.txn_base_revision(self.txn_ptr) else: self.base_rev = self.rev - 1 # Set the base root of the comparison self.base_root = fs.revision_root(self.fs_ptr, self.base_rev) # Get all the changes and sort by path editor = repos.ChangeCollector(self.fs_ptr, self.root) e_ptr, e_baton = delta.make_editor(editor) repos.replay(self.root, e_ptr, e_baton) self.changelist = editor.get_changes().items() self.changelist.sort()
def test_diff_repos_paths_external(self): """Test diffing of a repository path using an external diff (if available).""" # Test if this environment has the diff command, if not then skip the test try: diffout, differr = Popen(["diff"], stdin=PIPE, stderr=PIPE).communicate() except OSError as err: if err.errno == errno.ENOENT: self.skipTest("'diff' command not present") else: raise err fdiff = fs.FileDiff(fs.revision_root(self.fs, self.commitedrev), "/trunk/UniTest.txt", None, None, diffoptions=[]) diffp = fdiff.get_pipe() diffoutput = diffp.read().decode('utf8') self.assertTrue(diffoutput.find(u'< ' + self.unistr) > 0)
def _history(self, svn_path, start, end, pool): """`svn_path` must be a full scope path, UTF-8 encoded string. Generator yielding `(path, rev)` pairs, where `path` is an `unicode` object. Must start with `(path, created rev)`. """ if start < end: start, end = end, start root = fs.revision_root(self.fs_ptr, start, pool()) history_ptr = fs.node_history(root, svn_path, pool()) cross_copies = 1 while history_ptr: history_ptr = fs.history_prev(history_ptr, cross_copies, pool()) if history_ptr: path, rev = fs.history_location(history_ptr, pool()) if rev < end: break path = _from_svn(path) if not self.authz.has_permission(path): break yield path, rev
def __init__(self, path, rev, authz, scope, fs_ptr, pool=None): self.authz = authz self.scope = scope if scope != '/': self.scoped_path = scope + path else: self.scoped_path = path self.fs_ptr = fs_ptr self.pool = Pool(pool) self._requested_rev = rev self.root = fs.revision_root(fs_ptr, rev, self.pool()) node_type = fs.check_path(self.root, self.scoped_path, self.pool()) if not node_type in _kindmap: raise TracError, "No node at %s in revision %s" % (path, rev) self.created_rev = fs.node_created_rev(self.root, self.scoped_path, self.pool()) self.created_path = fs.node_created_path(self.root, self.scoped_path, self.pool()) # 'created_path' differs from 'path' if the last operation is a copy, # and furthermore, 'path' might not exist at 'create_rev' self.rev = self.created_rev Node.__init__(self, path, self.rev, _kindmap[node_type])
def get_changes(self): pool = Pool(self.pool) tmp = Pool(pool) root = fs.revision_root(self.fs_ptr, self.rev, pool()) editor = repos.RevisionChangeCollector(self.fs_ptr, self.rev, pool()) e_ptr, e_baton = delta.make_editor(editor, pool()) repos.svn_repos_replay(root, e_ptr, e_baton, pool()) idx = 0 copies, deletions = {}, {} changes = [] revroots = {} for path, change in editor.changes.items(): # Filtering on `path` if not (_is_path_within_scope(self.scope, path) and \ self.authz.has_permission(path)): continue path = change.path base_path = change.base_path base_rev = change.base_rev # Ensure `base_path` is within the scope if not (_is_path_within_scope(self.scope, base_path) and \ self.authz.has_permission(base_path)): base_path, base_rev = None, -1 # Determine the action if not path: # deletion if base_path: if base_path in deletions: continue # duplicates on base_path are possible (#3778) action = Changeset.DELETE deletions[base_path] = idx elif self.scope: # root property change action = Changeset.EDIT else: # deletion outside of scope, ignore continue elif change.added or not base_path: # add or copy action = Changeset.ADD if base_path and base_rev: action = Changeset.COPY copies[base_path] = idx else: action = Changeset.EDIT # identify the most interesting base_path/base_rev # in terms of last changed information (see r2562) if revroots.has_key(base_rev): b_root = revroots[base_rev] else: b_root = fs.revision_root(self.fs_ptr, base_rev, pool()) revroots[base_rev] = b_root tmp.clear() cbase_path = fs.node_created_path(b_root, base_path, tmp()) cbase_rev = fs.node_created_rev(b_root, base_path, tmp()) # give up if the created path is outside the scope if _is_path_within_scope(self.scope, cbase_path): base_path, base_rev = cbase_path, cbase_rev kind = _kindmap[change.item_kind] path = _path_within_scope(self.scope, _from_svn(path or base_path)) base_path = _path_within_scope(self.scope, _from_svn(base_path)) changes.append([path, kind, action, base_path, base_rev]) idx += 1 moves = [] for k, v in copies.items(): if k in deletions: changes[v][2] = Changeset.MOVE moves.append(deletions[k]) offset = 0 moves.sort() for i in moves: del changes[i - offset] offset += 1 changes.sort() for change in changes: yield tuple(change)
def has_node(self, path, rev, pool=None): if not pool: pool = self.pool rev_root = fs.revision_root(self.fs_ptr, rev, pool()) node_type = fs.check_path(rev_root, _to_svn(self.scope, path), pool()) return node_type in _kindmap
def main(pool, repos_dir, rev, config_fp): # Construct a ChangeCollector to fetch our changes. fs_ptr = repos.svn_repos_fs(repos.svn_repos_open(repos_dir, pool)) root = fs.revision_root(fs_ptr, rev, pool) # Get revision properties we need. (Subversion 1.2) # cc = repos.ChangeCollector(fs_ptr, root, pool) # props = cc.get_root_props() # author = str(props.get(core.SVN_PROP_REVISION_AUTHOR, '')) # log = str(props.get(core.SVN_PROP_REVISION_LOG, '')) # Get revision properties we need. (Subversion 1.1) cc = repos.RevisionChangeCollector(fs_ptr, rev, pool) author = fs.revision_prop(fs_ptr, rev, core.SVN_PROP_REVISION_AUTHOR, pool) log = fs.revision_prop(fs_ptr, rev, core.SVN_PROP_REVISION_LOG, pool) ### Do any Subversion-to-Scarab author mappings here ### # Example: # _authors = { # 'miw':'mick', # 'lif':'lisefr', # 'gni':'gunleik', # 'man':'Maja', # 'ako':'konand', # 'hho':'helga', # 'hba':'hilde', # 'rgc':'rgc' # } # author = _authors.get(author, author) # Now build the comment. First we start with some header # information about the revision, and a link to the ViewCVS revision # view. e_ptr, e_baton = delta.make_editor(cc, pool) repos.svn_repos_replay(root, e_ptr, e_baton, pool) comment = "%s %d: %s/?view=rev&rev=%d\n" \ % (MSG_SUBVERSION_COMMIT, rev, VIEWCVS_URL, rev) comment = comment + \ """------------------------------------------------------------------------- %s ------------------------------------------------------------------------- """ % log # Next, we'll figure out which paths changed and use that # information to generate ViewCVS links. # changes = cc.get_changes() # Subversion 1.2 changes = cc.changes # Subversion 1.1 paths = changes.keys() # paths.sort(lambda a, b: core.svn_path_compare_paths(a, b)) # Subversion 1.2 for path in paths: change = changes[path] diff_url = '' action = None if not change.path: ### Deleted (show the last living version) action = MSG_ACTION_DELETED diff_url = '%s/%s?view=auto&rev=%d' \ % (VIEWCVS_URL, urllib.quote(change.base_path[1:]), change.base_rev) elif change.added: ### Added if change.base_path and (change.base_rev != -1): ### (with history) action = MSG_ACTION_COPIED diff_url = '%s/%s?view=diff&rev=%d&p1=%s&r1=%d&p2=%s&r2=%d' \ % (VIEWCVS_URL, urllib.quote(change.path), rev, urllib.quote(change.base_path[1:]), change.base_rev, urllib.quote(change.path), rev) else: ### (without history, show new file) action = MSG_ACTION_ADDED diff_url = '%s/%s?view=auto&rev=%d' \ % (VIEWCVS_URL, urllib.quote(change.path), rev) elif change.text_changed: ### Modified action = MSG_ACTION_MODIFIED diff_url = '%s/%s?view=diff&rev=%d&p1=%s&r1=%d&p2=%s&r2=%d' \ % (VIEWCVS_URL, urllib.quote(change.path), rev, urllib.quote(change.base_path[1:]), change.base_rev, urllib.quote(change.path), rev) if action: comment = comment + "%s: %s\n %s\n" % (action, path, diff_url) # Connect to the xmlrpc server, and transmit our data. Server(SCARAB_XMLRPC_URL).simple.addComment(log, author, comment, DISABLE_EMAILS)
def get_deltas(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 TracError('The Base for Diff is invalid: path %s' ' doesn\'t exist in revision %s' \ % (old_path, old_rev)) if self.has_node(new_path, new_rev): new_node = self.get_node(new_path, new_rev) else: raise TracError('The Target for Diff is invalid: path %s' ' doesn\'t exist in revision %s' \ % (new_path, new_rev)) 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)) if new_node.isdir: editor = DiffChangeEditor() e_ptr, e_baton = delta.make_editor(editor) old_root = fs.revision_root(self.fs_ptr, old_rev) new_root = fs.revision_root(self.fs_ptr, new_rev) 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, old_path, b'', new_root, new_path, e_ptr, e_baton, authz_cb, text_deltas, 1, # directory entry_props, ignore_ancestry) for path, kind, change in editor.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, old_node.path)] yield (old_node, new_node, kind, change) else: old_root = fs.revision_root(self.fs_ptr, old_rev) new_root = fs.revision_root(self.fs_ptr, new_rev) if fs.contents_changed(old_root, old_path, new_root, new_path): yield (old_node, new_node, Node.FILE, Changeset.EDIT)
def suspicious_host(host): if host[0] == '-': return True for char in host: if not curses.ascii.isalnum(char) and not char in ':.-_[]@': return True return False native = locale.getlocale()[1] if not native: native = 'ascii' repos_handle = repos.open(sys.argv[1].decode(native).encode('utf-8')) fs_handle = repos.fs(repos_handle) txn_handle = fs.open_txn(fs_handle, sys.argv[2].decode(native).encode('utf-8')) txn_root = fs.txn_root(txn_handle) rev_root = fs.revision_root(fs_handle, fs.txn_root_base_revision(txn_root)) for path, change in fs.paths_changed2(txn_root).iteritems(): if change.prop_mod: # The new value, if any txn_prop = fs.node_prop(txn_root, path, "svn:externals") if not txn_prop: continue # The old value, if any rev_prop = None if change.change_kind == fs.path_change_modify: rev_prop = fs.node_prop(rev_root, path, "svn:externals") elif change.change_kind == fs.path_change_add and change.copyfrom_path:
def has_node(self, path, rev): rev_root = fs.revision_root(self.fs_ptr, rev) node_type = fs.check_path(rev_root, path) return node_type in _kindmap
def get_changes(self): """Retrieve file changes for a given revision. (wraps ``repos.svn_repos_replay``) """ pool = Pool(self.pool) tmp = Pool(pool) root = fs.revision_root(self.fs_ptr, self.rev, pool()) editor = repos.RevisionChangeCollector(self.fs_ptr, self.rev, pool()) e_ptr, e_baton = delta.make_editor(editor, pool()) repos.svn_repos_replay(root, e_ptr, e_baton, pool()) idx = 0 copies, deletions = {}, {} changes = [] revroots = {} for path_utf8, change in editor.changes.items(): new_path = _from_svn(path_utf8) # Filtering on `path` if not _is_path_within_scope(self.scope, new_path): continue path_utf8 = change.path base_path_utf8 = change.base_path path = _from_svn(path_utf8) base_path = _from_svn(base_path_utf8) base_rev = change.base_rev change_action = getattr(change, 'action', None) # Ensure `base_path` is within the scope if not _is_path_within_scope(self.scope, base_path): base_path, base_rev = None, -1 # Determine the action if not path and not new_path and self.scope == '/': action = Changeset.EDIT # root property change elif not path or (change_action is not None and change_action == repos.CHANGE_ACTION_DELETE): if new_path: # deletion action = Changeset.DELETE deletions[new_path.lstrip('/')] = idx else: # deletion outside of scope, ignore continue elif change.added or not base_path: # add or copy action = Changeset.ADD if base_path and base_rev: action = Changeset.COPY copies[base_path.lstrip('/')] = idx else: action = Changeset.EDIT # identify the most interesting base_path/base_rev # in terms of last changed information (see r2562) if base_rev in revroots: b_root = revroots[base_rev] else: b_root = fs.revision_root(self.fs_ptr, base_rev, pool()) revroots[base_rev] = b_root tmp.clear() cbase_path_utf8 = fs.node_created_path(b_root, base_path_utf8, tmp()) cbase_path = _from_svn(cbase_path_utf8) cbase_rev = fs.node_created_rev(b_root, base_path_utf8, tmp()) # give up if the created path is outside the scope if _is_path_within_scope(self.scope, cbase_path): base_path, base_rev = cbase_path, cbase_rev kind = _kindmap[change.item_kind] path = _path_within_scope(self.scope, new_path or base_path) base_path = _path_within_scope(self.scope, base_path) changes.append([path, kind, action, base_path, base_rev]) idx += 1 moves = [] # a MOVE is a COPY whose `base_path` corresponds to a `new_path` # which has been deleted for k, v in copies.items(): if k in deletions: changes[v][2] = Changeset.MOVE moves.append(deletions[k]) offset = 0 moves.sort() for i in moves: del changes[i - offset] offset += 1 changes.sort() for change in changes: yield tuple(change)
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 __init__(self, fs_ptr, root, pool=None, notify_cb=None): root = _svnfs.revision_root(fs_ptr, root) ChangeCollector.__init__(self, fs_ptr, root, pool, notify_cb)
def _getroot(self, rev): try: return self._fsroots[rev] except KeyError: r = self._fsroots[rev] = fs.revision_root(self.fs_ptr, rev) return r
def _get_changes(self, old_path, old_rev, new_path, new_rev, ignore_ancestry): 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()) 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(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, u'La base pour le calcul des ' u'différences est invalide') if self.has_node(new_path, new_rev): new_node = self.get_node(new_path, new_rev) else: raise NoSuchNode( new_path, new_rev, u'La cible pour le calcul des ' u'différences est invalide') if new_node.kind != old_node.kind: raise TracError(u'Erreur de calcul des différences: La base est un' u'%s (%s en révision %s) ' u'et la cible est un %s (%s en révision %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)