sj: Add -W/--wait option
[sunny256-utils.git] / git-rcmd
blob229bb45cac4b4bad84ab3efe7d71cfbbf7dc081a
1 #!/usr/bin/env perl
3 #=======================================================================
4 # git-rcmd
5 # File ID: 8ed5e844-cf09-11e4-b7ff-000df06acc56
7 # Execute command in remote Git repositories
9 # Character set: UTF-8
10 # ©opyleft 2012– Øyvind A. Holm <sunny@sunbase.org>
11 # License: GNU General Public License version 2 or later, see end of
12 # file for legal stuff.
13 #=======================================================================
15 use strict;
16 use warnings;
17 use Getopt::Long;
19 local $| = 1;
21 our %Opt = (
23 'cmd' => '',
24 'dry-run' => 0,
25 'help' => 0,
26 'local' => 0,
27 'quiet' => 0,
28 'verbose' => 0,
29 'version' => 0,
33 our $progname = $0;
34 $progname =~ s/^.*\/(.*?)$/$1/;
35 our $VERSION = '0.2.0';
37 our $hostname = `hostname`;
38 chomp($hostname);
40 Getopt::Long::Configure('bundling');
41 GetOptions(
43 'cmd|c=s' => \$Opt{'cmd'},
44 'dry-run|n' => \$Opt{'dry-run'},
45 'help|h' => \$Opt{'help'},
46 'local|l' => \$Opt{'local'},
47 'quiet|q+' => \$Opt{'quiet'},
48 'verbose|v+' => \$Opt{'verbose'},
49 'version' => \$Opt{'version'},
51 ) || die("$progname: Option error. Use -h for help.\n");
53 $Opt{'verbose'} -= $Opt{'quiet'};
54 $Opt{'help'} && usage(0);
55 if ($Opt{'version'}) {
56 print_version();
57 exit(0);
60 if (!length($Opt{'cmd'})) {
61 die("$progname: -c/--cmd option not specified\n");
64 exit(main());
66 sub main {
67 # {{{
68 my $Retval = 0;
70 if ($Opt{'local'}) {
71 system("ga-pwd");
72 mysystem($Opt{'cmd'});
73 $Opt{'verbose'} >= 0 && print("\n");
75 open(my $pipefp, 'git remote -v |') or die("$progname: git remote -v: Cannot open pipe: $!\n");
76 my %done = ();
77 while (my $curr = <$pipefp>) {
78 if ($curr =~ /^(\S+)\s+(\S+)\s/) {
79 my ($remote, $url) = ($1, $2);
80 if ($url =~ /^(\S+)\@(\S+):(\S+)$/) {
81 # The URL looks SSHish
82 my ($username, $host, $userdir) = ($1, $2, $3);
83 next if ($userdir =~ /\.git$/); # Avoid bare repos
84 if (!defined($done{"$username$host$userdir"})) {
85 my @cmd = (
86 'ssh',
87 '-A',
88 "$username\@$host",
89 "cd $userdir && (ga-pwd; $Opt{'cmd'})",
91 mysystem(@cmd);
92 $done{"$username$host$userdir"} = 1;
93 $Opt{'verbose'} >= 0 && print("\n");
95 } elsif (-d "$url/.") {
96 if (!defined($done{"$url"}) && chdir($url)) {
97 next if (!-d ".git/."); # Avoid bare repos
98 msg(0, "($hostname) chdir $url");
99 system("ga-pwd");
100 mysystem($Opt{'cmd'});
101 $done{"$url"} = 1;
102 $Opt{'verbose'} >= 0 && print("\n");
107 close($pipefp);
109 return $Retval;
110 # }}}
111 } # main()
113 sub check_sig {
114 # {{{
115 my $retval = shift;
116 ($retval & 127) && die("\n$progname: Child process interrupted, aborting.\n");
117 return(0);
118 # }}}
119 } # check_sig()
121 sub mysystem {
122 # {{{
123 my @cmd = @_;
124 msg(0, sprintf("(%s) %s '", $hostname, $Opt{'dry-run'} ? "Simulating" : "Executing") .
125 join(" ", @cmd) . "'...");
126 $? = 0;
127 !$Opt{'dry-run'} && system(@cmd) && check_sig($?);
128 return $?;
129 # }}}
130 } # mysystem()
132 sub print_version {
133 # Print program version {{{
134 print("$progname $VERSION\n");
135 return;
136 # }}}
137 } # print_version()
139 sub usage {
140 # Send the help message to stdout {{{
141 my $Retval = shift;
143 if ($Opt{'verbose'}) {
144 print("\n");
145 print_version();
147 print(<<"END");
149 Usage: $progname [options] -c COMMAND
151 Execute commands in remote repositories via ssh. Scans all available
152 remotes and checks if it looks SSHish. If it does, it logs in and
153 executes the command specified with the -c/--cmd option in the
154 directory.
156 Options:
158 -c COMMAND, --cmd COMMAND
159 Execute COMMAND in remote repositories.
160 -h, --help
161 Show this help.
162 -l, --local
163 Also execute the command in the local repository.
164 -n, --dry-run
165 Simulate, don't actually execute any commands.
166 -q, --quiet
167 Be more quiet. Can be repeated to increase silence.
168 -v, --verbose
169 Increase level of verbosity. Can be repeated.
170 --version
171 Print version information.
174 exit($Retval);
175 # }}}
176 } # usage()
178 sub msg {
179 # Print a status message to stderr based on verbosity level {{{
180 my ($verbose_level, $Txt) = @_;
182 if ($Opt{'verbose'} >= $verbose_level) {
183 print(STDERR "$progname: $Txt\n");
185 return;
186 # }}}
187 } # msg()
189 __END__
191 # This program is free software; you can redistribute it and/or modify
192 # it under the terms of the GNU General Public License as published by
193 # the Free Software Foundation; either version 2 of the License, or (at
194 # your option) any later version.
196 # This program is distributed in the hope that it will be useful, but
197 # WITHOUT ANY WARRANTY; without even the implied warranty of
198 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
199 # See the GNU General Public License for more details.
201 # You should have received a copy of the GNU General Public License
202 # along with this program.
203 # If not, see L<http://www.gnu.org/licenses/>.
205 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :