The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# BEGIN BPS TAGGED BLOCK {{{
# COPYRIGHT:
# 
# This software is Copyright (c) 2003-2006 Best Practical Solutions, LLC
#                                          <clkao@bestpractical.com>
# 
# (Except where explicitly superseded by other copyright notices)
# 
# 
# LICENSE:
# 
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of either:
# 
#   a) Version 2 of the GNU General Public License.  You should have
#      received a copy of the GNU General Public License along with this
#      program.  If not, write to the Free Software Foundation, Inc., 51
#      Franklin Street, Fifth Floor, Boston, MA 02110-1301 or visit
#      their web page on the internet at
#      http://www.gnu.org/copyleft/gpl.html.
# 
#   b) Version 1 of Perl's "Artistic License".  You should have received
#      a copy of the Artistic License with this package, in the file
#      named "ARTISTIC".  The license is also available at
#      http://opensource.org/licenses/artistic-license.php.
# 
# This work is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
# 
# CONTRIBUTION SUBMISSION POLICY:
# 
# (The following paragraph is not intended to limit the rights granted
# to you to modify and distribute this software under the terms of the
# GNU General Public License and is only of importance to you if you
# choose to contribute your changes and enhancements to the community
# by submitting them to Best Practical Solutions, LLC.)
# 
# By intentionally submitting any modifications, corrections or
# derivatives to this work, or any other work intended for use with SVK,
# to Best Practical Solutions, LLC, you confirm that you are the
# copyright holder for those contributions and you grant Best Practical
# Solutions, LLC a nonexclusive, worldwide, irrevocable, royalty-free,
# perpetual, license to use, copy, create derivative works based on
# those contributions, and sublicense and distribute those contributions
# and any derivatives thereof.
# 
# END BPS TAGGED BLOCK }}}
package SVK::Command::Cmerge;
use strict;
use SVK::Version;  our $VERSION = $SVK::VERSION;

use base qw( SVK::Command::Merge SVK::Command::Copy SVK::Command::Propset );
use SVK::XD;
use SVK::I18N;
use SVK::Logger;
use SVK::Editor::Combine;
use SVK::Inspector::Compat;

sub options {
    ($_[0]->SUPER::options);
}

sub parse_arg {
    my $self = shift;
    $self->SVK::Command::Merge::parse_arg (@_);
}

sub lock {
    my $self = shift;
    $self->SVK::Command::Merge::lock (@_);
}

sub run {
    my ($self, $src, $dst) = @_;
    # XXX: support checkonly
   
    if ($0 =~ /svk$/) { 
        # Only warn about deprecation if the user is running svk. 
        # (Don't warn when running tests)                 
        $logger->warn(loc("%1 cmerge is deprecated, pending improvements to the Subversion API",$0));
        $logger->warn(loc("'Use %1 merge -c' to obtain similar functionality.",$0)."\n");
    }
    my @revlist = $self->parse_revlist($src);
    for my $r (@revlist) {
        die("Revision spec must be N:M.\n") unless defined($r->[1])
    }

    my $repos = $src->repos;
    my $fs = $repos->fs;
    my $base = SVK::Merge->auto (%$self, repos => $repos, src => $src, dst => $dst,
				 ticket => 1)->{base};
    # find a branch target
    die loc("cannot find a path for temporary branch")
	if $base->{path} eq '/';
    my $tmpbranch = "$src->{path}-merge-$$";

    $self->command (copy =>
		    { message => "preparing for cherry picking merging" }
		   )->run ($base => $src->new (path => $tmpbranch))
		       unless $self->{check_only};

    my $ceditor = SVK::Editor::Combine->new(tgt_anchor => $base->{path},
					    #$check_only ? $base_path : $tmpbranch,
					    base_root => $base->root,
					    pool => SVN::Pool->new,
					   );

    my $spool = SVN::Pool->new_default;
    my $inspector = SVK::Inspector::Compat->new({$ceditor->callbacks});
    for (@revlist) {
	my ($fromrev, $torev) = @$_;
	$logger->info(loc("Merging with base %1 %2: applying %3 %4:%5.",
		  @{$base}{qw/path revision/}, $src->{path}, $fromrev, $torev));

	SVK::Merge->new (%$self, repos => $repos,
			 base => $src->new (revision => $fromrev),
			 src => $src->new (revision => $torev), dst => $dst,
			)->run ($ceditor, 
			        inspector => $inspector,
				# XXX: should be base_root's rev?
				cb_rev => sub { $fs->youngest_rev });
	$spool->clear;
    }

    $ceditor->replay (SVN::Delta::Editor->new
		      (_debug => 0,
		       _editor => [ $repos->get_commit_editor
				    ('file://' . $src->depot->repospath,
				     $tmpbranch,
				     $ENV{USER}, "merge $self->{chgspec} from $src->{path}",
				     sub { $logger->info(loc("Committed revision %1.", $_[0])) })
				  ]),
		      $fs->youngest_rev);
    my $newrev = $fs->youngest_rev;
    my $uuid = $fs->get_uuid;

    # give ticket to src
    my $ticket = SVK::Merge->new (xd => $self->{xd})->
	find_merge_sources ($src->new (revision => $newrev), 1, 1);
    $ticket->{"$uuid:$tmpbranch"} = $newrev;

    unless ($self->{check_only}) {
	my $oldmessage = $self->{message};
	$self->{message} = "cherry picking merge $self->{chgspec} to $dst->{path}";
	$self->do_propset_direct ($src, 'svk:merge',
				  join ("\n", map {"$_:$ticket->{$_}"} sort keys %$ticket));
	$self->{message} = $oldmessage;
    }

    my ($depot) = $src->depotname;
    ++$self->{auto};
    undef $self->{chgspec};
    undef $self->{revspec};
    $self->SUPER::run ($src->new (path => $tmpbranch,
				  depotpath => "/$depot$tmpbranch",
				  revision => $fs->youngest_rev),
		       $dst);
    return;
}

1;

__DATA__

=head1 NAME

SVK::Command::Cmerge - Merge specific changes

=head1 SYNOPSIS

 This command is currently deprecated, pending improvements to the
 Subversion API. In the meantime, use C<svk merge -c> to obtain
 similar functionality.

 cmerge -c CHGSPEC DEPOTPATH [PATH]
 cmerge -c CHGSPEC DEPOTPATH1 DEPOTPATH2

=head1 OPTIONS

 -c [--change] REV      : act on comma-separated revisions REV 
 -l [--log]             : use logs of merged revisions as commit message
 -r [--revision] N:M    : act on revisions between N and M
 -a [--auto]            : merge from the previous merge point
 --verbatim             : verbatim merge log without indents and header
 --no-ticket            : do not record this merge point
 -m [--message] MESSAGE : specify commit message MESSAGE
 -F [--file] FILENAME   : read commit message from FILENAME
 --template             : use the specified message as the template to edit
 --encoding ENC         : treat -m/-F value as being in charset encoding ENC
 -P [--patch] NAME      : instead of commit, save this change as a patch
 -S [--sign]            : sign this change
 -C [--check-only]      : try operation but make no changes
 --direct               : commit directly even if the path is mirrored