Merge branch 'master' of http://darcs.haskell.org/ghc
[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 -d "$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             $ignore_failure = 1;
421             if ($subcommand eq 'add') {
422                 @scm_args = ("remote", "add", $branch_name, $path);
423             } elsif ($subcommand eq 'rm') {
424                 @scm_args = ("remote", "rm", $branch_name);
425             } elsif ($subcommand eq 'set-branches') {
426                 @scm_args = ("remote", "set-branches", $branch_name);
427             } elsif ($subcommand eq 'set-url') {
428                 @scm_args = ("remote", "set-url", $branch_name, $path);
429             }
430             scm ($localpath, $scm, @scm_args, @args);
431         }
432         elsif ($command eq "checkout") {
433             # Not all repos are necessarily branched, so ignore failure
434             $ignore_failure = 1;
435             scm ($localpath, $scm, "checkout", @args)
436                 unless $scm eq "darcs";
437         }
438         elsif ($command eq "grep") {
439             # Hack around 'git grep' failing if there are no matches
440             $ignore_failure = 1;
441             scm ($localpath, $scm, "grep", @args)
442                 unless $scm eq "darcs";
443         }
444         elsif ($command eq "diff") {
445             scm ($localpath, $scm, "diff", @args)
446                 unless $scm eq "darcs";
447         }
448         elsif ($command eq "clean") {
449             scm ($localpath, $scm, "clean", @args)
450                 unless $scm eq "darcs";
451         }
452         elsif ($command eq "reset") {
453             scm ($localpath, $scm, "reset", @args)
454                 unless $scm eq "darcs";
455         }
456         elsif ($command eq "branch") {
457             scm ($localpath, $scm, "branch", @args)
458                 unless $scm eq "darcs";
459         }
460         elsif ($command eq "config") {
461             scm ($localpath, $scm, "config", @args)
462                 unless $scm eq "darcs";
463         }
464         elsif ($command eq "repack") {
465             scm ($localpath, $scm, "repack", @args)
466                 if $scm eq "git"
467         }
468         elsif ($command eq "format-patch") {
469             scm ($localpath, $scm, "format-patch", @args)
470                 if $scm eq "git"
471         }
472         elsif ($command eq "gc") {
473             scm ($localpath, $scm, "gc", @args)
474                 unless $scm eq "darcs";
475         }
476         elsif ($command eq "tag") {
477             scm ($localpath, $scm, "tag", @args);
478         }
479         else {
480             die "Unknown command: $command";
481         }
482     }
483
484     unlink "resume";
485 }
486
487 sub help
488 {
489         my $exit = shift;
490
491         # Get the built in help
492         my $help = <<END;
493 Usage:
494
495 ./sync-all [-q] [-s] [--ignore-failure] [-r repo] [--checked-out] [--bare]
496            [--nofib] [--extra] [--testsuite] [--no-dph] [--resume]
497            cmd [git flags]
498
499 Applies the command "cmd" to each repository in the tree.
500
501 A full repository tree is obtained by first cloning the ghc
502 repository, then getting the subrepositories with "sync-all get":
503
504   \$ git clone http://darcs.haskell.org/ghc.git
505   \$ cd ghc
506   \$ ./sync-all get
507
508 After this, "./sync-all pull" will pull from the original repository
509 tree.
510
511 A remote pointing to another local repository tree can be added like
512 this:
513
514   \$ ./sync-all -r /path/to/ghc remote add otherlocal
515
516 and then we can pull from this other tree with
517
518   \$ ./sync-all pull otherlocal
519
520 -------------- Commands -----------------
521 get
522
523     Clones all sub-repositories from the same place that the ghc
524     repository was cloned from. See "which repos to use" below
525     for details of how the subrepositories are laid out.
526
527     There are various --<package-tag> options that can be given
528     before "get" that enable extra repositories. The full list is
529     given at the end of this help. For example:
530
531     ./sync-all --testsuite get
532
533     would get the testsuite repository in addition to the usual set of
534     subrepositories.
535
536 remote add <remote-name>
537 remote rm <remote-name>
538 remote set-url [--push] <remote-name>
539
540     Runs a "git remote" command on each subrepository, adjusting the
541     repository location in each case appropriately. For example, to
542     add a new remote pointing to the upstream repositories:
543
544     ./sync-all -r http://darcs.haskell.org/ remote add upstream
545
546     The -r flag points to the root of the repository tree (see "which
547     repos to use" below). For a repository on the local filesystem it
548     would point to the ghc repository, and for a remote repository it
549     points to the directory containing "ghc.git".
550
551 These commands just run the equivalent git command on each repository, passing
552 any extra arguments to git:
553
554   branch
555   checkout
556   clean
557   commit
558   config
559   diff
560   fetch
561   format-patch
562   gc
563   grep
564   log
565   new
566   new-workdir
567   pull
568   push
569   repack
570   reset
571   send
572   status
573   tag
574
575 -------------- Flags -------------------
576 These flags are given *before* the command and modify the way sync-all behaves.
577 Flags given *after* the command are passed to git.
578
579   -q says to be quiet, and -s to be silent.
580
581   --resume will restart a command that failed, from the repo at which it
582   failed. This means you don't need to wait while, e.g., "pull" goes through
583   all the repos it's just pulled, and tries to pull them again.
584
585   --ignore-failure says to ignore errors and move on to the next repository
586
587   -r repo says to use repo as the location of package repositories
588
589   --checked-out says that the remote repo is in checked-out layout, as opposed
590   to the layout used for the main repo. By default a repo on the local
591   filesystem is assumed to be checked-out, and repos accessed via HTTP or SSH
592   are assumed to be in the main repo layout; use --checked-out to override the
593   latter.
594
595   --bare says that the local repo is in bare layout, same as the main repo. It
596   also means that these repos are bare. You only have to use this flag if you
597   don't have a bare ghc.git in the current directory and would like to 'get'
598   all of the repos bare. Requires packages.conf to be present in the current
599   directory (a renamed packages file from the main ghc repo).
600
601   Note: --checked-out and --bare flags are NOT the opposite of each other.
602         --checked-out: describes the layout of the remote repository tree.
603         --bare:        describes the layout of the local repository tree.
604
605   --nofib also clones the nofib benchmark suite
606
607   --testsuite also clones the ghc testsuite 
608
609   --extra also clone some extra library packages
610
611   --no-dph avoids cloning the dph pacakges
612
613
614 ------------ Checking out a branch -------------
615 To check out a branch you can run the following command:
616
617   \$ ./sync-all checkout ghc-7.4
618
619
620 ------------ Which repos to use -------------
621 sync-all uses the following algorithm to decide which remote repos to use
622
623 It always computes the remote repos from a single base, <repo_base> How is
624 <repo_base> set? If you say "-r repo", then that's <repo_base> otherwise
625 <repo_base> is set by asking git where the ghc repo came from, and removing the
626 last component (e.g. /ghc.git/ or /ghc/).
627
628 Then sync-all iterates over the package found in the file ./packages; see that
629 file for a description of the contents.
630
631 If <repo_base> looks like a local filesystem path, or if you give the
632 --checked-out flag, sync-all works on repos of form:
633
634   <repo_base>/<local-path>
635
636 otherwise sync-all works on repos of form:
637
638   <repo_base>/<remote-path>
639
640 This logic lets you say
641   both    sync-all -r http://darcs.haskell.org/ghc-6.12 remote add ghc-6.12
642   and     sync-all -r ../working remote add working
643 The latter is called a "checked-out tree".
644
645 sync-all *ignores* the defaultrepo of all repos other than the root one. So the
646 remote repos must be laid out in one of the two formats given by <local-path>
647 and <remote-path> in the file 'packages'.
648
649 Available package-tags are:
650 END
651
652         # Collect all the tags in the packages file
653         my %available_tags;
654         open IN, "< packages.conf"
655             or open IN, "< packages" # clashes with packages directory when using --bare
656             or die "Can't open packages file (or packages.conf)";
657         while (<IN>) {
658             chomp;
659             if (/^([^# ]+) +(?:([^ ]+) +)?([^ ]+) +([^ ]+)/) {
660                 if (defined($2) && $2 ne "-") {
661                     $available_tags{$2} = 1;
662                 }
663             }
664             elsif (! /^(#.*)?$/) {
665                 die "Bad line: $_";
666             }
667         }
668         close IN;
669
670         # Show those tags and the help text
671         my @available_tags = keys %available_tags;
672         print "$help@available_tags\n\n";
673         exit $exit;
674 }
675
676 sub main {
677
678     $tags{"-"} = 1;
679     $tags{"dph"} = 1;
680
681     while ($#_ ne -1) {
682         my $arg = shift;
683         # We handle -q here as well as lower down as we need to skip over it
684         # if it comes before the source-control command
685         if ($arg eq "-q") {
686             $verbose = 1;
687         }
688         elsif ($arg eq "-s") {
689             $verbose = 0;
690         }
691         elsif ($arg eq "-r") {
692             $defaultrepo = shift;
693         }
694         elsif ($arg eq "--resume") {
695             $try_to_resume = 1;
696         }
697         elsif ($arg eq "--ignore-failure") {
698             $ignore_failure = 1;
699         }
700         elsif ($arg eq "--complete" || $arg eq "--partial") {
701             $get_mode = $arg;
702         }
703         # Use --checked-out if the _remote_ repos are a checked-out tree,
704         # rather than the master trees.
705         elsif ($arg eq "--checked-out") {
706             $checked_out_flag = 1;
707         }
708         # Use --bare if the _local_ repos are bare repos,
709         # rather than a checked-out tree.
710         elsif ($arg eq "--bare") {
711             $bare_flag = $arg;
712         }
713         elsif ($arg eq "--help") {
714             help(0);
715         }
716         # --<tag> says we grab the libs tagged 'tag' with
717         # 'get'. It has no effect on the other commands.
718         elsif ($arg =~ m/^--no-(.*)$/) {
719             $tags{$1} = 0;
720         }
721         elsif ($arg =~ m/^--(.*)$/) {
722             $tags{$1} = 1;
723         }
724         else {
725             unshift @_, $arg;
726             if (grep /^-q$/, @_) {
727                 $verbose = 1;
728             }
729             last;
730         }
731     }
732
733     # check for ghc repositories in cwd
734     my $checked_out_found = 1 if (-d ".git" && -d "compiler");
735     my $bare_found = 1 if (-d "ghc.git");
736
737     if ($bare_flag && ! $bare_found && ! $defaultrepo) {
738         die "error: bare repository ghc.git not found.\n"
739           . "       Either clone a bare ghc repo first or specify the repo location. E.g.:\n"
740           . "       ./sync-all --bare [--testsuite --nofib --extra] -r http://darcs.haskell.org/ get\n"
741     }
742     elsif ($bare_found) {
743         $bare_flag = "--bare";
744     }
745     elsif (! $bare_flag && ! $checked_out_found) {
746         die "error: sync-all must be run from the top level of the ghc tree.";
747     }
748
749     if ($#_ eq -1) {
750         help(1);
751     }
752     else {
753         # Give the command and rest of the arguments to the main loop
754         # We normalise command names here to avoid duplicating the
755         # abbreviations that we allow.
756         my $command = shift;
757
758         if ($command =~ /^(?:g|ge|get)$/) {
759             $command = "get";
760         }
761         elsif ($command =~ /^(?:pus|push)$/) {
762             $command = "push";
763         }
764         elsif ($command =~ /^(?:pul|pull)$/) {
765             $command = "pull";
766         }
767         elsif ($command =~ /^(?:s|se|sen|send)$/) {
768             $command = "send";
769         }
770         elsif ($command =~ /^(?:w|wh|wha|what|whats|whatsn|whatsne|whatsnew|status)$/) {
771             $command = "status";
772         }
773
774         scmall ($command, @_);
775
776         if ($command eq "get") {
777             &scm(".", "git", "submodule", "init");
778         }
779         if ($command eq "pull") {
780             my $gitConfig = &tryReadFile(".git/config");
781             if ($gitConfig !~ /submodule/) {
782                 &scm(".", "git", "submodule", "init");
783             }
784         }
785         if ($command eq "get" or $command eq "pull") {
786             my $gitConfig = &tryReadFile(".git/config");
787             if ($gitConfig !~ /submodule/) {
788                 &scm(".", "git", "submodule", "init");
789             }
790             &scm(".", "git", "submodule", "update");
791         }
792     }
793 }
794
795 BEGIN {
796     $initial_working_directory = getcwd();
797 }
798
799 END {
800     my $ec = $?;
801
802     chdir($initial_working_directory);
803
804     message "== Checking for old haddock repo";
805     if (-d "utils/haddock/.git") {
806         chdir("utils/haddock");
807         if ((system "git log -1 87e2ca11c3d1b1bc49900fba0b5c5c6f85650718 > /dev/null 2> /dev/null") == 0) {
808             print <<EOF;
809 ============================
810 ATTENTION!
811
812 You have an old haddock repository in your GHC tree!
813
814 Please remove it (e.g. "rm -r utils/haddock"), and then run
815 "./sync-all get" to get the new repository.
816 ============================
817 EOF
818         }
819         chdir($initial_working_directory);
820     }
821
822     message "== Checking for old binary repo";
823     if (-d "libraries/binary/.git") {
824         chdir("libraries/binary");
825         if ((system "git log -1 749ac0efbde3b14901417364a872796598747aaf > /dev/null 2> /dev/null") == 0) {
826             print <<EOF;
827 ============================
828 ATTENTION!
829
830 You have an old binary repository in your GHC tree!
831
832 Please remove it (e.g. "rm -r libraries/binary"), and then run
833 "./sync-all get" to get the new repository.
834 ============================
835 EOF
836         }
837         chdir($initial_working_directory);
838     }
839
840     message "== Checking for old mtl repo";
841     if (-d "libraries/mtl/.git") {
842         chdir("libraries/mtl");
843         if ((system "git log -1 c67d8f7247c612dc35242bc67e616f7ea35eadb9 > /dev/null 2> /dev/null") == 0) {
844             print <<EOF;
845 ============================
846 ATTENTION!
847
848 You have an old mtl repository in your GHC tree!
849
850 Please remove it (e.g. "rm -r libraries/mtl"), and then run
851 "./sync-all get" to get the new repository.
852 ============================
853 EOF
854         }
855         chdir($initial_working_directory);
856     }
857
858     message "== Checking for old Cabal repo";
859     if (-d "libraries/Cabal/.git") {
860         chdir("libraries/Cabal");
861         if ((system "git log -1 c8ebd66a32865f72ae03ee0663c62df3d77f08fe > /dev/null 2> /dev/null") == 0) {
862             print <<EOF;
863 ============================
864 ATTENTION!
865
866 You have an old Cabal repository in your GHC tree!
867
868 Please remove it (e.g. "rm -r libraries/Cabal"), and then run
869 "./sync-all get" to get the new repository.
870 ============================
871 EOF
872         }
873         chdir($initial_working_directory);
874     }
875
876     message "== Checking for old time from tarball";
877     if (! -e "libraries/time/.git") {
878             print <<EOF;
879 ============================
880 ATTENTION!
881
882 You have an old time package in your GHC tree!
883
884 Please remove it (e.g. "rm -r libraries/time"), and then run
885 "./sync-all get" to get the new repository.
886 ============================
887 EOF
888     }
889
890     $? = $ec;
891 }
892
893 main(@ARGV);
894