madduck's git repository
Every one of the projects in this repository is available at the canonical
URL git://git.madduck.net/madduck/pub/<projectpath> — see
each project's metadata for the exact URL.
All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
SSH access, as well as push access can be individually
arranged.
If you use my repositories frequently, consider adding the following
snippet to ~/.gitconfig and using the third clone URL listed for each
project:
[url "git://git.madduck.net/madduck/"]
insteadOf = madduck:
=head1 NAME
mr - a Multiple Repository management tool
=head1 NAME
mr - a Multiple Repository management tool
It is not recommended for interactive operations.
Note that running more than 10 jobs at a time is likely to run afoul of
It is not recommended for interactive operations.
Note that running more than 10 jobs at a time is likely to run afoul of
-ssh connection limits. Running between 3 and 5 jobs at a time will yeild
+ssh connection limits. Running between 3 and 5 jobs at a time will yield
a good speedup in updates without loading the machine too much.
=back
a good speedup in updates without loading the machine too much.
=back
override these rcs specific actions. To add a new revision control system,
you can just add rcs specific actions for it.
override these rcs specific actions. To add a new revision control system,
you can just add rcs specific actions for it.
+=head1 EXTENSIONS
+
+mr can be extended to support things such as unison and git-svn. Some
+files providing such extensions are available in /usr/share/mr/. See
+the documentation in the files for details about using them.
+
=head1 AUTHOR
Copyright 2007 Joey Hess <joey@kitenet.net>
=head1 AUTHOR
Copyright 2007 Joey Hess <joey@kitenet.net>
use warnings;
use strict;
use Getopt::Long;
use warnings;
use strict;
use Getopt::Long;
my ($action, $dir, $topdir, $subdir) = @_;
if (exists $rcs{$dir}) {
my ($action, $dir, $topdir, $subdir) = @_;
if (exists $rcs{$dir}) {
else {
return $rcs{$dir}=$rcs;
}
else {
return $rcs{$dir}=$rcs;
}
my ($action, $dir, $topdir, $subdir, $is_checkout) = @_;
if (exists $config{$topdir}{$subdir}{$action}) {
my ($action, $dir, $topdir, $subdir, $is_checkout) = @_;
if (exists $config{$topdir}{$subdir}{$action}) {
my ($action, $dir, $topdir, $subdir) = @_;
$ENV{MR_CONFIG}=$configfiles{$topdir};
my ($action, $dir, $topdir, $subdir) = @_;
$ENV{MR_CONFIG}=$configfiles{$topdir};
# run actions on multiple repos, in parallel
# run actions on multiple repos, in parallel
my $action=shift;
my @repos=@_;
my $action=shift;
my @repos=@_;
my $dir=shift()->[0];
my $ret=shift;
my $dir=shift()->[0];
my $ret=shift;
else {
die "unknown exit status $ret";
}
else {
die "unknown exit status $ret";
}
my $action=shift;
if (! @ok && ! @failed && ! @skipped) {
die "mr $action: no repositories found to work on\n";
my $action=shift;
if (! @ok && ! @failed && ! @skipped) {
die "mr $action: no repositories found to work on\n";
print STDERR "mr $action: (failed: ".join(" ", @failed).")\n";
}
}
print STDERR "mr $action: (failed: ".join(" ", @failed).")\n";
}
}
my $count=shift;
my $singular=shift;
my $plural=shift;
my $count=shift;
my $singular=shift;
my $plural=shift;
return "$count ".($count > 1 ? $plural : $singular);
}
return;
return "$count ".($count > 1 ? $plural : $singular);
}
return;
# an ordered list of repos
# an ordered list of repos
my @list;
foreach my $topdir (sort keys %config) {
foreach my $subdir (sort keys %{$config{$topdir}}) {
my @list;
foreach my $topdir (sort keys %config) {
foreach my $subdir (sort keys %{$config{$topdir}}) {
||
$a->{subdir} cmp $b->{subdir}
} @list;
||
$a->{subdir} cmp $b->{subdir}
} @list;
# figure out which repos to act on
# figure out which repos to act on
my @repos;
foreach my $repo (repolist()) {
my $topdir=$repo->{topdir};
my @repos;
foreach my $repo (repolist()) {
my $topdir=$repo->{topdir};
$no_chdir=1;
}
return @repos;
$no_chdir=1;
}
return @repos;
if ($parameter eq "include") {
print "mr: including output of \"$value\"\n" if $verbose;
unshift @lines, `$value`;
if ($parameter eq "include") {
print "mr: including output of \"$value\"\n" if $verbose;
unshift @lines, `$value`;
+ if ($?) {
+ print STDERR "mr: include command exited nonzero ($?)\n";
+ }
foreach (@toload) {
loadconfig($_);
}
foreach (@toload) {
loadconfig($_);
}
my $f=shift;
# the section to modify or add
my $targetsection=shift;
my $f=shift;
# the section to modify or add
my $targetsection=shift;
open(my $out, ">", $f) || die "mr: write $f: $!\n";
print $out @out;
close $out;
open(my $out, ">", $f) || die "mr: write $f: $!\n";
print $out @out;
close $out;
my $action=shift;
# actions that do not operate on all repos
my $action=shift;
# actions that do not operate on all repos
record($repo, action($action, @$repo));
}
}
record($repo, action($action, @$repo));
}
}
exec($config{''}{DEFAULT}{help}) || die "exec: $!";
exec($config{''}{DEFAULT}{help}) || die "exec: $!";
if (@_ < 2) {
die "mr config: not enough parameters\n";
}
if (@_ < 2) {
die "mr config: not enough parameters\n";
}
}
modifyconfig($ENV{MR_CONFIG}, $section, %changefields) if %changefields;
exit 0;
}
modifyconfig($ENV{MR_CONFIG}, $section, %changefields) if %changefields;
exit 0;
if ($config_overridden) {
# Find the directory that the specified config file is
# located in.
if ($config_overridden) {
# Find the directory that the specified config file is
# located in.
join(" ", map { s/\//\/\//g; s/"/\"/g; '"'.$_.'"' } @ARGV);
print "mr register: running >>$command<<\n" if $verbose;
exec($command) || die "exec: $!";
join(" ", map { s/\//\/\//g; s/"/\"/g; '"'.$_.'"' } @ARGV);
print "mr register: running >>$command<<\n" if $verbose;
exec($command) || die "exec: $!";
# alias expansion and command stemming
# alias expansion and command stemming
my $action=shift;
if (exists $alias{$action}) {
$action=$alias{$action};
my $action=shift;
if (exists $alias{$action}) {
$action=$alias{$action};
my @saved=@ARGV;
Getopt::Long::Configure("bundling", "no_permute");
my $result=GetOptions(
my @saved=@ARGV;
Getopt::Long::Configure("bundling", "no_permute");
my $result=GetOptions(
last if $option eq $ARGV[0];
$ENV{MR_SWITCHES}.="$option ";
}
last if $option eq $ARGV[0];
$ENV{MR_SWITCHES}.="$option ";
}
$SIG{INT}=sub {
print STDERR "mr: interrupted\n";
exit 2;
$SIG{INT}=sub {
print STDERR "mr: interrupted\n";
exit 2;
use FindBin qw($Bin $Script);
$ENV{MR_PATH}=$Bin."/".$Script;
};
use FindBin qw($Bin $Script);
$ENV{MR_PATH}=$Bin."/".$Script;
};
# Finally, some useful actions that mr knows about by default.
# These can be overridden in ~/.mrconfig.
# Finally, some useful actions that mr knows about by default.
# These can be overridden in ~/.mrconfig.
__DATA__
[ALIAS]
co = checkout
__DATA__
[ALIAS]
co = checkout
bzr_push = bzr push "$@"
cvs_push = :
hg_push = hg push "$@"
bzr_push = bzr push "$@"
cvs_push = :
hg_push = hg push "$@"
-darcs_push = darcs push -a
+darcs_push = darcs push -a "$@"
svn_diff = svn diff "$@"
git_diff = git diff "$@"
svn_diff = svn diff "$@"
git_diff = git diff "$@"
info "no offline commands to run"
fi
offline =
info "no offline commands to run"
fi
offline =
touch ~/.mrlog
info "offline mode enabled"
remember =
touch ~/.mrlog
info "offline mode enabled"
remember =
ed = echo "A horse is a horse, of course, of course.."
T = echo "I pity the fool."
right = echo "Not found."
ed = echo "A horse is a horse, of course, of course.."
T = echo "I pity the fool."
right = echo "Not found."
# vim:sw=8:sts=0:ts=8:noet
# vim:sw=8:sts=0:ts=8:noet