Hi fella Monks!

I wrote a little semi-useful script to fake CVS import of a working
module.  How is it useful? Well, I found it useful (why else
would I have wasted my time on hacking up that damned script! ;) in cases
when you have an existing CVS repository and a separate working 
directory that has never been a part of that repository (that is,
it was never 'checked out' from it before...) and you wish
to add this directory of yours to the CVS repository in order
to start preserving older versions of whatever you hold in that
directory.

For example, there's a CVS repository located in /web/common/repository on your 'development' server and a working directory /export/home/fooadmin/myscripts in which you hold your perl scripts. Now, in order to allow yourself to preserve older versions of your scripts, you will have to 'import' this working directory into an existing CVS repository. One good old way of doing this would be via 'cvs import' command followed by immediate 'cvs checkout', which wouldn't work unless you 'rm -rf' your original working directory first or checkout into a different location... and if you do choose to remove your working directory in order to replace it with a version in the repository, the checked out version may have certain files that were present in the original working directory missing. This normally occurs if your cvs repository is configured, for example, to exclude binary files, reserved directories/files etc. The latter is a case with many repositories that I had to deal with. It is for this very reason that I chose to write up a script that would be a better alternative to 'cvs import'. This is an initial draft so any comment/suggestion would be appreciated. So, here we go (just copy and paste into a file of your choosing):
#!/usr/local/bin/perl -w # Author: Vladimir Bogdanov (Monk ID: c0d34w4y) # License? I guess GNU would apply. use strict; ######################## ### MAIN ######################## print intro(); my $pwd = `pwd`; chomp($pwd); exit unless (user_prompt("Add working directory '$pwd' to existing CVS + repository? (y/n): ", "[yY]")); unless(exists $ENV{CVSROOT} && length($ENV{CVSROOT})) { $ENV{CVSROOT} = user_ask("\nEnvironment variable CVSROOT is not se +t! What should I set it to?\n CVSROOT: "); check_cvsroot(); } else { print "Will use existing CVSROOT '" . $ENV{CVSROOT} ."'\n"; $ENV{CVSROOT} = user_ask("\nNew CVSROOT: ") unless (user_prompt("C +onfirm if you are OK with it? (y/n): ", "[yY]")); check_cvsroot(); } my $module = user_ask("\nRepository module name for the working direct +ory: "); my $cvs_module_path = "$ENV{CVSROOT}/$module"; my $cvs_dir = "$pwd/CVS"; eval { if (-d $cvs_dir) { print "\nDirectory '$cvs_dir' already exists!\n" ."Which implies that this working directory may belong to + an existing cvs repository."; exit unless user_prompt("\nProceed anyway? (will replace the c +ontents of '$cvs_dir' cvs directory): ", "[yY]"); } unless (-d $cvs_module_path) { print "\nDirectory '$cvs_module_path' doesn't exist! "; mkdir_rec($cvs_module_path) if (user_prompt("Create One? (y/n) +: ", "[yY]")); } print "\nInitializing..."; mkdir_rec($cvs_dir) unless (-d $cvs_dir); open(FOUT, ">$cvs_dir/Repository") or die "can't open '$cvs_dir/Re +pository'"; print FOUT "$module"; close(FOUT); open(FOUT, ">$cvs_dir/Root") or die "can't open '$cvs_dir/Root'"; print FOUT $ENV{CVSROOT}; close(FOUT); touch("$cvs_dir/Entries"); print "\nDone!\n"; }; if ($@) { print "\nFAILED: $@\n"; exit(0); } ######################## ### SUBS ######################## sub check_cvsroot { unless (-d $ENV{CVSROOT}) { print "Directory " . $ENV{CVSROOT} . " doesn't exist!\n"; exit; } } sub user_ask { print $_[0]; my $answer = <STDIN>; chomp($answer); return $answer; } sub user_prompt { my $answer = user_ask($_[0]); return ($answer =~ m/$_[1]/); } #--------------------------------------------------------------------- # mkdir_rec($dir, $mode, $safe) # # safe = 1 - return appropriate numerical code instead of a die. # 0 - die. (default) # sub mkdir_rec { my ($dir, $mode, $safe) = @_; return 0 unless ($dir); # $dir required. return 1 if (-d $dir); # return if already exists my $mode_o = ($mode)?"-m $mode":""; # execute shell comand: use -p to create directories recursively # back tick command should return 0 on failure. system("mkdir -p $dir $mode_o") == 0 or ($safe ? return 0 : die "Failed to create '$dir'."); return 1; } sub touch { my $now = time; local (*TMP); foreach my $file (@_) { utime ($now, $now, $file) || open (TMP, ">>$file") || die ("Couldn't touch file: $!\n"); } } sub intro { return <DATA>; } __DATA__ #----------------------------------------------------------------- # A CVS IMPORT like Utility # # Associates your current directory with an existing CVS # repository. Similar to what a 'cvs import' command would do. # # by Vladimir Bogdanov (email: user=b_vlad server=telus.net, Perl Monk + ID: c0d34w4y) #-----------------------------------------------------------------


--
print join(" ", map { sprintf "%#02x", $_ }unpack("C*",pack("L",0x1234 +5678)))

Replies are listed 'Best First'.
Re: Fake CVS import with Perl.
by vladb (Vicar) on Dec 18, 2001 at 03:37 UTC
    I've tested this script a bit more and discovered that cvs wouldn't work correctly if sub directories are not imported as well. Say, if I used the script on
    /usr/export/home/vladb/libs

    and than did

    > cd /usr/export/home/vladb/foo/bar > cvs -n update

    CVS would fail due to a missing CVS directory inside foo/bar.

    This slightly improved code should take care of this:

    #!/usr/local/bin/perl -w use strict; use Getopt::Std; ######################## ### MAIN ######################## print intro(); my %opts; getopts("rfnvd:m:", \%opts); $opts{$_} = exists($opts{$_}) for qw(r f n v); my $pwd = `pwd`; chomp($pwd); exit unless ($opts{f} || user_prompt("Add working directory '$pwd' to +existing CVS repository? (y/n): ", "[yY]")); # set CVSROOT if (exists $opts{d}) { $ENV{CVSROOT} = $opts{d}; print "CVSROOT set to '$ENV{CVSROOT}'\n"; } elsif (!(exists $ENV{CVSROOT} && length($ENV{CVSROOT}))) { $ENV{CVSROOT} = user_ask("\nEnvironment variable CVSROOT is not se +t! What should I set it to?\n CVSROOT: "); check_cvsroot(); } else { print "Will use existing CVSROOT '" . $ENV{CVSROOT} ."'\n"; $ENV{CVSROOT} = user_ask("\nNew CVSROOT: ") unless ($opts{f} || us +er_prompt("Confirm if you are OK with it? (y/n): ", "[yY]")); check_cvsroot(); } my $cvs_repository = (exists $opts{m}) ? $opts{m} : user_ask("\nRepository module name for the working directory: "); my $cvs_dir = "$pwd/CVS"; # check top CVS directory to ensure that user doesn't re-initialize # a working directory that may already belong to a cvs repository. if (!$opts{f} && -d $cvs_dir) { print "\nDirectory '$cvs_dir' already exists!\n" ."Which implies that this working directory may already belon +g to an existing cvs repository."; exit unless user_prompt("\nProceed anyway? (will replace the conte +nts of '$cvs_dir' cvs directory): ", "[yY]"); } eval { print "Initializing...\n"; my @modules = (""); if ($opts{r}) { # will have to create a CVS directory in each sub # directory (similar to what a cvs -import would do) print "[retreaving sub directories:\n"; push @modules, @{get_child_modules($pwd, "CVS")}; print "]\n\n"; } cvs_init_module({ cvs_root => $ENV{CVSROOT}, repository => $cvs_repository, working_root => $pwd, modules => \@modules, safe => $opts{n}, verbose => $opts{v} }); print "\nCompleted successfully!\n"; }; if ($@) { print "\nFAILED: $@\n"; exit(0); } exit; ######################## ### SUBS ######################## sub check_cvsroot { unless (-d $ENV{CVSROOT}) { print "Directory " . $ENV{CVSROOT} . " doesn't exist!\n"; exit; } } sub user_ask { print $_[0]; my $answer = <STDIN>; chomp($answer); return $answer; } sub user_prompt { my $answer = user_ask($_[0]); return ($answer =~ m/$_[1]/); } #--------------------------------------------------------------------- # mkdir_rec($dir, $mode, $safe) # # safe = 1 - return appropriate numerical code instead of a die. # 0 - die. (default) # sub mkdir_rec { my ($dir, $mode, $safe) = @_; return 0 unless ($dir); # $dir required. return 1 if (-d $dir); # return if already exists my $mode_o = ($mode)?"-m $mode":""; # execute shell comand: use -p to create directories recursively # back tick command should return 0 on failure. system("mkdir -p $dir $mode_o") == 0 or ($safe ? return 0 : die "Failed to create '$dir'."); return 1; } sub touch { my $now = time; local (*TMP); foreach my $file (@_) { utime ($now, $now, $file) || open (TMP, ">>$file") || die ("Couldn't touch file: $!\n"); } } sub get_child_modules { my ($start_path, $skip_match) = @_; # i'm not particularly happy with this since diagnostic # output of system call enclosed in `` will end up in # STDOUT my @dirs = grep !/^$|$skip_match/, map {s/^\.[\/]*//; chomp; "$_"; +} (`cd $start_path; find . -type d`); return \@dirs; } sub cvs_init_module { my $hargs = $_[0]; return unless (exists $$hargs{cvs_root} && exists $$hargs{working_root}); my $verbose = $$hargs{verbose} || 0; my @modules = @{$$hargs{modules}}; my $cvs_root = $$hargs{cvs_root}; my $working_root = $$hargs{working_root}; my $repository = $$hargs{repository}; my $safe = $$hargs{safe}; my ($cvs_module, $cvs_dir); print "\tREPOSITORY -> WORKING DIRECTORY\n" if ($verbose); my %failed_modules; for (@modules) { my $cvs_module = "$cvs_root/$repository/$_"; clean_path($cvs_module); my $cvs_dir = "$working_root/$_/CVS"; clean_path($cvs_dir); print "\t$cvs_module -> $cvs_dir\n" if ($verbose); unless ($safe) { eval { mkdir_rec($cvs_module); mkdir_rec($cvs_dir); }; if ($@) { $failed_modules{$_} = $@; next; } open(FOUT, ">$cvs_dir/Repository") or die "can't open '$cv +s_dir/Repository'"; print FOUT "$repository"; close(FOUT); open(FOUT, ">$cvs_dir/Root") or die "can't open '$cvs_dir/ +Root'"; print FOUT $ENV{CVSROOT}; close(FOUT); touch("$cvs_dir/Entries"); } } if ($verbose) { print "\nFAILED ON:\n\tDIRECTORY ->\tREASON:\n"; print "\t$_ ->\t". $failed_modules{$_} ."\n" foreach (keys %fa +iled_modules); } } # clean a directory path of extraneous '/' sub clean_path { for (my $i = 0; $i <= $#_; $i++) { # match two or more '/' between a pair of # other non '/' chars and replace the # multiple occurance of '/' with a single '/'. $_[$i] =~ s|([^/])[/]{2,}([^/])|$1/$2|g; # remove trailing garbage such as '/'... $_[$i] =~ s|[/\n\t\s]+$|| } } sub intro { return <DATA>; } __DATA__ #--------------------------------------------------------------------- +--------- # CVSINIT Utility # # Associates your current directory with an existing CVS # repository. # # USAGE: cvsinit [-rfmv] [-d [cvs root]] # [-m [new cvs module name for current working +directory]] # # # OPTIONS: # -r = initialize recursively # (will create a CVS directory in each of the given # working directory's sub directories) # # -f = don't prompt excessively # # -n = do not execute anything that will change the disk. # # -v = verbose # # comments? # contact: Vladimir Bogdanov (b_vlad@telus.net, Perl Monk ID: vladb) #--------------------------------------------------------------------- +---------