]>
Commit | Line | Data |
---|---|---|
1114b26e JW |
1 | #!/usr/bin/perl |
2 | # | |
3 | # Copyright 2005, Ryan Anderson <ryan@michonline.com> | |
4 | # Josef Weidendorfer <Josef.Weidendorfer@gmx.de> | |
5 | # | |
6 | # This file is licensed under the GPL v2, or a later version | |
7 | # at the discretion of Linus Torvalds. | |
8 | ||
9 | ||
10 | use warnings; | |
11 | use strict; | |
12 | use Getopt::Std; | |
13 | ||
14 | sub usage() { | |
15 | print <<EOT; | |
16 | $0 [-f] [-n] <source> <dest> | |
17 | $0 [-f] [-k] [-n] <source> ... <dest directory> | |
18 | ||
19 | In the first form, source must exist and be either a file, | |
20 | symlink or directory, dest must not exist. It renames source to dest. | |
21 | In the second form, the last argument has to be an existing | |
22 | directory; the given sources will be moved into this directory. | |
23 | ||
24 | Updates the git cache to reflect the change. | |
25 | Use "git commit" to make the change permanently. | |
26 | ||
27 | Options: | |
28 | -f Force renaming/moving, even if target exists | |
29 | -k Continue on error by skipping | |
30 | not-existing or not revision-controlled source | |
31 | -n Do nothing; show what would happen | |
32 | EOT | |
33 | exit(1); | |
34 | } | |
35 | ||
36 | # Sanity checks: | |
37 | my $GIT_DIR = $ENV{'GIT_DIR'} || ".git"; | |
38 | ||
39 | unless ( -d $GIT_DIR && -d $GIT_DIR . "/objects" && | |
40 | -d $GIT_DIR . "/objects/" && -d $GIT_DIR . "/refs") { | |
41 | print "Git repository not found."; | |
42 | usage(); | |
43 | } | |
44 | ||
45 | ||
46 | our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v); | |
47 | getopts("hnfkv") || usage; | |
48 | usage() if $opt_h; | |
49 | @ARGV >= 1 or usage; | |
50 | ||
51 | my (@srcArgs, @dstArgs, @srcs, @dsts); | |
52 | my ($src, $dst, $base, $dstDir); | |
53 | ||
54 | my $argCount = scalar @ARGV; | |
55 | if (-d $ARGV[$argCount-1]) { | |
56 | $dstDir = $ARGV[$argCount-1]; | |
f676fa76 JW |
57 | # remove any trailing slash |
58 | $dstDir =~ s/\/$//; | |
1114b26e JW |
59 | @srcArgs = @ARGV[0..$argCount-2]; |
60 | ||
61 | foreach $src (@srcArgs) { | |
62 | $base = $src; | |
63 | $base =~ s/^.*\///; | |
64 | $dst = "$dstDir/". $base; | |
65 | push @dstArgs, $dst; | |
66 | } | |
67 | } | |
68 | else { | |
69 | if ($argCount != 2) { | |
70 | print "Error: moving to directory '" | |
71 | . $ARGV[$argCount-1] | |
72 | . "' not possible; not exisiting\n"; | |
73 | usage; | |
74 | } | |
75 | @srcArgs = ($ARGV[0]); | |
76 | @dstArgs = ($ARGV[1]); | |
77 | $dstDir = ""; | |
78 | } | |
79 | ||
80 | my (@allfiles,@srcfiles,@dstfiles); | |
81 | my $safesrc; | |
05ff5649 | 82 | my (%overwritten, %srcForDst); |
1114b26e JW |
83 | |
84 | $/ = "\0"; | |
85 | open(F,"-|","git-ls-files","-z") | |
86 | or die "Failed to open pipe from git-ls-files: " . $!; | |
87 | ||
88 | @allfiles = map { chomp; $_; } <F>; | |
89 | close(F); | |
90 | ||
91 | ||
92 | my ($i, $bad); | |
93 | while(scalar @srcArgs > 0) { | |
94 | $src = shift @srcArgs; | |
95 | $dst = shift @dstArgs; | |
96 | $bad = ""; | |
97 | ||
98 | if ($opt_v) { | |
99 | print "Checking rename of '$src' to '$dst'\n"; | |
100 | } | |
101 | ||
102 | unless (-f $src || -l $src || -d $src) { | |
103 | $bad = "bad source '$src'"; | |
104 | } | |
105 | ||
106 | $overwritten{$dst} = 0; | |
107 | if (($bad eq "") && -e $dst) { | |
108 | $bad = "destination '$dst' already exists"; | |
109 | if (-f $dst && $opt_f) { | |
110 | print "Warning: $bad; will overwrite!\n"; | |
111 | $bad = ""; | |
112 | $overwritten{$dst} = 1; | |
113 | } | |
114 | } | |
115 | ||
116 | if (($bad eq "") && ($src eq $dstDir)) { | |
117 | $bad = "can not move directory '$src' into itself"; | |
118 | } | |
119 | ||
120 | if ($bad eq "") { | |
121 | $safesrc = quotemeta($src); | |
122 | @srcfiles = grep /^$safesrc(\/|$)/, @allfiles; | |
123 | if (scalar @srcfiles == 0) { | |
124 | $bad = "'$src' not under version control"; | |
125 | } | |
126 | } | |
127 | ||
05ff5649 JW |
128 | if ($bad eq "") { |
129 | if (defined $srcForDst{$dst}) { | |
130 | $bad = "can not move '$src' to '$dst'; already target of "; | |
131 | $bad .= "'".$srcForDst{$dst}."'"; | |
132 | } | |
133 | else { | |
134 | $srcForDst{$dst} = $src; | |
135 | } | |
136 | } | |
137 | ||
1114b26e JW |
138 | if ($bad ne "") { |
139 | if ($opt_k) { | |
140 | print "Warning: $bad; skipping\n"; | |
141 | next; | |
142 | } | |
143 | print "Error: $bad\n"; | |
144 | usage(); | |
145 | } | |
146 | push @srcs, $src; | |
147 | push @dsts, $dst; | |
148 | } | |
149 | ||
150 | # Final pass: rename/move | |
151 | my (@deletedfiles,@addedfiles,@changedfiles); | |
152 | while(scalar @srcs > 0) { | |
153 | $src = shift @srcs; | |
154 | $dst = shift @dsts; | |
155 | ||
156 | if ($opt_n || $opt_v) { print "Renaming $src to $dst\n"; } | |
157 | if (!$opt_n) { | |
158 | rename($src,$dst) | |
159 | or die "rename failed: $!"; | |
160 | } | |
161 | ||
162 | $safesrc = quotemeta($src); | |
163 | @srcfiles = grep /^$safesrc(\/|$)/, @allfiles; | |
164 | @dstfiles = @srcfiles; | |
165 | s/^$safesrc(\/|$)/$dst$1/ for @dstfiles; | |
166 | ||
167 | push @deletedfiles, @srcfiles; | |
168 | if (scalar @srcfiles == 1) { | |
169 | if ($overwritten{$dst} ==1) { | |
170 | push @changedfiles, $dst; | |
171 | } else { | |
172 | push @addedfiles, $dst; | |
173 | } | |
174 | } | |
175 | else { | |
176 | push @addedfiles, @dstfiles; | |
177 | } | |
178 | } | |
179 | ||
180 | if ($opt_n) { | |
181 | print "Changed : ". join(", ", @changedfiles) ."\n"; | |
182 | print "Adding : ". join(", ", @addedfiles) ."\n"; | |
183 | print "Deleting : ". join(", ", @deletedfiles) ."\n"; | |
184 | exit(1); | |
185 | } | |
186 | ||
187 | my $rc; | |
188 | if (scalar @changedfiles >0) { | |
189 | $rc = system("git-update-index","--",@changedfiles); | |
190 | die "git-update-index failed to update changed files with code $?\n" if $rc; | |
191 | } | |
192 | if (scalar @addedfiles >0) { | |
193 | $rc = system("git-update-index","--add","--",@addedfiles); | |
194 | die "git-update-index failed to add new names with code $?\n" if $rc; | |
195 | } | |
196 | $rc = system("git-update-index","--remove","--",@deletedfiles); | |
197 | die "git-update-index failed to remove old names with code $?\n" if $rc; |