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

Last change on this file since 894 was 894, checked in by joergs, on Jun 26, 2010 at 2:40:09 PM

complete handles global options

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