source: trunk/dasscm/dasscm@ 277

Last change on this file since 277 was 277, checked in by joergs, on Mar 6, 2009 at 5:25:20 PM

added check for nagios plugin

  • Property keyword set to id
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 30.8 KB
Line 
1#!/usr/bin/perl -w
2
3# $Id: dasscm 277 2009-03-06 16:25:20Z joergs $
4
5use strict;
6
7use Env
8 qw($DASSCM_PROD $DASSCM_REPO $USER $DASSCM_USERNAME $DASSCM_USER $DASSCM_PASSWORD $SHELL);
9use Cwd;
10use Getopt::Long;
11use File::Basename;
12use File::Compare;
13use File::Copy;
14use File::Find;
15use File::stat;
16use File::Path;
17use Term::ReadKey;
18
19#use Data::Dumper;
20
21#####################################################################
22#
23# global
24#
25
26# shell exit codes
27my $RETURN_OK = 0;
28my $RETURN_NOK = 1;
29
30# Nagios return codes
31my $RETURN_WARN = 1;
32my $RETURN_CRIT = 2;
33my $RETURN_UNKNOWN = 3;
34
35# file to store permissions
36my $permissions_file = "/etc/permissions.d/dasscm.permission_backup";
37
38# documentation file (for usage)
39my $doc_file = "/usr/share/doc/packages/dasscm/dasscm_howto.txt";
40
41# commands that require write access (and therefore a login)
42# to the repository server
43my @COMMANDS_REQUIRE_WRITE = ( "add", "commit" );
44
45# configuration file
46my $config_file = "/etc/dasscm.conf";
47my $config = get_config($config_file);
48my $DASSCM_LOCAL_REPOSITORY_BASE;
49my $DASSCM_REPOSITORY_NAME;
50my $DASSCM_SVN_REPOSITORY;
51my $DASSCM_CHECKOUT_USERNAME;
52my $DASSCM_CHECKOUT_PASSWORD;
53
54# current directory at program start
55my $StartDirectory = cwd();
56
57my $diff = "diff --exclude .svn ";
58my $SVN = "svn ";
59my $svnOptions = "";
60my $svnCheckoutCredentials = "";
61my $svnPasswordCredentials = "";
62
63# flag. Set to true by svn_update
64# This prevents, that svn_update is called multiple times
65my $svnRepositoryIsUptodate = 0;
66
67# command line options get stored in options hash
68my %options = ();
69
70# subcommand, that gets executed (add, commit, ...)
71my $command;
72
73my $verbose = 0;
74
75#####################################################################
76#
77# util functions
78#
79sub usage()
80{
81 print "usage: dasscm <subcommand> [options] [args]\n";
82 print "\n";
83 print "dasscm is intended to help versioning configuration files\n";
84 print "\n";
85 print "Available subcommands:\n";
86 print " help <subcommand>\n";
87 print " init\n";
88 print " login <username>\n";
89 print " up <path>\n";
90 print " ls <path>\n";
91 print " add <path>\n";
92 print " commit <path>\n";
93 print " diff <path>\n";
94 print " status <path>\n";
95 print " check\n";
96 print " cleanup\n";
97 print " permissions\n";
98 print "\n";
99 print "preparation:\n", " if dasscm is already configured,\n",
100 " use 'dasscm login' and then eg. 'add'.\n",
101 " The environment variables\n", " DASSCM_REPO\n", " DASSCM_PROD\n",
102 " DASSCM_USERNAME\n", " DASSCM_PASSWORD\n",
103 " are evaluated, but set automatically by 'dasscm login'.\n", "\n",
104 " If dasscm is not yet configured, read", " $doc_file\n";
105}
106
107sub warning(@)
108{
109 print "Warning: " . join( "\n ", @_ ) . "\n";
110}
111
112sub error(@)
113{
114 print "Error: " . join( "\n ", @_ ) . "\n";
115}
116
117sub fatalerror(@)
118{
119 error(@_);
120
121 #print "Exiting\n";
122 exit 1;
123}
124
125#
126# reading config file and return key/value pairs as hash
127#
128sub get_config
129{
130 my $file = $_[0];
131
132 if ( !$file ) {
133 fatalerror( "failed to open config file" . $file );
134 }
135
136 my $data = {};
137
138 # try to open config file
139 if ( !open( FH, $file ) ) {
140 fatalerror( "failed to open config file" . $file );
141 } else {
142 while (<FH>) {
143 chomp;
144 if (/^#/) {
145 next;
146 }
147 if ( $_ =~ /=/g ) {
148
149 # splitting in 2 fields at maximum
150 my ( $option, $value ) = split( /=/, $_, 2 );
151 $option =~ s/^\s+//g;
152 $option =~ s/\s+$//g;
153 $option =~ s/\"+//g;
154 $value =~ s/^\s+//g;
155 $value =~ s/\s+$//g;
156 $value =~ s/\"+//g;
157
158 if ( length($option) ) {
159 $data->{$option} = $value;
160 }
161 }
162 }
163 }
164 close(FH);
165
166 return $data;
167}
168
169#
170# check and evaluate environment variables
171#
172sub check_env()
173{
174
175 # DASSCM_PROD
176 if ( !$DASSCM_PROD ) {
177 $DASSCM_PROD = "/";
178 }
179
180 if ( !-d $DASSCM_PROD ) {
181 die "DASSCM_PROD ($DASSCM_PROD) is not set to a directory.\n";
182 }
183 if ($verbose) { print "DASSCM_PROD: " . $DASSCM_PROD . "\n"; }
184
185 # DASSCM_REPOSITORY_NAME
186 if ( !$DASSCM_REPOSITORY_NAME ) {
187 die
188 "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";
189 }
190
191 # DASSCM_REPO
192 if ( !$DASSCM_REPO ) {
193 if ( $DASSCM_LOCAL_REPOSITORY_BASE && $DASSCM_REPOSITORY_NAME ) {
194 $DASSCM_REPO =
195 $DASSCM_LOCAL_REPOSITORY_BASE . "/" . $DASSCM_REPOSITORY_NAME;
196 } else {
197 die
198 "Envirnonment variable DASSCM_REPO not set.\nSet DASSCM_REPO to the directory of the versioning system checkout for this machine.\n";
199 }
200 }
201 if ($verbose) { print "DASSCM_REPO: " . $DASSCM_REPO . "\n"; }
202
203 #
204 # subversion checkout user
205 #
206 if ( !$DASSCM_CHECKOUT_USERNAME ) {
207 fatalerror(
208 "variable DASSCM_CHECKOUT_USERNAME is not defined.",
209 "Use file $config_file to configure it."
210 );
211 }
212
213 if ( !$DASSCM_CHECKOUT_PASSWORD ) {
214 fatalerror(
215 "variable DASSCM_CHECKOUT_PASSWORD is not defined.",
216 "Use file $config_file to configure it."
217 );
218 }
219
220 #
221 # check if local repository directory exist
222 # (if not creating by init)
223 #
224 if ( $command ne "init" ) {
225 if ( not -d $DASSCM_REPO ) {
226 die
227 "Can't access local repository DASSCM_REPO\n($DASSCM_REPO)\nCheck configuration and execute\n dasscm init\n";
228 }
229
230 #
231 # user settings
232 #
233
234 # DASSCM_USER is legacy. Use DASSCM_USERNAME instead
235 if ( !$DASSCM_USERNAME ) {
236 $DASSCM_USERNAME = $DASSCM_USER;
237 }
238
239 # user root is not allowed for checkins.
240 # if user is root, DASSCM_USER has to be set,
241 # otherwise USER can be used
242 if ( "$USER" eq "root" ) {
243 if ( ( not $DASSCM_USERNAME )
244 and ( grep { m|^$command$| } @COMMANDS_REQUIRE_WRITE ) )
245 {
246
247 #( $command ne "login" ) and ( $command ne "status" ) ) {
248 fatalerror(
249 "Envirnonment variable DASSCM_USERNAME not set.",
250 "Set DASSCM_USERNAME to your subversion user account or",
251 "use 'dasscm login'"
252 );
253 }
254 $svnOptions .= " --no-auth-cache ";
255 } elsif ( !$DASSCM_USERNAME ) {
256 $DASSCM_USERNAME = $USER;
257 }
258
259 #
260 # password
261 #
262 if ($DASSCM_PASSWORD) {
263 $svnPasswordCredentials = " --password '$DASSCM_PASSWORD' ";
264 }
265 }
266
267 #$svnOptions .= " --username $DASSCM_USERNAME "
268}
269
270#
271# has been intendend,
272# to check addtitional parameters.
273# Currently not used.
274#
275sub check_parameter(@)
276{
277}
278
279#
280# generate from (relative) filename
281# all required file and directory names:
282# $basename, $dirname_prod, $dirname_repo,
283# $filename_prod, $filename_repo
284#
285sub get_filenames(@)
286{
287 my $filename_prod = $_[0] || ".";
288
289 # make filename absolut
290 if ( !( $filename_prod =~ m/^\// ) ) {
291 $filename_prod = cwd() . '/' . $filename_prod;
292 }
293
294 if ( not -r $filename_prod ) {
295 fatalerror( $filename_prod . " is not accessable" );
296 }
297
298 # dirname buggy: eg. "/etc/" is reduced to "/",
299 # "/etc" is used as filename
300 # herefore make sure, that if filename is a directory,
301 # it will end by "/"
302 if ( ( -d $filename_prod ) and ( !( $filename_prod =~ m/\/$/ ) ) ) {
303 $filename_prod = $filename_prod . '/';
304 }
305
306 ( my $basename, my $dirname_prod ) = fileparse($filename_prod);
307
308 # uses chdir to determine real directory in a unique way
309 chdir $dirname_prod or die $!;
310 $dirname_prod = cwd() . '/';
311 chdir $StartDirectory;
312
313 if ($verbose) {
314 print "dir: " . $dirname_prod . "\n";
315 print "fn: " . $basename . "\n";
316 }
317
318 my $dirname_repo = $DASSCM_REPO . "/" . $dirname_prod;
319 my $filename_repo = "$dirname_repo/$basename";
320
321 return (
322 $basename, $dirname_prod, $dirname_repo,
323 $filename_prod, $filename_repo
324 );
325}
326
327sub copy_file_to_repository( $ )
328{
329 my $filename = shift;
330
331 (
332 my $basename,
333 my $dirname_prod,
334 my $dirname_repo,
335 my $filename_prod,
336 my $filename_repo
337 )
338 = get_filenames($filename);
339
340 # TODO: are permissions also copied?
341 copy( $filename_prod, $filename_repo )
342 or error "failed to copy $filename_prod to repository: $!";
343}
344
345#
346# creates a file with permissions
347#
348sub generatePermissionList
349{
350
351 # generieren der Zeilen für Permission-Savefile
352 my @files = @_;
353 my @permlist = ();
354 foreach my $file (@files) {
355 $file = "/" . $file;
356 if ( -e $file ) {
357 my $info = stat($file) || die "failed to stat $file: aborting";
358 my $mode = get_type( $info->mode ) & 07777;
359 my $modestring = sprintf( "%04o", $mode );
360 my $uid = $info->uid;
361 my $uidname = getpwuid($uid);
362 my $gid = $info->gid;
363 my $gidname = getgrgid($gid);
364 push(
365 @permlist,
366 sprintf( "%-55s %-17s %4d",
367 $file, "${uidname}:${gidname}", $modestring )
368 );
369 } else {
370 print
371 "failed to get status of $file. It exists in the repository, but not on the system\n";
372 }
373 }
374 return @permlist;
375}
376
377sub get_type
378{
379
380 # Funktion übernommen aus /usr/bin/chkstat
381 my $S_IFLNK = 0120000; # symbolic link
382 my $S_IFREG = 0100000; # regular file
383 my $S_IFDIR = 0040000; # directory
384 my $S_IFCHAR = 0020000; # character device
385 my $S_IFBLK = 0060000; # block device
386 my $S_IFFIFO = 0010000; # fifo
387 my $S_IFSOCK = 0140000; # socket
388 my $S_IFMT = 0170000; # type of file
389
390 my $S_m;
391 if ( ( $_[0] & $S_IFMT ) == $S_IFLNK ) { $S_m = $_[0] - $S_IFLNK; }
392 elsif ( ( $_[0] & $S_IFMT ) == $S_IFREG ) { $S_m = $_[0] - $S_IFREG; }
393 elsif ( ( $_[0] & $S_IFMT ) == $S_IFDIR ) { $S_m = $_[0] - $S_IFDIR; }
394 elsif ( ( $_[0] & $S_IFMT ) == $S_IFCHAR ) { $S_m = $_[0] - $S_IFCHAR; }
395 elsif ( ( $_[0] & $S_IFMT ) == $S_IFBLK ) { $S_m = $_[0] - $S_IFBLK; }
396 elsif ( ( $_[0] & $S_IFMT ) == $S_IFFIFO ) { $S_m = $_[0] - $S_IFFIFO; }
397 elsif ( ( $_[0] & $S_IFMT ) == $S_IFSOCK ) { $S_m = $_[0] - $S_IFSOCK; }
398 $S_m;
399}
400
401sub run_command
402{
403 my $command = shift;
404
405 #print "executing command: " . $command . "\n";
406
407 open( RESULT, $command . ' 2>&1 |' );
408 my @result = <RESULT>;
409 close(RESULT);
410 my $retcode = $? >> 8;
411
412 #print @result;
413 #if( $retcode ) { print "return code: " . $retcode . "\n"; }
414
415 return ( $retcode, @result );
416}
417
418sub run_interactive
419{
420
421 if ($verbose) {
422 print "run_interactive:" . join( " ", @_ ) . "\n";
423 }
424
425 system(@_);
426 if ( $? == -1 ) {
427 printf "failed to execute: $!\n";
428 } elsif ( $? & 127 ) {
429 printf "child died with signal %d, %s coredump\n", ( $? & 127 ),
430 ( $? & 128 ) ? 'with' : 'without';
431 } elsif ( $? >> 8 != 0 ) {
432 printf "child exited with value %d\n", $? >> 8;
433 }
434 return ( $? >> 8 );
435}
436
437sub svn_check_credentials( $$;$$ )
438{
439 my $username = shift;
440 my $password = shift;
441
442 # check silently are allow user interaction?
443 my $interactive = shift || 0;
444
445 # default: exit program, if repository is not accessable
446 # (do not exit for 'init')
447 my $fatalerror = shift || 1;
448
449 print "checking credentials ";
450
451 if ( !$username ) {
452 fatalerror("no username given");
453 }
454
455 if ( !$password ) {
456 fatalerror("no password given");
457 }
458
459 print "for " . $username . "@" . $DASSCM_SVN_REPOSITORY . ": ";
460
461 # Options for "svn info" are not supported by subversion 1.0.0 (SLES9),
462 # therefore switching to "svn status"
463 # ( my $rc_update, my @result ) =
464 # run_command(
465 # "$SVN info --non-interactive --no-auth-cache --username $username --password $password $DASSCM_SVN_REPOSITORY"
466 # );
467 #print @result;
468
469 my $rc_update;
470 if ($interactive) {
471 $rc_update =
472 run_interactive(
473 "$SVN ls --no-auth-cache --username '$username' --password '$password' $DASSCM_SVN_REPOSITORY"
474 );
475 } else {
476 ( $rc_update, my @result ) =
477 run_command(
478 "$SVN ls --non-interactive --no-auth-cache --username '$username' --password '$password' $DASSCM_SVN_REPOSITORY"
479 );
480
481 if ( $rc_update != 0 ) {
482 print "\n", @result;
483 if ($fatalerror) {
484 fatalerror();
485 }
486 return;
487 }
488 }
489
490 # return success
491 return $rc_update == 0;
492}
493
494sub svn_update( ;$ )
495{
496 my $update_path = shift || "";
497
498 # use this flag to do only one update per run
499 if ( !$svnRepositoryIsUptodate ) {
500 ( my $rc_update, my @result ) =
501 run_command(
502 "$SVN update --non-interactive $svnCheckoutCredentials '$DASSCM_REPO/$update_path'"
503 );
504 print @result;
505 if ( $rc_update != 0 ) {
506 error( "failed to update local repository ($update_path)" );
507 } elsif ( not $update_path ) {
508
509 # set this flag if a full update is done
510 $svnRepositoryIsUptodate = 1;
511 }
512 }
513}
514
515sub svn_ls( ;@ )
516{
517 (
518 my $basename,
519 my $dirname_prod,
520 my $dirname_repo,
521 my $filename_prod,
522 my $filename_repo
523 )
524 = get_filenames( $_[0] );
525
526 # svn ls -R is better, but much, much slower
527 # ( my $rc, my @result ) = run_command("$SVN ls --recursive $svnCheckoutCredentials $path");
528
529 my @files = ();
530 my @links = ();
531 my @dirs = ();
532 my @others = ();
533
534 if ( -f $filename_prod ) {
535 @files = ($filename_prod);
536 } elsif ( -d $dirname_repo ) {
537 find(
538 {
539 wanted => sub {
540 my $name = $File::Find::name;
541 $name =~ s|^$dirname_repo||;
542 if ( $name =~ m/\.svn/ ) {
543
544 # skip svn meta data
545 } elsif ( -l $_ ) {
546
547 # soft link
548 # important: check for links first
549 # to exclude them from further checks
550 push( @links, $name );
551 } elsif ( -d $_ ) {
552
553 # directories
554 push( @dirs, $name );
555 } elsif ( -f $_ ) {
556
557 # regular file
558 push( @files, $name );
559 } else {
560 push( @others, $name );
561 }
562 }
563 },
564 ($dirname_repo)
565 );
566 }
567
568 return @files;
569}
570
571sub svn_revert( ;$ )
572{
573 my $path = shift || $DASSCM_REPO;
574
575 ( my $rc_update, my @result ) = run_command("$SVN revert -R '$path'");
576
577 if ( $rc_update != 0 ) {
578 print "\n", @result;
579 error("failed to revert subversion repository changes");
580 }
581}
582
583sub getModifiedFiles( ;$ )
584{
585 (
586 my $basename,
587 my $dirname_prod,
588 my $dirname_repo,
589 my $filename_prod,
590 my $filename_repo
591 )
592 = get_filenames( $_[0] );
593
594 my @files = svn_ls($filename_prod);
595
596 # stores result from status (cvscheck)
597 my %removedfiles = ();
598 my %changedfiles = ();
599
600 # create list of modified files
601 if (@files) {
602
603 foreach my $file (@files) {
604
605 my $realfile = $dirname_prod . $file;
606 my $cvsworkfile = $dirname_repo . $file;
607
608 if ( -d $realfile ) {
609 ## directory. do nothing
610 } elsif ( !-r $realfile ) {
611 $removedfiles{"$realfile"} = $cvsworkfile;
612 } else {
613 ( -r "$cvsworkfile" )
614 || die("Fehler: $cvsworkfile ist nicht lesbar");
615 if ( compare( $cvsworkfile, $realfile ) != 0 ) {
616 $changedfiles{"$realfile"} = $cvsworkfile;
617 }
618 }
619 }
620 }
621
622 return ( \%changedfiles, \%removedfiles );
623}
624
625#
626# from an array of files/dirs,
627# generates list of files
628# sorted by type
629#
630sub get_files( @ )
631{
632 my @files = ();
633 my @links = ();
634 my @dirs = ();
635 my @others = ();
636
637 if (@_) {
638 find(
639 {
640 wanted => sub {
641 my $fullname = cwd() . "/" . $_;
642 if ( -l $_ ) {
643
644 # soft link
645 # important: check for links first
646 # to exclude them from further checks
647 push( @links, $fullname );
648 } elsif ( -d $_ ) {
649
650 # directories
651 push( @dirs, $fullname );
652 } elsif ( -f $_ ) {
653
654 # regular file
655 push( @files, $fullname );
656 } else {
657 push( @others, $fullname );
658 }
659 }
660 },
661 @_
662 );
663 }
664
665 # don't rely on others.
666 # If more specific file types are needed,
667 # they will be added
668 return {
669 files => \@files,
670 links => \@links,
671 dirs => \@dirs,
672 others => \@others
673 };
674}
675
676#####################################################################
677#
678# functions
679
680sub help(;@)
681{
682 if ( @_ == 0 ) {
683 usage();
684 } else {
685 print "help for @_: ...\n";
686 usage();
687 }
688}
689
690sub login(@)
691{
692 check_parameter( @_, 1 );
693 check_env();
694
695 my $input_username = $_[0];
696
697 if ( not $input_username ) {
698 my $output_username = "";
699 if ($DASSCM_USERNAME) {
700 $output_username = " ($DASSCM_USERNAME)";
701 }
702
703 print "Enter DASSCM user name", $output_username, ": ";
704 $input_username = <STDIN>;
705 chomp($input_username);
706
707 $input_username = $input_username || $DASSCM_USERNAME;
708 }
709
710 # hidden password input
711 print "Enter password for $input_username: ";
712 ReadMode('noecho');
713 my $input_password = <STDIN>;
714 ReadMode('normal');
715 chomp($input_password);
716 print "\n";
717
718 # checking checkout username/password
719 svn_check_credentials( $DASSCM_CHECKOUT_USERNAME,
720 $DASSCM_CHECKOUT_PASSWORD );
721 print "checkout access okay\n";
722
723 svn_check_credentials( $input_username, $input_password );
724
725 #
726 # set environment variables
727 #
728 $ENV{'DASSCM_USERNAME'} = "$input_username";
729 $ENV{'DASSCM_PASSWORD'} = "$input_password";
730
731 print "subversion access okay\n\n", "DASSCM_USERNAME: $input_username\n",
732 "DASSCM_PASSWORD: (hidden)\n", "DASSCM_PROD: $DASSCM_PROD\n",
733 "DASSCM_REPO: $DASSCM_REPO\n",
734 "Server Repository: $DASSCM_SVN_REPOSITORY\n", "\n", "[dasscm shell]\n\n";
735
736 my $shell = $SHELL || "bash";
737 exec($shell) or die "failed to start new shell";
738}
739
740#
741# initialize local checkout directory (initial checkout)
742#
743sub init(@)
744{
745 check_parameter( @_, 1 );
746 check_env();
747
748 # don't do repository creation (svn mkdir) here,
749 # because then their must be a lot of prior checks
750
751 # update complete repository
752 # and create permission file
753 my $retcode =
754 run_interactive(
755 "cd $DASSCM_LOCAL_REPOSITORY_BASE; $SVN checkout $svnCheckoutCredentials $svnOptions $DASSCM_SVN_REPOSITORY; mkdir -p `dirname $permissions_file`; touch $permissions_file"
756 );
757}
758
759sub ls(@)
760{
761 check_parameter( @_, 1 );
762 check_env();
763
764 my @files = svn_ls(@_);
765
766 if (@files) {
767 print join( "\n", @files );
768 print "\n";
769 }
770}
771
772sub update(@)
773{
774 check_parameter( @_, 1 );
775 check_env();
776
777 #
778 # update local repository
779 #
780 svn_update();
781}
782
783#
784# helper function for "add" command
785#
786sub add_helper(@)
787{
788 (
789 my $basename,
790 my $dirname_prod,
791 my $dirname_repo,
792 my $filename_prod,
793 my $filename_repo
794 )
795 = get_filenames( $_[0] );
796
797 mkpath($dirname_repo);
798
799 # TODO: are permissions also copied?
800 copy( $filename_prod, $filename_repo )
801 or error "failed to copy $filename_prod to repository: $!";
802
803 # already checked in?
804 chdir $DASSCM_REPO;
805
806 # also add the path to filename.
807 for my $dir ( split( '/', $dirname_prod ) ) {
808 if ($dir) {
809 my ( $rc, @out ) = run_command("$SVN add --non-recursive '$dir'");
810 if ( $rc > 0 ) {
811 print join( "\n", @out );
812 }
813 chdir $dir;
814 }
815 }
816 my ( $rc, @out ) = run_command("$SVN add '$basename'");
817 if ( $rc > 0 ) {
818 print join( "\n", @out );
819 }
820 chdir $StartDirectory;
821
822}
823
824#
825# adding new files (or directories)
826#
827sub add(@)
828{
829 check_parameter( @_, 1 );
830 check_env();
831
832 #
833 # update local repository
834 #
835 svn_update();
836
837 # get all regular files and links
838 my $href_files = get_files(@_);
839
840 #print Dumper( $href_files );
841
842 my @files = @{ $href_files->{files} };
843 my @links = @{ $href_files->{links} };
844
845 if (@files) {
846 my $number = $#files + 1;
847 print "files to check-in ($number): \n";
848 print join( "\n", @files );
849 print "\n";
850 }
851
852 # TODO: check in links and also link target? At least warn about link target
853 if (@links) {
854 my $number = $#links + 1;
855 print "\n";
856 print "ignoring links ($number):\n";
857 print join( "\n", @links );
858 print "\n";
859 }
860
861 # TODO: confirm
862
863 # copy files one by one to local repository
864 for my $file (@files) {
865
866 # add file
867 add_helper($file);
868 }
869
870 # create new permissions file
871 permissions();
872
873 # add permissions file
874 add_helper($permissions_file);
875
876 if ( $options{'message'} ) {
877 $svnOptions .= " --message \"$options{'message'}\" ";
878 }
879
880 # commit calls $EDITOR.
881 # use "interactive" here, to display output
882 my $retcode =
883 run_interactive(
884 "$SVN commit $svnOptions --username '$DASSCM_USERNAME' $svnPasswordCredentials $DASSCM_REPO"
885 );
886
887 # svn commit does not deliever an error return code, if commit is canceld,
888 # so a revert is performed in any case
889 svn_revert();
890}
891
892#
893# checks in all modified files
894#
895sub commit(@)
896{
897 check_parameter( @_, 1 );
898 check_env();
899
900 (
901 my $basename,
902 my $dirname_prod,
903 my $dirname_repo,
904 my $filename_prod,
905 my $filename_repo
906 )
907 = get_filenames( $_[0] );
908
909 #
910 # update local repository
911 #
912 svn_update();
913
914 ( my $refChangedFiles, my $refRemovedFiles ) =
915 getModifiedFiles($filename_prod);
916 my %changedfiles = %{$refChangedFiles};
917 my %removedfiles = %{$refRemovedFiles};
918
919 if (%removedfiles) {
920 my $removedFilesString =
921 '"' . join( '" "', values(%removedfiles) ) . '"';
922 my ( $rc, @out ) = run_command("$SVN rm $removedFilesString");
923 if ( $rc > 0 ) {
924 print join( "\n", @out );
925 }
926 }
927
928 # copy files one by one to local repository
929 for my $file ( keys(%changedfiles) ) {
930 copy_file_to_repository($file);
931 }
932
933 # create new permissions file
934 permissions();
935
936 # add permissions file
937 add_helper($permissions_file);
938
939 if ( $options{'message'} ) {
940 $svnOptions .= " --message \"$options{'message'}\" ";
941 }
942
943 # commit calls $EDITOR.
944 # use "interactive" here, to display output
945 my $retcode =
946 run_interactive(
947 "$SVN commit $svnOptions --username '$DASSCM_USERNAME' $svnPasswordCredentials $DASSCM_REPO"
948 );
949
950 # svn commit does not deliever an error return code, if commit is canceld,
951 # so a revert is performed in any case
952 svn_revert();
953}
954
955sub blame(@)
956{
957 check_parameter( @_, 1 );
958 check_env();
959
960 (
961 my $basename,
962 my $dirname_prod,
963 my $dirname_repo,
964 my $filename_prod,
965 my $filename_repo
966 )
967 = get_filenames( $_[0] );
968
969 my $retcode = run_interactive("$SVN blame $svnOptions $filename_repo");
970}
971
972sub diff(@)
973{
974 check_parameter( @_, 1 );
975 check_env();
976
977 (
978 my $basename,
979 my $dirname_prod,
980 my $dirname_repo,
981 my $filename_prod,
982 my $filename_repo
983 )
984 = get_filenames( $_[0] );
985
986 #print "$basename,$dirname_prod,$dirname_repo\n";
987
988 ( my $rc_update, my @result ) = run_command("$SVN update $filename_repo");
989 if ( $rc_update != 0 ) {
990 print @result;
991 die;
992 }
993
994 ( my $rc_diff, my @diff_result ) =
995 run_command( $diff . " $filename_repo $filename_prod" );
996
997 print @diff_result;
998}
999
1000sub status(@)
1001{
1002 check_parameter( @_, 1 );
1003 check_env();
1004
1005 (
1006 my $basename,
1007 my $dirname_prod,
1008 my $dirname_repo,
1009 my $filename_prod,
1010 my $filename_repo
1011 )
1012 = get_filenames( $_[0] || "/" );
1013
1014 # return code for the shell
1015 # default: error
1016 my $return_code = $RETURN_NOK;
1017
1018 #
1019 # update local repository
1020 #
1021 svn_update( $filename_prod );
1022
1023 ( my $refChangedFiles, my $refRemovedFiles ) =
1024 getModifiedFiles($dirname_prod);
1025 my %changedfiles = %{$refChangedFiles};
1026 my %removedfiles = %{$refRemovedFiles};
1027
1028 if ( %removedfiles or %changedfiles ) {
1029 if (%removedfiles) {
1030 print "deleted files (found in repository, but not in system):\n";
1031 foreach my $key ( keys %removedfiles ) {
1032 print "$key\n";
1033 }
1034 print "\n";
1035 }
1036
1037 if (%changedfiles) {
1038 print "modified files:\n";
1039 foreach my $key ( keys %changedfiles ) {
1040 print "$key\n";
1041 }
1042 }
1043 } else {
1044 print "no modified files found in $dirname_repo\n";
1045 $return_code = $RETURN_OK;
1046 }
1047
1048 return $return_code;
1049}
1050
1051#
1052# return short status in Nagios plugin conform way
1053#
1054sub check()
1055{
1056 check_env();
1057
1058 # return code for the shell
1059 # default: error
1060 my $return_code = $RETURN_OK;
1061 my $return_string = "OK: no modified files";
1062
1063 ( my $refChangedFiles, my $refRemovedFiles ) =
1064 getModifiedFiles( "/" );
1065 my %changedfiles = %{$refChangedFiles};
1066 my %removedfiles = %{$refRemovedFiles};
1067
1068 if ( %removedfiles or %changedfiles ) {
1069 $return_string = "Warning: ";
1070 if( %changedfiles ) {
1071 $return_string .= "changed: " . join( ", ", ( keys %changedfiles ) ) . ". ";
1072 }
1073 if( %removedfiles ) {
1074 $return_string .= "removed: " . join( ", ", ( keys %removedfiles ) ) . ". ";
1075 }
1076 $return_code = $RETURN_WARN;
1077 }
1078
1079 # addition nagios Service Status
1080 #Critical
1081 #Unknown
1082
1083 print $return_string . "\n";
1084 return $return_code;
1085}
1086
1087
1088sub permissions()
1089{
1090 check_env();
1091
1092 #
1093 # update local repository
1094 #
1095 #svn_update();
1096
1097 my $dir = $DASSCM_REPO;
1098 my @files = svn_ls("/");
1099
1100 if (@files) {
1101
1102 # generieren der Permissions
1103 my @permissions = generatePermissionList(@files);
1104 my $OUTFILE;
1105 my $tofile = 0; # Status für schreiben in File
1106
1107 if ( -w dirname($permissions_file) ) {
1108
1109 # Verzeichnis existiert => schreiben
1110 print "storing permissions in file $permissions_file\n";
1111 open( OUTFILE, ">$permissions_file" )
1112 || die("failed to write to $permissions_file: $!");
1113 $tofile = 1; # Merken, daß in File geschrieben wird
1114 print OUTFILE "#\n";
1115 print OUTFILE "# created by dasscm permissions\n";
1116 print OUTFILE
1117 "# It is intended to be used for restoring permissions\n";
1118 } else {
1119
1120 # Pfad für Sicherungsdatei existiert nicht => schreiben auf stdout
1121 # Alias Filehandle für stdout erzeugen
1122 *OUTFILE = *STDOUT;
1123 }
1124 foreach my $line (@permissions) {
1125 print OUTFILE "$line\n";
1126 }
1127
1128 if ($tofile) {
1129 close(OUTFILE);
1130 }
1131 }
1132}
1133
1134#
1135# remove all uncommited changes in the repository
1136#
1137sub cleanup()
1138{
1139 check_env();
1140
1141 svn_revert($DASSCM_REPO);
1142}
1143
1144#####################################################################
1145#
1146# main
1147#
1148
1149my $return_code = $RETURN_OK;
1150my $number_arguments = @ARGV;
1151
1152if ( $number_arguments > 0 ) {
1153
1154 # get subcommand and remove it from @ARGV
1155 $command = $ARGV[0];
1156 shift @ARGV;
1157
1158 $DASSCM_LOCAL_REPOSITORY_BASE = $config->{'DASSCM_LOCAL_REPOSITORY_BASE'};
1159 $DASSCM_REPOSITORY_NAME = $config->{'DASSCM_REPOSITORY_NAME'};
1160
1161 # TODO: check variables
1162 $DASSCM_SVN_REPOSITORY =
1163 $config->{'DASSCM_SVN_REPOSITORY_BASE'} . "/" . $DASSCM_REPOSITORY_NAME;
1164
1165 $DASSCM_CHECKOUT_USERNAME = $config->{'DASSCM_CHECKOUT_USERNAME'};
1166 $DASSCM_CHECKOUT_PASSWORD = $config->{'DASSCM_CHECKOUT_PASSWORD'};
1167
1168 #
1169 # if a user is given by dasscm configuration file, we use it.
1170 # Otherwise we expect that read-only account is configured
1171 # as local subversion configuration.
1172 # If this is also not the case,
1173 # user is required to type username and password.
1174 # This will be stored as local subversion configuration thereafter.
1175 #
1176 if ( $DASSCM_CHECKOUT_USERNAME && $DASSCM_CHECKOUT_PASSWORD ) {
1177 $svnCheckoutCredentials =
1178 " --username $DASSCM_CHECKOUT_USERNAME --password $DASSCM_CHECKOUT_PASSWORD ";
1179 }
1180
1181 # get command line options and store them in options hash
1182 my $result = GetOptions( \%options, 'verbose', 'message=s' );
1183
1184 # print options
1185 foreach my $option ( keys %options ) {
1186 print "${option}: $options{$option}\n";
1187 }
1188
1189 # set verbose to command line option
1190 $verbose = $options{'verbose'};
1191
1192 #
1193 # action accordinly to command are taken
1194 # $command is rewritten in standard format,
1195 # so we can test for it later on more simply
1196 #
1197 $_ = $command;
1198 if (m/^help$/i) {
1199 help(@ARGV);
1200 } elsif (m/^login$/i) {
1201 $command = "login";
1202 login(@ARGV);
1203 } elsif (m/^init$/i) {
1204 $command = "init";
1205 init(@ARGV);
1206 } elsif (m/^ls$/i) {
1207 $command = "ls";
1208 ls(@ARGV);
1209 } elsif ( (m/^update$/i) || (m/^up$/i) ) {
1210 $command = "update";
1211 update(@ARGV);
1212 } elsif (m/^add$/i) {
1213 $command = "add";
1214 add(@ARGV);
1215 } elsif ( (m/^commit$/i) || (m/^checkin$/i) || (m/^ci$/i) ) {
1216 $command = "commit";
1217 commit(@ARGV);
1218 } elsif (m/^blame$/i) {
1219 $command = "blame";
1220 blame(@ARGV);
1221 } elsif (m/^diff$/i) {
1222 $command = "diff";
1223 diff(@ARGV);
1224 } elsif ( (m/^status$/i) || (m/^st$/i) ) {
1225 $command = "status";
1226 $return_code = status(@ARGV);
1227 } elsif (m/^check$/i) {
1228 $command = "check";
1229 $return_code = check();
1230 } elsif (m/^permissions$/i) {
1231 $command = "permissions";
1232 permissions();
1233 } elsif (m/^cleanup$/i) {
1234 $command = "cleanup";
1235 cleanup();
1236 } else {
1237 print "unknown command: $command\n\n";
1238 usage();
1239 check_env();
1240 $return_code = $RETURN_NOK;
1241 }
1242
1243 # revert
1244
1245}
1246
1247exit $return_code;
Note: See TracBrowser for help on using the repository browser.