Example #1
0
    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])
Example #2
0
    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
Example #3
0
File: svn_fs.py Project: t2y/trac
    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])
Example #4
0
    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])
Example #5
0
    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])
Example #6
0
def dump_tree(fsob, root, pool, path, indent=0):
  path = path + '/'

  entries = fs.dir_entries(root, path, pool)

  names = entries.keys()
  names.sort()

  subpool = _util.svn_pool_create(pool)

  for name in names:
    child = path + name
    line = ' '*indent + name

    id = fs.dirent_t_id_get(entries[name])
    is_dir = fs.is_dir(root, child, subpool)
    if is_dir:
      print line + '/'
      dump_tree(fsob, root, subpool, child, indent+2)
    else:
      rev = fs.node_created_rev(root, child, subpool)
      author = fs.revision_prop(fsob, rev, 'svn:author', pool)
      print line, author, rev

    _util.svn_pool_clear(subpool)

  _util.svn_pool_destroy(subpool)
Example #7
0
    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))
Example #8
0
  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))
Example #9
0
File: svn_fs.py Project: akun/atrac
    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]
Example #10
0
    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])
Example #11
0
 def created_rev(self, full_name, rev):
   return fs.node_created_rev(self._getroot(rev), full_name)
Example #12
0
File: svn_fs.py Project: t2y/trac
    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)
Example #13
0
 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():
         if not (_is_path_within_scope(self.scope, path)):
             continue
         
         path = change.path
         base_path = change.base_path
         base_rev = change.base_rev
         
         if not (_is_path_within_scope(self.scope, base_path)):
             base_path, base_rev = None, -1
         
         if not path:
             if base_path:
                 if base_path in deletions:
                     continue
                 action = 'D'
                 deletions[base_path] = idx
             elif self.scope == '/':
                 action = 'E'
             else:
                 continue
         elif change.added or not base_path:
             action = 'A'
             if base_path and base_rev:
                 action = 'C'
                 copies[base_path] = idx
         else:
             action = 'E'
             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())
             
             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': path, 'kind': kind, 'action': action,
                         'base_path': base_path, 'base_rev': base_rev})
         idx += 1
     
     moves = []
     for k,v in copies.items():
         if k in deletions:
             changes[v]['action'] = 'M'
             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 change
Example #14
0
 def created(self):
     return self.switch_rev(fs.node_created_rev(self._revision._root, self.path))
Example #15
0
 def created_rev(self, full_name, rev):
     return fs.node_created_rev(self._getroot(rev), full_name)
Example #16
0
    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)
Example #17
0
def created_rev(svnrepos, full_name, rev):
    fsroot = svnrepos._getroot(rev)
    return fs.node_created_rev(fsroot, full_name, svnrepos.pool)
Example #18
0
def created_rev(svnrepos, full_name, rev):
  fsroot = svnrepos._getroot(rev)
  return fs.node_created_rev(fsroot, full_name, svnrepos.pool)
Example #19
0
    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 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_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)
Example #20
0
    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)