my $verbose=0;
my $stats=0;
my $no_recurse=0;
+my $no_chdir=0;
my $jobs=1;
my %config;
my %configfiles;
my %knownactions;
my %alias;
my $directory=getcwd();
+my (@ok, @failed, @skipped);
-Getopt::Long::Configure("no_permute");
-my $result=GetOptions(
- "d|directory=s" => sub { $directory=abs_path($_[1]) },
- "c|config=s" => sub { $ENV{MR_CONFIG}=$_[1]; $config_overridden=1 },
- "v|verbose" => \$verbose,
- "s|stats" => \$stats,
- "n|no-recurse" => \$no_recurse,
- "j|jobs=i" => \$jobs,
-);
-if (! $result || @ARGV < 1) {
- die("Usage: mr [-d directory] action [params ...]\n".
- "(Use mr help for man page.)\n");
+getopts();
-}
+# This can happen if it's run in a directory that was removed
+# or other strangeness.
if (! defined $directory) {
die("mr: failed to determine working directory\n");
}
-
# Make sure MR_CONFIG is an absolute path, but don't use abs_path since
# the config file might be a symlink to elsewhere, and the directory it's
# in is significant.
#print Dumper(\%config);
my $action=expandaction(shift @ARGV);
+dispatch($action);
+showstats($action);
-# commands that do not operate on all repos
-if ($action eq 'help') {
- help(@ARGV);
+if (@failed) {
+ exit 1;
}
-elsif ($action eq 'config') {
- config(@ARGV);
+elsif (! @ok && @skipped) {
+ exit 1;
}
-elsif ($action eq 'register') {
- register(@ARGV);
+else {
+ exit 0;
}
-# work out what repos to act on
-my @repos;
-my $nochdir=0;
-foreach my $repo (repolist()) {
- my $topdir=$repo->{topdir};
- my $subdir=$repo->{subdir};
-
- next if $subdir eq 'DEFAULT';
- my $dir=($subdir =~/^\//) ? $subdir : $topdir.$subdir;
- my $d=$directory;
- $dir.="/" unless $dir=~/\/$/;
- $d.="/" unless $d=~/\/$/;
- next if $no_recurse && $d ne $dir;
- next if $dir ne $d && $dir !~ /^\Q$d\E/;
- push @repos, [$dir, $topdir, $subdir];
-}
-if (! @repos) {
- # fallback to find a leaf repo
- foreach my $repo (reverse repolist()) {
- my $topdir=$repo->{topdir};
- my $subdir=$repo->{subdir};
-
- next if $subdir eq 'DEFAULT';
- my $dir=($subdir =~/^\//) ? $subdir : $topdir.$subdir;
- my $d=$directory;
- $dir.="/" unless $dir=~/\/$/;
- $d.="/" unless $d=~/\/$/;
- if ($d=~/^\Q$dir\E/) {
- push @repos, [$dir, $topdir, $subdir];
- last;
- }
- }
- $nochdir=1;
-}
+sub dispatch { #{{{
+ my $action=shift;
-# run the action on each repository and print stats
-my (@ok, @failed, @skipped);
-if ($jobs > 1) {
- mrs(@repos);
-}
-else {
- foreach my $repo (@repos) {
- record($repo, action($action, @$repo));
+ # actions that do not operate on all repos
+ if ($action eq 'help') {
+ help(@ARGV);
}
-}
-if (! @ok && ! @failed && ! @skipped) {
- die "mr $action: no repositories found to work on\n";
-}
-print "mr $action: finished (".join("; ",
- showstat($#ok+1, "ok", "ok"),
- showstat($#failed+1, "failed", "failed"),
- showstat($#skipped+1, "skipped", "skipped"),
-).")\n";
-if ($stats) {
- if (@skipped) {
- print "mr $action: (skipped: ".join(" ", @skipped).")\n";
+ elsif ($action eq 'config') {
+ config(@ARGV);
}
- if (@failed) {
- print STDERR "mr $action: (failed: ".join(" ", @failed).")\n";
+ elsif ($action eq 'register') {
+ register(@ARGV);
}
-}
-if (@failed) {
- exit 1;
-}
-elsif (! @ok && @skipped) {
- exit 1;
-}
-exit 0;
+
+ if ($jobs > 1) {
+ mrs($action, selectrepos());
+ }
+ else {
+ foreach my $repo (selectrepos()) {
+ record($repo, action($action, @$repo));
+ }
+ }
+} #}}}
sub rcs_test { #{{{
my ($action, $dir, $topdir, $subdir) = @_;
}
}
- if (! $nochdir && ! chdir($dir)) {
+ if (! $no_chdir && ! chdir($dir)) {
print STDERR "mr $action: failed to chdir to $dir: $!\n";
return FAILED;
}
}
}
else {
- if (! $nochdir) {
+ if (! $no_chdir) {
print "mr $action: $topdir$subdir\n";
}
else {
# run actions on multiple repos, in parallel
sub mrs { #{{{
+ my $action=shift;
+ my @repos=@_;
+
$| = 1;
my @active;
my @fhs;
}
} #}}}
+sub showstats { #{{{
+ if (! @ok && ! @failed && ! @skipped) {
+ die "mr $action: no repositories found to work on\n";
+ }
+ print "mr $action: finished (".join("; ",
+ showstat($#ok+1, "ok", "ok"),
+ showstat($#failed+1, "failed", "failed"),
+ showstat($#skipped+1, "skipped", "skipped"),
+ ).")\n";
+ if ($stats) {
+ if (@skipped) {
+ print "mr $action: (skipped: ".join(" ", @skipped).")\n";
+ }
+ if (@failed) {
+ print STDERR "mr $action: (failed: ".join(" ", @failed).")\n";
+ }
+ }
+} #}}}
+
sub showstat { #{{{
my $count=shift;
my $singular=shift;
} @list;
} #}}}
+# figure out which repos to act on
+sub selectrepos { #{{{
+ my @repos;
+ foreach my $repo (repolist()) {
+ my $topdir=$repo->{topdir};
+ my $subdir=$repo->{subdir};
+
+ next if $subdir eq 'DEFAULT';
+ my $dir=($subdir =~/^\//) ? $subdir : $topdir.$subdir;
+ my $d=$directory;
+ $dir.="/" unless $dir=~/\/$/;
+ $d.="/" unless $d=~/\/$/;
+ next if $no_recurse && $d ne $dir;
+ next if $dir ne $d && $dir !~ /^\Q$d\E/;
+ push @repos, [$dir, $topdir, $subdir];
+ }
+ if (! @repos) {
+ # fallback to find a leaf repo
+ foreach my $repo (reverse repolist()) {
+ my $topdir=$repo->{topdir};
+ my $subdir=$repo->{subdir};
+
+ next if $subdir eq 'DEFAULT';
+ my $dir=($subdir =~/^\//) ? $subdir : $topdir.$subdir;
+ my $d=$directory;
+ $dir.="/" unless $dir=~/\/$/;
+ $d.="/" unless $d=~/\/$/;
+ if ($d=~/^\Q$dir\E/) {
+ push @repos, [$dir, $topdir, $subdir];
+ last;
+ }
+ }
+ $no_chdir=1;
+ }
+ return @repos;
+} #}}}
+
my %loaded;
sub loadconfig { #{{{
my $f=shift;
}
}
return $action;
-}
+} #}}}
+
+sub getopts { #{{{
+ Getopt::Long::Configure("no_permute");
+ my $result=GetOptions(
+ "d|directory=s" => sub { $directory=abs_path($_[1]) },
+ "c|config=s" => sub { $ENV{MR_CONFIG}=$_[1]; $config_overridden=1 },
+ "v|verbose" => \$verbose,
+ "s|stats" => \$stats,
+ "n|no-recurse" => \$no_recurse,
+ "j|jobs=i" => \$jobs,
+ );
+ if (! $result || @ARGV < 1) {
+ die("Usage: mr [-d directory] action [params ...]\n".
+ "(Use mr help for man page.)\n");
+ }
+} #}}}
# Finally, some useful actions that mr knows about by default.
# These can be overridden in ~/.mrconfig.