Staging
v0.5.1
Revision 7d09fbe4ab7f080a8f8f5dcef7e0f3edf5e26019 authored by Serge E. Hallyn on 18 April 2006, 13:11:06 UTC, committed by Junio C Hamano on 25 April 2006, 06:07:54 UTC
The set_reuse_addr() error case was the only error case in
socklist() where we returned rather than continued.  Not sure
why.  Either we must free the socklist, or continue.  This patch
continues on error.

Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
(cherry picked from 0032d548db56eac9ea09b4ba05843365f6325b85 commit)
1 parent 1ab661d
Raw File
git-mv.perl
#!/usr/bin/perl
#
# Copyright 2005, Ryan Anderson <ryan@michonline.com>
#                 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
#
# This file is licensed under the GPL v2, or a later version
# at the discretion of Linus Torvalds.


use warnings;
use strict;
use Getopt::Std;

sub usage() {
	print <<EOT;
$0 [-f] [-n] <source> <destination>
$0 [-f] [-n] [-k] <source> ... <destination directory>
EOT
	exit(1);
}

our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v);
getopts("hnfkv") || usage;
usage() if $opt_h;
@ARGV >= 1 or usage;

my $GIT_DIR = `git rev-parse --git-dir`;
exit 1 if $?; # rev-parse would have given "not a git dir" message.
chomp($GIT_DIR);

my (@srcArgs, @dstArgs, @srcs, @dsts);
my ($src, $dst, $base, $dstDir);

# remove any trailing slash in arguments
for (@ARGV) { s/\/*$//; }

my $argCount = scalar @ARGV;
if (-d $ARGV[$argCount-1]) {
	$dstDir = $ARGV[$argCount-1];
	@srcArgs = @ARGV[0..$argCount-2];

	foreach $src (@srcArgs) {
		$base = $src;
		$base =~ s/^.*\///;
		$dst = "$dstDir/". $base;
		push @dstArgs, $dst;
	}
}
else {
    if ($argCount < 2) {
	print "Error: need at least two arguments\n";
	exit(1);
    }
    if ($argCount > 2) {
	print "Error: moving to directory '"
	    . $ARGV[$argCount-1]
	    . "' not possible; not existing\n";
	exit(1);
    }
    @srcArgs = ($ARGV[0]);
    @dstArgs = ($ARGV[1]);
    $dstDir = "";
}

my $subdir_prefix = `git rev-parse --show-prefix`;
chomp($subdir_prefix);

# run in git base directory, so that git-ls-files lists all revisioned files
chdir "$GIT_DIR/..";

# normalize paths, needed to compare against versioned files and update-index
# also, this is nicer to end-users by doing ".//a/./b/.//./c" ==> "a/b/c"
for (@srcArgs, @dstArgs) {
    # prepend git prefix as we run from base directory
    $_ = $subdir_prefix.$_;
    s|^\./||;
    s|/\./|/| while (m|/\./|);
    s|//+|/|g;
    # Also "a/b/../c" ==> "a/c"
    1 while (s,(^|/)[^/]+/\.\./,$1,);
}

my (@allfiles,@srcfiles,@dstfiles);
my $safesrc;
my (%overwritten, %srcForDst);

$/ = "\0";
open(F, 'git-ls-files -z |')
        or die "Failed to open pipe from git-ls-files: " . $!;

@allfiles = map { chomp; $_; } <F>;
close(F);


my ($i, $bad);
while(scalar @srcArgs > 0) {
    $src = shift @srcArgs;
    $dst = shift @dstArgs;
    $bad = "";

    for ($src, $dst) {
	# Be nicer to end-users by doing ".//a/./b/.//./c" ==> "a/b/c"
	s|^\./||;
	s|/\./|/| while (m|/\./|);
	s|//+|/|g;
	# Also "a/b/../c" ==> "a/c"
	1 while (s,(^|/)[^/]+/\.\./,$1,);
    }

    if ($opt_v) {
	print "Checking rename of '$src' to '$dst'\n";
    }

    unless (-f $src || -l $src || -d $src) {
	$bad = "bad source '$src'";
    }

    $safesrc = quotemeta($src);
    @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;

    $overwritten{$dst} = 0;
    if (($bad eq "") && -e $dst) {
	$bad = "destination '$dst' already exists";
	if ($opt_f) {
	    # only files can overwrite each other: check both source and destination
	    if (-f $dst && (scalar @srcfiles == 1)) {
		print "Warning: $bad; will overwrite!\n";
		$bad = "";
		$overwritten{$dst} = 1;
	    }
	    else {
		$bad = "Can not overwrite '$src' with '$dst'";
	    }
	}
    }
    
    if (($bad eq "") && ($dst =~ /^$safesrc\//)) {
	$bad = "can not move directory '$src' into itself";
    }

    if ($bad eq "") {
        if (scalar @srcfiles == 0) {
	    $bad = "'$src' not under version control";
	}
    }

    if ($bad eq "") {
       if (defined $srcForDst{$dst}) {
           $bad = "can not move '$src' to '$dst'; already target of ";
           $bad .= "'".$srcForDst{$dst}."'";
       }
       else {
           $srcForDst{$dst} = $src;
       }
    }

    if ($bad ne "") {
	if ($opt_k) {
	    print "Warning: $bad; skipping\n";
	    next;
	}
	print "Error: $bad\n";
	exit(1);
    }
    push @srcs, $src;
    push @dsts, $dst;
}

# Final pass: rename/move
my (@deletedfiles,@addedfiles,@changedfiles);
$bad = "";
while(scalar @srcs > 0) {
    $src = shift @srcs;
    $dst = shift @dsts;

    if ($opt_n || $opt_v) { print "Renaming $src to $dst\n"; }
    if (!$opt_n) {
	if (!rename($src,$dst)) {
	    $bad = "renaming '$src' failed: $!";
	    if ($opt_k) {
		print "Warning: skipped: $bad\n";
		$bad = "";
		next;
	    }
	    last;
	}
    }

    $safesrc = quotemeta($src);
    @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
    @dstfiles = @srcfiles;
    s/^$safesrc(\/|$)/$dst$1/ for @dstfiles;

    push @deletedfiles, @srcfiles;
    if (scalar @srcfiles == 1) {
	# $dst can be a directory with 1 file inside
	if ($overwritten{$dst} ==1) {
	    push @changedfiles, $dstfiles[0];

	} else {
	    push @addedfiles, $dstfiles[0];
	}
    }
    else {
	push @addedfiles, @dstfiles;
    }
}

if ($opt_n) {
    if (@changedfiles) {
	print "Changed  : ". join(", ", @changedfiles) ."\n";
    }
    if (@addedfiles) {
	print "Adding   : ". join(", ", @addedfiles) ."\n";
    }
    if (@deletedfiles) {
	print "Deleting : ". join(", ", @deletedfiles) ."\n";
    }
}
else {
    if (@changedfiles) {
	open(H, "| git-update-index -z --stdin")
		or die "git-update-index failed to update changed files with code $!\n";
	foreach my $fileName (@changedfiles) {
		print H "$fileName\0";
	}
	close(H);
    }
    if (@addedfiles) {
	open(H, "| git-update-index --add -z --stdin")
		or die "git-update-index failed to add new names with code $!\n";
	foreach my $fileName (@addedfiles) {
		print H "$fileName\0";
	}
	close(H);
    }
    if (@deletedfiles) {
	open(H, "| git-update-index --remove -z --stdin")
		or die "git-update-index failed to remove old names with code $!\n";
	foreach my $fileName (@deletedfiles) {
		print H "$fileName\0";
	}
	close(H);
    }
}

if ($bad ne "") {
    print "Error: $bad\n";
    exit(1);
}
back to top