You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2022/01/14 14:01:51 UTC

svn commit: r1897034 [4/37] - in /subversion/branches/multi-wc-format: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ contrib/client-side/ contrib/client-side/svn_load_dirs/ contrib/hook-scripts/ contrib/se...

Modified: subversion/branches/multi-wc-format/configure.ac
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/configure.ac?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/configure.ac (original)
+++ subversion/branches/multi-wc-format/configure.ac Fri Jan 14 14:01:45 2022
@@ -23,7 +23,7 @@ AC_PREREQ(2.59)
 dnl Get the version of Subversion, using m4's esyscmd() command to do this
 dnl at m4-time, since AC_INIT() requires it then.
 AC_INIT([subversion],
-     [esyscmd(python build/getversion.py SVN subversion/include/svn_version.h)],
+     [esyscmd($PYTHON build/getversion.py SVN subversion/include/svn_version.h)],
      [http://subversion.apache.org/])
 
 AC_CONFIG_SRCDIR(subversion/include/svn_types.h)
@@ -56,6 +56,32 @@ SVN_CC_MODE_SETUP
 # Look for a C++ compiler (before anything can set CXXFLAGS)
 CXXUSERFLAGS="$CXXFLAGS"
 AC_PROG_CXX
+dnl Select C++ language level for GNU-like compilers
+dnl This is an advanced option for maintainers
+AC_ARG_ENABLE([c++],
+AS_HELP_STRING([--enable-c++=VER],
+               [Select C++ language standard for g++-like compilers]),
+[
+    if test "$enableval" = "yes"; then
+      cxx_language_level=any
+    elif test  "$enableval" = "no"; then
+      cxx_language_level=any
+      AC_MSG_WARN([--disable-c++ has no effect])
+    else
+      case "$enableval" in
+        [c++[0-9]*])   cxx_language_level="$enableval";;
+        [gnu++[0-9]*]) cxx_language_level="$enableval";;
+        [[0-9]*])      cxx_language_level="c++$enableval";;
+        [*])           cxx_language_level=undefined;;
+      esac
+      if test "$cxx_language_level" = undefined; then
+        AC_MSG_ERROR([--enable-c++ does not accept $enableval])
+      fi
+    fi
+],
+[
+    cxx_language_level=any
+])
 SVN_CXX_MODE_SETUP
 
 # Look for a C pre-processor
@@ -91,7 +117,7 @@ AC_SUBST([MKDIR])
 dnl verify apr version and set apr flags
 dnl These regular expressions should not contain "\(" and "\)".
 
-APR_VER_REGEXES=["1\.[3-9]\. 2\."]
+APR_VER_REGEXES=["1\.[4-9]\. 2\."]
 
 SVN_LIB_APR($APR_VER_REGEXES)
 
@@ -115,7 +141,7 @@ AC_SUBST(SVN_APR_MAJOR_VERSION)
 SVN_LT_SOVERSION="-version-info $svn_lib_ver"
 AC_SUBST(SVN_LT_SOVERSION)
 AC_DEFINE_UNQUOTED(SVN_SOVERSION, $svn_lib_ver,
-                   [Subversion library major verson])
+                   [Subversion library major version])
 
 dnl Search for pkg-config
 AC_PATH_PROG(PKG_CONFIG, pkg-config)
@@ -222,6 +248,8 @@ SVN_EXPAND_VAR(svn_localedir, "${exp_loc
 AC_DEFINE_UNQUOTED(SVN_LOCALE_DIR, "${svn_localedir}",
                    [Defined to be the path to the installed locale dirs])
 
+dnl Libtool has been broken for decades, incorrectly passing 'cru' to 'ar'
+AR_FLAGS=${AR_FLAGS:-cr}
 dnl Check for libtool -- we'll definitely need it for all our shared libs!
 AC_MSG_NOTICE([configuring libtool now])
 ifdef([LT_INIT], [LT_INIT], [AC_PROG_LIBTOOL])
@@ -593,7 +621,7 @@ if test "$with_old_gnome_keyring" != "no
                         [Is GNOME Keyring support enabled?])
               CPPFLAGS="$old_CPPFLAGS"
               SVN_GNOME_KEYRING_LIBS="`$PKG_CONFIG --libs glib-2.0 gnome-keyring-1`"
-              SVN_GNOME_KEYRING_PCLIBS="glib-2.0 gnome-keyring-1"
+              SVN_GNOME_KEYRING_PCLIBS="glib-2.0, gnome-keyring-1"
             else
               AC_MSG_RESULT([no])
               if test "$with_old_gnome_keyring" = "yes"; then
@@ -640,29 +668,6 @@ AC_SUBST(SVN_GNOME_KEYRING_LIBS)
 dnl LibSecret -------------------
 SVN_LIB_SECRET
 
-dnl Googlemock -----------------
-AC_ARG_ENABLE([googlemock],
-  AS_HELP_STRING([--disable-googlemock],
-                 [Do not use the Googlemock testing framework]),
-  [],
-  [enable_googlemock=yes])
-
-AC_SUBST([GOOGLEMOCK_SRCDIR], [$abs_srcdir/googlemock])
-AC_MSG_CHECKING([whether use Googlemock])
-if test "$enable_googlemock" != "no"; then
-  if test -d "$GOOGLEMOCK_SRCDIR"; then
-    AC_MSG_RESULT([yes])
-    SVN_USE_GOOGLEMOCK=true
-  else
-    AC_MSG_RESULT([no])
-    SVN_USE_GOOGLEMOCK=false
-  fi
-else
-  AC_MSG_RESULT([no])
-  SVN_USE_GOOGLEMOCK=false
-fi
-AC_SUBST([SVN_USE_GOOGLEMOCK])
-
 dnl Ev2 experimental features ----------------------
 dnl Note: The Ev2 implementations will be built unconditionally, but by
 dnl providing this flag, users can choose to use the currently-shimmed Ev2
@@ -782,7 +787,7 @@ AH_BOTTOM([
 #endif
 
 /* Macro used to specify that a variable is intentionally left unused.
-   Supresses compiler warnings about the variable being unused.  */
+   Suppresses compiler warnings about the variable being unused.  */
 #define SVN_UNUSED(v) ( (void)(v) )
 ])
 
@@ -1157,7 +1162,6 @@ if test "$enable_optimization" = "yes";
           SVN_CFLAGS_ADD_IFELSE([-O1],[],[
             SVN_CFLAGS_ADD_IFELSE([-O])])])])
       SVN_CFLAGS_ADD_IFELSE([-Wno-clobbered])
-      SVN_CFLAGS_ADD_IFELSE([-flto])
     fi
   fi
   if test -z ["`echo $CXXUSERFLAGS' ' | $EGREP -- '-O[^ ]* '`"]; then
@@ -1173,7 +1177,6 @@ if test "$enable_optimization" = "yes";
           SVN_CXXFLAGS_ADD_IFELSE([-O1],[],[
             SVN_CXXFLAGS_ADD_IFELSE([-O])])])])
       SVN_CXXFLAGS_ADD_IFELSE([-Wno-clobbered])
-      SVN_CXXFLAGS_ADD_IFELSE([-flto])
     fi
   fi
 elif test "$enable_optimization" = "no"; then
@@ -1187,9 +1190,11 @@ fi
 
 dnl Dump the current compiler options
 AC_MSG_NOTICE([C compiler flags: $CFLAGS])
+AC_MSG_NOTICE([  language-level: $CMODEFLAGS])
 AC_MSG_NOTICE([    user-defined: $CUSERFLAGS])
 AC_MSG_NOTICE([ maintainer-mode: $CMAINTAINERFLAGS])
 AC_MSG_NOTICE([C++ compiler flags: $CXXFLAGS])
+AC_MSG_NOTICE([    language-level: $CXXMODEFLAGS])
 AC_MSG_NOTICE([      user-defined: $CXXUSERFLAGS])
 AC_MSG_NOTICE([   maintainer-mode: $CXXMAINTAINERFLAGS])
 
@@ -1295,35 +1300,142 @@ AS_HELP_STRING([--enable-gprof],
 
 # Scripting and Bindings languages
 
-# Python: Used for testsuite, and bindings
-
+# Python: Used for testsuite
+AC_ARG_VAR([PYTHON], [Python interpreter command])
 
 PYTHON="`$abs_srcdir/build/find_python.sh`"
 if test -z "$PYTHON"; then
-  AC_MSG_WARN([Python 2.7 or later is required to run the testsuite])
-  AC_MSG_WARN([or to use the Subversion Python bindings])
+  AC_MSG_WARN([Python 2.7 or later is required to run the testsuite.])
   AC_MSG_WARN([])
   AC_MSG_WARN([If you have a suitable Python installed, but not on the])
   AC_MSG_WARN([PATH, set the environment variable PYTHON to the full path])
   AC_MSG_WARN([to the Python executable, and re-run configure])
+  PYTHON=none
 fi
-AC_PATH_PROGS(PYTHON, "$PYTHON", none)
+AC_SUBST(PYTHON)
 
 # The minimum version for the JVM runtime for our Java bytecode.
 JAVA_OLDEST_WORKING_VER='1.8'
 # SVN_CHECK_JDK sets $JAVA_CLASSPATH
 SVN_CHECK_JDK($JAVA_OLDEST_WORKING_VER)
 
-AC_PATH_PROG(PERL, perl, none)
+AC_ARG_WITH(swig_perl,
+[AS_HELP_STRING([[--with-swig-perl[=PATH|auto|no]|--without-swig-perl]],
+                [Specify path to SWIG bindings target Perl interpreter
+                 [default=auto]. If the option value is 'auto' or it is not
+                  specfied, search for the Perl program.]
+                m4_ifndef([SVN_RELEASE_MODE],
+                  [[Implies --with-swig=yes if PATH is specfied or Perl 
+                    is found on 'auto' detection.]]))
+],
+[],
+[
+if test -n "$PERL"; then
+  if test "$PERL" = "no" -o "$PERL" = "none"; then
+    with_swig_perl=no
+    AC_MSG_WARN([Disabling the SWIG Perl bindings' build by setting the PERL])
+    AC_MSG_WARN([environment variable to "none" is deprecated.])
+    AC_MSG_WARN([])
+    AC_MSG_WARN([Please use --without-swig-perl instead.])
+  else
+    with_swig_perl=auto
+    AC_MSG_WARN([Specfying the Perl path for SWIG Perl bindings' build])
+    AC_MSG_WARN([by setting the PERL environment variable is deprecated.])
+    AC_MSG_WARN([])
+    AC_MSG_WARN([Please use --with-swig-perl=PATH instead.])
+  fi
+else
+  with_swig_perl=auto
+fi
+])
+case $with_swig_perl in
+  yes|auto|"")
+    # honor PERL variable only if it is set and is full path. 
+    AC_PATH_PROG(PERL, perl, none)
+    SWIG_PL_PERL="$PERL"
+    ;;
+  no|none)
+    SWIG_PL_PERL=none
+    ;;
+  *)
+    SWIG_PL_PERL="$with_swig_perl"
+    ;;
+esac
+AC_SUBST(SWIG_PL_PERL)
+
+# Python: as a target of SWIG Python bindings
+AC_ARG_WITH(swig_python,
+[AS_HELP_STRING([[--with-swig-python[=PATH|auto|no]|--without-swig-python]],
+                [Specify path to SWIG bindings target Python interpreter
+                 [default=auto]. If the option value is 'auto' or it is not
+                 specfied, search for the Python program.]
+                m4_ifndef([SVN_RELEASE_MODE],
+                  [[Implies --with-swig=yes if PATH is specfied or Python
+                    is found on 'auto' detection.]]))
+],
+[],
+[
+  with_swig_python=auto
+])
+case $with_swig_python in
+  yes|auto|"")
+    SWIG_PY_PYTHON="$PYTHON"
+    ;;
+  no|none)
+    SWIG_PY_PYTHON=none
+    ;;
+  *)
+    SWIG_PY_PYTHON="$with_swig_python"
+    ;;
+esac
+AC_SUBST(SWIG_PY_PYTHON)
 
+AC_ARG_WITH(swig_ruby,
+[AS_HELP_STRING([[--with-swig-ruby[=PATH|auto|no]|--without-swig-ruby]],
+                [specify path to SWIG bindings target Ruby interpreter
+                 [default=auto]. If the option value is 'auto' or it is not
+                  specfied, search for the Ruby program.] 
+                m4_ifndef([SVN_RELEASE_MODE],
+                  [[Implies --with-swig=yes if PATH is specfied or Ruby
+                    is found on 'auto' detection.]]))
+],
+[],
+[
 if test -n "$RUBY"; then
-  AC_PATH_PROG(RUBY, "$RUBY", none)
+  if test "$RUBY" = "no" -o "$RUBY" = "none"; then
+    with_swig_ruby=no
+    AC_MSG_WARN([Disabling the SWIG Ruby bindings' build by setting the RUBY])
+    AC_MSG_WARN([environment variable to "none" is deprecated.])
+    AC_MSG_WARN([])
+    AC_MSG_WARN([Please use --without-swig-ruby instead.])
+  else
+    with_swig_ruby="$RUBY"
+    AC_MSG_WARN([Specfying the Ruby path for SWIG Ruby bindings' build])
+    AC_MSG_WARN([by setting the RUBY environment variable is deprecated.])
+    AC_MSG_WARN([])
+    AC_MSG_WARN([Please use --with-swig-ruby=PATH instead.])
+  fi
 else
-  AC_PATH_PROGS(RUBY, ruby ruby1 ruby1.8 ruby18 ruby1.9 ruby19 ruby1.9.3 ruby193 ruby2 ruby2.0 ruby20 ruby2.1 ruby21 ruby2.2 ruby22 ruby2.3 ruby23 ruby2.4 ruby24, none)
+  with_swig_ruby=auto
 fi
-if test "$RUBY" != "none"; then
+])
+case $with_swig_ruby in
+  yes|auto|"")
+    # honor RUBY variable only if it is set and is full path. 
+    AC_PATH_PROGS(RUBY, ruby ruby1 ruby1.8 ruby18 ruby1.9 ruby19 ruby1.9.3 ruby193 ruby2 ruby2.0 ruby20 ruby2.1 ruby21 ruby2.2 ruby22 ruby2.3 ruby23 ruby2.4 ruby24, none)
+    SWIG_RB_RUBY="$RUBY"
+    ;;
+  no|none)
+    SWIG_RB_RUBY=none
+    ;;
+  *)
+    SWIG_RB_RUBY="$with_swig_ruby"
+    ;;
+esac
+AC_SUBST(SWIG_RB_RUBY)
+if test "$SWIG_RB_RUBY" != "none"; then
   AC_MSG_CHECKING([rb_hash_foreach])
-  if "$RUBY" -r mkmf -e 'exit(have_func("rb_hash_foreach") ? 0 : 1)' >/dev/null; then
+  if "$SWIG_RB_RUBY" -r mkmf -e 'exit(have_func("rb_hash_foreach") ? 0 : 1)' >/dev/null; then
     AC_MSG_RESULT([yes])
     if test -n "$RDOC"; then
       AC_PATH_PROG(RDOC, "$RDOC", none)
@@ -1331,17 +1443,17 @@ if test "$RUBY" != "none"; then
       AC_PATH_PROGS(RDOC, rdoc rdoc1 rdoc1.8 rdoc18 rdoc1.9 rdoc19 rdoc1.9.3 rdoc193 rdoc2 rdoc2.0 rdoc20 rdoc2.1 rdoc21 rdoc2.2 rdoc22 rdoc2.3 rdoc23 rdoc2.4 rdoc24, none)
     fi
     AC_CACHE_CHECK([for Ruby major version], [svn_cv_ruby_major],[
-    svn_cv_ruby_major="`$RUBY -rrbconfig -e 'print RbConfig::CONFIG.fetch(%q(MAJOR))'`"
+    svn_cv_ruby_major="`$SWIG_RB_RUBY -rrbconfig -e 'print RbConfig::CONFIG.fetch(%q(MAJOR))'`"
     ])
     RUBY_MAJOR="$svn_cv_ruby_major"
 
     AC_CACHE_CHECK([for Ruby minor version], [svn_cv_ruby_minor],[
-    svn_cv_ruby_minor="`$RUBY -rrbconfig -e 'print RbConfig::CONFIG.fetch(%q(MINOR))'`"
+    svn_cv_ruby_minor="`$SWIG_RB_RUBY -rrbconfig -e 'print RbConfig::CONFIG.fetch(%q(MINOR))'`"
     ])
     RUBY_MINOR="$svn_cv_ruby_minor"
 
     AC_CACHE_CHECK([for Ruby teeny version], [svn_cv_ruby_teeny],[
-    svn_cv_ruby_teeny="`$RUBY -rrbconfig -e 'major, minor, teeny = RUBY_VERSION.split("."); print teeny;'`"
+    svn_cv_ruby_teeny="`$SWIG_RB_RUBY -rrbconfig -e 'major, minor, teeny = RUBY_VERSION.split("."); print teeny;'`"
     ])
     RUBY_TEENY="$svn_cv_ruby_teeny"
     
@@ -1350,13 +1462,13 @@ if test "$RUBY" != "none"; then
     AC_SUBST(RUBY_TEENY)
     if test \( "$RUBY_MAJOR" -eq "1" -a "$RUBY_MINOR" -gt "8" -a "$RUBY_TEENY" -lt "3" \); then
       # Disallow Ruby between 1.8.7 and 1.9.3
-      RUBY="none"
+      SWIG_RB_RUBY="none"
       AC_MSG_WARN([The detected Ruby is between 1.9 and 1.9.3])
       AC_MSG_WARN([Only 1.8.x and 1.9.3 or later are supported at this time])
     fi
   else
     AC_MSG_RESULT([no])
-    RUBY="none"
+    SWIG_RB_RUBY="none"
     AC_MSG_WARN([The detected Ruby is too old for Subversion to use])
     AC_MSG_WARN([A Ruby which has rb_hash_foreach is required to use the])
     AC_MSG_WARN([Subversion Ruby bindings])
@@ -1458,6 +1570,69 @@ AC_SUBST(SVN_FS_LIB_DEPS)
 AC_SUBST(SVN_FS_LIB_INSTALL_DEPS)
 AC_SUBST(SVN_FS_LIB_LINK)
 
+# ==== SVN++ =================================================================
+
+dnl Possibly compile SVN++
+do_svnxx_build=no
+AC_ARG_ENABLE(svnxx,
+  AS_HELP_STRING([--enable-svnxx],
+      [Enable compilation of the C++ bindings (requires C++)]),
+  [ if test "$enableval" = "yes" ; then
+        AC_MSG_NOTICE([Enabling the C++ bindings])
+        do_svnxx_build=yes
+    fi
+  ])
+
+dnl Possibly compile SVN++ tests
+do_svnxx_test_build=no
+AC_ARG_ENABLE(svnxx-tests,
+  AS_HELP_STRING([--enable-svnxx-tests],
+      [Enable compilation of tests for the C++ bindings
+      (implies --enable-svnxx, requires Boost and Boost.Test)]),
+  [ if test "$enableval" = "yes" ; then
+        AC_MSG_NOTICE([Enabling tests for the C++ bindings])
+        do_svnxx_test_build=yes
+    fi
+  ])
+
+AX_BOOST_BASE([1.58],
+  [
+    if test "$do_svnxx_test_build" = "yes"; then
+        AX_BOOST_UNIT_TEST_FRAMEWORK
+    fi
+  ],
+  [
+    if test "$do_svnxx_test_build" = "yes"; then
+        AC_MSG_WARN([Tests for the C++ bindings require Boost and Boost.Test])
+        do_svnxx_test_build=no
+    fi
+  ])
+
+if test "$do_svnxx_test_build" = "yes"; then
+    if test "$want_boost" != "yes"; then
+        AC_MSG_WARN([Tests for the C++ bindings require Boost and Boost.Test])
+        do_svnxx_test_build=no
+        SVN_BUILD_SVNXX_TESTS=false
+    else
+        if test "$do_svnxx_build" != "yes"; then
+            AC_MSG_WARN([Enabling the C++ bindings because their tests are enabled])
+            do_svnxx_build=yes
+        fi
+        SVN_BUILD_SVNXX_TESTS=true
+    fi
+else
+    SVN_BUILD_SVNXX_TESTS=false
+fi
+
+if test "$do_svnxx_build" = "yes"; then
+    SVN_BUILD_SVNXX=true
+else
+    SVN_BUILD_SVNXX=false
+fi
+
+AC_SUBST(SVN_BUILD_SVNXX)
+AC_SUBST(SVN_BUILD_SVNXX_TESTS)
+
 # ==== JavaHL ================================================================
 
 dnl Possibly compile JavaHL
@@ -1594,6 +1769,7 @@ done
 
 SVN_CONFIG_SCRIPT(tools/backup/hot-backup.py)
 SVN_CONFIG_SCRIPT(tools/hook-scripts/commit-access-control.pl)
+SVN_CONFIG_SCRIPT(subversion/tests/cmdline/svneditor.sh)
 SVN_CONFIG_SCRIPT(subversion/bindings/swig/perl/native/Makefile.PL)
 if test -e packages/solaris/pkginfo.in; then
   SVN_CONFIG_SCRIPT(packages/solaris/pkginfo)
@@ -1601,7 +1777,7 @@ fi
 AC_SUBST(SVN_CONFIG_SCRIPT_FILES)
 
 # Ensure that SWIG is checked after reconfiguration.
-rm -f .swig_checked
+rm -f .swig_checked .swig_pl_checked .swig_py_checked .swig_rb_checked
 
 dnl Provide ${host} for use in compiled code (for svn --version)
 AC_DEFINE_UNQUOTED([SVN_BUILD_HOST], "${host}",

Modified: subversion/branches/multi-wc-format/contrib/client-side/svn-clean
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/contrib/client-side/svn-clean?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/contrib/client-side/svn-clean (original)
+++ subversion/branches/multi-wc-format/contrib/client-side/svn-clean Fri Jan 14 14:01:45 2022
@@ -180,7 +180,7 @@ faster than parsing the output of the B<
 
 =item B<-e>, B<--exclude>
 
-A regular expression for filenames to be exluded. For example, the following
+A regular expression for filenames to be excluded. For example, the following
 command will skip files ending in ".zip":
 
 =over 8

Modified: subversion/branches/multi-wc-format/contrib/client-side/svn_load_dirs/svn_load_dirs.pl.in
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/contrib/client-side/svn_load_dirs/svn_load_dirs.pl.in?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/contrib/client-side/svn_load_dirs/svn_load_dirs.pl.in (original)
+++ subversion/branches/multi-wc-format/contrib/client-side/svn_load_dirs/svn_load_dirs.pl.in Fri Jan 14 14:01:45 2022
@@ -196,7 +196,7 @@ elsif ( -f "$ENV{HOME}/.subversion/confi
       {
         if ( /^global-ignores\s*=\s*(.*?)\s*$/ )
           {
-	    $ignores_str = $1;
+            $ignores_str = $1;
             last;
           }
       }
@@ -1344,6 +1344,8 @@ sub usage
       "  -p filename    table listing properties to apply to matching files\n",
       "  -svn_username  username to perform commits as\n",
       "  -svn_password  password to supply to svn commit\n",
+      "                 WARNING: passing the password in a command-line argument\n",
+      "                 may make it visible to other local OS users\n",
       "  -t tag_dir     create a tag copy in tag_dir, relative to svn_url\n",
       "  -v             increase program verbosity, multiple -v's allowed\n",
       "  -wc path       use the already checked-out working copy at path\n",
@@ -1500,6 +1502,18 @@ sub file_info
   return '?';
 }
 
+# Copy arguments and replace what follows --password with '*'s.
+sub sanitize_pwd
+{
+  my @str = @_;
+  my $hide_next = 0;
+  foreach(@str) {
+    $_ = '*' x length if ( $hide_next );
+    $hide_next = ($_ eq '--password');
+  }
+  @str;
+}
+
 # Start a child process safely without using /bin/sh.
 sub safe_read_from_pipe
 {
@@ -1511,7 +1525,7 @@ sub safe_read_from_pipe
   my $openfork_available = "MSWin32" ne $OSNAME;
   if ($openfork_available)
     {
-      print "Running @_\n";
+      print join(' ', &sanitize_pwd("Running", @_, "\n") );
       my $pid = open(SAFE_READ, "-|");
       unless (defined $pid)
         {
@@ -1523,7 +1537,9 @@ sub safe_read_from_pipe
           open(STDERR, ">&STDOUT")
             or die "$0: cannot dup STDOUT: $!\n";
           exec(@_)
-            or die "$0: cannot exec '@_': $!\n";
+            or die "$0: cannot exec '"
+              . join(' ', &sanitize_pwd(@_) )
+              . "': $!\n";
         }
     }
   else
@@ -1560,7 +1576,7 @@ sub safe_read_from_pipe
             }
         }
 
-      print "Running @commandline\n";
+      print join(' ', &sanitize_pwd("Running", @commandline, "\n") );
       if ( $comment ) { print $comment; }
 
       # Now do the pipe.
@@ -1582,7 +1598,9 @@ sub safe_read_from_pipe
   my $cd     = $result & 128 ? "with core dump" : "";
   if ($signal or $cd)
     {
-      warn "$0: pipe from '@_' failed $cd: exit=$exit signal=$signal\n";
+      warn "$0: pipe from '"
+        . join(' ', &sanitize_pwd(@_) )
+        . "' failed $cd: exit=$exit signal=$signal\n";
     }
   if (wantarray)
     {
@@ -1605,8 +1623,9 @@ sub read_from_process
   my ($status, @output) = &safe_read_from_pipe(@_);
   if ($status)
     {
-      print STDERR "$0: @_ failed with this output:\n", join("\n", @output),
-                   "\n";
+      print STDERR
+        join(' ', &sanitize_pwd("$0:", @_, "failed with this output:\n") ),
+        join("\n", @output), "\n";
       unless ($opt_no_user_input)
         {
           print STDERR
@@ -1658,7 +1677,7 @@ sub recursive_ls_and_hash
     };
   find({no_chdir   => 1,
         preprocess => sub
-	  {
+          {
             grep
               {
                 my $ok=1;
@@ -2054,5 +2073,6 @@ sub new
 sub DESTROY
 {
   print "Cleaning up $temp_dir\n";
+  chdir( $temp_dir . "/.." );
   File::Path::rmtree([$temp_dir], 0, 0);
 }

Modified: subversion/branches/multi-wc-format/contrib/hook-scripts/case-insensitive.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/contrib/hook-scripts/case-insensitive.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/contrib/hook-scripts/case-insensitive.py (original)
+++ subversion/branches/multi-wc-format/contrib/hook-scripts/case-insensitive.py Fri Jan 14 14:01:45 2022
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 # Licensed under the same terms as Subversion.
 
@@ -65,14 +65,14 @@ from svn import repos, fs
 locale.setlocale(locale.LC_ALL, 'en_GB')
 
 def canonicalize(path):
-  return path.decode('utf-8').lower().encode('utf-8')
+  return path.lower()
 
 def get_new_paths(txn_root):
   new_paths = []
-  for path, change in fs.paths_changed(txn_root).iteritems():
+  for path, change in fs.paths_changed(txn_root).items():
     if (change.change_kind == fs.path_change_add
         or change.change_kind == fs.path_change_replace):
-      new_paths.append(path)
+      new_paths.append(path.decode('utf-8'))
   return new_paths
 
 def split_path(path):
@@ -87,9 +87,10 @@ def join_path(dir, name):
   return dir + '/' + name
 
 def ensure_names(path, names, txn_root):
-  if (not names.has_key(path)):
+  if (path not in names):
      names[path] = []
-     for name, dirent in fs.dir_entries(txn_root, path).iteritems():
+     for name, dirent in fs.dir_entries(txn_root, path).items():
+       name = name.decode('utf-8')
        names[path].append([canonicalize(name), name])
 
 names = {}   # map of: key - path, value - list of two element lists of names
@@ -97,9 +98,9 @@ clashes = {} # map of: key - path, value
 
 native = locale.getlocale()[1]
 if not native: native = 'ascii'
-repos_handle = repos.open(sys.argv[1].decode(native).encode('utf-8'))
+repos_handle = repos.open(sys.argv[1].encode('utf-8'))
 fs_handle = repos.fs(repos_handle)
-txn_handle = fs.open_txn(fs_handle, sys.argv[2].decode(native).encode('utf-8'))
+txn_handle = fs.open_txn(fs_handle, sys.argv[2].encode('utf-8'))
 txn_root = fs.txn_root(txn_handle)
 
 new_paths = get_new_paths(txn_root)
@@ -110,18 +111,16 @@ for path in new_paths:
   for name_pair in names[dir]:
     if (name_pair[0] == canonical and name_pair[1] != name):
       canonical_path = join_path(dir, canonical)
-      if (not clashes.has_key(canonical_path)):
+      if (canonical_path not in clashes):
         clashes[canonical_path] = {}
       clashes[canonical_path][join_path(dir, name)] = True
       clashes[canonical_path][join_path(dir, name_pair[1])] = True
 
 if (clashes):
   # native = 'ascii' # Force ASCII output for Apache
-  for canonical_path in clashes.iterkeys():
-    sys.stderr.write(u'Clash:'.encode(native))
-    for path in clashes[canonical_path].iterkeys():
-      sys.stderr.write(u' \''.encode(native) +
-                       str(path).decode('utf-8').encode(native, 'replace') +
-                       u'\''.encode(native))
-    sys.stderr.write(u'\n'.encode(native))
+  for canonical_path in clashes.keys():
+    sys.stderr.write('Clash:')
+    for path in clashes[canonical_path].keys():
+      sys.stderr.write(' \'' + path + '\'')
+    sys.stderr.write('\n')
   sys.exit(1)

Modified: subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/README
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/README?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/README (original)
+++ subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/README Fri Jan 14 14:01:45 2022
@@ -25,6 +25,3 @@ Backup your repository before running th
 For more details, see the email from Julian Foad on 2010-10-06, subject
 "Fixing FSFS 'Corrupt node-revision' and 'Corrupt representation' errors",
 <http://svn.haxx.se/dev/archive-2010-10/0095.shtml>.
-
-This script does not support fixing revisions that had been packed.  Consider
-using ../../../tools/server-side/fsfs-reshard.py first.

Modified: subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/find_good_id.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/find_good_id.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/find_good_id.py (original)
+++ subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/find_good_id.py Fri Jan 14 14:01:45 2022
@@ -1,9 +1,12 @@
 #!/usr/bin/env python
 
 usage = """
-Print the correct FSFS node-rev id, given one that is correct except for
-its byte-offset part.
-Usage: $0 REPO-DIR FSFS-ID-WITH-BAD-OFFSET
+Usage:
+  $0 REPO-DIR FSFS-ID-WITH-BAD-OFFSET
+    -- Find the correct FSFS node-rev id, given one that is correct except for
+       its byte-offset part.
+  $0 REPO-DIR REV SIZE
+    -- Find a rep header that matches REV and SIZE.
 Example:
   Result of running 'svnadmin verify':
     svnadmin: Corrupt node-revision '5-12302.1-12953.r12953/29475'
@@ -29,42 +32,107 @@ def parse_id(id):
   noderev = node_id + '.' + copy_id + '.r' + rev
   return noderev, rev, offset
 
-def rev_file_path(repo_dir, rev):
-  """Return the path to the revision file in the repository at REPO_DIR
-     (a path string) for revision number REV (int or string).
+class Repository:
+  """Encapsulates key information of a repository:
+     its NAME, PATH, SHARD_SIZE, HEAD revision and MIN_UNPACKED_REV.
      """
-  if REVS_PER_SHARD:
-    shard = int(rev) / REVS_PER_SHARD
-    path = os.path.join(repo_dir, 'db', 'revs', str(shard), str(rev))
-  else:
-    path = os.path.join(repo_dir, 'db', 'revs', str(rev))
-  return path
-
-def rev_file_indexes(repo_dir, rev):
-  """Return (ids, texts), where IDS is a dictionary of all node-rev ids
-     defined in revision REV of the repo at REPO_DIR, in the form
-     {noderev: full_id}, and TEXTS is an array of
-     (offset, size, expanded-size, csum [,sha1-csum, uniquifier]) tuples
-     taken from all the "text: REV ..." representation lines
-     in revision REV.
 
-     Here, NODEREV is the node-revision id minus the /offset part, and
-     FULL_ID is the full node-revision id (including the /offset part).
-     """
-  ids = {}
-  texts = []
-  for line in open(rev_file_path(repo_dir, rev)):
-    if line.startswith('id: '):
-      id = line.replace('id: ', '').rstrip()
-      id_noderev, id_rev, _ = parse_id(id)
-      assert id_rev == rev
-      ids[id_noderev] = id
-    if line.startswith('text: ' + rev + ' '):  # also 'props:' lines?
-      fields = line.split()
-      texts.append(tuple(fields[2:]))
-  return ids, texts
+  def _read_repo_file(self, filename):
+    """Read and return all lines from FILENAME in REPO.
+    """
+
+    f = open(os.path.join(self.path, filename), "rb")
+    lines = f.readlines()
+    f.close()
+    return lines
+
+  def _read_config(self, filename):
+    """ Read and return all lines from FILENAME.
+        This will be used to read 'format', 'current' etc. . """
+
+    if filename not in self.db_config:
+      f = open(os.path.join(self.path, 'db', filename), "rb")
+      self.db_config[filename] = f.readlines()
+      f.close()
+
+    return self.db_config[filename]
+
+  def __init__(self, path_or_parent, name=None):
+    """Constructor collecting everything we need to know about
+       the repository at path PATH_OR_PARENT or NAME within PARENT folder.
+    """
+
+    if name is None:
+      self.name = os.path.basename(path_or_parent)
+      self.path = path_or_parent
+    else:
+      self.name = name
+      self.path = os.path.join(path_or_parent, name)
+
+    self.db_config = {}
+    self.repo_format = int(self._read_repo_file('format')[0])
+    self.fs_type = self._read_config('fs-type')[0].rstrip()
+    self.db_format = int(self._read_config('format')[0])
+    try:
+      self.shard_size = int(self._read_config('format')[1].split(' ')[2])
+    except IndexError:
+      self.shard_size = 0
+    if self.db_format >= 4:
+      self.min_unpacked_rev = int(self._read_config('min-unpacked-rev')[0])
+    else:
+      self.min_unpacked_rev = 0
+    self.head = int(self._read_config('current')[0])
+
+  def rev_file_path(self, rev):
+    """Return the path to the revision file in the repository at REPO_DIR
+       (a path string) for revision number REV (int or string).
+       """
+    if isinstance(rev, str):
+      rev = int(rev)
+    if self.shard_size > 0:
+      shard = int(rev) / self.shard_size
+      if rev < self.min_unpacked_rev:
+          path = os.path.join(self.path, 'db', 'revs', str(shard) + '.pack', 'pack')
+      else:
+          path = os.path.join(self.path, 'db', 'revs', str(shard), str(rev))
+    else:
+      path = os.path.join(self.path, 'db', 'revs', str(rev))
+    return path
+
+  def rev_file_indexes(self, rev):
+    """Return (ids, texts), where IDS is a dictionary of all node-rev ids
+       defined in revision REV of the repo at REPO_DIR, in the form
+       {noderev: full_id}, and TEXTS is an array of
+       (offset, size, expanded-size, csum [,sha1-csum, uniquifier]) tuples
+       taken from all the "text: REV ..." representation lines
+       in revision REV.
+
+       Here, NODEREV is the node-revision id minus the /offset part, and
+       FULL_ID is the full node-revision id (including the /offset part).
+       """
+    if isinstance(rev, str):
+      rev = int(rev)
+    ids = {}
+    texts = []
+    for line in open(self.rev_file_path(rev)):
+      if line.startswith('id: '):
+        id = line.replace('id: ', '').rstrip()
+        id_noderev, id_rev, _ = parse_id(id)
+        id_rev = int(id_rev)
+        # all ids in an unpacked rev file should match its rev number
+        if rev >= self.min_unpacked_rev:
+          assert id_rev == rev
+        # in a pre-f7 pack, revs are ordered so after REV we can stop looking
+        if id_rev > rev:
+          break
+        if id_rev == rev:
+          ids[id_noderev] = id
+      elif line.startswith('text: ' + str(rev) + ' '):  # also 'props:' lines?
+        fields = line.split()
+        texts.append(tuple(fields[2:]))
+    return ids, texts
 
-def find_good_id(repo_dir, bad_id):
+def find_good_id(repo, bad_id):
   """Return the node-rev id that is like BAD_ID but has the byte-offset
      part corrected, by looking in the revision file in the repository
      at REPO_DIR.
@@ -74,17 +142,21 @@ def find_good_id(repo_dir, bad_id):
          possibility of a false match.
   """
 
+  if isinstance(repo, str):
+    repo = Repository(repo)
   noderev, rev, bad_offset = parse_id(bad_id)
-  ids, _ = rev_file_indexes(repo_dir, rev)
+  ids, _ = repo.rev_file_indexes(rev)
 
   if noderev not in ids:
     raise FixError("NodeRev Id '" + noderev + "' not found in r" + rev)
   return ids[noderev]
 
-def find_good_rep_header(repo_dir, rev, size):
+def find_good_rep_header(repo, rev, size):
   """Find a rep header that matches REV and SIZE.
      Return the correct offset."""
-  _, texts = rev_file_indexes(repo_dir, rev)
+  if isinstance(repo, str):
+    repo = Repository(repo)
+  _, texts = repo.rev_file_indexes(rev)
   n_matches = 0
   for fields in texts:
     if fields[1] == size:
@@ -101,7 +173,8 @@ if __name__ == '__main__':
     repo_dir = sys.argv[1]
     rev = sys.argv[2]
     size = sys.argv[3]
-    print("Good offset:", find_good_rep_header(repo_dir, rev, size))
+    repo = Repository(repo_dir)
+    print("Good rep header offset:", find_good_rep_header(repo, rev, size))
     sys.exit(0)
 
   if len(sys.argv) != 3:
@@ -111,7 +184,8 @@ if __name__ == '__main__':
   repo_dir = sys.argv[1]
   bad_id = sys.argv[2]
 
-  good_id = find_good_id(repo_dir, bad_id)
+  repo = Repository(repo_dir)
+  good_id = find_good_id(repo, bad_id)
 
   # Replacement ID must be the same length, otherwise I don't know how to
   # reconstruct the file so as to preserve all offsets.

Modified: subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/fix-rev.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/fix-rev.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/fix-rev.py (original)
+++ subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/fix-rev.py Fri Jan 14 14:01:45 2022
@@ -12,7 +12,7 @@ $LastChangedRevision$
 import os, sys, re, subprocess
 from subprocess import Popen, PIPE
 
-from find_good_id import FixError, rev_file_path, find_good_id, find_good_rep_header
+from find_good_id import FixError, Repository, find_good_id, find_good_rep_header
 from fixer_config import *
 
 
@@ -70,11 +70,11 @@ def replace_in_file(filename, old, new):
                 "    with '" + new + "'")
   os.remove(filename + '.bak')
 
-def replace_in_rev_file(repo_dir, rev, old, new):
+def replace_in_rev_file(repo, rev, old, new):
   """Replace all occurrences of the string OLD with the string NEW in the
      revision file for revision REV in the repository at REPO_DIR.  Raise an
      error if nothing changes."""
-  rev_file = rev_file_path(repo_dir, rev)
+  rev_file = repo.rev_file_path(rev)
   replace_in_file(rev_file, old, new)
 
 # Fix a node-rev ID that has a bad byte-offset part.  Look up the correct
@@ -85,10 +85,10 @@ def replace_in_rev_file(repo_dir, rev, o
 #   since the error reported for <REV> might actually exist in an older
 #   revision that is referenced by <REV>.
 #
-def fix_id(repo_dir, rev, bad_id):
+def fix_id(repo, rev, bad_id):
 
   # Find the GOOD_ID to replace BAD_ID.
-  good_id = find_good_id(repo_dir, bad_id)
+  good_id = find_good_id(repo, bad_id)
 
   # Replacement ID must be the same length, otherwise I don't know how to
   # reconstruct the file so as to preserve all offsets.
@@ -100,46 +100,48 @@ def fix_id(repo_dir, rev, bad_id):
     raise FixError("The ID supplied is already correct: " +
                    "good id '" + good_id + "'")
 
-  replace_in_rev_file(repo_dir, rev, bad_id, good_id)
+  replace_in_rev_file(repo, rev, bad_id, good_id)
   print("Fixed id: " + bad_id + " -> " + good_id)
   fixed_ids[bad_id] = good_id
 
-def fix_checksum(repo_dir, rev, old_checksum, new_checksum):
+def fix_checksum(repo, rev, old_checksum, new_checksum):
   """Change all occurrences of OLD_CHECKSUM to NEW_CHECKSUM in the revision
      file for REV in REPO_DIR."""
 
   assert len(old_checksum) and len(new_checksum)
   assert old_checksum != new_checksum
 
-  replace_in_rev_file(repo_dir, rev, old_checksum, new_checksum)
+  replace_in_rev_file(repo, rev, old_checksum, new_checksum)
   print("Fixed checksum: " + old_checksum + " -> " + new_checksum)
   fixed_checksums[old_checksum] = new_checksum
 
-def fix_rep_ref(repo_dir, rev, prefix, rep_rev, bad_offset, rep_size):
+def fix_rep_ref(repo, rev, prefix, rep_rev, bad_offset, rep_size):
   """Fix a "DELTA <REP_REV> <BAD_OFFSET> <REP_SIZE>"
         or "text: <REP_REV> <BAD_OFFSET> <REP_SIZE> ..."
      line in the revision file for REV in REPO_DIR, where <BAD_OFFSET> is
      wrong.  PREFIX is 'DELTA' or 'text:'.
   """
-  good_offset = find_good_rep_header(repo_dir, rep_rev, rep_size)
+  good_offset = find_good_rep_header(repo, rep_rev, rep_size)
   old_line = ' '.join([prefix, rep_rev, bad_offset, rep_size])
   new_line = ' '.join([prefix, rep_rev, good_offset, rep_size])
   if good_offset == bad_offset:
     raise FixError("Attempting to fix a rep ref that appears to be correct: " + old_line)
-  replace_in_rev_file(repo_dir, rev, old_line, new_line)
+  replace_in_rev_file(repo, rev, old_line, new_line)
   print("Fixed rep ref:", old_line, "->", new_line)
 
 
-def handle_one_error(repo_dir, rev, error_lines):
+def handle_one_error(repo, rev, error_lines):
   """If ERROR_LINES describes an error we know how to fix, then fix it.
      Return True if fixed, False if not fixed."""
 
   for line in error_lines:
     verbose_print(line)
 
-  match = re.match(r"svn.*: Filesystem is corrupt", error_lines[0])
-  if match:
-    # This is an additional line in v1.7+ error messages: skip it.
+  # Skip uninteresting lines
+  #   svnadmin 1.9+: r"\* Error verifying revision .*"
+  #   svnadmin 1.7+: r"svn.*: Filesystem is corrupt"
+  while (re.match(r"\* Error verifying revision .*", error_lines[0]) or
+         re.match(r"svn.*: Filesystem is corrupt", error_lines[0])):
     error_lines = error_lines[1:]
 
   line1 = error_lines[0]
@@ -149,7 +151,7 @@ def handle_one_error(repo_dir, rev, erro
     # Fix it.
     bad_id = match.group(1)
     verbose_print(error_lines[0])
-    fix_id(repo_dir, rev, bad_id)
+    fix_id(repo, rev, bad_id)
 
     # Verify again, and expect to discover a checksum mismatch.
     # verbose_print("Fixed an ID; now verifying to discover the checksum we need to update")
@@ -161,7 +163,7 @@ def handle_one_error(repo_dir, rev, erro
     #
     # expected = ...
     # actual   = ...
-    # fix_checksum(repo_dir, rev, expected, actual)
+    # fix_checksum(repo, rev, expected, actual)
 
     return True
 
@@ -169,7 +171,7 @@ def handle_one_error(repo_dir, rev, erro
   if match:
     expected = re.match(r' *expected: *([^ ]*)', error_lines[1]).group(1)
     actual   = re.match(r' *actual: *([^ ]*)',   error_lines[2]).group(1)
-    fix_checksum(repo_dir, rev, expected, actual)
+    fix_checksum(repo, rev, expected, actual)
     return True
 
   match = re.match(r"svn.*: Corrupt representation '([0-9]*) ([0-9]*) ([0-9]*) .*'", line1)
@@ -194,11 +196,11 @@ def handle_one_error(repo_dir, rev, erro
     # a knock-on effect, invalidating the checksum of the rep so that all
     # references to this rep will then need their checksums correcting.
     try:
-      fix_rep_ref(repo_dir, rev, 'DELTA', bad_rev, bad_offset, bad_size)
+      fix_rep_ref(repo, rev, 'DELTA', bad_rev, bad_offset, bad_size)
     except FixError:
       # In at least one case of corruption, every bad reference has been in a
       # 'text:' line.  Fixing this has no knock-on effect.
-      fix_rep_ref(repo_dir, rev, 'text:', bad_rev, bad_offset, bad_size)
+      fix_rep_ref(repo, rev, 'text:', bad_rev, bad_offset, bad_size)
 
     return True
 
@@ -211,18 +213,18 @@ def grab_stderr(child_argv):
   child_err = [line for line in stderr.splitlines() if '(apr_err=' not in line]
   return child_err
 
-def fix_one_error(repo_dir, rev):
+def fix_one_error(repo, rev):
   """Verify, and if there is an error we know how to fix, then fix it.
      Return False if no error, True if fixed, exception if can't fix."""
 
   # Capture the output of 'svnadmin verify' (ignoring any debug-build output)
-  svnadmin_err = grab_stderr([SVNADMIN, 'verify', '-q', '-r'+rev, repo_dir])
+  svnadmin_err = grab_stderr([SVNADMIN, 'verify', '-q', '-r'+rev, repo.path])
 
   if svnadmin_err == []:
     return False
 
   try:
-    if handle_one_error(repo_dir, rev, svnadmin_err):
+    if handle_one_error(repo, rev, svnadmin_err):
       return True
     else:
       verbose_print("Unrecognized error message; trying 'svnlook' instead.")
@@ -235,51 +237,48 @@ def fix_one_error(repo_dir, rev):
   # one that we *can* handle.
 
   # Capture the output of 'svnlook tree' (ignoring any debug-build output)
-  svnlook_err = grab_stderr([SVNLOOK, 'tree', '-r'+rev, repo_dir])
+  svnlook_err = grab_stderr([SVNLOOK, 'tree', '-r'+rev, repo.path])
 
   if svnlook_err == []:
     print('warning: svnlook did not find an error')
   else:
-    if handle_one_error(repo_dir, rev, svnlook_err):
+    if handle_one_error(repo, rev, svnlook_err):
       return True
     else:
       verbose_print("Unrecognized error message.")
 
   raise FixError("unable to fix r" + str(rev))
 
-def check_formats(repo_dir):
+def check_formats(repo):
   """Check that REPO_DIR isn't newer than we know how to handle."""
 
-  repos_format = int(open(os.path.join(repo_dir, 'format')).readline())
-  if repos_format not in [3,5]:
+  if repo.repo_format not in [3,5]:
     raise FixError("Repository '%s' too new (format %d); try the version at %s"
-                   % (repo_dir, repos_format, URL))
+                   % (repo.path, repo.repo_format, URL))
 
-  fs_type = open(os.path.join(repo_dir, 'db', 'fs-type')).read().rstrip()
-  if fs_type != 'fsfs':
+  if repo.fs_type != 'fsfs':
     raise FixError("Repository '%s' has wrong FS backend: "
-                   "found '%s', expected '%s'" % (repo_dir, fs_type, 'fsfs'))
+                   "found '%s', expected '%s'" % (repo.path, repo.fs_type, 'fsfs'))
 
-  fsfs_format = int(open(os.path.join(repo_dir, 'db', 'format')).readline())
-  if fsfs_format > MAX_FSFS_FORMAT:
+  if repo.db_format > MAX_FSFS_FORMAT:
     raise FixError("Filesystem '%s' is too new (format %d); try the version at %s"
-                   % (os.path.join(repo_dir, 'db'), fsfs_format, URL))
+                   % (os.path.join(repo.path, 'db'), repo.db_format, URL))
 
 # ----------------------------------------------------------------------
 # Main program
 
-def fix_rev(repo_dir, rev):
+def fix_rev(repo, rev):
   """"""
 
-  check_formats(repo_dir)
+  check_formats(repo)
 
   # Back up the file
-  if not os.path.exists(rev_file_path(repo_dir, rev) + '.orig'):
+  if not os.path.exists(repo.rev_file_path(rev) + '.orig'):
     pass
     # cp -a "$FILE" "$FILE.orig"
 
   # Keep looking for verification errors in r$REV and fixing them while we can.
-  while fix_one_error(repo_dir, rev):
+  while fix_one_error(repo, rev):
     pass
   print("Revision " + rev + " verifies OK.")
 
@@ -293,8 +292,9 @@ if __name__ == '__main__':
   repo_dir = sys.argv[1]
   rev = sys.argv[2]
 
+  repo = Repository(repo_dir)
   try:
-    fix_rev(repo_dir, rev)
+    fix_rev(repo, rev)
   except FixError as e:
     print('error:', e)
     sys.exit(1)

Modified: subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/fixer_config.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/fixer_config.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/fixer_config.py (original)
+++ subversion/branches/multi-wc-format/contrib/server-side/fsfsfixer/fixer/fixer_config.py Fri Jan 14 14:01:45 2022
@@ -9,16 +9,3 @@ SVNLOOK = 'svnlook'
 # Verbosity: True for verbose, or False for quiet
 VERBOSE = True
 
-# PER-REPOSITORY CONFIGURATION
-
-# The number of revs per shard of the repository being accessed, or 'None'
-# for a linear (that is, non-sharded) layout.  This is 1000 for almost all
-# repositories in practice.
-#
-# The correct value can be found in the 'db/format' file in the repository.
-# The second line of that file will say something like 'layout sharded 1000'
-# or 'layout linear'.
-#
-# TODO: Read this value automatically from the db/format file.
-REVS_PER_SHARD=1000
-

Modified: subversion/branches/multi-wc-format/doc/doxygen.conf
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/doc/doxygen.conf?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/doc/doxygen.conf (original)
+++ subversion/branches/multi-wc-format/doc/doxygen.conf Fri Jan 14 14:01:45 2022
@@ -112,7 +112,7 @@ INLINE_INHERITED_MEMB  = NO
 # path before files name in the file list and in the header files. If set
 # to NO the shortest path that makes the file name unique will be used.
 
-FULL_PATH_NAMES        = NO
+FULL_PATH_NAMES        = YES
 
 # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
 # can be used to strip a user-defined part of the path. Stripping is
@@ -121,7 +121,7 @@ FULL_PATH_NAMES        = NO
 # If left blank the directory from which doxygen is run is used as the
 # path to strip.
 
-STRIP_FROM_PATH        =
+STRIP_FROM_PATH        = subversion/include subversion/bindings/cxx/include
 
 # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
 # the path mentioned in the documentation of a class, which tells
@@ -130,7 +130,7 @@ STRIP_FROM_PATH        =
 # definition is used. Otherwise one should specify the include paths that
 # are normally passed to the compiler using the -I flag.
 
-STRIP_FROM_INC_PATH    =
+STRIP_FROM_INC_PATH    = subversion/include subversion/bindings/cxx/include
 
 # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
 # (but less readable) file names. This can be useful is your file systems
@@ -280,22 +280,6 @@ SUBGROUPING            = YES
 
 TYPEDEF_HIDES_STRUCT   = NO
 
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penality.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will rougly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols
-
-SYMBOL_CACHE_SIZE      = 0
-
 #---------------------------------------------------------------------------
 # Build related configuration options
 #---------------------------------------------------------------------------
@@ -478,12 +462,6 @@ MAX_INITIALIZER_LINES  = 30
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
 # Set the SHOW_FILES tag to NO to disable the generation of the Files page.
 # This will remove the Files entry from the Quick Index and from the
 # Folder Tree View (if specified). The default is YES.
@@ -577,6 +555,10 @@ WARN_LOGFILE           =
 # with spaces.
 
 INPUT                  = subversion/include \
+                         subversion/bindings/cxx/include \
+                         subversion/bindings/cxx/include/svnxx \
+                         subversion/bindings/cxx/include/svnxx/client \
+                         subversion/bindings/cxx/include/svnxx/detail \
                          subversion/include/private/svn_doxygen.h
 
 # This tag can be used to specify the character encoding of the source files
@@ -594,7 +576,7 @@ INPUT_ENCODING         = UTF-8
 # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
 # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
 
-FILE_PATTERNS          = *.h
+FILE_PATTERNS          = *.h *.hpp
 
 # The RECURSIVE tag can be used to turn specify whether or not subdirectories
 # should be searched for input files as well. Possible values are YES and NO.
@@ -805,12 +787,6 @@ HTML_FOOTER            =
 
 HTML_STYLESHEET        =
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
 # documentation will contain sections that can be hidden and shown after the
 # page has loaded. For this to work a browser that supports
@@ -959,11 +935,6 @@ ENUM_VALUES_PER_LINE   = 1
 
 GENERATE_TREEVIEW      = NO
 
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
-
-USE_INLINE_TREES       = NO
-
 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
 # used to set the initial width (in pixels) of the frame in which the tree
 # is shown.
@@ -1151,18 +1122,6 @@ GENERATE_XML           = NO
 
 XML_OUTPUT             = xml
 
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_SCHEMA             =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_DTD                =
-
 # If the XML_PROGRAMLISTING tag is set to YES Doxygen will
 # dump the program listings (including syntax highlighting
 # and cross-referencing information) to the XML output. Note that
@@ -1378,7 +1337,7 @@ HAVE_DOT               = NO
 # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
 # containing the font.
 
-DOT_FONTNAME           = FreeSans
+DOT_FONTNAME           =
 
 # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
 # The default size is 10pt.

Modified: subversion/branches/multi-wc-format/gen-make.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/gen-make.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/gen-make.py (original)
+++ subversion/branches/multi-wc-format/gen-make.py Fri Jan 14 14:01:45 2022
@@ -70,7 +70,7 @@ def main(fname, gentype, verfname=None,
 
   if ('--debug', '') in other_options:
     for dep_type, target_dict in generator.graph.deps.items():
-      sorted_targets = list(target_dict.keys()); sorted_targets.sort()
+      sorted_targets = sorted(target_dict.keys(), key=str)
       for target in sorted_targets:
         print(dep_type + ": " + _objinfo(target))
         for source in target_dict[target]:
@@ -175,6 +175,8 @@ def _usage_exit(err=None):
   print("")
   print("  --with-swig=DIR")
   print("           look for the swig program in DIR")
+  print("  --with-py3c=DIR")
+  print("           look for the py3c library in DIR")
   print("")
   print("  --with-sqlite=DIR")
   print("           look for sqlite in DIR")
@@ -204,6 +206,9 @@ def _usage_exit(err=None):
   print("  --with-static-openssl")
   print("           Use static openssl")
   print("")
+  print("  --with-shared-serf")
+  print("           Use shared library version of serf")
+  print("")
   print("  --vsnet-version=VER")
   print("           generate for VS.NET version VER (2005-2017 or 9.0-15.0)")
   print("           [implies '-t vcproj']")
@@ -214,8 +219,6 @@ def _usage_exit(err=None):
   print("")
   print("  --with-apr_memcache=DIR")
   print("           the apr_memcache sources are in DIR")
-  print("  --disable-gmock")
-  print("           do not use Googlemock")
   sys.exit(1)
 
 
@@ -251,11 +254,13 @@ if __name__ == '__main__':
                             'with-jdk=',
                             'with-junit=',
                             'with-swig=',
+                            'with-py3c=',
                             'with-sqlite=',
                             'with-sasl=',
                             'with-apr_memcache=',
                             'with-static-apr',
                             'with-static-openssl',
+                            'with-shared-serf',
                             'enable-pool-debug',
                             'enable-purify',
                             'enable-quantify',
@@ -263,7 +268,6 @@ if __name__ == '__main__':
                             'disable-shared',
                             'installed-libs=',
                             'vsnet-version=',
-                            'disable-gmock',
                             ])
     if len(args) > 1:
       _usage_exit("Too many arguments")

Modified: subversion/branches/multi-wc-format/get-deps.sh
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/get-deps.sh?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/get-deps.sh (original)
+++ subversion/branches/multi-wc-format/get-deps.sh Fri Jan 14 14:01:45 2022
@@ -31,28 +31,24 @@
 # features already used in the file.  Reviewing the history of changes
 # may be useful as well.
 
-APR_VERSION=${APR_VERSION:-"1.4.6"}
+APR_VERSION=${APR_VERSION:-"1.5.0"}
 APU_VERSION=${APU_VERSION:-"1.5.1"}
+PY3C_VERSION=${PY3C_VERSION:='1.1'}
 SERF_VERSION=${SERF_VERSION:-"1.3.8"}
 ZLIB_VERSION=${ZLIB_VERSION:-"1.2.8"}
 SQLITE_VERSION=${SQLITE_VERSION:-"3.8.11.1"}
 # Used to construct the SQLite download URL.
 SQLITE_VERSION_REL_YEAR=2015
-GTEST_VERSION=${GMOCK_VERSION:-"1.7.0"}
-GMOCK_VERSION=${GMOCK_VERSION:-"1.7.0"}
 HTTPD_VERSION=${HTTPD_VERSION:-"2.4.10"}
 APR_ICONV_VERSION=${APR_ICONV_VERSION:-"1.2.1"}
 
 APR=apr-${APR_VERSION}
 APR_UTIL=apr-util-${APU_VERSION}
+PY3C=py3c-${PY3C_VERSION}
 SERF=serf-${SERF_VERSION}
 ZLIB=zlib-${ZLIB_VERSION}
 SQLITE_VERSION_LIST=`echo $SQLITE_VERSION | sed -e 's/\./ /g'`
 SQLITE=sqlite-amalgamation-`printf %d%02d%02d%02d $SQLITE_VERSION_LIST`
-GTEST=release-${GTEST_VERSION}
-GTEST_URL=https://github.com/google/googletest/archive
-GMOCK=release-${GMOCK_VERSION}
-GMOCK_URL=https://github.com/google/googlemock/archive
 
 HTTPD=httpd-${HTTPD_VERSION}
 APR_ICONV=apr-iconv-${APR_ICONV_VERSION}
@@ -67,12 +63,12 @@ HTTP_FETCH=
 
 # Need this uncommented if any of the specific versions of the ASF tarballs to
 # be downloaded are no longer available on the general mirrors.
-APACHE_MIRROR=http://archive.apache.org/dist
+APACHE_MIRROR=https://archive.apache.org/dist
 
 # helpers
 usage() {
     echo "Usage: $0"
-    echo "Usage: $0 [ apr | serf | zlib | sqlite | googlemock ] ..."
+    echo "Usage: $0 [ apr | py3c | serf | zlib | sqlite ] ..."
     exit $1
 }
 
@@ -90,6 +86,19 @@ get_apr() {
     test -d $BASEDIR/apr-util || mv $APR_UTIL apr-util
 }
 
+get_py3c() {
+    test -d $BASEDIR/py3c && return
+    py3cdist=v${PY3C_VERSION}.tar.gz
+
+    cd $TEMPDIR
+    $HTTP_FETCH https://github.com/encukou/py3c/archive/${py3cdist}
+    cd $BASEDIR
+
+    gzip -dc $TEMPDIR/${py3cdist} | tar -xf -
+
+    mv $PY3C py3c
+}
+
 get_serf() {
     test -d $BASEDIR/serf && return
 
@@ -106,7 +115,7 @@ get_zlib() {
     test -d $BASEDIR/zlib && return
 
     cd $TEMPDIR
-    $HTTP_FETCH http://sourceforge.net/projects/libpng/files/zlib/$ZLIB_VERSION/$ZLIB.tar.gz
+    $HTTP_FETCH https://sourceforge.net/projects/libpng/files/zlib/$ZLIB_VERSION/$ZLIB.tar.gz
     cd $BASEDIR
 
     gzip -dc $TEMPDIR/$ZLIB.tar.gz | tar -xf -
@@ -127,29 +136,11 @@ get_sqlite() {
 
 }
 
-get_googlemock() {
-    test -d $BASEDIR/googlemock && return
-
-    cd $TEMPDIR
-    $HTTP_FETCH ${GTEST_URL}/${GTEST}.zip
-    unzip -q ${GTEST}.zip
-    rm -f ${GTEST}.zip
-
-    $HTTP_FETCH ${GMOCK_URL}/${GMOCK}.zip
-    unzip -q ${GMOCK}.zip
-    rm -f ${GMOCK}.zip
-
-    cd $BASEDIR
-    mkdir googlemock
-    mv $TEMPDIR/googletest-release-${GTEST_VERSION} googlemock/googletest
-    mv $TEMPDIR/googlemock-release-${GMOCK_VERSION} googlemock/googlemock
-}
-
 # main()
 get_deps() {
     mkdir -p $TEMPDIR
 
-    for i in zlib serf sqlite-amalgamation apr apr-util gmock-fused; do
+    for i in zlib serf sqlite-amalgamation py3c apr apr-util; do
       if [ -d $i ]; then
         echo "Local directory '$i' already exists; the downloaded copy won't be used" >&2
       fi
@@ -165,6 +156,7 @@ get_deps() {
       done
     else
       get_apr
+      get_py3c
       get_serf
       get_zlib
       get_sqlite

Modified: subversion/branches/multi-wc-format/notes/anchors_and_targets.txt
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/notes/anchors_and_targets.txt?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/notes/anchors_and_targets.txt (original)
+++ subversion/branches/multi-wc-format/notes/anchors_and_targets.txt Fri Jan 14 14:01:45 2022
@@ -104,7 +104,7 @@ The Status Quo
    scheme, however, such as the need to examine the a directory
    target's parent, and perhaps a handful of unspecified
    "spidey-sense" warnings.  PLEASE, if you have valid technical
-   complaints, (re-)voice them in reponse to this mail so they can be
+   complaints, (re-)voice them in response to this mail so they can be
    evaluated more closely, offering better solutions if you can.
 
    For example, the editor could be changed so that some flavor of

Modified: subversion/branches/multi-wc-format/notes/commit-access-templates/full-committer.tmpl
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/notes/commit-access-templates/full-committer.tmpl?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/notes/commit-access-templates/full-committer.tmpl (original)
+++ subversion/branches/multi-wc-format/notes/commit-access-templates/full-committer.tmpl Fri Jan 14 14:01:45 2022
@@ -5,7 +5,7 @@ of "{AT}" with real "@" signs.  It's jus
 fool the spam address harvesters.
 ]]]
 
-### see http://www.apache.org/dev/pmc.html#newpmc for procedure
+### see https://www.apache.org/dev/pmc.html#newpmc for procedure
 
 From: "Some Committer" <a....@wherever.example.com>
 To: New Full Committer <ne...@wherever.new.committers.live>

Modified: subversion/branches/multi-wc-format/notes/commit-access-templates/partial-committer.tmpl
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/notes/commit-access-templates/partial-committer.tmpl?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/notes/commit-access-templates/partial-committer.tmpl (original)
+++ subversion/branches/multi-wc-format/notes/commit-access-templates/partial-committer.tmpl Fri Jan 14 14:01:45 2022
@@ -5,6 +5,8 @@ instances of "{AT}" with real "@" signs.
 template to fool the spam address harvesters.
 ]]]
 
+### see https://www.apache.org/dev/pmc.html#newcommitter for procedure
+
 From: "Some Committer" <a....@wherever.example.com>
 To: New Partial Committer <ne...@wherever.new.committers.live>
 Cc: private{AT}subversion.apache.org

Modified: subversion/branches/multi-wc-format/notes/commit-access-templates/pmc-member.tmpl
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/notes/commit-access-templates/pmc-member.tmpl?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/notes/commit-access-templates/pmc-member.tmpl (original)
+++ subversion/branches/multi-wc-format/notes/commit-access-templates/pmc-member.tmpl Fri Jan 14 14:01:45 2022
@@ -5,7 +5,7 @@ real "@" signs.  It's just masked in thi
 address harvesters.
 ]]]
 
-### see http://www.apache.org/dev/pmc.html#newpmc for procedure
+### see https://www.apache.org/dev/pmc.html#newpmc for procedure
 
 From: "Some PMC Member" <a....@wherever.example.com>
 To: New PMC Member <ne...@wherever.new.pmcers.live>

Modified: subversion/branches/multi-wc-format/notes/dump-load-format.txt
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/notes/dump-load-format.txt?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/notes/dump-load-format.txt (original)
+++ subversion/branches/multi-wc-format/notes/dump-load-format.txt Fri Jan 14 14:01:45 2022
@@ -1,6 +1,6 @@
 = How to interpret Subversion dumpfiles =
 
-Version 1.1, 2013-02-02
+Version 1.3, 2020-12-21
 
 == Introduction ==
 
@@ -22,6 +22,9 @@ has a property section.  How are they to
 2. The section on the semantics of kinds of operations documents a
 minor bug at r39883 in the behavior of "add".  Has this been fixed?
 
+3. The diff format and compression (if any) used in Version 3
+format are not described.
+
 Portions of text relevant to these questions are tagged with FIXME.
 
 == Syntax ==
@@ -95,7 +98,12 @@ Revision record.  These two numbers will
 record; the Content-length header is added for the benefit of software
 that can parse RFC-822 messages.
 
-A revision record is followed by one or more Node records (see below).
+A revision record is followed by zero or more Node records (see below).
+
+Revisions are always dumped in monotonically increasing
+revision-number order. The date property of a revision may be
+explicitly set to any value, or even unset, but normally a sequence of
+commits will have monotonically increasing timestamps.
 
 ==== Node records ====
 
@@ -151,6 +159,7 @@ Text-content-length will be present only
 Zero is a legal value for this length, indicating an empty file.
 
 Prop-content-length will be present only when there is a properties section.
+A properties section has non-zero length even if it has no entries.
 
 Content-length will be present if there is either a text or a
 properties section.  This is not always the case.  In particular, 
@@ -357,20 +366,47 @@ The revision properties do not persist t
 has exactly the revision properties specified in its revision record, or
 no revision properties if there is no property section.
 
-The key thing to know about Node properties is that they are 
-persistent, once set, until modified by a future property 
-section on the same path.
-
-Normally, a dumpfile re-lists the entire property set for a directory
-or file in every Node record that changes any part of it. (But see
-the material on delta dumps for an exception.)
+Node properties, like node text, are persistent: once set, they are
+carried forward until modified by a future property section, both on the
+same path and on the target of a copyfrom operation.
 
-This implies that to delete a given property from a path, a dumpfile
+In non-delta format, to delete a given property from a path, a dumpfile
 generator will issue a Node record with all other properties listed in it;
 to delete all properties from a path, the dumpfile generator will
-simply issue a node with an empty properties section. Note that this
-is different from an *absent* properties section, which will change
-no properties and will be associated with a change to content!
+issue a node with an empty properties section. (This is different from
+an *absent* properties section, which will change no properties.)
+
+=== Special properties === 
+
+svn:author::
+    Identification of the commit author, normally a Unix username on
+    the repository server.
+
+svn:date::
+    An RFC3339 UTC timestamp to millisecond precision.  Here is an example:
+    "2011-11-30T16:41:55.154754Z". The length and precision of this
+    field is fixed: 27 characters with the trailing Zulu timezone
+    required.
+
+svn:log::
+    The change comment associated with this revision.
+
+The following per-node properties are interpreted by Subversion itself:
+
+svn:executable::
+    When this is set on a node, the executable bits in the metadata of
+    checkout copies corresponding file are set. On Unix systems which
+    of the x bits are set is filtered by the current umask.
+
+svn:ignore, svn:global-ignores::
+    Set ignore patterns for Subversion clients. Read the Subversion
+    manual for semantic details.
+
+svn:mergeinfo, svn:mime-type, svn:keywords, svn:eol-style, svn:externals::
+    Read the Subversion manual for semantic details.
+
+All other property settings are ignored by Subversion, but preserved
+in repositories and dump streams.
 
 === Representation of symbolic links ===
 
@@ -384,15 +420,24 @@ be defined.  None such yet exist as of r
 
 === Implementation pragmatics ===
 
+Dumpfile generation in general is not canonical, nor minimalist. In
+particular, interpreters should be prepared to see many empty property
+sections (nominally deleting all properties) when there are no
+previous properties set to be deleted.
+
 Because directory operations with copyfroms don't specify all the file
 paths they modify, an interpreter for this format must build a map of
 the paths in the file store it is manipulating, and update that map as
 it processes each Node record.
 
 On a repository with thousands of commits, the per-revision list of
-maps can become quite large. For space economy, the file map for each 
-revision can be discarded after it is processed *unless it is a source
-revision for a copyfrom*. 
+maps can become quite large. It is tempting to think that the file map
+for each revision can be discarded after it is processed unless it is
+a source revision for a copyfrom, but there are cases in which doing
+this will leave you unable to trace ancestry chains through copies.
+
+Instead, it is advisable to build your filemaps using a copy-on-write
+store.
 
 == An example ==
 

Modified: subversion/branches/multi-wc-format/notes/knobs
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/notes/knobs?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/notes/knobs (original)
+++ subversion/branches/multi-wc-format/notes/knobs Fri Jan 14 14:01:45 2022
@@ -56,6 +56,7 @@ SVN_SQLITE_MIN_VERSION
 SVN_SERF_NO_LOGGING
 SVN_ALLOW_SHORT_INTS
 SVN_ALLOW_NON_8_BIT_CHARS
+SVNXX_USE_BOOST
 
 2.3 Debugging Support
 
@@ -75,6 +76,7 @@ SVN_FS__TRAIL_DEBUG
 SVN_FS_FS__LOG_ACCESS
 SVN_FS_EMULATE_PATHS_CHANGED
 SVN_FS_EMULATE_REPORT_CHANGES
+SVNXX_POOL_DEBUG
 
 2.4 Test-only
 
@@ -304,6 +306,15 @@ SVN_I_LIKE_LATENCY_SO_IGNORE_HTTPV2
   Default:   not defined
   Suggested: not defined (to ensure correct behaviour)
 
+4.13 SVNXX_USE_BOOST
+  Scope:     SVN++ (subversion/bindings/cxx)
+  Purpose:   Adds header-only conversions and overloads to make SVN++
+             interoperate cleanly with selected Boost types. Defining this
+             symbol does *not* affect the SVN++ ABI. Users may define the
+             symbol when using SVN++ after libsvnxx has been built.
+  Range:     definedness
+  Default:   not defined
+  Suggested: defined for testing SVN++, otherwise not defined
 
 5 Defines controlling debug support
 ==================================
@@ -458,6 +469,14 @@ SVN_I_LIKE_LATENCY_SO_IGNORE_HTTPV2
   Default:   TRUE (local default if macro has not been defined)
   Suggested: FALSE
 
+5.17 SVNXX_POOL_DEBUG
+
+  Scope:     SVN++ (subversion/bindings/cxx)
+  Purpose:   Logs debugging info about the lifetime of the SVN++ global pool.
+             Depends on SVN_DEBUG being defined.
+  Range:     definedness
+  Default:   not defined
+  Suggested: defined, not defined
 
 6 Defines that affect unit tests
 ================================

Modified: subversion/branches/multi-wc-format/notes/moves
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/notes/moves?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/notes/moves (original)
+++ subversion/branches/multi-wc-format/notes/moves Fri Jan 14 14:01:45 2022
@@ -75,7 +75,7 @@ private libsvn_wc API:
 
 More API changes might be needed (TBD).
 In particular, scan_deletion may need to return a list of moves
-in the multi-layer case (http://wiki.apache.org/subversion/MultiLayerMoves)
+in the multi-layer case (https://cwiki.apache.org/confluence/display/SVN/MultiLayerMoves)
 
 We might require a working copy upgrade when going from 1.7 to 1.8,
 and only allow new move functionality to be used with 1.8 working copies.

Modified: subversion/branches/multi-wc-format/notes/repos-dictated-config
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/notes/repos-dictated-config?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/notes/repos-dictated-config (original)
+++ subversion/branches/multi-wc-format/notes/repos-dictated-config Fri Jan 14 14:01:45 2022
@@ -1,2 +1,2 @@
 [  The contents and further evolution of this document have been moved to  ]
-[  http://wiki.apache.org/subversion/ServerDictatedConfiguration           ]
+[  https://cwiki.apache.org/confluence/display/SVN/ServerDictatedConfiguration  ]

Modified: subversion/branches/multi-wc-format/notes/shelving/shelf-structure.txt
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/notes/shelving/shelf-structure.txt?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/notes/shelving/shelf-structure.txt (original)
+++ subversion/branches/multi-wc-format/notes/shelving/shelf-structure.txt Fri Jan 14 14:01:45 2022
@@ -1,28 +1,54 @@
 == Storage Structure for Shelving ==
 
 
-=== Shelving (trunk) ===
+=== Shelving v3 (trunk) ===
 
-In development in trunk (1.11-dev), marked "experimental".
+In development in trunk (1.12-dev), marked "experimental".
+
+Each shelf-version is stored in an entire copy of the WC. The shelves are
+stored in a sibling to the user's WC, at '<WC-root-dir>.shelves'. Inside it:
+
+* .../<encoded-name>.current
+  Holds an ASCII-decimal number stating the latest shelf-version of the
+  shelf <encoded-name>, followed by a newline character (LF).
+
+* .../<encoded-name>.log
+  Holds the 'revision' properties of the shelf, in svn_hash_write2() format
+  terminated with "PROPS-END". Created when any revprop is set; need not
+  exist.
+
+* .../<encoded-name>-<version>.wc
+  Directory holding a shelf-version as a real WC.
+
+
+=== Shelving v2 ===
+
+Released in Subversion 1.11.0, marked "experimental".
 
 Each shelf has zero or more versions of the change, and exactly one set of
 'revision' properties.
 
-* .svn/shelves
+* .svn/experimental/shelves/v2
   This subdirectory holds all shelving metadata and data.
   It is created on demand, and never deleted.
 
-* .svn/shelves/<encoded-name>.current
+* .svn/experimental/shelves/v2/<encoded-name>.current
   Holds an ASCII-decimal number stating the latest shelf-version of the
-  shelf <encoded-name>.
+  shelf <encoded-name>, followed by a newline character (LF).
 
-* .svn/shelves/<encoded-name>.log
+* .svn/experimental/shelves/v2/<encoded-name>.log
   Holds the 'revision' properties of the shelf, in svn_hash_write2() format
   terminated with "PROPS-END". Created when any revprop is set; need not
   exist.
 
-* .svn/shelves/<encoded-name>-<version>.patch
-  The patch file representing version <version>.
+* .svn/experimental/shelves/v2/<encoded-name>-<version>.d
+  Directory holding the metadata and {base,working}{text,props} files for a
+  shelf-version. For each shelved WC-relpath <P>:
+  - <P>.meta : metadata, serialized in a shelf-v2-specific format
+  - <P>.base : the base text (absent for a directory)
+  - <P>.work : the working text (absent for a directory)
+  - <P>.base-props : the base properties
+  - <P>.work-props : the working properties
 
 <encoded-name>: the shelf name as UTF-8, encoded byte-by-byte into
   two-hex-digit pairs, e.g. shelf name 'Az' is encoded as '417f'.

Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/README
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/README?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/bindings/javahl/README (original)
+++ subversion/branches/multi-wc-format/subversion/bindings/javahl/README Fri Jan 14 14:01:45 2022
@@ -36,7 +36,7 @@ check-all-javahl      run all JavaHL tes
 
 (In order to run check-javahl, you must have specified a path to a JUnit
 jar file with --with-junit when running configure; JUnit version 4.11
-has been tested.  JUnit can be downloaded from http://junit.org/ .)
+has been tested.  JUnit can be downloaded from https://junit.org/ .)
 
 
 MacOS X:
@@ -63,8 +63,9 @@ workspace.  The private project/workspac
 Success stories
 ---------------
 
-Subclipse, Eclipse IDE plug-in <http://subclipse.tigris.org/>
-SmartSVN, cross-platform Subversion client (http://www.smartsvn.com/)
+Subclipse, Eclipse IDE plug-in
+<https://marketplace.eclipse.org/content/subclipse/>
+SmartSVN, cross-platform Subversion client (https://www.smartsvn.com/)
 
 
 Why not 100% pure Java?
@@ -78,10 +79,10 @@ itself.  The official Subversion C libra
 implementation of a Subversion client's logic, and are the most robust
 client implementation available.  Using JNI allows the effort that has
 gone into the existing libraries to be leveraged from Java, and allows
-developer time to me more efficently spent on further development of the
+developer time to me more efficiently spent on further development of the
 underlying libraries shared by many implementations.
 
-The SVNKit <http://svnkit.com/> client library (formerly known as
+The SVNKit <https://svnkit.com/> client library (formerly known as
 JavaSVN) is a 100% pure Java implementation, and attempts to track the
 latest changes to Subversion's core libraries; however, this is an
 independent project and the Subversion project cannot make any promises

Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/native/BlameCallback.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/native/BlameCallback.cpp?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/bindings/javahl/native/BlameCallback.cpp (original)
+++ subversion/branches/multi-wc-format/subversion/bindings/javahl/native/BlameCallback.cpp Fri Jan 14 14:01:45 2022
@@ -28,14 +28,20 @@
 #include "CreateJ.h"
 #include "JNIUtil.h"
 #include "svn_time.h"
+
+#include "svn_private_config.h"
+
 /**
  * Create a BlameCallback object
  * @param jcallback the Java callback object.
  */
-BlameCallback::BlameCallback(jobject jcallback)
-{
-  m_callback = jcallback;
-}
+BlameCallback::BlameCallback(jobject jrangeCallback, jobject jlineCallback)
+  : m_start_revnum(SVN_INVALID_REVNUM),
+    m_end_revnum(SVN_INVALID_REVNUM),
+    m_range_callback_invoked(false),
+    m_range_callback(jrangeCallback),
+    m_line_callback(jlineCallback)
+{}
 /**
  * Destroy a BlameCallback object
  */
@@ -48,36 +54,84 @@ BlameCallback::~BlameCallback()
 /* implements svn_client_blame_receiver3_t */
 svn_error_t *
 BlameCallback::callback(void *baton,
-                        svn_revnum_t start_revnum,
-                        svn_revnum_t end_revnum,
                         apr_int64_t line_no,
                         svn_revnum_t revision,
                         apr_hash_t *rev_props,
                         svn_revnum_t merged_revision,
                         apr_hash_t *merged_rev_props,
                         const char *merged_path,
-                        const char *line,
+                        const svn_string_t *line,
                         svn_boolean_t local_change,
                         apr_pool_t *pool)
 {
-  if (baton)
-    return static_cast<BlameCallback *>(baton)->singleLine(start_revnum,
-        end_revnum, line_no, revision, rev_props, merged_revision,
-        merged_rev_props, merged_path, line, local_change, pool);
+  BlameCallback *const self = static_cast<BlameCallback *>(baton);
+  svn_error_t *err = SVN_NO_ERROR;
 
-  return SVN_NO_ERROR;
+  if (self)
+    {
+      if (self->m_range_callback && !self->m_range_callback_invoked)
+        {
+          self->m_range_callback_invoked = true;
+          err = self->setRange();
+        }
+
+      if (self->m_line_callback && err == SVN_NO_ERROR)
+        {
+          err = self->singleLine(
+              line_no, revision, rev_props, merged_revision,
+              merged_rev_props, merged_path, line, local_change, pool);
+        }
+    }
+
+  return err;
 }
 
+svn_error_t *
+BlameCallback::setRange()
+{
+  if (m_start_revnum == SVN_INVALID_REVNUM
+      || m_end_revnum == SVN_INVALID_REVNUM)
+    return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL,
+                            _("Blame revision range was not resolved"));
+
+  JNIEnv *env = JNIUtil::getEnv();
+
+  // Create a local frame for our references
+  env->PushLocalFrame(LOCAL_FRAME_SIZE);
+  if (JNIUtil::isJavaExceptionThrown())
+    return SVN_NO_ERROR;
+
+  // The method id will not change during the time this library is
+  // loaded, so it can be cached.
+  static jmethodID mid = 0;
+  if (mid == 0)
+    {
+      jclass clazz = env->FindClass(JAVAHL_CLASS("/callback/BlameRangeCallback"));
+      if (JNIUtil::isJavaExceptionThrown())
+        POP_AND_RETURN(SVN_NO_ERROR);
+
+      mid = env->GetMethodID(clazz, "setRange", "(JJ)V");
+      if (JNIUtil::isJavaExceptionThrown() || mid == 0)
+        POP_AND_RETURN(SVN_NO_ERROR);
+    }
+
+  // call the Java method
+  env->CallVoidMethod(m_range_callback, mid,
+                      (jlong)m_start_revnum, (jlong)m_end_revnum);
+
+  POP_AND_RETURN_EXCEPTION_AS_SVNERROR();
+}
+
+
 /**
  * Callback called for a single line in the file, for which the blame
  * information was requested.  See the Java-doc for more information.
  */
 svn_error_t *
-BlameCallback::singleLine(svn_revnum_t start_revnum, svn_revnum_t end_revnum,
-                          apr_int64_t line_no, svn_revnum_t revision,
+BlameCallback::singleLine(apr_int64_t line_no, svn_revnum_t revision,
                           apr_hash_t *revProps, svn_revnum_t mergedRevision,
                           apr_hash_t *mergedRevProps, const char *mergedPath,
-                          const char *line, svn_boolean_t localChange,
+                          const svn_string_t *line, svn_boolean_t localChange,
                           apr_pool_t *pool)
 {
   JNIEnv *env = JNIUtil::getEnv();
@@ -92,13 +146,13 @@ BlameCallback::singleLine(svn_revnum_t s
   static jmethodID mid = 0;
   if (mid == 0)
     {
-      jclass clazz = env->FindClass(JAVAHL_CLASS("/callback/BlameCallback"));
+      jclass clazz = env->FindClass(JAVAHL_CLASS("/callback/BlameLineCallback"));
       if (JNIUtil::isJavaExceptionThrown())
         POP_AND_RETURN(SVN_NO_ERROR);
 
       mid = env->GetMethodID(clazz, "singleLine",
                              "(JJLjava/util/Map;JLjava/util/Map;"
-                             "Ljava/lang/String;Ljava/lang/String;Z)V");
+                             "Ljava/lang/String;Z[B)V");
       if (JNIUtil::isJavaExceptionThrown() || mid == 0)
         POP_AND_RETURN(SVN_NO_ERROR);
     }
@@ -120,14 +174,14 @@ BlameCallback::singleLine(svn_revnum_t s
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN(SVN_NO_ERROR);
 
-  jstring jline = JNIUtil::makeJString(line);
+  jbyteArray jline = JNIUtil::makeJByteArray(line);
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN(SVN_NO_ERROR);
 
   // call the Java method
-  env->CallVoidMethod(m_callback, mid, (jlong)line_no, (jlong)revision,
+  env->CallVoidMethod(m_line_callback, mid, (jlong)line_no, (jlong)revision,
                       jrevProps, (jlong)mergedRevision, jmergedRevProps,
-                      jmergedPath, jline, (jboolean)localChange);
+                      jmergedPath, (jboolean)localChange, jline);
 
   POP_AND_RETURN_EXCEPTION_AS_SVNERROR();
 }

Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/native/BlameCallback.h
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/native/BlameCallback.h?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/bindings/javahl/native/BlameCallback.h (original)
+++ subversion/branches/multi-wc-format/subversion/bindings/javahl/native/BlameCallback.h Fri Jan 14 14:01:45 2022
@@ -37,40 +37,44 @@
 class BlameCallback
 {
  public:
-  BlameCallback(jobject jcallback);
+  BlameCallback(jobject jrangeCallback, jobject jlineCallback);
   ~BlameCallback();
 
   static svn_error_t *callback(void *baton,
-                               svn_revnum_t start_revnum,
-                               svn_revnum_t end_revnum,
                                apr_int64_t line_no,
                                svn_revnum_t revision,
                                apr_hash_t *rev_props,
                                svn_revnum_t merged_revision,
                                apr_hash_t *merged_rev_props,
                                const char *merged_path,
-                               const char *line,
+                               const svn_string_t *line,
                                svn_boolean_t local_change,
                                apr_pool_t *pool);
 
+  svn_revnum_t *get_start_revnum_p() { return &m_start_revnum; }
+  svn_revnum_t *get_end_revnum_p()   { return &m_end_revnum; }
+
  protected:
-  svn_error_t *singleLine(svn_revnum_t start_revnum,
-                          svn_revnum_t end_revnum,
-                          apr_int64_t line_no,
+  svn_error_t *setRange();
+  svn_error_t *singleLine(apr_int64_t line_no,
                           svn_revnum_t revision,
                           apr_hash_t *rev_props,
                           svn_revnum_t merged_revision,
                           apr_hash_t *merged_rev_props,
                           const char *merged_path,
-                          const char *line,
+                          const svn_string_t *line,
                           svn_boolean_t local_change,
                           apr_pool_t *pool);
 
  private:
-  /**
-   * This a local reference to the Java object.
-   */
-  jobject m_callback;
+  // Arguments for svn_client_blame6
+  svn_revnum_t m_start_revnum;
+  svn_revnum_t m_end_revnum;
+  bool m_range_callback_invoked;
+
+  // These are local references to the Java objects.
+  jobject m_range_callback;
+  jobject m_line_callback;
 };
 
 #endif  // BLAMECALLBACK_H

Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/native/CommitEditor.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/native/CommitEditor.cpp?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/bindings/javahl/native/CommitEditor.cpp (original)
+++ subversion/branches/multi-wc-format/subversion/bindings/javahl/native/CommitEditor.cpp Fri Jan 14 14:01:45 2022
@@ -444,7 +444,8 @@ svn_error_t* open_callback_session(svn_r
   if (!session)
     {
       const char* corrected_url = NULL;
-      SVN_ERR(svn_ra_open4(&session, &corrected_url, url, uuid,
+      const char* redirect_url = NULL;
+      SVN_ERR(svn_ra_open5(&session, &corrected_url, &redirect_url, url, uuid,
                            context->getCallbacks(),
                            context->getCallbackBaton(),
                            context->getConfigData(),
@@ -459,8 +460,8 @@ svn_error_t* open_callback_session(svn_r
           return svn_error_createf(
               SVN_ERR_RA_ILLEGAL_URL, NULL,
               _("Repository URL changed while session was open.\n"
-                "Expected URL: %s\nApparent URL: %s"),
-              url, corrected_url);
+                "Expected URL: %s\nRedirect URL:%s\nApparent URL: %s\n"),
+              url, redirect_url, corrected_url);
         }
     }
   return SVN_NO_ERROR;

Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/native/EditorProxy.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/native/EditorProxy.cpp?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/bindings/javahl/native/EditorProxy.cpp (original)
+++ subversion/branches/multi-wc-format/subversion/bindings/javahl/native/EditorProxy.cpp Fri Jan 14 14:01:45 2022
@@ -132,7 +132,7 @@ get_editor_method(jmethodID& mid, const
 
 jobject wrap_input_stream(svn_stream_t* stream)
 {
-  std::auto_ptr<JavaHL::NativeInputStream>
+  JavaHL::cxx::owned_ptr<JavaHL::NativeInputStream>
     wrapped(new JavaHL::NativeInputStream());
   apr_pool_t* const wrapped_pool = wrapped->get_pool().getPool();
   wrapped->set_stream(svn_stream_disown(stream, wrapped_pool));

Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/native/EditorProxy.h
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/native/EditorProxy.h?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/bindings/javahl/native/EditorProxy.h (original)
+++ subversion/branches/multi-wc-format/subversion/bindings/javahl/native/EditorProxy.h Fri Jan 14 14:01:45 2022
@@ -33,6 +33,8 @@
 #include "private/svn_editor.h"
 #include "private/svn_delta_private.h"
 
+#include "CxxCompat.hpp"
+
 /**
  * These callbacks are needed by the delta-to-Ev2 shims.
  */
@@ -53,7 +55,7 @@ struct EditorProxyCallbacks
 class EditorProxy
 {
 public:
-  typedef std::auto_ptr<EditorProxy> UniquePtr;
+  typedef ::JavaHL::cxx::owned_ptr<EditorProxy> UniquePtr;
 
   EditorProxy(jobject jeditor, apr_pool_t* edit_pool,
               const char* repos_root_url, const char* base_relpath,

Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/native/JNIStackElement.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/native/JNIStackElement.cpp?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/bindings/javahl/native/JNIStackElement.cpp (original)
+++ subversion/branches/multi-wc-format/subversion/bindings/javahl/native/JNIStackElement.cpp Fri Jan 14 14:01:45 2022
@@ -66,7 +66,7 @@ JNIStackElement::JNIStackElement(JNIEnv
       else
         {
           // This will call java.lang.Object.toString, even when it is
-          // overriden.
+          // overridden.
           jobject oStr = env->CallNonvirtualObjectMethod(jthis, jlo, mid);
           if (JNIUtil::isJavaExceptionThrown())
             return;