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

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

added missing command descriptions

  • Property keyword set to id
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 45.2 KB
Line 
1#!/usr/bin/perl -w
2
3# $Id: dasscm 914 2010-07-02 15:16:50Z 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 914 2010-07-02 15:16:50Z 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 for $input_username: ";
1056 ReadMode('noecho');
1057 my $input_password = <STDIN>;
1058 ReadMode('normal');
1059 chomp($input_password);
1060 print "\n";
1061
1062 # checking checkout username/password
1063 svn_check_credentials( $DASSCM_CHECKOUT_USERNAME,
1064 $DASSCM_CHECKOUT_PASSWORD );
1065 print "checkout access okay\n";
1066
1067 svn_check_credentials( $input_username, $input_password );
1068
1069 #
1070 # set environment variables
1071 #
1072 $ENV{'DASSCM_USERNAME'} = "$input_username";
1073 $ENV{'DASSCM_PASSWORD'} = "$input_password";
1074
1075 print "subversion access okay\n\n", "DASSCM_USERNAME: $input_username\n",
1076 "DASSCM_PASSWORD: (hidden)\n", "DASSCM_PROD: $DASSCM_PROD\n",
1077 "DASSCM_REPO: $DASSCM_REPO\n",
1078 "Server Repository: $DASSCM_SVN_REPOSITORY\n", "\n";
1079
1080 status();
1081
1082 print "\n[dasscm shell]\n\n";
1083 my $shell = $SHELL || "bash";
1084 exec($shell) or die "failed to start new shell";
1085}
1086
1087#
1088# initialize local checkout directory (initial checkout)
1089#
1090sub init(@)
1091{
1092 check_parameter( @_, 1 );
1093 check_env();
1094
1095 # don't do repository creation (svn mkdir) here,
1096 # because then their must be a lot of prior checks
1097
1098 # update complete repository
1099 # and create permission file
1100 my $retcode = run_interactive(
1101 "cd $DASSCM_LOCAL_REPOSITORY_BASE; $SVN checkout $svnCheckoutCredentials $svnOptions $DASSCM_SVN_REPOSITORY; mkdir -p `dirname $DASSCM_PERMISSION_FILE`; touch $DASSCM_PERMISSION_FILE"
1102 );
1103}
1104
1105sub ls(@)
1106{
1107 check_parameter( @_, 1 );
1108 check_env();
1109
1110 my @files = svn_ls(@_);
1111
1112 if (@files) {
1113 print join( "\n", @files );
1114 print "\n";
1115 }
1116}
1117
1118sub update(@)
1119{
1120 check_parameter( @_, 1 );
1121 check_env();
1122
1123 #
1124 # update local repository
1125 #
1126 svn_update();
1127}
1128
1129#
1130# helper function for "add" command
1131#
1132sub add_helper(@)
1133{
1134 (
1135 my $basename,
1136 my $dirname_prod,
1137 my $dirname_repo,
1138 my $filename_prod,
1139 my $filename_repo
1140 ) = get_filenames( $_[0] );
1141
1142 mkpath($dirname_repo);
1143 copy_file_to_repository($filename_prod);
1144
1145 # already checked in?
1146 chdir $DASSCM_REPO;
1147
1148 # also add the path to filename.
1149 for my $dir ( split( '/', $dirname_prod ) ) {
1150 if ($dir) {
1151 my ( $rc, @out ) = run_command("$SVN add --non-recursive '$dir'");
1152 if ( $rc > 0 ) {
1153 print join( "\n", @out );
1154 }
1155 chdir $dir;
1156 }
1157 }
1158 my ( $rc, @out ) = run_command("$SVN add '$basename'");
1159 if ( $rc > 0 ) {
1160 print join( "\n", @out );
1161 }
1162 chdir $StartDirectory;
1163
1164}
1165
1166#
1167# adding new files (or directories)
1168#
1169sub add(@)
1170{
1171 check_parameter( @_, 1 );
1172 check_env();
1173
1174 #
1175 # update local repository
1176 #
1177 svn_update();
1178
1179 # get all regular files and links
1180 my $href_files = get_files(@_);
1181
1182 #print Dumper( $href_files );
1183
1184 my @files = @{ $href_files->{files} };
1185 my @links = @{ $href_files->{links} };
1186
1187 if (@files) {
1188 my $number = $#files + 1;
1189 print "files to check-in ($number): \n";
1190 print join( "\n", @files );
1191 print "\n";
1192 }
1193
1194 # TODO: check in links and also link target? At least warn about link target
1195 if (@links) {
1196 my $number = $#links + 1;
1197 print "\n";
1198 print "ignoring links ($number):\n";
1199 print join( "\n", @links );
1200 print "\n";
1201 }
1202
1203 # TODO: confirm
1204
1205 # copy files one by one to local repository
1206 for my $file (@files) {
1207
1208 # add file
1209 add_helper($file);
1210 }
1211
1212 # create new permissions file
1213 permissions();
1214
1215 # add permissions file
1216 add_helper($DASSCM_PERMISSION_FILE);
1217
1218 if ( $options{'message'} ) {
1219 $svnOptions .= " --message \"$options{'message'}\" ";
1220 }
1221
1222 # commit calls $EDITOR.
1223 # use "interactive" here, to display output
1224 my $retcode = run_interactive(
1225 "$SVN commit $svnOptions --username '$DASSCM_USERNAME' $svnPasswordCredentials $DASSCM_REPO"
1226 );
1227
1228 # svn commit does not deliever an error return code, if commit is canceld,
1229 # so a revert is performed in any case
1230 svn_revert();
1231}
1232
1233#
1234# checks in all modified files
1235#
1236sub commit(@)
1237{
1238 check_parameter( @_, 1 );
1239 check_env();
1240
1241 (
1242 my $basename,
1243 my $dirname_prod,
1244 my $dirname_repo,
1245 my $filename_prod,
1246 my $filename_repo
1247 ) = get_filenames( $_[0] );
1248
1249 #
1250 # update local repository
1251 #
1252 svn_update();
1253
1254 ( my $refChangedFiles, my $refRemovedFiles ) =
1255 getModifiedFiles($filename_prod);
1256 my %changedfiles = %{$refChangedFiles};
1257 my %removedfiles = %{$refRemovedFiles};
1258
1259 if (%removedfiles) {
1260 my $removedFilesString =
1261 '"' . join( '" "', values(%removedfiles) ) . '"';
1262 my ( $rc, @out ) = run_command("$SVN rm $removedFilesString");
1263 if ( $rc > 0 ) {
1264 print join( "\n", @out );
1265 }
1266 }
1267
1268 # copy files one by one to local repository
1269 for my $file ( keys(%changedfiles) ) {
1270 copy_file_to_repository($file);
1271 }
1272
1273 # create new permissions file
1274 permissions();
1275
1276 # add permissions file
1277 add_helper($DASSCM_PERMISSION_FILE);
1278
1279 if ( $options{'message'} ) {
1280 $svnOptions .= " --message \"$options{'message'}\" ";
1281 }
1282
1283 # commit calls $EDITOR.
1284 # use "interactive" here, to display output
1285 my $retcode = run_interactive(
1286 "$SVN commit $svnOptions --username '$DASSCM_USERNAME' $svnPasswordCredentials $DASSCM_REPO"
1287 );
1288
1289 # svn commit does not deliever an error return code, if commit is canceld,
1290 # so a revert is performed in any case
1291 svn_revert();
1292}
1293
1294#
1295# revert: copies files back from repository to system
1296#
1297sub revert(@)
1298{
1299 check_parameter( @_, 1 );
1300 check_env();
1301
1302 (
1303 my $basename,
1304 my $dirname_prod,
1305 my $dirname_repo,
1306 my $filename_prod,
1307 my $filename_repo
1308 ) = get_filenames( $_[0] );
1309
1310 # return code for the shell
1311 # default: error
1312 my $return_code = $RETURN_OK;
1313
1314 # cleanup repository
1315 cleanup();
1316
1317 #svn_update();
1318
1319 ( my $refChangedFiles, my $refRemovedFiles, my $refUnknownFiles ) =
1320 getModifiedFiles($filename_prod);
1321 my %changedfiles = %{$refChangedFiles};
1322 my %removedfiles = %{$refRemovedFiles};
1323 my %unknownfiles = %{$refUnknownFiles};
1324
1325 if ( %removedfiles or %changedfiles or %unknownfiles ) {
1326
1327 if (%removedfiles) {
1328 print "DELETED files and directories. Recreated from repository:\n";
1329 my @removedPaths =
1330 ( sort { length $a > length $b } keys %removedfiles );
1331 print join( "\n", @removedPaths ) . "\n\n";
1332
1333 # copy files one by one from local repository to system
1334 # and also create directories
1335 # paths are sorted, so that directories are created first
1336 for my $real_path (@removedPaths) {
1337 if ( -d $removedfiles{"$real_path"} ) {
1338 mkpath("$real_path");
1339 } else {
1340 copy_file_from_repository_to_system($real_path);
1341 }
1342 }
1343 }
1344
1345 if (%changedfiles) {
1346 print "MODIFIED files. Copied from repository to the system:\n";
1347 print join( "\n", ( keys %changedfiles ) ) . "\n\n";
1348
1349 # copy files one by one from local repository to system
1350 for my $real_file ( keys(%changedfiles) ) {
1351 copy_file_from_repository_to_system($real_file);
1352 }
1353
1354 }
1355
1356 if (%unknownfiles) {
1357 print "UNKNOWN: insufficient permission to check files:\n";
1358 print join( "\n", ( keys %unknownfiles ) ) . "\n\n";
1359
1360 $return_code = $RETURN_NOK;
1361 }
1362
1363 } else {
1364 print "no modified files found in $dirname_repo\n";
1365 }
1366
1367 return $return_code;
1368}
1369
1370sub blame(@)
1371{
1372 check_parameter( @_, 1 );
1373 check_env();
1374
1375 (
1376 my $basename,
1377 my $dirname_prod,
1378 my $dirname_repo,
1379 my $filename_prod,
1380 my $filename_repo
1381 ) = get_filenames( $_[0] );
1382
1383 my $retcode = run_interactive("$SVN blame $svnOptions $filename_repo");
1384}
1385
1386sub diff(@)
1387{
1388 check_parameter( @_, 1 );
1389 check_env();
1390
1391 (
1392 my $basename,
1393 my $dirname_prod,
1394 my $dirname_repo,
1395 my $filename_prod,
1396 my $filename_repo
1397 ) = get_filenames( $_[0] );
1398
1399 #print "$basename,$dirname_prod,$dirname_repo\n";
1400
1401 svn_update();
1402
1403 ( my $rc_diff, my @diff_result ) =
1404 run_command( $diff . " $filename_repo $filename_prod" );
1405
1406 print @diff_result;
1407}
1408
1409sub status(@)
1410{
1411 check_parameter( @_, 1 );
1412 check_env();
1413
1414 (
1415 my $basename,
1416 my $dirname_prod,
1417 my $dirname_repo,
1418 my $filename_prod,
1419 my $filename_repo
1420 ) = get_filenames( $_[0] || "/" );
1421
1422 # return code for the shell
1423 # default: error
1424 my $return_code = $RETURN_NOK;
1425
1426 #
1427 # update local repository
1428 #
1429 #svn_update( $filename_prod );
1430
1431 # check, if permissions have changed
1432 permissions();
1433
1434 # get modified files
1435 ( my $refChangedFiles, my $refRemovedFiles, my $refUnknownFiles ) =
1436 getModifiedFiles($dirname_prod);
1437 my %changedfiles = %{$refChangedFiles};
1438 my %removedfiles = %{$refRemovedFiles};
1439 my %unknownfiles = %{$refUnknownFiles};
1440
1441 if ( %removedfiles or %changedfiles or %unknownfiles ) {
1442
1443 if (%removedfiles) {
1444 print "DELETED: files found in repository, but not in system:\n";
1445 print join( "\n", sort ( keys %removedfiles ) ) . "\n\n";
1446 }
1447
1448 if (%changedfiles) {
1449 print "MODIFIED: files differs between repository and system:\n";
1450 print join( "\n", ( keys %changedfiles ) ) . "\n\n";
1451 }
1452
1453 if (%unknownfiles) {
1454 print "UNKNOWN: insufficient permission to check files:\n";
1455 print join( "\n", ( keys %unknownfiles ) ) . "\n\n";
1456 }
1457
1458 } else {
1459 print "no modified files found in $dirname_repo\n";
1460 $return_code = $RETURN_OK;
1461 }
1462
1463 return $return_code;
1464}
1465
1466#
1467# return short status in Nagios plugin conform way
1468#
1469sub check()
1470{
1471 check_env();
1472
1473 # return code for the shell
1474 my $return_code = $RETURN_OK;
1475 my $return_string = "OK: no modified files";
1476
1477 # check, if permissions have changed
1478 permissions();
1479
1480 # get modified files
1481 ( my $refChangedFiles, my $refRemovedFiles, my $refUnknownFiles ) =
1482 getModifiedFiles("/");
1483 my %changedfiles = %{$refChangedFiles};
1484 my %removedfiles = %{$refRemovedFiles};
1485 my %unknownfiles = %{$refUnknownFiles};
1486
1487 if ( %removedfiles or %changedfiles ) {
1488 $return_string = "Warning: ";
1489 if (%changedfiles) {
1490 $return_string .=
1491 "changed: " . join( ", ", ( keys %changedfiles ) ) . ". ";
1492 }
1493 if (%removedfiles) {
1494 $return_string .=
1495 "removed: " . join( ", ", ( keys %removedfiles ) ) . ". ";
1496 }
1497 if (%unknownfiles) {
1498 $return_string .=
1499 "unknown: " . join( ", ", ( keys %unknownfiles ) ) . ". ";
1500 }
1501 $return_code = $RETURN_WARN;
1502 }
1503
1504 # addition nagios Service Status
1505 #Critical
1506 #Unknown
1507
1508 print "$return_string\n";
1509 return $return_code;
1510}
1511
1512sub permissions()
1513{
1514 check_env();
1515
1516 my $return_code = $RETURN_OK;
1517
1518 #
1519 # update local repository
1520 #
1521 #svn_update();
1522
1523 my $dir = $DASSCM_REPO;
1524 my @files = svn_ls("/");
1525
1526 if (@files) {
1527
1528 # generieren der Permissions
1529 my @permissions = generatePermissionList(@files);
1530 my $OUTFILE;
1531 my $tofile = 0; # Status für schreiben in File
1532
1533 if ( -w dirname($DASSCM_PERMISSION_FILE) ) {
1534
1535 # Verzeichnis existiert => schreiben
1536 open( OUTFILE, ">$DASSCM_PERMISSION_FILE" )
1537 || die("failed to write to $DASSCM_PERMISSION_FILE: $!");
1538 $tofile = 1; # Merken, daß in File geschrieben wird
1539 print OUTFILE "#\n";
1540 print OUTFILE "# created by dasscm permissions\n";
1541 print OUTFILE
1542 "# It is intended to be used for restoring permissions\n";
1543 print OUTFILE "#\n";
1544 } else {
1545
1546 if ( $command eq "permission" ) {
1547
1548 # Pfad für Sicherungsdatei existiert nicht => schreiben auf stdout
1549 # Alias Filehandle für stdout erzeugen
1550 $return_code = $RETURN_WARN;
1551 *OUTFILE = *STDOUT;
1552 } else {
1553
1554 # TODO: improve this. Check for diff?
1555 $return_code = $RETURN_CRIT;
1556 return $return_code;
1557 }
1558 }
1559
1560 foreach my $line (@permissions) {
1561 print OUTFILE "$line\n";
1562 }
1563
1564 if ($tofile) {
1565 close(OUTFILE);
1566 }
1567 }
1568
1569 return $return_code;
1570}
1571
1572#
1573# remove all uncommited changes in the repository
1574#
1575sub cleanup()
1576{
1577 check_env();
1578
1579 svn_revert($DASSCM_REPO);
1580 svn_remove_unknown_files($DASSCM_REPO);
1581}
1582
1583#
1584# used for bash completion
1585# prints the next possible command line parameters
1586#
1587sub complete(@)
1588{
1589 my @input = @_;
1590 my %options_complete = ();
1591
1592 # check and remove global options. if options are wrong, nothing to do
1593 @ARGV = @input;
1594 if ( GetOptions( \%options_complete, @OPTIONS_GLOBAL ) ) {
1595 my $number_arguments = @input;
1596 if ( $number_arguments <= 1 ) {
1597
1598 # complete dasscm commands
1599 my $input = $input[0] || "";
1600 map { m/^$input/ && print $_, "\n" } ( keys %COMMANDS );
1601 } else {
1602
1603 # complete dasscm parameter
1604 my $command = get_command_uniform_name( $input[0] );
1605 if ($command) {
1606
1607 # remove command
1608 shift @input;
1609
1610 # check and remove options
1611 my @options = get_command_possible_options($command);
1612 @ARGV = @input;
1613 if ( ( not @options )
1614 || ( GetOptions( \%options_complete, @options ) ) )
1615 {
1616
1617 my @params = get_command_possible_params($command);
1618 if ($verbose) { print "params: ", Dumper(@params); }
1619
1620 my $number_arguments = @input;
1621
1622 #print "input: ", join( ",", @input ), " (", $number_arguments, ")\n";
1623
1624 if ( $number_arguments > 0 ) {
1625 my $parameter_number = $number_arguments - 1;
1626 if ( defined( $params[$parameter_number] )
1627 && $params[$parameter_number] )
1628 {
1629 my $param = $params[$parameter_number];
1630 if ($verbose) {
1631 print "param used: ", $param, "\n";
1632 }
1633 if ( $param eq "PATH_PROD" ) {
1634 complete_path(
1635 $input[ $number_arguments - 1 ] );
1636 } elsif ( $param eq "PATH_REPO" ) {
1637 complete_repopath(
1638 $input[ $number_arguments - 1 ] );
1639 }
1640 }
1641 }
1642 }
1643 }
1644 }
1645 }
1646}
1647
1648sub complete_path(@)
1649{
1650 check_parameter( @_, 1 );
1651 check_env();
1652
1653 (
1654 my $basename,
1655 my $dirname_prod,
1656 my $dirname_repo,
1657 my $filename_prod,
1658 my $filename_repo
1659 ) = get_filenames( $_[0] );
1660
1661 my @files = get_complete_path_globbing($filename_prod);
1662
1663 if (@files) {
1664 print join( "\n", @files );
1665 print "\n";
1666 }
1667}
1668
1669sub complete_repopath(@)
1670{
1671 check_parameter( @_, 1 );
1672 check_env();
1673
1674 (
1675 my $basename,
1676 my $dirname_prod,
1677 my $dirname_repo,
1678 my $filename_prod,
1679 my $filename_repo
1680 ) = get_filenames( $_[0] );
1681
1682 my @files = get_complete_path_globbing($filename_repo);
1683
1684 if (@files) {
1685
1686 # remove DASSCM_REPO path again
1687 print join(
1688 "\n",
1689 map( {
1690 s|^${DASSCM_REPO}|/|;
1691 $_
1692 } @files )
1693 );
1694 print "\n";
1695 }
1696
1697}
1698
1699#####################################################################
1700#
1701# main
1702#
1703
1704my $return_code = $RETURN_OK;
1705my $number_arguments = @ARGV;
1706
1707# global options
1708# stops at first non-option
1709Getopt::Long::Configure('require_order');
1710if ( not GetOptions( \%options, @OPTIONS_GLOBAL ) ) {
1711 usage();
1712 exit $RETURN_NOK;
1713}
1714
1715# set verbose to command line option
1716$verbose = $options{'verbose'};
1717
1718if ( $options{'help'} ) {
1719 help(@ARGV);
1720 exit;
1721}
1722
1723# get subcommand and remove it from @ARGV
1724if ( defined( $ARGV[0] ) ) {
1725 $command = get_command_uniform_name( $ARGV[0] );
1726 shift @ARGV;
1727}
1728
1729if ( not defined($command) ) {
1730 usage();
1731 exit $RETURN_NOK;
1732}
1733
1734$DASSCM_LOCAL_REPOSITORY_BASE = $config->{'DASSCM_LOCAL_REPOSITORY_BASE'};
1735$DASSCM_REPOSITORY_NAME = $config->{'DASSCM_REPOSITORY_NAME'};
1736
1737# TODO: check variables
1738$DASSCM_SVN_REPOSITORY =
1739 $config->{'DASSCM_SVN_REPOSITORY_BASE'} . "/" . $DASSCM_REPOSITORY_NAME;
1740
1741$DASSCM_CHECKOUT_USERNAME = $config->{'DASSCM_CHECKOUT_USERNAME'};
1742$DASSCM_CHECKOUT_PASSWORD = $config->{'DASSCM_CHECKOUT_PASSWORD'};
1743
1744#
1745# if a user is given by dasscm configuration file, we use it.
1746# Otherwise we expect that read-only account is configured
1747# as local subversion configuration.
1748# If this is also not the case,
1749# user is required to type username and password.
1750# This will be stored as local subversion configuration thereafter.
1751#
1752if ( $DASSCM_CHECKOUT_USERNAME && $DASSCM_CHECKOUT_PASSWORD ) {
1753 $svnCheckoutCredentials =
1754 " --username $DASSCM_CHECKOUT_USERNAME --password $DASSCM_CHECKOUT_PASSWORD ";
1755}
1756
1757$DASSCM_PERMISSION_FILE = $config->{'DASSCM_PERMISSION_FILE'}
1758 || "/etc/permissions.d/dasscm.permission_backup";
1759
1760# check for command options
1761my @cmd_options = get_command_possible_options($command);
1762if (@cmd_options) {
1763
1764 # get command line options and store them in options hash
1765 my $result = GetOptions( \%options, @cmd_options );
1766
1767 # print options
1768 foreach my $option ( keys %options ) {
1769 print "${option}: $options{$option}\n";
1770 }
1771}
1772
1773#
1774# action accordinly to command are taken
1775#
1776&{ get_command_function($command) }(@ARGV);
1777
1778exit $return_code;
Note: See TracBrowser for help on using the repository browser.