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

Last change on this file since 893 was 893, checked in by joergs, on Jun 26, 2010 at 2:13:20 PM

better option handling

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