use strict;
use Getopt::Long;
use Cwd qw(getcwd abs_path);
-use POSIX "WNOHANG";
+
+# things that can happen when mr runs a command
use constant {
OK => 0,
FAILED => 1,
ABORT => 3,
};
-$SIG{INT}=sub {
- print STDERR "mr: interrupted\n";
- exit 2;
-};
-
-$ENV{MR_CONFIG}="$ENV{HOME}/.mrconfig";
+# configurables
my $config_overridden=0;
my $verbose=0;
my $stats=0;
my $no_recurse=0;
my $no_chdir=0;
my $jobs=1;
+my $directory=getcwd();
+
+# globals :-(
my %config;
my %configfiles;
my %knownactions;
my %alias;
-my $directory=getcwd();
-
-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.
-if ($ENV{MR_CONFIG} !~ /^\//) {
- $ENV{MR_CONFIG}=getcwd()."/".$ENV{MR_CONFIG};
-}
-# Try to set MR_PATH to the path to the program.
-eval {
- use FindBin qw($Bin $Script);
- $ENV{MR_PATH}=$Bin."/".$Script;
-};
-
-loadconfig(\*DATA);
-loadconfig($ENV{MR_CONFIG});
-#use Data::Dumper;
-#print Dumper(\%config);
-
-my $action=expandaction(shift @ARGV);
-
-# actions that do not operate on all repos
-if ($action eq 'help') {
- help(@ARGV);
-}
-elsif ($action eq 'config') {
- config(@ARGV);
-}
-elsif ($action eq 'register') {
- register(@ARGV);
-}
-
my (@ok, @failed, @skipped);
-if ($jobs > 1) {
- mrs(selectrepos());
-}
-else {
- foreach my $repo (selectrepos()) {
- record($repo, action($action, @$repo));
- }
-}
-showstats();
-
-if (@failed) {
- exit 1;
-}
-elsif (! @ok && @skipped) {
- exit 1;
-}
-exit 0;
+main();
sub rcs_test { #{{{
my ($action, $dir, $topdir, $subdir) = @_;
# run actions on multiple repos, in parallel
sub mrs { #{{{
+ my $action=shift;
my @repos=@_;
$| = 1;
} #}}}
sub showstats { #{{{
+ my $action=shift;
if (! @ok && ! @failed && ! @skipped) {
die "mr $action: no repositories found to work on\n";
}
my $ret=system($value);
if ($ret != 0) {
if (($? & 127) == 2) {
- print STDERR "mr $action: chain test interrupted\n";
+ print STDERR "mr: chain test interrupted\n";
exit 2;
}
elsif ($? & 127) {
- print STDERR "mr $action: chain test received signal ".($? & 127)."\n";
+ print STDERR "mr: chain test received signal ".($? & 127)."\n";
}
}
else {
print $out @out;
close $out;
} #}}}
-
+
+sub dispatch { #{{{
+ my $action=shift;
+
+ # actions that do not operate on all repos
+ if ($action eq 'help') {
+ help(@ARGV);
+ }
+ elsif ($action eq 'config') {
+ config(@ARGV);
+ }
+ elsif ($action eq 'register') {
+ register(@ARGV);
+ }
+
+ if ($jobs > 1) {
+ mrs($action, selectrepos());
+ }
+ else {
+ foreach my $repo (selectrepos()) {
+ record($repo, action($action, @$repo));
+ }
+ }
+} #}}}
+
sub help { #{{{
- exec($config{''}{DEFAULT}{$action}) || die "exec: $!";
+ exec($config{''}{DEFAULT}{help}) || die "exec: $!";
} #}}}
sub config { #{{{
}
}
if (! $found) {
- die "mr $action: $section $_ not set\n";
+ die "mr config: $section $_ not set\n";
}
}
}
# Find the closest known mrconfig file to the current
# directory.
$directory.="/" unless $directory=~/\/$/;
+ my $foundconfig=0;
foreach my $topdir (reverse sort keys %config) {
next unless length $topdir;
if ($directory=~/^\Q$topdir\E/) {
$ENV{MR_CONFIG}=$configfiles{$topdir};
$directory=$topdir;
+ $foundconfig=1;
last;
}
}
+ if (! $foundconfig) {
+ $directory=""; # no config file, use builtin
+ }
}
if (@ARGV) {
my $subdir=shift @ARGV;
if (! chdir($subdir)) {
- print STDERR "mr $action: failed to chdir to $subdir: $!\n";
+ print STDERR "mr register: failed to chdir to $subdir: $!\n";
}
}
$ENV{MR_REPO}=getcwd();
my $command=findcommand("register", $ENV{MR_REPO}, $directory, 'DEFAULT');
if (! defined $command) {
- die "mr $action: unknown repository type\n";
+ die "mr register: unknown repository type\n";
}
$ENV{MR_REPO}=~s/.*\/(.*)/$1/;
$command="set -e; ".$config{$directory}{DEFAULT}{lib}."\n".
"my_action(){ $command\n }; my_action ".
join(" ", map { s/\//\/\//g; s/"/\"/g; '"'.$_.'"' } @ARGV);
- print "mr $action: running >>$command<<\n" if $verbose;
+ print "mr register: running >>$command<<\n" if $verbose;
exec($command) || die "exec: $!";
} #}}}
}
} #}}}
+sub init { #{{{
+ $SIG{INT}=sub {
+ print STDERR "mr: interrupted\n";
+ exit 2;
+ };
+
+ $ENV{MR_CONFIG}="$ENV{HOME}/.mrconfig";
+
+ # 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.
+ if ($ENV{MR_CONFIG} !~ /^\//) {
+ $ENV{MR_CONFIG}=getcwd()."/".$ENV{MR_CONFIG};
+ }
+ # Try to set MR_PATH to the path to the program.
+ eval {
+ use FindBin qw($Bin $Script);
+ $ENV{MR_PATH}=$Bin."/".$Script;
+ };
+} #}}}
+
+sub main { #{{{
+ getopts();
+ init();
+ loadconfig(\*DATA);
+ loadconfig($ENV{MR_CONFIG});
+ #use Data::Dumper; print Dumper(\%config);
+
+ my $action=expandaction(shift @ARGV);
+ dispatch($action);
+ showstats($action);
+
+ if (@failed) {
+ exit 1;
+ }
+ elsif (! @ok && @skipped) {
+ exit 1;
+ }
+ else {
+ exit 0;
+ }
+} #}}}
+
# Finally, some useful actions that mr knows about by default.
# These can be overridden in ~/.mrconfig.
#DATA{{{