X-Git-Url: https://git.madduck.net/code/myrepos.git/blobdiff_plain/2467756e9e048a4579ee65c9980672316e12ee24..e2ccc21918b8a4bdfecc4a8e078f36d8b1b164a0:/mr?ds=sidebyside

diff --git a/mr b/mr
index 97720d4..d3c79ac 100755
--- a/mr
+++ b/mr
@@ -41,7 +41,7 @@ B<mr> [options] remember action [params ...]
 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 revision
+bzr, darcs and fossil repositories, and support for other version
 control systems can easily be added.
 
 B<mr> cds into and operates on all registered repositories at or below your
@@ -55,7 +55,7 @@ in turn chain load .mrconfig files from repositories. It also automatically
 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 revision
+These predefined commands should be fairly familiar to users of any version
 control system:
 
 =over 4
@@ -87,14 +87,14 @@ The optional -m parameter allows specifying a commit message.
 =item record
 
 Records changes to the local repository, but does not push them to the
-remote repository. Only supported for distributed revision control systems.
+remote repository. Only supported for distributed version 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
-centralized revision control systems.
+centralized version control systems.
 
 =item diff
 
@@ -189,8 +189,8 @@ Actions can be abbreviated to any unambiguous substring, so
 update"
 
 Additional parameters can be passed to most commands, and are passed on
-unchanged to the underlying revision control system. This is mostly useful
-if the repositories mr will act on all use the same revision control
+unchanged to the underlying version control system. This is mostly useful
+if the repositories mr will act on all use the same version control
 system.
 
 =head1 OPTIONS
@@ -339,6 +339,9 @@ The "MR_CONFIG" environment variable is set to the .mrconfig file
 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
@@ -354,8 +357,21 @@ mr is run by joey. The second uses the hours_since function
 (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
+
+  [linux]
+  checkout = ...
   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
 
 =item order
 
@@ -381,6 +397,14 @@ part of the including file.
 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
@@ -413,15 +437,15 @@ run before committing; "post_update" is run after updating.
 
 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 revision 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 version 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
-the action that is performed for a given revision control system, you can
-override these rcs specific actions. To add a new revision control system,
-you can just add rcs specific actions for it.
+the action that is performed for a given version control system, you can
+override these VCS specific actions. To add a new version control system,
+you can just add VCS specific actions for it.
 
 =head1 UNTRUSTED MRCONFIG FILES
 
@@ -503,41 +527,41 @@ my (@ok, @failed, @skipped);
 
 main();
 
-my %rcs;
-sub rcs_test {
+my %vcs;
+sub vcs_test {
 	my ($action, $dir, $topdir, $subdir) = @_;
 
-	if (exists $rcs{$dir}) {
-		return $rcs{$dir};
+	if (exists $vcs{$dir}) {
+		return $vcs{$dir};
 	}
 
 	my $test="set -e\n";
-	foreach my $rcs_test (
+	foreach my $vcs_test (
 			sort {
 				length $a <=> length $b 
 				          ||
 				       $a cmp $b
 			} grep { /_test$/ } keys %{$config{$topdir}{$subdir}}) {
-		my ($rcs)=$rcs_test=~/(.*)_test/;
-		$test="my_$rcs_test() {\n$config{$topdir}{$subdir}{$rcs_test}\n}\n".$test;
-		$test.="if my_$rcs_test; then echo $rcs; fi\n";
+		my ($vcs)=$vcs_test=~/(.*)_test/;
+		$test="my_$vcs_test() {\n$config{$topdir}{$subdir}{$vcs_test}\n}\n".$test;
+		$test.="if my_$vcs_test; then echo $vcs; fi\n";
 	}
 	$test=$config{$topdir}{$subdir}{lib}."\n".$test
 		if exists $config{$topdir}{$subdir}{lib};
 	
-	print "mr $action: running rcs test >>$test<<\n" if $verbose;
-	my $rcs=`$test`;
-	chomp $rcs;
-	if ($rcs=~/\n/s) {
-		$rcs=~s/\n/, /g;
-		print STDERR "mr $action: found multiple possible repository types ($rcs) for ".fulldir($topdir, $subdir)."\n";
+	print "mr $action: running vcs test >>$test<<\n" if $verbose;
+	my $vcs=`$test`;
+	chomp $vcs;
+	if ($vcs=~/\n/s) {
+		$vcs=~s/\n/, /g;
+		print STDERR "mr $action: found multiple possible repository types ($vcs) for ".fulldir($topdir, $subdir)."\n";
 		return undef;
 	}
-	if (! length $rcs) {
-		return $rcs{$dir}=undef;
+	if (! length $vcs) {
+		return $vcs{$dir}=undef;
 	}
 	else {
-		return $rcs{$dir}=$rcs;
+		return $vcs{$dir}=$vcs;
 	}
 }
 	
@@ -552,11 +576,11 @@ sub findcommand {
 		return undef;
 	}
 
-	my $rcs=rcs_test(@_);
+	my $vcs=vcs_test(@_);
 
-	if (defined $rcs && 
-	    exists $config{$topdir}{$subdir}{$rcs."_".$action}) {
-		return $config{$topdir}{$subdir}{$rcs."_".$action};
+	if (defined $vcs && 
+	    exists $config{$topdir}{$subdir}{$vcs."_".$action}) {
+		return $config{$topdir}{$subdir}{$vcs."_".$action};
 	}
 	else {
 		return undef;
@@ -579,6 +603,7 @@ sub action {
 	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);
@@ -639,13 +664,13 @@ sub action {
 		return FAILED;
 	}
 	elsif (! defined $command) {
-		my $rcs=rcs_test(@_);
-		if (! defined $rcs) {
+		my $vcs=vcs_test(@_);
+		if (! defined $vcs) {
 			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 $rcs repository $fulldir, skipping\n";
+			print STDERR "mr $action: no defined action for $vcs repository $fulldir, skipping\n";
 			return SKIPPED;
 		}
 	}
@@ -1154,11 +1179,43 @@ sub loadconfig {
 	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 $line=0;
+	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";
+		}
+	};
+
 	while (@lines) {
-		$_=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;
@@ -1184,10 +1241,9 @@ sub loadconfig {
 
 			# continued value
 			while (@lines && $lines[0]=~/^\s(.+)/) {
-				shift(@lines);
-				$line++;
 				$value.="\n$1";
 				chomp $value;
+				$nextline->();
 			}
 
 			if (! $trusted) {
@@ -1213,15 +1269,17 @@ sub loadconfig {
 
 			if ($parameter eq "include") {
 				print "mr: including output of \"$value\"\n" if $verbose;
-				unshift @lines, `$value`;
+				my @inc=`$value`;
 				if ($?) {
 					print STDERR "mr: include command exited nonzero ($?)\n";
 				}
+				$included += @inc;
+				unshift @lines, @inc;
 				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;
@@ -1262,7 +1320,7 @@ sub loadconfig {
 			}
 		}
 		else {
-			die "$f line $line: parse error\n";
+			$lineerror->("parse error");
 		}
 	}
 
@@ -1703,6 +1761,13 @@ lib =
 	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