package VCP::Dest::cvs ;
=head1 NAME
VCP::Dest::cvs - cvs destination driver
=head1 SYNOPSIS
vcp <source> cvs:module
vcp <source> cvs:CVSROOT:module
vcp <source> cvs:/path/to/cvsroot:module --init-cvsroot
vcp <source> cvs:/path/to/cvsroot:module --init-cvsroot --delete-cvsroot
where module is a module or directory that already exists within CVS.
=head1 DESCRIPTION
Checks out the indicated module or directory in to a temporary directory and
use it to add, delete, and alter files.
If the module does not exists, uses "cvs import" to create it.
This driver allows L<vcp|vcp> to insert revisions in to a CVS repository.
There are no options at this time.
TODO: Skip all directories named "CVS", in case a CVS tree is being imported.
Perhaps make it fatal, but use an option to allow it. In this case, CVS
directories can be detected by scanning revs before doing anything.
=head1 OPTIONS
=over
=item --init-cvsroot
Initializes a cvs repository in the directory indicated in the cvs
CVSROOT spec. Refuses to init a non-empty directory.
=item --delete-cvsroot
If C<--init-cvsroot> is passed and the target directory is not empty, it
will be deleted. THIS IS DANGEROUS AND SHOULD ONLY BE USED IN TEST
ENVIRONMENTS.
=item --state-location=$dir
The directory to store the state information for this transfer in. This
includes the mapping of source repository versions (name+rev_id, usually)
to destination repository versions and the status of the last transfer,
so that incremental transfers may restart where they left off.
=back
=cut
$VERSION = 1 ;
use strict ;
use vars qw( $debug ) ;
$debug = 0 ;
use Carp ;
use File::Basename ;
use File::Path ;
use Getopt::Long ;
use VCP::Debug ':debug' ;
use VCP::Rev ;
use VCP::Utils::cvs qw( RCS_underscorify_tag );
## If we ever want to store state in the dest repo, this constant
## turns that on. It should become an option if it is ever
## reenabled, probably replacing the VCP::RevMapDB.
use constant store_state_in_repo => 0;
use base qw( VCP::Dest VCP::Utils::cvs ) ;
use fields (
'CVS_CHANGE_ID', ## The current change_id in the rev_meta sequence, if any
'CVS_LAST_MOD_TIME', ## A HASH keyed on working files of the mod_times of
## the previous revisions of those files. This is used
## to make sure that new revision get a different mod_time
## so that CVS never thinks that a new revision hasn't
## changed just because the VCP::Source happened to create
## two files with the same mod_time.
'CVS_PENDING_COMMAND', ## "add" or "edit"
'CVS_PENDING', ## Revs to be committed
## These next fields are used to detect changes between revs that cause a
## commit. Commits are batched for efficiency's sake.
'CVS_PREV_CHANGE_ID', ## Change ID of previous rev
'CVS_PREV_COMMENT', ## Revs to be committed
'CVS_LAST_SEEN', ## HASH of last seen revisions, keyed by name
) ;
## Optimization note: The slowest thing is the call to "cvs commit" when
## something's been added or altered. After all the changed files have
## been checked in by CVS, there's a huge pause (at least with a CVSROOT
## on the local filesystem). So, we issue "cvs add" whenever we need to,
## but we queue up the files until a non-add is seem. Same for when
## a file is edited. This preserves the order of the files, without causing
## lots of commits. Note that we commit before each delete to make sure
## that the order of adds/edits and deletes is maintained.
#=item new
#
#Creates a new instance of a VCP::Dest::cvs. Contacts the cvsd using the cvs
#command and gets some initial information ('cvs info' and 'cvs labels').
#
#=cut
sub new {
my $class = shift ;
$class = ref $class || $class ;
my VCP::Dest::cvs $self = $class->SUPER::new( @_ ) ;
## Parse the options
my ( $spec, $options ) = @_ ;
$self->parse_cvs_repo_spec( $spec ) ;
$self->deduce_rev_root( $self->repo_filespec ) ;
my $init_cvsroot;
my $delete_cvsroot;
my $state_location;
{
local *ARGV = $options ;
GetOptions(
"init-cvsroot" => \$init_cvsroot,
"delete-cvsroot" => \$delete_cvsroot,
"state-location=s" => \$state_location,
)
or $self->usage_and_exit ;
}
$self->command_stderr_filter(
qr{^(?:cvs (?:server|add|remove): (re-adding|use 'cvs commit' to).*)\n}
) ;
$self->set_state_location( $state_location );
if ( $init_cvsroot ) {
$self->rev_map->delete_db if $delete_cvsroot;
$self->init_cvsroot( $delete_cvsroot );
}
else {
warn "vcp: ignoring --delete-cvsroot, which is only useful with --init-cvsroot\n"
if $delete_cvsroot;
}
$self->rev_map->open_db;
return $self ;
}
sub init_cvsroot {
my VCP::Dest::cvs $self = shift;
my ( $delete_cvsroot ) = @_;
my $root = $self->cvsroot;
die "vcp: cvsroot undefined\n"
unless defined $root;
die "vcp: cvsroot is empty string\n"
if $root eq "";
die "vcp: cvsroot not specified\n"
if substr( $root, 0, 1 ) eq ":";
die "vcp: cannot cvs init non local root $root\n"
if substr( $root, 0, 1 ) eq ":";
die "vcp: $root is not a dir\n"
if -e $root && ! -d _;
my @files;
@files = glob "$root/*" if -d $root;
if ( @files && $delete_cvsroot ) {
require File::Path;
rmtree [ @files ];
@files = glob "$root/*";
}
die "vcp: cannot cvs init non-empty dir $root\n"
if @files;
$self->cvs( [ qw( init ) ], { in_dir => $root } );
}
sub handle_header {
my VCP::Dest::cvs $self = shift ;
debug "vcp: first rev" if debugging $self ;
$self->rev_root( $self->header->{rev_root} )
unless defined $self->rev_root ;
$self->create_cvs_workspace(
create_in_repository => 1,
) ;
$self->{CVS_PENDING_COMMAND} = "" ;
$self->{CVS_PENDING} = [] ;
$self->{CVS_PREV_COMMENT} = undef ;
$self->{CVS_PREV_CHANGE_ID} = undef ;
$self->SUPER::handle_header( @_ ) ;
}
sub checkout_file {
my VCP::Dest::cvs $self = shift ;
my VCP::Rev $r ;
( $r ) = @_ ;
debug "vcp: $r checking out ", $r->as_string, " from cvs dest repo"
if debugging $self ;
my $fn = $self->denormalize_name( $r->name );
my $work_path = $self->work_path( $fn ) ;
debug "vcp: work_path '$work_path'" if debugging $self ;
$self->{CVS_LAST_SEEN}->{$r->name} = $r;
my ( undef, $work_dir ) = fileparse( $work_path ) ;
$self->mkpdir( $work_path ) unless -d $work_dir ;
my $tag = store_state_in_repo
? RCS_underscorify_tag "vcp_" . $r->id
: ($self->rev_map->get( $r->id ))[0];
## Ok, the tricky part: we need to use a tag, but we don't want it
## to be sticky, or we get an error the next time we commit this
## file, since the tag is not likely to be a branch revision.
## Apparently the way to do this is to print it to stdout on update
## (or checkout, but we used update so it works with a $fn relative
## to the cwd, ie a $fn with no module name first).
## The -kb is a hack to get the tests to pass on Win32, where \n
## becomes \r\n on checkout otherwise. TODO: figure out what is
## the best thing to do. We might try it without the -kb, then
## if the digest check fails, try it again with -kb. Problem is
## that said digest check occurs in VCP/Source/revml, not here,
## so we need to add a "can retry" return result to the API and
## modify the Sources to use it if a digest check fails.
# my ( $base_fn, $dir ) = fileparse( $fn );
$self->cvs(
[ qw( update -d -kb -p ), -r => $tag, $fn ],
\undef,
$work_path,
# {
# in_dir => $dir,
# }
) ;
die "'$work_path' not created by cvs checkout" unless -e $work_path ;
return $work_path;
}
sub handle_rev {
my VCP::Dest::cvs $self = shift ;
my VCP::Rev $r ;
( $r ) = @_ ;
if (
( @{$self->{CVS_PENDING}} )#|| $self->{CVS_DELETES_PENDING} )
&& (
@{$self->{CVS_PENDING}} > 25 ## Limit command line length
|| (
defined $r->change_id && defined $self->{CVS_PREV_CHANGE_ID}
&& $r->change_id ne $self->{CVS_PREV_CHANGE_ID}
&& ( debugging( $self ) ? debug "vcp: change_id changed" : 1 )
)
|| (
defined $r->comment && defined $self->{CVS_PREV_COMMENT}
&& $r->comment ne $self->{CVS_PREV_COMMENT}
&& ( debugging( $self ) ? debug "vcp: comment changed" : 1 )
)
|| (
grep( $r->name eq $_->name, @{$self->{CVS_PENDING}} )
&& ( debugging( $self ) ? debug "vcp: name repeated" : 1 )
)
)
) {
debug "vcp: committing on general principles" if debugging $self ;
$self->commit ;
}
$self->compare_base_revs( $r )
if $r->is_base_rev && defined $r->work_path ;
return if $r->is_base_rev ;
my $fn = $self->denormalize_name( $r->name ) ;
my $work_path = $self->work_path( $fn ) ;
if ( $r->action eq 'delete' ) {
$self->commit ;
unlink $work_path || die "$! unlinking $work_path" ;
$self->cvs( ['remove', $fn] ) ;
## Do this commit by hand since there are no CVS_PENDING revs, which
## means $self->commit will not work. It's relatively fast, too.
$self->cvs( ['commit', '-m', $r->comment || '', $fn] ) ;
delete $self->{CVS_LAST_SEEN}->{$r->name};
}
else {
## TODO: Move this in to commit().
{
my ( $vol, $work_dir, undef ) = File::Spec->splitpath( $work_path ) ;
unless ( -d $work_dir ) {
my @dirs = File::Spec->splitdir( $work_dir ) ;
my $this_dir = shift @dirs ;
my $base_dir = File::Spec->catpath( $vol, $this_dir, "" ) ;
do {
## Warn: MacOS danger here: "" is like Unix's "..". Shouldn't
## ever be a problem, we hope.
if ( length $base_dir && ! -d $base_dir ) {
$self->mkdir( $base_dir ) ;
## We dont' queue these to a PENDING because these
## should be pretty rare after the first checkin. Could
## have a modal CVS_PENDING with modes like "add", "remove",
## etc. and commit whenever the mode's about to change,
## I guess.
$self->cvs( ["add", $base_dir] ) ;
}
$this_dir = shift @dirs ;
$base_dir = File::Spec->catdir( $base_dir, $this_dir ) ;
} while @dirs ;
}
}
my $last_seen = $self->{CVS_LAST_SEEN}->{$r->name};
$self->{CVS_LAST_SEEN}->{$r->name} = $r;
my $branch_id = $r->branch_id || "";
my $switch_branches = $last_seen
&& ( ( $last_seen->branch_id || "" ) ne $branch_id );
$self->commit if $switch_branches;
## CVS must see the mod_time change to recognize a file as new.
## So we peek at the previously entered one and studiously avoid
## committing a new version with the same mod_time. This is
## an issue when importing files from a source that does not
## track mod_times because we can easily fire multiple versions
## at cvs within a second.
my $mod_time_to_avoid;
if ( -e $work_path ) {
unlink $work_path or die "$! unlinking $work_path";
$mod_time_to_avoid = (stat $work_path)[9];
}
if ( $switch_branches ) {
if ( length $branch_id ) {
if ( $r->previous
&& $branch_id ne ( $r->previous->branch_id || "" )
) {
# Tag the parent revision that is the base for this branch.
my ( $parent_rev_id ) =
$self->rev_map->get( $r->previous->id );
$self->cvs(
[ "tag", "-b", "-r" . $parent_rev_id, $r->branch_id, $fn ]
);
}
$self->cvs( [ "update", "-r", $branch_id, $fn ] );
}
else {
$self->cvs( [ "update", "-A", $fn ] );
}
$mod_time_to_avoid = (stat $work_path)[9];
unlink $work_path or die "$! unlinking $work_path"
if -e $work_path;
}
debug "vcp: linking ", $r->work_path, " to $work_path"
if debugging $self ;
## TODO: Don't assume same filesystem or working link().
link $r->work_path, $work_path
or die "$! linking '", $r->work_path, "' -> $work_path" ;
if ( defined $r->mod_time ) {
utime $r->mod_time, $r->mod_time, $work_path
or die "$! changing times on $work_path" ;
}
my ( $acc_time, $mod_time ) = (stat( $work_path ))[8,9] ;
while ( ( $self->{CVS_LAST_MOD_TIME}->{$work_path} || 0 ) == $mod_time
|| ( ( $mod_time_to_avoid || 0 ) == $mod_time )
) {
debug "vcp: tweaking mod_time on '$work_path' from ",
"".localtime $mod_time,
" to ",
"".localtime $mod_time + 1,
" at ",
"".localtime
if debugging $self ;
++$mod_time ;
utime $acc_time, $mod_time, $work_path
or die "$! changing times on $work_path" ;
}
$self->{CVS_LAST_MOD_TIME}->{$work_path} = $mod_time ;
$r->dest_work_path( $fn ) ;
if ( ! $last_seen ) {
## New file.
my @bin_opts = $r->type ne "text" ? "-kb" : () ;
$self->commit if $self->{CVS_PENDING_COMMAND} ne "add" ;
$self->cvs( [ "add", @bin_opts, "-m", $r->comment || '', $fn ] ) ;
$self->{CVS_PENDING_COMMAND} = "add" ;
}
else {
## Change the existing file
$self->commit if $self->{CVS_PENDING_COMMAND} ne "edit" ;
$self->{CVS_PENDING_COMMAND} = "edit" ;
}
push @{$self->{CVS_PENDING}}, $r ;
}
$self->{CVS_PREV_CHANGE_ID} = $r->change_id ;
$self->{CVS_PREV_COMMENT} = $r->comment ;
}
sub handle_footer {
my VCP::Dest::cvs $self = shift ;
$self->commit
if $self->{CVS_PENDING} && @{$self->{CVS_PENDING}} ;#|| $self->{CVS_DELETES_PENDING} ;
$self->SUPER::handle_footer ;
}
sub commit {
my VCP::Dest::cvs $self = shift ;
return unless @{$self->{CVS_PENDING}} ;
## All comments should be the same, since we alway commit when the
## comment changes.
my $comment = $self->{CVS_PENDING}->[0]->comment || '' ;
## @names was originally to try to convince cvs to commit things in the
## preferred order. No go: cvs chooses some order I can't fathom without
## reading it's source code. I'm leaving this in for now to keep cvs
## from having to scan the working dirs for changes, which may or may
## not be happening now (need to check at some point).
my @names = map $_->dest_work_path, @{$self->{CVS_PENDING}} ;
## Parse out the rev numbers that CVS assigned.
my $commit_log;
$self->cvs( ['commit', '-m', $comment, @names ], undef, \$commit_log ) ;
my %cvs_rev_ids;
{
my $fn;
while ( $commit_log =~ m/\G(.*)([\r\n]+|\z)/g ) {
my $line = $1;
if ( $line =~ /^Checking in (.*);/ ) {
$fn = $1;
next;
}
elsif ( $line =~ /^\w+ revision:\s+([.0-9]+)/ ) {
$cvs_rev_ids{$fn} = $1;
undef $fn;
}
}
}
for my $r ( @{$self->{CVS_PENDING}} ) {
$self->tag( $_, $r->dest_work_path ) for (
store_state_in_repo && defined $r->id ? "vcp_" . $r->id : (),
$r->labels,
) ;
my $cvs_rev_id = $cvs_rev_ids{$r->dest_work_path};
unless ( defined $cvs_rev_id ) {
$commit_log =~ s/^/ /mg;
require Data::Dumper;
die "vcp: No rev number found in cvs commit log output for ",
$r->as_string,
":\n",
$commit_log,
"cvs revs parsed: ",
Data::Dumper::Dumper( \%cvs_rev_ids );
}
$self->rev_map->set( $r->id, $cvs_rev_id );
}
@{$self->{CVS_PENDING}} = () ;
$self->{CVS_PENDING_COMMAND} = "" ;
}
sub tag {
my VCP::Dest::cvs $self = shift ;
my $tag = RCS_underscorify_tag shift;
$self->cvs( ['tag', $tag, @_] ) ;
}
=head1 AUTHOR
Barrie Slaymaker <barries@slaysys.com>
=head1 COPYRIGHT
Copyright (c) 2000, 2001, 2002 Perforce Software, Inc.
All rights reserved.
See L<VCP::License|VCP::License> (C<vcp help license>) for the terms of use.
=cut
1
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #72 | 4507 | Barrie Slaymaker |
- RevML: - added <action>, removed <delete>, <placeholder> and <move> - added <from_id> for clones (and eventually merge actions) - Simplified DTD (can't branch DTD based on which action any more) - VCP::Source::cvs, VCP::Filter::changesets and VCP::Dest::p4 support from_id in <action>clone</action> records - VCP::Dest::perl_data added - VCP::Rev::action() "branch" added, no more undefined action strings - "placeholder" action removed |
||
| #71 | 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 |
||
| #70 | 4127 | Barrie Slaymaker |
- VCP::Dest::cvs now forces commits so that unchanged files will be committed. |
||
| #69 | 4126 | Barrie Slaymaker |
- Comments with leading hyphens and embedded quotes are now tested for - VCP::Dest::cvs now handles comments with embedded double quotes on Win32 |
||
| #68 | 4021 | Barrie Slaymaker |
- Remove all phashes and all base & fields pragmas - Work around SWASHGET error |
||
| #67 | 4012 | Barrie Slaymaker | - Remove dependance on pseudohashes (deprecated Perl feature) | ||
| #66 | 3970 | Barrie Slaymaker |
- VCP::Source handles rev queing, uses disk to reduce RAM - Lots of other fixes |
||
| #65 | 3930 | Barrie Slaymaker |
- VCP::Source::cvs and VCP::Dest::p4 handle cloning deletes - "placeholder" actions and is_placeholder_rev() deprecated in favor of is_branch_rev() and is_clone_rev(). - Misc cleanups and minor bugfixes |
||
| #64 | 3908 | Barrie Slaymaker | - Debugging cleanups | ||
| #63 | 3855 | Barrie Slaymaker |
- vcp scan, filter, transfer basically functional - Need more work in re: storage format, etc, but functional |
||
| #62 | 3850 | Barrie Slaymaker | - No longer stores all revs in memory | ||
| #61 | 3837 | Barrie Slaymaker | - Improved progress bar support | ||
| #60 | 3813 | Barrie Slaymaker | - VCP::Rev::previous() is no more | ||
| #59 | 3812 | Barrie Slaymaker | - VCP::Dest::* no longer need VCP::Rev->previous() | ||
| #58 | 3811 | Barrie Slaymaker | - fetch_*() and get_rev() renamed get_source_file() | ||
| #57 | 3809 | Barrie Slaymaker | - compare_base_revs() now always called with 2 parameters | ||
| #56 | 3805 | Barrie Slaymaker | - VCP::Revs::fetch_files() removed | ||
| #55 | 3706 | Barrie Slaymaker | - VCP gives some indication of output progress (need more) | ||
| #54 | 3460 | Barrie Slaymaker |
- Revamp Plugin/Source/Dest hierarchy to allow for reguritating options in to .vcp files |
||
| #53 | 3410 | Barrie Slaymaker |
- Minor win32 adaptation - More aggressive filesystem cleanup |
||
| #52 | 3384 | John Fetkovich | moved setting of default repo_id | ||
| #51 | 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. |
||
| #50 | 3278 | John Fetkovich | split 'sub init' out from 'sub new' | ||
| #49 | 3208 | John Fetkovich | documentation (pod) fixes. | ||
| #48 | 3194 | John Fetkovich | pod fix | ||
| #47 | 3165 | Barrie Slaymaker | Don't commit so often but do tell the user what's going on. | ||
| #46 | 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. |
||
| #45 | 3133 | Barrie Slaymaker |
Make destinations call back to sources to check out files to simplify the architecture (is_metadata_only() no longer needed) and make it more optimizable (checkouts can be batched). |
||
| #44 | 2973 | Barrie Slaymaker | Fix handling of branched but unchanged files | ||
| #43 | 2972 | Barrie Slaymaker | Interim checkin | ||
| #42 | 2926 | John Fetkovich |
remove --state-location switch add --db-dir and --repo-id switches build state location from concatenation of those two. |
||
| #41 | 2901 | Barrie Slaymaker |
Make VCP::Dest::cvs use more persistant state to handle boundary conditions better. |
||
| #40 | 2872 | Barrie Slaymaker | Improve VCP::Dest::cvs branch handling | ||
| #39 | 2838 | John Fetkovich | Use parse_options rather than using Getopt::Long directly. | ||
| #38 | 2802 | John Fetkovich |
Added a source_repo_id to each revision, and repo_id to each Source and Dest. The repo_ids include repository type (cvs,p4,revml,vss,...) and the repo_server fields. Changed the $self->...->set() and $self->...->get() lines in VCP::Dest::* to pass in a conglomerated key value, by passing in the key as an ARRAY ref. Also various restructuring in VCP::DB.pm, VCP::DB_file.pm and VCP::DB_file::sdbm.pm related to this change. |
||
| #37 | 2774 | Barrie Slaymaker | Update HeadRevDB on submit/commit/write | ||
| #36 | 2725 | Barrie Slaymaker | Start using HeadRevs.pm. | ||
| #35 | 2720 | Barrie Slaymaker | Factor RevMapDB code up in to VCP::Dest. | ||
| #34 | 2713 | Barrie Slaymaker | Factor RevMapDB management up in to VCP::Dest | ||
| #33 | 2712 | Barrie Slaymaker |
RevMapDB works, branching seems to (pending further changes in statefulness so we can get incremental revml output without using labels in the source repo). |
||
| #32 | 2706 | Barrie Slaymaker | Interim checkin | ||
| #31 | 2703 | Barrie Slaymaker | use the new RevMapDB in VCP::Dest::cvs | ||
| #30 | 2699 | Barrie Slaymaker | remove unnecessary dependancies | ||
| #29 | 2663 | Barrie Slaymaker |
Fix mtime bug in VCP::Dest::cvs in branching code Improve temp directory management |
||
| #28 | 2647 | Barrie Slaymaker | Add VCP::Dest::cvs --delete-cvsroot option | ||
| #27 | 2620 | John Fetkovich | Added some error checks. | ||
| #26 | 2293 | Barrie Slaymaker | Update CHANGES, TODO, improve .vcp files, add --init-cvs | ||
| #25 | 2235 | Barrie Slaymaker | Debugging cvs speed reader. | ||
| #24 | 2042 | Barrie Slaymaker | Basic source::p4 branching support | ||
| #23 | 2026 | Barrie Slaymaker | VCP::8::cvs now supoprt branching | ||
| #22 | 2015 | Barrie Slaymaker | submit changes | ||
| #21 | 2009 | Barrie Slaymaker |
lots of fixes, improve core support for branches and VCP::Source::cvs now supports branches. |
||
| #20 | 2006 | Barrie Slaymaker |
more preparations for branching support, handling of cvs :foo:... CVSROOT specs, misc fixes, improvements |
||
| #19 | 1998 | Barrie Slaymaker | Initial, revml and core VCP support for branches | ||
| #18 | 1758 | Barrie Slaymaker | Minor TODO added | ||
| #17 | 1728 | Barrie Slaymaker | CVS on win32, minor bugfixes | ||
| #16 | 1367 | Barrie Slaymaker | lots of docco updates | ||
| #15 | 1055 | Barrie Slaymaker |
add sorting, revamp test suite, misc cleanup. Dest/revml is not portable off my system yet (need to release ...::Diff) |
||
| #14 | 827 | Barrie Slaymaker | Add a test for and debug p4->cvs incremental exports. | ||
| #13 | 825 | Barrie Slaymaker |
test, handle case where no revs are transferred and VCP::Dest::*::handle_footer() blew up. |
||
| #12 | 811 | Barrie Slaymaker | more sensible name for a method. | ||
| #11 | 723 | Barrie Slaymaker | VCP::Dest::cvs tuning and cvs and p4 bugfixes | ||
| #10 | 720 | Barrie Slaymaker | Fix handling of $r->comment in VCP::Dest::cvs | ||
| #9 | 705 | Barrie Slaymaker | Release 0.22. | ||
| #8 | 628 | Barrie Slaymaker | Cleaned up POD in bin/vcp, added BSD-style license. | ||
| #7 | 623 | Barrie Slaymaker | Prefix CVS-unfriendly tags w/ "tag_" instead of "_" | ||
| #6 | 620 | Barrie Slaymaker |
Underscorify CVS tags, only warn about undeleted files if debugging. |
||
| #5 | 609 | Barrie Slaymaker |
Add a file to the test procedure that it alternately added and deleted (file is named "readd"). Fixed all destinations to handle that. |
||
| #4 | 480 | Barrie Slaymaker |
0.06 Wed Dec 20 23:19:15 EST 2000 - bin/vcp: Added --versions, which loads all modules and checks them for a $VERSION and print the results out. This should help with diagnosing out-of-sync modules. - Added $VERSION vars to a few modules :-). Forgot to increment any $VERSION strings. - VCP::Dest::cvs: The directory "deeply" was not being `cvs add`ed on paths like "a/deeply/nested/file", assuming "deeply" had no files in it. - VCP::Dest::revml: fixed a bug that was causing files with a lot of linefeeds to be emitted in base64 instead of deltaed. This means most text files. - Various minor cleanups of diagnostics and error messages, including exposing "Can't locate Foo.pm" when a VCP::Source or VCP::Dest module depends on a module that's not installed, as reported by Jeff Anton. |
||
| #3 | 478 | Barrie Slaymaker |
0.05 Mon Dec 18 07:27:53 EST 2000 - Use `p4 labels //...@label` command as per Rober Cowham's suggestion, with the '-s' flag recommended by Christopher Siewald and Amaury.FORGEOTDARC@atsm.fr. Though it's actually something like vcp: running /usr/bin/p4 -u safari -c safari -p localhost:5666 -s files //.../NtLkly //...@compiler_a3 //.../NtLkly //...@compiler_may3 and so //on //for 50 parameters to get the speed up. I use the //.../NtLkly "file" as //a separator between the lists of files in various //revisions. Hope nobody has any files named that :-). What I should do is choose a random label that doesn't occur in the labels list, I guess. - VCP::Source::revml and VCP::Dest::revml are now binary, control code, and "hibit ASCII" (I know, that's an oxymoron) clean. The <comment>, <delta>, and <content> elements now escape anything other than tab, line feed, space, or printable chars (32 <= c <= ASCII 126) using a tag like '<char code="0x09">'. The test suite tests all this. Filenames should also be escaped this way, but I didn't get to that. - The decision whether to do deltas or encode the content in base64 is now based on how many characters would need to be escaped. - We now depend on the users' diff program to have a "-a" option to force it to diff even if the files look binary to it. I need to use Diff.pm and adapt it for use on binary data. - VCP::Dest::cvs now makes sure that no two consecutive revisions of the same file have the same mod_time. VCP::Source::p4 got so fast at pulling revisions from the repositories the test suite sets up that CVS was not noticing that files had changed. - VCP::Plugin now allows you to set a list of acceptable result codes, since we now use p4 in ways that make it return non-zero result codes. - VCP::Revs now croaks if you try to add two entries of the same VCP::Rev (ie matching filename and rev_id). - The <type> tag is now limited to "text" or "binary", and is meant to pass that level of info between foreign repositories. - The <p4_info> on each file now carries the one line p4 description of the file so that p4->p4 transferes can pick out the more detailed info. VCP::Source::p4, VCP::Dest::p4 do this. - VCP::{Source,Dest}::{p4,cvs} now set binaryness on added files properly, I think. For p4->p4, the native p4 type is preserved. For CVS sources, seeing the keyword substitution flag 'o' or 'b' implies binaryness, for p4, seeing a filetype like qr/u?x?binary/ or qr/x?tempobj/ or "resource" implies binaryness (to non-p4 destinations). NOTE: Seeing a 'o' or 'b' in a CVS source only ends up setting the 'b' option on the destination. That should be ok for most uses, but we can make it smarter for cvs->cvs transfers if need be. |
||
| #2 | 468 | Barrie Slaymaker |
- VCP::Dest::p4 now does change number aggregation based on the comment field changing or whenever a new revision of a file with unsubmitted changes shows up on the input stream. Since revisions of files are normally sorted in time order, this should work in a number of cases. I'm sure we'll need to generalize it, perhaps with a time thresholding function. - t/90cvs.t now tests cvs->p4 replication. - VCP::Dest::p4 now doesn't try to `p4 submit` when no changes are pending. - VCP::Rev now prevents the same label from being applied twice to a revision. This was occuring because the "r_1"-style label that gets added to a target revision by VCP::Dest::p4 could duplicate a label "r_1" that happened to already be on a revision. - Added t/00rev.t, the beginnings of a test suite for VCP::Rev. - Tweaked bin/gentrevml to comment revisions with their change number instead of using a unique comment for every revision for non-p4 t/test-*-in-0.revml files. This was necessary to test cvs->p4 functionality. |
||
| #1 | 467 | Barrie Slaymaker | Version 0.01, initial checkin in perforce public depot. |