1 | #!/usr/bin/perl |
---|
2 | |
---|
3 | # $Id: dasscm 1069 2012-08-17 11:23:16Z joergs $ |
---|
4 | |
---|
5 | use warnings; |
---|
6 | use strict; |
---|
7 | |
---|
8 | use Env |
---|
9 | qw($DASSCM_PROD $DASSCM_REPO $USER $DASSCM_USERNAME $DASSCM_USER $DASSCM_PASSWORD $SHELL); |
---|
10 | use Cwd; |
---|
11 | use Getopt::Long; |
---|
12 | use File::Basename; |
---|
13 | use File::Compare; |
---|
14 | ## used system("cp -a"), because File::Copy does not keep permissions |
---|
15 | ##use File::Copy; |
---|
16 | use File::Find; |
---|
17 | use File::stat; |
---|
18 | use File::Path; |
---|
19 | ## Term::ReadKey (ReadMode('noecho')) replaced by "stty" to reduce dependencies |
---|
20 | ##use Term::ReadKey; |
---|
21 | |
---|
22 | use Data::Dumper; |
---|
23 | |
---|
24 | ##################################################################### |
---|
25 | # |
---|
26 | # global |
---|
27 | # |
---|
28 | |
---|
29 | # shell exit codes |
---|
30 | my $RETURN_OK = 0; |
---|
31 | my $RETURN_NOK = 1; |
---|
32 | |
---|
33 | # Nagios return codes |
---|
34 | my $RETURN_WARN = 1; |
---|
35 | my $RETURN_CRIT = 2; |
---|
36 | my $RETURN_UNKNOWN = 3; |
---|
37 | |
---|
38 | # documentation file (for usage) |
---|
39 | my $doc_file = "/usr/share/doc/packages/dasscm/dasscm_howto.txt"; |
---|
40 | |
---|
41 | my $config_file = "/etc/dasscm.conf"; |
---|
42 | my $config = get_config($config_file); |
---|
43 | |
---|
44 | my @OPTIONS_GLOBAL = ( 'help', 'verbose' ); |
---|
45 | |
---|
46 | # command called => command definition key |
---|
47 | my %COMMANDS = ( |
---|
48 | 'help' => 'help', |
---|
49 | 'login' => 'login', |
---|
50 | 'init' => 'init', |
---|
51 | 'ls' => 'ls', |
---|
52 | 'update' => 'update', |
---|
53 | 'up' => 'update', |
---|
54 | 'add' => 'add', |
---|
55 | 'commit' => 'commit', |
---|
56 | 'checkin' => 'commit', |
---|
57 | 'ci' => 'commit', |
---|
58 | 'revert' => 'revert', |
---|
59 | 'blame' => 'blame', |
---|
60 | 'diff' => 'diff', |
---|
61 | 'status' => 'status', |
---|
62 | 'st' => 'status', |
---|
63 | 'check' => 'check', |
---|
64 | 'permissions' => 'permissions', |
---|
65 | 'cleanup' => 'cleanup', |
---|
66 | 'complete' => 'complete', |
---|
67 | 'complete_path' => 'complete_path', |
---|
68 | 'complete_repopath' => 'complete_repopath', |
---|
69 | 'plugins' => 'plugins', |
---|
70 | ); |
---|
71 | |
---|
72 | # desc: description (eg. for usage) |
---|
73 | # params: parameters |
---|
74 | # CMD |
---|
75 | # USER |
---|
76 | # PATH_PROD |
---|
77 | # PATH_REPO |
---|
78 | # require: |
---|
79 | # WRITE commands that require write access (and therefore a login) |
---|
80 | my %COMMAND_DEFINITIONS = ( |
---|
81 | 'help' => { |
---|
82 | 'desc' => ["print help and usage information"], |
---|
83 | 'params' => ["CMD"], |
---|
84 | 'function' => \&help, |
---|
85 | }, |
---|
86 | 'login' => { |
---|
87 | 'desc' => ["user login to Subversion repositoty"], |
---|
88 | 'params' => ["USER"], |
---|
89 | 'function' => \&login |
---|
90 | }, |
---|
91 | 'init' => { |
---|
92 | 'desc' => [ |
---|
93 | "initialize local subversion checkout.", |
---|
94 | "This is the first thing to do (after configuring $config_file)" |
---|
95 | ], |
---|
96 | 'params' => [], |
---|
97 | 'function' => \&init |
---|
98 | }, |
---|
99 | 'ls' => { |
---|
100 | 'desc' => ["list file from repository"], |
---|
101 | 'params' => ["PATH_REPO"], |
---|
102 | 'function' => \&ls |
---|
103 | }, |
---|
104 | 'update' => { |
---|
105 | 'desc' => [ |
---|
106 | "update local repository checkout", |
---|
107 | "Normally, this is done automatically" |
---|
108 | ], |
---|
109 | 'params' => ["PATH_REPO"], |
---|
110 | 'function' => \&update |
---|
111 | }, |
---|
112 | 'add' => { |
---|
113 | 'desc' => [ |
---|
114 | "add a file to the subversion repository", |
---|
115 | "Unlike the native svn command,", |
---|
116 | "dasscm adds and immediatly submits a file to the subversion repository" |
---|
117 | ], |
---|
118 | 'params' => ["PATH_PROD"], |
---|
119 | 'options' => [ 'verbose', 'message=s' ], |
---|
120 | 'require' => ["WRITE"], |
---|
121 | 'function' => \&add |
---|
122 | }, |
---|
123 | 'commit' => { |
---|
124 | 'desc' => ["commit a changed file to the subversion repository"], |
---|
125 | ## TODO: only modified files |
---|
126 | 'params' => ["PATH_REPO"], |
---|
127 | 'options' => [ 'verbose', 'message=s' ], |
---|
128 | 'require' => ["WRITE"], |
---|
129 | 'function' => \&commit |
---|
130 | }, |
---|
131 | 'revert' => { |
---|
132 | 'desc' => [ |
---|
133 | "revert local changes back to version from the repository (see diff)" |
---|
134 | ], |
---|
135 | 'params' => ["PATH_REPO"], |
---|
136 | 'function' => \&revert |
---|
137 | }, |
---|
138 | 'blame' => { |
---|
139 | 'desc' => ['like "svn blame"'], |
---|
140 | ## TODO: only files from PATH_REPO |
---|
141 | 'params' => ["PATH_REPO"], |
---|
142 | 'function' => \&blame |
---|
143 | }, |
---|
144 | 'diff' => { |
---|
145 | 'desc' => [ |
---|
146 | 'display the differences between files on the system and the repository' |
---|
147 | ], |
---|
148 | 'params' => ["PATH_REPO"], |
---|
149 | 'function' => \&diff |
---|
150 | }, |
---|
151 | 'status' => { |
---|
152 | 'desc' => [ |
---|
153 | 'display status information about modified and deleted files.', |
---|
154 | 'If no path is given "/" is assumed', |
---|
155 | '(in contract to "svn" with assumes ".")' |
---|
156 | ], |
---|
157 | 'params' => ["PATH_REPO"], |
---|
158 | 'function' => \&status |
---|
159 | }, |
---|
160 | 'check' => { |
---|
161 | 'desc' => ["perform Nagios NRPE conform check"], |
---|
162 | 'params' => [], |
---|
163 | 'function' => \&check |
---|
164 | }, |
---|
165 | 'permissions' => { |
---|
166 | 'desc' => |
---|
167 | ["internal, print permissions for all files in the repository"], |
---|
168 | 'params' => [], |
---|
169 | 'function' => \&permissions |
---|
170 | }, |
---|
171 | 'cleanup' => { |
---|
172 | 'desc' => ["internal, used to clean repository checkout"], |
---|
173 | 'params' => [], |
---|
174 | 'function' => \&cleanup |
---|
175 | }, |
---|
176 | 'complete' => { |
---|
177 | 'desc' => ["internal, used for bash completion"], |
---|
178 | 'params' => ["CMD"], |
---|
179 | 'function' => \&complete |
---|
180 | }, |
---|
181 | 'complete_path' => { |
---|
182 | 'desc' => ["internal, used for bash completion"], |
---|
183 | 'params' => [], |
---|
184 | 'function' => \&complete_path |
---|
185 | }, |
---|
186 | 'complete_repopath' => { |
---|
187 | 'desc' => ["internal, used for bash completion"], |
---|
188 | 'params' => [], |
---|
189 | 'function' => \&complete_repopath |
---|
190 | }, |
---|
191 | 'plugins' => { |
---|
192 | 'desc' => ["internal, perform plugins"], |
---|
193 | 'params' => [], |
---|
194 | 'function' => \&perform_plugins |
---|
195 | }, |
---|
196 | |
---|
197 | ); |
---|
198 | |
---|
199 | # configuration file |
---|
200 | my $DASSCM_LOCAL_REPOSITORY_BASE; |
---|
201 | my $DASSCM_REPOSITORY_NAME; |
---|
202 | my $DASSCM_PLUGIN_RESULTS_PATH; |
---|
203 | my $DASSCM_SVN_REPOSITORY; |
---|
204 | my $DASSCM_CHECKOUT_USERNAME; |
---|
205 | my $DASSCM_CHECKOUT_PASSWORD; |
---|
206 | my $DASSCM_GID; |
---|
207 | my @DASSCM_ADDITIONAL_FILES; |
---|
208 | |
---|
209 | # current directory at program start |
---|
210 | my $StartDirectory = cwd(); |
---|
211 | |
---|
212 | my $diff = "diff --exclude .svn "; |
---|
213 | my $SVN = "svn "; |
---|
214 | my $svnOptions = ""; |
---|
215 | my $svnCheckoutCredentials = ""; |
---|
216 | my $svnPasswordCredentials = ""; |
---|
217 | |
---|
218 | # flag. Set to true by svn_update |
---|
219 | # This prevents, that svn_update is called multiple times |
---|
220 | my $svnRepositoryIsUptodate = 0; |
---|
221 | |
---|
222 | # command line options get stored in options hash |
---|
223 | my %options = (); |
---|
224 | |
---|
225 | # subcommand, that gets executed (add, commit, ...) |
---|
226 | my $command; |
---|
227 | |
---|
228 | my $verbose = 0; |
---|
229 | |
---|
230 | ##################################################################### |
---|
231 | # |
---|
232 | # util functions |
---|
233 | # |
---|
234 | sub usage() |
---|
235 | { |
---|
236 | print '$Id: dasscm 1069 2012-08-17 11:23:16Z joergs $'; |
---|
237 | print "\n\n"; |
---|
238 | print "usage: dasscm <subcommand> [options] [args]\n"; |
---|
239 | print "\n"; |
---|
240 | print "dasscm is intended to help versioning configuration files\n"; |
---|
241 | print "\n"; |
---|
242 | print "Available subcommands:\n"; |
---|
243 | foreach my $i ( sort keys(%COMMAND_DEFINITIONS) ) { |
---|
244 | print " ", $i, " ", join( " ", get_command_possible_params($i) ), |
---|
245 | "\n"; |
---|
246 | foreach my $line ( get_command_desc($i) ) { |
---|
247 | print " " x 20, $line, "\n"; |
---|
248 | } |
---|
249 | } |
---|
250 | print "\n"; |
---|
251 | print "If dasscm is not yet configured, read $doc_file\n"; |
---|
252 | } |
---|
253 | |
---|
254 | sub warning(@) |
---|
255 | { |
---|
256 | print "Warning: " . join( "\n ", @_ ) . "\n"; |
---|
257 | } |
---|
258 | |
---|
259 | sub error(@) |
---|
260 | { |
---|
261 | print "Error: " . join( "\n ", @_ ) . "\n"; |
---|
262 | } |
---|
263 | |
---|
264 | sub fatalerror(@) |
---|
265 | { |
---|
266 | error(@_); |
---|
267 | |
---|
268 | #print "Exiting\n"; |
---|
269 | exit 1; |
---|
270 | } |
---|
271 | |
---|
272 | # |
---|
273 | # reading config file and return key/value pairs as hash |
---|
274 | # |
---|
275 | sub get_config |
---|
276 | { |
---|
277 | my $file = $_[0]; |
---|
278 | |
---|
279 | if ( !$file ) { |
---|
280 | fatalerror( "failed to open config file" . $file ); |
---|
281 | } |
---|
282 | |
---|
283 | my $data = {}; |
---|
284 | |
---|
285 | # try to open config file |
---|
286 | if ( !open( FH, $file ) ) { |
---|
287 | fatalerror( "failed to open config file" . $file ); |
---|
288 | } else { |
---|
289 | while (<FH>) { |
---|
290 | chomp; |
---|
291 | if (/^#/) { |
---|
292 | next; |
---|
293 | } |
---|
294 | if ( $_ =~ /=/g ) { |
---|
295 | |
---|
296 | # splitting in 2 fields at maximum |
---|
297 | my ( $option, $value ) = split( /=/, $_, 2 ); |
---|
298 | $option =~ s/^\s+//g; |
---|
299 | $option =~ s/\s+$//g; |
---|
300 | $option =~ s/\"+//g; |
---|
301 | $value =~ s/^\s+//g; |
---|
302 | $value =~ s/\s+$//g; |
---|
303 | $value =~ s/\"+//g; |
---|
304 | |
---|
305 | if ( length($option) ) { |
---|
306 | $data->{$option} = $value; |
---|
307 | } |
---|
308 | } |
---|
309 | } |
---|
310 | } |
---|
311 | close(FH); |
---|
312 | |
---|
313 | return $data; |
---|
314 | } |
---|
315 | |
---|
316 | # |
---|
317 | # check and evaluate environment variables |
---|
318 | # |
---|
319 | sub check_env() |
---|
320 | { |
---|
321 | |
---|
322 | # DASSCM_PROD |
---|
323 | if ( !$DASSCM_PROD ) { |
---|
324 | $DASSCM_PROD = "/"; |
---|
325 | } |
---|
326 | |
---|
327 | if ( !-d $DASSCM_PROD ) { |
---|
328 | die "DASSCM_PROD ($DASSCM_PROD) is not set to a directory.\n"; |
---|
329 | } |
---|
330 | if ($verbose) { print "DASSCM_PROD: " . $DASSCM_PROD . "\n"; } |
---|
331 | |
---|
332 | # DASSCM_REPOSITORY_NAME |
---|
333 | if ( !$DASSCM_REPOSITORY_NAME ) { |
---|
334 | die |
---|
335 | "Variable DASSCM_REPOSITORY_NAME is not defined.\nIt needs to be a unique name.\nNormally the full qualified host name is used.\nUse file $config_file to configure it.\n"; |
---|
336 | } |
---|
337 | |
---|
338 | # DASSCM_REPO |
---|
339 | if ( !$DASSCM_REPO ) { |
---|
340 | if ( $DASSCM_LOCAL_REPOSITORY_BASE && $DASSCM_REPOSITORY_NAME ) { |
---|
341 | $DASSCM_REPO = |
---|
342 | $DASSCM_LOCAL_REPOSITORY_BASE . "/" . $DASSCM_REPOSITORY_NAME; |
---|
343 | } else { |
---|
344 | die |
---|
345 | "Envirnonment variable DASSCM_REPO not set.\nSet DASSCM_REPO to the directory of the versioning system checkout for this machine.\n"; |
---|
346 | } |
---|
347 | } |
---|
348 | $DASSCM_REPO = normalize_path($DASSCM_REPO); |
---|
349 | if ($verbose) { print "DASSCM_REPO: " . $DASSCM_REPO . "\n"; } |
---|
350 | |
---|
351 | # |
---|
352 | # subversion checkout user |
---|
353 | # |
---|
354 | if ( !$DASSCM_CHECKOUT_USERNAME ) { |
---|
355 | fatalerror( |
---|
356 | "variable DASSCM_CHECKOUT_USERNAME is not defined.", |
---|
357 | "Use file $config_file to configure it." |
---|
358 | ); |
---|
359 | } |
---|
360 | |
---|
361 | if ( !$DASSCM_CHECKOUT_PASSWORD ) { |
---|
362 | fatalerror( |
---|
363 | "variable DASSCM_CHECKOUT_PASSWORD is not defined.", |
---|
364 | "Use file $config_file to configure it." |
---|
365 | ); |
---|
366 | } |
---|
367 | |
---|
368 | # |
---|
369 | # check if local repository directory exist |
---|
370 | # (if not creating by init) |
---|
371 | # |
---|
372 | if ( $command ne "init" ) { |
---|
373 | if ( not -d $DASSCM_REPO ) { |
---|
374 | fatalerror( |
---|
375 | "Can't access local repository DASSCM_REPO", |
---|
376 | "($DASSCM_REPO)", |
---|
377 | "Check configuration and execute", |
---|
378 | "dasscm init" |
---|
379 | ); |
---|
380 | } |
---|
381 | |
---|
382 | # |
---|
383 | # user settings |
---|
384 | # |
---|
385 | |
---|
386 | # DASSCM_USER is legacy. Use DASSCM_USERNAME instead |
---|
387 | if ( !$DASSCM_USERNAME ) { |
---|
388 | $DASSCM_USERNAME = $DASSCM_USER; |
---|
389 | } |
---|
390 | |
---|
391 | # user root is not allowed for checkins. |
---|
392 | # if user is root, DASSCM_USER has to be set, |
---|
393 | # otherwise USER can be used |
---|
394 | if ( "$USER" eq "root" ) { |
---|
395 | if ( ( not $DASSCM_USERNAME ) |
---|
396 | and ( get_command_requires_write($command) ) ) |
---|
397 | { |
---|
398 | |
---|
399 | #( $command ne "login" ) and ( $command ne "status" ) ) { |
---|
400 | fatalerror( |
---|
401 | "Envirnonment variable DASSCM_USERNAME not set.", |
---|
402 | "Set DASSCM_USERNAME to your subversion user account or", |
---|
403 | "use 'dasscm login'" |
---|
404 | ); |
---|
405 | } |
---|
406 | $svnOptions .= " --no-auth-cache "; |
---|
407 | } elsif ( !$DASSCM_USERNAME ) { |
---|
408 | $DASSCM_USERNAME = $USER; |
---|
409 | } |
---|
410 | |
---|
411 | # |
---|
412 | # password |
---|
413 | # |
---|
414 | if ($DASSCM_PASSWORD) { |
---|
415 | $svnPasswordCredentials = " --password '$DASSCM_PASSWORD' "; |
---|
416 | } |
---|
417 | } |
---|
418 | |
---|
419 | #$svnOptions .= " --username $DASSCM_USERNAME " |
---|
420 | |
---|
421 | # |
---|
422 | # prepare file permissions |
---|
423 | # (read-write access for group "dasscm", |
---|
424 | # if this group exists) |
---|
425 | # |
---|
426 | (my $gname, my $gpw, $DASSCM_GID, my $members) = getgrnam( "dasscm" ); |
---|
427 | if( $DASSCM_GID ) { |
---|
428 | umask 0007 |
---|
429 | } |
---|
430 | } |
---|
431 | |
---|
432 | # |
---|
433 | # has been intendend, |
---|
434 | # to check addtitional parameters. |
---|
435 | # Currently not used. |
---|
436 | # |
---|
437 | sub check_parameter(@) |
---|
438 | { |
---|
439 | } |
---|
440 | |
---|
441 | sub get_command_uniform_name( $ ) |
---|
442 | { |
---|
443 | my $command_abbrivation = $_[0]; |
---|
444 | if ( defined( $COMMANDS{$command_abbrivation} ) ) { |
---|
445 | return $COMMANDS{$command_abbrivation}; |
---|
446 | } |
---|
447 | return; |
---|
448 | } |
---|
449 | |
---|
450 | sub get_command_desc( $ ) |
---|
451 | { |
---|
452 | my $command = get_command_uniform_name( $_[0] ); |
---|
453 | my @desc = (); |
---|
454 | if ( $command && defined( $COMMAND_DEFINITIONS{$command}{'desc'} ) ) { |
---|
455 | @desc = @{ $COMMAND_DEFINITIONS{$command}{'desc'} }; |
---|
456 | } |
---|
457 | return @desc; |
---|
458 | } |
---|
459 | |
---|
460 | sub get_command_function( $ ) |
---|
461 | { |
---|
462 | my $command = get_command_uniform_name( $_[0] ); |
---|
463 | my $func; |
---|
464 | if ( $command && defined( $COMMAND_DEFINITIONS{$command}{'function'} ) ) { |
---|
465 | $func = $COMMAND_DEFINITIONS{$command}{'function'}; |
---|
466 | } |
---|
467 | return $func; |
---|
468 | } |
---|
469 | |
---|
470 | sub get_command_possible_params( $ ) |
---|
471 | { |
---|
472 | my $command = get_command_uniform_name( $_[0] ); |
---|
473 | my @params = (); |
---|
474 | if ( $command && defined( $COMMAND_DEFINITIONS{$command}{'params'} ) ) { |
---|
475 | @params = @{ $COMMAND_DEFINITIONS{$command}{'params'} }; |
---|
476 | } |
---|
477 | return @params; |
---|
478 | } |
---|
479 | |
---|
480 | sub get_command_possible_options( $ ) |
---|
481 | { |
---|
482 | my $command = get_command_uniform_name( $_[0] ); |
---|
483 | my @params = (); |
---|
484 | if ( $command && defined( $COMMAND_DEFINITIONS{$command}{'options'} ) ) { |
---|
485 | @params = @{ $COMMAND_DEFINITIONS{$command}{'options'} }; |
---|
486 | } |
---|
487 | return @params; |
---|
488 | } |
---|
489 | |
---|
490 | sub get_command_requirements( $ ) |
---|
491 | { |
---|
492 | my $command = get_command_uniform_name( $_[0] ); |
---|
493 | my @requirements = (); |
---|
494 | if ( $command && defined( $COMMAND_DEFINITIONS{$command}{'require'} ) ) { |
---|
495 | @requirements = @{ $COMMAND_DEFINITIONS{$command}{'require'} }; |
---|
496 | } |
---|
497 | return @requirements; |
---|
498 | } |
---|
499 | |
---|
500 | sub get_command_requires_write( $ ) |
---|
501 | { |
---|
502 | return grep( /^WRITE$/, get_command_requirements( $_[0] ) ); |
---|
503 | } |
---|
504 | |
---|
505 | # |
---|
506 | # normalize path namens: |
---|
507 | # - directories should end with "/" |
---|
508 | # - use only single "/" |
---|
509 | # |
---|
510 | sub normalize_path($) |
---|
511 | { |
---|
512 | my $path = shift || ""; |
---|
513 | |
---|
514 | if ( $path =~ m|^/| ) { |
---|
515 | |
---|
516 | # full path |
---|
517 | if ( -d $path ) { |
---|
518 | |
---|
519 | # ensure, a directory ends with '/' |
---|
520 | $path .= '/'; |
---|
521 | } |
---|
522 | } elsif ( -d cwd() . '/' . $path ) { |
---|
523 | |
---|
524 | # ensure, a directory ends with '/' |
---|
525 | $path .= '/'; |
---|
526 | } |
---|
527 | |
---|
528 | # remove double (triple) slashes (/) |
---|
529 | $path =~ s|/[/]*|/|g; |
---|
530 | |
---|
531 | # remove self reference path |
---|
532 | $path =~ s|/./|/|g; |
---|
533 | |
---|
534 | return $path; |
---|
535 | } |
---|
536 | |
---|
537 | # |
---|
538 | # generate from (relative) filename |
---|
539 | # all required file and directory names: |
---|
540 | # $basename, $dirname_prod, $dirname_repo, |
---|
541 | # $filename_prod, $filename_repo |
---|
542 | # |
---|
543 | sub get_filenames(@) |
---|
544 | { |
---|
545 | my $filename_prod = $_[0] || "."; |
---|
546 | |
---|
547 | # make filename absolut |
---|
548 | if ( !( $filename_prod =~ m/^\// ) ) { |
---|
549 | $filename_prod = cwd() . '/' . $filename_prod; |
---|
550 | } |
---|
551 | |
---|
552 | # file must be readable. |
---|
553 | # The only exceptions are, |
---|
554 | # - if the file parameter is to be completed or |
---|
555 | # - if a file should be reverted |
---|
556 | if ( $command ne "revert" && $command !~ m/^complete/ ) { |
---|
557 | if ( not -r $filename_prod ) { |
---|
558 | fatalerror( $filename_prod . " is not accessable" ); |
---|
559 | } |
---|
560 | } |
---|
561 | |
---|
562 | # dirname buggy: eg. "/etc/" is reduced to "/", |
---|
563 | # "/etc" is used as filename |
---|
564 | # herefore make sure, that if filename is a directory, |
---|
565 | # it will end by "/" |
---|
566 | $filename_prod = normalize_path($filename_prod); |
---|
567 | |
---|
568 | ( my $basename, my $dirname_prod ) = fileparse($filename_prod); |
---|
569 | |
---|
570 | # normalize path. |
---|
571 | # not done for reverting, because in this case, the directory may not exist |
---|
572 | # and the correct path should already be stored in the repository |
---|
573 | if ( $command ne "revert" ) { |
---|
574 | |
---|
575 | # uses chdir to determine real directory in a unique way |
---|
576 | chdir $dirname_prod |
---|
577 | or fatalerror( "failed to access directory $dirname_prod: " . $! ); |
---|
578 | $dirname_prod = normalize_path( cwd() ); |
---|
579 | chdir $StartDirectory; |
---|
580 | } |
---|
581 | |
---|
582 | my $dirname_repo = normalize_path( $DASSCM_REPO . "/" . $dirname_prod ); |
---|
583 | my $filename_repo = normalize_path("$dirname_repo/$basename"); |
---|
584 | |
---|
585 | if ($verbose) { |
---|
586 | print "filename_repo: " . $filename_repo . "\n"; |
---|
587 | print "dirname_repo: " . $dirname_repo . "\n"; |
---|
588 | print "filename_prod: " . $filename_prod . "\n"; |
---|
589 | print "dirname_prod: " . $dirname_prod . "\n"; |
---|
590 | print "basename: " . $basename . "\n"; |
---|
591 | } |
---|
592 | |
---|
593 | return ( |
---|
594 | $basename, $dirname_prod, $dirname_repo, |
---|
595 | $filename_prod, $filename_repo |
---|
596 | ); |
---|
597 | } |
---|
598 | |
---|
599 | sub copy_file_to_repository( $ ) |
---|
600 | { |
---|
601 | my $filename = shift; |
---|
602 | |
---|
603 | ( |
---|
604 | my $basename, |
---|
605 | my $dirname_prod, |
---|
606 | my $dirname_repo, |
---|
607 | my $filename_prod, |
---|
608 | my $filename_repo |
---|
609 | ) = get_filenames($filename); |
---|
610 | |
---|
611 | #copy( $filename_prod, $filename_repo ) |
---|
612 | ( my $rc, my @result ) = |
---|
613 | run_command("cp -a \"$filename_prod\" \"$filename_repo\""); |
---|
614 | if ( $rc != 0 ) { |
---|
615 | error( "failed to copy $filename_prod to repository: ", @result ); |
---|
616 | } |
---|
617 | |
---|
618 | # return success |
---|
619 | return $rc == 0; |
---|
620 | } |
---|
621 | |
---|
622 | sub copy_file_from_repository_to_system( $ ) |
---|
623 | { |
---|
624 | my $filename = shift; |
---|
625 | |
---|
626 | ( |
---|
627 | my $basename, |
---|
628 | my $dirname_prod, |
---|
629 | my $dirname_repo, |
---|
630 | my $filename_prod, |
---|
631 | my $filename_repo |
---|
632 | ) = get_filenames($filename); |
---|
633 | |
---|
634 | ( my $rc, my @result ) = |
---|
635 | run_command("cp -a \"$filename_repo\" \"$filename_prod\""); |
---|
636 | if ( $rc != 0 ) { |
---|
637 | error( "failed to copy $filename_repo to $filename_prod: ", @result ); |
---|
638 | } |
---|
639 | |
---|
640 | # return success |
---|
641 | return $rc == 0; |
---|
642 | } |
---|
643 | |
---|
644 | # |
---|
645 | # creates a file with permissions |
---|
646 | # |
---|
647 | sub generatePermissionList |
---|
648 | { |
---|
649 | |
---|
650 | # generieren der Zeilen für Permission-Savefile |
---|
651 | my @files = @_; |
---|
652 | my @permlist = (); |
---|
653 | foreach my $file (@files) { |
---|
654 | $file = "/" . $file; |
---|
655 | if ( -e $file ) { |
---|
656 | my $info = stat($file) || die "failed to stat $file: aborting"; |
---|
657 | my $mode = get_type( $info->mode ) & 07777; |
---|
658 | my $modestring = sprintf( "%04o", $mode ); |
---|
659 | my $uidnumber = $info->uid; |
---|
660 | my $uid = getpwuid($uidnumber) || $uidnumber; |
---|
661 | my $gidnumber = $info->gid; |
---|
662 | my $gid = getgrgid($gidnumber) || $gidnumber; |
---|
663 | push( |
---|
664 | @permlist, |
---|
665 | sprintf( "%-55s %-17s %4d", |
---|
666 | $file, "${uid}:${gid}", $modestring ) |
---|
667 | ); |
---|
668 | } |
---|
669 | } |
---|
670 | return @permlist; |
---|
671 | } |
---|
672 | |
---|
673 | sub get_type |
---|
674 | { |
---|
675 | |
---|
676 | # Funktion übernommen aus /usr/bin/chkstat |
---|
677 | my $S_IFLNK = 0120000; # symbolic link |
---|
678 | my $S_IFREG = 0100000; # regular file |
---|
679 | my $S_IFDIR = 0040000; # directory |
---|
680 | my $S_IFCHAR = 0020000; # character device |
---|
681 | my $S_IFBLK = 0060000; # block device |
---|
682 | my $S_IFFIFO = 0010000; # fifo |
---|
683 | my $S_IFSOCK = 0140000; # socket |
---|
684 | my $S_IFMT = 0170000; # type of file |
---|
685 | |
---|
686 | my $S_m; |
---|
687 | if ( ( $_[0] & $S_IFMT ) == $S_IFLNK ) { $S_m = $_[0] - $S_IFLNK; } |
---|
688 | elsif ( ( $_[0] & $S_IFMT ) == $S_IFREG ) { $S_m = $_[0] - $S_IFREG; } |
---|
689 | elsif ( ( $_[0] & $S_IFMT ) == $S_IFDIR ) { $S_m = $_[0] - $S_IFDIR; } |
---|
690 | elsif ( ( $_[0] & $S_IFMT ) == $S_IFCHAR ) { $S_m = $_[0] - $S_IFCHAR; } |
---|
691 | elsif ( ( $_[0] & $S_IFMT ) == $S_IFBLK ) { $S_m = $_[0] - $S_IFBLK; } |
---|
692 | elsif ( ( $_[0] & $S_IFMT ) == $S_IFFIFO ) { $S_m = $_[0] - $S_IFFIFO; } |
---|
693 | elsif ( ( $_[0] & $S_IFMT ) == $S_IFSOCK ) { $S_m = $_[0] - $S_IFSOCK; } |
---|
694 | $S_m; |
---|
695 | } |
---|
696 | |
---|
697 | sub run_command |
---|
698 | { |
---|
699 | my $command = shift; |
---|
700 | |
---|
701 | if ($verbose) { |
---|
702 | print "executing command: " . $command . "\n"; |
---|
703 | } |
---|
704 | |
---|
705 | my @result; |
---|
706 | if( open( RESULT, $command . ' 2>&1 |' ) ) { |
---|
707 | @result = <RESULT>; |
---|
708 | close(RESULT); |
---|
709 | } |
---|
710 | my $retcode = $? >> 8; |
---|
711 | |
---|
712 | if ($verbose) { |
---|
713 | print @result; |
---|
714 | if( $retcode ) { print "return code: " . $retcode . "\n"; } |
---|
715 | } |
---|
716 | |
---|
717 | return ( $retcode, @result ); |
---|
718 | } |
---|
719 | |
---|
720 | sub run_interactive |
---|
721 | { |
---|
722 | |
---|
723 | if ($verbose) { |
---|
724 | print "run_interactive:" . join( " ", @_ ) . "\n"; |
---|
725 | } |
---|
726 | |
---|
727 | system(@_); |
---|
728 | if ( $? == -1 ) { |
---|
729 | printf "failed to execute: $!\n"; |
---|
730 | } elsif ( $? & 127 ) { |
---|
731 | printf "child died with signal %d, %s coredump\n", ( $? & 127 ), |
---|
732 | ( $? & 128 ) ? 'with' : 'without'; |
---|
733 | } elsif ( $? >> 8 != 0 ) { |
---|
734 | printf "child exited with value %d\n", $? >> 8; |
---|
735 | } |
---|
736 | return ( $? >> 8 ); |
---|
737 | } |
---|
738 | |
---|
739 | # |
---|
740 | # en- or disable echo mode. |
---|
741 | # used for reading passwords from STDIN |
---|
742 | # |
---|
743 | sub setEchoMode( $ ) |
---|
744 | { |
---|
745 | my $mode = shift; |
---|
746 | if ($mode) { |
---|
747 | run_command("stty echo"); |
---|
748 | } else { |
---|
749 | run_command("stty -echo"); |
---|
750 | } |
---|
751 | } |
---|
752 | |
---|
753 | sub write_array_to_file( $@ ) |
---|
754 | { |
---|
755 | my $filename = shift; |
---|
756 | my @array = @_; |
---|
757 | |
---|
758 | if ( -e $filename && !-w $filename ) { |
---|
759 | warning( "failed to write to $filename:", "permission denied" ); |
---|
760 | return; |
---|
761 | } |
---|
762 | |
---|
763 | if ( !-w dirname($filename) ) { |
---|
764 | warning( "failed to write to $filename:", "directory does not exist" ); |
---|
765 | return; |
---|
766 | } |
---|
767 | |
---|
768 | # directory exists => write |
---|
769 | if ( !open( OUTFILE, ">$filename" ) ) { |
---|
770 | warning("failed to open $filename: $!"); |
---|
771 | return; |
---|
772 | } |
---|
773 | |
---|
774 | foreach my $line (@array) { |
---|
775 | print OUTFILE "$line"; |
---|
776 | } |
---|
777 | close(OUTFILE); |
---|
778 | |
---|
779 | # if group dasscm exists, |
---|
780 | # create plugin results with group membership dasscm |
---|
781 | if( $DASSCM_GID ) { |
---|
782 | chown( -1, $DASSCM_GID, $filename ); |
---|
783 | } |
---|
784 | |
---|
785 | return 1; |
---|
786 | } |
---|
787 | |
---|
788 | sub perform_plugins() |
---|
789 | { |
---|
790 | check_env(); |
---|
791 | |
---|
792 | my @plugin_results = (); |
---|
793 | |
---|
794 | # get all defined plugins. |
---|
795 | # Plugin definitions starting with DASSCM_PLUGIN_ |
---|
796 | my @plugins = grep( /^DASSCM_PLUGIN_CMD_/, keys( %{$config} ) ); |
---|
797 | |
---|
798 | for my $plugin (@plugins) { |
---|
799 | my $plugin_name = substr( $plugin, length("DASSCM_PLUGIN_CMD_") ); |
---|
800 | my $plugin_test = $config->{ 'DASSCM_PLUGIN_TEST_' . $plugin_name }; |
---|
801 | if ($verbose) { print "Plugin $plugin_name: "; } |
---|
802 | # all plugins are executed with LANG settings C |
---|
803 | # bash -c is used, to supress all output |
---|
804 | # (otherwise there are problem with && commands) |
---|
805 | ( my $rc_test, my @result_test ) = run_command( 'LANG=C bash -c "' . $plugin_test . '"' ); |
---|
806 | if ( $rc_test != 0 ) { |
---|
807 | if ($verbose) { print "skipped\n"; } |
---|
808 | } else { |
---|
809 | if ($verbose) { print "$config->{$plugin}\n"; } |
---|
810 | ( my $rc, my @result ) = run_command( 'LANG=C bash -c "' . $config->{$plugin} . '"' ); |
---|
811 | if ( $rc != 0 ) { |
---|
812 | warning("failed to run plugin $plugin"); |
---|
813 | } else { |
---|
814 | my $plugin_result_file = |
---|
815 | $DASSCM_PLUGIN_RESULTS_PATH . "/" . $plugin_name; |
---|
816 | write_array_to_file( $plugin_result_file, @result ); |
---|
817 | push @plugin_results, $plugin_result_file; |
---|
818 | } |
---|
819 | } |
---|
820 | } |
---|
821 | return @plugin_results; |
---|
822 | } |
---|
823 | |
---|
824 | sub svn_check_credentials( $$;$$ ) |
---|
825 | { |
---|
826 | my $username = shift; |
---|
827 | my $password = shift; |
---|
828 | |
---|
829 | # check silently are allow user interaction? |
---|
830 | my $interactive = shift || 0; |
---|
831 | |
---|
832 | # default: exit program, if repository is not accessable |
---|
833 | # (do not exit for 'init') |
---|
834 | my $fatalerror = shift || 1; |
---|
835 | |
---|
836 | print "checking credentials "; |
---|
837 | |
---|
838 | if ( !$username ) { |
---|
839 | fatalerror("no username given"); |
---|
840 | } |
---|
841 | |
---|
842 | if ( !$password ) { |
---|
843 | fatalerror("no password given"); |
---|
844 | } |
---|
845 | |
---|
846 | print "for " . $username . "@" . $DASSCM_SVN_REPOSITORY . ": "; |
---|
847 | |
---|
848 | # Options for "svn info" are not supported by subversion 1.0.0 (SLES9), |
---|
849 | # therefore switching to "svn status" |
---|
850 | # ( my $rc_update, my @result ) = |
---|
851 | # run_command( |
---|
852 | # "$SVN info --non-interactive --no-auth-cache --username $username --password $password $DASSCM_SVN_REPOSITORY" |
---|
853 | # ); |
---|
854 | #print @result; |
---|
855 | |
---|
856 | my $rc_update; |
---|
857 | if ($interactive) { |
---|
858 | $rc_update = run_interactive( |
---|
859 | "$SVN ls --no-auth-cache --username '$username' --password '$password' $DASSCM_SVN_REPOSITORY" |
---|
860 | ); |
---|
861 | } else { |
---|
862 | ( $rc_update, my @result ) = run_command( |
---|
863 | "$SVN ls --non-interactive --no-auth-cache --username '$username' --password '$password' $DASSCM_SVN_REPOSITORY" |
---|
864 | ); |
---|
865 | |
---|
866 | if ( $rc_update != 0 ) { |
---|
867 | print "\n", @result; |
---|
868 | if ($fatalerror) { |
---|
869 | fatalerror(); |
---|
870 | } |
---|
871 | return; |
---|
872 | } |
---|
873 | } |
---|
874 | |
---|
875 | # return success |
---|
876 | return $rc_update == 0; |
---|
877 | } |
---|
878 | |
---|
879 | sub svn_update( ;$ ) |
---|
880 | { |
---|
881 | my $update_path = shift || ""; |
---|
882 | |
---|
883 | # return value |
---|
884 | my $update_ok = 1; |
---|
885 | |
---|
886 | # use this flag to do only one update per run |
---|
887 | if ( !$svnRepositoryIsUptodate ) { |
---|
888 | ( my $rc_update, my @result ) = run_command( |
---|
889 | "$SVN update --non-interactive $svnCheckoutCredentials '$DASSCM_REPO/$update_path'" |
---|
890 | ); |
---|
891 | print @result; |
---|
892 | if ( $rc_update != 0 ) { |
---|
893 | error("failed to update local repository ($update_path)"); |
---|
894 | $update_ok = 0; |
---|
895 | } elsif ( not $update_path ) { |
---|
896 | |
---|
897 | # set this flag if a full update is done |
---|
898 | $svnRepositoryIsUptodate = 1; |
---|
899 | } |
---|
900 | } |
---|
901 | return $update_ok; |
---|
902 | } |
---|
903 | |
---|
904 | sub svn_ls( ;@ ) |
---|
905 | { |
---|
906 | ( |
---|
907 | my $basename, |
---|
908 | my $dirname_prod, |
---|
909 | my $dirname_repo, |
---|
910 | my $filename_prod, |
---|
911 | my $filename_repo |
---|
912 | ) = get_filenames( $_[0] ); |
---|
913 | |
---|
914 | # svn ls -R is better, but much, much slower |
---|
915 | # ( my $rc, my @result ) = run_command("$SVN ls --recursive $svnCheckoutCredentials $path"); |
---|
916 | |
---|
917 | my @files = (); |
---|
918 | my @links = (); |
---|
919 | my @dirs = (); |
---|
920 | my @others = (); |
---|
921 | |
---|
922 | find( |
---|
923 | { |
---|
924 | wanted => sub { |
---|
925 | my $name = normalize_path($File::Find::name); |
---|
926 | $name =~ s|^$dirname_repo||; |
---|
927 | |
---|
928 | #print "($name)\n";# . $File::Find::dir . "\n"; |
---|
929 | if ( not $name ) { |
---|
930 | |
---|
931 | # name string is empty (top directory). |
---|
932 | # do nothing |
---|
933 | } elsif ( $name =~ m/\.svn/ ) { |
---|
934 | |
---|
935 | # skip svn meta data |
---|
936 | } elsif ( -l $_ ) { |
---|
937 | |
---|
938 | # soft link |
---|
939 | # important: check for links first |
---|
940 | # to exclude them from further checks |
---|
941 | push( @links, $name ); |
---|
942 | } elsif ( -d $_ ) { |
---|
943 | |
---|
944 | # directories |
---|
945 | push( @dirs, $name ); |
---|
946 | } elsif ( -f $_ ) { |
---|
947 | |
---|
948 | # regular file |
---|
949 | push( @files, $name ); |
---|
950 | } else { |
---|
951 | push( @others, $name ); |
---|
952 | } |
---|
953 | } |
---|
954 | }, |
---|
955 | ($filename_repo) |
---|
956 | ); |
---|
957 | |
---|
958 | return ( sort( @dirs, @files ) ); |
---|
959 | } |
---|
960 | |
---|
961 | sub svn_revert( ;$ ) |
---|
962 | { |
---|
963 | my $path = shift || $DASSCM_REPO; |
---|
964 | |
---|
965 | ( my $rc_update, my @result ) = run_command("$SVN revert -R '$path'"); |
---|
966 | |
---|
967 | if ( $rc_update != 0 ) { |
---|
968 | print "\n", @result; |
---|
969 | error("failed to revert subversion repository changes"); |
---|
970 | } |
---|
971 | } |
---|
972 | |
---|
973 | sub svn_remove_unknown_files( ;$ ) |
---|
974 | { |
---|
975 | my $path = shift || $DASSCM_REPO; |
---|
976 | |
---|
977 | ( my $rc_update, my @result ) = run_command("$SVN status '$path'"); |
---|
978 | |
---|
979 | if ( $rc_update != 0 ) { |
---|
980 | print "\n", @result; |
---|
981 | error("failed to receive subversion repository information"); |
---|
982 | } else { |
---|
983 | foreach (@result) { |
---|
984 | if (s/^\? +//) { |
---|
985 | chomp; |
---|
986 | |
---|
987 | # if file is unknown to subversion (line starts with "?") |
---|
988 | # remove it |
---|
989 | print "removing $_\n"; |
---|
990 | |
---|
991 | # unlink doesn't work recursive, there "rm -rf" is used |
---|
992 | #unlink($_); |
---|
993 | system("rm -rf $_"); |
---|
994 | } |
---|
995 | } |
---|
996 | } |
---|
997 | } |
---|
998 | |
---|
999 | sub getModifiedFiles( ;$ ) |
---|
1000 | { |
---|
1001 | ( |
---|
1002 | my $basename, |
---|
1003 | my $dirname_prod, |
---|
1004 | my $dirname_repo, |
---|
1005 | my $filename_prod, |
---|
1006 | my $filename_repo |
---|
1007 | ) = get_filenames( $_[0] ); |
---|
1008 | |
---|
1009 | my @files = svn_ls($filename_prod); |
---|
1010 | |
---|
1011 | # stores result from status (cvscheck) |
---|
1012 | my %removedfiles = (); |
---|
1013 | my %changedfiles = (); |
---|
1014 | my %unknownfiles = (); |
---|
1015 | |
---|
1016 | # create list of modified files |
---|
1017 | if (@files) { |
---|
1018 | |
---|
1019 | foreach my $file (@files) { |
---|
1020 | |
---|
1021 | my $realfile = $dirname_prod . $file; |
---|
1022 | my $cvsworkfile = $dirname_repo . $file; |
---|
1023 | |
---|
1024 | if ( -d $realfile ) { |
---|
1025 | |
---|
1026 | # directory |
---|
1027 | if ( !-d "$cvsworkfile" ) { |
---|
1028 | |
---|
1029 | # real is directory, repository is not. This is a problem |
---|
1030 | $changedfiles{"$realfile"} = $cvsworkfile; |
---|
1031 | } |
---|
1032 | } elsif ( !-e $realfile ) { |
---|
1033 | $removedfiles{"$realfile"} = $cvsworkfile; |
---|
1034 | } elsif ( !-r $realfile ) { |
---|
1035 | |
---|
1036 | # don't have permission to read the file, |
---|
1037 | # can't check it |
---|
1038 | $unknownfiles{"$realfile"} = $cvsworkfile; |
---|
1039 | } else { |
---|
1040 | ( -r "$cvsworkfile" ) |
---|
1041 | || fatalerror("failed to read $cvsworkfile"); |
---|
1042 | if ( compare( $cvsworkfile, $realfile ) != 0 ) { |
---|
1043 | $changedfiles{"$realfile"} = $cvsworkfile; |
---|
1044 | } |
---|
1045 | } |
---|
1046 | } |
---|
1047 | } |
---|
1048 | |
---|
1049 | return ( \%changedfiles, \%removedfiles, \%unknownfiles ); |
---|
1050 | } |
---|
1051 | |
---|
1052 | # |
---|
1053 | # from an array of files/dirs, |
---|
1054 | # generates list of files |
---|
1055 | # sorted by type |
---|
1056 | # |
---|
1057 | sub get_files( @ ) |
---|
1058 | { |
---|
1059 | my @files = (); |
---|
1060 | my @links = (); |
---|
1061 | my @dirs = (); |
---|
1062 | my @others = (); |
---|
1063 | |
---|
1064 | if (@_) { |
---|
1065 | find( |
---|
1066 | { |
---|
1067 | wanted => sub { |
---|
1068 | my $fullname = cwd() . "/" . $_; |
---|
1069 | if ( -l $_ ) { |
---|
1070 | |
---|
1071 | # soft link |
---|
1072 | # important: check for links first |
---|
1073 | # to exclude them from further checks |
---|
1074 | push( @links, $fullname ); |
---|
1075 | } elsif ( -d $_ ) { |
---|
1076 | |
---|
1077 | # directories |
---|
1078 | push( @dirs, $fullname ); |
---|
1079 | } elsif ( -f $_ ) { |
---|
1080 | |
---|
1081 | # regular file |
---|
1082 | push( @files, $fullname ); |
---|
1083 | } else { |
---|
1084 | push( @others, $fullname ); |
---|
1085 | } |
---|
1086 | } |
---|
1087 | }, |
---|
1088 | @_ |
---|
1089 | ); |
---|
1090 | } |
---|
1091 | |
---|
1092 | # don't rely on others. |
---|
1093 | # If more specific file types are needed, |
---|
1094 | # they will be added |
---|
1095 | return { |
---|
1096 | files => \@files, |
---|
1097 | links => \@links, |
---|
1098 | dirs => \@dirs, |
---|
1099 | others => \@others |
---|
1100 | }; |
---|
1101 | } |
---|
1102 | |
---|
1103 | sub print_files_hash( $ ) |
---|
1104 | { |
---|
1105 | my $href_files = shift; |
---|
1106 | |
---|
1107 | my @files = @{ $href_files->{files} }; |
---|
1108 | my @links = @{ $href_files->{links} }; |
---|
1109 | |
---|
1110 | if (@files) { |
---|
1111 | my $number = $#files + 1; |
---|
1112 | print "files to check-in ($number): \n"; |
---|
1113 | print join( "\n", @files ); |
---|
1114 | print "\n"; |
---|
1115 | } |
---|
1116 | |
---|
1117 | # TODO: check in links and also link target? At least warn about link target |
---|
1118 | if (@links) { |
---|
1119 | my $number = $#links + 1; |
---|
1120 | print "\n"; |
---|
1121 | print "ignoring links ($number):\n"; |
---|
1122 | print join( "\n", @links ); |
---|
1123 | print "\n"; |
---|
1124 | } |
---|
1125 | |
---|
1126 | } |
---|
1127 | |
---|
1128 | # |
---|
1129 | # use globbing to get lsit of files |
---|
1130 | # that matches the given prefix |
---|
1131 | # used for bash completion |
---|
1132 | # |
---|
1133 | sub get_complete_path_globbing( $ ) |
---|
1134 | { |
---|
1135 | my $path = shift; |
---|
1136 | |
---|
1137 | # add globbing |
---|
1138 | $path .= "*"; |
---|
1139 | |
---|
1140 | # get files |
---|
1141 | my @files = glob($path); |
---|
1142 | |
---|
1143 | if ( $#files == 0 ) { |
---|
1144 | |
---|
1145 | # if only one result is available |
---|
1146 | # and this result is a directory, |
---|
1147 | # add another result entry |
---|
1148 | # (directory with and withour trainling /), |
---|
1149 | # otherwise complete will stop here and continue with the next parameter |
---|
1150 | my $path = normalize_path( $files[0] ); |
---|
1151 | if ( -d $path ) { |
---|
1152 | @files = ( substr( $path, 0, -1 ), $path ); |
---|
1153 | } |
---|
1154 | } else { |
---|
1155 | |
---|
1156 | # add "/" to all directories |
---|
1157 | @files = map( { normalize_path($_) } @files ); |
---|
1158 | } |
---|
1159 | |
---|
1160 | return @files; |
---|
1161 | } |
---|
1162 | |
---|
1163 | ##################################################################### |
---|
1164 | # |
---|
1165 | # functions |
---|
1166 | sub help(;@) |
---|
1167 | { |
---|
1168 | if ( not @_ ) { |
---|
1169 | usage(); |
---|
1170 | } else { |
---|
1171 | print "help for ", join( " ", @_ ), ": ...\n"; |
---|
1172 | usage(); |
---|
1173 | } |
---|
1174 | |
---|
1175 | return $RETURN_OK; |
---|
1176 | } |
---|
1177 | |
---|
1178 | sub login(@) |
---|
1179 | { |
---|
1180 | check_parameter( @_, 1 ); |
---|
1181 | check_env(); |
---|
1182 | |
---|
1183 | my $input_username = $_[0]; |
---|
1184 | |
---|
1185 | if ( not $input_username ) { |
---|
1186 | my $output_username = ""; |
---|
1187 | if ($DASSCM_USERNAME) { |
---|
1188 | $output_username = " ($DASSCM_USERNAME)"; |
---|
1189 | } |
---|
1190 | |
---|
1191 | print "Enter DASSCM user name", $output_username, ": "; |
---|
1192 | $input_username = <STDIN>; |
---|
1193 | chomp($input_username); |
---|
1194 | |
---|
1195 | $input_username = $input_username || $DASSCM_USERNAME; |
---|
1196 | } |
---|
1197 | |
---|
1198 | # hidden password input |
---|
1199 | print "Enter password for $input_username: "; |
---|
1200 | setEchoMode(0); |
---|
1201 | my $input_password = <STDIN>; |
---|
1202 | setEchoMode(1); |
---|
1203 | chomp($input_password); |
---|
1204 | print "\n"; |
---|
1205 | |
---|
1206 | # checking checkout username/password |
---|
1207 | svn_check_credentials( $DASSCM_CHECKOUT_USERNAME, |
---|
1208 | $DASSCM_CHECKOUT_PASSWORD ); |
---|
1209 | print "checkout access okay\n"; |
---|
1210 | |
---|
1211 | svn_check_credentials( $input_username, $input_password ); |
---|
1212 | |
---|
1213 | # |
---|
1214 | # set environment variables |
---|
1215 | # |
---|
1216 | $ENV{'DASSCM_USERNAME'} = "$input_username"; |
---|
1217 | $ENV{'DASSCM_PASSWORD'} = "$input_password"; |
---|
1218 | |
---|
1219 | print "subversion access okay\n\n", "DASSCM_USERNAME: $input_username\n", |
---|
1220 | "DASSCM_PASSWORD: (hidden)\n", "DASSCM_PROD: $DASSCM_PROD\n", |
---|
1221 | "DASSCM_REPO: $DASSCM_REPO\n", |
---|
1222 | "Server Repository: $DASSCM_SVN_REPOSITORY\n", "\n"; |
---|
1223 | |
---|
1224 | status(); |
---|
1225 | |
---|
1226 | print "\n[dasscm shell]\n\n"; |
---|
1227 | my $shell = $SHELL || "bash"; |
---|
1228 | exec($shell) or die "failed to start new shell"; |
---|
1229 | } |
---|
1230 | |
---|
1231 | # |
---|
1232 | # initialize local checkout directory (initial checkout) |
---|
1233 | # |
---|
1234 | sub init(@) |
---|
1235 | { |
---|
1236 | check_parameter( @_, 1 ); |
---|
1237 | check_env(); |
---|
1238 | |
---|
1239 | # don't do repository creation (svn mkdir) here, |
---|
1240 | # because then their must be a lot of prior checks |
---|
1241 | |
---|
1242 | # update complete repository |
---|
1243 | my $retcode = run_interactive( |
---|
1244 | "cd $DASSCM_LOCAL_REPOSITORY_BASE; $SVN checkout $svnCheckoutCredentials $svnOptions $DASSCM_SVN_REPOSITORY" |
---|
1245 | ); |
---|
1246 | |
---|
1247 | return $retcode; |
---|
1248 | } |
---|
1249 | |
---|
1250 | sub ls(@) |
---|
1251 | { |
---|
1252 | my $return_code = $RETURN_OK; |
---|
1253 | check_parameter( @_, 1 ); |
---|
1254 | check_env(); |
---|
1255 | |
---|
1256 | my @files = svn_ls(@_); |
---|
1257 | |
---|
1258 | if (@files) { |
---|
1259 | print join( "\n", @files ); |
---|
1260 | print "\n"; |
---|
1261 | } |
---|
1262 | return $return_code; |
---|
1263 | } |
---|
1264 | |
---|
1265 | sub update(@) |
---|
1266 | { |
---|
1267 | my $return_code = $RETURN_OK; |
---|
1268 | check_parameter( @_, 1 ); |
---|
1269 | check_env(); |
---|
1270 | |
---|
1271 | # |
---|
1272 | # update local repository |
---|
1273 | # |
---|
1274 | if( ! svn_update() ) { |
---|
1275 | $return_code = $RETURN_NOK; |
---|
1276 | } |
---|
1277 | return $return_code; |
---|
1278 | } |
---|
1279 | |
---|
1280 | # |
---|
1281 | # helper function for "add" command |
---|
1282 | # |
---|
1283 | sub add_helper(@) |
---|
1284 | { |
---|
1285 | ( |
---|
1286 | my $basename, |
---|
1287 | my $dirname_prod, |
---|
1288 | my $dirname_repo, |
---|
1289 | my $filename_prod, |
---|
1290 | my $filename_repo |
---|
1291 | ) = get_filenames( $_[0] ); |
---|
1292 | |
---|
1293 | mkpath($dirname_repo); |
---|
1294 | copy_file_to_repository($filename_prod); |
---|
1295 | |
---|
1296 | # already checked in? |
---|
1297 | chdir $DASSCM_REPO; |
---|
1298 | |
---|
1299 | # also add the path to filename. |
---|
1300 | for my $dir ( split( '/', $dirname_prod ) ) { |
---|
1301 | if ($dir) { |
---|
1302 | my ( $rc, @out ) = run_command("$SVN add --non-recursive '$dir'"); |
---|
1303 | if ( $rc > 0 ) { |
---|
1304 | print join( "\n", @out ); |
---|
1305 | } |
---|
1306 | chdir $dir; |
---|
1307 | } |
---|
1308 | } |
---|
1309 | my ( $rc, @out ) = run_command("$SVN add '$basename'"); |
---|
1310 | if ( $rc > 0 ) { |
---|
1311 | print join( "\n", @out ); |
---|
1312 | } |
---|
1313 | chdir $StartDirectory; |
---|
1314 | |
---|
1315 | } |
---|
1316 | |
---|
1317 | sub add_helper_multi(@) |
---|
1318 | { |
---|
1319 | |
---|
1320 | # get all regular files and links |
---|
1321 | my $href_files = get_files(@_); |
---|
1322 | |
---|
1323 | #print Dumper( $href_files ); |
---|
1324 | |
---|
1325 | my @files = @{ $href_files->{files} }; |
---|
1326 | my @links = @{ $href_files->{links} }; |
---|
1327 | |
---|
1328 | # copy files one by one to local repository |
---|
1329 | for my $file (@files) { |
---|
1330 | |
---|
1331 | # add file |
---|
1332 | add_helper($file); |
---|
1333 | } |
---|
1334 | |
---|
1335 | return $href_files; |
---|
1336 | } |
---|
1337 | |
---|
1338 | # |
---|
1339 | # adding new files (or directories) |
---|
1340 | # |
---|
1341 | sub add(@) |
---|
1342 | { |
---|
1343 | check_parameter( @_, 1 ); |
---|
1344 | check_env(); |
---|
1345 | |
---|
1346 | # |
---|
1347 | # update local repository |
---|
1348 | # |
---|
1349 | svn_update(); |
---|
1350 | |
---|
1351 | # add files to repository, print information about added files |
---|
1352 | print_files_hash( add_helper_multi(@_) ); |
---|
1353 | |
---|
1354 | # perform plugins and add additional files, like plugin results |
---|
1355 | perform_plugins(); |
---|
1356 | add_helper_multi(@DASSCM_ADDITIONAL_FILES); |
---|
1357 | |
---|
1358 | if ( $options{'message'} ) { |
---|
1359 | $svnOptions .= " --message \"$options{'message'}\" "; |
---|
1360 | } |
---|
1361 | |
---|
1362 | # commit calls $EDITOR. |
---|
1363 | # use "interactive" here, to display output |
---|
1364 | my $retcode = run_interactive( |
---|
1365 | "$SVN commit $svnOptions --username '$DASSCM_USERNAME' $svnPasswordCredentials $DASSCM_REPO" |
---|
1366 | ); |
---|
1367 | |
---|
1368 | # svn commit does not deliever an error return code, if commit is canceld, |
---|
1369 | # so a revert is performed in any case |
---|
1370 | svn_revert(); |
---|
1371 | return $retcode; |
---|
1372 | } |
---|
1373 | |
---|
1374 | # |
---|
1375 | # checks in all modified files |
---|
1376 | # |
---|
1377 | sub commit(@) |
---|
1378 | { |
---|
1379 | check_parameter( @_, 1 ); |
---|
1380 | check_env(); |
---|
1381 | |
---|
1382 | ( |
---|
1383 | my $basename, |
---|
1384 | my $dirname_prod, |
---|
1385 | my $dirname_repo, |
---|
1386 | my $filename_prod, |
---|
1387 | my $filename_repo |
---|
1388 | ) = get_filenames( $_[0] ); |
---|
1389 | |
---|
1390 | # |
---|
1391 | # update local repository |
---|
1392 | # |
---|
1393 | svn_update(); |
---|
1394 | |
---|
1395 | ( my $refChangedFiles, my $refRemovedFiles ) = |
---|
1396 | getModifiedFiles($filename_prod); |
---|
1397 | my %changedfiles = %{$refChangedFiles}; |
---|
1398 | my %removedfiles = %{$refRemovedFiles}; |
---|
1399 | |
---|
1400 | if (%removedfiles) { |
---|
1401 | my $removedFilesString = |
---|
1402 | '"' . join( '" "', values(%removedfiles) ) . '"'; |
---|
1403 | my ( $rc, @out ) = run_command("$SVN rm $removedFilesString"); |
---|
1404 | if ( $rc > 0 ) { |
---|
1405 | print join( "\n", @out ); |
---|
1406 | } |
---|
1407 | } |
---|
1408 | |
---|
1409 | # copy files one by one to local repository |
---|
1410 | for my $file ( keys(%changedfiles) ) { |
---|
1411 | copy_file_to_repository($file); |
---|
1412 | } |
---|
1413 | |
---|
1414 | perform_plugins(); |
---|
1415 | add_helper_multi(@DASSCM_ADDITIONAL_FILES); |
---|
1416 | |
---|
1417 | if ( $options{'message'} ) { |
---|
1418 | $svnOptions .= " --message \"$options{'message'}\" "; |
---|
1419 | } |
---|
1420 | |
---|
1421 | # commit calls $EDITOR. |
---|
1422 | # use "interactive" here, to display output |
---|
1423 | my $retcode = run_interactive( |
---|
1424 | "$SVN commit $svnOptions --username '$DASSCM_USERNAME' $svnPasswordCredentials $DASSCM_REPO" |
---|
1425 | ); |
---|
1426 | |
---|
1427 | # svn commit does not deliever an error return code, if commit is canceld, |
---|
1428 | # so a revert is performed in any case |
---|
1429 | svn_revert(); |
---|
1430 | return $retcode; |
---|
1431 | } |
---|
1432 | |
---|
1433 | # |
---|
1434 | # revert: copies files back from repository to system |
---|
1435 | # |
---|
1436 | sub revert(@) |
---|
1437 | { |
---|
1438 | check_parameter( @_, 1 ); |
---|
1439 | check_env(); |
---|
1440 | |
---|
1441 | ( |
---|
1442 | my $basename, |
---|
1443 | my $dirname_prod, |
---|
1444 | my $dirname_repo, |
---|
1445 | my $filename_prod, |
---|
1446 | my $filename_repo |
---|
1447 | ) = get_filenames( $_[0] ); |
---|
1448 | |
---|
1449 | # return code for the shell |
---|
1450 | # default: error |
---|
1451 | my $return_code = $RETURN_OK; |
---|
1452 | |
---|
1453 | # cleanup repository |
---|
1454 | cleanup(); |
---|
1455 | |
---|
1456 | #svn_update(); |
---|
1457 | |
---|
1458 | ( my $refChangedFiles, my $refRemovedFiles, my $refUnknownFiles ) = |
---|
1459 | getModifiedFiles($filename_prod); |
---|
1460 | my %changedfiles = %{$refChangedFiles}; |
---|
1461 | my %removedfiles = %{$refRemovedFiles}; |
---|
1462 | my %unknownfiles = %{$refUnknownFiles}; |
---|
1463 | |
---|
1464 | if ( %removedfiles or %changedfiles or %unknownfiles ) { |
---|
1465 | |
---|
1466 | if (%removedfiles) { |
---|
1467 | print "DELETED files and directories. Recreated from repository:\n"; |
---|
1468 | my @removedPaths = |
---|
1469 | ( sort { length $a > length $b } keys %removedfiles ); |
---|
1470 | print join( "\n", @removedPaths ) . "\n\n"; |
---|
1471 | |
---|
1472 | # copy files one by one from local repository to system |
---|
1473 | # and also create directories |
---|
1474 | # paths are sorted, so that directories are created first |
---|
1475 | for my $real_path (@removedPaths) { |
---|
1476 | if ( -d $removedfiles{"$real_path"} ) { |
---|
1477 | mkpath("$real_path"); |
---|
1478 | } else { |
---|
1479 | copy_file_from_repository_to_system($real_path); |
---|
1480 | } |
---|
1481 | } |
---|
1482 | } |
---|
1483 | |
---|
1484 | if (%changedfiles) { |
---|
1485 | print "MODIFIED files. Copied from repository to the system:\n"; |
---|
1486 | print join( "\n", ( keys %changedfiles ) ) . "\n\n"; |
---|
1487 | |
---|
1488 | # copy files one by one from local repository to system |
---|
1489 | for my $real_file ( keys(%changedfiles) ) { |
---|
1490 | copy_file_from_repository_to_system($real_file); |
---|
1491 | } |
---|
1492 | |
---|
1493 | } |
---|
1494 | |
---|
1495 | if (%unknownfiles) { |
---|
1496 | print "UNKNOWN: insufficient permission to check files:\n"; |
---|
1497 | print join( "\n", ( keys %unknownfiles ) ) . "\n\n"; |
---|
1498 | |
---|
1499 | $return_code = $RETURN_NOK; |
---|
1500 | } |
---|
1501 | |
---|
1502 | } else { |
---|
1503 | print "no modified files found in $dirname_repo\n"; |
---|
1504 | } |
---|
1505 | |
---|
1506 | return $return_code; |
---|
1507 | } |
---|
1508 | |
---|
1509 | sub blame(@) |
---|
1510 | { |
---|
1511 | check_parameter( @_, 1 ); |
---|
1512 | check_env(); |
---|
1513 | |
---|
1514 | ( |
---|
1515 | my $basename, |
---|
1516 | my $dirname_prod, |
---|
1517 | my $dirname_repo, |
---|
1518 | my $filename_prod, |
---|
1519 | my $filename_repo |
---|
1520 | ) = get_filenames( $_[0] ); |
---|
1521 | |
---|
1522 | my $retcode = run_interactive("$SVN blame --non-interactive $svnCheckoutCredentials $svnOptions $filename_repo"); |
---|
1523 | return $retcode; |
---|
1524 | } |
---|
1525 | |
---|
1526 | sub diff(@) |
---|
1527 | { |
---|
1528 | check_parameter( @_, 1 ); |
---|
1529 | check_env(); |
---|
1530 | |
---|
1531 | ( |
---|
1532 | my $basename, |
---|
1533 | my $dirname_prod, |
---|
1534 | my $dirname_repo, |
---|
1535 | my $filename_prod, |
---|
1536 | my $filename_repo |
---|
1537 | ) = get_filenames( $_[0] ); |
---|
1538 | |
---|
1539 | #print "$basename,$dirname_prod,$dirname_repo\n"; |
---|
1540 | |
---|
1541 | svn_update(); |
---|
1542 | |
---|
1543 | ( my $rc_diff, my @diff_result ) = |
---|
1544 | run_command( $diff . " $filename_repo $filename_prod" ); |
---|
1545 | |
---|
1546 | print @diff_result; |
---|
1547 | return $rc_diff; |
---|
1548 | } |
---|
1549 | |
---|
1550 | sub status(@) |
---|
1551 | { |
---|
1552 | check_parameter( @_, 1 ); |
---|
1553 | check_env(); |
---|
1554 | |
---|
1555 | ( |
---|
1556 | my $basename, |
---|
1557 | my $dirname_prod, |
---|
1558 | my $dirname_repo, |
---|
1559 | my $filename_prod, |
---|
1560 | my $filename_repo |
---|
1561 | ) = get_filenames( $_[0] || "/" ); |
---|
1562 | |
---|
1563 | # return code for the shell |
---|
1564 | # default: error |
---|
1565 | my $return_code = $RETURN_NOK; |
---|
1566 | |
---|
1567 | # |
---|
1568 | # update local repository |
---|
1569 | # |
---|
1570 | #svn_update( $filename_prod ); |
---|
1571 | |
---|
1572 | # perform plugins (required to see changes in plugin results) |
---|
1573 | perform_plugins(); |
---|
1574 | |
---|
1575 | # get modified files |
---|
1576 | ( my $refChangedFiles, my $refRemovedFiles, my $refUnknownFiles ) = |
---|
1577 | getModifiedFiles($dirname_prod); |
---|
1578 | my %changedfiles = %{$refChangedFiles}; |
---|
1579 | my %removedfiles = %{$refRemovedFiles}; |
---|
1580 | my %unknownfiles = %{$refUnknownFiles}; |
---|
1581 | |
---|
1582 | if ( %removedfiles or %changedfiles or %unknownfiles ) { |
---|
1583 | |
---|
1584 | if (%removedfiles) { |
---|
1585 | print "DELETED: files found in repository, but not in system:\n"; |
---|
1586 | print join( "\n", sort ( keys %removedfiles ) ) . "\n\n"; |
---|
1587 | } |
---|
1588 | |
---|
1589 | if (%changedfiles) { |
---|
1590 | print "MODIFIED: files differs between repository and system:\n"; |
---|
1591 | print join( "\n", ( keys %changedfiles ) ) . "\n\n"; |
---|
1592 | } |
---|
1593 | |
---|
1594 | if (%unknownfiles) { |
---|
1595 | print "UNKNOWN: insufficient permission to check files:\n"; |
---|
1596 | print join( "\n", ( keys %unknownfiles ) ) . "\n\n"; |
---|
1597 | } |
---|
1598 | |
---|
1599 | } else { |
---|
1600 | print "no modified files found in $dirname_repo\n"; |
---|
1601 | $return_code = $RETURN_OK; |
---|
1602 | } |
---|
1603 | |
---|
1604 | return $return_code; |
---|
1605 | } |
---|
1606 | |
---|
1607 | # |
---|
1608 | # return short status in Nagios plugin conform way |
---|
1609 | # |
---|
1610 | sub check() |
---|
1611 | { |
---|
1612 | check_env(); |
---|
1613 | |
---|
1614 | # return code for the shell |
---|
1615 | my $return_code = $RETURN_OK; |
---|
1616 | my $return_string = "OK: no modified files"; |
---|
1617 | |
---|
1618 | # perform plugins (required to see changes in plugin results) |
---|
1619 | perform_plugins(); |
---|
1620 | |
---|
1621 | # get modified files |
---|
1622 | ( my $refChangedFiles, my $refRemovedFiles, my $refUnknownFiles ) = |
---|
1623 | getModifiedFiles("/"); |
---|
1624 | my %changedfiles = %{$refChangedFiles}; |
---|
1625 | my %removedfiles = %{$refRemovedFiles}; |
---|
1626 | my %unknownfiles = %{$refUnknownFiles}; |
---|
1627 | |
---|
1628 | if ( %removedfiles or %changedfiles ) { |
---|
1629 | $return_string = "Warning: "; |
---|
1630 | if (%changedfiles) { |
---|
1631 | $return_string .= |
---|
1632 | "changed: " . join( ", ", ( keys %changedfiles ) ) . ". "; |
---|
1633 | } |
---|
1634 | if (%removedfiles) { |
---|
1635 | $return_string .= |
---|
1636 | "removed: " . join( ", ", ( keys %removedfiles ) ) . ". "; |
---|
1637 | } |
---|
1638 | if (%unknownfiles) { |
---|
1639 | $return_string .= |
---|
1640 | "unknown: " . join( ", ", ( keys %unknownfiles ) ) . ". "; |
---|
1641 | } |
---|
1642 | $return_code = $RETURN_WARN; |
---|
1643 | } |
---|
1644 | |
---|
1645 | # addition nagios Service Status |
---|
1646 | #Critical |
---|
1647 | #Unknown |
---|
1648 | |
---|
1649 | print "$return_string\n"; |
---|
1650 | return $return_code; |
---|
1651 | } |
---|
1652 | |
---|
1653 | sub permissions() |
---|
1654 | { |
---|
1655 | check_env(); |
---|
1656 | |
---|
1657 | my $return_code = $RETURN_OK; |
---|
1658 | |
---|
1659 | # |
---|
1660 | # update local repository |
---|
1661 | # |
---|
1662 | #svn_update(); |
---|
1663 | |
---|
1664 | my $dir = $DASSCM_REPO; |
---|
1665 | my @files = svn_ls("/"); |
---|
1666 | |
---|
1667 | if (@files) { |
---|
1668 | |
---|
1669 | print "#\n"; |
---|
1670 | print "# created by dasscm permissions\n"; |
---|
1671 | print "# It is intended to be used for restoring permissions\n"; |
---|
1672 | print "#\n"; |
---|
1673 | |
---|
1674 | # generate and print permissions |
---|
1675 | foreach my $line ( generatePermissionList(@files) ) { |
---|
1676 | print "$line\n"; |
---|
1677 | } |
---|
1678 | |
---|
1679 | } |
---|
1680 | |
---|
1681 | return $return_code; |
---|
1682 | } |
---|
1683 | |
---|
1684 | # |
---|
1685 | # remove all uncommited changes in the repository |
---|
1686 | # |
---|
1687 | sub cleanup() |
---|
1688 | { |
---|
1689 | my $return_code = $RETURN_OK; |
---|
1690 | |
---|
1691 | check_env(); |
---|
1692 | |
---|
1693 | svn_revert($DASSCM_REPO); |
---|
1694 | svn_remove_unknown_files($DASSCM_REPO); |
---|
1695 | |
---|
1696 | return $return_code; |
---|
1697 | } |
---|
1698 | |
---|
1699 | # |
---|
1700 | # used for bash completion |
---|
1701 | # prints the next possible command line parameters |
---|
1702 | # |
---|
1703 | sub complete(@) |
---|
1704 | { |
---|
1705 | my @input = @_; |
---|
1706 | my %options_complete = (); |
---|
1707 | |
---|
1708 | my $return_code = $RETURN_OK; |
---|
1709 | |
---|
1710 | # check and remove global options. if options are wrong, nothing to do |
---|
1711 | @ARGV = @input; |
---|
1712 | if ( GetOptions( \%options_complete, @OPTIONS_GLOBAL ) ) { |
---|
1713 | my $number_arguments = @input; |
---|
1714 | if ( $number_arguments <= 1 ) { |
---|
1715 | |
---|
1716 | # complete dasscm commands |
---|
1717 | my $input = $input[0] || ""; |
---|
1718 | map { m/^$input/ && print $_, "\n" } ( keys %COMMANDS ); |
---|
1719 | } else { |
---|
1720 | |
---|
1721 | # complete dasscm parameter |
---|
1722 | my $command = get_command_uniform_name( $input[0] ); |
---|
1723 | if ($command) { |
---|
1724 | |
---|
1725 | # remove command |
---|
1726 | shift @input; |
---|
1727 | |
---|
1728 | # check and remove options |
---|
1729 | my @options = get_command_possible_options($command); |
---|
1730 | @ARGV = @input; |
---|
1731 | if ( ( not @options ) |
---|
1732 | || ( GetOptions( \%options_complete, @options ) ) ) |
---|
1733 | { |
---|
1734 | |
---|
1735 | my @params = get_command_possible_params($command); |
---|
1736 | if ($verbose) { print "params: ", Dumper(@params); } |
---|
1737 | |
---|
1738 | my $number_arguments = @input; |
---|
1739 | |
---|
1740 | #print "input: ", join( ",", @input ), " (", $number_arguments, ")\n"; |
---|
1741 | |
---|
1742 | if ( $number_arguments > 0 ) { |
---|
1743 | my $parameter_number = $number_arguments - 1; |
---|
1744 | if ( defined( $params[$parameter_number] ) |
---|
1745 | && $params[$parameter_number] ) |
---|
1746 | { |
---|
1747 | my $param = $params[$parameter_number]; |
---|
1748 | if ($verbose) { |
---|
1749 | print "param used: ", $param, "\n"; |
---|
1750 | } |
---|
1751 | if ( $param eq "PATH_PROD" ) { |
---|
1752 | complete_path( |
---|
1753 | $input[ $number_arguments - 1 ] ); |
---|
1754 | } elsif ( $param eq "PATH_REPO" ) { |
---|
1755 | complete_repopath( |
---|
1756 | $input[ $number_arguments - 1 ] ); |
---|
1757 | } |
---|
1758 | } |
---|
1759 | } |
---|
1760 | } |
---|
1761 | } |
---|
1762 | } |
---|
1763 | } |
---|
1764 | return $return_code; |
---|
1765 | } |
---|
1766 | |
---|
1767 | sub complete_path(@) |
---|
1768 | { |
---|
1769 | my $return_code = $RETURN_OK; |
---|
1770 | check_parameter( @_, 1 ); |
---|
1771 | check_env(); |
---|
1772 | |
---|
1773 | ( |
---|
1774 | my $basename, |
---|
1775 | my $dirname_prod, |
---|
1776 | my $dirname_repo, |
---|
1777 | my $filename_prod, |
---|
1778 | my $filename_repo |
---|
1779 | ) = get_filenames( $_[0] ); |
---|
1780 | |
---|
1781 | my @files = get_complete_path_globbing($filename_prod); |
---|
1782 | |
---|
1783 | if (@files) { |
---|
1784 | print join( "\n", @files ); |
---|
1785 | print "\n"; |
---|
1786 | } |
---|
1787 | return $return_code; |
---|
1788 | } |
---|
1789 | |
---|
1790 | sub complete_repopath(@) |
---|
1791 | { |
---|
1792 | my $return_code = $RETURN_OK; |
---|
1793 | check_parameter( @_, 1 ); |
---|
1794 | check_env(); |
---|
1795 | |
---|
1796 | ( |
---|
1797 | my $basename, |
---|
1798 | my $dirname_prod, |
---|
1799 | my $dirname_repo, |
---|
1800 | my $filename_prod, |
---|
1801 | my $filename_repo |
---|
1802 | ) = get_filenames( $_[0] ); |
---|
1803 | |
---|
1804 | my @files = get_complete_path_globbing($filename_repo); |
---|
1805 | |
---|
1806 | if (@files) { |
---|
1807 | |
---|
1808 | # remove DASSCM_REPO path again |
---|
1809 | print join( |
---|
1810 | "\n", |
---|
1811 | map( { |
---|
1812 | s|^${DASSCM_REPO}|/|; |
---|
1813 | $_ |
---|
1814 | } @files ) |
---|
1815 | ); |
---|
1816 | print "\n"; |
---|
1817 | } |
---|
1818 | return $return_code; |
---|
1819 | } |
---|
1820 | |
---|
1821 | ##################################################################### |
---|
1822 | # |
---|
1823 | # main |
---|
1824 | # |
---|
1825 | |
---|
1826 | my $return_code = $RETURN_OK; |
---|
1827 | my $number_arguments = @ARGV; |
---|
1828 | |
---|
1829 | # global options |
---|
1830 | # stops at first non-option |
---|
1831 | Getopt::Long::Configure('require_order'); |
---|
1832 | if ( not GetOptions( \%options, @OPTIONS_GLOBAL ) ) { |
---|
1833 | usage(); |
---|
1834 | exit $RETURN_NOK; |
---|
1835 | } |
---|
1836 | |
---|
1837 | # set verbose to command line option |
---|
1838 | $verbose = $options{'verbose'}; |
---|
1839 | |
---|
1840 | if ( $options{'help'} ) { |
---|
1841 | help(@ARGV); |
---|
1842 | exit; |
---|
1843 | } |
---|
1844 | |
---|
1845 | # get subcommand and remove it from @ARGV |
---|
1846 | if ( defined( $ARGV[0] ) ) { |
---|
1847 | $command = get_command_uniform_name( $ARGV[0] ); |
---|
1848 | shift @ARGV; |
---|
1849 | } |
---|
1850 | |
---|
1851 | if ( not defined($command) ) { |
---|
1852 | usage(); |
---|
1853 | exit $RETURN_NOK; |
---|
1854 | } |
---|
1855 | |
---|
1856 | $DASSCM_LOCAL_REPOSITORY_BASE = $config->{'DASSCM_LOCAL_REPOSITORY_BASE'}; |
---|
1857 | $DASSCM_REPOSITORY_NAME = $config->{'DASSCM_REPOSITORY_NAME'}; |
---|
1858 | |
---|
1859 | $DASSCM_PLUGIN_RESULTS_PATH = |
---|
1860 | $config->{'DASSCM_LOCAL_REPOSITORY_BASE'} . "/" . "plugin-results/"; |
---|
1861 | |
---|
1862 | # get list of additional directories and files, seperated by blank (" ") |
---|
1863 | # these files are always stored in subversion |
---|
1864 | if ( $config->{'DASSCM_ADDITIONAL_FILES'} ) { |
---|
1865 | @DASSCM_ADDITIONAL_FILES = split / /, $config->{'DASSCM_ADDITIONAL_FILES'}; |
---|
1866 | } else { |
---|
1867 | @DASSCM_ADDITIONAL_FILES = ( $DASSCM_PLUGIN_RESULTS_PATH ); |
---|
1868 | } |
---|
1869 | |
---|
1870 | # TODO: check variables |
---|
1871 | $DASSCM_SVN_REPOSITORY = |
---|
1872 | $config->{'DASSCM_SVN_REPOSITORY_BASE'} . "/" . $DASSCM_REPOSITORY_NAME; |
---|
1873 | |
---|
1874 | $DASSCM_CHECKOUT_USERNAME = $config->{'DASSCM_CHECKOUT_USERNAME'}; |
---|
1875 | $DASSCM_CHECKOUT_PASSWORD = $config->{'DASSCM_CHECKOUT_PASSWORD'}; |
---|
1876 | |
---|
1877 | # |
---|
1878 | # if a user is given by dasscm configuration file, we use it. |
---|
1879 | # Otherwise we expect that read-only account is configured |
---|
1880 | # as local subversion configuration. |
---|
1881 | # If this is also not the case, |
---|
1882 | # user is required to type username and password. |
---|
1883 | # This will be stored as local subversion configuration thereafter. |
---|
1884 | # |
---|
1885 | if ( $DASSCM_CHECKOUT_USERNAME && $DASSCM_CHECKOUT_PASSWORD ) { |
---|
1886 | $svnCheckoutCredentials = |
---|
1887 | " --username $DASSCM_CHECKOUT_USERNAME --password $DASSCM_CHECKOUT_PASSWORD "; |
---|
1888 | } |
---|
1889 | |
---|
1890 | |
---|
1891 | # check for command options |
---|
1892 | my @cmd_options = get_command_possible_options($command); |
---|
1893 | if (@cmd_options) { |
---|
1894 | |
---|
1895 | # get command line options and store them in options hash |
---|
1896 | my $result = GetOptions( \%options, @cmd_options ); |
---|
1897 | |
---|
1898 | # print options |
---|
1899 | foreach my $option ( keys %options ) { |
---|
1900 | print "${option}: $options{$option}\n"; |
---|
1901 | } |
---|
1902 | } |
---|
1903 | |
---|
1904 | # |
---|
1905 | # action accordinly to command are taken |
---|
1906 | # |
---|
1907 | $return_code = &{ get_command_function($command) }(@ARGV); |
---|
1908 | |
---|
1909 | exit $return_code; |
---|