]>
git.madduck.net Git - code/myrepos.git/blobdiff - mr
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:
B<mr> is a Multiple Repository management tool. It can checkout, update, or
perform other actions on a set of repositories as if they were one combined
repository. It supports any combination of subversion, git, cvs, mercurial,
B<mr> is a Multiple Repository management tool. It can checkout, update, or
perform other actions on a set of repositories as if they were one combined
repository. It supports any combination of subversion, git, cvs, mercurial,
-bzr, darcs and fossil repositories, and support for other revi sion
+bzr, darcs and fossil repositories, and support for other ver sion
control systems can easily be added.
B<mr> cds into and operates on all registered repositories at or below your
control systems can easily be added.
B<mr> cds into and operates on all registered repositories at or below your
looks for a .mrconfig file in the current directory, or in one of its
parent directories.
looks for a .mrconfig file in the current directory, or in one of its
parent directories.
-These predefined commands should be fairly familiar to users of any revi sion
+These predefined commands should be fairly familiar to users of any ver sion
=item record
Records changes to the local repository, but does not push them to the
=item record
Records changes to the local repository, but does not push them to the
-remote repository. Only supported for distributed revi sion control systems.
+remote repository. Only supported for distributed ver sion control systems.
The optional -m parameter allows specifying a commit message.
=item push
Pushes committed local changes to the remote repository. A no-op for
The optional -m parameter allows specifying a commit message.
=item push
Pushes committed local changes to the remote repository. A no-op for
-centralized revi sion control systems.
+centralized ver sion control systems.
update"
Additional parameters can be passed to most commands, and are passed on
update"
Additional parameters can be passed to most commands, and are passed on
-unchanged to the underlying revi sion control system. This is mostly useful
-if the repositories mr will act on all use the same revi sion control
+unchanged to the underlying ver sion control system. This is mostly useful
+if the repositories mr will act on all use the same ver sion control
that defines the repo being acted on, or, if the repo is not yet in a config
file, the .mrconfig file that should be modified to register the repo.
that defines the repo being acted on, or, if the repo is not yet in a config
file, the .mrconfig file that should be modified to register the repo.
+The "MR_ACTION" environment variable is set to the command being run
+(update, checkout, etc).
+
A few parameters have special meanings:
=over 4
A few parameters have special meanings:
=over 4
(included in mr's built-in library) to skip updating the repo unless it's
been at least 12 hours since the last update.
(included in mr's built-in library) to skip updating the repo unless it's
been at least 12 hours since the last update.
+ [mystuff]
+ checkout = ...
skip = test `whoami` != joey
skip = test `whoami` != joey
+
+ [linux]
+ checkout = ...
skip = [ "$1" = update ] && ! hours_since "$1" 12
skip = [ "$1" = update ] && ! hours_since "$1" 12
+
+Another way to use skip is for a lazy checkout. This makes mr skip
+operating on a repo unless it already exists. To enable the
+repo, you have to explicitly check it out (using "mr -d foo checkout").
+
+ [foo]
+ checkout = ...
+ skip = lazy
Unlike all other parameters, this parameter does not need to be placed
within a section.
Unlike all other parameters, this parameter does not need to be placed
within a section.
+B<mr> ships several libraries that can be included to add support for
+additional version control type things (unison, git-svn, vcsh, git-fake-bare,
+git-subtree). To include them all, you could use:
+
+ include = cat /usr/share/mr/*
+
+See the individual files for details.
+
=item deleted
If the "deleted" parameter is set and its command returns true, then
=item deleted
If the "deleted" parameter is set and its command returns true, then
When looking for a command to run for a given action, mr first looks for
a parameter with the same name as the action. If that is not found, it
When looking for a command to run for a given action, mr first looks for
a parameter with the same name as the action. If that is not found, it
-looks for a parameter named "rcs _action" (substituting in the name of the
-revision control system and the action). The name of the revi sion control
-system is itself determined by running each defined "rcs _test" action,
+looks for a parameter named "VCS _action" (substituting in the name of the
+version control system and the action). The name of the ver sion control
+system is itself determined by running each defined "VCS _test" action,
until one succeeds.
Internally, mr has settings for "git_update", "svn_update", etc. To change
until one succeeds.
Internally, mr has settings for "git_update", "svn_update", etc. To change
-the action that is performed for a given revi sion control system, you can
-override these rcs specific actions. To add a new revi sion control system,
-you can just add rcs specific actions for it.
+the action that is performed for a given ver sion control system, you can
+override these VCS specific actions. To add a new ver sion control system,
+you can just add VCS specific actions for it.
=head1 UNTRUSTED MRCONFIG FILES
=head1 UNTRUSTED MRCONFIG FILES
-my %r cs;
-sub r cs_test {
+my %v cs;
+sub v cs_test {
my ($action, $dir, $topdir, $subdir) = @_;
my ($action, $dir, $topdir, $subdir) = @_;
- if (exists $r cs{$dir}) {
- return $r cs{$dir};
+ if (exists $v cs{$dir}) {
+ return $v cs{$dir};
sort {
length $a <=> length $b
||
$a cmp $b
} grep { /_test$/ } keys %{$config{$topdir}{$subdir}}) {
sort {
length $a <=> length $b
||
$a cmp $b
} grep { /_test$/ } keys %{$config{$topdir}{$subdir}}) {
- my ($rcs)=$r cs_test=~/(.*)_test/;
- $test="my_$rcs_test() {\n$config{$topdir}{$subdir}{$r cs_test}\n}\n".$test;
- $test.="if my_$rcs_test; then echo $r cs; fi\n";
+ my ($vcs)=$v cs_test=~/(.*)_test/;
+ $test="my_$vcs_test() {\n$config{$topdir}{$subdir}{$v cs_test}\n}\n".$test;
+ $test.="if my_$vcs_test; then echo $v cs; fi\n";
}
$test=$config{$topdir}{$subdir}{lib}."\n".$test
if exists $config{$topdir}{$subdir}{lib};
}
$test=$config{$topdir}{$subdir}{lib}."\n".$test
if exists $config{$topdir}{$subdir}{lib};
- print "mr $action: running r cs test >>$test<<\n" if $verbose;
- my $r cs=`$test`;
- chomp $r cs;
- if ($r cs=~/\n/s) {
- $r cs=~s/\n/, /g;
- print STDERR "mr $action: found multiple possible repository types ($r cs) for ".fulldir($topdir, $subdir)."\n";
+ print "mr $action: running v cs test >>$test<<\n" if $verbose;
+ my $v cs=`$test`;
+ chomp $v cs;
+ if ($v cs=~/\n/s) {
+ $v cs=~s/\n/, /g;
+ print STDERR "mr $action: found multiple possible repository types ($v cs) for ".fulldir($topdir, $subdir)."\n";
- if (! length $r cs) {
- return $r cs{$dir}=undef;
+ if (! length $v cs) {
+ return $v cs{$dir}=undef;
- return $rcs{$dir}=$r cs;
+ return $vcs{$dir}=$v cs;
- if (defined $r cs &&
- exists $config{$topdir}{$subdir}{$r cs."_".$action}) {
- return $config{$topdir}{$subdir}{$r cs."_".$action};
+ if (defined $v cs &&
+ exists $config{$topdir}{$subdir}{$v cs."_".$action}) {
+ return $config{$topdir}{$subdir}{$v cs."_".$action};
my $is_update=($action =~ /update/);
$ENV{MR_REPO}=$dir;
my $is_update=($action =~ /update/);
$ENV{MR_REPO}=$dir;
+ $ENV{MR_ACTION}=$action;
foreach my $testname ("skip", "deleted") {
my $testcommand=findcommand($testname, $dir, $topdir, $subdir, $is_checkout);
foreach my $testname ("skip", "deleted") {
my $testcommand=findcommand($testname, $dir, $topdir, $subdir, $is_checkout);
return FAILED;
}
elsif (! defined $command) {
return FAILED;
}
elsif (! defined $command) {
- my $rcs=r cs_test(@_);
- if (! defined $r cs) {
+ my $vcs=v cs_test(@_);
+ if (! defined $v cs) {
print STDERR "mr $action: unknown repository type and no defined $action command for $fulldir\n";
return FAILED;
}
else {
print STDERR "mr $action: unknown repository type and no defined $action command for $fulldir\n";
return FAILED;
}
else {
- print STDERR "mr $action: no defined action for $r cs repository $fulldir, skipping\n";
+ print STDERR "mr $action: no defined action for $v cs repository $fulldir, skipping\n";
print STDERR "mr $hook: received signal ".($? & 127)."\n";
return ABORT;
}
print STDERR "mr $hook: received signal ".($? & 127)."\n";
return ABORT;
}
+ else {
+ return FAILED;
+ }
-# figure out which repos to act on
+# Figure out which repos to act on. Returns a list of array refs
+# in the format:
+#
+# [ "$full_repo_path/", "$mr_config_path/", $section_header ]
sub selectrepos {
my @repos;
foreach my $repo (repolist()) {
sub selectrepos {
my @repos;
foreach my $repo (repolist()) {
close $in unless ref $f eq 'GLOB';
my $section;
close $in unless ref $f eq 'GLOB';
my $section;
+
+ # Keep track of the current line in the config file;
+ # when a file is included track the current line from the include.
+ my $included=undef;
+ my $includeline=0;
+ my $nextline = sub {
+ if ($included) {
+ $includeline++;
+ $included--;
+ }
+ else {
+ $included=undef;
+ $includeline=0;
+ $line++;
+ }
+ my $l=shift @lines;
+ chomp $l;
+ return $l
+ };
+ my $lineerror = sub {
+ my $msg=shift;
+ if (defined $included) {
+ die "mr: $f line $line include line $includeline: $msg\n";
+ }
+ else {
+ die "mr: $f line $line: $msg\n";
+ }
+ };
+
- $_=shift @lines;
- $line++;
- chomp;
+ $_=$nextline->();
+
+ if (! $trusted && /[[:cntrl:]]/) {
+ trusterror("mr: illegal control character", $f, $line, $bootstrap_url);
+ }
+
next if /^\s*\#/ || /^\s*$/;
if (/^\[([^\]]*)\]\s*$/) {
$section=$1;
next if /^\s*\#/ || /^\s*$/;
if (/^\[([^\]]*)\]\s*$/) {
$section=$1;
# continued value
while (@lines && $lines[0]=~/^\s(.+)/) {
# continued value
while (@lines && $lines[0]=~/^\s(.+)/) {
- shift(@lines);
- $line++;
$value.="\n$1";
chomp $value;
$value.="\n$1";
chomp $value;
if ($parameter eq "include") {
print "mr: including output of \"$value\"\n" if $verbose;
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";
}
if ($?) {
print STDERR "mr: include command exited nonzero ($?)\n";
}
+ $included += @inc;
+ unshift @lines, @inc;
next;
}
if (! defined $section) {
next;
}
if (! defined $section) {
- die "$f line $.: parameter ($parameter) not in section\n" ;
+ $lineerror->("parameter ($parameter) not in section") ;
}
if ($section eq 'ALIAS') {
$alias{$parameter}=$value;
}
if ($section eq 'ALIAS') {
$alias{$parameter}=$value;
$knownactions{$parameter}=1;
}
if ($parameter eq 'chain' &&
$knownactions{$parameter}=1;
}
if ($parameter eq 'chain' &&
- length $dir && $section ne "DEFAULT" &&
- -e $dir.$section."/.mrconfig") {
- my $ret=system($value);
- if ($ret != 0) {
- if (($? & 127) == 2) {
- print STDERR "mr: chain test interrupted\n";
- exit 2;
+ length $dir && $section ne "DEFAULT") {
+ my $chaindir="$section";
+ if ($chaindir !~ m!^/!) {
+ $chaindir=$dir.$chaindir;
+ }
+ if (-e "$chaindir/.mrconfig") {
+ my $ret=system($value);
+ if ($ret != 0) {
+ if (($? & 127) == 2) {
+ print STDERR "mr: chain test interrupted\n";
+ exit 2;
+ }
+ elsif ($? & 127) {
+ print STDERR "mr: chain test received signal ".($? & 127)."\n";
+ }
- elsif ($? & 127) {
- print STDERR "mr: chain test received signal ".($? & 127)."\n" ;
+ else {
+ push @toload, ["$chaindir/.mrconfig", $chaindir] ;
- else {
- push @toload, $dir.$section."/.mrconfig";
- }
- die "$f line $line: parse error\n" ;
+ $lineerror->("parse error") ;
- foreach (@toload) {
- loadconfig($_ );
+ foreach my $c (@toload) {
+ loadconfig(@$c );
is_bzr_checkout() {
LANG=C bzr info | egrep -q '^Checkout'
}
is_bzr_checkout() {
LANG=C bzr info | egrep -q '^Checkout'
}
+ lazy() {
+ if [ "$MR_ACTION" = checkout ] || [ -d "$MR_REPO" ]; then
+ return 1
+ else
+ return 0
+ fi
+ }
svn_test = test -d "$MR_REPO"/.svn
git_test = test -d "$MR_REPO"/.git
svn_test = test -d "$MR_REPO"/.svn
git_test = test -d "$MR_REPO"/.git