]> 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:

factor out runsh
[code/myrepos.git] / mr
diff --git a/mr b/mr
index 4dd3a07293076dbd4b49d643b2a598fc581b0273..38bf2b779306063440b13aeb5fd487c714c93c99 100755 (executable)
--- a/mr
+++ b/mr
@@ -539,6 +539,42 @@ my (@ok, @failed, @skipped);
 
 main();
 
 
 main();
 
+sub shellquote {
+       my $i=shift;
+       $i=~s/'/'"'"'/g;
+       return "'$i'";
+}
+
+# Runs a shell command using a supplied function.
+# The lib will be included in the shell command line, and any params
+# will be available in the shell as $1, $2, etc.
+my $lastlib;
+sub runsh {
+       my ($action, $topdir, $subdir, $command, $params, $runner) = @_;
+
+       # optimisation: avoid running the shell for true and false
+       if ($command =~ /^\s*true\s*$/) {
+               $?=0;
+               return 0;
+       }
+       elsif ($command =~ /^\s*false\s*$/) {
+               $?=0;
+               return 1;
+       }
+       
+       my $quotedparams=join(" ", (map { shellquote($_) } @$params));
+       my $lib=exists $config{$topdir}{$subdir}{lib} ?
+                      $config{$topdir}{$subdir}{lib}."\n" : "";
+       if ($verbose && (! defined $lastlib || $lastlib ne $lib)) {
+               print "mr library now: >>$lib<<\n";
+               $lastlib=$lib;
+       }
+       my $shellcode="set -e;".$lib.
+               "my_sh(){ $command\n }; my_sh $quotedparams";
+       print "mr $action: running $action >>$command<<\n" if $verbose;
+       $runner->($shellcode);
+}
+
 my %vcs;
 sub vcs_test {
        my ($action, $dir, $topdir, $subdir) = @_;
 my %vcs;
 sub vcs_test {
        my ($action, $dir, $topdir, $subdir) = @_;
@@ -547,7 +583,7 @@ sub vcs_test {
                return $vcs{$dir};
        }
 
                return $vcs{$dir};
        }
 
-       my $test="set -e\n";
+       my $test="";
        foreach my $vcs_test (
                        sort {
                                length $a <=> length $b 
        foreach my $vcs_test (
                        sort {
                                length $a <=> length $b 
@@ -558,12 +594,13 @@ sub vcs_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="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 vcs test >>$test<<\n" if $verbose;
-       my $vcs=`$test`;
-       chomp $vcs;
+
+       my $vcs=runsh "vcs test", $topdir, $subdir, $test, [], sub {
+               my $sh=shift;
+               my $ret=`$sh`;
+               chomp $ret;
+               return $ret;
+       };
        if ($vcs=~/\n/s) {
                $vcs=~s/\n/, /g;
                print STDERR "mr $action: found multiple possible repository types ($vcs) for ".fulldir($topdir, $subdir)."\n";
        if ($vcs=~/\n/s) {
                $vcs=~s/\n/, /g;
                print STDERR "mr $action: found multiple possible repository types ($vcs) for ".fulldir($topdir, $subdir)."\n";
@@ -609,8 +646,6 @@ sub action {
        my $fulldir=fulldir($topdir, $subdir);
 
        $ENV{MR_CONFIG}=$configfiles{$topdir};
        my $fulldir=fulldir($topdir, $subdir);
 
        $ENV{MR_CONFIG}=$configfiles{$topdir};
-       my $lib=exists $config{$topdir}{$subdir}{lib} ?
-                      $config{$topdir}{$subdir}{lib}."\n" : "";
        my $is_checkout=($action eq 'checkout');
        my $is_update=($action =~ /update/);
 
        my $is_checkout=($action eq 'checkout');
        my $is_update=($action =~ /update/);
 
@@ -621,10 +656,9 @@ sub action {
                my $testcommand=findcommand($testname, $dir, $topdir, $subdir, $is_checkout);
 
                if (defined $testcommand) {
                my $testcommand=findcommand($testname, $dir, $topdir, $subdir, $is_checkout);
 
                if (defined $testcommand) {
-                       my $test="set -e;".$lib.
-                               "my_action(){ $testcommand\n }; my_action '$action'";
-                       print "mr $action: running $testname test >>$test<<\n" if $verbose;
-                       my $ret=system($test);
+                       my $ret=runsh "$testname test", $topdir, $subdir,
+                               $testcommand, [$action],
+                               sub { system(shift()) };
                        if ($ret != 0) {
                                if (($? & 127) == 2) {
                                        print STDERR "mr $action: interrupted\n";
                        if ($ret != 0) {
                                if (($? & 127) == 2) {
                                        print STDERR "mr $action: interrupted\n";
@@ -701,22 +735,22 @@ sub action {
                my $hookret=hook("pre_$action", $topdir, $subdir);
                return $hookret if $hookret != OK;
 
                my $hookret=hook("pre_$action", $topdir, $subdir);
                return $hookret if $hookret != OK;
 
-               $command="set -e; ".$lib.
-                       "my_action(){ $command\n }; my_action ".
-                       join(" ", map { s/\\/\\\\/g; s/"/\"/g; '"'.$_.'"' } @ARGV);
-               print "mr $action: running >>$command<<\n" if $verbose;
-               my $ret;
-               if ($quiet) {
-                       my $output = qx/$command 2>&1/;
-                       $ret = $?;
-                       if ($ret != 0) {
-                               print "$actionmsg\n";
-                               print STDERR $output;
-                       }
-               }
-               else {
-                       $ret=system($command);
-               }
+               my $ret=runsh $action, $topdir, $subdir,
+                       $command, \@ARGV, sub {
+                               my $sh=shift;
+                               if ($quiet) {
+                                       my $output = qx/$sh 2>&1/;
+                                       my $ret = $?;
+                                       if ($ret != 0) {
+                                               print "$actionmsg\n";
+                                               print STDERR $output;
+                                       }
+                                       return $ret;
+                               }
+                               else {
+                                       system($sh);
+                               }
+                       };
                if ($ret != 0) {
                        if (($? & 127) == 2) {
                                print STDERR "mr $action: interrupted\n";
                if ($ret != 0) {
                        if (($? & 127) == 2) {
                                print STDERR "mr $action: interrupted\n";
@@ -767,22 +801,20 @@ sub hook {
 
        my $command=$config{$topdir}{$subdir}{$hook};
        return OK unless defined $command;
 
        my $command=$config{$topdir}{$subdir}{$hook};
        return OK unless defined $command;
-       my $lib=exists $config{$topdir}{$subdir}{lib} ?
-                      $config{$topdir}{$subdir}{lib}."\n" : "";
-       my $shell="set -e;".$lib.
-               "my_hook(){ $command\n }; my_hook";
-       print "mr $hook: running >>$shell<<\n" if $verbose;
-       my $ret;
-       if ($quiet) {
-               my $output = qx/$shell 2>&1/;
-               $ret = $?;
-               if ($ret != 0) {
-                       print STDERR $output;
-               }
-       }
-       else {
-               $ret=system($shell);
-       }
+       my $ret=runsh $hook, $topdir, $subdir, $command, [], sub {
+                       my $sh=shift;
+                       if ($quiet) {
+                               my $output = qx/$sh 2>&1/;
+                               my $ret = $?;
+                               if ($ret != 0) {
+                                       print STDERR $output;
+                               }
+                               return $ret;
+                       }
+                       else {
+                               system($sh);
+                       }
+               };
        if ($ret != 0) {
                if (($? & 127) == 2) {
                        print STDERR "mr $hook: interrupted\n";
        if ($ret != 0) {
                if (($? & 127) == 2) {
                        print STDERR "mr $hook: interrupted\n";
@@ -1119,20 +1151,6 @@ sub is_trusted_checkout {
        return 0;
 }
 
        return 0;
 }
 
-sub trusterror {
-       my ($err, $file, $line, $url)=@_;
-       
-       if (defined $url) {
-               die "$err in untrusted $url line $line\n".
-                       "(To trust this url, --trust-all can be used; but please use caution;\n".
-                       "this can allow arbitrary code execution!)\n";
-       }
-       else {
-               die "$err in untrusted $file line $line\n".
-                       "(To trust this file, list it in ~/.mrtrust.)\n";
-       }
-}
-
 my %loaded;
 sub loadconfig {
        my $f=shift;
 my %loaded;
 sub loadconfig {
        my $f=shift;
@@ -1197,30 +1215,43 @@ sub loadconfig {
 
        # Keep track of the current line in the config file;
        # when a file is included track the current line from the include.
 
        # 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 $lineno=0;
        my $included=undef;
        my $included=undef;
-       my $includeline=0;
+
+       my $line;
        my $nextline = sub {
                if ($included) {
        my $nextline = sub {
                if ($included) {
-                       $includeline++;
                        $included--;
                }
                else {
                        $included=undef;
                        $included--;
                }
                else {
                        $included=undef;
-                       $includeline=0;
-                       $line++;
+                       $lineno++;
                }
                }
-               my $l=shift @lines;
-               chomp $l;
-               return $l
+               $line=shift @lines;
+               chomp $line;
+               return $line;
        };
        my $lineerror = sub {
                my $msg=shift;
                if (defined $included) {
        };
        my $lineerror = sub {
                my $msg=shift;
                if (defined $included) {
-                       die "mr: $f line $line include line $includeline: $msg\n";
+                       die "mr: $msg at $f line $lineno, included line: $line\n";
+               }
+               else {
+                       die "mr: $msg at $f line $lineno\n";
+               }
+       };
+       my $trusterror = sub {
+               my $msg=shift;
+               my ($err, $file, $lineno, $url)=@_;
+       
+               if (defined $bootstrap_url) {
+                       die "mr: $err in untrusted $bootstrap_url line $lineno\n".
+                               "(To trust this url, --trust-all can be used; but please use caution;\n".
+                               "this can allow arbitrary code execution!)\n";
                }
                else {
                }
                else {
-                       die "mr: $f line $line: $msg\n";
+                       die "mr: $err in untrusted $file line $lineno\n".
+                               "(To trust this file, list it in ~/.mrtrust.)\n";
                }
        };
 
                }
        };
 
@@ -1228,7 +1259,7 @@ sub loadconfig {
                $_=$nextline->();
 
                if (! $trusted && /[[:cntrl:]]/) {
                $_=$nextline->();
 
                if (! $trusted && /[[:cntrl:]]/) {
-                       trusterror("mr: illegal control character", $f, $line, $bootstrap_url);
+                       $trusterror->("illegal control character");
                }
 
                next if /^\s*\#/ || /^\s*$/;
                }
 
                next if /^\s*\#/ || /^\s*$/;
@@ -1239,7 +1270,7 @@ sub loadconfig {
                                if (! is_trusted_repo($section) ||
                                    $section eq 'ALIAS' ||
                                    $section eq 'DEFAULT') {
                                if (! is_trusted_repo($section) ||
                                    $section eq 'ALIAS' ||
                                    $section eq 'DEFAULT') {
-                                       trusterror("mr: illegal section \"[$section]\"", $f, $line, $bootstrap_url)
+                                       $trusterror->("illegal section \"[$section]\"");
                                }
                        }
                        $section=expandenv($section) if $trusted;
                                }
                        }
                        $section=expandenv($section) if $trusted;
@@ -1266,7 +1297,7 @@ sub loadconfig {
                                # settings in specific known-safe formats.
                                if ($parameter eq 'checkout') {
                                        if (! is_trusted_checkout($value)) {
                                # settings in specific known-safe formats.
                                if ($parameter eq 'checkout') {
                                        if (! is_trusted_checkout($value)) {
-                                               trusterror("mr: illegal checkout command \"$value\"", $f, $line, $bootstrap_url);
+                                               $trusterror->("illegal checkout command \"$value\"");
                                        }
                                }
                                elsif ($parameter eq 'order') {
                                        }
                                }
                                elsif ($parameter eq 'order') {
@@ -1278,7 +1309,7 @@ sub loadconfig {
                                        # safe.
                                }
                                else {
                                        # safe.
                                }
                                else {
-                                       trusterror("mr: illegal setting \"$parameter=$value\"", $f, $line, $bootstrap_url);
+                                       $trusterror->("illegal setting \"$parameter=$value\"");
                                }
                        }
 
                                }
                        }