source: dasscm/trunk/usr/bin/dasscm@ 914

Last change on this file since 914 was 914, checked in by joergs, on Jul 2, 2010 at 5:16:50 PM

added missing command descriptions

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