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