You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2014/03/09 11:08:53 UTC

svn commit: r1575685 [13/13] - in /subversion/branches/fsfs-ucsnorm: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/cgi/ contrib/client-side/emacs/ contrib/client-side/svn2cl/ contrib/hook-scripts/ contrib/server-side/sv...

Modified: subversion/branches/fsfs-ucsnorm/tools/dist/backport.pl
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/tools/dist/backport.pl?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/tools/dist/backport.pl (original)
+++ subversion/branches/fsfs-ucsnorm/tools/dist/backport.pl Sun Mar  9 10:08:46 2014
@@ -20,24 +20,27 @@ use feature qw/switch say/;
 # specific language governing permissions and limitations
 # under the License.
 
+use Carp qw/croak confess carp cluck/;
 use Digest ();
 use Term::ReadKey qw/ReadMode ReadKey/;
 use File::Basename qw/basename dirname/;
 use File::Copy qw/copy move/;
 use File::Temp qw/tempfile/;
-use POSIX qw/ctermid strftime/;
+use POSIX qw/ctermid strftime isprint isspace/;
 use Text::Wrap qw/wrap/;
 use Tie::File ();
 
 ############### Start of reading values from environment ###############
 
 # Programs we use.
+#
+# TODO: document which are interpreted by sh and which should point to binary.
 my $SVNAUTH = $ENV{SVNAUTH} // 'svnauth'; # optional dependency
 my $SVN = $ENV{SVN} || 'svn'; # passed unquoted to sh
 my $SHELL = $ENV{SHELL} // '/bin/sh';
 my $VIM = 'vim';
 my $EDITOR = $ENV{SVN_EDITOR} // $ENV{VISUAL} // $ENV{EDITOR} // 'ed';
-my $PAGER = $ENV{PAGER} // 'less -F' // 'cat';
+my $PAGER = $ENV{PAGER} // 'less' // 'cat';
 
 # Mode flags.
 #    svn-role:      YES=1 MAY_COMMIT=1      (plus '--renormalize')
@@ -73,7 +76,7 @@ my ($AVAILID) = $ENV{AVAILID} // do {
 my $STATUS = './STATUS';
 my $STATEFILE = './.backports1';
 my $BRANCHES = '^/subversion/branches';
-$ENV{LC_ALL} = "C";  # since we parse 'svn info' output
+$ENV{LC_ALL} = "C";  # since we parse 'svn info' output and use isprint()
 
 # Globals.
 my %ERRORS = ();
@@ -200,10 +203,17 @@ sub prompt {
   my %args = @_;
   my $getchar = sub {
     my $answer;
-    ReadMode 'cbreak';
-    eval { $answer = (ReadKey 0) };
-    ReadMode 'normal';
-    die $@ if $@;
+    do {
+      ReadMode 'cbreak';
+      $answer = (ReadKey 0);
+      ReadMode 'normal';
+      die if $@ or not defined $answer;
+      # Swallow terminal escape codes (e.g., arrow keys).
+      unless (isprint $answer or isspace $answer) {
+        $answer = (ReadKey -1) while defined $answer;
+        # TODO: provide an indication that the keystroke was sensed and ignored.
+      }
+    } until defined $answer and (isprint $answer or isspace $answer);
     print $answer;
     return $answer;
   };
@@ -217,41 +227,57 @@ sub prompt {
          : ($answer =~ /^y/i) ? 1 : 0;
 }
 
+# Bourne-escape a string.
+# Example:
+#     >>> shell_escape(q[foo'bar]) eq q['foo'\''bar']
+#     True
+sub shell_escape {
+  map {
+    local $_ = $_; # the LHS $_ is mutable; the RHS $_ may not be.
+    s/\x27/'\\\x27'/g;
+    "'$_'"
+  } @_
+}
+
+sub shell_safe_path_or_url($) {
+  local $_ = shift;
+  return m{^[A-Za-z0-9._:+/-]+$} and !/^-|^[+]/;
+}
+  
+# Shell-safety-validating wrapper for File::Temp::tempfile
+sub my_tempfile {
+  my ($fh, $fn) = tempfile();
+  croak "Tempfile name '$fn' not shell-safe; aborting"
+        unless shell_safe_path_or_url $fn;
+  return ($fh, $fn);
+}
+
 
 sub merge {
   my %entry = @_;
-  $MERGED_SOMETHING++;
 
-  my ($logmsg_fh, $logmsg_filename) = tempfile();
-  my ($mergeargs, $pattern);
+  my ($logmsg_fh, $logmsg_filename) = my_tempfile();
+  my (@mergeargs);
 
-  # Include the time so it's easier to find the interesting backups.
-  my $backupfile = strftime "backport_pl.%Y%m%d-%H%M%S.$$.tmp", localtime;
-  die if -s $backupfile;
+  my $shell_escaped_branch = shell_escape($entry{branch})
+    if defined($entry{branch});
 
   if ($entry{branch}) {
-    my $vim_escaped_branch = 
-      join "",
-      map { sprintf '\[%s%s]', $_, ($_ x ($_ eq '\\')) }
-      split //,
-      $entry{branch};
-    $pattern = sprintf '\VBranch: \*\n\? \*\(\.\*\/branches\/\)\?%s',
-                 $vim_escaped_branch;
     if ($SVNvsn >= 1_008_000) {
-      $mergeargs = "$BRANCHES/$entry{branch}";
+      @mergeargs = shell_escape "$BRANCHES/$entry{branch}";
       say $logmsg_fh "Merge $entry{header}:";
     } else {
-      $mergeargs = "--reintegrate $BRANCHES/$entry{branch}";
+      @mergeargs = shell_escape qw/--reintegrate/, "$BRANCHES/$entry{branch}";
       say $logmsg_fh "Reintegrate $entry{header}:";
     }
     say $logmsg_fh "";
   } elsif (@{$entry{revisions}}) {
-    $pattern = '^ *[*] \V' . 'r' . $entry{revisions}->[0];
-    $mergeargs = join " ",
+    @mergeargs = shell_escape(
       ($entry{accept} ? "--accept=$entry{accept}" : ()),
       (map { "-c$_" } @{$entry{revisions}}),
       '--',
-      '^/subversion/trunk';
+      '^/subversion/trunk',
+    );
     say $logmsg_fh
       "Merge $entry{header} from trunk",
       $entry{accept} ? ", with --accept=$entry{accept}" : "",
@@ -270,16 +296,8 @@ set -e
 if $sh[$DEBUG]; then
   set -x
 fi
-$SVN diff > $backupfile
-if ! $sh[$MAY_COMMIT] ; then
-  cp STATUS STATUS.$$
-fi
-$SVNq revert -R .
-if ! $sh[$MAY_COMMIT] ; then
-  mv STATUS.$$ STATUS
-fi
 $SVNq up
-$SVNq merge $mergeargs
+$SVNq merge @mergeargs
 if [ "`$SVN status -q | wc -l`" -eq 1 ]; then
   if [ -n "`$SVN diff | perl -lne 'print if s/^(Added|Deleted|Modified): //' | grep -vx svn:mergeinfo`" ]; then
     # This check detects STATUS entries that name non-^/subversion/ revnums.
@@ -294,7 +312,7 @@ if $sh[$MAY_COMMIT]; then
   # Remove the approved entry.  The sentinel guarantees the right number of blank
   # lines is removed, which prevents spurious '--renormalize' commits tomorrow.
   echo "sentinel" >> $STATUS
-  $VIM -e -s -n -N -i NONE -u NONE -c '/$pattern/normal! dap' -c wq $STATUS
+  $VIM -e -s -n -N -i NONE -u NONE -c ':0normal! $entry{parno}\x{7d}kdap' -c wq $STATUS
   $VIM -e -s -n -N -i NONE -u NONE -c '\$d' -c wq $STATUS
   $SVNq commit -F $logmsg_filename
 elif ! $sh[$YES]; then
@@ -312,24 +330,33 @@ reinteg_rev=\`$SVN info $STATUS | sed -n
 if $sh[$MAY_COMMIT]; then
   # Sleep to avoid out-of-order commit notifications
   if $sh[$YES]; then sleep 15; fi
-  $SVNq rm $BRANCHES/$entry{branch} -m "Remove the '$entry{branch}' branch, $reintegrated_word in r\$reinteg_rev."
+  $SVNq rm $BRANCHES/$shell_escaped_branch -m "Remove the '"$shell_escaped_branch"' branch, $reintegrated_word in r\$reinteg_rev."
   if $sh[$YES]; then sleep 1; fi
 elif ! $sh[$YES]; then
-  echo "Would remove $reintegrated_word '$entry{branch}' branch"
+  echo "Would remove $reintegrated_word '"$shell_escaped_branch"' branch"
 fi
 EOF
 
-  open SHELL, '|-', qw#/bin/sh# or die "$! (in '$entry{header}')";
-  print SHELL $script;
-  close SHELL or warn "$0: sh($?): $! (in '$entry{header}')";
-  $ERRORS{$entry{id}} = [\%entry, "sh($?): $!"] if $?;
-
+  # Include the time so it's easier to find the interesting backups.
+  my $backupfile = strftime "backport_pl.%Y%m%d-%H%M%S.$$.tmp", localtime;
+  die if -s $backupfile;
+  system("$SVN diff > $backupfile") == 0
+    or die "Saving a backup diff ($backupfile) failed ($?): $!";
   if (-z $backupfile) {
     unlink $backupfile;
   } else {
     warn "Local mods saved to '$backupfile'\n";
   }
 
+  # If $MAY_COMMIT, then $script will edit STATUS anyway.
+  revert(verbose => 0, discard_STATUS => $MAY_COMMIT);
+
+  $MERGED_SOMETHING++;
+  open SHELL, '|-', qw#/bin/sh# or die "$! (in '$entry{header}')";
+  print SHELL $script;
+  close SHELL or warn "$0: sh($?): $! (in '$entry{header}')";
+  $ERRORS{$entry{id}} = [\%entry, "sh($?): $!"] if $?;
+
   unlink $logmsg_filename unless $? or $!;
 }
 
@@ -362,6 +389,7 @@ sub logsummarysummary {
 # TODO: may need to parse other headers too?
 sub parse_entry {
   my $raw = shift;
+  my $parno = shift;
   my @lines = @_;
   my $depends;
   my $accept;
@@ -454,6 +482,7 @@ sub parse_entry {
     accept => $accept,
     raw => $raw,
     digest => digest_entry($raw),
+    parno => $parno, # $. from backport_main()
   );
 }
 
@@ -465,7 +494,7 @@ sub edit_string {
   my $name = shift;
   my %args = @_;
   my $trailing_eol = $args{trailing_eol};
-  my ($fh, $fn) = tempfile;
+  my ($fh, $fn) = my_tempfile();
   print $fh $string;
   $fh->flush or die $!;
   system("$EDITOR -- $fn") == 0
@@ -577,12 +606,9 @@ sub vote {
   system "$SVN diff -- $STATUS";
   printf "[[[\n%s%s]]]\n", $logmsg, ("\n" x ($logmsg !~ /\n\z/));
   if (prompt "Commit these votes? ") {
-    my ($logmsg_fh, $logmsg_filename) = tempfile();
+    my ($logmsg_fh, $logmsg_filename) = my_tempfile();
     print $logmsg_fh $logmsg;
     close $logmsg_fh;
-    warn("Tempfile name '$logmsg_filename' not shell-safe; "
-         ."refraining from commit.\n") and return
-        unless $logmsg_filename =~ /^([A-Z0-9._-]|\x2f)+$/i;
     system("$SVN commit -F $logmsg_filename -- $STATUS") == 0
         or warn("Committing the votes failed($?): $!") and return;
     unlink $logmsg_filename;
@@ -607,13 +633,24 @@ sub check_local_mods_to_STATUS {
 
 sub renormalize_STATUS {
   my $vimscript = <<'EOVIM';
-:"" Strip trailing whitespace.
-:%s/\s*$//
+:"" Strip trailing whitespace before entries and section headers, but not
+:"" inside entries (e.g., multi-paragraph Notes: fields).
+:""
+:"" Since an entry is always followed by another entry, section header, or EOF,
+:"" there is no need to separately strip trailing whitespace from lines following
+:"" entries.
+:%s/\v\s+\n(\s*\n)*\ze(\s*[*]|\w)/\r\r/g
+
 :"" Ensure there is exactly one blank line around each entry and header.
+:""
+:"" First, inject a new empty line above and below each entry and header; then,
+:"" squeeze runs of empty lines together.
 :0/^=/,$ g/^ *[*]/normal! O
 :g/^=/normal! o
 :g/^=/-normal! O
+:
 :%s/\n\n\n\+/\r\r/g
+
 :"" Save.
 :wq
 EOVIM
@@ -628,11 +665,16 @@ EOVIM
 }
 
 sub revert {
-  copy $STATUS, "$STATUS.$$.tmp";
-  system "$SVN revert -q $STATUS";
-  system "$SVN revert -R ./" . ($YES && !$MAY_COMMIT
-                             ? " -q" : "");
-  move "$STATUS.$$.tmp", $STATUS;
+  my %args = @_;
+  die "Bug: \$args{verbose} undefined" unless exists $args{verbose};
+  die "Bug: unknown argument" if grep !/^(?:verbose|discard_STATUS)$/, keys %args;
+
+  copy $STATUS, "$STATUS.$$.tmp"        unless $args{discard_STATUS};
+  system("$SVN revert -q $STATUS") == 0
+    or die "revert failed ($?): $!";
+  system("$SVN revert -R ./" . (" -q" x !$args{verbose})) == 0
+    or die "revert failed ($?): $!";
+  move "$STATUS.$$.tmp", $STATUS        unless $args{discard_STATUS};
   $MERGED_SOMETHING = 0;
 }
 
@@ -640,7 +682,7 @@ sub maybe_revert {
   # This is both a SIGINT handler, and the tail end of main() in normal runs.
   # @_ is 'INT' in the former case and () in the latter.
   delete $SIG{INT} unless @_;
-  revert if !$YES and $MERGED_SOMETHING and prompt 'Revert? ';
+  revert verbose => 1 if !$YES and $MERGED_SOMETHING and prompt 'Revert? ';
   (@_ ? exit : return);
 }
 
@@ -705,9 +747,10 @@ sub handle_entry {
   my $votes = shift;
   my $state = shift;
   my $raw = shift;
+  my $parno = shift;
   my $skip = shift;
-  my %entry = parse_entry $raw, @_;
-  my @vetoes = grep { /^  -1:/ } @{$entry{votes}};
+  my %entry = parse_entry $raw, $parno, @_;
+  my @vetoes = grep /^\s*-1:/, @{$entry{votes}};
 
   my $match = defined($skip) ? ($raw =~ /\Q$skip\E/ or $raw =~ /$skip/msi) : 0
               unless $YES;
@@ -723,7 +766,11 @@ sub handle_entry {
         merge %entry;
 
         my $output = `$SVN status`;
-        my (@conflicts) = ($output =~ m#^(?:C...|.C..|...C)...\s(.*)#mg);
+
+        # Pre-1.6 svn's don't have the 7th column, so fake it.
+        $output =~ s/^(......)/$1 /mg if $SVNvsn < 1_006_000;
+
+        my (@conflicts) = ($output =~ m#^(?:C......|.C.....|......C)\s(.*)#mg);
         if (@conflicts and !$entry{depends}) {
           $ERRORS{$entry{id}} //= [\%entry,
                                    sprintf "Conflicts on %s%s%s",
@@ -736,7 +783,7 @@ sub handle_entry {
           say STDERR "Conflicts merging $entry{header}!";
           say STDERR "";
           say STDERR $output;
-          system "$SVN diff -- @conflicts";
+          system "$SVN diff -- " . join ' ', shell_escape @conflicts;
         } elsif (!@conflicts and $entry{depends}) {
           # Not a warning since svn-role may commit the dependency without
           # also committing the dependent in the same pass.
@@ -745,7 +792,7 @@ sub handle_entry {
         } elsif (@conflicts) {
           say "Conflicts found merging $entry{header}, as expected.";
         }
-        revert;
+        revert verbose => 0;
       }
     }
   } elsif (defined($skip) ? not $match : $state->{$entry{digest}}) {
@@ -795,7 +842,7 @@ sub handle_entry {
               next;
             }
           }
-          revert;
+          revert verbose => 1;
           next PROMPT;
         }
         # NOTREACHED
@@ -803,7 +850,7 @@ sub handle_entry {
       when (/^l/i) {
         if ($entry{branch}) {
             system "$SVN log --stop-on-copy -v -g -r 0:HEAD -- "
-                   ."$BRANCHES/$entry{branch} "
+                   .shell_escape("$BRANCHES/$entry{branch}")." "
                    ."| $PAGER";
         } elsif (@{$entry{revisions}}) {
             system "$SVN log ".(join ' ', map { "-r$_" } @{$entry{revisions}})
@@ -836,6 +883,7 @@ sub handle_entry {
         my $original = $entry{raw};
         $entry{raw} = edit_string $entry{raw}, $entry{header},
                         trailing_eol => 2;
+        # TODO: parse the edited entry (empty lines, logsummary+votes, etc.)
         $votes->{$key} = ['edit', \%entry] # marker for the 2nd pass
             if $original ne $entry{raw};
         last PROMPT;
@@ -870,9 +918,10 @@ sub backport_main {
   my %approved;
   my %votes;
   my $state = read_state;
+  my $renormalize;
 
   if (@ARGV && $ARGV[0] eq '--renormalize') {
-    renormalize_STATUS;
+    $renormalize = 1;
     shift;
   }
 
@@ -884,8 +933,9 @@ sub backport_main {
   open STATUS, "<", $STATUS or (backport_usage, exit 1);
 
   # Because we use the ':normal' command in Vim...
-  die "A vim with the +ex_extra feature is required for \$MAY_COMMIT mode"
-      if $MAY_COMMIT and `${VIM} --version` !~ /[+]ex_extra/;
+  die "A vim with the +ex_extra feature is required for --renormalize and "
+      ."\$MAY_COMMIT modes"
+      if ($renormalize or $MAY_COMMIT) and `${VIM} --version` !~ /[+]ex_extra/;
 
   # ### TODO: need to run 'revert' here
   # ### TODO: both here and in merge(), unlink files that previous merges added
@@ -895,6 +945,7 @@ sub backport_main {
     or die "$0: svn error; point \$SVN to an appropriate binary";
 
   check_local_mods_to_STATUS;
+  renormalize_STATUS if $renormalize;
 
   # Skip most of the file
   $/ = ""; # paragraph mode
@@ -928,7 +979,8 @@ sub backport_main {
       when (/^ *\*/) {
         warn "Too many bullets in $lines[0]" and next
           if grep /^ *\*/, @lines[1..$#lines];
-        handle_entry $in_approved, \%approved, \%votes, $state, $lines, $skip,
+        handle_entry $in_approved, \%approved, \%votes, $state, $lines, $.,
+                     $skip,
                      @lines;
       }
       default {
@@ -959,7 +1011,7 @@ sub nominate_main {
   my ($URL) = `$SVN info` =~ /^URL: (.*)$/m;
   die "Can't retrieve URL of cwd" unless $URL;
 
-  die if $URL !~ m%^[A-Za-z0-9:_.+/][A-Za-z0-9:_.+/-]*$%;
+  die unless shell_safe_path_or_url $URL;
   system "$SVN info -- $URL-r$revnums[0] 2>/dev/null";
   my $branch = ($? == 0) ? basename("$URL-r$revnums[0]") : undef;
 

Modified: subversion/branches/fsfs-ucsnorm/tools/server-side/fsfs-stats.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/tools/server-side/fsfs-stats.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/tools/server-side/fsfs-stats.c (original)
+++ subversion/branches/fsfs-ucsnorm/tools/server-side/fsfs-stats.c Sun Mar  9 10:08:46 2014
@@ -355,7 +355,6 @@ get_content(svn_stringbuf_t **content,
   *content = svn_stringbuf_create_ensure(len, pool);
   (*content)->len = len;
 
-#if APR_VERSION_AT_LEAST(1,3,0)
   /* for better efficiency use larger buffers on large reads */
   if (   (len >= large_buffer_size)
       && (apr_file_buffer_size_get(file) < large_buffer_size))
@@ -363,7 +362,6 @@ get_content(svn_stringbuf_t **content,
                         apr_palloc(apr_file_pool_get(file),
                                    large_buffer_size),
                         large_buffer_size);
-#endif
 
   SVN_ERR(svn_io_file_seek(file, APR_SET, &offset, pool));
   SVN_ERR(svn_io_file_read_full2(file, (*content)->data, len,
@@ -1551,9 +1549,14 @@ read_revisions(fs_t **fs,
   SVN_ERR(fs_open(fs, path, pool));
   ffd = (*fs)->fs->fsap_data;
 
-  /* create data containers and caches */
+  /* create data containers and caches
+   * Note: this assumes that int is at least 32-bits and that we only support
+   * 32-bit wide revision numbers (actually 31-bits due to the signedness
+   * of both the nelts field of the array and our revision numbers). This
+   * means this code will fail on platforms where int is less than 32-bits
+   * and the repository has more revisions than int can hold. */
   (*fs)->revisions = apr_array_make(pool,
-                                    ffd->youngest_rev_cache + 1,
+                                    (int) ffd->youngest_rev_cache + 1,
                                     sizeof(revision_info_t *));
   (*fs)->null_base = apr_pcalloc(pool, sizeof(*(*fs)->null_base));
   initialize_largest_changes(*fs, 64, pool);

Modified: subversion/branches/fsfs-ucsnorm/tools/server-side/mod_dontdothat/mod_dontdothat.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/tools/server-side/mod_dontdothat/mod_dontdothat.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/tools/server-side/mod_dontdothat/mod_dontdothat.c (original)
+++ subversion/branches/fsfs-ucsnorm/tools/server-side/mod_dontdothat/mod_dontdothat.c Sun Mar  9 10:08:46 2014
@@ -40,7 +40,7 @@
 #include "svn_path.h"
 #include "private/svn_fspath.h"
 
-module AP_MODULE_DECLARE_DATA dontdothat_module;
+extern module AP_MODULE_DECLARE_DATA dontdothat_module;
 
 typedef struct dontdothat_config_rec {
   const char *config_file;

Modified: subversion/branches/fsfs-ucsnorm/win-tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/win-tests.py?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/win-tests.py (original)
+++ subversion/branches/fsfs-ucsnorm/win-tests.py Sun Mar  9 10:08:46 2014
@@ -117,10 +117,6 @@ cp = configparser.ConfigParser()
 cp.read('gen-make.opts')
 gen_obj = gen_win_dependencies.GenDependenciesBase('build.conf', version_header,
                                                    cp.items('options'))
-all_tests = gen_obj.test_progs + gen_obj.bdb_test_progs \
-          + gen_obj.scripts + gen_obj.bdb_scripts
-client_tests = [x for x in all_tests if x.startswith(CMDLINE_TEST_SCRIPT_PATH)]
-
 opts, args = my_getopt(sys.argv[1:], 'hrdvqct:pu:f:',
                        ['release', 'debug', 'verbose', 'quiet', 'cleanup',
                         'test=', 'url=', 'svnserve-args=', 'fs-type=', 'asp.net-hack',
@@ -257,9 +253,13 @@ else:
 if not fs_type:
   fs_type = 'fsfs'
 
-# Don't run bdb tests if they want to test fsfs
-if fs_type == 'fsfs':
-  all_tests = gen_obj.test_progs + gen_obj.scripts
+if fs_type == 'bdb':
+  all_tests = gen_obj.test_progs + gen_obj.bdb_test_progs \
+            + gen_obj.scripts + gen_obj.bdb_scripts
+else:
+  all_tests = gen_obj.test_progs + gen_obj.scripts            
+
+client_tests = [x for x in all_tests if x.startswith(CMDLINE_TEST_SCRIPT_PATH)]
 
 if run_httpd:
   if not httpd_port: