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 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 xrange(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 xrange(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 1: 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 annotresult.has_key(k): 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 xrange(len(annotresult.keys())): sys.stdout.write("Line %d (rev %d):%s" % (x, annotresult[x][0], annotresult[x][1]))
def get_path_history(self, path, rev=None, limit=None): path = self.normalize_path(path) rev = self.normalize_rev(rev) expect_deletion = False subpool = Pool(self.pool) while rev: subpool.clear() rev_root = fs.revision_root(self.fs_ptr, rev, subpool()) node_type = fs.check_path(rev_root, path, subpool()) if node_type in _kindmap: # then path exists at that rev if expect_deletion: # it was missing, now it's there again: rev+1 must be a delete yield path, rev + 1, Changeset.DELETE newer = None # 'newer' is the previously seen history tuple older = None # 'older' is the currently examined history tuple for p, r in _get_history(path, self.authz, self.fs_ptr, subpool, 0, rev, limit): older = (self.normalize_path(p), r, Changeset.ADD) rev = self.previous_rev(r) if newer: if older[ 0] == path: # still on the path: 'newer' was an edit yield newer[0], newer[1], Changeset.EDIT else: # the path changed: 'newer' was a copy rev = self.previous_rev( newer[1]) # restart before the copy op yield newer[0], newer[1], Changeset.COPY older = (older[0], older[1], 'unknown') break newer = older if older: # either a real ADD or the source of a COPY yield older else: expect_deletion = True rev = self.previous_rev(rev)
def __init__(self, path, rev, authz, scope, fs_ptr): self.authz = authz self.scope = scope if scope != b'/': 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.decode('UTF-8'), 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 _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 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_history(self, path, rev, path_type, limit=0, options={}): if self.youngest == 0: return [] rev_paths = [] fsroot = self._getroot(rev) show_all_logs = options.get("svn_show_all_dir_logs", 0) if not show_all_logs: # See if the path is a file or directory. kind = fs.check_path(fsroot, path) if kind is core.svn_node_file: show_all_logs = 1 # Instantiate a NodeHistory collector object, and use it to collect # history items for PATH@REV. history = NodeHistory(self.fs_ptr, show_all_logs, limit) try: repos.svn_repos_history(self.fs_ptr, path, history.add_history, 1, rev, options.get("svn_cross_copies", 0)) except core.SubversionException as e: if e.apr_err != core.SVN_ERR_CEASE_INVOCATION: raise # Now, iterate over those history items, checking for changes of # location, pruning as necessitated by authz rules. for hist_rev, hist_path in history: hist_path = _to_str(hist_path) path_parts = _path_parts(hist_path) if not vclib.check_path_access(self, path_parts, path_type, hist_rev): break rev_paths.append([hist_rev, hist_path]) return rev_paths
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 __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 write(self, data, uname='', commitmsg='',istext=False): txn = repos.fs_begin_txn_for_commit(self._repo.repos_ptr, self.revno, uname, commitmsg) r = None try: txn_root = fs.txn_root(txn) kind = fs.check_path(txn_root, self.path) if kind == core.svn_node_none: if not _create_file(txn_root, self.path): raise 'attempt to create file, but file creation error: %s'%path pass elif kind == core.svn_node_dir: raise 'attempt to create file, but directory already exists: %s'%self.path if istext: fs.change_node_prop(txn_root, self.path, 'svn:eol-style', 'native') pass handler, baton = fs.apply_textdelta(txn_root, self.path, None, None) delta.svn_txdelta_send_string(data, handler, baton) r = repos.fs_commit_txn(self._repo.repos_ptr, txn) except Exception, a: fs.abort_txn(txn) raise
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 _create_dirs(txn_root, cpath): if not cpath: return True kind = fs.check_path(txn_root,cpath) if kind == core.svn_node_dir: return True elif kind == core.svn_node_file: return False for dpath,p in misc.iterdir(cpath): dpath = _c(dpath) kind = fs.check_path(txn_root, dpath) if kind == core.svn_node_none: fs.make_dir(txn_root, dpath) continue pass return True
def do_ls(self, arg): """list the contents of the current directory or provided path""" parent = self.path if not len(arg): # no arg -- show a listing for the current directory. entries = fs.dir_entries(self.root, self.path) else: # arg? show a listing of that path. newpath = self._parse_path(arg) kind = fs.check_path(self.root, newpath) if kind == core.svn_node_dir: parent = newpath entries = fs.dir_entries(self.root, parent) elif kind == core.svn_node_file: parts = self._path_to_parts(newpath) name = parts.pop(-1) parent = self._parts_to_path(parts) print(parent + ':' + name) tmpentries = fs.dir_entries(self.root, parent) if not tmpentries.get(name, None): return entries = {} entries[name] = tmpentries[name] else: print("Path '%s' not found." % newpath) return keys = sorted(entries.keys()) print(" REV AUTHOR NODE-REV-ID SIZE DATE NAME") print( "----------------------------------------------------------------------------" ) for entry in keys: fullpath = parent + '/' + entry size = '' is_dir = fs.is_dir(self.root, fullpath) if is_dir: name = entry + '/' else: size = str(fs.file_length(self.root, fullpath)) name = entry node_id = fs.unparse_id(entries[entry].id) created_rev = fs.node_created_rev(self.root, fullpath) author = fs.revision_prop(self.fs_ptr, created_rev, core.SVN_PROP_REVISION_AUTHOR) if not author: author = "" date = fs.revision_prop(self.fs_ptr, created_rev, core.SVN_PROP_REVISION_DATE) if not date: date = "" else: date = self._format_date(date) print("%6s %8s %12s %8s %12s %s" % (created_rev, author[:8], node_id, size, date, name))
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 do_ls(self, arg): """list the contents of the current directory or provided path""" parent = self.path if not len(arg): # no arg -- show a listing for the current directory. entries = fs.dir_entries(self.root, self.path) else: # arg? show a listing of that path. newpath = self._parse_path(arg) kind = fs.check_path(self.root, newpath) if kind == core.svn_node_dir: parent = newpath entries = fs.dir_entries(self.root, parent) elif kind == core.svn_node_file: parts = self._path_to_parts(newpath) name = parts.pop(-1) parent = self._parts_to_path(parts) print(parent + ':' + name) tmpentries = fs.dir_entries(self.root, parent) if not tmpentries.get(name, None): return entries = {} entries[name] = tmpentries[name] else: print("Path '%s' not found." % newpath) return keys = sorted(entries.keys()) print(" REV AUTHOR NODE-REV-ID SIZE DATE NAME") print("----------------------------------------------------------------------------") for entry in keys: fullpath = parent + '/' + entry size = '' is_dir = fs.is_dir(self.root, fullpath) if is_dir: name = entry + '/' else: size = str(fs.file_length(self.root, fullpath)) name = entry node_id = fs.unparse_id(entries[entry].id) created_rev = fs.node_created_rev(self.root, fullpath) author = fs.revision_prop(self.fs_ptr, created_rev, core.SVN_PROP_REVISION_AUTHOR) if not author: author = "" date = fs.revision_prop(self.fs_ptr, created_rev, core.SVN_PROP_REVISION_DATE) if not date: date = "" else: date = self._format_date(date) print("%6s %8s %12s %8s %12s %s" % (created_rev, author[:8], node_id, size, date, name))
def itemtype(self, path_parts, rev): rev = self._getrev(rev) basepath = self._getpath(path_parts) kind = fs.check_path(self._getroot(rev), basepath, self.scratch_pool) self._scratch_clear() if kind == core.svn_node_dir: return vclib.DIR if kind == core.svn_node_file: return vclib.FILE raise vclib.ItemNotFound(path_parts)
def do_cd(self, arg): """change directory""" newpath = self._parse_path(arg) # make sure that path actually exists in the filesystem as a directory kind = fs.check_path(self.root, newpath) if kind != core.svn_node_dir: print("Path '%s' is not a valid filesystem directory." % newpath) return self.path = newpath
def _gettype(self, path, rev): # Similar to itemtype(), but without the authz check. Returns # None for missing paths. try: kind = fs.check_path(self._getroot(rev), path) except Exception: return None if kind == core.svn_node_dir: return vclib.DIR if kind == core.svn_node_file: return vclib.FILE return None
def _gettype(self, path, rev): # Similar to itemtype(), but without the authz check. Returns # None for missing paths. try: kind = fs.check_path(self._getroot(rev), path) except: return None if kind == core.svn_node_dir: return vclib.DIR if kind == core.svn_node_file: return vclib.FILE return None
def _do_path_landing(self): """try to land on self.path as a directory in root, failing up to '/'""" not_found = 1 newpath = self.path while not_found: kind = fs.check_path(self.root, newpath) if kind == core.svn_node_dir: not_found = 0 else: parts = self._path_to_parts(newpath) parts.pop(-1) newpath = self._parts_to_path(parts) self.path = newpath
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, '', 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 get_entries(self, path): # lots of conversions from and to utf-8 disk_url = directory(self.name).encode('utf-8') root_path_utf8 = repos.svn_repos_find_root_path(disk_url) if root_path_utf8 is None or not os.path.exists(root_path_utf8): if os.path.exists(disk_url): raise EncodingError(disk_url) raise DoesNotExistError(disk_url) try: repository = repos.svn_repos_open(root_path_utf8) except SubversionException as e: # check for messages like the following: # "Expected FS Format 'x'; found format 'y'" # there are different errorcodes for each version, so do a string # match instead of errorcode match errstr = str(e) if "Expected" in errstr and "format" in errstr and "found" in errstr: raise VersionError raise PermissionError fs_ptr = repos.svn_repos_fs(repository) path_utf8 = path youngest_revision_number = fs.youngest_rev(fs_ptr) try: root = fs.revision_root(fs_ptr, youngest_revision_number) except SubversionException as e: raise PermissionError entries = fs.dir_entries(root, path_utf8) # returns list of bytes-strings dirs = [] for entry in entries.keys(): entry_utf8 = entry.decode('utf-8') d = {} node_type = fs.check_path(root, os.path.join(path_utf8, entry_utf8)) if (node_type == core.svn_node_dir): d['kind'] = 'dir' elif (node_type == core.svn_node_file): d['kind'] = 'file' else: d['kind'] = 'unknown' d['name'] = entry_utf8 dirs.append(d) return dirs
def get_entries(self, path): # lots of conversions from and to utf-8 disk_url = directory(self.name) root_path_utf8 = repos.svn_repos_find_root_path(disk_url) if root_path_utf8 is None or not os.path.exists(root_path_utf8): raise DoesNotExistError(disk_url) try: repository = repos.svn_repos_open(root_path_utf8) except SubversionException as e: # check for messages like the following: # "Expected FS Format 'x'; found format 'y'" # there are different errorcodes for each version, so do a string # match instead of errorcode match errstr = str(e) if "Expected" in errstr and "format" in errstr and "found" in errstr: raise VersionError raise PermissionError fs_ptr = repos.svn_repos_fs(repository) path_utf8 = uc_to_svn(uc_str(path)) youngest_revision_number = fs.youngest_rev(fs_ptr) try: root = fs.revision_root(fs_ptr, youngest_revision_number) except SubversionException as e: raise PermissionError entries = fs.dir_entries(root, path_utf8) dirs = [] for entry in entries.keys(): d = {} node_type = fs.check_path(root, os.path.join(path_utf8, entry)) if (node_type == core.svn_node_dir): d['kind'] = 'dir' elif (node_type == core.svn_node_file): d['kind'] = 'file' else: d['kind'] = 'unknown' d['name'] = uc_from_svn(entry) dirs.append(d) return dirs
def do_pcat(self, arg): """list the properties of a path""" catpath = self.path if len(arg): catpath = self._parse_path(arg) kind = fs.check_path(self.root, catpath) if kind == core.svn_node_none: print("Path '%s' does not exist." % catpath) return plist = fs.node_proplist(self.root, catpath) if not plist: return for pkey, pval in plist.items(): print('K ' + str(len(pkey))) print(pkey) print('P ' + str(len(pval))) print(pval) print('PROPS-END')
def add(self, deltas): """ Add the supplied set of deltas to the repository. They will all be added with the same user name, date, and comment. """ # Split up the deltas array into smaller sub-arrays, otherwise # we choke running out of memory due to really large changesets # like the CDDL 2005/06/08 putback in ON that touched every file while len(deltas): if len(deltas) > 1000: print "partitioning deltas into smaller new_deltas" new_deltas = deltas[:1000] deltas = deltas[1000:] # Add all of the directories first, or we will be trying # to cross transactions, which is bad. for delta in new_deltas: self._addDirectories(delta) print "preparing %s version %s (%s) by %s" % (delta.pathname, delta.version, delta.date, delta.author) subpool = core.svn_pool_create(self.pool) (revision, transaction, root) = self._revisionSetup(subpool, new_deltas[0].author, new_deltas[0].comment) for delta in new_deltas: subversionPath = delta.getRepositoryName() kind = fs.check_path(root, subversionPath, subpool) if kind == core.svn_node_none: fs.make_file(root, subversionPath, subpool) elif kind == core.svn_node_dir: raise EnvironmentError(subversionPath + " already present as a directory.") handler, baton = fs.apply_textdelta(root, subversionPath, None, None, subpool) svn.delta.svn_txdelta_send_string(delta.getFileContents(), handler, baton, subpool) if delta.version.isdigit: fs.change_node_prop(root, subversionPath, 'sccs:sid', delta.version, subpool) print "sending ", subversionPath, delta.getDate(), "by", delta.author print "committing version ", print self._commit(revision, delta.getDate(), transaction, subpool) core.svn_pool_destroy(subpool)
def _get_history(svnrepos, full_name, rev, options={}): fsroot = svnrepos._getroot(rev) show_all_logs = options.get('svn_show_all_dir_logs', 0) if not show_all_logs: # See if the path is a file or directory. kind = fs.check_path(fsroot, full_name, svnrepos.pool) if kind is core.svn_node_file: show_all_logs = 1 # Instantiate a NodeHistory collector object. history = NodeHistory(svnrepos.fs_ptr, show_all_logs) # Do we want to cross copy history? cross_copies = options.get('svn_cross_copies', 0) # Get the history items for PATH. repos.svn_repos_history(svnrepos.fs_ptr, full_name, history.add_history, 1, rev, cross_copies, svnrepos.pool) return history.histories
def do_cat(self, arg): """dump the contents of a file""" if not len(arg): print("You must supply a file path.") return catpath = self._parse_path(arg) kind = fs.check_path(self.root, catpath) if kind == core.svn_node_none: print("Path '%s' does not exist." % catpath) return if kind == core.svn_node_dir: print("Path '%s' is not a file." % catpath) return ### be nice to get some paging in here. stream = fs.file_contents(self.root, catpath) while True: data = core.svn_stream_read(stream, core.SVN_STREAM_CHUNK_SIZE) sys.stdout.write(data) if len(data) < core.SVN_STREAM_CHUNK_SIZE: break
def __init__(self, path, file_path, rev=None): self.file_path = file_path self.path = path repos_path = core.svn_path_canonicalize( os.path.normpath(self.path).replace('\\', '/') ) svn_repos = repos.svn_repos_open(repos_path) fs_ptr = repos.svn_repos_fs(svn_repos) if rev: self.rev = rev else: self.rev = fs.youngest_rev(fs_ptr) self.root = fs.revision_root(fs_ptr, self.rev) self.kind = KIND_MAP[fs.check_path(self.root, self.file_path)] self.name = os.path.split(self.file_path)[-1] self.cr = fs.node_created_rev(self.root, self.file_path) props = fs.revision_proplist(fs_ptr, self.cr) self.date = props[core.SVN_PROP_REVISION_DATE] self.author = props[core.SVN_PROP_REVISION_AUTHOR] self.log = props[core.SVN_PROP_REVISION_LOG]
def validate_added_extensions(repos_path, txn_name, extensions, action): # Open the repository and transaction. fs_ptr = repos.fs(repos.open(repos_path)) txn_t = fs.open_txn(fs_ptr, txn_name) txn_root = fs.txn_root(txn_t) # Fetch the changes made in this transaction. changes = fs.svn_fs_paths_changed(txn_root) paths = changes.keys() # Check the changes. for path in paths: change = changes[path] # Always allow deletions. if change.change_kind == fs.path_change_delete: continue # Always allow non-files. kind = fs.check_path(txn_root, path) if kind != core.svn_node_file: continue # If this was a newly added (without history) file ... if ((change.change_kind == fs.path_change_replace) \ or (change.change_kind == fs.path_change_add)): copyfrom_rev, copyfrom_path = fs.copied_from(txn_root, path) if copyfrom_rev == core.SVN_INVALID_REVNUM: # ... then check it for a valid extension. base, ext = os.path.splitext(path) if ext: ext = ext[1:].lower() if ((ext in extensions) and (action == 'deny')) \ or ((ext not in extensions) and (action == 'allow')): sys.stderr.write( "Path '%s' has an extension disallowed by server " "configuration.\n" % (path)) sys.exit(1)
def validate_added_extensions(repos_path, txn_name, extensions, action): # Open the repository and transaction. fs_ptr = repos.fs(repos.open(repos_path)) txn_t = fs.open_txn(fs_ptr, txn_name) txn_root = fs.txn_root(txn_t) # Fetch the changes made in this transaction. changes = fs.svn_fs_paths_changed(txn_root) paths = changes.keys() # Check the changes. for path in paths: change = changes[path] # Always allow deletions. if change.change_kind == fs.path_change_delete: continue # Always allow non-files. kind = fs.check_path(txn_root, path) if kind != core.svn_node_file: continue # If this was a newly added (without history) file ... if ((change.change_kind == fs.path_change_replace) \ or (change.change_kind == fs.path_change_add)): copyfrom_rev, copyfrom_path = fs.copied_from(txn_root, path) if copyfrom_rev == core.SVN_INVALID_REVNUM: # ... then check it for a valid extension. base, ext = os.path.splitext(path) if ext: ext = ext[1:].lower() if ((ext in extensions) and (action == 'deny')) \ or ((ext not in extensions) and (action == 'allow')): sys.stderr.write("Path '%s' has an extension disallowed by server " "configuration.\n" % (path)) sys.exit(1)
def _get_history(self, path, rev, path_type, limit=0, options={}): if self.youngest == 0: return [] rev_paths = [] fsroot = self._getroot(rev) show_all_logs = options.get('svn_show_all_dir_logs', 0) if not show_all_logs: # See if the path is a file or directory. kind = fs.check_path(fsroot, path) if kind is core.svn_node_file: show_all_logs = 1 # Instantiate a NodeHistory collector object, and use it to collect # history items for PATH@REV. history = NodeHistory(self.fs_ptr, show_all_logs, limit) try: repos.svn_repos_history(self.fs_ptr, path, history.add_history, 1, rev, options.get('svn_cross_copies', 0)) except core.SubversionException, e: _fix_subversion_exception(e) if e.apr_err != _SVN_ERR_CEASE_INVOCATION: raise
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 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, self.scope + path, pool()) return node_type in _kindmap
def commit(self, t_fs, ctx): # commit this transaction print 'committing: %s, over %d seconds' % (time.ctime( self.t_min), self.t_max - self.t_min) # create a pool for the entire commit c_pool = util.svn_pool_create(ctx.pool) rev = fs.youngest_rev(t_fs, c_pool) txn = fs.begin_txn(t_fs, rev, c_pool) root = fs.txn_root(txn, c_pool) lastcommit = (None, None) # create a pool for each file; it will be cleared on each iteration f_pool = util.svn_pool_create(c_pool) for f, r in self.changes: # compute a repository path. ensure we have a leading "/" and drop # the ,v from the file name repos_path = '/' + relative_name(ctx.cvsroot, f[:-2]) #print 'DEBUG:', repos_path print ' changing %s : %s' % (r, repos_path) ### hmm. need to clarify OS path separators vs FS path separators dirname = os.path.dirname(repos_path) if dirname != '/': # get the components of the path (skipping the leading '/') parts = string.split(dirname[1:], os.sep) for i in range(1, len(parts) + 1): # reassemble the pieces, adding a leading slash parent_dir = '/' + string.join(parts[:i], '/') if fs.check_path(root, parent_dir, f_pool) == svn_node_none: print ' making dir:', parent_dir fs.make_dir(root, parent_dir, f_pool) if fs.check_path(root, repos_path, f_pool) == svn_node_none: created_file = 1 fs.make_file(root, repos_path, f_pool) else: created_file = 0 handler, baton = fs.apply_textdelta(root, repos_path, f_pool) # figure out the real file path for "co" try: statcache.stat(f) except os.error: dirname, fname = os.path.split(f) f = os.path.join(dirname, 'Attic', fname) statcache.stat(f) pipe = os.popen('co -q -p%s %s' % (r, f), 'r', 102400) # if we just made the file, we can send it in one big hunk, rather # than streaming it in. ### we should watch out for file sizes here; we don't want to yank ### in HUGE files... if created_file: _delta.svn_txdelta_send_string(pipe.read(), handler, baton, f_pool) else: # open an SVN stream onto the pipe stream2 = util.svn_stream_from_stdio(pipe, f_pool) # Get the current file contents from the repo, or, if we have # multiple CVS revisions to the same file being done in this # single commit, then get the contents of the previous # revision from co, or else the delta won't be correct because # the contents in the repo won't have changed yet. if repos_path == lastcommit[0]: infile2 = os.popen("co -q -p%s %s" % (lastcommit[1], f), "r", 102400) stream1 = util.svn_stream_from_stdio(infile2, f_pool) else: stream1 = fs.file_contents(root, repos_path, f_pool) txstream = _delta.svn_txdelta(stream1, stream2, f_pool) _delta.svn_txdelta_send_txstream(txstream, handler, baton, f_pool) # shut down the previous-rev pipe, if we opened it infile2 = None # shut down the current-rev pipe pipe.close() # wipe the pool. this will get rid of the pipe streams and the delta # stream, and anything the FS may have done. util.svn_pool_clear(f_pool) # remember what we just did, for the next iteration lastcommit = (repos_path, r) for f, r in self.deletes: # compute a repository path. ensure we have a leading "/" and drop # the ,v from the file name repos_path = '/' + relative_name(ctx.cvsroot, f[:-2]) print ' deleting %s : %s' % (r, repos_path) # If the file was initially added on a branch, the first mainline # revision will be marked dead, and thus, attempts to delete it will # fail, since it doesn't really exist. if r != '1.1': ### need to discriminate between OS paths and FS paths fs.delete(root, repos_path, f_pool) # wipe the pool, in case the delete loads it up util.svn_pool_clear(f_pool) # get the metadata for this commit author, log, date = self.get_metadata(c_pool) fs.change_txn_prop(txn, 'svn:author', author, c_pool) fs.change_txn_prop(txn, 'svn:log', log, c_pool) conflicts, new_rev = fs.commit_txn(txn) # set the time to the proper (past) time fs.change_rev_prop(t_fs, new_rev, 'svn:date', date, c_pool) ### how come conflicts is a newline? if conflicts != '\n': print ' CONFLICTS:', ` conflicts ` print ' new revision:', new_rev # done with the commit and file pools util.svn_pool_destroy(c_pool)
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, 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)
def kind(self): return fs.check_path(self._revision._root, self.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, 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)