Git.pm: tentative fix to test the freshly built Git.pm
[gitweb.git] / git-mv.perl
index b6c0b4881845bf6a8d9681817fc540a2003b889e..f1bde4307ba719ce0e78ad360aa2ce1f4b7c6958 100755 (executable)
@@ -10,6 +10,7 @@
 use warnings;
 use strict;
 use Getopt::Std;
+use Git;
 
 sub usage() {
        print <<EOT;
@@ -19,25 +20,24 @@ ()
        exit(1);
 }
 
-my $GIT_DIR = `git rev-parse --git-dir`;
-exit 1 if $?; # rev-parse would have given "not a git dir" message.
-chomp($GIT_DIR);
-
 our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v);
 getopts("hnfkv") || usage;
 usage() if $opt_h;
 @ARGV >= 1 or usage;
 
+my $repo = Git->repository();
+
 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];
-       # remove any trailing slash
-       $dstDir =~ s/\/$//;
        @srcArgs = @ARGV[0..$argCount-2];
-       
+
        foreach $src (@srcArgs) {
                $base = $src;
                $base =~ s/^.*\///;
@@ -46,10 +46,14 @@ ()
        }
 }
 else {
-    if ($argCount != 2) {
+    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 exisiting\n";
+           . "' not possible; not existing\n";
        exit(1);
     }
     @srcArgs = ($ARGV[0]);
@@ -57,16 +61,32 @@ ()
     $dstDir = "";
 }
 
+my $subdir_prefix = $repo->wc_subdir();
+
+# run in git base directory, so that git-ls-files lists all revisioned files
+chdir $repo->wc_path();
+$repo->wc_chdir('');
+
+# 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);
+{
+       local $/ = "\0";
+       @allfiles = $repo->command('ls-files', '-z');
+}
 
 
 my ($i, $bad);
@@ -75,6 +95,15 @@ ()
     $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";
     }
@@ -187,28 +216,28 @@ ()
 }
 else {
     if (@changedfiles) {
-       open(H, "| git-update-index -z --stdin")
-               or die "git-update-index failed to update changed files with code $!\n";
+       my ($fd, $ctx) = $repo->command_input_pipe('update-index', '-z', '--stdin');
        foreach my $fileName (@changedfiles) {
-               print H "$fileName\0";
+               print $fd "$fileName\0";
        }
-       close(H);
+       git_cmd_try { $repo->command_close_pipe($fd, $ctx); }
+               'git-update-index failed to update changed files with code %d';
     }
     if (@addedfiles) {
-       open(H, "| git-update-index --add -z --stdin")
-               or die "git-update-index failed to add new names with code $!\n";
+       my ($fd, $ctx) = $repo->command_input_pipe('update-index', '--add', '-z', '--stdin');
        foreach my $fileName (@addedfiles) {
-               print H "$fileName\0";
+               print $fd "$fileName\0";
        }
-       close(H);
+       git_cmd_try { $repo->command_close_pipe($fd, $ctx); }
+               'git-update-index failed to add new files with code %d';
     }
     if (@deletedfiles) {
-       open(H, "| git-update-index --remove -z --stdin")
-               or die "git-update-index failed to remove old names with code $!\n";
+       my ($fd, $ctx) = $repo->command_input_pipe('update-index', '--remove', '-z', '--stdin');
        foreach my $fileName (@deletedfiles) {
-               print H "$fileName\0";
+               print $fd "$fileName\0";
        }
-       close(H);
+       git_cmd_try { $repo->command_close_pipe($fd, $ctx); }
+               'git-update-index failed to remove old files with code %d';
     }
 }