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 2012/03/06 18:50:31 UTC

svn commit: r1297604 [12/12] - in /subversion/branches/reintegrate-keep-alive: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ notes/ notes/api-errata/1.7/ subversion/bindings/javahl/native/ subversion/bindings/javah...

Modified: subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/svntest/verify.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/svntest/verify.py?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/svntest/verify.py (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/svntest/verify.py Tue Mar  6 17:50:23 2012
@@ -25,7 +25,8 @@
 ######################################################################
 
 import re, sys
-from difflib import unified_diff
+from difflib import unified_diff, ndiff
+import pprint
 
 import svntest
 
@@ -68,6 +69,10 @@ class SVNIncorrectDatatype(SVNUnexpected
   run_and_verify_* API"""
   pass
 
+class SVNDumpParseError(svntest.Failure):
+  """Exception raised if parsing a dump file fails"""
+  pass
+
 
 ######################################################################
 # Comparison of expected vs. actual output
@@ -397,3 +402,193 @@ def verify_exit_code(message, actual, ex
     display_lines(message, "Exit Code",
                   str(expected) + '\n', str(actual) + '\n')
     raise raisable
+
+# A simple dump file parser.  While sufficient for the current
+# testsuite it doesn't cope with all valid dump files.
+class DumpParser:
+  def __init__(self, lines):
+    self.current = 0
+    self.lines = lines
+    self.parsed = {}
+
+  def parse_line(self, regex, required=True):
+    m = re.match(regex, self.lines[self.current])
+    if not m:
+      if required:
+        raise SVNDumpParseError("expected '%s' at line %d\n%s"
+                                % (regex, self.current,
+                                   self.lines[self.current]))
+      else:
+        return None
+    self.current += 1
+    return m.group(1)
+
+  def parse_blank(self, required=True):
+    if self.lines[self.current] != '\n':  # Works on Windows
+      if required:
+        raise SVNDumpParseError("expected blank at line %d\n%s"
+                                % (self.current, self.lines[self.current]))
+      else:
+        return False
+    self.current += 1
+    return True
+
+  def parse_format(self):
+    return self.parse_line('SVN-fs-dump-format-version: ([0-9]+)$')
+
+  def parse_uuid(self):
+    return self.parse_line('UUID: ([0-9a-z-]+)$')
+
+  def parse_revision(self):
+    return self.parse_line('Revision-number: ([0-9]+)$')
+
+  def parse_prop_length(self, required=True):
+    return self.parse_line('Prop-content-length: ([0-9]+)$', required)
+
+  def parse_content_length(self, required=True):
+    return self.parse_line('Content-length: ([0-9]+)$', required)
+
+  def parse_path(self):
+    path = self.parse_line('Node-path: (.+)$', required=False)
+    if not path and self.lines[self.current] == 'Node-path: \n':
+      self.current += 1
+      path = ''
+    return path
+
+  def parse_kind(self):
+    return self.parse_line('Node-kind: (.+)$', required=False)
+
+  def parse_action(self):
+    return self.parse_line('Node-action: ([0-9a-z-]+)$')
+
+  def parse_copyfrom_rev(self):
+    return self.parse_line('Node-copyfrom-rev: ([0-9]+)$', required=False)
+
+  def parse_copyfrom_path(self):
+    path = self.parse_line('Node-copyfrom-path: (.+)$', required=False)
+    if not path and self.lines[self.current] == 'Node-copyfrom-path: \n':
+      self.current += 1
+      path = ''
+    return path
+
+  def parse_copy_md5(self):
+    return self.parse_line('Text-copy-source-md5: ([0-9a-z]+)$', required=False)
+
+  def parse_copy_sha1(self):
+    return self.parse_line('Text-copy-source-sha1: ([0-9a-z]+)$', required=False)
+
+  def parse_text_md5(self):
+    return self.parse_line('Text-content-md5: ([0-9a-z]+)$', required=False)
+
+  def parse_text_sha1(self):
+    return self.parse_line('Text-content-sha1: ([0-9a-z]+)$', required=False)
+
+  def parse_text_length(self):
+    return self.parse_line('Text-content-length: ([0-9]+)$', required=False)
+
+  # One day we may need to parse individual property name/values into a map
+  def get_props(self):
+    props = []
+    while not re.match('PROPS-END$', self.lines[self.current]):
+      props.append(self.lines[self.current])
+      self.current += 1
+    self.current += 1
+    return props
+
+  def get_content(self, length):
+    content = ''
+    while len(content) < length:
+      content += self.lines[self.current]
+      self.current += 1
+    if len(content) == length + 1:
+      content = content[:-1]
+    elif len(content) != length:
+      raise SVNDumpParseError("content length expected %d actual %d at line %d"
+                              % (length, len(content), self.current))
+    return content
+
+  def parse_one_node(self):
+    node = {}
+    node['kind'] = self.parse_kind()
+    action = self.parse_action()
+    node['copyfrom_rev'] = self.parse_copyfrom_rev()
+    node['copyfrom_path'] = self.parse_copyfrom_path()
+    node['copy_md5'] = self.parse_copy_md5()
+    node['copy_sha1'] = self.parse_copy_sha1()
+    node['prop_length'] = self.parse_prop_length(required=False)
+    node['text_length'] = self.parse_text_length()
+    node['text_md5'] = self.parse_text_md5()
+    node['text_sha1'] = self.parse_text_sha1()
+    node['content_length'] = self.parse_content_length(required=False)
+    self.parse_blank()
+    if node['prop_length']:
+      node['props'] = self.get_props()
+    if node['text_length']:
+      node['content'] = self.get_content(int(node['text_length']))
+    # Hard to determine how may blanks is 'correct' (a delete that is
+    # followed by an add that is a replace and a copy has one fewer
+    # than expected but that can't be predicted until seeing the add)
+    # so allow arbitrary number
+    blanks = 0
+    while self.current < len(self.lines) and self.parse_blank(required=False):
+      blanks += 1
+    node['blanks'] = blanks
+    return action, node
+
+  def parse_all_nodes(self):
+    nodes = {}
+    while True:
+      if self.current >= len(self.lines):
+        break
+      path = self.parse_path()
+      if not path and not path is '':
+        break
+      if not nodes.get(path):
+        nodes[path] = {}
+      action, node = self.parse_one_node()
+      if nodes[path].get(action):
+        raise SVNDumpParseError("duplicate action '%s' for node '%s' at line %d"
+                                % (action, path, self.current))
+      nodes[path][action] = node
+    return nodes
+
+  def parse_one_revision(self):
+    revision = {}
+    number = self.parse_revision()
+    revision['prop_length'] = self.parse_prop_length()
+    revision['content_length'] = self.parse_content_length()
+    self.parse_blank()
+    revision['props'] = self.get_props()
+    self.parse_blank()
+    revision['nodes'] = self.parse_all_nodes()
+    return number, revision
+
+  def parse_all_revisions(self):
+    while self.current < len(self.lines):
+      number, revision = self.parse_one_revision()
+      if self.parsed.get(number):
+        raise SVNDumpParseError("duplicate revision %d at line %d"
+                                % (number, self.current))
+      self.parsed[number] = revision
+
+  def parse(self):
+    self.parsed['format'] = self.parse_format()
+    self.parse_blank()
+    self.parsed['uuid'] = self.parse_uuid()
+    self.parse_blank()
+    self.parse_all_revisions()
+    return self.parsed
+
+def compare_dump_files(message, label, expected, actual):
+  """Parse two dump files EXPECTED and ACTUAL, both of which are lists
+  of lines as returned by run_and_verify_dump, and check that the same
+  revisions, nodes, properties, etc. are present in both dumps.
+  """
+
+  parsed_expected = DumpParser(expected).parse()
+  parsed_actual = DumpParser(actual).parse()
+
+  if parsed_expected != parsed_actual:
+    raise svntest.Failure('\n' + '\n'.join(ndiff(
+          pprint.pformat(parsed_expected).splitlines(),
+          pprint.pformat(parsed_actual).splitlines())))

Modified: subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/switch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/switch_tests.py?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/switch_tests.py (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/switch_tests.py Tue Mar  6 17:50:23 2012
@@ -1532,33 +1532,29 @@ def mergeinfo_switch_elision(sbox):
   beta_path     = os.path.join(wc_dir, "A", "B", "E", "beta")
 
   # Make branches A/B_COPY_1 and A/B_COPY_2
-  svntest.actions.run_and_verify_svn(
-    None,
-    ["A    " + os.path.join(wc_dir, "A", "B_COPY_1", "lambda") + "\n",
+  expected_stdout = verify.UnorderedOutput([
+     "A    " + os.path.join(wc_dir, "A", "B_COPY_1", "lambda") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_1", "E") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_1", "E", "alpha") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_1", "E", "beta") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_1", "F") + "\n",
      "Checked out revision 1.\n",
-     "A         " + B_COPY_1_path + "\n"],
-    [],
-    'copy',
-    sbox.repo_url + "/A/B",
-    B_COPY_1_path)
-
-  svntest.actions.run_and_verify_svn(
-    None,
-    ["A    " + os.path.join(wc_dir, "A", "B_COPY_2", "lambda") + "\n",
+     "A         " + B_COPY_1_path + "\n",
+    ])
+  svntest.actions.run_and_verify_svn(None, expected_stdout, [], 'copy',
+                                     sbox.repo_url + "/A/B", B_COPY_1_path)
+
+  expected_stdout = verify.UnorderedOutput([
+     "A    " + os.path.join(wc_dir, "A", "B_COPY_2", "lambda") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_2", "E") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_2", "E", "alpha") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_2", "E", "beta") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_2", "F") + "\n",
      "Checked out revision 1.\n",
-     "A         " + B_COPY_2_path + "\n"],
-    [],
-    'copy',
-    sbox.repo_url + "/A/B",
-    B_COPY_2_path)
+     "A         " + B_COPY_2_path + "\n",
+    ])
+  svntest.actions.run_and_verify_svn(None, expected_stdout, [], 'copy',
+                                     sbox.repo_url + "/A/B", B_COPY_2_path)
 
   expected_output = svntest.wc.State(wc_dir, {
     'A/B_COPY_1' : Item(verb='Adding'),

Modified: subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/update_tests.py?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/update_tests.py Tue Mar  6 17:50:23 2012
@@ -307,6 +307,92 @@ def update_binary_file_2(sbox):
 
 #----------------------------------------------------------------------
 
+@XFail()
+@Issue(4128)
+def update_binary_file_3(sbox):
+  "update locally modified file to equal versions"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # Suck up contents of a test .png file.
+  theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read()
+
+  # Write our files contents out to disk, in A/theta.
+  theta_path = os.path.join(wc_dir, 'A', 'theta')
+  svntest.main.file_write(theta_path, theta_contents, 'wb')
+
+  # Now, `svn add' that file.
+  svntest.main.run_svn(None, 'add', theta_path)
+
+  # Created expected output tree for 'svn ci'
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/theta' : Item(verb='Adding  (bin)'),
+    })
+
+  # Create expected status tree
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.add({
+    'A/theta' : Item(status='  ', wc_rev=2),
+    })
+
+  # Commit the new binary file, creating revision 2.
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        expected_status, None, wc_dir)
+
+  # Make some mods to the binary files.
+  svntest.main.file_append(theta_path, "foobar")
+  new_theta_contents = theta_contents + "foobar"
+
+  # Created expected output tree for 'svn ci'
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/theta' : Item(verb='Sending'),
+    })
+
+  # Create expected status tree
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.add({
+    'A/theta' : Item(status='  ', wc_rev=3),
+    })
+
+  # Commit modified working copy, creating revision 3.
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        expected_status, None, wc_dir)
+
+  # Now we locally modify the file back to the old version.
+  svntest.main.file_write(theta_path, theta_contents, 'wb')
+
+  # Create expected output tree for an update to rev 2.
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/theta' : Item(status='  '),
+    })
+
+  # Create expected disk tree for the update
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+    'A/theta' : Item(theta_contents,
+                     props={'svn:mime-type' : 'application/octet-stream'}),
+    })
+
+  # Create expected status tree for the update.
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.add({
+    'A/theta' : Item(status='  ', wc_rev=2),
+    })
+
+  # Do an update from revision 2 and make sure that our binary file
+  # gets reverted to its original contents.
+  # This used to raise a conflict.
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None,
+                                        None, None, 1,
+                                        '-r', '2', wc_dir)
+
+#----------------------------------------------------------------------
+
 def update_missing(sbox):
   "update missing items (by name) in working copy"
 
@@ -1189,6 +1275,7 @@ def another_hudson_problem(sbox):
 
   # Sigh, I can't get run_and_verify_update to work (but not because
   # of issue 919 as far as I can tell)
+  expected_output = svntest.verify.UnorderedOutput(expected_output)
   svntest.actions.run_and_verify_svn(None,
                                      expected_output, [],
                                      'up', G_path)
@@ -3142,19 +3229,17 @@ def mergeinfo_update_elision(sbox):
   lambda_path = os.path.join(wc_dir, "A", "B", "lambda")
 
   # Make a branch A/B_COPY
-  svntest.actions.run_and_verify_svn(
-    None,
-    ["A    " + os.path.join(wc_dir, "A", "B_COPY", "lambda") + "\n",
+  expected_stdout =  verify.UnorderedOutput([
+     "A    " + os.path.join(wc_dir, "A", "B_COPY", "lambda") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY", "E") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY", "E", "alpha") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY", "E", "beta") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY", "F") + "\n",
      "Checked out revision 1.\n",
-     "A         " + B_COPY_path + "\n"],
-    [],
-    'copy',
-    sbox.repo_url + "/A/B",
-    B_COPY_path)
+     "A         " + B_COPY_path + "\n",
+    ])
+  svntest.actions.run_and_verify_svn(None, expected_stdout, [], 'copy',
+                                     sbox.repo_url + "/A/B", B_COPY_path)
 
   expected_output = wc.State(wc_dir, {'A/B_COPY' : Item(verb='Adding')})
 
@@ -5682,6 +5767,7 @@ test_list = [ None,
               update_moved_dir_file_add,
               update_moved_dir_dir_add,
               update_moved_dir_file_move,
+              update_binary_file_3,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/upgrade_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/upgrade_tests.py?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/upgrade_tests.py (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/upgrade_tests.py Tue Mar  6 17:50:23 2012
@@ -83,7 +83,7 @@ def replace_sbox_repo_with_tarfile(sbox,
 
   if not dir:
     dir = tar_filename.split('.')[0]
-    
+
   tarpath = os.path.join(os.path.dirname(sys.argv[0]), 'upgrade_tests_data',
                          tar_filename)
   t = tarfile.open(tarpath, 'r:bz2')
@@ -1079,7 +1079,7 @@ def upgrade_with_missing_subdir(sbox):
   svntest.main.safe_rmtree(sbox.ospath('A/B'))
 
   # Now upgrade the working copy and expect a missing subdir
-  expected_output = [
+  expected_output = svntest.verify.UnorderedOutput([
     "Upgraded '%s'\n" % sbox.wc_dir,
     "Upgraded '%s'\n" % sbox.ospath('A'),
     "Skipped '%s'\n" % sbox.ospath('A/B'),
@@ -1087,7 +1087,7 @@ def upgrade_with_missing_subdir(sbox):
     "Upgraded '%s'\n" % sbox.ospath('A/D'),
     "Upgraded '%s'\n" % sbox.ospath('A/D/G'),
     "Upgraded '%s'\n" % sbox.ospath('A/D/H'),
-  ]
+  ])
   svntest.actions.run_and_verify_svn(None, expected_output, [],
                                      'upgrade', sbox.wc_dir)
 
@@ -1163,7 +1163,7 @@ def upgrade_file_externals(sbox):
   svntest.actions.run_and_verify_svn(None, None, [], 'relocate',
                                      'file:///tmp/repo', sbox.repo_url,
                                      sbox.wc_dir)
-  
+
   expected_output = svntest.wc.State(sbox.wc_dir, {
       'A/mu'            : Item(status=' U'),
       'A/B/lambda'      : Item(status=' U'),

Modified: subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_diff/diff-diff3-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_diff/diff-diff3-test.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_diff/diff-diff3-test.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_diff/diff-diff3-test.c Tue Mar  6 17:50:23 2012
@@ -2394,7 +2394,40 @@ merge_adjacent_changes(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+/* Issue #4133, '"diff -x -w" showing wrong change'.
+   The magic number used in this test, 1<<17, is
+   CHUNK_SIZE from ../../libsvn_diff/diff_file.c
+ */
+static svn_error_t *
+test_wrap(apr_pool_t *pool)
+{
+  char ldata[(1<<17) + 4+4+3+1];
+  char rdata[(1<<17) + 4+3+3+1];
+  svn_string_t left, right;
+  svn_diff_file_options_t *diff_opts = svn_diff_file_options_create(pool);
+  diff_opts->ignore_space = TRUE;
 
+  /* Two long lines. */
+  memset(ldata, '@', 1<<17);
+  memset(rdata, '@', 1<<17);
+  strcpy(&ldata[1<<17], "foo\n" "ba \n" "x \n");
+  strcpy(&rdata[1<<17], "foo\n" "ba\n"  "x\t\n");
+
+  /* Cast them to svn_string_t. */
+  left.data = ldata;
+  right.data = rdata;
+  left.len = sizeof(ldata)-1;
+  right.len = sizeof(rdata)-1;
+
+  /* Diff them.  Modulo whitespace, they are identical. */
+  {
+    svn_diff_t *diff;
+    SVN_ERR(svn_diff_mem_string_diff(&diff, &left, &right, diff_opts, pool));
+    SVN_TEST_ASSERT(FALSE == svn_diff_contains_diffs(diff));
+  }
+
+  return SVN_NO_ERROR;
+}
 
 /* ========================================================================== */
 
@@ -2425,5 +2458,7 @@ struct svn_test_descriptor_t test_funcs[
                    "3-way merge with conflict styles"),
     SVN_TEST_PASS2(test_diff4,
                    "4-way merge; see variance-adjusted-patching.html"),
+    SVN_TEST_XFAIL2(test_wrap,
+                   "difference at the start of a 128KB window"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/checksum-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/checksum-test.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/checksum-test.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/checksum-test.c Tue Mar  6 17:50:23 2012
@@ -59,11 +59,34 @@ test_checksum_parse(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_checksum_empty(apr_pool_t *pool)
+{
+  svn_checksum_t *checksum;
+  char data = '\0';
+
+  checksum = svn_checksum_empty_checksum(svn_checksum_md5, pool);
+  SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum));
+
+  checksum = svn_checksum_empty_checksum(svn_checksum_sha1, pool);
+  SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum));
+
+  SVN_ERR(svn_checksum(&checksum, svn_checksum_md5, &data, 0, pool));
+  SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum));
+
+  SVN_ERR(svn_checksum(&checksum, svn_checksum_sha1, &data, 0, pool));
+  SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum));
+
+  return SVN_NO_ERROR;
+}
+
 /* An array of all test functions */
 struct svn_test_descriptor_t test_funcs[] =
   {
     SVN_TEST_NULL,
     SVN_TEST_PASS2(test_checksum_parse,
                    "checksum parse"),
+    SVN_TEST_PASS2(test_checksum_empty,
+                   "checksum emptiness"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/spillbuf-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/spillbuf-test.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/spillbuf-test.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/spillbuf-test.c Tue Mar  6 17:50:23 2012
@@ -112,7 +112,7 @@ test_spillbuf_callback(apr_pool_t *pool)
   SVN_ERR(svn_spillbuf__process(&exhausted, buf, read_callback, &counter,
                                 pool));
   SVN_TEST_ASSERT(!exhausted);
-  
+
   SVN_ERR(svn_spillbuf__process(&exhausted, buf, read_callback, &counter,
                                 pool));
   SVN_TEST_ASSERT(exhausted);

Modified: subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/stream-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/stream-test.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/stream-test.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_subr/stream-test.c Tue Mar  6 17:50:23 2012
@@ -568,6 +568,165 @@ test_stream_base64(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+/* This test doesn't test much unless run under valgrind when it
+   triggers the problem reported here:
+
+   http://mail-archives.apache.org/mod_mbox/subversion-dev/201202.mbox/%3C87sjik3m8q.fsf@stat.home.lan%3E
+
+   The two data writes caused the base 64 code to allocate a buffer
+   that was a byte short but exactly matched a stringbuf blocksize.
+   That meant the stringbuf didn't overallocate and a write beyond
+   the end of the buffer occured.
+ */
+static svn_error_t *
+test_stream_base64_2(apr_pool_t *pool)
+{
+  const struct data_t {
+    const char *encoded1;
+    const char *encoded2;
+  } data[] = {
+    {
+      "MTI",
+      "123456789A123456789B123456789C123456789D123456789E"
+      "223456789A123456789B123456789C123456789D123456789E"
+      "323456789A123456789B123456789C123456789D123456789E"
+      "423456789A123456789B123456789C123456789D123456789E"
+      "523456789A123456789B123456789C123456789D123456789E"
+      "623456789A123456789B123456789C123456789D123456789E"
+      "723456789A123456789B123456789C123456789D123456789E"
+      "823456789A123456789B123456789C123456789D123456789E"
+      "923456789A123456789B123456789C123456789D123456789E"
+      "A23456789A123456789B123456789C123456789D123456789E"
+      "123456789A123456789B123456789C123456789D123456789E"
+      "223456789A123456789B123456789C123456789D123456789E"
+      "323456789A123456789B123456789C123456789D123456789E"
+      "423456789A123456789B123456789C123456789D123456789E"
+      "523456789A123456789B123456789C123456789D123456789E"
+      "623456789A123456789B123456789C123456789D123456789E"
+      "723456789A123456789B123456789C123456789D123456789E"
+      "823456789A123456789B123456789C123456789D123456789E"
+      "923456789A123456789B123456789C123456789D123456789E"
+      "B23456789A123456789B123456789C123456789D123456789E"
+      "123456789A123456789B123456789C123456789D123456789E"
+      "223456789A123456789B123456789C123456789D123456789E"
+      "323456789A123456789B123456789C123456789D123456789E"
+      "423456789A123456789B123456789C123456789D123456789E"
+      "523456789A123456789B123456789C123456789D123456789E"
+      "623456789A123456789B123456789C123456789D123456789E"
+      "723456789A123456789B123456789C123456789D123456789E"
+      "823456789A123456789B123456789C123456789D123456789E"
+      "923456789A123456789B123456789C123456789D123456789E"
+      "C23456789A123456789B123456789C123456789D123456789E"
+      "123456789A123456789B123456789C123456789D123456789E"
+      "223456789A123456789B123456789C123456789D123456789E"
+      "323456789A123456789B123456789C123456789D123456789E"
+      "423456789A123456789B123456789C123456789D123456789E"
+      "523456789A123456789B123456789C123456789D123456789E"
+      "623456789A123456789B123456789C123456789D123456789E"
+      "723456789A123456789B123456789C123456789D123456789E"
+      "823456789A123456789B123456789C123456789D123456789E"
+      "923456789A123456789B123456789C123456789D123456789E"
+      "D23456789A123456789B123456789C123456789D123456789E"
+      "123456789A123456789B123456789C123456789D123456789E"
+      "223456789A123456789B123456789C123456789D123456789E"
+      "323456789A123456789B123456789C123456789D123456789E"
+      "423456789A123456789B123456789C123456789D123456789E"
+      "523456789A123456789B123456789C123456789D123456789E"
+      "623456789A123456789B123456789C123456789D123456789E"
+      "723456789A123456789B123456789C123456789D123456789E"
+      "823456789A123456789B123456789C123456789D123456789E"
+      "923456789A123456789B123456789C123456789D123456789E"
+      "E23456789A123456789B123456789C123456789D123456789E"
+      "123456789A123456789B123456789C123456789D123456789E"
+      "223456789A123456789B123456789C123456789D123456789E"
+      "323456789A123456789B123456789C123456789D123456789E"
+      "423456789A123456789B123456789C123456789D123456789E"
+      "523456789A123456789B123456789C123456789D123456789E"
+      "623456789A123456789B123456789C123456789D123456789E"
+      "723456789A123456789B123456789C123456789D123456789E"
+      "823456789A123456789B123456789C123456789D123456789E"
+      "923456789A123456789B123456789C123456789D123456789E"
+      "F23456789A123456789B123456789C123456789D123456789E"
+      "123456789A123456789B123456789C123456789D123456789E"
+      "223456789A123456789B123456789C123456789D123456789E"
+      "323456789A123456789B123456789C123456789D123456789E"
+      "423456789A123456789B123456789C123456789D123456789E"
+      "523456789A123456789B123456789C123456789D123456789E"
+      "623456789A123456789B123456789C123456789D123456789E"
+      "723456789A123456789B123456789C123456789D123456789E"
+      "823456789A123456789B123456789C123456789D123456789E"
+      "923456789A123456789B123456789C123456789D123456789E"
+      "G23456789A123456789B123456789C123456789D123456789E"
+      "123456789A123456789B123456789C123456789D123456789E"
+      "223456789A123456789B123456789C123456789D123456789E"
+      "323456789A123456789B123456789C123456789D123456789E"
+      "423456789A123456789B123456789C123456789D123456789E"
+      "523456789A123456789B123456789C123456789D123456789E"
+      "623456789A123456789B123456789C123456789D123456789E"
+      "723456789A123456789B123456789C123456789D123456789E"
+      "823456789A123456789B123456789C123456789D123456789E"
+      "923456789A123456789B123456789C123456789D123456789E"
+      "H23456789A123456789B123456789C123456789D123456789E"
+      "123456789A123456789B123456789C123456789D123456789E"
+      "223456789A123456789B123456789C123456789D123456789E"
+      "323456789A123456789B123456789C123456789D123456789E"
+      "423456789A123456789B123456789C123456789D123456789E"
+      "523456789A123456789B123456789C123456789D123456789E"
+      "623456789A123456789B123456789C123456789D123456789E"
+      "723456789A123456789B123456789C123456789D123456789E"
+      "823456789A123456789B123456789C123456789D123456789E"
+      "923456789A123456789B123456789C123456789D123456789E"
+      "I23456789A123456789B123456789C123456789D123456789E"
+      "123456789A123456789B123456789C123456789D123456789E"
+      "223456789A123456789B123456789C123456789D123456789E"
+      "323456789A123456789B123456789C123456789D123456789E"
+      "423456789A123456789B123456789C123456789D123456789E"
+      "523456789A123456789B123456789C123456789D123456789E"
+      "623456789A123456789B123456789C123456789D123456789E"
+      "723456789A123456789B123456789C123456789D123456789E"
+      "823456789A123456789B123456789C123456789D123456789E"
+      "923456789A123456789B123456789C123456789D123456789E"
+      "J23456789A123456789B123456789C123456789D123456789E"
+      "123456789A123456789B123456789C123456789D123456789E"
+      "223456789A123456789B123456789C123456789D123456789E"
+      "323456789A123456789B123456789C123456789D123456789E"
+      "423456789A123456789B123456789C123456789D123456789E"
+      "523456789A123456789B123456789C123456789D12345"
+    },
+    {
+      NULL,
+      NULL,
+    },
+  };
+  int i;
+
+  for (i = 0; data[i].encoded1; i++)
+    {
+      apr_size_t len1 = strlen(data[i].encoded1);
+
+      svn_stringbuf_t *actual = svn_stringbuf_create_empty(pool);
+      svn_stringbuf_t *expected = svn_stringbuf_create_empty(pool);
+      svn_stream_t *stream = svn_stream_from_stringbuf(actual, pool);
+
+      stream = svn_base64_encode(stream, pool);
+      stream = svn_base64_decode(stream, pool);
+
+      SVN_ERR(svn_stream_write(stream, data[i].encoded1, &len1));
+      svn_stringbuf_appendbytes(expected, data[i].encoded1, len1);
+
+      if (data[i].encoded2)
+        {
+          apr_size_t len2 = strlen(data[i].encoded2);
+          SVN_ERR(svn_stream_write(stream, data[i].encoded2, &len2));
+          svn_stringbuf_appendbytes(expected, data[i].encoded2, len2);
+        }
+
+      SVN_ERR(svn_stream_close(stream));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* The test table.  */
 
 struct svn_test_descriptor_t test_funcs[] =
@@ -591,5 +750,7 @@ struct svn_test_descriptor_t test_funcs[
                    "test compressed streams with empty files"),
     SVN_TEST_PASS2(test_stream_base64,
                    "test base64 encoding/decoding streams"),
+    SVN_TEST_PASS2(test_stream_base64_2,
+                   "base64 decoding allocation problem"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_wc/op-depth-test.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_wc/op-depth-test.c Tue Mar  6 17:50:23 2012
@@ -350,12 +350,12 @@ print_row(const nodes_row_t *row,
     moved_here_str = ", here";
   else
     moved_here_str = "";
-      
+
   if (row->file_external)
     file_external_str = ", file-external";
   else
     file_external_str = "";
-      
+
   if (row->repo_revnum == SVN_INVALID_REVNUM)
     return apr_psprintf(result_pool, "%d, %s, %s%s%s%s",
                         row->op_depth, row->local_relpath, row->presence,
@@ -3727,7 +3727,7 @@ incomplete_switch(const svn_test_opts_t 
       {0}
     };
 
-    nodes_row_t after_update[] = { 
+    nodes_row_t after_update[] = {
       {0, "",      "normal", 4, "X"},
       {0, "B",     "normal", 4, "A/B"},
       {0, "B/C",   "normal", 4, "A/B/C"},
@@ -4195,7 +4195,7 @@ move_to_swap(const svn_test_opts_t *opts
 
   SVN_ERR(wc_move(&b, "A/Y", "X/Y"));
   SVN_ERR(wc_move(&b, "X/B", "A/B"));
-  
+
   {
     nodes_row_t nodes[] = {
       {0, "",    "normal",       1, ""},

Modified: subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_wc/wc-incomplete-tester.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_wc/wc-incomplete-tester.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_wc/wc-incomplete-tester.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/tests/libsvn_wc/wc-incomplete-tester.c Tue Mar  6 17:50:23 2012
@@ -78,7 +78,7 @@ int main(int argc, const char *argv[])
               "Mark WCPATH incomplete at REVISION [and REPOS_RELPATH]\n");
       exit(EXIT_FAILURE);
     }
-          
+
   if (apr_initialize())
     {
       fprintf(stderr, "apr_initialize failed\n");

Modified: subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/ubuntu-x64/svnbuild.sh
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/ubuntu-x64/svnbuild.sh?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/ubuntu-x64/svnbuild.sh (original)
+++ subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/ubuntu-x64/svnbuild.sh Tue Mar  6 17:50:23 2012
@@ -30,7 +30,7 @@ echo "========= autogen.sh"
 echo "========= configure"
 ./configure --enable-javahl --enable-maintainer-mode \
             --without-berkeley-db \
-            --with-jdk=/usr/lib/jvm/java-6-openjdk/ \
+            --with-jdk=/usr/lib/jvm/java-7-openjdk-amd64/ \
             --with-junit=/usr/share/java/junit.jar || exit $?
 
 echo "========= make"

Modified: subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/win32-SharpSvn/svntest-bindings.cmd
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/win32-SharpSvn/svntest-bindings.cmd?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/win32-SharpSvn/svntest-bindings.cmd (original)
+++ subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/win32-SharpSvn/svntest-bindings.cmd Tue Mar  6 17:50:23 2012
@@ -32,8 +32,6 @@ IF ERRORLEVEL 1 (
 PATH %PATH%;%TESTDIR%\bin
 SET result=0
 
-
-echo python win-tests.py -r -f fsfs --javahl "%TESTDIR%\tests"
 python win-tests.py -r -f fsfs --javahl "%TESTDIR%\tests"
 IF ERRORLEVEL 1 (
   echo [python reported error %ERRORLEVEL%]
@@ -44,10 +42,10 @@ IF EXIST "%TESTDIR%\swig" rmdir /s /q "%
 mkdir "%TESTDIR%\swig\py-release\libsvn"
 mkdir "%TESTDIR%\swig\py-release\svn"
 
-xcopy "release\subversion\bindings\swig\python\*.pyd" "%TESTDIR%\swig\py-release\libsvn\*.pyd"
-xcopy "release\subversion\bindings\swig\python\libsvn_swig_py\*.dll" "%TESTDIR%\swig\py-release\libsvn\*.dll"
-xcopy "subversion\bindings\swig\python\*.py" "%TESTDIR%\swig\py-release\libsvn\*.py"
-xcopy "subversion\bindings\swig\python\svn\*.py" "%TESTDIR%\swig\py-release\svn\*.py"
+xcopy "release\subversion\bindings\swig\python\*.pyd" "%TESTDIR%\swig\py-release\libsvn\*.pyd" > nul:
+xcopy "release\subversion\bindings\swig\python\libsvn_swig_py\*.dll" "%TESTDIR%\swig\py-release\libsvn\*.dll" > nul:
+xcopy "subversion\bindings\swig\python\*.py" "%TESTDIR%\swig\py-release\libsvn\*.py" > nul:
+xcopy "subversion\bindings\swig\python\svn\*.py" "%TESTDIR%\swig\py-release\svn\*.py" > nul:
 
 SET PYTHONPATH=%TESTDIR%\swig\py-release
 
@@ -57,4 +55,25 @@ IF ERRORLEVEL 1 (
   SET result=1
 )
 
+mkdir "%TESTDIR%\swig\pl-release\SVN"
+mkdir "%TESTDIR%\swig\pl-release\auto\SVN"
+xcopy subversion\bindings\swig\perl\native\*.pm "%TESTDIR%\swig\pl-release\SVN" > nul:
+pushd release\subversion\bindings\swig\perl\native
+for %%i in (*.dll) do (
+  set name=%%i
+  mkdir "%TESTDIR%\swig\pl-release\auto\SVN\!name:~0,-4!"
+  xcopy "!name:~0,-4!.*" "%TESTDIR%\swig\pl-release\auto\SVN\!name:~0,-4!" > nul:
+  xcopy /y "_Core.dll" "%TESTDIR%\swig\pl-release\auto\SVN\!name:~0,-4!" > nul:
+)
+popd
+
+SET PERL5LIB=%PERL5LIB%;%TESTDIR%\swig\pl-release;
+pushd subversion\bindings\swig\perl\native
+perl -MExtUtils::Command::MM -e test_harness() t\*.t
+IF ERRORLEVEL 1 (
+  echo [Perl reported error %ERRORLEVEL%]
+  REM SET result=1
+)
+popd
+
 exit /b %result%

Modified: subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/win32-SharpSvn/svntest-cleanup.cmd
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/win32-SharpSvn/svntest-cleanup.cmd?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/win32-SharpSvn/svntest-cleanup.cmd (original)
+++ subversion/branches/reintegrate-keep-alive/tools/buildbot/slaves/win32-SharpSvn/svntest-cleanup.cmd Tue Mar  6 17:50:23 2012
@@ -48,7 +48,9 @@ IF NOT ERRORLEVEL 1 (
 )
 POPD
 
+
 taskkill /im svn.exe /f 2> nul:
+taskkill /im svnlook.exe /f 2> nul:
 taskkill /im svnadmin.exe /f 2> nul:
 taskkill /im svnserve.exe /f 2> nul:
 taskkill /im svnrdump.exe /f 2> nul:
@@ -58,6 +60,9 @@ taskkill /im op-depth-test.exe /f 2> nul
 IF EXIST "%TESTDIR%\tests\subversion\tests\cmdline\httpd\" (
   rmdir /s /q  "%TESTDIR%\tests\subversion\tests\cmdline\httpd"
 )
+IF EXIST "%TESTDIR%\swig\" (
+  rmdir /s /q  "%TESTDIR%\swig"
+)
 
 del "%TESTDIR%\tests\*.log" 2> nul:
 

Modified: subversion/branches/reintegrate-keep-alive/tools/client-side/detach.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/client-side/detach.py?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/client-side/detach.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/client-side/detach.py Tue Mar  6 17:50:23 2012
@@ -67,7 +67,7 @@ def  migrate_sqlite(wc_src, target, wcro
   src_c.execute('select count(*) from wc_lock')
   count = int(src_c.fetchone()[0])
   assert count == 0
-    
+
   src_c.execute('select count(*) from work_queue')
   count = int(src_c.fetchone()[0])
   assert count == 0

Modified: subversion/branches/reintegrate-keep-alive/tools/client-side/mergeinfo-sanitizer.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/client-side/mergeinfo-sanitizer.py?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/client-side/mergeinfo-sanitizer.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/client-side/mergeinfo-sanitizer.py Tue Mar  6 17:50:23 2012
@@ -177,7 +177,7 @@ def sanitize_mergeinfo(parsed_original_m
   for entry in parsed_original_mergeinfo:
     get_new_location_segments(parsed_original_mergeinfo[entry], repo_root, wcpath, ctx)
     full_mergeinfo.update(parsed_original_mergeinfo[entry])
-    
+
   hasher(hash_file, newmergeinfo_file)
   diff_mergeinfo = core.svn_mergeinfo_diff(full_mergeinfo,
                                            mergeinfo, 1, temp_pool)
@@ -200,7 +200,7 @@ def fix_sanitized_mergeinfo(parsed_origi
                             ctx, hash_file, newmergeinfo_file, temp_pool):
   has_local_modification = check_local_modifications(wcpath, temp_pool)
   old_hash = ''
-  new_hash = '' 
+  new_hash = ''
   try:
     with open(hash_file, "r") as f:
       old_hash = pickle.load(f)
@@ -248,7 +248,7 @@ the working copy before running the scri
     sys.exit(1)
 
 def get_original_mergeinfo(wcpath, revision, depth, ctx, temp_pool):
-  propget_list = client.svn_client_propget3("svn:mergeinfo", wcpath, 
+  propget_list = client.svn_client_propget3("svn:mergeinfo", wcpath,
                                             revision, revision, depth, None,
                                             ctx, temp_pool)
 

Modified: subversion/branches/reintegrate-keep-alive/tools/client-side/svnmucc/svnmucc.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/client-side/svnmucc/svnmucc.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/client-side/svnmucc/svnmucc.c (original)
+++ subversion/branches/reintegrate-keep-alive/tools/client-side/svnmucc/svnmucc.c Tue Mar  6 17:50:23 2012
@@ -826,7 +826,7 @@ main(int argc, const char **argv)
                                                sizeof(struct action *));
   const char *anchor = NULL;
   svn_error_t *err = SVN_NO_ERROR;
-  apr_getopt_t *getopt;
+  apr_getopt_t *opts;
   enum {
     config_dir_opt = SVN_OPT_FIRST_LONGOPT_ID,
     config_inline_opt,
@@ -866,15 +866,15 @@ main(int argc, const char **argv)
   config_options = apr_array_make(pool, 0,
                                   sizeof(svn_cmdline__config_argument_t*));
 
-  apr_getopt_init(&getopt, pool, argc, argv);
-  getopt->interleave = 1;
+  apr_getopt_init(&opts, pool, argc, argv);
+  opts->interleave = 1;
   while (1)
     {
       int opt;
       const char *arg;
       const char *opt_arg;
 
-      apr_status_t status = apr_getopt_long(getopt, options, &opt, &arg);
+      apr_status_t status = apr_getopt_long(opts, options, &opt, &arg);
       if (APR_STATUS_IS_EOF(status))
         break;
       if (status != APR_SUCCESS)
@@ -957,7 +957,7 @@ main(int argc, const char **argv)
           no_auth_cache = TRUE;
           break;
         case version_opt:
-          SVN_INT_ERR(display_version(getopt, pool));
+          SVN_INT_ERR(display_version(opts, pool));
           exit(EXIT_SUCCESS);
           break;
         case 'h':
@@ -968,10 +968,10 @@ main(int argc, const char **argv)
 
   /* Copy the rest of our command-line arguments to an array,
      UTF-8-ing them along the way. */
-  action_args = apr_array_make(pool, getopt->argc, sizeof(const char *));
-  while (getopt->ind < getopt->argc)
+  action_args = apr_array_make(pool, opts->argc, sizeof(const char *));
+  while (opts->ind < opts->argc)
     {
-      const char *arg = getopt->argv[getopt->ind++];
+      const char *arg = opts->argv[opts->ind++];
       if ((err = svn_utf_cstring_to_utf8(&(APR_ARRAY_PUSH(action_args,
                                                           const char *)),
                                          arg, pool)))

Modified: subversion/branches/reintegrate-keep-alive/tools/dev/merge-graph.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/dev/merge-graph.py?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/dev/merge-graph.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/dev/merge-graph.py Tue Mar  6 17:50:23 2012
@@ -22,237 +22,9 @@
 args_message = 'GRAPH_CONFIG_FILE...'
 help_message = """Produce pretty graphs representing branches and merging.
 For each config file specified, construct a graph and write it as a PNG file."""
-example = """
-  [graph]
-  filename = merge-sync-1.png
-  title = Sync Merge: CC vs SVN
-  # Branches: (branch name, branched from node, first rev, last rev).
-  branches = [
-    ('A', 'O0', 1, 4),
-    ('O', None, 0, 0),
-    ('B', 'O0', 1, 5)
-    ]
-  # Changes: nodes in which a change was committed; merge targets need not
-  # be listed here.
-  changes = [
-    'A1', 'A2', 'A3', 'A4',
-    'B1', 'B2', 'B3', 'B4', 'B5'
-    ]
-  # Merges: (base node, source-right node, target node, label).
-  # Base is also known as source-left.
-  merges = [
-    ('O0', 'A:1', 'B3', 'sync'),
-    ('A2', 'A:3', 'B5', 'sync'),
-    ]
-  # Annotations for nodes: (node, annotation text).
-  annotations = [
-    ('A2', 'cc:YCA')
-    ]
-"""
-
-# Notes about different kinds of merge.
-#
-# A basic 3-way merge is ...
-#
-# The ClearCase style of merge is a 3-way merge.
-#
-# The Subversion style of merge (that is, one phase of a Subversion merge)
-# is a three-way merge with its base (typically the YCA) on the source branch.
-
 
 import sys
-import pydot
-from pydot import Node, Edge
-
-
-def mergeinfo_to_node_list(mi):
-  """Convert a mergeinfo string such as '/foo:1,3-5*' into a list of
-     node names such as ['foo1', 'foo3', 'foo4', 'foo5']."""
-  ### Doesn't yet strip the leading slash.
-  l = []
-  if mi:
-    for mi_str in mi.split(' '):
-      path, ranges = mi_str.split(':')
-      for r in ranges.split(','):
-        if r.endswith('*'):
-          # TODO: store & use this 'non-inheritable' flag
-          # Remove the flag
-          r = r[:-1]
-        rlist = r.split('-')
-        r1 = int(rlist[0])
-        if len(rlist) == 2:
-          r2 = int(rlist[1])
-        else:
-          r2 = r1
-        for rev in range(r1, r2 + 1):
-          l.append(path + str(rev))
-  return l
-
-
-class MergeGraph(pydot.Graph):
-  """Base class, not intended for direct use.  Use MergeDot for the main
-     graph and MergeSubgraph for a subgraph."""
-
-  def mk_origin_node(graph, name):
-    """Add a node to the graph"""
-    graph.add_node(Node(name + '0', label=name, shape='plaintext'))
-
-  def mk_invis_node(graph, name):
-    """Add a node to the graph"""
-    graph.add_node(Node(name, style='invis'))
-
-  def mk_node(graph, name):
-    """Add a node to the graph, if not already present"""
-    if not graph.get_node(name):
-      if name in graph.changes:
-        graph.add_node(Node(name))
-      else:
-        graph.add_node(Node(name, color='grey', label=''))
-
-  def mk_merge_target(graph, target_node, important):
-    """Add a merge target node to the graph."""
-    if important:
-      color = 'red'
-    else:
-      color = 'black'
-    graph.add_node(Node(target_node, color=color, fontcolor=color, style='bold'))
-
-  def mk_edge(graph, name1, name2, **attrs):
-    """Add an ordinary edge to the graph"""
-    graph.add_edge(Edge(name1, name2, dir='none', style='dotted', color='grey', **attrs))
-
-  def mk_br_edge(graph, name1, name2):
-    """Add a branch-creation edge to the graph"""
-    # Constraint=false to avoid the Y-shape skewing the nice parallel branch lines
-    graph.mk_edge(name1, name2, constraint='false')
-
-  def mk_merge_edge(graph, src_node, tgt_node, kind, label, important):
-    """Add a merge edge to the graph"""
-    if important:
-      color = 'red'
-    else:
-      color = 'grey'
-    e = Edge(src_node, tgt_node, constraint='false',
-             label='"' + label + '"',
-             color=color, fontcolor=color,
-             style='bold')
-    if kind == 'cherry':
-      e.set_style('dashed')
-      e.set_dir('both')
-      e.set_arrowtail('tee')
-    graph.add_edge(e)
-
-  def mk_mergeinfo_edge(graph, base_node, src_node, important):
-    """"""
-    if important:
-      color = 'red'
-    else:
-      color = 'grey'
-    graph.add_edge(Edge(base_node, src_node,
-                        dir='both', arrowtail='odot', arrowhead='tee',
-                        color=color, constraint='false'))
-
-  def mk_invis_edge(graph, name1, name2):
-    """Add an invisible edge to the graph"""
-    graph.add_edge(Edge(name1, name2, style='invis'))
-
-  def add_merge(graph, merge, important):
-    """Add a merge"""
-    base_node, src_node, tgt_node, kind = merge
-
-    if base_node and src_node and kind != 'cherry':
-      graph.mk_mergeinfo_edge(base_node, src_node, important)
-
-    # Merge target node
-    graph.mk_merge_target(tgt_node, important)
-
-    # Merge edge
-    graph.mk_merge_edge(src_node, tgt_node, kind, kind, important)
-
-  def add_annotation(graph, node, label, color='red'):
-    """"""
-    ann_node = node + '_annotation'
-    g = pydot.Subgraph(rank='same')
-    g.add_node(Node(ann_node, shape='box', color=color, label='"' + label + '"'))
-    g.add_edge(Edge(ann_node, node, style='dotted', color=color, dir='none', constraint='false'))
-    graph.add_subgraph(g)
-
-class MergeSubgraph(MergeGraph, pydot.Subgraph):
-  """"""
-  def __init__(graph, **attrs):
-    """"""
-    MergeGraph.__init__(graph)
-    pydot.Subgraph.__init__(graph, **attrs)
-
-class MergeDot(MergeGraph, pydot.Dot):
-  """
-  # TODO: In the 'merges' input, find the predecessor automatically.
-  """
-  def __init__(graph, config_filename, **attrs):
-    """Return a new MergeDot graph generated from the specified config file."""
-    MergeGraph.__init__(graph)
-    pydot.Dot.__init__(graph, **attrs)
-
-    graph.read_config(config_filename)
-
-    graph.construct()
-
-  def read_config(graph, config_filename):
-    """"""
-    import ConfigParser
-    config = ConfigParser.SafeConfigParser()
-    files_read = config.read(config_filename)
-    if len(files_read) == 0:
-      print >> sys.stderr, 'graph: unable to read graph config from "' + config_filename + '"'
-      sys.exit(1)
-    graph.title = config.get('graph', 'title')
-    graph.filename = config.get('graph', 'filename')
-    graph.branches = eval(config.get('graph', 'branches'))
-    graph.changes = eval(config.get('graph', 'changes'))
-    graph.merges = eval(config.get('graph', 'merges'))
-    graph.annotations = eval(config.get('graph', 'annotations'))
-
-  def construct(graph):
-    """"""
-    # Origin nodes (done first, in an attempt to set the order)
-    for br, orig, r1, head in graph.branches:
-      graph.mk_origin_node(br)
-
-    # Edges and target nodes for merges
-    for merge in graph.merges:
-      # Emphasize the last merge, as it's the important one
-      important = (merge == graph.merges[-1])
-      graph.add_merge(merge, important)
-
-    # Edges for basic lines of descent
-    for br, orig, r1, head in graph.branches:
-      sub_g = MergeSubgraph(ordering='out')
-      for i in range(1, head + 1):
-        prev_n = br + str(i - 1)
-        this_n = br + str(i)
-
-        # Normal edges and nodes
-        if i < r1:
-          graph.mk_invis_node(this_n)
-        else:
-          graph.mk_node(this_n)
-        if i <= r1:
-          graph.mk_invis_edge(prev_n, this_n)
-        else:
-          graph.mk_edge(prev_n, this_n)
-
-      # Branch creation edges
-      if orig:
-        sub_g.mk_br_edge(orig, br + str(r1))
-
-      graph.add_subgraph(sub_g)
-
-    # Annotations
-    for node, label in graph.annotations:
-      graph.add_annotation(node, label)
-
-    # A title for the graph (added last so it goes at the top)
-    #graph.add_node(Node('title', shape='plaintext', label='"' + graph.title + '"'))
+from mergegraph import MergeDot
 
 
 # If run as a program, process each input filename as a graph config file.

Propchange: subversion/branches/reintegrate-keep-alive/tools/dev/merge-graph.py
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/reintegrate-keep-alive/tools/dev/unix-build/Makefile.svn
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/dev/unix-build/Makefile.svn?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/dev/unix-build/Makefile.svn (original)
+++ subversion/branches/reintegrate-keep-alive/tools/dev/unix-build/Makefile.svn Tue Mar  6 17:50:23 2012
@@ -70,7 +70,7 @@ SERF_VER	= 1.0.0
 SERF_OLD_VER	= 0.3.1
 CYRUS_SASL_VER	= 2.1.23
 SQLITE_VER	= 3070603
-LIBMAGIC_VER	= 5.07
+LIBMAGIC_VER	= 5.11
 RUBY_VER	= 1.8.7-p334
 BZ2_VER	= 1.0.6
 PYTHON_VER	= 2.7.2

Modified: subversion/branches/reintegrate-keep-alive/tools/dev/which-error.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/dev/which-error.py?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/dev/which-error.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/dev/which-error.py Tue Mar  6 17:50:23 2012
@@ -81,7 +81,10 @@ def print_error(code):
   try:
     print('%08d  %s' % (code, __svn_error_codes[code]))
   except KeyError:
-    print('%08d  *** UNKNOWN ERROR CODE ***' % (code))
+    if code == -41:
+      print("Sit by a lake.")
+    else:
+      print('%08d  *** UNKNOWN ERROR CODE ***' % (code))
 
 if __name__ == "__main__":
   global __svn_error_codes

Modified: subversion/branches/reintegrate-keep-alive/tools/dev/windows-build/Makefile
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/dev/windows-build/Makefile?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/dev/windows-build/Makefile (original)
+++ subversion/branches/reintegrate-keep-alive/tools/dev/windows-build/Makefile Tue Mar  6 17:50:23 2012
@@ -107,7 +107,7 @@ config: targetdir
 libsvn_auth_gnome_keyring libsvn_auth_kwallet libsvn_client libsvn_delta libsvn_diff libsvn_fs libsvn_fs_base libsvn_fs_fs libsvn_fs_util libsvn_ra libsvn_ra_local libsvn_ra_neon libsvn_ra_serf libsvn_ra_svn libsvn_repos libsvn_subr libsvn_wc: targetdir
 	$(MSBUILD) /t:Libraries\$@
 	$(MAKE) package
-svn svnadmin svndumpfilter svnlook svnmucc svnserve svnsync svnversion entries-dump: targetdir
+svn svnadmin svndumpfilter svnlook svnmucc svnserve svnsync svnversion svnrdump entries-dump: targetdir
 	$(MSBUILD) /t:Programs\$@
 	$(MAKE) package
 auth-test cache-test changes-test checksum-test client-test compat-test config-test db-test diff-diff3-test dir-delta-editor dirent_uri-test error-test fs-base-test fs-pack-test fs-test hashdump-test key-test locks-test mergeinfo-test opt-test path-test ra-local-test random-test repos-test revision-test skel-test stream-test string-test strings-reps-test svn_test_fs svn_test_main svndiff-test target-test time-test translate-test tree-conflict-data-test utf-test vdelta-test window-test: targetdir
@@ -128,7 +128,7 @@ all2: targetdir
 package:
 	test -d $(SVNDIR)\$(CONFIG)\Subversion\tests\cmdline || mkdir $(SVNDIR)\$(CONFIG)\Subversion\tests\cmdline
 	test -d $(TARGETDIR)\bin || mkdir $(TARGETDIR)\bin
-	for %%i in (svn svnadmin svndumpfilter svnlook svnserve svnsync svnversion) do @$(CP) $(CONFIG)\subversion\%%i\%%i.exe $(TARGETDIR)\bin
+	for %%i in (svn svnadmin svndumpfilter svnlook svnserve svnsync svnversion svnrdump) do @$(CP) $(CONFIG)\subversion\%%i\%%i.exe $(TARGETDIR)\bin
 	for %%i in (diff diff3 diff4) do @if exist $(CONFIG)\tools\diff\%%i.exe $(CP) $(CONFIG)\tools\diff\%%i.exe $(TARGETDIR)\bin
 	$(CP) $(APRDIR)\$(CONFIG)/*.dll $(TARGETDIR)\bin
 	$(CP) $(APRUTILDIR)\$(CONFIG)/*.dll $(TARGETDIR)\bin

Modified: subversion/branches/reintegrate-keep-alive/tools/diff/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/diff/diff.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/diff/diff.c (original)
+++ subversion/branches/reintegrate-keep-alive/tools/diff/diff.c Tue Mar  6 17:50:23 2012
@@ -89,6 +89,8 @@ int main(int argc, const char *argv[])
 
   options_array = apr_array_make(pool, 0, sizeof(const char *));
 
+  diff_options = svn_diff_file_options_create(pool);
+
   for (i = 1 ; i < argc ; i++)
     {
       if (!no_more_options && (argv[i][0] == '-'))
@@ -105,6 +107,11 @@ int main(int argc, const char *argv[])
               show_c_function = TRUE;
               continue;
             }
+          if (argv[i][1] == 'w' && !argv[i][2])
+            {
+              diff_options->ignore_space = svn_diff_file_ignore_space_all;
+              continue;
+            }
           APR_ARRAY_PUSH(options_array, const char *) = argv[i];
         }
       else
@@ -127,8 +134,6 @@ int main(int argc, const char *argv[])
       return 2;
     }
 
-  diff_options = svn_diff_file_options_create(pool);
-
   svn_err = svn_diff_file_options_parse(diff_options, options_array, pool);
   if (svn_err)
     {

Modified: subversion/branches/reintegrate-keep-alive/tools/dist/backport.pl
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/dist/backport.pl?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/dist/backport.pl (original)
+++ subversion/branches/reintegrate-keep-alive/tools/dist/backport.pl Tue Mar  6 17:50:23 2012
@@ -1,6 +1,7 @@
 #!/usr/bin/perl -l
 use warnings;
 use strict;
+use feature qw/switch say/;
 
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
@@ -21,14 +22,23 @@ use strict;
 
 use Term::ReadKey qw/ReadMode ReadKey/;
 use File::Temp qw/tempfile/;
-
-$/ = ""; # paragraph mode
+use POSIX qw/ctermid/;
 
 my $SVN = $ENV{SVN} || 'svn'; # passed unquoted to sh
 my $VIM = 'vim';
 my $STATUS = './STATUS';
 my $BRANCHES = '^/subversion/branches';
+
+my $YES = $ENV{YES}; # batch mode: eliminate prompts, add sleeps
 my $WET_RUN = qw[false true][1]; # don't commit
+my $DEBUG = qw[false true][0]; # 'set -x', etc
+
+# derived values
+my $SVNq;
+
+$SVN .= " --non-interactive" if $YES or not defined ctermid;
+$SVNq = "$SVN -q ";
+$SVNq =~ s/-q// if $DEBUG eq 'true';
 
 sub usage {
   my $basename = $0;
@@ -70,7 +80,7 @@ sub merge {
     # NOTE: This doesn't escape the branch into the pattern.
     $pattern = sprintf '\V\(%s branch(es)?\|branches\/%s\|Branch(es)?:\n *%s\)', $entry{branch}, $entry{branch}, $entry{branch};
     $mergeargs = "--reintegrate $BRANCHES/$entry{branch}";
-    print $logmsg_fh "Reintergrate the $entry{header}:";
+    print $logmsg_fh "Reintegrate the $entry{header}:";
     print $logmsg_fh "";
   } elsif (@{$entry{revisions}}) {
     $pattern = '^ [*] \V' . 'r' . $entry{revisions}->[0];
@@ -91,13 +101,20 @@ sub merge {
   my $script = <<"EOF";
 #!/bin/sh
 set -e
+if $DEBUG; then
+  set -x
+fi
 $SVN diff > $backupfile
-$SVN revert -R .
-$SVN up
-$SVN merge $mergeargs
+$SVNq revert -R .
+$SVNq up
+$SVNq merge $mergeargs
 $VIM -e -s -n -N -i NONE -u NONE -c '/$pattern/normal! dap' -c wq $STATUS
 if $WET_RUN; then
-  $SVN commit -F $logmsg_filename
+  if [ -n "\$PRINT_SOMETHING_BETWEEN_PROMPTS" ]; then
+    # hack for pw-driver.pl to see some output between prompts
+    head -n1 $logmsg_filename
+  fi
+  $SVNq commit -F $logmsg_filename
 else
   echo "Committing:"
   $SVN status -q
@@ -108,13 +125,16 @@ EOF
   $script .= <<"EOF" if $entry{branch};
 reinteg_rev=\`$SVN info $STATUS | sed -ne 's/Last Changed Rev: //p'\`
 if $WET_RUN; then
-  $SVN rm $BRANCHES/$entry{branch} -m "Remove the '$entry{branch}' branch, reintegrated in r\$reinteg_rev."
+  # Sleep to avoid out-of-order commit notifications
+  if [ -n "$YES" ]; then sleep 15; fi
+  $SVNq rm $BRANCHES/$entry{branch} -m "Remove the '$entry{branch}' branch, reintegrated in r\$reinteg_rev."
+  if [ -n "$YES" ]; then sleep 1; fi
 else
   echo "Removing reintegrated '$entry{branch}' branch"
 fi
 EOF
 
-  open SHELL, '|-', qw#/bin/sh -x# or die $!;
+  open SHELL, '|-', qw#/bin/sh# or die $!;
   print SHELL $script;
   close SHELL or warn "$0: sh($?): $!";
 
@@ -143,7 +163,7 @@ sub parse_entry {
   # revisions
   $branch = sanitize_branch $1 if $_[0] =~ /^(\S*) branch$/;
   while ($_[0] =~ /^r/) {
-    while ($_[0] =~ s/^r(\d+)(?:,\s*)?//) {
+    while ($_[0] =~ s/^r(\d+)(?:$|[,; ]+)//) {
       push @revisions, $1;
     }
     shift;
@@ -180,21 +200,27 @@ sub parse_entry {
 
 sub handle_entry {
   my %entry = parse_entry @_;
+  my @vetoes = grep { /^  -1:/ } @{$entry{votes}};
 
-  print "";
-  print "\n>>> The $entry{header}:";
-  print join ", ", map { "r$_" } @{$entry{revisions}};
-  print "$BRANCHES/$entry{branch}" if $entry{branch};
-  print "";
-  print for @{$entry{logsummary}};
-  print "";
-  print for @{$entry{votes}};
-  print "";
-  print "Vetoes found!" if grep { /^  -1:/ } @{$entry{votes}};
+  if ($YES) {
+    merge %entry unless @vetoes;
+  } else {
+    print "";
+    print "\n>>> The $entry{header}:";
+    print join ", ", map { "r$_" } @{$entry{revisions}};
+    print "$BRANCHES/$entry{branch}" if $entry{branch};
+    print "";
+    print for @{$entry{logsummary}};
+    print "";
+    print for @{$entry{votes}};
+    print "";
+    print "Vetoes found!" if @vetoes;
+
+    merge %entry if prompt;
+  }
 
-  # TODO: this changes ./STATUS, which we're reading below, but
+  # TODO: merge() changes ./STATUS, which we're reading below, but
   #       on my system the loop in main() doesn't seem to care.
-  merge %entry if $ENV{YES} or prompt;
 
   1;
 }
@@ -203,19 +229,37 @@ sub main {
   usage, exit 0 if @ARGV;
   usage, exit 1 unless -r $STATUS;
 
-  my $sawapproved;
   @ARGV = $STATUS;
-  while (<>) {
-    my @lines = split /\n/;
 
-    # Section header?
-    next unless $sawapproved ||= /^Approved changes/;
-    print "\n\n=== $lines[0]" and next if $lines[0] =~ /^[A-Z].*:$/i;
+  # Skip most of the file
+  while (<>) {
+    last if /^Approved changes/;
+  }
+  while (<>) {
+    last unless /^=+$/;
+  }
+  $/ = ""; # paragraph mode
 
-    # Backport entry?
-    handle_entry @lines and next if $lines[0] =~ /^ \*/ and $sawapproved;
+  while (<>) {
+    my @lines = split /\n/;
 
-    warn "Unknown entry '$lines[0]' at $ARGV:$.\n";
+    given ($lines[0]) {
+      # Section header
+      when (/^[A-Z].*:$/i) {
+        print "\n\n=== $lines[0]" unless $YES;
+      }
+      # Separator after section header
+      when (/^=+$/i) {
+        break;
+      }
+      # Backport entry?
+      when (/^ \*/) {
+        handle_entry @lines;
+      }
+      default {
+        warn "Unknown entry '$lines[0]' at $ARGV:$.\n";
+      }
+    }
   }
 }
 

Modified: subversion/branches/reintegrate-keep-alive/tools/dist/release.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/dist/release.py?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/dist/release.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/dist/release.py Tue Mar  6 17:50:23 2012
@@ -396,9 +396,9 @@ def roll_tarballs(args):
            raise RuntimeError('Cannot find usable %s' % dep.label)
 
     if branch != 'trunk':
-        # Make sure CHANGES is sync'd.    
+        # Make sure CHANGES is sync'd.
         compare_changes(repos, branch, args.revnum)
-    
+
     # Ensure the output directory doesn't already exist
     if os.path.exists(get_deploydir(args.base_dir)):
         raise RuntimeError('output directory \'%s\' already exists'

Modified: subversion/branches/reintegrate-keep-alive/tools/examples/get-location-segments.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/examples/get-location-segments.py?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/examples/get-location-segments.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/examples/get-location-segments.py Tue Mar  6 17:50:23 2012
@@ -105,6 +105,9 @@ def prompt_func_simple_prompt(realm, use
   simple_cred.may_save = False
   return simple_cred
 
+def prompt_func_gnome_keyring_prompt(keyring, pool):
+  return getpass.getpass(prompt="Password for '%s' GNOME keyring: " % keyring)
+
 def main():
   try:
     url, peg_revision, start_revision, end_revision = parse_args(sys.argv[1:])
@@ -125,7 +128,12 @@ ERROR: %s
 
   core.svn_config_ensure(None)
   ctx = client.svn_client_create_context()
-  providers = [
+  ctx.config = core.svn_config_get_config(None)
+
+  # Make sure that these are at the start of the list, so passwords from
+  # gnome-keyring / kwallet are checked before asking for new passwords.
+  providers = core.svn_auth_get_platform_specific_client_providers(ctx.config['config'], None)
+  providers.extend([
     client.get_simple_provider(),
     core.svn_auth_get_ssl_server_trust_file_provider(),
     core.svn_auth_get_simple_prompt_provider(prompt_func_simple_prompt, 2),
@@ -134,9 +142,12 @@ ERROR: %s
     client.get_ssl_server_trust_file_provider(),
     client.get_ssl_client_cert_file_provider(),
     client.get_ssl_client_cert_pw_file_provider(),
-    ]
+  ])
+
   ctx.auth_baton = core.svn_auth_open(providers)
-  ctx.config = core.svn_config_get_config(None)
+
+  if hasattr(core, 'svn_auth_set_gnome_keyring_unlock_prompt_func'):
+    core.svn_auth_set_gnome_keyring_unlock_prompt_func(ctx.auth_baton, prompt_func_gnome_keyring_prompt)
 
   ra_callbacks = ra.callbacks_t()
   ra_callbacks.auth_baton = ctx.auth_baton

Modified: subversion/branches/reintegrate-keep-alive/tools/server-side/svnpredumpfilter.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/server-side/svnpredumpfilter.py?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/server-side/svnpredumpfilter.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/server-side/svnpredumpfilter.py Tue Mar  6 17:50:23 2012
@@ -114,12 +114,12 @@ def log(msg, min_verbosity):
     elif min_verbosity == 2:
       sys.stderr.write("[**] ")
     sys.stderr.write(msg + "\n")
-    
+
 class DependencyTracker:
   def __init__(self, include_paths):
     self.include_paths = include_paths[:]
     self.dependent_paths = []
-    
+
   def path_included(self, path):
     for include_path in self.include_paths + self.dependent_paths:
       if subsumes(include_path, path):
@@ -143,7 +143,7 @@ def readline(stream):
 def svn_log_stream_get_dependencies(stream, included_paths):
   import re
 
-  dt = DependencyTracker(included_paths)  
+  dt = DependencyTracker(included_paths)
 
   header_re = re.compile(r'^r([0-9]+) \|.*$')
   action_re = re.compile(r'^   [ADMR] /(.*)$')
@@ -153,7 +153,7 @@ def svn_log_stream_get_dependencies(stre
   eof = False
   path_copies = {}
   found_changed_path = False
-  
+
   while not eof:
     try:
       line = line_buf is not None and line_buf or readline(stream)
@@ -220,7 +220,7 @@ def svn_log_stream_get_dependencies(stre
     raise LogStreamError("No changed paths found; did you remember to run "
                          "'svn log' with the --verbose (-v) option when "
                          "generating the input to this script?")
-    
+
   return dt
 
 def analyze_logs(included_paths):
@@ -268,13 +268,13 @@ def usage_and_exit(errmsg=None):
 def main():
   config_dir = None
   targets_file = None
-  
+
   try:
     opts, args = getopt.getopt(sys.argv[1:], "hv",
                                ["help", "verbose", "targets="])
   except getopt.GetoptError, e:
     usage_and_exit(str(e))
-    
+
   for option, value in opts:
     if option in ['-h', '--help']:
       usage_and_exit()

Modified: subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnpubsub/client.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnpubsub/client.py?rev=1297604&r1=1295003&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnpubsub/client.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnpubsub/client.py Tue Mar  6 17:50:23 2012
@@ -145,8 +145,8 @@ class XMLStreamHandler(xml.sax.handler.C
 
 
 class Revision(object):
-  def __init__(self, repos, rev):
-    self.repos = repos
+  def __init__(self, uuid, rev):
+    self.uuid = uuid
     self.rev = rev
     self.dirs_changed = [ ]
     self.author = None

Modified: subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnpubsub/server.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnpubsub/server.py?rev=1297604&r1=1295003&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnpubsub/server.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnpubsub/server.py Tue Mar  6 17:50:23 2012
@@ -37,7 +37,7 @@
 #   URL is built into 3 parts:
 #       /${type}/${optional_repo_uuid}/${format}
 #
-#   If the repository UUID is included in the URl, you will only recieve 
+#   If the repository UUID is included in the URl, you will only receive
 #   messages about that repository.
 #
 # Example Pub clients:
@@ -88,7 +88,7 @@ class Revision:
                                           'author': self.author,
                                           'log': self.log,
                                           'date': self.date}}) +","
-        elif format == "xml": 
+        elif format == "xml":
             c = ET.Element('commit', {'repository': self.repos, 'revision': "%d" % (self.rev)})
             ET.SubElement(c, 'author').text = self.author
             ET.SubElement(c, 'date').text = self.date
@@ -107,7 +107,7 @@ class Revision:
             return json.dumps({'commit': {'repository': self.repos,
                                           'revision': self.rev,
                                           'dirs_changed': self.dirs_changed}}) +","
-        elif format == "xml": 
+        elif format == "xml":
             c = ET.Element('commit', {'repository': self.repos, 'revision': "%d" % (self.rev)})
             d = ET.SubElement(c, 'dirs_changed')
             for p in self.dirs_changed:
@@ -133,7 +133,7 @@ class Client(object):
     def finished(self, reason):
         self.alive = False
         log.msg("CLOSE: %s:%d (%d clients online)"% (self.r.getClientIP(), self.r.client.port, self.pubsub.cc()))
-        try: 
+        try:
             self.pubsub.remove(self)
         except ValueError:
             pass
@@ -210,11 +210,11 @@ class SvnPubSub(resource.Resource):
         else:
             fmt = uri[3]
             uuid = uri[2]
-        
+
         if type not in self.clients.keys():
             request.setResponseCode(400)
             return "Invalid Reuqest Type\n"
-        
+
         clients = {'json': JSONClient, 'xml': XMLClient}
         clientCls = clients.get(fmt)
         if clientCls == None:
@@ -262,7 +262,7 @@ def svnpubsub_server():
     root.putChild("commits", s)
     root.putChild("commit", s)
     return server.Site(root)
-  
+
 if __name__ == "__main__":
     log.startLogging(sys.stdout)
     # Port 2069 "HTTP Event Port", whatever, sounds good to me

Modified: subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svntweet.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svntweet.py?rev=1297604&r1=1295003&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svntweet.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svntweet.py Tue Mar  6 17:50:23 2012
@@ -21,7 +21,7 @@
 #
 # Example:
 #  svntweet.py  my-config.json
-#  
+#
 # With my-config.json containing stream paths and the twitter auth info:
 #    {"stream": "http://svn-master.apache.org:2069/commits/xml",
 #     "username": "asfcommits",
@@ -90,9 +90,9 @@ class Revision:
         self.log = None
         self.date = None
 
-class StreamHandler(handler.ContentHandler):   
+class StreamHandler(handler.ContentHandler):
     def __init__(self, bdec):
-        handler.ContentHandler.__init__(self) 
+        handler.ContentHandler.__init__(self)
         self.bdec =  bdec
         self.rev = None
         self.text_value = None
@@ -115,7 +115,7 @@ class StreamHandler(handler.ContentHandl
             self.bdec.stillalive()
     def characters(self, data):
         if self.text_value is not None:
-            self.text_value = self.text_value + data 
+            self.text_value = self.text_value + data
         else:
             self.text_value = data
 
@@ -179,7 +179,7 @@ class BigDoEverythingClasss(object):
     def pageStart(self):
         log.msg("Stream Connection Established")
         self.failures = 0
-        
+
     def _restartStream(self):
         (self.stream, self.transport) = connectTo(self.url, self)
         self.stream.deferred.addBoth(self.streamDead)
@@ -253,6 +253,6 @@ def main(config_file):
 if __name__ == "__main__":
     if len(sys.argv) != 2:
         print "invalid args, read source code"
-        sys.exit(0) 
+        sys.exit(0)
     log.startLogging(sys.stdout)
     main(sys.argv[1])

Modified: subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnwcsub.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnwcsub.py?rev=1297604&r1=1295003&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnwcsub.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/svnwcsub.py Tue Mar  6 17:50:23 2012
@@ -36,8 +36,9 @@ import os
 import re
 import ConfigParser
 import time
-import logging
+import logging.handlers
 import Queue
+import optparse
 
 from twisted.internet import reactor, task, threads
 from twisted.internet.utils import getProcessOutput
@@ -130,7 +131,7 @@ class WorkingCopy(object):
         uuid = info['Repository UUID']
         relpath = url[len(repos):]  # also has leading '/'
         return [relpath, url, repos, uuid]
-        
+
 
 class HTTPStream(HTTPClientFactory):
     protocol = HTTPPageDownloader
@@ -154,9 +155,9 @@ class Revision:
         self.rev = rev
         self.dirs_changed = []
 
-class StreamHandler(handler.ContentHandler):   
+class StreamHandler(handler.ContentHandler):
     def __init__(self, stream, bdec):
-        handler.ContentHandler.__init__(self) 
+        handler.ContentHandler.__init__(self)
         self.stream = stream
         self.bdec =  bdec
         self.rev = None
@@ -167,7 +168,7 @@ class StreamHandler(handler.ContentHandl
         """
         <commit revision="7">
                         <dirs_changed><path>/</path></dirs_changed>
-                      </commit> 
+                      </commit>
         """
         if name == "commit":
             self.rev = Revision(attrs['repository'], int(attrs['revision']))
@@ -175,7 +176,7 @@ class StreamHandler(handler.ContentHandl
             self.bdec.stillalive(self.stream)
     def characters(self, data):
         if self.text_value is not None:
-            self.text_value = self.text_value + data 
+            self.text_value = self.text_value + data
         else:
             self.text_value = data
 
@@ -230,7 +231,6 @@ class BigDoEverythingClasss(object):
         self.svnbin = config.get_value('svnbin')
         self.env = config.get_env()
         self.worker = BackgroundWorker(self.svnbin, self.env)
-        self.worker.start()
         self.service = service
         self.failures = 0
         self.alive = time.time()
@@ -333,12 +333,15 @@ class BackgroundWorker(threading.Thread)
         threading.Thread.__init__(self)
 
         # The main thread/process should not wait for this thread to exit.
-        self.daemon = True
+        ### compat with Python 2.5
+        self.setDaemon(True)
 
         self.svnbin = svnbin
         self.env = env
         self.q = Queue.Queue()
 
+        self.has_started = False
+
     def run(self):
         while True:
             if self.q.qsize() > BACKLOG_TOO_HIGH:
@@ -360,6 +363,12 @@ class BackgroundWorker(threading.Thread)
             self.q.task_done()
 
     def add_work(self, operation, wc):
+        # Start the thread when work first arrives. Thread-start needs to
+        # be delayed in case the process forks itself to become a daemon.
+        if not self.has_started:
+            self.start()
+            self.has_started = True
+
         self.q.put((operation, wc))
 
     def _update(self, wc):
@@ -443,21 +452,93 @@ class ReloadableConfig(ConfigParser.Safe
         return str(option)
 
 
-def main(config_file):
+def prepare_logging(logfile):
+    "Log to the specified file, or to stdout if None."
+
+    if logfile:
+        # Rotate logs daily, keeping 7 days worth.
+        handler = logging.handlers.TimedRotatingFileHandler(
+          logfile, when='midnight', backupCount=7,
+          )
+    else:
+        handler = logging.StreamHandler(sys.stdout)
+
+    # Add a timestamp to the log records
+    formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s',
+                                  '%Y-%m-%d %H:%M:%S')
+    handler.setFormatter(formatter)
+
+    # Apply the handler to the root logger
+    root = logging.getLogger()
+    root.addHandler(handler)
+    
+    ### use logging.INFO for now. switch to cmdline option or a config?
+    root.setLevel(logging.INFO)
+
+
+def handle_options(options):
+    # Set up the logging, then process the rest of the options.
+    prepare_logging(options.logfile)
+
+    if options.pidfile:
+        pid = os.getpid()
+        open(options.pidfile, 'w').write('%s\n' % pid)
+        logging.info('pid %d written to %s', pid, options.pidfile)
+
+    if options.uid:
+        try:
+            uid = int(options.uid)
+        except ValueError:
+            import pwd
+            uid = pwd.getpwnam(options.uid)[2]
+        logging.info('setting uid %d', uid)
+        os.setuid(uid)
+
+    if options.gid:
+        try:
+            gid = int(options.gid)
+        except ValueError:
+            import grp
+            gid = grp.getgrnam(options.gid)[2]
+        logging.info('setting gid %d', gid)
+        os.setgid(gid)
+
+    if options.umask:
+        umask = int(options.umask, 8)
+        os.umask(umask)
+        logging.info('umask set to %03o', umask)
+
+
+def main(args):
+    parser = optparse.OptionParser(
+        description='An SvnPubSub client to keep working copies synchronized '
+                    'with a repository.',
+        usage='Usage: %prog [options] CONFIG_FILE',
+        )
+    parser.add_option('--logfile',
+                      help='filename for logging')
+    parser.add_option('--pidfile',
+                      help="the process' PID will be written to this file")
+    parser.add_option('--uid',
+                      help='switch to this UID before running')
+    parser.add_option('--gid',
+                      help='switch to this GID before running')
+    parser.add_option('--umask',
+                      help='set this (octal) umask before running')
+
+    options, extra = parser.parse_args(args)
+
+    if len(extra) != 1:
+        parser.error('CONFIG_FILE is required')
+    config_file = extra[0]
+
+    # Process any provided options.
+    handle_options(options)
+
     c = ReloadableConfig(config_file)
     big = BigDoEverythingClasss(c)
     reactor.run()
 
 
 if __name__ == "__main__":
-    if len(sys.argv) != 2:
-        print "invalid args, read source code"
-        sys.exit(0)
-
-    ### use logging.INFO for now. review/adjust the calls above for the
-    ### proper logging level. then remove the level (to return to default).
-    ### future: switch to config for logfile and loglevel.
-    logging.basicConfig(level=logging.INFO, stream=sys.stdout,
-                        datefmt='%Y-%m-%d %H:%M:%S',
-                        format='%(asctime)s [%(levelname)s] %(message)s')
-    main(sys.argv[1])
+    main(sys.argv[1:])

Modified: subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/test.conf
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/test.conf?rev=1297604&r1=1295003&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/test.conf (original)
+++ subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/test.conf Tue Mar  6 17:50:23 2012
@@ -1,4 +1,9 @@
-# For use with testserver.py
+# For use with connecting to testserver.py
 
 [DEFAULT]
+svnbin: svn
 streams: http://127.0.0.1:2069/commits/xml
+
+[env]
+
+[track]

Modified: subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/watcher.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/watcher.py?rev=1297604&r1=1295003&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/watcher.py (original)
+++ subversion/branches/reintegrate-keep-alive/tools/server-side/svnpubsub/watcher.py Tue Mar  6 17:50:23 2012
@@ -53,5 +53,5 @@ def main(config_file):
 if __name__ == "__main__":
   if len(sys.argv) != 2:
     print "invalid args, read source code"
-    sys.exit(0) 
+    sys.exit(0)
   main(sys.argv[1])