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