subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hwri...@apache.org
Subject svn commit: r1424772 [4/4] - in /subversion/branches/ev2-export: ./ build/ build/ac-macros/ build/win32/ subversion/bindings/cxxhl/include/ subversion/bindings/cxxhl/include/svncxxhl/ subversion/bindings/cxxhl/include/types/ subversion/bindings/cxxhl/s...
Date Fri, 21 Dec 2012 00:23:41 GMT
Modified: subversion/branches/ev2-export/subversion/svnrdump/svnrdump.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/svnrdump/svnrdump.h?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/svnrdump/svnrdump.h (original)
+++ subversion/branches/ev2-export/subversion/svnrdump/svnrdump.h Fri Dec 21 00:23:39 2012
@@ -39,9 +39,15 @@ extern "C" {
 
 /**
  * Get a dump editor @a editor along with a @a edit_baton allocated in
- * @a pool.  The editor will write output to @a stream.  Use @a
- * cancel_func and @a cancel_baton to check for user cancellation of
- * the operation (for timely-but-safe termination).
+ * @a pool.  The editor will write output to @a stream.
+ *
+ * @a update_anchor_relpath is the repository relative path of the
+ * anchor of the update-style drive which will happen on @a *editor;
+ * if a replay-style drive will instead be used, it should be passed
+ * as @c NULL.
+ *
+ * Use @a cancel_func and @a cancel_baton to check for user
+ * cancellation of the operation (for timely-but-safe termination).
  */
 svn_error_t *
 svn_rdump__get_dump_editor(const svn_delta_editor_t **editor,
@@ -49,6 +55,7 @@ svn_rdump__get_dump_editor(const svn_del
                            svn_revnum_t revision,
                            svn_stream_t *stream,
                            svn_ra_session_t *ra_session,
+                           const char *update_anchor_relpath,
                            svn_cancel_func_t cancel_func,
                            void *cancel_baton,
                            apr_pool_t *pool);
@@ -59,6 +66,7 @@ svn_rdump__get_dump_editor_v2(svn_editor
                               svn_revnum_t revision,
                               svn_stream_t *stream,
                               svn_ra_session_t *ra_session,
+                              const char *edit_root_relpath,
                               svn_cancel_func_t cancel_func,
                               void *cancel_baton,
                               apr_pool_t *scratch_pool,
@@ -98,6 +106,20 @@ svn_rdump__normalize_props(apr_hash_t **
                            apr_hash_t *props,
                            apr_pool_t *result_pool);
 
+/* Normalize the line ending style of a single property that "needs
+ * translation" (according to svn_prop_needs_translation(),
+ * currently all svn:* props) so that they contain only LF (\n) line endings.
+ * "\r" characters found mid-line are replaced with "\n".
+ * "\r\n" sequences are replaced with "\n"
+ *
+ * NAME is used to check that VALUE should be normalized, and if this is the
+ * case, VALUE is then normalized, allocated from RESULT_POOL
+ */
+svn_error_t *
+svn_rdump__normalize_prop(const char *name,
+                          const svn_string_t **value,
+                          apr_pool_t *result_pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/ev2-export/subversion/svnrdump/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/svnrdump/util.c?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/svnrdump/util.c (original)
+++ subversion/branches/ev2-export/subversion/svnrdump/util.c Fri Dec 21 00:23:39 2012
@@ -31,6 +31,25 @@
 
 
 svn_error_t *
+svn_rdump__normalize_prop(const char *name,
+                          const svn_string_t **value,
+                          apr_pool_t *result_pool)
+{
+  if (svn_prop_needs_translation(name))
+    {
+      const char *cstring;
+
+      SVN_ERR(svn_subst_translate_cstring2((*value)->data, &cstring,
+                                           "\n", TRUE,
+                                           NULL, FALSE,
+                                           result_pool));
+
+      *value = svn_string_create(cstring, result_pool);
+    }
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_rdump__normalize_props(apr_hash_t **normal_props,
                            apr_hash_t *props,
                            apr_pool_t *result_pool)
@@ -45,16 +64,8 @@ svn_rdump__normalize_props(apr_hash_t **
       const char *key = svn__apr_hash_index_key(hi);
       const svn_string_t *value = svn__apr_hash_index_val(hi);
 
-      if (svn_prop_needs_translation(key))
-        {
-          const char *cstring;
-
-          SVN_ERR(svn_subst_translate_cstring2(value->data, &cstring,
-                                               "\n", TRUE,
-                                               NULL, FALSE,
-                                               result_pool));
-          value = svn_string_create(cstring, result_pool);
-        }
+      SVN_ERR(svn_rdump__normalize_prop(key, &value,
+                                        result_pool));
 
       apr_hash_set(*normal_props, key, APR_HASH_KEY_STRING, value);
     }

Modified: subversion/branches/ev2-export/subversion/svnsync/svnsync.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/svnsync/svnsync.c?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/svnsync/svnsync.c (original)
+++ subversion/branches/ev2-export/subversion/svnsync/svnsync.c Fri Dec 21 00:23:39 2012
@@ -53,6 +53,7 @@ static svn_opt_subcommand_t initialize_c
 
 enum svnsync__opt {
   svnsync_opt_non_interactive = SVN_OPT_FIRST_LONGOPT_ID,
+  svnsync_opt_force_interactive,
   svnsync_opt_no_auth_cache,
   svnsync_opt_auth_username,
   svnsync_opt_auth_password,
@@ -71,6 +72,7 @@ enum svnsync__opt {
 };
 
 #define SVNSYNC_OPTS_DEFAULT svnsync_opt_non_interactive, \
+                             svnsync_opt_force_interactive, \
                              svnsync_opt_no_auth_cache, \
                              svnsync_opt_auth_username, \
                              svnsync_opt_auth_password, \
@@ -173,7 +175,13 @@ static const apr_getopt_option_t svnsync
     {"allow-non-empty", svnsync_opt_allow_non_empty, 0,
                        N_("allow a non-empty destination repository") },
     {"non-interactive", svnsync_opt_non_interactive, 0,
-                       N_("do no interactive prompting") },
+                       N_("do no interactive prompting (default is to prompt\n"
+                          "                             "
+                          "only if standard input is a terminal device)")},
+    {"force-interactive", svnsync_opt_force_interactive, 0,
+                      N_("do interactive prompting even if standard input\n"
+                         "                             "
+                         "is not a terminal device")},
     {"no-auth-cache",  svnsync_opt_no_auth_cache, 0,
                        N_("do not cache authentication tokens") },
     {"username",       svnsync_opt_auth_username, 1,
@@ -1888,6 +1896,7 @@ main(int argc, const char *argv[])
   const char *password = NULL, *source_password = NULL, *sync_password = NULL;
   apr_array_header_t *config_options = NULL;
   const char *source_prop_encoding = NULL;
+  svn_boolean_t force_interactive;
 
   if (svn_cmdline_init("svnsync", stderr) != EXIT_SUCCESS)
     {
@@ -1950,6 +1959,10 @@ main(int argc, const char *argv[])
             opt_baton.non_interactive = TRUE;
             break;
 
+          case svnsync_opt_force_interactive:
+            force_interactive = TRUE;
+            break;
+
           case svnsync_opt_trust_server_cert:
             opt_baton.trust_server_cert = TRUE;
             break;
@@ -2079,6 +2092,20 @@ main(int argc, const char *argv[])
   if (opt_baton.help)
     subcommand = svn_opt_get_canonical_subcommand2(svnsync_cmd_table, "help");
 
+  /* The --non-interactive and --force-interactive options are mutually
+   * exclusive. */
+  if (opt_baton.non_interactive && force_interactive)
+    {
+      err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                             _("--non-interactive and --force-interactive "
+                               "are mutually exclusive"));
+      return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
+    }
+  else
+    opt_baton.non_interactive = !svn_cmdline__be_interactive(
+                                  opt_baton.non_interactive,
+                                  force_interactive);
+
   /* Disallow the mixing --username/password with their --source- and
      --sync- variants.  Treat "--username FOO" as "--source-username
      FOO --sync-username FOO"; ditto for "--password FOO". */

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/basic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/basic_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/basic_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/basic_tests.py Fri Dec 21 00:23:39 2012
@@ -2255,12 +2255,14 @@ def automatic_conflict_resolution(sbox):
                                      # stdout, stderr
                                      None,
                                      ".*invalid 'accept' ARG",
-                                     'resolve', '--accept=edit')
+                                     'resolve', '--accept=edit',
+                                     '--force-interactive')
   svntest.actions.run_and_verify_svn(None,
                                      # stdout, stderr
                                      None,
                                      ".*invalid 'accept' ARG",
-                                     'resolve', '--accept=launch')
+                                     'resolve', '--accept=launch',
+                                     '--force-interactive')
   # Run 'svn resolved --accept=NOPE.  Using omega for the test.
   svntest.actions.run_and_verify_svn("Resolve command", None,
                                      ".*NOPE' is not a valid --accept value",
@@ -2499,8 +2501,17 @@ def basic_relative_url_with_peg_revision
                                 '^//A/@3', iota_url)
 
 
+def basic_auth_test_xfail_predicate():
+  """Predicate for XFail for basic_auth_test:
+  The test will fail if plaintext password storage is disabled,
+  and the RA method requires authentication."""
+  return (not svntest.main.is_os_windows()
+          and svntest.main.is_ra_type_dav()
+          and svntest.main.is_plaintext_password_storage_disabled())
+
 # Issue 2242, auth cache picking up password from wrong username entry
 @Issue(2242)
+@XFail(basic_auth_test_xfail_predicate)
 def basic_auth_test(sbox):
   "basic auth test"
 

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/commit_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/commit_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/commit_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/commit_tests.py Fri Dec 21 00:23:39 2012
@@ -1974,6 +1974,7 @@ def from_wc_top_with_bad_editor(sbox):
   exit_code, out, err = svntest.actions.run_and_verify_svn(
     "Commit succeeded when should have failed.",
     None, svntest.verify.AnyOutput,
+    '--force-interactive',
     'ci', '--editor-cmd', 'no_such-editor')
 
   err = " ".join([x.strip() for x in err])

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/davautocheck.sh
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/davautocheck.sh?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/davautocheck.sh (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/davautocheck.sh Fri Dec 21 00:23:39 2012
@@ -219,7 +219,7 @@ fi
 [ -r "$MOD_AUTHZ_SVN" ] \
   || fail "authz_svn_module not found, please use '--enable-shared --enable-dso --with-apxs' with your 'configure' script"
 
-for d in `find "$ABS_BUILDDIR" -type d -name .libs`; do
+for d in "$ABS_BUILDDIR"/subversion/*/.libs; do
   if [ -z "$BUILDDIR_LIBRARY_PATH" ]; then
     BUILDDIR_LIBRARY_PATH="$d"
   else
@@ -441,7 +441,7 @@ MaxRequestsPerChild 0
 <IfModule worker.c>
   ThreadsPerChild   8
 </IfModule>
-MaxClients          16
+MaxClients          32
 HostNameLookups     Off
 LogFormat           "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" format
 CustomLog           "$HTTPD_ROOT/req" format

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/diff_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/diff_tests.py Fri Dec 21 00:23:39 2012
@@ -3711,7 +3711,7 @@ def diff_git_with_props(sbox):
                     make_diff_prop_header("new") + \
                     make_diff_prop_added("svn:eol-style", "native") + \
                     make_git_diff_header(iota_path, "iota",
-                                         "revision 1", "working copy",
+                                         "revision 2", "working copy",
                                          text_changes=False) + \
                     make_diff_prop_header("iota") + \
                     make_diff_prop_added("svn:keywords", "Id")
@@ -3722,7 +3722,6 @@ def diff_git_with_props(sbox):
   svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff',
                                      '--git', wc_dir)
 
-@XFail()
 @Issue(4010)
 def diff_correct_wc_base_revnum(sbox):
   "diff WC-WC shows the correct base rev num"
@@ -4108,7 +4107,7 @@ def diff_properties_no_newline(sbox):
   # may not be predictable.)
   for pname, old_val, new_val in subtests:
     expected_output = \
-      make_diff_header("iota", "revision 1", "working copy") + \
+      make_diff_header("iota", "revision 2", "working copy") + \
       make_diff_prop_header("iota") + \
       make_diff_prop_modified(pname, old_val, new_val)
 

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/getopt_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/getopt_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/getopt_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/getopt_tests.py Fri Dec 21 00:23:39 2012
@@ -59,6 +59,9 @@ def load_expected_output(basename):
 
   return exp_stdout, exp_stderr
 
+# With plaintext password storage enabled, `svn --version' emits a warning:
+warn_line_re = re.compile("WARNING: Plaintext password storage")
+
 # This is a list of lines to delete.
 del_lines_res = [
                  # In 'svn --version', the date line is variable, for example:
@@ -100,6 +103,7 @@ rep_lines_res = [
 switch_res_line = 'System information:'
 
 # This is a list of lines to delete after having seen switch_res_line.
+switched_warn_line_re = None
 switched_del_lines_res = [
                           # In svn --version --verbose, dependent libs loaded
                           # shared libs are optional.
@@ -119,20 +123,31 @@ switched_rep_lines_res = [
 def process_lines(lines):
   "delete lines that should not be compared and search and replace the rest"
   output = [ ]
+  warn_re = warn_line_re
   del_res = del_lines_res
   rep_res = rep_lines_res
 
+  skip_next_line = 0
   for line in lines:
+    if skip_next_line:
+      skip_next_line = 0
+      continue
+
     if line.startswith(switch_res_line):
+      warn_re = switched_warn_line_re
       del_res = switched_del_lines_res
       rep_res = switched_rep_lines_res
 
     # Skip these lines from the output list.
     delete_line = 0
-    for delete_re in del_res:
-      if delete_re.match(line):
-        delete_line = 1
-        break
+    if warn_re and warn_re.match(line):
+      delete_line = 1
+      skip_next_line = 1     # Ignore the empty line after the warning
+    else:
+      for delete_re in del_res:
+        if delete_re.match(line):
+          delete_line = 1
+          break
     if delete_line:
       continue
 

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout Fri Dec 21 00:23:39 2012
@@ -116,7 +116,10 @@ Global options:
   --username ARG           : specify a username ARG
   --password ARG           : specify a password ARG
   --no-auth-cache          : do not cache authentication tokens
-  --non-interactive        : do no interactive prompting
+  --non-interactive        : do no interactive prompting (default is to prompt
+                             only if standard input is a terminal device)
+  --force-interactive      : do interactive prompting even if standard input
+                             is not a terminal device
   --trust-server-cert      : accept SSL server certificates from unknown
                              certificate authorities without prompting (but only
                              with '--non-interactive')
@@ -196,7 +199,10 @@ Global options:
   --username ARG           : specify a username ARG
   --password ARG           : specify a password ARG
   --no-auth-cache          : do not cache authentication tokens
-  --non-interactive        : do no interactive prompting
+  --non-interactive        : do no interactive prompting (default is to prompt
+                             only if standard input is a terminal device)
+  --force-interactive      : do interactive prompting even if standard input
+                             is not a terminal device
   --trust-server-cert      : accept SSL server certificates from unknown
                              certificate authorities without prompting (but only
                              with '--non-interactive')

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/merge_authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/merge_authz_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/merge_authz_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/merge_authz_tests.py Fri Dec 21 00:23:39 2012
@@ -257,7 +257,6 @@ def mergeinfo_and_skipped_paths(sbox):
     })
   expected_skip = wc.State(A_COPY_2_path, {
     'B/E'     : Item(),
-    'D/G'       : Item(),
     'D/H/psi'   : Item(),
     })
   svntest.actions.run_and_verify_merge(A_COPY_2_path, '4', '8',

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/merge_reintegrate_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/merge_reintegrate_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/merge_reintegrate_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/merge_reintegrate_tests.py Fri Dec 21 00:23:39 2012
@@ -818,23 +818,13 @@ def reintegrate_on_shallow_wc(sbox):
   # Now revert the reintegrate and make a second change on the
   # branch in r4, but this time change a subtree that corresponds
   # to the missing (shallow) portion of the source.  The reintegrate
-  # should still succeed, albeit skipping some paths.
+  # should still succeed.
   svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir)
   svntest.main.file_write(psi_COPY_path, "more branch work")
   svntest.main.run_svn(None, 'commit', '-m',
                        'Some more work on the A_COPY branch', wc_dir)
-  # Reuse the same expectations as the prior merge, except that
-  # non-inheritable mergeinfo is set on the root of the missing subtree...
-  expected_mergeinfo_output.add({
-      'D' : Item(status=' U')
-      })
-  expected_A_status.tweak('D', status=' M')
-  expected_A_disk.tweak('D', props={SVN_PROP_MERGEINFO : '/A_COPY/D:2-4*'})
-  # ... a depth-restricted item is skipped ...
-  expected_A_skip.add({
-      'D/H' : Item()
-  })
-  # ... and the mergeinfo on the target root includes the latest rev on the branch.
+  # Reuse the same expectations as the prior merge, except for the mergeinfo
+  # on the target root that now includes the latest rev on the branch.
   expected_A_disk.tweak('', props={SVN_PROP_MERGEINFO : '/A_COPY:2-4'})
   svntest.actions.run_and_verify_merge(A_path, None, None,
                                        sbox.repo_url + '/A_COPY', None,

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/merge_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/merge_tests.py Fri Dec 21 00:23:39 2012
@@ -7812,8 +7812,8 @@ def merge_to_sparse_directories(sbox):
   # Merge r4:9 into the immediates WC.
   # The root of the immediates WC should get inheritable r4:9 as should
   # the one file present 'mu'.  The three directory children present, 'B',
-  # 'C', and 'D' are checked out at depth empty; the two of these affected
-  # by the merge, 'B' and 'D', get non-inheritable mergeinfo for r4:9.
+  # 'C', and 'D' are checked out at depth empty; the one of these affected
+  # by the merge, 'D', gets non-inheritable mergeinfo for r4:9.
   # The root and 'D' do should also get the changes
   # that affect them directly (the prop adds from r8 and r9).
   expected_output = wc.State(immediates_dir, {
@@ -7823,14 +7823,14 @@ def merge_to_sparse_directories(sbox):
     })
   expected_mergeinfo_output = wc.State(immediates_dir, {
     ''  : Item(status=' U'),
-    'B' : Item(status=' U'),
     'D' : Item(status=' U'),
     })
   expected_elision_output = wc.State(immediates_dir, {
+    'D' : Item(status=' U'),
     })
   expected_status = wc.State(immediates_dir, {
     ''          : Item(status=' M', wc_rev=9),
-    'B'         : Item(status=' M', wc_rev=9),
+    'B'         : Item(status='  ', wc_rev=9),
     'mu'        : Item(status='M ', wc_rev=9),
     'C'         : Item(status='  ', wc_rev=9),
     'D'         : Item(status=' M', wc_rev=9),
@@ -7838,15 +7838,12 @@ def merge_to_sparse_directories(sbox):
   expected_disk = wc.State('', {
     ''          : Item(props={SVN_PROP_MERGEINFO : '/A:5-9',
                               "prop:name" : "propval"}),
-    'B'         : Item(props={SVN_PROP_MERGEINFO : '/A/B:5-9*'}),
+    'B'         : Item(),
     'mu'        : Item("New content"),
     'C'         : Item(),
-    'D'         : Item(props={SVN_PROP_MERGEINFO : '/A/D:5-9*',
-                              "prop:name" : "propval"}),
+    'D'         : Item(props={"prop:name" : "propval"}),
     })
   expected_skip = svntest.wc.State(immediates_dir, {
-    'D/H'               : Item(),
-    'B/E'               : Item(),
     })
   svntest.actions.run_and_verify_merge(immediates_dir, '4', '9',
                                        sbox.repo_url + '/A', None,
@@ -7900,7 +7897,6 @@ def merge_to_sparse_directories(sbox):
     })
   expected_skip = svntest.wc.State(files_dir, {
     'D'               : Item(),
-    'B'               : Item(),
     })
   svntest.actions.run_and_verify_merge(files_dir, '4', '9',
                                        sbox.repo_url + '/A', None,
@@ -7944,7 +7940,6 @@ def merge_to_sparse_directories(sbox):
   expected_skip = svntest.wc.State(empty_dir, {
     'mu'               : Item(),
     'D'               : Item(),
-    'B'               : Item(),
     })
   svntest.actions.run_and_verify_merge(empty_dir, '4', '9',
                                        sbox.repo_url + '/A', None,

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/merge_tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/merge_tree_conflict_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/merge_tree_conflict_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/merge_tree_conflict_tests.py Fri Dec 21 00:23:39 2012
@@ -1332,12 +1332,8 @@ def tree_conflicts_merge_edit_onto_missi
   expected_skip = svntest.wc.State('', {
     'F/alpha'           : Item(),
     # BH: After fixing several issues in the obstruction handling
-    #     I get the following Skip notifications. Please review!
+    #     I get the following Skip notification. Please review!
     'D/D1'              : Item(),
-    'DD/D1'             : Item(),
-    'DF/D1'             : Item(),
-    'DDD/D1'            : Item(),
-    'DDF/D1'            : Item(),
     })
 
 
@@ -1414,13 +1410,6 @@ def tree_conflicts_merge_del_onto_missin
   expected_skip = svntest.wc.State('', {
     'F/alpha'           : Item(),
     'D/D1'              : Item(),
-    # BH: After fixing several issues in the obstruction handling
-    #     I get the following Skip notifications. Please review!
-    'D/D1'              : Item(),
-    'DD/D1'             : Item(),
-    'DF/D1'             : Item(),
-    'DDD/D1'            : Item(),
-    'DDF/D1'            : Item(),
     })
 
   svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox,

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/patch_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/patch_tests.py Fri Dec 21 00:23:39 2012
@@ -4202,6 +4202,7 @@ def patch_git_with_index_line(sbox):
                                        1) # dry-run
 
 @XFail()
+@Issue(4273)
 def patch_change_symlink_target(sbox):
   "patch changes symlink target"
 

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/revert_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/revert_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/revert_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/revert_tests.py Fri Dec 21 00:23:39 2012
@@ -1617,6 +1617,52 @@ def revert_nonexistent(sbox):
   svntest.actions.run_and_verify_svn(None, 'Skipped.*nonexistent', [],
                                      'revert', '-R', sbox.ospath('nonexistent'))
 
+@Issue(4168)
+def revert_obstructing_wc(sbox):
+  "revert with an obstructing working copy"
+  
+  sbox.build(create_wc=False, read_only=True)
+  wc_dir = sbox.wc_dir
+  
+  expected_output = svntest.wc.State(wc_dir, {})
+  expected_disk = svntest.wc.State(wc_dir, {})  
+  
+  # Checkout wc as depth empty
+  svntest.actions.run_and_verify_checkout(sbox.repo_url, wc_dir,
+                                          expected_output, expected_disk,
+                                          None, None, None, None,
+                                          '--depth', 'empty')
+
+  # And create an obstructing working copy as A
+  svntest.actions.run_and_verify_checkout(sbox.repo_url, wc_dir + '/A',
+                                          expected_output, expected_disk,
+                                          None, None, None, None,
+                                          '--depth', 'empty')
+
+  # Now try to fetch the entire wc, which will find an obstruction
+  expected_output = svntest.wc.State(wc_dir, {
+    'A'     : Item(verb='Skipped'),
+    'iota'  : Item(status='A '),
+  })
+  expected_status = svntest.wc.State(wc_dir, {
+    ''      : Item(status='  ', wc_rev='1'),
+    'iota'  : Item(status='  ', wc_rev='1'),
+    # A is not versioned but exists
+  })
+
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output, None, expected_status,
+                                        None, None, None,
+                                        None, None, None,
+                                        wc_dir, '--set-depth', 'infinity')
+
+  # Revert should do nothing (no local changes), and report the obstruction
+  # (reporting the obstruction is nice for debuging, but not really required
+  #  in this specific case, as the node was not modified)
+  svntest.actions.run_and_verify_svn(None, "Skipped '.*A' -- .*obstruct.*", [],
+                                     'revert', '-R', wc_dir)
+
+
 ########################################################################
 # Run the tests
 
@@ -1656,6 +1702,7 @@ test_list = [ None,
               revert_no_text_change_conflict_recursive,
               revert_with_unversioned_targets,
               revert_nonexistent,
+              revert_obstructing_wc
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/svnrdump_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/svnrdump_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/svnrdump_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/svnrdump_tests.py Fri Dec 21 00:23:39 2012
@@ -94,11 +94,13 @@ def compare_repos_dumps(svnrdump_sbox, s
 
 def run_dump_test(sbox, dumpfile_name, expected_dumpfile_name = None,
                   subdir = None, bypass_prop_validation = False,
-                  ignore_base_checksums = False):
+                  ignore_base_checksums = False, extra_options = []):
+
   """Load a dumpfile using 'svnadmin load', dump it with 'svnrdump
   dump' and check that the same dumpfile is produced or that
   expected_dumpfile_name is produced if provided. Additionally, the
-  subdir argument appends itself to the URL"""
+  subdir argument appends itself to the URL.  EXTRA_OPTIONS is an
+  array of optional additional options to pass to 'svnrdump dump'."""
 
   # Create an empty sandbox repository
   build_repos(sbox)
@@ -121,10 +123,10 @@ def run_dump_test(sbox, dumpfile_name, e
     repo_url = repo_url + subdir
 
   # Create a dump file using svnrdump
+  opts = extra_options + ['-q', 'dump', repo_url]
   svnrdump_dumpfile = \
       svntest.actions.run_and_verify_svnrdump(None, svntest.verify.AnyOutput,
-                                              [], 0, '-q', 'dump',
-                                              repo_url)
+                                              [], 0, *opts)
 
   if expected_dumpfile_name:
     svnadmin_dumpfile = open(os.path.join(svnrdump_tests_dir,
@@ -335,7 +337,7 @@ def copy_revprops_load(sbox):
 def only_trunk_dump(sbox):
   "dump: subdirectory"
   run_dump_test(sbox, "trunk-only.dump", subdir="/trunk",
-                expected_dumpfile_name="trunk-only.expected.dump",)
+                expected_dumpfile_name="trunk-only.expected.dump")
 
 def only_trunk_A_with_changes_dump(sbox):
   "dump: subdirectory with changes on root"
@@ -356,7 +358,6 @@ def copy_bad_line_endings_dump(sbox):
                 expected_dumpfile_name="copy-bad-line-endings.expected.dump",
                 bypass_prop_validation=True)
 
-@XFail()
 @Issue(4263)
 def copy_bad_line_endings_load(sbox):
   "load: inconsistent line endings in svn:* props"
@@ -738,7 +739,34 @@ def svnrdump_load_partial_incremental_du
                                           svntest.verify.AnyOutput,
                                           [], 0, 'load', sbox.repo_url)
 
-  ########################################################################
+
+#----------------------------------------------------------------------
+@Issue(4101)
+def range_dump(sbox):
+  "dump: using -rX:Y"
+  run_dump_test(sbox, "trunk-only.dump",
+                expected_dumpfile_name="root-range.expected.dump",
+                extra_options=['-r2:HEAD'])
+
+@Issue(4101)
+def only_trunk_range_dump(sbox):
+  "dump: subdirectory using -rX:Y"
+  run_dump_test(sbox, "trunk-only.dump", subdir="/trunk",
+                expected_dumpfile_name="trunk-only-range.expected.dump",
+                extra_options=['-r1:HEAD'])
+
+@Issue(4101)
+def only_trunk_A_range_dump(sbox):
+  "dump: deeper subdirectory using -rX:Y"
+  run_dump_test(sbox, "trunk-only.dump", subdir="/trunk/A",
+                expected_dumpfile_name="trunk-A-range.expected.dump",
+                extra_options=['-r2:HEAD'])
+
+
+#----------------------------------------------------------------------
+
+
+########################################################################
 # Run the tests
 
 
@@ -789,6 +817,9 @@ test_list = [ None,
               reflect_dropped_renumbered_revs,
               dont_drop_valid_mergeinfo_during_incremental_svnrdump_loads,
               svnrdump_load_partial_incremental_dump,
+              range_dump,
+              only_trunk_range_dump,
+              only_trunk_A_range_dump,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/svntest/main.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/svntest/main.py Fri Dec 21 00:23:39 2012
@@ -1234,6 +1234,17 @@ def server_enforces_date_syntax():
 def server_has_atomic_revprop():
   return options.server_minor_version >= 7
 
+def is_plaintext_password_storage_disabled():
+  try:
+    predicate = re.compile("^WARNING: Plaintext password storage is enabled!")
+    code, out, err = run_svn(False, "--version")
+    for line in out:
+      if predicate.match(line):
+        return False
+  except:
+    return False
+  return True
+
 ######################################################################
 
 

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/update_tests.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/update_tests.py Fri Dec 21 00:23:39 2012
@@ -3966,6 +3966,7 @@ def update_accept_conflicts(sbox):
                                         % (pi_path_backup)],
                                       "system(.*) returned.*", 0,
                                       'update', '--accept=edit',
+                                      '--force-interactive',
                                       pi_path_backup)
 
   # rho: --accept=launch
@@ -3978,6 +3979,7 @@ def update_accept_conflicts(sbox):
                                       '  Text conflicts: 1\n'],
                                      [],
                                      'update', '--accept=launch',
+                                     '--force-interactive',
                                      rho_path_backup)
 
   # Set the expected disk contents for the test
@@ -4108,7 +4110,8 @@ interactive-conflicts = true
   svntest.actions.run_and_verify_update(wc_dir, None, None, None,
                                         "Can't read stdin: End of file found",
                                         None, None, None, None, 1,
-                                        wc_dir, '--config-dir', config_dir)
+                                        wc_dir, '--force-interactive',
+                                        '--config-dir', config_dir)
 
   # Now update -r1 again.  Hopefully we don't get a checksum error!
   expected_output = svntest.wc.State(wc_dir, {

Modified: subversion/branches/ev2-export/subversion/tests/libsvn_subr/error-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/libsvn_subr/error-test.c?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/libsvn_subr/error-test.c (original)
+++ subversion/branches/ev2-export/subversion/tests/libsvn_subr/error-test.c Fri Dec 21 00:23:39 2012
@@ -125,8 +125,9 @@ test_error_purge_tracing(apr_pool_t *poo
     svn_error_malfunction_handler_t orig_handler;
 
     /* For this test, use a random error status. */
-    err = svn_error_create(SVN_ERR_BAD_UUID, NULL, SVN_ERR__TRACED);
+    err = svn_error_create(SVN_ERR_BAD_UUID, NULL, "");
     err = svn_error_trace(err);
+    err->child->message = err->message;
 
     /* Register a malfunction handler that doesn't call abort() to
        check that a new error chain with an assertion error is

Modified: subversion/branches/ev2-export/subversion/tests/libsvn_subr/mergeinfo-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/libsvn_subr/mergeinfo-test.c?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/libsvn_subr/mergeinfo-test.c (original)
+++ subversion/branches/ev2-export/subversion/tests/libsvn_subr/mergeinfo-test.c Fri Dec 21 00:23:39 2012
@@ -1702,7 +1702,7 @@ struct svn_test_descriptor_t test_funcs[
                    "turning rangelist back into a string"),
     SVN_TEST_PASS2(test_mergeinfo_to_string,
                    "turning mergeinfo back into a string"),
-    SVN_TEST_XFAIL2(test_rangelist_merge,
+    SVN_TEST_PASS2(test_rangelist_merge,
                    "merge of rangelists"),
     SVN_TEST_PASS2(test_rangelist_diff,
                    "diff of rangelists"),

Modified: subversion/branches/ev2-export/subversion/tests/libsvn_wc/conflict-data-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/libsvn_wc/conflict-data-test.c?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/libsvn_wc/conflict-data-test.c (original)
+++ subversion/branches/ev2-export/subversion/tests/libsvn_wc/conflict-data-test.c Fri Dec 21 00:23:39 2012
@@ -202,8 +202,8 @@ test_read_write_tree_conflicts(const svn
 
   SVN_ERR(svn_test__sandbox_create(&sbox, "read_write_tree_conflicts", opts, pool));
   parent_abspath = svn_dirent_join(sbox.wc_abspath, "A", pool);
-  SVN_ERR(svn_wc__db_op_add_directory(sbox.wc_ctx->db, parent_abspath, NULL,
-                                      pool));
+  SVN_ERR(svn_wc__db_op_add_directory(sbox.wc_ctx->db, parent_abspath,
+                                      NULL /*props*/, NULL, pool));
   child1_abspath = svn_dirent_join(parent_abspath, "foo", pool);
   child2_abspath = svn_dirent_join(parent_abspath, "bar", pool);
 

Modified: subversion/branches/ev2-export/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/libsvn_wc/op-depth-test.c?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/branches/ev2-export/subversion/tests/libsvn_wc/op-depth-test.c Fri Dec 21 00:23:39 2012
@@ -5325,7 +5325,7 @@ struct svn_test_descriptor_t test_funcs[
                        "mixed_rev_move"),
     SVN_TEST_OPTS_PASS(update_prop_mod_into_moved,
                        "update_prop_mod_into_moved"),
-    SVN_TEST_OPTS_XFAIL(nested_move_update,
+    SVN_TEST_OPTS_PASS(nested_move_update,
                        "nested_move_update"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/ev2-export/subversion/tests/libsvn_wc/utils.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/libsvn_wc/utils.c?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/libsvn_wc/utils.c (original)
+++ subversion/branches/ev2-export/subversion/tests/libsvn_wc/utils.c Fri Dec 21 00:23:39 2012
@@ -174,7 +174,8 @@ sbox_wc_add(svn_test__sandbox_t *b, cons
   parent_abspath = svn_dirent_dirname(path, b->pool);
   SVN_ERR(svn_wc__acquire_write_lock(NULL, b->wc_ctx, parent_abspath, FALSE,
                                      b->pool, b->pool));
-  SVN_ERR(svn_wc_add_from_disk(b->wc_ctx, path, NULL, NULL, b->pool));
+  SVN_ERR(svn_wc_add_from_disk2(b->wc_ctx, path, NULL /*props*/,
+                                NULL, NULL, b->pool));
   SVN_ERR(svn_wc__release_write_lock(b->wc_ctx, parent_abspath, b->pool));
   return SVN_NO_ERROR;
 }
@@ -294,8 +295,12 @@ sbox_wc_commit(svn_test__sandbox_t *b, c
 
   APR_ARRAY_PUSH(targets, const char *) = sbox_wc_path(b, path);
   SVN_ERR(svn_client_create_context2(&ctx, NULL, b->pool));
-  return svn_client_commit5(targets, svn_depth_infinity,
-                            FALSE, FALSE, TRUE, /* keep locks/cl's/use_ops*/
+  return svn_client_commit6(targets, svn_depth_infinity,
+                            FALSE /* keep_locks */,
+                            FALSE /* keep_changelist */,
+                            TRUE  /* commit_as_operations */,
+                            TRUE  /* include_file_externals */,
+                            FALSE /* include_dir_externals */,
                             NULL, NULL, NULL, NULL, ctx, b->pool);
 }
 

Modified: subversion/branches/ev2-export/tools/dist/release.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/tools/dist/release.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/tools/dist/release.py (original)
+++ subversion/branches/ev2-export/tools/dist/release.py Fri Dec 21 00:23:39 2012
@@ -381,7 +381,7 @@ def compare_changes(repos, branch, revis
       # Treat this as a warning since we are now putting entries for future
       # minor releases in CHANGES on trunk.
       logging.warning('CHANGES has unmerged revisions: %s' %
-		      stdout.replace("\n", " "))
+                      stdout.replace("\n", " "))
 
 def roll_tarballs(args):
     'Create the release artifacts.'
@@ -627,7 +627,13 @@ def write_news(args):
 
 def get_sha1info(args, replace=False):
     'Return a list of sha1 info for the release'
-    sha1s = glob.glob(os.path.join(get_deploydir(args.base_dir), '*.sha1'))
+
+    if args.target:
+        target = args.target
+    else:
+        target = get_deploydir(args.base_dir)
+
+    sha1s = glob.glob(os.path.join(target, '*.sha1'))
 
     class info(object):
         pass
@@ -651,10 +657,11 @@ def get_sha1info(args, replace=False):
 def write_announcement(args):
     'Write the release announcement.'
     sha1info = get_sha1info(args)
+    siginfo = "\n".join(get_siginfo(args, True)) + "\n"
 
     data = { 'version'              : str(args.version),
              'sha1info'             : sha1info,
-             'siginfo'              : open('getsigs-output', 'r').read(),
+             'siginfo'              : siginfo,
              'major-minor'          : '%d.%d' % (args.version.major,
                                                  args.version.minor),
              'major-minor-patch'    : args.version.base,
@@ -689,8 +696,8 @@ def write_downloads(args):
 key_start = '-----BEGIN PGP SIGNATURE-----'
 fp_pattern = re.compile(r'^pub\s+(\w+\/\w+)[^\n]*\n\s+Key\sfingerprint\s=((\s+[0-9A-F]{4}){10})\nuid\s+([^<\(]+)\s')
 
-def check_sigs(args):
-    'Check the signatures for the release.'
+def get_siginfo(args, quiet=False):
+    'Returns a list of signatures for the release.'
 
     try:
         import gnupg
@@ -704,13 +711,16 @@ def check_sigs(args):
         target = get_deploydir(args.base_dir)
 
     good_sigs = {}
+    fingerprints = {}
+    output = []
 
     glob_pattern = os.path.join(target, 'subversion*-%s*.asc' % args.version)
     for filename in glob.glob(glob_pattern):
         text = open(filename).read()
         keys = text.split(key_start)
 
-        logging.info("Checking %d sig(s) in %s" % (len(keys[1:]), filename))
+        if not quiet:
+            logging.info("Checking %d sig(s) in %s" % (len(keys[1:]), filename))
         for key in keys[1:]:
             fd, fn = tempfile.mkstemp()
             os.write(fd, key_start + key)
@@ -740,18 +750,30 @@ def check_sigs(args):
                                                      if l[0:7] != 'Warning' ])
 
         fp = fp_pattern.match(gpg_output).groups()
-        print("   %s [%s] with fingerprint:" % (fp[3], fp[0]))
-        print("   %s" % fp[1])
+        fingerprints["%s [%s] %s" % (fp[3], fp[0], fp[1])] = fp
 
+    for entry in sorted(fingerprints.keys()):
+        fp = fingerprints[entry]
+        output.append("   %s [%s] with fingerprint:" % (fp[3], fp[0]))
+        output.append("   %s" % fp[1])
+
+    return output
+
+def check_sigs(args):
+    'Check the signatures for the release.'
+
+    output = get_siginfo(args)
+    for line in output:
+        print(line)
 
 def get_keys(args):
     'Import the LDAP-based KEYS file to gpg'
     # We use a tempfile because urlopen() objects don't have a .fileno()
     with tempfile.SpooledTemporaryFile() as fd:
-	fd.write(urllib2.urlopen(KEYS).read())
-	fd.flush()
+        fd.write(urllib2.urlopen(KEYS).read())
+        fd.flush()
         fd.seek(0)
-	subprocess.check_call(['gpg', '--import'], stdin=fd)
+        subprocess.check_call(['gpg', '--import'], stdin=fd)
 
 #----------------------------------------------------------------------
 # Main entry point for argument parsing and handling
@@ -865,6 +887,9 @@ def main():
                     help='''Output to stdout template text for the emailed
                             release announcement.''')
     subparser.set_defaults(func=write_announcement)
+    subparser.add_argument('--target',
+                    help='''The full path to the directory containing
+                            release artifacts.''')
     subparser.add_argument('version', type=Version,
                     help='''The release label, such as '1.7.0-alpha1'.''')
 

Modified: subversion/branches/ev2-export/tools/server-side/fsfs-reorg.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/tools/server-side/fsfs-reorg.c?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/tools/server-side/fsfs-reorg.c (original)
+++ subversion/branches/ev2-export/tools/server-side/fsfs-reorg.c Fri Dec 21 00:23:39 2012
@@ -1,4 +1,5 @@
-/* diff.c -- test driver for text diffs
+/* fsfs-reorg.c -- prototypic tool to reorganize packed FSFS repositories
+ *                 to reduce seeks
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -45,7 +46,7 @@
 #define _(x) x
 #endif
 
-#define ERROR_TAG "diff: "
+#define ERROR_TAG "fsfs-reporg: "
 
 /* forward declarations */
 typedef struct noderev_t noderev_t;

Modified: subversion/branches/ev2-export/tools/server-side/fsfs-stats.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/tools/server-side/fsfs-stats.c?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/tools/server-side/fsfs-stats.c (original)
+++ subversion/branches/ev2-export/tools/server-side/fsfs-stats.c Fri Dec 21 00:23:39 2012
@@ -1,4 +1,4 @@
-/* diff.c -- test driver for text diffs
+/* fsfs-stats.c -- gather size statistics on FSFS repositories
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -22,7 +22,6 @@
 
 
 #include <assert.h>
-#include <sys/stat.h>
 
 #include <apr.h>
 #include <apr_general.h>
@@ -46,20 +45,29 @@
 #define _(x) x
 #endif
 
-#define ERROR_TAG "diff: "
+#define ERROR_TAG "fsfs-stats: "
 
+/* We group representations into 2x2 different kinds plus one default:
+ * [dir / file] x [text / prop]. The assignment is done by the first node
+ * that references the respective representation.
+ */
 typedef enum rep_kind_t
 {
+  /* The representation is _directly_ unused, i.e. not referenced by any
+   * noderev. However, some other representation may use it as delta base.
+   * null value. Should not occur in real-word repositories. */
   unused_rep,
 
+  /* a properties on directory rep  */
   dir_property_rep,
 
+  /* a properties on file rep  */
   file_property_rep,
 
-  /* a directory rep (including PLAIN / DELTA header) */
+  /* a directory rep  */
   dir_rep,
 
-  /* a file rep (including PLAIN / DELTA header) */
+  /* a file rep  */
   file_rep
 } rep_kind_t;
 
@@ -73,6 +81,7 @@ typedef struct representation_t
   /* item length in bytes */
   apr_size_t size;
 
+  /* item length after de-deltification */
   apr_size_t expanded_size;
 
   /* deltification base, or NULL if there is none */
@@ -80,13 +89,15 @@ typedef struct representation_t
 
   /* revision that contains this representation
    * (may be referenced by other revisions, though) */
-  
   svn_revnum_t revision;
+
+  /* number of nodes that reference this representation */
   apr_uint32_t ref_count;
 
   /* length of the PLAIN / DELTA line in the source file in bytes */
   apr_uint16_t header_size;
 
+  /* classification of the representation. values of rep_kind_t */
   char kind;
   
   /* the source content has a PLAIN header, so we may simply copy the
@@ -118,9 +129,16 @@ typedef struct revision_info_t
    * for non-packed revs) */
   apr_size_t end;
 
+  /* number of directory noderevs in this revision */
   apr_size_t dir_noderev_count;
+
+  /* number of file noderevs in this revision */
   apr_size_t file_noderev_count;
+
+  /* total size of directory noderevs (i.e. the structs - not the rep) */
   apr_size_t dir_noderev_size;
+
+  /* total size of file noderevs (i.e. the structs - not the rep) */
   apr_size_t file_noderev_size;
   
   /* all representation_t of this revision (in no particular order),
@@ -315,7 +333,7 @@ get_window_cache_index(fs_fs_t *fs,
   return (revision + offset * 0xd1f3da69) % fs->window_cache->entry_count;
 }
 
-/* Return the cached txdelta window stored in REPRESENTAION within FS.
+/* Return the cached txdelta window stored in REPRESENTATION within FS.
  * If that has not been found in cache, return NULL.
  */
 static svn_stringbuf_t *
@@ -334,7 +352,7 @@ get_cached_window(fs_fs_t *fs,
     : NULL;
 }
 
-/* Cache the undeltified txdelta WINDOW for REPRESENTAION within FS.
+/* Cache the undeltified txdelta WINDOW for REPRESENTATION within FS.
  */
 static void
 set_cached_window(fs_fs_t *fs,
@@ -365,8 +383,9 @@ set_cached_window(fs_fs_t *fs,
   entry->revision = revision;
 }
 
-/* Given REV in FS, set *REV_OFFSET to REV's offset in the packed file.
-   Use POOL for temporary allocations. */
+/* Given rev pack PATH in FS, read the manifest file and return the offsets
+ * in *MANIFEST. Use POOL for allocations.
+ */
 static svn_error_t *
 read_manifest(apr_array_header_t **manifest,
               fs_fs_t *fs,
@@ -409,6 +428,10 @@ read_manifest(apr_array_header_t **manif
   return svn_stream_close(manifest_stream);
 }
 
+/* Read header information for the revision stored in FILE_CONTENT (one
+ * whole revision).  Return the offsets within FILE_CONTENT for the
+ * *ROOT_NODEREV, the list of *CHANGES and its len in *CHANGES_LEN.
+ * Use POOL for temporary allocations. */
 static svn_error_t *
 read_revision_header(apr_size_t *changes,
                      apr_size_t *changes_len,
@@ -447,8 +470,10 @@ read_revision_header(apr_size_t *changes
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                             _("Final line in revision file missing space"));
 
+  /* terminate the header line */
   *space = 0;
-  
+
+  /* extract information */
   SVN_ERR(svn_cstring_strtoui64(&val, line+1, 0, APR_SIZE_MAX, 10));
   *root_noderev = (apr_size_t)val;
   SVN_ERR(svn_cstring_strtoui64(&val, space+1, 0, APR_SIZE_MAX, 10));
@@ -458,6 +483,10 @@ read_revision_header(apr_size_t *changes
   return SVN_NO_ERROR;
 }
 
+/* Read the FSFS format number and sharding size from the format file at
+ * PATH and return it in *PFORMAT and *MAX_FILES_PER_DIR respectively.
+ * Use POOL for temporary allocations.
+ */
 static svn_error_t *
 read_format(int *pformat, int *max_files_per_dir,
             const char *path, apr_pool_t *pool)
@@ -467,6 +496,7 @@ read_format(int *pformat, int *max_files
   char buf[80];
   apr_size_t len;
 
+  /* open format file and read the first line */
   err = svn_io_file_open(&file, path, APR_READ | APR_BUFFERED,
                          APR_OS_DEFAULT, pool);
   if (err && APR_STATUS_IS_ENOENT(err->apr_err))
@@ -541,21 +571,27 @@ read_format(int *pformat, int *max_files
   return svn_io_file_close(file, pool);
 }
 
+/* Read the content of the file at PATH and return it in *RESULT.
+ * Use POOL for temporary allocations.
+ */
 static svn_error_t *
 read_number(svn_revnum_t *result, const char *path, apr_pool_t *pool)
 {
   svn_stringbuf_t *content;
-  apr_int64_t number;
+  apr_uint64_t number;
   
   SVN_ERR(svn_stringbuf_from_file2(&content, path, pool));
 
   content->data[content->len-1] = 0;
-  SVN_ERR(svn_cstring_atoi64(&number, content->data));
+  SVN_ERR(svn_cstring_strtoui64(&number, content->data, 0, LONG_MAX, 10));
   *result = (svn_revnum_t)number;
 
   return SVN_NO_ERROR;
 }
 
+/* Create *FS for the repository at PATH and read the format and size info.
+ * Use POOL for temporary allocations.
+ */
 static svn_error_t *
 fs_open(fs_fs_t **fs, const char *path, apr_pool_t *pool)
 {
@@ -570,7 +606,8 @@ fs_open(fs_fs_t **fs, const char *path, 
                       pool));
   if (((*fs)->format != 4) && ((*fs)->format != 6))
     return svn_error_create(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL, NULL);
-    
+
+  /* read size (HEAD) info */
   SVN_ERR(read_number(&(*fs)->min_unpacked_rev,
                       svn_dirent_join(path, "db/min-unpacked-rev", pool),
                       pool));
@@ -579,12 +616,18 @@ fs_open(fs_fs_t **fs, const char *path, 
                      pool);
 }
 
+/* Utility function that returns true if STRING->DATA matches KEY.
+ */
 static svn_boolean_t
 key_matches(svn_string_t *string, const char *key)
 {
   return strcmp(string->data, key) == 0;
 }
 
+/* Comparator used for binary search comparing the absolute file offset
+ * of a representation to some other offset. DATA is a *representation_t,
+ * KEY is a pointer to an apr_size_t.
+ */
 static int
 compare_representation_offsets(const void *data, const void *key)
 {
@@ -597,6 +640,15 @@ compare_representation_offsets(const voi
   return diff > 0 ? 1 : 0;
 }
 
+/* Find the revision_info_t object to the given REVISION in FS and return
+ * it in *REVISION_INFO. For performance reasons, we skip the lookup if
+ * the info is already provided.
+ *
+ * In that revision, look for the representation_t object for offset OFFSET.
+ * If it already exists, set *IDX to its index in *REVISION_INFO's
+ * representations list and return the representation object. Otherwise,
+ * set the index to where it must be inserted and return NULL.
+ */
 static representation_t *
 find_representation(int *idx,
                     fs_fs_t *fs,
@@ -606,7 +658,8 @@ find_representation(int *idx,
 {
   revision_info_t *info;
   *idx = -1;
-  
+
+  /* first let's find the revision */
   info = revision_info ? *revision_info : NULL;
   if (info == NULL || info->revision != revision)
     {
@@ -617,23 +670,36 @@ find_representation(int *idx,
         *revision_info = info;
     }
 
+  /* not found -> no result */
   if (info == NULL)
     return NULL;
+  
+  assert(revision == info->revision);
 
+  /* look for the representation */
   *idx = svn_sort__bsearch_lower_bound(&offset,
                                        info->representations,
                                        compare_representation_offsets);
   if (*idx < info->representations->nelts)
     {
+      /* return the representation, if this is the one we were looking for */
       representation_t *result
         = APR_ARRAY_IDX(info->representations, *idx, representation_t *);
       if (result->offset == offset)
         return result;
     }
 
+  /* not parsed, yet */
   return NULL;
 }
 
+/* Read the representation header in FILE_CONTENT at OFFSET.  Return its
+ * size in *HEADER_SIZE, set *IS_PLAIN if no deltification was used and
+ * return the deltification base representation in *REPRESENTATION.  If
+ * there is none, set it to NULL.  Use FS to it look up.
+ *
+ * Use POOL for allocations and SCRATCH_POOL for temporaries.
+ */
 static svn_error_t *
 read_rep_base(representation_t **representation,
               apr_size_t *header_size,
@@ -649,10 +715,12 @@ read_rep_base(representation_t **represe
   svn_revnum_t revision;
   apr_uint64_t temp;
 
+  /* identify representation header (1 line) */
   const char *buffer = file_content->data + offset;
   const char *line_end = strchr(buffer, '\n');
   *header_size = line_end - buffer + 1;
 
+  /* check for PLAIN rep */
   if (strncmp(buffer, "PLAIN\n", *header_size) == 0)
     {
       *is_plain = TRUE;
@@ -660,6 +728,7 @@ read_rep_base(representation_t **represe
       return SVN_NO_ERROR;
     }
 
+  /* check for DELTA against empty rep */
   *is_plain = FALSE;
   if (strncmp(buffer, "DELTA\n", *header_size) == 0)
     {
@@ -671,7 +740,7 @@ read_rep_base(representation_t **represe
   str = apr_pstrndup(scratch_pool, buffer, line_end - buffer);
   last_str = str;
 
-  /* We hopefully have a DELTA vs. a non-empty base revision. */
+  /* parse it. */
   str = svn_cstring_tokenize(" ", &last_str);
   str = svn_cstring_tokenize(" ", &last_str);
   SVN_ERR(svn_revnum_parse(&revision, str, NULL));
@@ -679,10 +748,18 @@ read_rep_base(representation_t **represe
   str = svn_cstring_tokenize(" ", &last_str);
   SVN_ERR(svn_cstring_strtoui64(&temp, str, 0, APR_SIZE_MAX, 10));
 
+  /* it should refer to a rep in an earlier revision.  Look it up */
   *representation = find_representation(&idx, fs, NULL, revision, (apr_size_t)temp);
   return SVN_NO_ERROR;
 }
 
+/* Parse the representation reference (text: or props:) in VALUE, look
+ * it up in FS and return it in *REPRESENTATION.  To be able to parse the
+ * base rep, we pass the FILE_CONTENT as well.
+ * 
+ * If necessary, allocate the result in POOL; use SCRATCH_POOL for temp.
+ * allocations.
+ */
 static svn_error_t *
 parse_representation(representation_t **representation,
                      fs_fs_t *fs,
@@ -700,15 +777,20 @@ parse_representation(representation_t **
   apr_uint64_t expanded_size;
   int idx;
 
+  /* read location (revision, offset) and size */
   char *c = (char *)value->data;
   SVN_ERR(svn_revnum_parse(&revision, svn_cstring_tokenize(" ", &c), NULL));
   SVN_ERR(svn_cstring_strtoui64(&offset, svn_cstring_tokenize(" ", &c), 0, APR_SIZE_MAX, 10));
   SVN_ERR(svn_cstring_strtoui64(&size, svn_cstring_tokenize(" ", &c), 0, APR_SIZE_MAX, 10));
   SVN_ERR(svn_cstring_strtoui64(&expanded_size, svn_cstring_tokenize(" ", &c), 0, APR_SIZE_MAX, 10));
 
+  /* look it up */
   result = find_representation(&idx, fs, &revision_info, revision, (apr_size_t)offset);
   if (!result)
     {
+      /* not parsed, yet (probably a rep in the same revision).
+       * Create a new rep object and determine its base rep as well.
+       */
       apr_size_t header_size;
       svn_boolean_t is_plain;
       
@@ -732,8 +814,10 @@ parse_representation(representation_t **
   return SVN_NO_ERROR;
 }
 
-/* Get the file content of revision REVISION in FS and return it in *DATA.
- * Use SCRATCH_POOL for temporary allocations.
+/* Get the unprocessed (i.e. still deltified) content of REPRESENTATION in
+ * FS and return it in *CONTENT.  If no NULL, FILE_CONTENT must contain
+ * the contents of the revision that also contains the representation.
+ * Use POOL for allocations.
  */
 static svn_error_t *
 get_rep_content(svn_stringbuf_t **content,
@@ -773,8 +857,12 @@ get_rep_content(svn_stringbuf_t **conten
 }
 
 
-/* Skip forwards to THIS_CHUNK in REP_STATE and then read the next delta
-   window into *NWIN. */
+/* Read the delta window contents of all windows in REPRESENTATION in FS.
+ * If no NULL, FILE_CONTENT must contain the contents of the revision that
+ * also contains the representation.
+ * Return the data as svn_txdelta_window_t* instances in *WINDOWS.
+ * Use POOL for allocations.
+ */
 static svn_error_t *
 read_windows(apr_array_header_t **windows,
              fs_fs_t *fs,
@@ -789,13 +877,16 @@ read_windows(apr_array_header_t **window
 
   *windows = apr_array_make(pool, 0, sizeof(svn_txdelta_window_t *));
 
+  /* get the whole revision content */
   SVN_ERR(get_rep_content(&content, fs, representation, file_content, pool));
 
+  /* create a read stream and position it directly after the rep header */
   content->data += 3;
   content->len -= 3;
   stream = svn_stream_from_stringbuf(content, pool);
   SVN_ERR(svn_stream_read(stream, &version, &len));
 
+  /* read the windows from that stream */
   while (TRUE)
     {
       svn_txdelta_window_t *window;
@@ -816,9 +907,12 @@ read_windows(apr_array_header_t **window
   return SVN_NO_ERROR;
 }
 
-/* Get the undeltified window that is a result of combining all deltas
-   from the current desired representation identified in *RB with its
-   base representation.  Store the window in *RESULT. */
+/* Get the undeltified representation that is a result of combining all
+ * deltas from the current desired REPRESENTATION in FS with its base
+ * representation.  If no NULL, FILE_CONTENT must contain the contents of
+ * the revision that also contains the representation.  Store the result
+ * in *CONTENT.  Use POOL for allocations.
+ */
 static svn_error_t *
 get_combined_window(svn_stringbuf_t **content,
                     fs_fs_t *fs,
@@ -833,20 +927,28 @@ get_combined_window(svn_stringbuf_t **co
   apr_pool_t *sub_pool = svn_pool_create(pool);
   apr_pool_t *iter_pool = svn_pool_create(pool);
 
+  /* special case: no un-deltification necessary */
   if (representation->is_plain)
     return get_rep_content(content, fs, representation, file_content, pool);
 
+  /* special case: data already in cache */
   *content = get_cached_window(fs, representation, pool);
   if (*content)
     return SVN_NO_ERROR;
   
+  /* read the delta windows for this representation */
+  sub_pool = svn_pool_create(pool);
+  iter_pool = svn_pool_create(pool);
   SVN_ERR(read_windows(&windows, fs, representation, file_content, sub_pool));
+
+  /* fetch the / create a base content */
   if (representation->delta_base && representation->delta_base->revision)
     SVN_ERR(get_combined_window(&base_content, fs,
                                 representation->delta_base, NULL, sub_pool));
   else
     base_content = svn_stringbuf_create_empty(sub_pool);
 
+  /* apply deltas */
   result = svn_stringbuf_create_empty(pool);
   source = base_content->data;
   
@@ -869,12 +971,15 @@ get_combined_window(svn_stringbuf_t **co
 
   svn_pool_destroy(iter_pool);
   svn_pool_destroy(sub_pool);
-  
+
+  /* cache result and return it */
   set_cached_window(fs, representation, result);
   *content = result;
+  
   return SVN_NO_ERROR;
 }
 
+/* forward declaration */
 static svn_error_t *
 read_noderev(fs_fs_t *fs,
              svn_stringbuf_t *file_content,
@@ -883,6 +988,12 @@ read_noderev(fs_fs_t *fs,
              apr_pool_t *pool,
              apr_pool_t *scratch_pool);
 
+/* Starting at the directory in REPRESENTATION in FILE_CONTENT, read all
+ * DAG nodes, directories and representations linked in that tree structure.
+ * Store them in FS and REVISION_INFO.  Also, read them only once.
+ *
+ * Use POOL for persistent allocations and SCRATCH_POOL for temporaries.
+ */
 static svn_error_t *
 parse_dir(fs_fs_t *fs,
           svn_stringbuf_t *file_content,
@@ -898,9 +1009,11 @@ parse_dir(fs_fs_t *fs,
   const char *revision_key;
   apr_size_t key_len;
 
+  /* special case: empty dir rep */
   if (representation == NULL)
     return SVN_NO_ERROR;
 
+  /* get the directory as unparsed string */
   iter_pool = svn_pool_create(scratch_pool);
   text_pool = svn_pool_create(scratch_pool);
 
@@ -908,14 +1021,16 @@ parse_dir(fs_fs_t *fs,
                               text_pool));
   current = text->data;
 
+  /* calculate some invariants */
   revision_key = apr_psprintf(text_pool, "r%ld/", representation->revision);
   key_len = strlen(revision_key);
   
-  /* Translate the string dir entries into real entries. */
+  /* Parse and process all directory entries. */
   while (*current != 'E')
     {
       char *next;
 
+      /* skip "K ???\n<name>\nV ???\n" lines*/
       current = strchr(current, '\n');
       if (current)
         current = strchr(current+1, '\n');
@@ -927,11 +1042,14 @@ parse_dir(fs_fs_t *fs,
            _("Corrupt directory representation in rev %ld at offset %ld"),
                                  representation->revision,
                                  (long)representation->offset);
-      
+
+      /* iff this entry refers to a node in the same revision as this dir,
+       * recurse into that node */
       *next = 0;
       current = strstr(current, revision_key);
       if (current)
         {
+          /* recurse */
           apr_uint64_t offset;
 
           SVN_ERR(svn_cstring_strtoui64(&offset, current + key_len, 0,
@@ -949,6 +1067,13 @@ parse_dir(fs_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+/* Starting at the noderev at OFFSET in FILE_CONTENT, read all DAG nodes,
+ * directories and representations linked in that tree structure.  Store
+ * them in FS and REVISION_INFO.  Also, read them only once.  Return the
+ * result in *NODEREV.
+ *
+ * Use POOL for persistent allocations and SCRATCH_POOL for temporaries.
+ */
 static svn_error_t *
 read_noderev(fs_fs_t *fs,
              svn_stringbuf_t *file_content,
@@ -964,9 +1089,11 @@ read_noderev(fs_fs_t *fs,
   svn_boolean_t is_dir = FALSE;
 
   scratch_pool = svn_pool_create(scratch_pool);
-  
+
+  /* parse the noderev line-by-line until we find an empty line */
   while (1)
     {
+      /* for this line, extract key and value. Ignore invalid values */
       svn_string_t key;
       svn_string_t value;
       char *sep;
@@ -975,6 +1102,8 @@ read_noderev(fs_fs_t *fs,
 
       line = svn_string_ncreate(start, end - start, scratch_pool);
       offset += end - start + 1;
+
+      /* empty line -> end of noderev data */
       if (line->len == 0)
         break;
       
@@ -992,6 +1121,7 @@ read_noderev(fs_fs_t *fs,
       value.data = sep + 2;
       value.len = line->len - (key.len + 2);
 
+      /* translate (key, value) into noderev elements */
       if (key_matches(&key, "type"))
         is_dir = strcmp(value.data, "dir") == 0;
       else if (key_matches(&key, "text"))
@@ -999,6 +1129,8 @@ read_noderev(fs_fs_t *fs,
           SVN_ERR(parse_representation(&text, fs, file_content,
                                        &value, revision_info,
                                        pool, scratch_pool));
+          
+          /* if we are the first to use this rep, mark it as "text rep" */
           if (++text->ref_count == 1)
             text->kind = is_dir ? dir_rep : file_rep;
         }
@@ -1007,15 +1139,20 @@ read_noderev(fs_fs_t *fs,
           SVN_ERR(parse_representation(&props, fs, file_content,
                                        &value, revision_info,
                                        pool, scratch_pool));
+
+          /* if we are the first to use this rep, mark it as "prop rep" */
           if (++props->ref_count == 1)
             props->kind = is_dir ? dir_property_rep : file_property_rep;
         }
     }
 
+  /* if this is a directory and has not been processed, yet, read and
+   * process it recursively */
   if (is_dir && text && text->ref_count == 1)
     SVN_ERR(parse_dir(fs, file_content, text, revision_info,
                       pool, scratch_pool));
 
+  /* update stats */
   if (is_dir)
     {
       revision_info->dir_noderev_size += offset - start_offset;
@@ -1031,6 +1168,9 @@ read_noderev(fs_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+/* Given the unparsed changes list in CHANGES with LEN chars, return the
+ * number of changed paths encoded in it.
+ */
 static apr_size_t
 get_change_count(const char *changes,
                  apr_size_t len)
@@ -1038,19 +1178,27 @@ get_change_count(const char *changes,
   apr_size_t lines = 0;
   const char *end = changes + len;
 
+  /* line count */
   for (; changes < end; ++changes)
     if (*changes == '\n')
       ++lines;
 
+  /* two lines per change */
   return lines / 2;
 }
 
-static void print_progress(svn_revnum_t revision)
+/* Simple utility to print a REVISION number and make it appear immediately.
+ */
+static void
+print_progress(svn_revnum_t revision)
 {
   printf("%8ld", revision);
   fflush(stdout);
 }
 
+/* Read the content of the pack file staring at revision BASE and store it
+ * in FS.  Use POOL for allocations.
+ */
 static svn_error_t *
 read_pack_file(fs_fs_t *fs,
                svn_revnum_t base,
@@ -1063,17 +1211,20 @@ read_pack_file(fs_fs_t *fs,
   apr_off_t file_size = 0;
   const char *pack_folder = get_pack_folder(fs, base, local_pool);
 
+  /* parse the manifest file */
   SVN_ERR(read_manifest(&manifest, fs, pack_folder, local_pool));
   if (manifest->nelts != fs->max_files_per_dir)
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, NULL);
 
   SVN_ERR(rev_or_pack_file_size(&file_size, fs, base, pool));
 
+  /* process each revision in the pack file */
   for (i = 0; i < manifest->nelts; ++i)
     {
       apr_size_t root_node_offset;
       svn_stringbuf_t *rev_content;
   
+      /* create the revision info for the current rev */
       revision_info_t *info = apr_pcalloc(pool, sizeof(*info));
       info->representations = apr_array_make(iter_pool, 4, sizeof(representation_t*));
 
@@ -1103,15 +1254,20 @@ read_pack_file(fs_fs_t *fs,
       info->representations = apr_array_copy(pool, info->representations);
       APR_ARRAY_PUSH(fs->revisions, revision_info_t*) = info;
       
+      /* destroy temps */
       svn_pool_clear(iter_pool);
     }
 
+  /* one more pack file processed */
   print_progress(base);
   apr_pool_destroy(local_pool);
 
   return SVN_NO_ERROR;
 }
 
+/* Read the content of the file for REVSION and store its contents in FS.
+ * Use POOL for allocations.
+ */
 static svn_error_t *
 read_revision_file(fs_fs_t *fs,
                    svn_revnum_t revision,
@@ -1123,8 +1279,10 @@ read_revision_file(fs_fs_t *fs,
   revision_info_t *info = apr_pcalloc(pool, sizeof(*info));
   apr_off_t file_size = 0;
 
+  /* read the whole pack file into memory */
   SVN_ERR(rev_or_pack_file_size(&file_size, fs, revision, pool));
 
+  /* create the revision info for the current rev */
   info->representations = apr_array_make(pool, 4, sizeof(representation_t*));
 
   info->revision = revision;
@@ -1139,16 +1297,19 @@ read_revision_file(fs_fs_t *fs,
                                rev_content,
                                local_pool));
 
+  /* put it into our containers */
   APR_ARRAY_PUSH(fs->revisions, revision_info_t*) = info;
 
   info->change_count
     = get_change_count(rev_content->data + info->changes,
                        info->changes_len);
 
+  /* parse the revision content recursively. */
   SVN_ERR(read_noderev(fs, rev_content,
                        root_node_offset, info,
                        pool, local_pool));
 
+  /* show progress every 1000 revs or so */
   if (revision % fs->max_files_per_dir == 0)
     print_progress(revision);
 
@@ -1157,6 +1318,10 @@ read_revision_file(fs_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+/* Read the repository at PATH beginning with revision START_REVISION and
+ * return the result in *FS.  Allocate caches with MEMSIZE bytes total
+ * capacity.  Use POOL for non-cache allocations.
+ */
 static svn_error_t *
 read_revisions(fs_fs_t **fs,
                const char *path,
@@ -1176,6 +1341,7 @@ read_revisions(fs_fs_t **fs,
   
   SVN_ERR(fs_open(fs, path, pool));
 
+  /* create data containers and caches */
   (*fs)->start_revision = start_revision
                         - (start_revision % (*fs)->max_files_per_dir);
   (*fs)->revisions = apr_array_make(pool,
@@ -1187,41 +1353,71 @@ read_revisions(fs_fs_t **fs,
                          (svn_pool_create_allocator(FALSE)),
                           10000, window_cache_size);
 
+  /* read all packed revs */
   for ( revision = start_revision
       ; revision < (*fs)->min_unpacked_rev
       ; revision += (*fs)->max_files_per_dir)
     SVN_ERR(read_pack_file(*fs, revision, pool));
-    
+
+  /* read non-packed revs */
   for ( ; revision <= (*fs)->max_revision; ++revision)
     SVN_ERR(read_revision_file(*fs, revision, pool));
 
   return SVN_NO_ERROR;
 }
 
+/* Compression statistics we collect over a given set of representations.
+ */
 typedef struct rep_pack_stats_t
 {
+  /* number of representations */
   apr_int64_t count;
+
+  /* total size after deltification (i.e. on disk size) */
   apr_int64_t packed_size;
+  
+  /* total size after de-deltification (i.e. plain text size) */
   apr_int64_t expanded_size;
+
+  /* total on-disk header size */
   apr_int64_t overhead_size;
 } rep_pack_stats_t;
 
+/* Statistics we collect over a given set of representations.
+ * We group them into shared and non-shared ("unique") reps.
+ */
 typedef struct representation_stats_t
 {
+  /* stats over all representations */
   rep_pack_stats_t total;
+  
+  /* stats over those representations with ref_count == 1 */
   rep_pack_stats_t uniques;
+
+  /* stats over those representations with ref_count > 1 */
   rep_pack_stats_t shared;
   
+  /* sum of all ref_counts */
   apr_int64_t references;
+
+  /* sum of ref_count * expanded_size,
+   * i.e. total plaintext content if there was no rep sharing */
   apr_int64_t expanded_size;
 } representation_stats_t;
 
+/* Basic statistics we collect over a given set of noderevs.
+ */
 typedef struct node_stats_t
 {
+  /* number of noderev structs */
   apr_int64_t count;
+  
+  /* their total size on disk (structs only) */
   apr_int64_t size;
 } node_stats_t;
 
+/* Accumulate stats of REP in STATS.
+ */
 static void
 add_rep_pack_stats(rep_pack_stats_t *stats,
                    representation_t *rep)
@@ -1230,9 +1426,11 @@ add_rep_pack_stats(rep_pack_stats_t *sta
   
   stats->packed_size += rep->size;
   stats->expanded_size += rep->expanded_size;
-  stats->overhead_size += rep->header_size + 7;
+  stats->overhead_size += rep->header_size + 7 /* ENDREP\n */;
 }
 
+/* Accumulate stats of REP in STATS.
+ */
 static void
 add_rep_stats(representation_stats_t *stats,
               representation_t *rep)
@@ -1247,6 +1445,9 @@ add_rep_stats(representation_stats_t *st
   stats->expanded_size += rep->ref_count * rep->expanded_size;
 }
 
+/* Print statistics for the given group of representations to console.
+ * Use POOL for allocations.
+ */
 static void
 print_rep_stats(representation_stats_t *stats,
                 apr_pool_t *pool)
@@ -1267,12 +1468,16 @@ print_rep_stats(representation_stats_t *
          svn__i64toa_sep(stats->references - stats->total.count, ',', pool));
 }
 
+/* Post-process stats for FS and print them to the console.
+ * Use POOL for allocations.
+ */
 static void
 print_stats(fs_fs_t *fs,
             apr_pool_t *pool)
 {
   int i, k;
-  
+
+  /* initialize stats to collect */
   representation_stats_t file_rep_stats = { { 0 } };
   representation_stats_t dir_rep_stats = { { 0 } };
   representation_stats_t file_prop_rep_stats = { { 0 } };
@@ -1286,11 +1491,14 @@ print_stats(fs_fs_t *fs,
   apr_int64_t total_size = 0;
   apr_int64_t change_count = 0;
   apr_int64_t change_len = 0;
-  
+
+  /* aggregate info from all revisions */
   for (i = 0; i < fs->revisions->nelts; ++i)
     {
       revision_info_t *revision = APR_ARRAY_IDX(fs->revisions, i,
                                                 revision_info_t *);
+
+      /* data gathered on a revision level */
       change_count += revision->change_count;
       change_len += revision->changes_len;
       total_size += revision->end - revision->offset;
@@ -1303,11 +1511,14 @@ print_stats(fs_fs_t *fs,
                               + revision->file_noderev_count;
       total_node_stats.size += revision->dir_noderev_size
                              + revision->file_noderev_size;
-      
+
+      /* process representations */
       for (k = 0; k < revision->representations->nelts; ++k)
         {
           representation_t *rep = APR_ARRAY_IDX(revision->representations,
                                                 k, representation_t *);
+
+          /* accumulate in the right bucket */
           switch(rep->kind)
             {
               case file_rep:
@@ -1330,6 +1541,7 @@ print_stats(fs_fs_t *fs,
         }
     }
 
+  /* print results */
   printf("\nGlobal statistics:\n");
   printf(_("%20s bytes in %12s revisions\n"
            "%20s bytes in %12s changes\n"
@@ -1388,6 +1600,9 @@ print_stats(fs_fs_t *fs,
   print_rep_stats(&file_prop_rep_stats, pool);
 }
 
+/* Write tool usage info text to OSTREAM using PROGNAME as a prefix and
+ * POOL for allocations.
+ */
 static void
 print_usage(svn_stream_t *ostream, const char *progname,
             apr_pool_t *pool)
@@ -1404,6 +1619,7 @@ print_usage(svn_stream_t *ostream, const
      progname));
 }
 
+/* linear control flow */
 int main(int argc, const char *argv[])
 {
   apr_pool_t *pool;

Modified: subversion/branches/ev2-export/tools/server-side/svnpubsub/commit-hook.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/tools/server-side/svnpubsub/commit-hook.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/tools/server-side/svnpubsub/commit-hook.py (original)
+++ subversion/branches/ev2-export/tools/server-side/svnpubsub/commit-hook.py Fri Dec 21 00:23:39 2012
@@ -59,6 +59,19 @@ def svncmd_dirs(repo, revision):
         dirs.append(line.strip())
     return dirs
 
+def svncmd_changed(repo, revision):
+    cmd = "%s changed -r %s %s" % (SVNLOOK, revision, repo)
+    p = svncmd(cmd)
+    changed = {} 
+    while True:
+        line = p.stdout.readline()
+        if not line:
+            break
+        line = line.strip()
+        (flags, filename) = (line[0:3], line[4:])
+        changed[filename] = {'flags': flags} 
+    return changed
+
 def do_put(body):
     opener = urllib2.build_opener(urllib2.HTTPHandler)
     request = urllib2.Request("http://%s:%d/dirs-changed" %(HOST, PORT), data=body)
@@ -72,12 +85,14 @@ def main(repo, revision):
     i = svncmd_info(repo, revision)
     data = {'revision': int(revision),
             'dirs_changed': [],
+            'changed': {},
             'repos': svncmd_uuid(repo),
             'author': i['author'],
             'log': i['log'],
             'date': i['date'],
             }
     data['dirs_changed'].extend(svncmd_dirs(repo, revision))
+    data['changed'].update(svncmd_changed(repo, revision))
     body = json.dumps(data)
     #print body
     do_put(body)

Modified: subversion/branches/ev2-export/tools/server-side/svnpubsub/svnpubsub/client.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/tools/server-side/svnpubsub/svnpubsub/client.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/tools/server-side/svnpubsub/svnpubsub/client.py (original)
+++ subversion/branches/ev2-export/tools/server-side/svnpubsub/svnpubsub/client.py Fri Dec 21 00:23:39 2012
@@ -119,10 +119,15 @@ class XMLStreamHandler(xml.sax.handler.C
 
     self.rev = None
     self.chars = ''
+    self.parent = None
+    self.attrs = [ ] 
 
   def startElement(self, name, attrs):
+    self.attrs = attrs
     if name == 'commit':
       self.rev = Revision(attrs['repository'], int(attrs['revision']))
+    elif name == "dirs_changed" or name == "changed":
+      self.parent = name
     # No other elements to worry about.
 
   def characters(self, data):
@@ -134,10 +139,15 @@ class XMLStreamHandler(xml.sax.handler.C
       self.rev = None
     elif name == 'stillalive':
       self.event_callback('ping')
+    elif name == self.parent:
+      self.parent = None
     elif self.chars and self.rev:
       value = self.chars.strip()
-      if name == 'path':
+      if self.parent == 'dirs_changed' and name == 'path':
         self.rev.dirs_changed.append(value.decode('unicode_escape'))
+      elif self.parent == 'changed' and name == 'path':
+        path = value.decode('unicode_escape')
+        self.rev.changed[path] = dict(p for p in self.attrs.items())
       elif name == 'author':
         self.rev.author = value.decode('unicode_escape')
       elif name == 'date':
@@ -147,6 +157,8 @@ class XMLStreamHandler(xml.sax.handler.C
 
     # Toss out any accumulated characters for this element.
     self.chars = ''
+    # Toss out the saved attributes for this element.
+    self.attrs = [ ]
 
 
 class Revision(object):
@@ -154,6 +166,7 @@ class Revision(object):
     self.uuid = uuid
     self.rev = rev
     self.dirs_changed = [ ]
+    self.changed = { } 
     self.author = None
     self.date = None
     self.log = None

Modified: subversion/branches/ev2-export/tools/server-side/svnpubsub/svnpubsub/server.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/tools/server-side/svnpubsub/svnpubsub/server.py?rev=1424772&r1=1424771&r2=1424772&view=diff
==============================================================================
--- subversion/branches/ev2-export/tools/server-side/svnpubsub/svnpubsub/server.py (original)
+++ subversion/branches/ev2-export/tools/server-side/svnpubsub/svnpubsub/server.py Fri Dec 21 00:23:39 2012
@@ -78,7 +78,8 @@ class Revision:
         # thus creating invalid XML, so the XML code paths do escaping.
         self.rev = r.get('revision')
         self.repos = r.get('repos')
-        self.dirs_changed = [x for x in r.get('dirs_changed')]
+        self.dirs_changed = r.get('dirs_changed')
+        self.changed = r.get('changed')
         self.author = r.get('author')
         self.log = r.get('log')
         self.date = r.get('date')
@@ -88,6 +89,7 @@ class Revision:
             return json.dumps({'commit': {'repository': self.repos,
                                           'revision': self.rev,
                                           'dirs_changed': self.dirs_changed,
+                                          'changed': self.changed,
                                           'author': self.author,
                                           'log': self.log,
                                           'date': self.date}}) +","
@@ -100,6 +102,11 @@ class Revision:
             for p in self.dirs_changed:
                 x = ET.SubElement(d, 'path')
                 x.text = p.encode('unicode_escape')
+            ch = ET.SubElement(c, 'changed')
+            for chp in self.changed.keys():
+                x = ET.SubElement(ch, 'path', self.changed[chp])
+                x.text = chp.encode('unicode_escape')
+
             str = ET.tostring(c, 'UTF-8') + "\n"
             return str[39:]
         else:

Propchange: subversion/branches/ev2-export/tools/server-side/svnpubsub/svntweet.py
------------------------------------------------------------------------------
    svn:executable = *



Mime
View raw message