source: trunk/dasscm/dasscm@ 270

Last change on this file since 270 was 270, checked in by joergs, on Mar 4, 2009 at 7:58:29 PM

better handling of relative pathnames

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