Login | Register
My pages Projects Community openCollabNet

Discussions > cvs > CVS update: /svnutils/trunk/src/mergesvn

svnutils
Discussion topic

Back to topic list

CVS update: /svnutils/trunk/src/mergesvn

Author sunny256
Full name Øyvind A. Holm
Date 2007-03-05 08:45:52 PST
Message User: sunny256
Date: 2007-03-05 08:45:52-0800
Log:
 r186 | sunny256 | 2007-03-05 16:35:47 +0000 (Mon, 05 Mar 2007) | 5 lines
 
 * /trunk/src/mergesvn
   Added the "-C"/"--conflict" functionality — scan for the first
   revision a conflict occurs so the merges can be taken in smaller steps
   with the -t option.

File Changes:

Directory: /svnutils/trunk/src/
===============================

File [changed]: mergesvn
Url: http://svnutils.tigr​is.org/source/browse​/svnutils/trunk/src/​mergesvn?r1=1.11​&r2=1.12
Delta lines: +127 -6
---------------------
--- mergesvn 2007-03-05 08:45:12-0800 1.11
+++ mergesvn 2007-03-05 08:45:49-0800 1.12
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -w
 
 #===================​====================​====================​============
-# $Id: mergesvn 185 2007-03-05 11:00:31Z sunny256 $
+# $Id: mergesvn 186 2007-03-05 16:35:47Z sunny256 $
 # Merges new changes into a file version controlled by Subversion.
 #
 # Character set: UTF-8
@@ -20,6 +20,7 @@
 
 our %Opt = (
     'alias' => "",
+ 'conflict' => 0,
     'debug' => 0,
     'diff' => 0,
     'dry-run' => 0,
@@ -31,13 +32,14 @@
 our $progname = $0;
 $progname =~ s#^.*/(.*?)$#$1#;
 
-my $rcs_id = '$Id: mergesvn 185 2007-03-05 11:00:31Z sunny256 $';
+my $rcs_id = '$Id: mergesvn 186 2007-03-05 16:35:47Z sunny256 $';
 my $id_date = $rcs_id;
 $id_date =~ s/^.*?\d+ (\d\d\d\d-.*?\d​\d:\d\d:\d\d\S​+).*/$1/;
 
 Getopt::Long::Config​ure("bundling");
 GetOptions(
     "alias|a=s" => \$Opt{'alias'},
+ "conflict|C" => \$Opt{'conflict'},
     "debug" => \$Opt{'debug'},
     "diff|d" => \$Opt{'diff'},
     "dry-run" => \$Opt{'dry-run'},
@@ -90,6 +92,10 @@
                      "Unable to get newest revision\n");
                 next LOOP;
             }
+ if ($Opt{'conflict'}) {
+ find_conflict($master_file, $File, $last_merge, $curr_rev);
+ next LOOP;
+ }
             if ($Opt{'diff'}) {
                 my $Repos = repos_url($File);
                 mysyst(
@@ -122,6 +128,107 @@
     # }}}
 }
 
+sub find_conflict {
+ # Scan a specific revision range for the first merge conflict and
+ # return the revision number
+ # {{{
+ my ($Src, $Dest, $Start, $End) = @_;
+
+ D("find_conflict('$Src', '$Dest', '$Start', '$End')");
+ print("$progname: $Dest: Scanning revision range r$Start:$End " .
+ "for conflicts\n");
+ my @Array = revisions($Src, $Start, $End);
+ if (!scalar(@Array)) {
+ print("No revisions found.\n");
+ return undef;
+ }
+
+ my $rev_count = scalar(@Array);
+ printf("$rev_count revision%s to check\n", $rev_count == 1 ? "" : "s");
+ print("(" . join(", ", @Array) . ")\n");
+
+ my $min_block = 0;
+ my ($min_pos, $max_pos) = (0, $rev_count);
+
+ my $last_mid = 0;
+ my $first_conflict = 0;
+ my $last_good = 0;
+
+ while (1) {
+ my $mid_pos = int(($min_pos + $max_pos) / 2);
+ last if ($mid_pos == $last_mid);
+ my $Rev = $Array[$mid_pos];
+ print("Checking revision $Rev ($mid_pos)...");
+ if (!has_conflict($Src, $Dest, $Start, $Rev)) {
+ print("No conflict\n");
+ $min_pos = $mid_pos;
+ D("min_pos set to '$mid_pos'");
+ if (!$last_good || ($Rev > $last_good)) {
+ $last_good = $Rev;
+ }
+ } else {
+ print("Conflict\n");
+ $max_pos = $mid_pos;
+ D("max_pos set to '$mid_pos'");
+ if (!$first_conflict || ($Rev < $first_conflict)) {
+ $first_conflict = $Rev;
+ }
+ }
+ $last_mid = $mid_pos;
+ }
+ print($first_conflict
+ ? "First conflict at r$first_conflict. "
+ : "No conflicts found. "
+ );
+ print($last_good
+ ? "Last revision without conflict at r$last_good.\n"
+ : "No revisions without conflicts found.\n"
+ );
+
+ # }}}
+} # find_conflict()
+
+sub has_conflict {
+ # {{{
+ my ($Src, $Dest, $Start, $End) = @_;
+ my ( $safe_src, $safe_dest) =
+ (escape_filename($Src), escape_filename($Dest));
+ my $Retval = 0;
+ D("has_conflict('$Src', '$Dest', '$Start', '$End')");
+ if (open(ConflFP, "$CMD_SVN merge --dry-run " .
+ "-r$Start:$End $safe_src $safe_dest |")) {
+ while (<ConflFP>) {
+ my $Stat = substr($_, 0, 2);
+ ($Stat =~ /C/) && ($Retval = 1);
+ }
+ close(ConflFP);
+ }
+ return($Retval);
+ # }}}
+} # has_conflict()
+
+sub revisions {
+ # Return an array of revision numbers from a specific revision range
+ # for a version controlled element
+ # {{{
+ my ($File, $Start, $End) = @_;
+ D("revisions('$File', '$Start', '$End')");
+ my $safe_file = escape_filename($File);
+ my $Data = "";
+ my @Revs = ();
+
+ if (open(PipeFP, "svn log --xml -r$Start:$End $safe_file |")) {
+ $Data = join("", <PipeFP>);
+ close(PipeFP);
+ $Data =~ s/<logentry\b.*?​\brevision="(\d+)"​.*?>/push(@Revs, "$1")/egs;
+ }
+ if ($Revs[0] eq $Start) {
+ splice(@Revs, 0, 1);
+ }
+ return(@Revs);
+ # }}}
+} # revisions()
+
 sub highest_revision {
     # Return the newest revision of a versioned element inside a
     # specified revision range
@@ -139,10 +246,10 @@
     my $File = shift;
     my $safe_file = escape_filename($File);
     my $Retval = `$CMD_SVN info --xml $safe_file`;
- $Retval =~ s/^.*<url>(.*?​)<\/url>.*$/​$1/s;
+ $Retval =~ s/^.*<url>(.*?​)<\/url>.*$/​$1/s; # FIXME: Add XML parsing
     return($Retval);
     # }}}
-}
+} # repos_url()
 
 sub mysyst {
     # Customised system() {{{
@@ -203,6 +310,12 @@
   -a x, --alias x
     Use x as alias for the master URL. The old value will still be
     written to the mergesvn property.
+ -c, --conflict
+ Do not merge, but search for the first revision a conflict will
+ occur when a merge is done. After the search is finished, the first
+ revision number of a troublesome patch is printed, and you can
+ choose by using the -t option if you want to include the conflicting
+ revision in the merge.
   -d, --diff
     Instead of merging, show a repository diff between the master URL
     and the versioned element.
@@ -248,7 +361,7 @@
 
 =head1 REVISION
 
-$Id: mergesvn 185 2007-03-05 11:00:31Z sunny256 $
+$Id: mergesvn 186 2007-03-05 16:35:47Z sunny256 $
 
 =head1 SYNOPSIS
 
@@ -284,6 +397,14 @@
 Use I<x> as alias for the master URL. The old value will still be
 written to the mergesvn property.
 
+=item B<-c>, B<--conflict>
+
+Do not merge, but search for the first revision a conflict will occur
+when a merge is done. After the search is finished, the first revision
+number of a troublesome patch is printed, and you can choose by using
+the -t option if you want to include the conflicting revision in the
+merge.
+
 =item B<-d>, B<--diff>
 
 Instead of merging, show a repository diff between the master URL and
@@ -356,4 +477,4 @@
 # }}}
 
 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :
-# End of file $Id: mergesvn 185 2007-03-05 11:00:31Z sunny256 $
+# End of file $Id: mergesvn 186 2007-03-05 16:35:47Z sunny256 $

« Previous message in topic | 1 of 1 | Next message in topic »

Messages

Show all messages in topic

CVS update: /svnutils/trunk/src/mergesvn sunny256 Øyvind A. Holm 2007-03-05 08:45:52 PST
Messages per page: