Re-enable a flag-consistency check
[ghc.git] / sync-all
1 #!/usr/bin/perl -w
2
3 use strict;
4 use Cwd;
5
6 $| = 1; # autoflush stdout after each print, to avoid output after die
7
8 my $initial_working_directory;
9
10 my $defaultrepo;
11 my @packages;
12 my $verbose = 2;
13 my $try_to_resume = 0;
14 my $ignore_failure = 0;
15 my $checked_out_flag = 0; # NOT the opposite of bare_flag (describes remote repo state)
16 my $get_mode;
17 my $bare_flag = ""; # NOT the opposite of checked_out_flag (describes local repo state)
18
19 my %tags;
20
21 # Figure out where to get the other repositories from.
22 sub getrepo {
23     my $repo;
24
25     if (defined($defaultrepo)) {
26         $repo = $defaultrepo;
27         chomp $repo;
28     } else {
29         # Figure out where to get the other repositories from,
30         # based on where this GHC repo came from.
31         my $git_dir = $bare_flag ? "--git-dir=ghc.git" : "";
32         my $branch  = `git $git_dir branch | grep "\* " | sed "s/^\* //"`; chomp $branch;
33         my $remote  = `git $git_dir config branch.$branch.remote`;         chomp $remote;
34         if ($remote eq "") {
35             # remotes are not mandatory for branches (e.g. not recorded by default for bare repos)
36             $remote = "origin";
37         }
38         $repo       = `git $git_dir config remote.$remote.url`;            chomp $repo;
39     }
40
41     my $repo_base;
42     my $checked_out_tree;
43
44     if ($repo =~ /^...*:/) {
45         # HTTP or SSH
46         # Above regex says "at least two chars before the :", to avoid
47         # catching Win32 drives ("C:\").
48         $repo_base = $repo;
49
50         # --checked-out is needed if you want to use a checked-out repo
51         # over SSH or HTTP
52         if ($checked_out_flag) {
53             $checked_out_tree = 1;
54         } else {
55             $checked_out_tree = 0;
56         }
57
58         # Don't drop the last part of the path if specified with -r, as
59         # it expects repos of the form:
60         #
61         #   http://darcs.haskell.org
62         #
63         # rather than
64         #
65         #   http://darcs.haskell.org/ghc
66         #
67         if (!$defaultrepo) {
68             $repo_base =~ s#/[^/]+/?$##;
69         }
70     }
71     elsif ($repo =~ /^\/|\.\.\/|.:(\/|\\)/) {
72         # Local filesystem, either absolute (C:/ or /) or relative (../) path
73         $repo_base = $repo;
74         if (-f "$repo/HEAD") {
75             # assume a local mirror:
76             $checked_out_tree = 0;
77             $repo_base =~ s#/[^/]+/?$##;
78         } elsif (-d "$repo/ghc.git") {
79             # assume a local mirror:
80             $checked_out_tree = 0;
81         } else {
82             # assume a checked-out tree:
83             $checked_out_tree = 1;
84         }
85     }
86     else {
87         die "Couldn't work out repo";
88     }
89
90     return $repo_base, $checked_out_tree;
91 }
92
93 sub parsePackages {
94     my @repos;
95     my $lineNum;
96
97     open IN, "< packages.conf"
98         or open IN, "< packages" # clashes with packages directory when using --bare
99         or die "Can't open packages file (or packages.conf)";
100     @repos = <IN>;
101     close IN;
102
103     @packages = ();
104     $lineNum = 0;
105     foreach (@repos) {
106         chomp;
107         $lineNum++;
108         if (/^([^# ]+) +([^ ]+) +([^ ]+)$/) {
109             my %line;
110             $line{"localpath"}  = $1;
111             $line{"tag"}        = $2;
112             $line{"remotepath"} = $3;
113             push @packages, \%line;
114         }
115         elsif (! /^(#.*)?$/) {
116             die "Bad content on line $lineNum of packages file: $_";
117         }
118     }
119 }
120
121 sub tryReadFile {
122     my $filename = shift;
123     my @lines;
124
125     open (FH, $filename) or return "";
126     @lines = <FH>;
127     close FH;
128     return join('', @lines);
129 }
130
131 sub message {
132     if ($verbose >= 2) {
133         print "@_\n";
134     }
135 }
136
137 sub warning {
138     if ($verbose >= 1) {
139         print "warning: @_\n";
140     }
141 }
142
143 sub gitNewWorkdir {
144     my $dir = shift;
145     my $target = shift;
146     my $target_dir = "$target/$dir";
147
148     if ($dir eq '.') {
149         message "== running git-new-workdir . $target_dir @_";
150     } else {
151         message "== $dir: running git-new-workdir . $target_dir @_";
152         chdir($dir);
153     }
154
155     system ("git-new-workdir", ".", $target_dir, @_) == 0
156         or $ignore_failure
157         or die "git-new-workdir failed: $?";
158
159     if ($dir ne '.') {
160         chdir($initial_working_directory);
161     }
162 }
163
164 sub configure_repository {
165     my $localpath = shift;
166
167     &git($localpath, "config", "--local", "core.ignorecase", "true");
168
169     chdir($localpath);
170     open my $git_autocrlf, '-|', 'git', 'config', '--get', 'core.autocrlf'
171         or die "Executing git config failed: $!";
172     my $autocrlf = <$git_autocrlf>;
173     $autocrlf = "" unless defined($autocrlf);
174     chomp $autocrlf;
175     close($git_autocrlf);
176     chdir($initial_working_directory);
177     if ($autocrlf eq "true") {
178         &git($localpath, "config", "--local", "core.autocrlf", "false");
179         &git($localpath, "reset", "--hard");
180     }
181 }
182
183 sub git {
184     my $dir = shift;
185
186     if ($dir eq '.') {
187         message "== running git @_";
188     } else {
189         message "== $dir: running git @_";
190         chdir($dir);
191     }
192
193     system ("git", @_) == 0
194         or $ignore_failure
195         or die "git failed: $?";
196
197     if ($dir ne '.') {
198         chdir($initial_working_directory);
199     }
200 }
201
202 sub gitall {
203     my $command = shift;
204
205     my $localpath;
206     my $tag;
207     my $remotepath;
208     my $line;
209     my $branch_name;
210     my $subcommand;
211
212     my $path;
213
214     my @args;
215
216     my $started;
217     my $doing;
218     my $start_repo;
219
220     my ($repo_base, $checked_out_tree) = getrepo();
221
222     my $is_github_repo = $repo_base =~ m/(git@|git:\/\/|https:\/\/)github.com/;
223
224     parsePackages;
225
226     @args = ();
227
228     if ($command =~ /^remote$/) {
229         while (@_ > 0 && $_[0] =~ /^-/) {
230             push(@args,shift);
231         }
232         if (@_ < 1) { help(1); }
233         $subcommand = shift;
234         if ($subcommand ne 'add' &&
235             $subcommand ne 'rm' &&
236             $subcommand ne 'set-branches' &&
237             $subcommand ne 'set-url') {
238             help(1);
239         }
240         while (@_ > 0 && $_[0] =~ /^-/) {
241             push(@args,shift);
242         }
243         if (($subcommand eq 'add' || $subcommand eq 'rm') && @_ < 1) {
244             help(1);
245         } elsif (@_ < 1) { # set-url
246             $branch_name = 'origin';
247         } else {
248             $branch_name = shift;
249         }
250     } elsif ($command eq 'new') {
251         if (@_ < 1) {
252             $branch_name = 'origin';
253         } else {
254             $branch_name = shift;
255         }
256     }
257
258     push(@args, @_);
259
260     # $doing is a good enough approximation to what we are doing that
261     # we can use it to check that --resume is resuming the right command
262     $doing = join(" ", ($command, @args));
263     $started = 1;
264     if ($try_to_resume && -f "resume") {
265         my $what;
266         open RESUME, "< resume"
267             or die "Can't open resume file";
268         $start_repo = <RESUME>;
269         chomp $start_repo;
270         $what = <RESUME>;
271         chomp $what;
272         close RESUME;
273         if ($what eq $doing) {
274             $started = 0;
275         }
276     }
277
278     for $line (@packages) {
279         $tag        = $$line{"tag"};
280         # Use the "remote" structure for bare git repositories
281         $localpath  = ($bare_flag) ?
282                       $$line{"remotepath"} : $$line{"localpath"};
283         $remotepath = ($checked_out_tree) ?
284                       $$line{"localpath"}  : $$line{"remotepath"};
285
286         if (!$started) {
287             if ($start_repo eq $localpath) {
288                 $started = 1;
289             }
290             else {
291                 next;
292             }
293         }
294
295         open RESUME, "> resume.tmp";
296         print RESUME "$localpath\n";
297         print RESUME "$doing\n";
298         close RESUME;
299         rename "resume.tmp", "resume";
300
301         # We can't create directories on GitHub, so we translate
302         # "packages/foo" into "package-foo".
303         if ($is_github_repo) {
304             $remotepath =~ s/\//-/;
305         }
306
307         # Construct the path for this package in the repo we pulled from
308         $path = "$repo_base/$remotepath";
309
310         if ($command eq "get") {
311             next if $remotepath eq "-"; # "git submodule init/update" will get this later
312
313             # Skip any repositories we have not included the tag for
314             if (not defined($tags{$tag})) {
315                 $tags{$tag} = 0;
316             }
317             if ($tags{$tag} == 0) {
318                 next;
319             }
320
321             if (-d $localpath) {
322                 warning("$localpath already present; omitting")
323                     if $localpath ne ".";
324                 &configure_repository($localpath);
325                 next;
326             }
327
328             # Note that we use "." as the path, as $localpath
329             # doesn't exist yet.
330             my @argsWithBare = @args;
331             push @argsWithBare, $bare_flag if $bare_flag;
332             &git(".", "clone", $path, $localpath, @argsWithBare);
333             &configure_repository($localpath);
334             next;
335         }
336
337         my $git_repo_present = 1 if -e "$localpath/.git" || ($bare_flag && -d "$localpath");
338         if (not $git_repo_present) {
339             if ($tag eq "") {
340                 die "Required repo $localpath is missing";
341             }
342             else {
343                  message "== $localpath repo not present; skipping";
344                  next;
345             }
346         }
347
348         # Work out the arguments we should give to the SCM
349         if ($command eq "status") {
350             &git($localpath, $command, @args);
351         }
352         elsif ($command eq "commit") {
353             # git fails if there is nothing to commit, so ignore failures
354             $ignore_failure = 1;
355             &git($localpath, "commit", @args);
356         }
357         elsif ($command eq "check_submodules") {
358             # If we have a submodule then check whether it is up-to-date
359             if ($remotepath eq "-") {
360                 my %remote_heads;
361
362                 message "== Checking sub-module $localpath";
363
364                 chdir($localpath);
365
366                 open my $lsremote, '-|', 'git', 'ls-remote', '--heads', '-q'
367                     or die "Executing ls-remote failed: $!";
368                 while (<$lsremote>) {
369                     if (/^([0-9a-f]{40})\s*refs\/heads\//) {
370                         $remote_heads{$1} = 1;
371                     }
372                     else {
373                         die "Bad output from ls-remote: $_";
374                     }
375                 }
376                 close($lsremote);
377
378                 open my $revparse, '-|', 'git', 'rev-parse', '--verify', 'HEAD'
379                     or die "Executing rev-parse failed: $!";
380                 my $myhead;
381                 $myhead = <$revparse>;
382                     # or die "Failed to read from rev-parse: $!";
383                 chomp $myhead;
384                 close($revparse);
385
386                 if (not defined($remote_heads{$myhead})) {
387                     die "Sub module $localpath needs to be pushed; see http://hackage.haskell.org/trac/ghc/wiki/Repositories/Upstream";
388                 }
389                 
390                 chdir($initial_working_directory);
391             }
392         }
393         elsif ($command eq "push") {
394             # We don't automatically push to the submodules. If you want
395             # to push to them then you need to use a special command, as
396             # described on
397             # http://hackage.haskell.org/trac/ghc/wiki/Repositories/Upstream
398             if ($remotepath ne "-") {
399                 &git($localpath, "push", @args);
400             }
401         }
402         elsif ($command eq "pull") {
403             my $realcmd;
404             my @realargs;
405             if ($remotepath eq "-") {
406                 # Only fetch for the submodules. "git submodule update"
407                 # will take care of making us point to the right commit.
408                 $realcmd = "fetch";
409                 # we like "sync-all pull --rebase" to work:
410                 @realargs = grep(!/--rebase/,@args);
411             }
412             else {
413                 $realcmd = "pull";
414                 @realargs = @args;
415             }
416             &git($localpath, $realcmd, @realargs);
417         }
418         elsif ($command eq "new-workdir") {
419             gitNewWorkdir ($localpath, @args);
420         }
421         elsif ($command eq "send") {
422             $command = "send-email";
423             &git($localpath, $command, @args);
424         }
425         elsif ($command eq "fetch") {
426             &git($localpath, "fetch", @args);
427         }
428         elsif ($command eq "new") {
429             my @scm_args = ("log", "$branch_name..");
430             &git($localpath, @scm_args, @args);
431         }
432         elsif ($command eq "log") {
433             &git($localpath, "log", @args);
434         }
435         elsif ($command eq "remote") {
436             my @scm_args;
437             my $rpath;
438             $ignore_failure = 1;
439             if ($remotepath eq '-') {
440                 $rpath = "$repo_base/$localpath";
441             } else {
442                 $rpath = $path;
443             }
444             if ($subcommand eq 'add') {
445                 @scm_args = ("remote", "add", $branch_name, $rpath);
446             } elsif ($subcommand eq 'rm') {
447                 @scm_args = ("remote", "rm", $branch_name);
448             } elsif ($subcommand eq 'set-branches') {
449                 @scm_args = ("remote", "set-branches", $branch_name);
450             } elsif ($subcommand eq 'set-url') {
451                 @scm_args = ("remote", "set-url", $branch_name, $rpath);
452             }
453             &git($localpath, @scm_args, @args);
454         }
455         elsif ($command eq "checkout") {
456             # Not all repos are necessarily branched, so ignore failure
457             $ignore_failure = 1;
458             &git($localpath, "checkout", @args);
459         }
460         elsif ($command eq "grep") {
461             # Hack around 'git grep' failing if there are no matches
462             $ignore_failure = 1;
463             &git($localpath, "grep", @args);
464         }
465         elsif ($command eq "diff") {
466             &git($localpath, "diff", @args);
467         }
468         elsif ($command eq "clean") {
469             &git($localpath, "clean", @args);
470         }
471         elsif ($command eq "reset") {
472             &git($localpath, "reset", @args);
473         }
474         elsif ($command eq "branch") {
475             &git($localpath, "branch", @args);
476         }
477         elsif ($command eq "config") {
478             &git($localpath, "config", @args);
479         }
480         elsif ($command eq "repack") {
481             &git($localpath, "repack", @args);
482         }
483         elsif ($command eq "format-patch") {
484             &git($localpath, "format-patch", @args);
485         }
486         elsif ($command eq "gc") {
487             &git($localpath, "gc", @args);
488         }
489         elsif ($command eq "tag") {
490             &git($localpath, "tag", @args);
491         }
492         else {
493             die "Unknown command: $command";
494         }
495     }
496
497     unlink "resume";
498 }
499
500 sub help
501 {
502         my $exit = shift;
503
504         # Get the built in help
505         my $help = <<END;
506 Usage:
507
508 ./sync-all [-q] [-s] [--ignore-failure] [-r repo] [--checked-out] [--bare]
509            [--nofib] [--extra] [--testsuite] [--no-dph] [--resume]
510            cmd [git flags]
511
512 Applies the command "cmd" to each repository in the tree.
513
514 A full repository tree is obtained by first cloning the ghc
515 repository, then getting the subrepositories with "sync-all get":
516
517   \$ git clone http://darcs.haskell.org/ghc.git
518   \$ cd ghc
519   \$ ./sync-all get
520
521 After this, "./sync-all pull" will pull from the original repository
522 tree.
523
524 A remote pointing to another local repository tree can be added like
525 this:
526
527   \$ ./sync-all -r /path/to/ghc remote add otherlocal
528
529 and then we can pull from this other tree with
530
531   \$ ./sync-all pull otherlocal
532
533 -------------- Commands -----------------
534 get
535
536     Clones all sub-repositories from the same place that the ghc
537     repository was cloned from. See "which repos to use" below
538     for details of how the subrepositories are laid out.
539
540     There are various --<package-tag> options that can be given
541     before "get" that enable extra repositories. The full list is
542     given at the end of this help. For example:
543
544     ./sync-all --testsuite get
545
546     would get the testsuite repository in addition to the usual set of
547     subrepositories.
548
549 remote add <remote-name>
550 remote rm <remote-name>
551 remote set-url [--push] <remote-name>
552
553     Runs a "git remote" command on each subrepository, adjusting the
554     repository location in each case appropriately. For example, to
555     add a new remote pointing to the upstream repositories:
556
557     ./sync-all -r http://darcs.haskell.org/ remote add upstream
558
559     The -r flag points to the root of the repository tree (see "which
560     repos to use" below). For a repository on the local filesystem it
561     would point to the ghc repository, and for a remote repository it
562     points to the directory containing "ghc.git".
563
564 These commands just run the equivalent git command on each repository, passing
565 any extra arguments to git:
566
567   branch
568   checkout
569   clean
570   commit
571   config
572   diff
573   fetch
574   format-patch
575   gc
576   grep
577   log
578   new
579   new-workdir
580   pull
581   push
582   repack
583   reset
584   send
585   status
586   tag
587
588 -------------- Flags -------------------
589 These flags are given *before* the command and modify the way sync-all behaves.
590 Flags given *after* the command are passed to git.
591
592   -q says to be quiet, and -s to be silent.
593
594   --resume will restart a command that failed, from the repo at which it
595   failed. This means you don't need to wait while, e.g., "pull" goes through
596   all the repos it's just pulled, and tries to pull them again.
597
598   --ignore-failure says to ignore errors and move on to the next repository
599
600   -r repo says to use repo as the location of package repositories
601
602   --checked-out says that the remote repo is in checked-out layout, as opposed
603   to the layout used for the main repo. By default a repo on the local
604   filesystem is assumed to be checked-out, and repos accessed via HTTP or SSH
605   are assumed to be in the main repo layout; use --checked-out to override the
606   latter.
607
608   --bare says that the local repo is in bare layout, same as the main repo. It
609   also means that these repos are bare. You only have to use this flag if you
610   don't have a bare ghc.git in the current directory and would like to 'get'
611   all of the repos bare. Requires packages.conf to be present in the current
612   directory (a renamed packages file from the main ghc repo).
613
614   Note: --checked-out and --bare flags are NOT the opposite of each other.
615         --checked-out: describes the layout of the remote repository tree.
616         --bare:        describes the layout of the local repository tree.
617
618   --nofib also clones the nofib benchmark suite
619
620   --testsuite also clones the ghc testsuite 
621
622   --extra also clone some extra library packages
623
624   --no-dph avoids cloning the dph pacakges
625
626
627 ------------ Checking out a branch -------------
628 To check out a branch you can run the following command:
629
630   \$ ./sync-all checkout ghc-7.4
631
632
633 ------------ Which repos to use -------------
634 sync-all uses the following algorithm to decide which remote repos to use
635
636 It always computes the remote repos from a single base, <repo_base> How is
637 <repo_base> set? If you say "-r repo", then that's <repo_base> otherwise
638 <repo_base> is set by asking git where the ghc repo came from, and removing the
639 last component (e.g. /ghc.git/ or /ghc/).
640
641 Then sync-all iterates over the package found in the file ./packages; see that
642 file for a description of the contents.
643
644 If <repo_base> looks like a local filesystem path, or if you give the
645 --checked-out flag, sync-all works on repos of form:
646
647   <repo_base>/<local-path>
648
649 otherwise sync-all works on repos of form:
650
651   <repo_base>/<remote-path>
652
653 This logic lets you say
654   both    sync-all -r http://darcs.haskell.org/ghc-6.12 remote add ghc-6.12
655   and     sync-all -r ../working remote add working
656 The latter is called a "checked-out tree".
657
658 sync-all *ignores* the defaultrepo of all repos other than the root one. So the
659 remote repos must be laid out in one of the two formats given by <local-path>
660 and <remote-path> in the file 'packages'.
661
662 Available package-tags are:
663 END
664
665         # Collect all the tags in the packages file
666         my %available_tags;
667         open IN, "< packages.conf"
668             or open IN, "< packages" # clashes with packages directory when using --bare
669             or die "Can't open packages file (or packages.conf)";
670         while (<IN>) {
671             chomp;
672             if (/^([^# ]+) +(?:([^ ]+) +)?([^ ]+) +([^ ]+)/) {
673                 if (defined($2) && $2 ne "-") {
674                     $available_tags{$2} = 1;
675                 }
676             }
677             elsif (! /^(#.*)?$/) {
678                 die "Bad line: $_";
679             }
680         }
681         close IN;
682
683         # Show those tags and the help text
684         my @available_tags = keys %available_tags;
685         print "$help@available_tags\n\n";
686         exit $exit;
687 }
688
689 sub main {
690
691     $tags{"-"} = 1;
692     $tags{"dph"} = 1;
693
694     while ($#_ ne -1) {
695         my $arg = shift;
696         # We handle -q here as well as lower down as we need to skip over it
697         # if it comes before the source-control command
698         if ($arg eq "-q") {
699             $verbose = 1;
700         }
701         elsif ($arg eq "-s") {
702             $verbose = 0;
703         }
704         elsif ($arg eq "-r") {
705             $defaultrepo = shift;
706         }
707         elsif ($arg eq "--resume") {
708             $try_to_resume = 1;
709         }
710         elsif ($arg eq "--ignore-failure") {
711             $ignore_failure = 1;
712         }
713         elsif ($arg eq "--complete" || $arg eq "--partial") {
714             $get_mode = $arg;
715         }
716         # Use --checked-out if the _remote_ repos are a checked-out tree,
717         # rather than the master trees.
718         elsif ($arg eq "--checked-out") {
719             $checked_out_flag = 1;
720         }
721         # Use --bare if the _local_ repos are bare repos,
722         # rather than a checked-out tree.
723         elsif ($arg eq "--bare") {
724             $bare_flag = $arg;
725         }
726         elsif ($arg eq "--help") {
727             help(0);
728         }
729         # --<tag> says we grab the libs tagged 'tag' with
730         # 'get'. It has no effect on the other commands.
731         elsif ($arg =~ m/^--no-(.*)$/) {
732             $tags{$1} = 0;
733         }
734         elsif ($arg =~ m/^--(.*)$/) {
735             $tags{$1} = 1;
736         }
737         else {
738             unshift @_, $arg;
739             if (grep /^-q$/, @_) {
740                 $verbose = 1;
741             }
742             last;
743         }
744     }
745
746     # check for ghc repositories in cwd
747     my $checked_out_found = 1 if (-d ".git" && -d "compiler");
748     my $bare_found = 1 if (-d "ghc.git");
749
750     if ($bare_flag && ! $bare_found && ! $defaultrepo) {
751         die "error: bare repository ghc.git not found.\n"
752           . "       Either clone a bare ghc repo first or specify the repo location. E.g.:\n"
753           . "       ./sync-all --bare [--testsuite --nofib --extra] -r http://darcs.haskell.org/ get\n"
754     }
755     elsif ($bare_found) {
756         $bare_flag = "--bare";
757     }
758     elsif (! $bare_flag && ! $checked_out_found) {
759         die "error: sync-all must be run from the top level of the ghc tree.";
760     }
761
762     if ($#_ eq -1) {
763         help(1);
764     }
765     else {
766         # Give the command and rest of the arguments to the main loop
767         # We normalise command names here to avoid duplicating the
768         # abbreviations that we allow.
769         my $command = shift;
770
771         if ($command =~ /^(?:g|ge|get)$/) {
772             $command = "get";
773         }
774         elsif ($command =~ /^(?:pus|push)$/) {
775             $command = "push";
776         }
777         elsif ($command =~ /^(?:pul|pull)$/) {
778             $command = "pull";
779         }
780         elsif ($command =~ /^(?:s|se|sen|send)$/) {
781             $command = "send";
782         }
783         elsif ($command =~ /^(?:w|wh|wha|what|whats|whatsn|whatsne|whatsnew|status)$/) {
784             $command = "status";
785         }
786
787         if ($command eq "push") {
788             &gitall("check_submodules", @_);
789         }
790
791         &gitall($command, @_);
792
793         my @submodule_args = grep(/^-q/,@_);
794
795         if ($command eq "get") {
796             &git(".", "submodule", "init", @submodule_args);
797         }
798         if ($command eq "pull") {
799             my $gitConfig = &tryReadFile(".git/config");
800             if ($gitConfig !~ /submodule/) {
801                 &git(".", "submodule", "init", @submodule_args);
802             }
803         }
804         if ($command eq "get" or $command eq "pull") {
805             my $gitConfig = &tryReadFile(".git/config");
806             if ($gitConfig !~ /submodule/) {
807                 &git(".", "submodule", "init", @submodule_args);
808             }
809             &git(".", "submodule", "update", @submodule_args);
810         }
811     }
812 }
813
814 BEGIN {
815     $initial_working_directory = getcwd();
816 }
817
818 END {
819     my $ec = $?;
820
821     chdir($initial_working_directory);
822
823     message "== Checking for old haddock repo";
824     if (-d "utils/haddock/.git") {
825         chdir("utils/haddock");
826         if ((system "git log -1 87e2ca11c3d1b1bc49900fba0b5c5c6f85650718 > /dev/null 2> /dev/null") == 0) {
827             print <<EOF;
828 ============================
829 ATTENTION!
830
831 You have an old haddock repository in your GHC tree!
832
833 Please remove it (e.g. "rm -r utils/haddock"), and then run
834 "./sync-all get" to get the new repository.
835 ============================
836 EOF
837         }
838         chdir($initial_working_directory);
839     }
840
841     message "== Checking for old binary repo";
842     if (-d "libraries/binary/.git") {
843         chdir("libraries/binary");
844         if ((system "git log -1 749ac0efbde3b14901417364a872796598747aaf > /dev/null 2> /dev/null") == 0) {
845             print <<EOF;
846 ============================
847 ATTENTION!
848
849 You have an old binary repository in your GHC tree!
850
851 Please remove it (e.g. "rm -r libraries/binary"), and then run
852 "./sync-all get" to get the new repository.
853 ============================
854 EOF
855         }
856         chdir($initial_working_directory);
857     }
858
859     message "== Checking for old mtl repo";
860     if (-d "libraries/mtl/.git") {
861         chdir("libraries/mtl");
862         if ((system "git log -1 c67d8f7247c612dc35242bc67e616f7ea35eadb9 > /dev/null 2> /dev/null") == 0) {
863             print <<EOF;
864 ============================
865 ATTENTION!
866
867 You have an old mtl repository in your GHC tree!
868
869 Please remove it (e.g. "rm -r libraries/mtl"), and then run
870 "./sync-all get" to get the new repository.
871 ============================
872 EOF
873         }
874         chdir($initial_working_directory);
875     }
876
877     message "== Checking for old Cabal repo";
878     if (-d "libraries/Cabal/.git") {
879         chdir("libraries/Cabal");
880         if ((system "git log -1 c8ebd66a32865f72ae03ee0663c62df3d77f08fe > /dev/null 2> /dev/null") == 0) {
881             print <<EOF;
882 ============================
883 ATTENTION!
884
885 You have an old Cabal repository in your GHC tree!
886
887 Please remove it (e.g. "rm -r libraries/Cabal"), and then run
888 "./sync-all get" to get the new repository.
889 ============================
890 EOF
891         }
892         chdir($initial_working_directory);
893     }
894
895     message "== Checking for old time from tarball";
896     if (-d "libraries/time" and ! -e "libraries/time/.git") {
897             print <<EOF;
898 ============================
899 ATTENTION!
900
901 You have an old time package in your GHC tree!
902
903 Please remove it (e.g. "rm -r libraries/time"), and then run
904 "./sync-all get" to get the new repository.
905 ============================
906 EOF
907     }
908
909     $? = $ec;
910 }
911
912 main(@ARGV);
913