package VCP::Utils::cvs ; =head1 NAME VCP::Utils::cvs - utilities for dealing with the cvs command =head1 SYNOPSIS use VCP::Utils::cvs ; =head1 DESCRIPTION A mix-in class providing methods shared by VCP::Source::cvs and VCP::Dest::cvs, mostly wrappers for calling the cvs command. =for test_scripts t/90revml2cvs.t t/91cvs2revml.t =cut @EXPORT_OK = qw( RCS_check_tag RCS_underscorify_tag ); @ISA = qw( Exporter ); use Exporter; use strict ; use Carp ; use VCP::Debug qw( debug debugging ) ; use VCP::Utils qw( empty ); use File::Spec ; use File::Temp qw( mktemp ) ; use POSIX ":sys_wait_h" ; =head1 METHODS =over =item cvs Calls the cvs command with the appropriate cvsroot option. =cut sub cvs { my $self = shift ; my $args = shift ; unshift @$args, "-d" . $self->cvsroot if defined $self->repo_server; return $self->run_safely( [ qw( cvs -Q -z9 ), @$args ], @_ ) ; } =item parse_cvs_repo_spec This handles ":pserver:"-like type repository specs specially, defaulting to normal processing if the scheme is not followed by something like "foo". The username and password are parsed out of the spec If the first colon is followed by a colon, like cvs::pserver:user@server/foo:bar , then the special processing kicks in and the spec is parsed accordingly. Everything up to and including the first colon and starting with the last colon are stripped, just like with L<normal specs|VCP::Plugin/parse_repo_spec>, and the remainder becomes the CVSROOT. This does have the side effect of plaintexting the password in various CVS places (like the local CVS directories and the command lines that VCP forks to launch CVS). Let me know if you need this changed. =cut sub parse_cvs_repo_spec { my $self = shift; my ( $spec ) = @_; unless ( $spec =~ /\A\w+::/ ) { $self->parse_repo_spec( @_ ) unless $spec =~ /\A\w+::/; } else { my ( $scheme, $cvs_root, $filespec ) = ( $spec =~ /\A([^:]*):(.*):([^:]*)\z/ ) or die "Can't parse CVS remote file spec '$spec'\n"; $self->repo_scheme( $scheme ); $self->repo_server( $cvs_root ); $self->repo_filespec( $filespec ); } my $filespec = $self->repo_filespec; $filespec =~ s(/{2,})(/)g; $filespec =~ s(\\{2,})(\\)g; $self->repo_filespec( $filespec ); debug "vcp: parsed '$spec' as", " scheme=", $self->repo_scheme, " server=", $self->repo_server, " filespec=", $self->repo_filespec if debugging $self; die "parse_cvs_repo_spec does not return a result" if defined wantarray; } =item cvsroot Returns the specced cvsroot if set, or $ENV{CVSROOT} if not. While $ENV{CVSROOT} must be an absolute path if it's local (to be completely consistent with the cvs command), the path repo_server value, if set, may be relative (unless it begins with a ':', which indicates a non-local path). =cut my $base_cwd; sub cvsroot { my VCP::Utils::cvs $self = shift; my $root = $self->repo_server; ( ! empty $root ) ? substr( $root, 0, 1 ) eq ":" ? $root ## Remote repo : do { unless ( defined $base_cwd ) { require Cwd; $base_cwd = Cwd::cwd; } File::Spec->rel2abs( $root, $base_cwd ) ## local repo. } : $ENV{CVSROOT}; } =item create_cvs_workspace $self->create_cvs_workspace; $self->create_cvs_workspace( create_in_repository => 1 ); Creates a temp dir named "co" for C<cvs> to work in, checks out the module there, and sets the work root and cvs working dir to that directory. =cut sub create_cvs_workspace { my $self = shift ; my %options = @_; confess "Can't create_workspace twice" if $self->revs->get ; ## establish_workspace in a directory named "co" for "checkout". This is ## so that VCP::Source::cvs can use a different directory to contain ## the revs, since all the revs need to be kept around until the VCP::Dest ## is through with them. $self->command_chdir( $self->tmp_dir( "co" ) ) ; my $module = $self->repo_filespec; die "Empty cvs module spec\n" if empty $module ; $module =~ s{[\\/]+[^\\/]*(?:\.\.\.|[*\\?[].*)}{}; ## if the server contains a username we must log in if ( ( $self->repo_server || "" ) =~ /^:[^:]+:[^:]*(?::([^:]*))?\@/ ) { my $password = defined $1 ? $1 : ""; $self->cvs( ["login"], \$password ); } my @expect_cannot_find_module = ( stderr_filter => qr/cvs checkout: cannot find module .*\n/, ok_result_codes => [0,1], ); $self->cvs( [ "checkout", $module ], { $options{create_in_repository} ? @expect_cannot_find_module : ( ok_result_codes => [0], ## Shouldn't be needed, but Just In Case ), } ) ; if ( $self->command_result_code == 1 ) { my $empty_dir = $self->tmp_dir( "empty_dir" ); $self->mkdir( $empty_dir ); $self->cvs( [ "import", "-m", "VCP destination directory creation", $module, "vcp", "start" ] ); $self->cvs( [ "checkout", $module ] ) ; } $self->work_root( $self->tmp_dir( "co" ) ) ; } =item RCS_check_tag RCS_check_tag $tag1, ...; Checks a list of tags for legality, die()s if it's not legal. Named after the corresponding routine in CVS's rcs.c source file. No clue how this interacts with your locale. =cut sub RCS_check_tag { my @errors; for ( @_ ) { if ( /\A[^a-zA-Z]/ ) { push @errors, "vcp: RCS tag '$_' must start with a letter\n"; } elsif ( /([[:^graph:]])/ ) { push @errors, sprintf "vcp: RCS tag '%s' must not contain \\0x%02x\n", $_, ord $1; } elsif ( /(["\$,.:;\@])/ ) { push @errors, "vcp: RCS tag '$_' must not contain '$1'\n" } } die @errors if @errors; } =item RCS_underscorify_tag @tags = RCS_check_tag $tag1, ...; Modifies a list of tags, replacing illegal characters with underscores. This may lead to tag collisions, but it should be ok for most uses. Converts something like "a@" to "a_AF_". Not a guaranteed solution, but good enough for now. =cut sub RCS_underscorify_tag { my @out = @_; for ( @out ) { s/(["\$,.:;\@[:^graph:]])/sprintf( "_%02x_", ord $1 )/ge; s/\A([^a-zA-Z])/tag_$1/; } wantarray ? @out : @out > 1 ? Carp::confess "Returning multiple tags in scalar context" : $out[0]; } =back =head1 COPYRIGHT Copyright 2000, Perforce Software, Inc. All Rights Reserved. This module and the VCP package are licensed according to the terms given in the file LICENSE accompanying this distribution, a copy of which is included in L<vcp>. =cut 1 ;
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#31 | 5081 | Barrie Slaymaker |
- VCP::Utils::cvs only tries cvs login if :pserver: and password field is missing. |
||
#30 | 5080 | Barrie Slaymaker | - Don't try to log in to cvs when using :ext: in CVSROOT | ||
#29 | 4227 | Barrie Slaymaker |
- VCP::Dest::cvs now handles a module name with no trailing "/..." (reported by Alexandros Karypidis karypid inf uth gr). - VCP::Dest::cvs now handles a missing filespec (module name) if the source repository passed along a rev_root |
||
#28 | 4209 | Barrie Slaymaker |
- CVS workspace creation announces cvs subcommands consistently with other parts of VCP |
||
#27 | 4207 | Barrie Slaymaker |
- The cvs login command is now run with STDERR unredirected to allow the user to log in. - The cvs workspace setup process prints what it's doing before running possibly long-lived cvs commands |
||
#26 | 4151 | Barrie Slaymaker | - dist/vcp.exe now works again | ||
#25 | 4021 | Barrie Slaymaker |
- Remove all phashes and all base & fields pragmas - Work around SWASHGET error |
||
#24 | 3970 | Barrie Slaymaker |
- VCP::Source handles rev queing, uses disk to reduce RAM - Lots of other fixes |
||
#23 | 3571 | Barrie Slaymaker | - Get working with cvs-11.5 on Win2k | ||
#22 | 3532 | John Fetkovich |
changed File::Spec->rel2abs( blah, start_dir ) to start_dir_rel2abs blah everywhere. which does the same thing and is defined in VCP::Utils |
||
#21 | 3384 | John Fetkovich | moved setting of default repo_id | ||
#20 | 3285 | John Fetkovich |
In 'sub new' constructor, Only call parse_cvs_repo_spec if a $spec is provided. parse_cvs_repo_spec also now sets repo_id. |
||
#19 | 3167 | Barrie Slaymaker |
Add profiling report that details various chunks of time taken. |
||
#18 | 3155 | Barrie Slaymaker |
Convert to logging using VCP::Logger to reduce stdout/err spew. Simplify & speed up debugging quite a bit. Provide more verbose information in logs. Print to STDERR progress reports to keep users from wondering what's going on. Breaks test; halfway through upgrading run3() to an inline function for speed and for VCP specific features. |
||
#17 | 3129 | Barrie Slaymaker |
Stop calling the slow Cwd::cwd so much, use start_dir instead. |
||
#16 | 2933 | John Fetkovich | Added calls to empty() | ||
#15 | 2691 | Barrie Slaymaker |
Generalize underscorification of RCS tags a bit to reduce chances of a collision (still possible, but should be much lower probability). |
||
#14 | 2680 | Barrie Slaymaker |
Implemented real CVS tag testing and underscorification based on reading CVS's rcs.c source code. |
||
#13 | 2667 | Barrie Slaymaker | Convert more to IPC::Run3 | ||
#12 | 2389 | John Fetkovich |
removed calls to methods: command_stderr_filter command_ok_result_codes command_chdir and replaced with named Plugin::run_safely method parameters stderr_filter ok_result_codes in_dir respectively, where possible. |
||
#11 | 2293 | Barrie Slaymaker | Update CHANGES, TODO, improve .vcp files, add --init-cvs | ||
#10 | 2267 | Barrie Slaymaker | factor out cvs2revml, test both --use-cvs and direct modes, with times | ||
#9 | 2240 | Barrie Slaymaker | Start on cvs -r option support. | ||
#8 | 2228 | Barrie Slaymaker | working checkin | ||
#7 | 2026 | Barrie Slaymaker | VCP::8::cvs now supoprt branching | ||
#6 | 2009 | Barrie Slaymaker |
lots of fixes, improve core support for branches and VCP::Source::cvs now supports branches. |
||
#5 | 2006 | Barrie Slaymaker |
more preparations for branching support, handling of cvs :foo:... CVSROOT specs, misc fixes, improvements |
||
#4 | 1742 | Barrie Slaymaker | document VCP::Utils::cvs::create_cvs_workspace() | ||
#3 | 813 | Barrie Slaymaker | Fix path math when checking out a module. | ||
#2 | 723 | Barrie Slaymaker | VCP::Dest::cvs tuning and cvs and p4 bugfixes | ||
#1 | 705 | Barrie Slaymaker | Release 0.22. |