X-Git-Url: https://git.madduck.net/code/myrepos.git/blobdiff_plain/d5108dc849fc3a3b75e02e5913a3b917e800a3bc..de0874e8884604b08e3a3b9a1bf682cf2b88f1f2:/mr?ds=inline diff --git a/mr b/mr index 4de2872..2187aa0 100755 --- a/mr +++ b/mr @@ -314,31 +314,22 @@ my $config_overridden=0; 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. @@ -357,86 +348,42 @@ loadconfig($ENV{MR_CONFIG}); #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) = @_; @@ -536,7 +483,7 @@ sub action { #{{{ } } - if (! $nochdir && ! chdir($dir)) { + if (! $no_chdir && ! chdir($dir)) { print STDERR "mr $action: failed to chdir to $dir: $!\n"; return FAILED; } @@ -552,7 +499,7 @@ sub action { #{{{ } } else { - if (! $nochdir) { + if (! $no_chdir) { print "mr $action: $topdir$subdir\n"; } else { @@ -596,6 +543,9 @@ sub action { #{{{ # run actions on multiple repos, in parallel sub mrs { #{{{ + my $action=shift; + my @repos=@_; + $| = 1; my @active; my @fhs; @@ -684,6 +634,25 @@ sub record { #{{{ } } #}}} +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; @@ -715,6 +684,43 @@ sub repolist { #{{{ } @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; @@ -1043,7 +1049,23 @@ sub expandaction { #{{{ } } 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.