Added option to avoid temporary directory in "remote"ly deployed file.
[deployable.git] / remote
blob62cfa8ba9c358512a4e0b8b528cae60ff0d25796
1 #!/usr/bin/perl
2 use strict;
3 use warnings;
4 use 5.006_002;
5 my $VERSION = '0.0.1';
6 use English qw( -no_match_vars );
7 use Fatal qw( close chdir mkdir );
8 use File::Temp qw( tempdir );
9 use File::Spec::Functions
10 qw( file_name_is_absolute splitpath splitdir catfile );
11 use File::Basename qw( basename );
12 use POSIX qw( strftime );
13 use Getopt::Long qw( :config gnu_getopt );
14 use Cwd qw( getcwd );
16 my %default_config = ( # default values
17 workdir => '/tmp/our-deploy',
18 cleanup => 1,
20 my %config;
21 GetOptions(
22 \%config, 'usage|help|man',
23 'version', 'cleanup|c!',
24 'dryrun|dry-run', 'no-deploy!',
25 'show|show-options|s!', 'workdir|work-directory|deploy-directory|w=s',
26 'no-tempdir!',
29 usage() if $config{usage};
30 version() if $config{version};
32 my %script_config = (%default_config, get_config());
33 if ($config{show}) {
34 require Data::Dumper;
35 print {*STDOUT} Data::Dumper::Dumper(\%script_config);
36 exit 1;
39 # Merge configurations and go on
40 %config = (%script_config, %config);
41 $config{deploy} = [] if $config{'no-deploy'};
43 if ($config{dryrun}) {
44 require Data::Dumper;
45 print {*STDOUT} Data::Dumper::Dumper(\%config);
46 exit 1;
49 # go into the working directory, creating any intermediate if needed
50 my ($volume, $directories) = splitpath($config{workdir}, 1);
51 my @directories = splitdir($directories);
52 if (@directories) {
53 if ($directories[0] eq '') {
54 shift @directories;
55 chdir '/';
57 for my $subdir (@directories) {
58 next unless length $subdir;
59 mkdir $subdir unless -e $subdir;
60 chdir $subdir;
62 } ## end if (@directories)
63 print {*STDERR} "### Got into working directory '$config{workdir}'\n\n";
65 my $tempdir;
66 if (!$config{'no-tempdir'}) { # Only if not prohibited
67 my $now = strftime('%Y-%m-%d_%H-%M-%S', localtime);
68 $tempdir =
69 tempdir($now . 'X' x 10, DIR => '.', CLEANUP => $config{cleanup});
71 chdir $tempdir;
72 print {*STDERR}
73 "### Created and got into temporary directory '$tempdir'\n";
74 print {*STDERR} "### (will clean it up later)\n" if $config{cleanup};
75 print {*STDERR} "\n";
76 } ## end if (!$config{'no-tempdir'...
78 eval { # Not really needed, but you know...
79 $ENV{PATH} = '/bin:/usr/bin:/sbin:/usr/sbin';
80 save_files();
81 execute_deploy_programs();
84 # Get back so that cleanup can successfully happen, if requested
85 chdir '..' if defined $tempdir;
87 sub execute_deploy_programs {
88 DEPLOY:
89 for my $deploy (@{$config{deploy}}) {
90 $deploy = catfile('.', $deploy)
91 unless file_name_is_absolute($deploy);
92 if (!-x $deploy) {
93 print {*STDERR} "### Skipping '$deploy', not executable\n\n";
94 next DEPLOY;
96 print {*STDERR} "### Executing '$deploy'...\n";
97 system {$deploy} $deploy;
98 print {*STDERR} "\n";
99 } ## end for my $deploy (@{$config...
101 return;
102 } ## end sub execute_deploy_programs
105 my ($last, $getlast);
106 sub unget_DATA_line { $getlast = 1 }
108 sub get_DATA_line {
109 if (!$getlast) {
110 if (defined($last = <DATA>)) {
111 $last =~ s/#.*//;
112 $last =~ s/\s+//g;
114 } ## end if (!$getlast)
115 $getlast = 0; # reset the flag anyway
116 return $_ = $last;
117 } ## end sub get_DATA_line
120 sub skip_DATA_spaces {
121 local $_;
122 while (defined get_DATA_line()) { last if /\S/ }
123 unget_DATA_line();
126 sub get_config {
127 my %config;
129 while (defined get_DATA_line()) {
130 next unless length $_;
131 last if $_ eq '[files]';
133 my ($name, $value) = split /=/, $_;
134 $value = pack 'H*', $value;
136 if (substr($name, -1) eq '@') {
137 substr $name, -1, 1, '';
138 push @{$config{$name}}, $value;
140 else {
141 $config{$name} = $value;
143 } ## end while (defined get_DATA_line...
145 return %config if wantarray;
146 return \%config;
147 } ## end sub get_config
149 sub save_files {
150 while (defined get_DATA_line()) {
151 next unless length $_;
153 my ($tag, $filename) = split /\s*=\s*/, $_;
155 # Un-hexify and ensure it's written in the current directory
156 $filename = pack 'H*', $filename;
157 my $mode;
158 ($mode, $filename) = split /\s+/, $filename, 2 if $tag eq 'file';
159 $filename = basename($filename);
161 print {*STDERR} "### Working on $tag '$filename'\n";
163 # Establish where to send the output
164 my @fhs;
165 push @fhs, output_fh($filename)
166 if ($tag eq 'file') || ($tag eq 'tarfile');
167 push @fhs, pipe_to_tar()
168 if ($tag eq 'directory') || ($tag eq 'tarfile');
169 print {*STDERR} "skipping invalid file tag '$tag'\n"
170 unless @fhs;
172 # Skip empty lines and filter input stuff to output handles
173 skip_DATA_spaces();
174 while (defined get_DATA_line()) {
175 last unless length $_; # empty line marks end of chunk
176 if (@fhs) { # work only if really necessary
177 my $line = pack 'H*', $_;
178 print {$_} $line for @fhs;
180 } ## end while (defined get_DATA_line...
181 close $_ for @fhs;
183 chmod oct($mode), $filename if $tag eq 'file';
185 print {*STDERR} "\n";
186 } ## end while (defined get_DATA_line...
187 } ## end sub save_files
189 sub output_fh {
190 my ($filename) = @_;
191 open my $fh, '>', $filename or die "open('$filename'): $OS_ERROR";
192 binmode $fh;
193 return $fh;
194 } ## end sub output_fh
196 sub pipe_to_tar {
197 open my $fh, '|-', '/bin/tar', 'xvzf', '-', '--no-same-owner', '--touch'
198 or die "open() for /bin/tar: $OS_ERROR";
199 binmode $fh;
200 return $fh;
201 } ## end sub pipe_to_tar
203 sub usage {
204 print {*STDOUT} <<"END_OF_USAGE" ;
205 $0 version $VERSION
207 More or less, this script is intended to be launched without parameters.
208 Anyway, you can also set the following options, which will override any
209 present configuration (except in "--show-options"):
211 * --usage | --man | --help
212 print these help lines and exit
214 * --version
215 print script version and exit
217 * --show-options | -s
218 print configured options and exit
220 * --cleanup | --no-cleanup
221 perform / don't perform temporary directory cleanup after work done
223 * --no-deploy
224 prevent execution of deploy scripts (they are executed by default)
226 * --no-tempdir
227 execute directly in workdir (see below), without creating the
228 temporary directory
230 * --dryrun | --dry-run
231 print final options and exit
233 * --workdir | -w
234 working base directory (a temporary subdirectory will be created
235 there anyway)
237 END_OF_USAGE
238 exit 1;
239 } ## end sub usage
241 sub version {
242 print "$0 version $VERSION\n";
243 exit 1;
246 __END__
247 ########################################################################
248 # General configurations
250 # workdir = /tmp/our-deploy
251 workdir = 2f746d702f6f75722d6465706c6f79
253 # cleanup = 0
254 cleanup = 30
256 # deploy@ = test-deploy
257 deploy@ = 746573742d6465706c6f79
259 ########################################################################
260 # List of files
261 [files]
263 # file saves both mode and filename
264 # file = 0755 test-deploy
265 file = 3037353520746573742d6465706c6f79
266 23212f62696e2f626173680a0a504154483d272f62696e3a2f7573722f62696e
267 3a2f7362696e3a2f7573722f7362696e270a0a6563686f20276369616f206120
268 7475747469270a7077640a66696e640a
270 # directory testdir, extracted into:
271 # directory = .
272 directory = 2e
273 1f8b0800afdb5a470003ed934b0ac3300c44bdee297c83caa9649dc7b459180a
274 098edaf3d72e31649366e58412bdcd182cd06718e92779c474350d810c131575
275 4cb0d48a71c09d27c42ebfc1ddd87963a9e55095d72421596bc6e1d98bc4d5ba
276 adffba48d53f4166ffc734bc43a31ee51e1ef187ff7ef6df2141ae73c80cc6ee
277 72c493fbfff5fd72f414ca51d4fcdf63185af5d8ce3f2df2cf25ff445ef3bf07
278 c5778dbfa228caf9f800fd955b7b000e00000000000000000000000000000000
279 0000000000000000000000000000000000000000000000000000000000000000
280 0000000000000000000000000000000000000000000000000000000000000000
281 0000000000000000000000000000000000000000000000000000000000000000
282 0000000000000000000000000000000000000000000000000000000000000000
283 0000000000000000000000000000000000000000000000000000000000000000
284 0000000000000000000000000000000000000000000000000000000000000000
285 0000000000000000000000000000000000000000000000000000000000000000
286 0000000000000000000000000000000000000000000000000000000000000000
287 0000000000000000000000000000000000000000000000000000000000000000
288 0000000000000000000000000000000000000000000000000000000000000000
290 # tarfile will also be extracted into .
291 # tarfile = tarfile-contents.tar.gz
292 tarfile = 74617266696c652d636f6e74656e74732e7461722e677a
293 1f8b080062c85a470003edd17d0ac2300c87e11ea51718b65db39e67c884c2e8
294 648bf7d709039988821f307c9f7f7e9414da24da8e87dc77d57e28da159d76e6
295 f3dc451299d32771b7b930dea5d0488cbef6c67991108d952ffce5ce69d276b4
296 d61c87be53cd0fef3dab2f8d2cb911badefff5944bb52ebcf1c63c8f26c6d7f7
297 1f42a893b13f19e29fef1f000000000000000000000000c0769d0198ae093a00
298 280000
300 # here-directory = heredir/, extracted into:
301 # directory = .
302 directory = 2e
303 1f8b0800afdb5a470003d3d367a039300002735353106d686e6a804cc30083a1
304 81b99199a9898981b9218381a191898131838229ed9dc6c0505a5c9258a4a0c0
305 50909f935a529289531d2179984760f410017afa19a945a9699939a9ba9979ba
306 20764a661195ed00858799890909f16f6668048c7fba04e2088fff51300a46c1
307 c8050061a52c3500080000000000000000000000000000000000000000000000
308 0000000000000000000000000000000000000000000000000000000000000000
309 0000000000000000000000000000000000000000000000000000000000000000
310 0000000000000000000000000000000000000000000000000000000000000000
311 0000000000000000000000000000000000000000000000000000000000000000
312 0000000000000000000000000000000000000000000000000000000000000000
313 0000000000000000000000000000000000000000000000000000000000000000
314 0000000000000000000000000000000000000000000000000000000000000000
315 0000000000000000000000000000000000000000000000000000000000000000
316 0000000000000000000000000000000000000000000000000000000000000000
317 0000000000000000000000000000000000000000000000000000000000000000
318 0000000000000000000000000000000000000000000000000000000000000000