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

Last change on this file since 915 was 915, checked in by joergs, on Jul 16, 2010 at 6:28:10 PM

replaced ReadMode('noecho') by to reduce dependencies

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