16 # Import an external git repository into the OpenAFS tree, taking the path
17 # to a local clone of that repository, a file containing a list of mappings
18 # between that repository and the location in the OpenAFS one, and optionally
24 my $result = GetOptions("help|?" => \$help,
26 "externaldir=s" => \$externalDir);
28 pod2usage(1) if $help;
29 pod2usage(-existatus => 0, -verbose =>2) if $man;
32 my $clonePath = shift;
33 my $commitish = shift;
35 pod2usage(2) if !defined($module) || !defined($clonePath);
41 # Use the PROGRAM_NAME to work out where we should be importing to.
43 $externalDir = dirname(Cwd::abs_path($PROGRAM_NAME));
46 # Read in our mapping file
48 my $fh = IO::File->new("$externalDir/$module-files")
49 or die "Couldn't open mapping file : $!\n";
52 if (/^(\S+)\s+(\S+)$/) {
55 die "Unrecognised line in mapping file : $_\n";
60 # Read in our last-sha1 file
63 $fh = IO::File->new("$externalDir/$module-last");
71 $fh = IO::File->new("$externalDir/$module-author");
73 $author = $fh->getline;
78 # Create the external directory, if it doesn't exist.
79 mkdir "$externalDir/$module" if (! -d "$externalDir/$module");
81 # Make ourselves a temporary directory
82 my $tempdir = File::Temp::tempdir(CLEANUP => 1);
84 # Write a list of all of the files that we're going to want out of the other
85 # repository in a format we can use with tar.
86 $fh = IO::File->new($tempdir."/filelist", "w")
87 or die "Can't open temporary file list for writing\n";
88 foreach (sort keys(%mapping)) {
89 $fh->print("source/".$_."\n");
93 # Change directory to the root of the source repository
95 or die "Unable to change directory to $clonePath : $!\n";
97 # Figure out some better names for the commit object we're using
98 my $commitSha1 = `git rev-parse $commitish`;
99 my $commitDesc = `git describe $commitish`;
103 # If we know what our last import was, then get a list of all of the changes
107 my $filelist = join(' ', sort keys(%mapping));
108 $changes = `git shortlog $last..$commitish $filelist`;
111 # Populate our temporary directory with the originals of everything that was
112 # listed in the mapping file
113 system("git archive --format=tar --prefix=source/ $commitish".
114 " | tar -x -C $tempdir -T $tempdir/filelist") == 0
115 or die "git archive and tar failed : $!\n";
117 # change our CWD to the module directory - git ls-files seems to require this
118 chdir "$externalDir/$module"
119 or die "Unable to change directory to $externalDir/$module : $!\n";
121 # Now we're about to start fiddling with local state. Make a note of where we
124 # Use git stash to preserve whatever state there may be in the current
125 # working tree. Sadly git stash returns a 0 exit status if there are no
126 # local changes, so we need to check for local changes first.
129 if (system("git diff-index --quiet --cached HEAD --ignore-submodules") != 0 ||
130 system("git diff-files --quiet --ignore-submodules") != 0) {
131 if (system("git stash") != 0) {
132 die "git stash failed with : $!\n";
138 # Use git-ls-files to get the list of currently committed files for the module
139 my $lspipe = IO::Pipe->new();
140 $lspipe->reader(qw(git ls-files));
148 foreach my $source (sort keys(%mapping)) {
149 if (-f "$tempdir/source/$source") {
150 File::Path::make_path(File::Basename::dirname($mapping{$source}));
151 system("cp $tempdir/source/$source ".
152 " $externalDir/$module/".$mapping{$source}) == 0
153 or die "Copy failed with $!\n";
154 system("git add $externalDir/$module/".$mapping{$source}) == 0
155 or die "git add failed with $!\n";
156 delete $filesInTree{$mapping{$source}}
158 die "Couldn't find file $source in original tree\n";
162 # Use git rm to delete everything that's committed that we don't have a
164 foreach my $missing (keys(%filesInTree)) {
165 system("git rm $missing") == 0
166 or die "Couldn't git rm $missing : $!\n";
169 if (system("git status") == 0) {
170 my $fh=IO::File->new("$externalDir/$module-last", "w");
171 $fh->print($commitSha1."\n");
173 system("git add $externalDir/$module-last") == 0
174 or die "Git add of last file failed with $!\n";
176 $fh=IO::File->new("$tempdir/commit-msg", "w")
177 or die "Unable to write commit message\n";
178 $fh->print("Import of code from $module\n");
180 $fh->print("This commit updates the code imported from $module to\n");
181 $fh->print("$commitSha1 ($commitDesc)\n");
184 $fh->print("Upstream changes are:\n\n");
185 $fh->print($changes);
188 $author="--author '$author'" if ($author);
189 system("git commit -F $tempdir/commit-msg $author") == 0
190 or die "Commit failed : $!\n";
197 print STDERR "Import failed with $@\n";
198 print STDERR "Attempting to reset back to where we were ...\n";
199 system("git reset --hard HEAD") == 0
200 or die "Unable to reset, sorry. You'll need to pick up the pieces\n";
205 system("git stash pop") == 0
206 or die "git stash pop failed with : $!\n";
215 import-external-git - Import bits of an external git repo to OpenAFS
219 import-external-git [options] <module> <repository> [<commitish>]
222 --help brief help message
223 --man full documentation
224 --externalDir exact path to import into
228 import-external-git imports selected files from an external git repository
229 into the OpenAFS src/external tree. For a given <module> it assumes that
230 src/external/<module>-files already exists, and contains a space separated
231 list of source and destination file names. <repository> should point to a
232 local clone of the external project's git repository, and <commitish> points
233 to an object within that tree. If <commitish> isn't specified, the current
234 branch HEAD of that repository is used.