#!/usr/bin/perl -w # $Id: dasscm 205 2007-07-02 15:15:47Z joergs $ use strict; use Env qw($DASSCM_PROD $DASSCM_REPO $USER $DASSCM_USERNAME $DASSCM_USER $DASSCM_PASSWORD); use Cwd; use Term::ReadKey; use File::Basename; use File::stat; use File::Path; use File::Copy; use Getopt::Long; # # used ConfigFile instead of SmartClient::Config, # because the huge amount of SmartClient dependencies #use SmartClient::Config; use ConfigFile; ##################################################################### # # global # my $config_file = "/etc/dasscm.conf"; # my $config = SmartClient::Config->( $config_file ); my $config = ConfigFile::read_config_file($config_file); my $DASSCM_LOCAL_REPOSITORY_BASE; my $DASSCM_REPOSITORY_NAME; my $DASSCM_SVN_REPOSITORY; my $SVN = "svn "; my $svnOptions = ""; my $svnCheckoutCredentials = ""; my $svnPasswordCredentials = ""; # command line options get stored in options hash my %options = (); # subcommand, that gets executed (add, commit, ...) my $command; my $verbose = 0; ##################################################################### # # util functions # sub usage() { print "usage: dasscm [options] [args]\n"; print "\n"; print "dasscm is intended to help versioning configuration files\n"; print "\n"; print "Available subcommands:\n"; print " init\n"; print " login\n"; print " add \n"; print " commit \n"; print " diff \n"; print " help \n"; print "\n"; print "preperation:\n"; print "check out the configuration repository, e.g.\n"; print "svn checkout --no-auth-cache --username USERNAME https://dass-it.de/svn/dasscm/HOSTNAME\n"; print "environment variables\n", " DASSCM_REPO\n", " DASSCM_PROD¸n", " DASSCM_USERNAME\n", " DASSCM_PASSWORD\n", "are evaluated.\n"; print "\n"; } sub check_env() { # DASSCM_PROD if ( !$DASSCM_PROD ) { $DASSCM_PROD = "/"; } if ( !-d $DASSCM_PROD ) { die "DASSCM_PROD ($DASSCM_PROD) is not set to a directory.\n"; } if ($verbose) { print "DASSCM_PROD: " . $DASSCM_PROD . "\n"; } # DASSCM_REPOSITORY_NAME if ( !$DASSCM_REPOSITORY_NAME ) { die "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"; } # DASSCM_REPO if ( !$DASSCM_REPO ) { if ( $DASSCM_LOCAL_REPOSITORY_BASE && $DASSCM_REPOSITORY_NAME ) { $DASSCM_REPO = $DASSCM_LOCAL_REPOSITORY_BASE . "/" . $DASSCM_REPOSITORY_NAME; } else { die "Envirnonment variable DASSCM_REPO not set.\nSet DASSCM_REPO to the directory of the versioning system checkout for this machine.\n"; } } print "DASSCM_REPO: " . $DASSCM_REPO . "\n"; # # check if local repository directory exist (if not creating by init) # if ( $command ne "init" ) { if ( not -d $DASSCM_REPO ) { die "Can't access local repository DASSCM_REPO\n($DASSCM_REPO)\nCheck configuration and execute\n dasscm init\n"; } # # user settings # # DASSCM_USER is legacy. Use DASSCM_USERNAME instead if( !$DASSCM_USERNAME ) { $DASSCM_USERNAME=$DASSCM_USER; } # user root is not allowed for checkins. # if user is root, DASSCM_USER has to be set, # otherwise USER can be used if ( "$USER" eq "root" ) { if (( not $DASSCM_USERNAME ) and ( $command ne "login" )) { die "Envirnonment variable DASSCM_USERNAME not set.\nSet DASSCM_USERNAME to your subversion user account.\n"; } $svnOptions .= " --no-auth-cache "; } elsif ( !$DASSCM_USERNAME ) { $DASSCM_USERNAME = $USER; } # # password # if( $DASSCM_PASSWORD ) { $svnPasswordCredentials = " --password $DASSCM_PASSWORD "; } } #$svnOptions .= " --username $DASSCM_USERNAME " } sub check_parameter(@) { } sub get_filenames(@) { my $filename_prod = $_[0]; if ( !( $filename_prod =~ m/^\// ) ) { $filename_prod = cwd() . "/" . $filename_prod; } -r $filename_prod or die "$filename_prod is not accessable"; # TODO: dirname buggy: eg. "/etc/" is reduced to "/", # "/etc" is used as filename my $dirname_prod = dirname($filename_prod); chdir $dirname_prod or die $!; $dirname_prod = cwd(); my $basename = basename($filename_prod); print "dir: " . $dirname_prod . "\n"; print "fn: " . $basename . "\n"; my $dirname_repo = $DASSCM_REPO . "/" . $dirname_prod; my $filename_repo = "$dirname_repo/$basename"; return ( $basename, $dirname_prod, $dirname_repo, $filename_prod, $filename_repo ); } sub run_command { my $command = shift; #print "executing command: " . $command . "\n"; open( RESULT, $command . ' 2>&1 |' ); my @result = ; close(RESULT); my $retcode = $? >> 8; #print @result; #if( $retcode ) { print "return code: " . $retcode . "\n"; } return ( $retcode, @result ); } sub run_interactive { if( $verbose ) { print "run_interactive:" . join( " ", @_ ) . "\n"; } system(@_); if ( $? == -1 ) { printf "failed to execute: $!\n"; } elsif ( $? & 127 ) { printf "child died with signal %d, %s coredump\n", ( $? & 127 ), ( $? & 128 ) ? 'with' : 'without'; } elsif ( $? >> 8 != 0 ) { printf "child exited with value %d\n", $? >> 8; } return ( $? >> 8 ); } sub svn_check_credentials( $$ ) { my $username = shift; my $password = shift; ( my $rc_update, my @result ) = run_command( "$SVN info --non-interactive --no-auth-cache --username $username --password $password $DASSCM_SVN_REPOSITORY" ); print @result; if ( $rc_update != 0 ) { print @result; die; } } sub svn_update( ;$ ) { my $update_path = shift || $DASSCM_REPO; ( my $rc_update, my @result ) = run_command("$SVN update $svnCheckoutCredentials $update_path"); if ( $rc_update != 0 ) { print @result; die; } print @result; } ##################################################################### # # functions sub help(;@) { if ( @_ == 0 ) { usage(); } else { print "help for @_: ...\n"; } } sub login(@) { check_parameter( @_, 1 ); check_env(); my $output_username = ""; if ($DASSCM_USERNAME) { $output_username = " ($DASSCM_USERNAME)"; } print "Enter DASSCM user name", $output_username, ": "; my $input_username = ; chomp($input_username); # hidden password input print "Enter DASSCM user password: "; ReadMode('noecho'); my $input_password = ; ReadMode('normal'); chomp($input_password); svn_check_credentials( $input_username, $input_password ); # # set environment variables # $ENV{'DASSCM_USERNAME'} = $input_username; $ENV{'DASSCM_PASSWORD'} = $input_password; # TODO: print environment exec("bash") or die "can't login"; } sub init(@) { check_parameter( @_, 1 ); check_env(); # update complete repository my $retcode = run_interactive("cd $DASSCM_LOCAL_REPOSITORY_BASE; $SVN checkout $svnCheckoutCredentials $svnOptions $DASSCM_SVN_REPOSITORY"); } # # add (is used for command add and commit) # sub add(@) { check_parameter( @_, 1 ); check_env(); ( my $basename, my $dirname_prod, my $dirname_repo, my $filename_prod, my $filename_repo ) = get_filenames( $_[0] ); if ( $command eq "add" ) { mkpath($dirname_repo); } # update complete repository my $retcode = run_interactive("$SVN update $svnOptions $DASSCM_REPO"); copy( $filename_prod, $filename_repo ) or die $!; if ( $command eq "add" ) { # already checked in? chdir($DASSCM_REPO); # also add the path to filename. for my $dir ( split( '/', $dirname_prod ) ) { if ($dir) { run_command("$SVN add --non-recursive $dir"); chdir $dir; } } run_command("$SVN add $basename"); } if ( $options{'message'} ) { $svnOptions .= " --message \"$options{'message'}\" "; } # commit calls $EDITOR. uses "interactive" here, to display output $retcode = run_interactive( "$SVN commit $svnOptions --username $DASSCM_USERNAME $svnPasswordCredentials $DASSCM_REPO"); print $filename_prod. "\n"; print $dirname_repo. "\n"; } sub blame(@) { check_parameter( @_, 1 ); check_env(); ( my $basename, my $dirname_prod, my $dirname_repo, my $filename_prod, my $filename_repo ) = get_filenames( $_[0] ); my $retcode = run_interactive("$SVN blame $svnOptions $filename_repo"); } sub diff(@) { check_parameter( @_, 1 ); check_env(); ( my $basename, my $dirname_prod, my $dirname_repo, my $filename_prod, my $filename_repo ) = get_filenames( $_[0] ); #print "$basename,$dirname_prod,$dirname_repo\n"; ( my $rc_update, my @result ) = run_command("$SVN update $filename_repo"); if ( $rc_update != 0 ) { print @result; die; } ( my $rc_diff, my @diff ) = run_command("diff $filename_repo $filename_prod"); print @diff; } ##################################################################### # # main # my $number_arguments = @ARGV; if ( $number_arguments > 0 ) { # get subcommand and remove it from @ARGV $command = $ARGV[0]; shift @ARGV; $DASSCM_LOCAL_REPOSITORY_BASE = $config->{'DASSCM_LOCAL_REPOSITORY_BASE'}; $DASSCM_REPOSITORY_NAME = $config->{'DASSCM_REPOSITORY_NAME'}; # TODO: check variables $DASSCM_SVN_REPOSITORY = $config->{'DASSCM_SVN_REPOSITORY_BASE'} . "/" . $DASSCM_REPOSITORY_NAME; my $DASSCM_CHECKOUT_USERNAME = $config->{'DASSCM_CHECKOUT_USERNAME'}; my $DASSCM_CHECKOUT_PASSWORD = $config->{'DASSCM_CHECKOUT_PASSWORD'}; # # if a user is given by dasscm configuration file, we use it. # Otherwise we expect that read-only account is configured # as local subversion configuration. # If this is also not the case, # user is required to type username and password. # This will be stored as local subversion configuration thereafter. # if ( $DASSCM_CHECKOUT_USERNAME && $DASSCM_CHECKOUT_PASSWORD ) { $svnCheckoutCredentials = " --username $DASSCM_CHECKOUT_USERNAME --password $DASSCM_CHECKOUT_PASSWORD "; } # get command line options and store them in options hash my $result = GetOptions( \%options, 'message=s' ); # print options foreach my $option ( keys %options ) { print $option. ": " . $options{$option} . "\n"; } $_ = $command; if (m/help/i) { help(@ARGV); } elsif (m/login/i) { $command ="login"; login(@ARGV); } elsif (m/init/i) { $command ="init"; init(@ARGV); } elsif (m/add/i) { ## rewrite command $command = "add"; add(@ARGV); } elsif (m/commit/i) { $command = "commit"; add(@ARGV); } elsif (m/blame/i) { $command ="blame"; blame(@ARGV); } elsif (m/diff/i) { $command ="diff"; diff(@ARGV); } elsif (m/activate/i) { ## TODO activate(@ARGV); } else { usage(); check_env(); } # login # up # commitall # revert # status (chkconf) }