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