Author: julianfoad Date: Mon Nov 16 17:46:37 2015 New Revision: 1714640 URL: http://svn.apache.org/viewvc?rev=1714640&view=rev Log: Merge the 'svnmover' prototype from the 'move-tracking-2' branch to trunk.
See the dev@ email thread "Merge 'svnmover' demo tool to trunk" started on 2015-11-10, archived at e.g. <http://mail-archives.apache.org/mod_mbox/subversion-dev/201511.mbox/%3CCAEcU=1ye5ci02j_4aaeb_ros1x0h2qwpp3juu0exjvj-fgc...@mail.gmail.com%3E>. This is a reintegration (performed as an automatic merge) followed by reverting the unwanted parts. As such, those unwanted parts (such as shim insertions in several libraries) will be treated as 'record-only merged' and will not be picked up by any subsequent automatic merge to trunk. A brief description of the changes follows. * build.conf Adjust to build the new files. * configure.ac Adjust compiler warning flags to not warn about passing or returning a structure, because some of the code does so. * LICENSE Add the licence text for the embedded 'linenoise' library. * notes/move-tracking/README New file, describing this work. * subversion/include/private/svn_branch.h, subversion/include/private/svn_branch_compat.h, subversion/include/private/svn_branch_impl.h, subversion/include/private/svn_branch_nested.h, subversion/include/private/svn_branch_repos.h, subversion/include/private/svn_element.h New files. * subversion/libsvn_delta/branch.c, subversion/libsvn_delta/branch_compat.c, subversion/libsvn_delta/branch_migrate.c, subversion/libsvn_delta/branch_nested.c, subversion/libsvn_delta/branch_repos.c, subversion/libsvn_delta/element.c New files. * subversion/include/private/svn_cmdline_private.h subversion/libsvn_subr/cmdline.c (svn_cmdline__stdin_is_a_terminal, svn_cmdline__stdout_is_a_terminal, svn_cmdline__stderr_is_a_terminal): New. * subversion/tests/cmdline/svnmover_tests.py New file. * subversion/tests/cmdline/svntest/actions.py (run_and_verify_svnmover, run_and_verify_svnmover2): New. * subversion/tests/cmdline/svntest/main.py (svnmover_binary, run_svnmover): New. (execute_tests): Initialize 'svnmover_binary'. * subversion/tests/cmdline/svntest/wc.py (State): Add 'rename' and 'from_eids' methods. (StateItem): Add an 'eid' attribute. * tools/dev/svnmover New tool. Added: subversion/trunk/notes/move-tracking/ - copied from r1714632, subversion/branches/move-tracking-2/notes/move-tracking/ subversion/trunk/subversion/include/private/svn_branch.h - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/include/private/svn_branch.h subversion/trunk/subversion/include/private/svn_branch_compat.h - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/include/private/svn_branch_compat.h subversion/trunk/subversion/include/private/svn_branch_impl.h - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/include/private/svn_branch_impl.h subversion/trunk/subversion/include/private/svn_branch_nested.h - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/include/private/svn_branch_nested.h subversion/trunk/subversion/include/private/svn_branch_repos.h - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/include/private/svn_branch_repos.h subversion/trunk/subversion/include/private/svn_element.h - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/include/private/svn_element.h subversion/trunk/subversion/libsvn_delta/branch.c - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c subversion/trunk/subversion/libsvn_delta/branch_compat.c - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_compat.c subversion/trunk/subversion/libsvn_delta/branch_migrate.c - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_migrate.c subversion/trunk/subversion/libsvn_delta/branch_nested.c - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_nested.c subversion/trunk/subversion/libsvn_delta/branch_repos.c - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_repos.c subversion/trunk/subversion/libsvn_delta/element.c - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/libsvn_delta/element.c subversion/trunk/subversion/tests/cmdline/svnmover_tests.py - copied unchanged from r1714632, subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py subversion/trunk/tools/dev/svnmover/ - copied from r1714632, subversion/branches/move-tracking-2/tools/dev/svnmover/ Modified: subversion/trunk/ (props changed) subversion/trunk/LICENSE subversion/trunk/build.conf subversion/trunk/configure.ac subversion/trunk/notes/move-tracking/README (props changed) subversion/trunk/subversion/include/private/svn_cmdline_private.h subversion/trunk/subversion/libsvn_fs_x/ (props changed) subversion/trunk/subversion/libsvn_subr/cmdline.c subversion/trunk/subversion/tests/cmdline/svntest/actions.py subversion/trunk/subversion/tests/cmdline/svntest/main.py subversion/trunk/subversion/tests/cmdline/svntest/wc.py Propchange: subversion/trunk/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Mon Nov 16 17:46:37 2015 @@ -58,7 +58,7 @@ /subversion/branches/log-addressing:1509279-1546844 /subversion/branches/log-g-performance:870941-871032 /subversion/branches/merge-skips-obstructions:874525-874615 -/subversion/branches/move-tracking-2:1607334 +/subversion/branches/move-tracking-2:1606692-1714632 /subversion/branches/multi-layer-moves:1239019-1300930 /subversion/branches/nfc-nfd-aware-client:870276,870376 /subversion/branches/node_pool:1304828-1305388 Modified: subversion/trunk/LICENSE URL: http://svn.apache.org/viewvc/subversion/trunk/LICENSE?rev=1714640&r1=1714639&r2=1714640&view=diff ============================================================================== --- subversion/trunk/LICENSE (original) +++ subversion/trunk/LICENSE Mon Nov 16 17:46:37 2015 @@ -366,3 +366,32 @@ subversion/libsvn_subr/x509.h * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +For the (modified) 'linenoise' library in tools/dev/svnmover/linenoise + + Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com> + Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Modified: subversion/trunk/build.conf URL: http://svn.apache.org/viewvc/subversion/trunk/build.conf?rev=1714640&r1=1714639&r2=1714640&view=diff ============================================================================== --- subversion/trunk/build.conf (original) +++ subversion/trunk/build.conf Mon Nov 16 17:46:37 2015 @@ -45,6 +45,8 @@ private-includes = subversion/bindings/cxxhl/src/private/*.hpp subversion/bindings/javahl/native/*.hpp subversion/bindings/javahl/native/jniwrapper/jni_*.hpp + tools/dev/svnmover/linenoise/linenoise.h + tools/dev/svnmover/linenoise/linenoise.c subversion/libsvn_subr/utf8proc/utf8proc.h subversion/libsvn_subr/utf8proc/utf8proc.c subversion/libsvn_subr/utf8proc/utf8proc_data.c @@ -252,7 +254,7 @@ type = lib install = fsmod-lib path = subversion/libsvn_delta libs = libsvn_subr aprutil apriconv apr zlib -msvc-export = svn_delta.h private/svn_editor.h private/svn_delta_private.h +msvc-export = svn_delta.h private/svn_editor.h private/svn_delta_private.h private/svn_element.h private/svn_branch.h private/svn_branch_compat.h private/svn_branch_impl.h private/svn_branch_nested.h private/svn_branch_repos.h # Routines for diffing [libsvn_diff] @@ -1544,7 +1546,7 @@ path = build/win32 libs = __ALL_TESTS__ diff diff3 diff4 fsfs-access-map svnauth svn-populate-node-origins-index x509-parser svn-wc-db-tester - svn-mergeinfo-normalizer + svn-mergeinfo-normalizer svnmover [__LIBS__] type = project @@ -1673,3 +1675,12 @@ path = tools/dev sources = x509-parser.c install = tools libs = libsvn_subr apr + +[svnmover] +description = Subversion Mover Command Client +type = exe +path = tools/dev/svnmover +sources = *.c +libs = libsvn_client libsvn_ra libsvn_subr libsvn_delta apriconv apr +install = tools +manpages = tools/dev/svnmover/svnmover.1 Modified: subversion/trunk/configure.ac URL: http://svn.apache.org/viewvc/subversion/trunk/configure.ac?rev=1714640&r1=1714639&r2=1714640&view=diff ============================================================================== --- subversion/trunk/configure.ac (original) +++ subversion/trunk/configure.ac Mon Nov 16 17:46:37 2015 @@ -1054,7 +1054,7 @@ AS_HELP_STRING([--enable-maintainer-mode CFLAGS="$CFLAGS_KEEP" dnl Add flags that all versions of GCC (should) support - CMAINTAINERFLAGS="-Wall -Wpointer-arith -Wwrite-strings -Wshadow -Wformat=2 -Wunused -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wno-multichar -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wbad-function-cast $CMAINTAINERFLAGS" + CMAINTAINERFLAGS="-Wall -Wpointer-arith -Wwrite-strings -Wshadow -Wformat=2 -Wunused -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wno-multichar -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wbad-function-cast $CMAINTAINERFLAGS" fi if test "$GXX" = "yes"; then AC_MSG_NOTICE([maintainer-mode: adding G++ warning flags]) Propchange: subversion/trunk/notes/move-tracking/README ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Mon Nov 16 17:46:37 2015 @@ -55,6 +55,7 @@ /subversion/branches/log-addressing/BRANCH-README:1509279-1546844 /subversion/branches/log-g-performance/BRANCH-README:870941-871032 /subversion/branches/merge-skips-obstructions/BRANCH-README:874525-874615 +/subversion/branches/move-tracking-2/notes/move-tracking/README:1714595-1714632 /subversion/branches/multi-layer-moves/BRANCH-README:1239019-1300930 /subversion/branches/nfc-nfd-aware-client/BRANCH-README:870276,870376 /subversion/branches/node_pool/BRANCH-README:1304828-1305388 Modified: subversion/trunk/subversion/include/private/svn_cmdline_private.h URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_cmdline_private.h?rev=1714640&r1=1714639&r2=1714640&view=diff ============================================================================== --- subversion/trunk/subversion/include/private/svn_cmdline_private.h (original) +++ subversion/trunk/subversion/include/private/svn_cmdline_private.h Mon Nov 16 17:46:37 2015 @@ -213,6 +213,18 @@ svn_cmdline__getopt_init(apr_getopt_t ** const char *argv[], apr_pool_t *pool); +/* */ +svn_boolean_t +svn_cmdline__stdin_is_a_terminal(void); + +/* */ +svn_boolean_t +svn_cmdline__stdout_is_a_terminal(void); + +/* */ +svn_boolean_t +svn_cmdline__stderr_is_a_terminal(void); + /* Determine whether interactive mode should be enabled, based on whether * the user passed the --non-interactive or --force-interactive options. * If neither option was passed, interactivity is enabled if standard Propchange: subversion/trunk/subversion/libsvn_fs_x/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Mon Nov 16 17:46:37 2015 @@ -58,6 +58,7 @@ /subversion/branches/log-addressing/subversion/libsvn_fs_x:1511324 /subversion/branches/log-g-performance/subversion/libsvn_fs_x:870941-871032 /subversion/branches/merge-skips-obstructions/subversion/libsvn_fs_x:874525-874615 +/subversion/branches/move-tracking-2/subversion/libsvn_fs_x:1606692-1714632 /subversion/branches/multi-layer-moves/subversion/libsvn_fs_x:1239019-1300930 /subversion/branches/nfc-nfd-aware-client/subversion/libsvn_fs_x:870276,870376 /subversion/branches/node_pool/subversion/libsvn_fs_x:1304828-1305388 Modified: subversion/trunk/subversion/libsvn_subr/cmdline.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/cmdline.c?rev=1714640&r1=1714639&r2=1714640&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_subr/cmdline.c (original) +++ subversion/trunk/subversion/libsvn_subr/cmdline.c Mon Nov 16 17:46:37 2015 @@ -1171,6 +1171,36 @@ svn_cmdline__print_xml_prop_hash(svn_str } svn_boolean_t +svn_cmdline__stdin_is_a_terminal(void) +{ +#ifdef WIN32 + return (_isatty(STDIN_FILENO) != 0); +#else + return (isatty(STDIN_FILENO) != 0); +#endif +} + +svn_boolean_t +svn_cmdline__stdout_is_a_terminal(void) +{ +#ifdef WIN32 + return (_isatty(STDOUT_FILENO) != 0); +#else + return (isatty(STDOUT_FILENO) != 0); +#endif +} + +svn_boolean_t +svn_cmdline__stderr_is_a_terminal(void) +{ +#ifdef WIN32 + return (_isatty(STDERR_FILENO) != 0); +#else + return (isatty(STDERR_FILENO) != 0); +#endif +} + +svn_boolean_t svn_cmdline__be_interactive(svn_boolean_t non_interactive, svn_boolean_t force_interactive) { Modified: subversion/trunk/subversion/tests/cmdline/svntest/actions.py URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/actions.py?rev=1714640&r1=1714639&r2=1714640&view=diff ============================================================================== --- subversion/trunk/subversion/tests/cmdline/svntest/actions.py (original) +++ subversion/trunk/subversion/tests/cmdline/svntest/actions.py Mon Nov 16 17:46:37 2015 @@ -402,6 +402,27 @@ def run_and_verify_svnrdump(dumpfile_con return output +def run_and_verify_svnmover(expected_stdout, expected_stderr, + *varargs): + """Run svnmover command and check its output""" + + expected_exit = 0 + if expected_stderr is not None and expected_stderr != []: + expected_exit = 1 + return run_and_verify_svnmover2(expected_stdout, expected_stderr, + expected_exit, *varargs) + +def run_and_verify_svnmover2(expected_stdout, expected_stderr, + expected_exit, *varargs): + """Run svnmover command and check its output and exit code.""" + + exit_code, out, err = main.run_svnmover(*varargs) + verify.verify_outputs("Unexpected output", out, err, + expected_stdout, expected_stderr) + verify.verify_exit_code("Unexpected return code", exit_code, expected_exit) + return exit_code, out, err + + def run_and_verify_svnmucc(expected_stdout, expected_stderr, *varargs): """Run svnmucc command and check its output""" Modified: subversion/trunk/subversion/tests/cmdline/svntest/main.py URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/main.py?rev=1714640&r1=1714639&r2=1714640&view=diff ============================================================================== --- subversion/trunk/subversion/tests/cmdline/svntest/main.py (original) +++ subversion/trunk/subversion/tests/cmdline/svntest/main.py Mon Nov 16 17:46:37 2015 @@ -179,6 +179,7 @@ svnauthz_binary = os.path.abspath('../.. svnauthz_validate_binary = os.path.abspath( '../../../tools/server-side/svnauthz-validate' + _exe ) +svnmover_binary = os.path.abspath('../../../tools/dev/svnmover/svnmover' + _exe) # Location to the pristine repository, will be calculated from test_area_url # when we know what the user specified for --url. @@ -773,6 +774,12 @@ def run_svnversion(*varargs): as list of lines (including line terminators).""" return run_command(svnversion_binary, 1, False, *varargs) +def run_svnmover(*varargs): + """Run svnmover with VARARGS, returns exit code as int; stdout, stderr as + list of lines (including line terminators).""" + return run_command(svnmover_binary, 1, False, + *(_with_auth(_with_config_dir(varargs)))) + def run_svnmucc(*varargs): """Run svnmucc with VARARGS, returns exit code as int; stdout, stderr as list of lines (including line terminators). Use binary mode for output.""" @@ -2188,6 +2195,7 @@ def execute_tests(test_list, serial_only global svnsync_binary global svndumpfilter_binary global svnversion_binary + global svnmover_binary global svnmucc_binary global svnauthz_binary global svnauthz_validate_binary @@ -2286,6 +2294,7 @@ def execute_tests(test_list, serial_only svnauthz_binary = os.path.join(options.tools_bin, 'svnauthz' + _exe) svnauthz_validate_binary = os.path.join(options.tools_bin, 'svnauthz-validate' + _exe) + svnmover_binary = os.path.join(options.tools_bin, 'svnmover' + _exe) ###################################################################### Modified: subversion/trunk/subversion/tests/cmdline/svntest/wc.py URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/wc.py?rev=1714640&r1=1714639&r2=1714640&view=diff ============================================================================== --- subversion/trunk/subversion/tests/cmdline/svntest/wc.py (original) +++ subversion/trunk/subversion/tests/cmdline/svntest/wc.py Mon Nov 16 17:46:37 2015 @@ -116,6 +116,14 @@ _re_parse_co_restored = re.compile('^(Re _re_parse_commit_ext = re.compile('^(([A-Za-z]+( [a-z]+)*)) \'(.+)\'( --.*)?') _re_parse_commit = re.compile('^(\w+( \(bin\))?)\s+(.+)') +#rN: eids 0 15 branches 4 +_re_parse_eid_header = re.compile('^r(-1|[0-9]+): eids ([0-9]+) ([0-9]+) ' + 'branches ([0-9]+)$') +# B0.2 root-eid 3 +_re_parse_eid_branch = re.compile('^(B[0-9.]+) root-eid ([0-9]+) num-eids ([0-9]+)( from [^ ]*)?$') +# e4: normal 6 C +_re_parse_eid_ele = re.compile('^e([0-9]+): (none|normal|subbranch) ' + '(-1|[0-9]+) (.*)$') class State: """Describes an existing or expected state of a working copy. @@ -206,6 +214,30 @@ class State: if list(filter(path, item)): item.tweak(**kw) + def rename(self, moves): + """Change the path of some items. + + MOVES is a dictionary mapping source path to destination + path. Children move with moved parents. All subtrees are moved in + reverse depth order to temporary storage before being moved in + depth order to the final location. This allows nested moves. + + """ + temp = {} + for src, dst in sorted(moves.items(), key=lambda (src, dst): src)[::-1]: + temp[src] = {} + for path, item in self.desc.items(): + if path == src or path[:len(src) + 1] == src + '/': + temp[src][path] = item; + del self.desc[path] + for src, dst in sorted(moves.items(), key=lambda (src, dst): dst): + for path, item in temp[src].items(): + if path == src: + new_path = dst + else: + new_path = dst + path[len(src):] + self.desc[new_path] = item + def subtree(self, subtree_path): """Return a State object which is a deep copy of the sub-tree beneath SUBTREE_PATH (which is assumed to be rooted at the tree of @@ -750,6 +782,58 @@ class State: return cls('', desc) + @classmethod + def from_eids(cls, lines): + + # Need to read all elements in a branch before we can construct + # the full path to an element. + # For the full path we use <branch-id>/<path-within-branch>. + + def eid_path(eids, eid): + ele = eids[eid] + if ele[0] == '-1': + return ele[1] + parent_path = eid_path(eids, ele[0]) + if parent_path == '': + return ele[1] + return parent_path + '/' + ele[1] + + def eid_full_path(eids, eid, branch_id): + path = eid_path(eids, eid) + if path == '': + return branch_id + return branch_id + '/' + path + + def add_to_desc(eids, desc, branch_id): + for k, v in eids.items(): + desc[eid_full_path(eids, k, branch_id)] = StateItem(eid=k) + + branch_id = None + eids = {} + desc = {} + for line in lines: + + match = _re_parse_eid_ele.search(line) + if match and match.group(2) != 'none': + eid = match.group(1) + parent_eid = match.group(3) + path = match.group(4) + if path == '.': + path = '' + eids[eid] = [parent_eid, path] + + match = _re_parse_eid_branch.search(line) + if match: + if branch_id: + add_to_desc(eids, desc, branch_id) + eids = {} + branch_id = match.group(1) + root_eid = match.group(2) + + add_to_desc(eids, desc, branch_id) + + return cls('', desc) + class StateItem: """Describes an individual item within a working copy. @@ -764,7 +848,8 @@ class StateItem: entry_rev=None, entry_status=None, entry_copied=None, locked=None, copied=None, switched=None, writelocked=None, treeconflict=None, moved_from=None, moved_to=None, - prev_status=None, prev_verb=None, prev_treeconflict=None): + prev_status=None, prev_verb=None, prev_treeconflict=None, + eid=None): # provide an empty prop dict if it wasn't provided if props is None: props = { } @@ -772,6 +857,8 @@ class StateItem: ### keep/make these ints one day? if wc_rev is not None: wc_rev = str(wc_rev) + if eid is not None: + eid = str(eid) # Any attribute can be None if not relevant, unless otherwise stated. @@ -807,6 +894,7 @@ class StateItem: # Relative paths to the move locations self.moved_from = moved_from self.moved_to = moved_to + self.eid = eid def copy(self): "Make a deep copy of self." @@ -820,6 +908,8 @@ class StateItem: # Refine the revision args (for now) to ensure they are strings. if value is not None and name == 'wc_rev': value = str(value) + if value is not None and name == 'eid': + value = str(value) setattr(self, name, value) def __eq__(self, other): @@ -867,6 +957,8 @@ class StateItem: atts['moved_from'] = self.moved_from if self.moved_to is not None: atts['moved_to'] = self.moved_to + if self.eid is not None: + atts['eid'] = self.eid return (os.path.normpath(path), self.contents, self.props, atts)
