package VCP::Rev; =head1 NAME VCP::Rev - VCP's concept of a revision =head1 SYNOPSIS use VCP::Rev; use VCP::Rev qw( iso8601format ); my $r = VCP::Rev->new; =head1 DESCRIPTION A data structure that represents a revision to a file (but, technically, not a version of a file, though the two are often synonymous). =head1 METHODS =over =cut $VERSION = 1 ; @EXPORT_OK = qw( iso8601format ); use Exporter (); *import = \&Exporter::import; *import = \&Exporter::import; use strict ; use Carp ; use VCP::Debug ':debug' ; use VCP::Utils 'empty' ; use vars qw( %FIELDS ) ; use fields ( ## ## RevML fields: ## 'ID', ## A unique identifier for the rev 'NAME', ## The file name, relative to REV_ROOT 'SOURCE_NAME', ## immutable field, initialized to NAME 'SOURCE_FILEBRANCH_ID', ## immutable field, initialized to NAME or NAME<branch_number> for cvs 'SOURCE_REPO_ID', ## immutable field, initialized to <repo_type>:<repo_server> 'TYPE', ## Type. Binary/text. Need to stdize the values here 'BRANCH_ID', ## What branch this revision is on 'SOURCE_BRANCH_ID', ## immutable field initialized to BRANCH_ID 'REV_ID', ## The source repositories unique ID for this revision 'SOURCE_REV_ID', ## immutable field initialized to REV_ID 'CHANGE_ID', ## The unique ID for the change set, if any 'SOURCE_CHANGE_ID', ## immutable field initialized to CHANGE_ID 'P4_INFO', ## p4-specific info. 'CVS_INFO', ## cvs-specific info. 'STATE', ## The state (CVS specific at the moment). 'TIME', ## The commit/submit time, if available, as a simple number 'MOD_TIME', ## The last modification time, if available 'USER_ID', ## The submitter/commiter of the revision 'LABELS', ## A HASH, keys are tags/labels assoc. with this rev. 'COMMENT', ## The comment/message for this rev. 'ACTION', ## What was done ('edit', 'move', 'delete', etc.) 'PREVIOUS_ID', ## The id of the preceding version ## ## Internal fields: used by VCP::* modules, but not present in RevML files. ## 'WORK_PATH', ## Where to find the revision on the local filesys 'DEST_WORK_PATH', ## Where to find the rev on local fs if it was backfilled 'VCP_SOURCE_SCM_FN',## Non-normalized name of the file, meaningful only to ## a specific VCP::Source 'PREVIOUS', ## A reference to the preceding version, if any 'AVG_COMMENT_TIME', ## Calculated by VCP::Dest for sorting purposes 'SORT_TIME', ## When TIME is missing (think VSS), we need ## to kludge in a time without passing that ## time to the dest repository. ) ; BEGIN { ## Define accessors. my %dont_do = ( WORK_PATH => undef, DEST_WORK_PATH => undef, ID => undef, NAME => undef, COMMENT => undef, LABELS => undef, PREVIOUS => undef, REV_ID => undef, CHANGE_ID => undef, SOURCE_NAME => undef, SOURCE_REV_ID => undef, SOURCE_CHANGE_ID => undef, SOURCE_FILEBRANCH_ID => undef, SOURCE_REPO_ID => undef, ); my @funcs; for ( grep !exists $dont_do{$_}, keys %FIELDS ) { my $f = lc( $_ ) ; push @funcs, qq{ #line 1 'VCP::Rev::$f autogenerated accessor' sub $f { my VCP::Rev \$self = shift ; confess "too many parameters passed" if \@_ > 1 ; \$self->{$_} = shift if \@_ == 1 ; return \$self->{$_} ; } }; } eval( join "", @funcs, 1 ) or die $@; } # Because names and comments have so much duplication, we store them # in hashes and refer to those hashes. Each element is actually # an ARRAY in which we store both the name and a rank. Once all names # have been read, we sort the names and assign the first name the # rank of 0, etc. This allows for very fast sorting. my %names; my %comments; # Same goes for rev_ids and change_ids, which are not really much of # a space savings over storing the strings, but this allows us to # treat each rev_id once and only once, instead of once per file, # for instance, which is valuable when many files can have the same # rev_id. This saves both processor and memory. my %ids; #END { # print "names: " . keys %names, "\n"; # print "comments: " . keys %comments, "\n"; # print "ids: " . keys %ids, "\n"; # print "comment bytes: ", length( join "", keys %comments ), "\n"; #} # cache repo_ids too. my %repo_ids; sub name { my VCP::Rev $self = shift ; confess "too many parameters passed" if @_ > 1 ; $self->{NAME} = $names{$_[0]} ||= [ $_[0], undef ] if @_ == 1 ; return $self->{NAME}->[0]; } sub source_name { my VCP::Rev $self = shift ; confess "too many parameters passed" if @_ > 1 ; $self->{SOURCE_NAME} = $names{$_[0]} ||= [ $_[0], undef ] if @_ == 1 ; return $self->{SOURCE_NAME}->[0]; } sub source_filebranch_id { my VCP::Rev $self = shift ; confess "too many parameters passed" if @_ > 1 ; # TODO: is this still the case? # for most repositories (except cvs) the filebranch_id will be the # same as the name, so cache it there. $self->{SOURCE_FILEBRANCH_ID} = $names{$_[0]} ||= [ $_[0], undef ] if @_ == 1 ; return $self->{SOURCE_FILEBRANCH_ID}->[0]; } sub source_repo_id { my VCP::Rev $self = shift ; confess "too many parameters passed" if @_ > 1 ; $self->{SOURCE_REPO_ID} = $repo_ids{$_[0]} ||= [ $_[0], undef ] if @_ == 1 ; return $self->{SOURCE_REPO_ID}->[0]; } sub comment { my VCP::Rev $self = shift ; confess "too many parameters passed" if @_ > 1 ; if ( @_ == 1 ) { $self->{COMMENT} = defined $_[0] ? $comments{$_[0]} ||= [ $_[0], undef ] : [ undef, 0 ]; } return $self->{COMMENT}->[0]; } sub rev_id { my VCP::Rev $self = shift ; confess "too many parameters passed" if @_ > 1 ; $self->{REV_ID} = $ids{$_[0]} ||= [ $_[0], undef ] if @_ == 1 ; return $self->{REV_ID}->[0]; } sub source_rev_id { my VCP::Rev $self = shift ; confess "too many parameters passed" if @_ > 1 ; $self->{SOURCE_REV_ID} = $ids{$_[0]} ||= [ $_[0], undef ] if @_ == 1 ; return $self->{SOURCE_REV_ID}->[0]; } sub change_id { my VCP::Rev $self = shift ; confess "too many parameters passed" if @_ > 1 ; $self->{CHANGE_ID} = $ids{$_[0]} ||= [ $_[0], undef ] if @_ == 1 ; return $self->{CHANGE_ID}->[0]; } sub source_change_id { my VCP::Rev $self = shift ; confess "too many parameters passed" if @_ > 1 ; $self->{SOURCE_CHANGE_ID} = $ids{$_[0]} ||= [ $_[0], undef ] if @_ == 1 ; return $self->{SOURCE_CHANGE_ID}->[0]; } sub labels { my VCP::Rev $self = shift ; if ( @_ ) { $self->{LABELS} = {} ; @{$self->{LABELS}}{@_} = (undef) x @_ ; } return $self->{LABELS} ? sort keys %{$self->{LABELS}} : () ; } sub _split_name { shift; local $_ = $_[0]; return () unless defined ; return ( "" ) unless length ; s{\A[\\/]+}{}; s{[\\/]+\z}{}; return split qr{[\\/]+}; } =item split_id VCP::Rev->split_id( $id ); Splits an id in to chunks on punctuation and number/letter boundaries. Id Result == ====== 1 ( 1 ) 1a ( 1, "a" ) 1.2 ( 1, "", 2 ) 1a.2 ( 1, "a", 2 ) This oddness is to facilitate manually named revisions that use a lettering scheme. Note that the sort algorithms make an assumption that "1.0a" is after "1.0". This prevents kind of naming like "1.2pre1". =cut sub split_id { shift; for ( $_[0] ) { return () unless defined ; return ( "" ) unless length ; my @r = map /(\d*)(\D*)/, split /[^[:alnum:]]+/; pop @r while @r && ! length $r[-1]; return @r; } } =item join_id VCP::Rev->join_id( @id ); Joins an id's chunks back to being an id in dotted format. =cut sub join_id { shift; my @in = ref $_[0] ? @{shift()} : @_; my @out; while ( @in ) { my $num = shift @in; $num .= shift @in if @in; push @out, $num; } return join ".", @out; } =item cmp_id VCP::Rev->cmp_id( $id1, $id2 ); VCP::Rev->cmp_id( \@id1, \@id2 ); # for presplit ids splits $id1 and $id2 if necessary and compares them using C<< <=> >> on even numbered elements and C<cmp> on odd numbered elements. =cut sub cmp_id { my $self = shift; Carp::confess unless UNIVERSAL::isa( $self, __PACKAGE__ ); my @a = ref $_[0] ? @{$_[0]} : $self->split_id( $_[0] ); my @b = ref $_[1] ? @{$_[1]} : $self->split_id( $_[1] ); my ( $A, $B, $r ); while ( 1 ) { last unless @a && @b; ( $A, $B ) = ( shift @a, shift @b ); $r = $A <=> $B; return $r if $r; last unless @a && @b; ( $A, $B ) = ( shift @a, shift @b ); $r = $A cmp $B; return $r if $r; } return @a <=> @b; } =item sort_time When some revisions come without a time field, as in VSS, the sort algorithm needs to plug in a "best guess" time to facilitate sorting. If no time (or a time of 0) is set, the sort_time field is used instead, if set. =cut # sort time is autognerated =item preindex NOTE: A function. This is called from sort_revs() to rank certain fields by sorting them and using numbers to represent their sort order. This is both a speed and a memory optimization. =cut # Called after last rev is added, before doing any sorting. sub preindex { my $rank = 0; $comments{$_}->[1] = $rank++ for sort keys %comments; { # names are more work: we split them in to segments and do a segment # oriented sort. my @names = values %names; $_->[1] = [ VCP::Rev->_split_name( $_->[0] ) ] for @names; $rank = 0; $_->[1] = $rank++ for sort { my @a = @{$a->[1]}; my @b = @{$b->[1]}; my $r = 0; $r = shift( @a ) cmp shift( @b ) while ! $r && @a && @b; $r || @a <=> @b; } @names; } { # ids are more work yet: we split them in to segments, pack() # all segments back in to a single string, and use that string # as the sort criterion, then replace the sort criterion with # the rank. my @max_lengths; my @ids = values %ids; for ( @ids ) { ## TODO: Store the revision type somewhere and use it instead of ## VCP::Rev my @segments = VCP::Rev->split_id( $_->[0] ); $_->[1] = \@segments; for ( my $i = 0; $i <= $#segments; ++$i ) { my $l = length $segments[$i]; $max_lengths[$i] = $l if ! defined $max_lengths[$i] || $l > $max_lengths[$i]; } } # even segments are assumed to be numeric, odd to be alphabetic my $seg_num = 0; my $fmt = join "", map $seg_num++ % 2 ? "Z" . ( $_ + 1 ) : "N", @max_lengths; $_->[1] = pack $fmt, @{$_->[1]} for map { for ( my $seg_num = 0; $seg_num <= $#max_lengths; ++$seg_num ) { for ( $_->[1]->[$seg_num] ) { $_ = $seg_num % 2 ? "\000" : 0 if empty $_ ; } } $_; } @ids; $rank = 0; $_->[1] = $rank++ for sort { $a->[1] cmp $b->[1] } @ids; } } =item pack_format Returns the pack format for a field. Only sortable fields are supported. =cut sub pack_format { "N"; ## All string fields are ranked as above. } =item index_value_expression Returns an expression that, given "$_", returns the packable code for a field. Only sortable fields are supported. =cut { my %ranked_fields = ( NAME => undef, COMMENT => undef, REV_ID => undef, CHANGE_ID => undef, ); sub index_value_expression { my VCP::Rev $self = shift; my ( $field_name ) = @_; $field_name = uc $field_name; if ( $field_name eq "TIME" ) { return "(\$_->{TIME} || \$_->{SORT_TIME} || 0)"; } if ( exists $ranked_fields{$field_name} ) { return "(\$_->{$field_name}->[1] || 0)"; } return "(\$_->{$field_name} || 0)"; } } ## We never, ever want to delete a file that has revs referring to it. ## So, we put a cleanup object in %files_to_delete and manually manage a ## reference count on it. The hash is keyed on filename and contains ## a count value. When the count reaches 0, it is cleaned. We add a warning ## about undeleted files, which is a great PITA. The reason there's a ## warning is that we could be using gobs of disk space for temporary files ## if there's some bug preventing VCP::Rev objects from being DESTROYed ## soon enough. It's a PITA because it means that the source and ## destination object really must be dereferenced ASAP, so their SEEN ## arrays get cleaned up, and every once in awhile I screw it up somehow. my %files_to_delete ; END { if ( debugging && ! $ENV{VCPNODELETE} ) { for ( sort keys %files_to_delete ) { if ( -e $_ ) { warn "$_ not deleted" ; } } } } =item new Creates an instance, see subclasses for options. my VCP::Rev $rev = VCP::Rev->new( name => 'foo', time => $commit_time, ... ) ; =cut sub new { my $class = shift ; $class = ref $class || $class ; my VCP::Rev $self ; { no strict 'refs' ; $self = bless [ \%{"$class\::FIELDS"} ], $class ; } while ( @_ ) { my $key = shift ; my $meth = lc $key; $meth eq "labels" ? $self->$meth( @{shift() || []} ) : $self->$meth( shift ); } $self->{LABELS} = {} unless $self->{LABELS} ; return $self ; } =item is_base_rev Returns TRUE if this is a base revision. This is the case if no action is defined. A base revision is a revision that is being transferred merely to check it's contents against the destination repository's contents. Base revisions contain no action and contain a <digest> but no <delta> or <content>. When a VCP::Dest::* receives a base revision, the actual body of the revision is 'backfilled' from the destination repository and checked against the digest. This cuts down on transfer size, since the full body of the file never need be sent with incremental updates. See L<VCP::Dest/backfill> as well. =cut sub is_base_rev { my VCP::Rev $self = shift ; return ! defined $self->{ACTION} ; } =item is_placeholder_rev Returns TRUE if this is a placeholder revision. Placeholder revisions are used to record branch points for files that have not been altered on their branches. This occurse when reading CVS repositories and finding files that have branch tags but no revisions on the branch. A placeholder revision has an action of "placeholder". Note that placeholders may have rev_id and change_id fields, but they may be malformed; they are present for sorting purposes only and should be ignored by the destination repository. Placeholders may not be present for branches which have files on them. =cut sub is_placeholder_rev { my VCP::Rev $self = shift ; return ( $self->{ACTION} || "" ) eq "placeholder" ; } sub previous { my VCP::Rev $self = shift; confess "too many parameters passed" if @_ > 1 ; if ( @_ ) { my $n = $self->{PREVIOUS} = shift; my %seen = ( int $self => undef ); my @seen; while ( $n ) { push @seen, $n; confess "\$rev->previous_id loop detected:\n", map " " . $_->as_string . "\n", @seen if exists $seen{int $n}; $seen{int $n} = undef; $n = $n->previous; } } return $self->{PREVIOUS} ; } =item base_revify Converts a "normal" rev in to a base rev. =cut sub base_revify { my VCP::Rev $self = shift ; $self->{$_} = undef for qw( P4_INFO CVS_INFO STATE TIME MOD_TIME USER_ID LABELS COMMENT ACTION ); } =item id Sets/gets the id. Returns "$name#$rev_id" by default, which should work for most systems. =cut sub id { my VCP::Rev $self = shift; $self->{ID} = shift if @_; return defined $self->{ID} ? $self->{ID} : $self->{NAME}->[0] . "#" . $self->{REV_ID}->[0]; } =item work_path, dest_work_path These set/get the name of the working file for sources and destinations, respectively. These files are automatically cleaned up when all VCP::Rev instances that refer to them are DESTROYED or have their work_path or dest_work_path set to other files or undef. =cut sub _set_work_path { my VCP::Rev $self = shift ; my ( $field, $fn ) = @_ ; my $doomed = $self->{$field} ; if ( defined $doomed && $files_to_delete{$doomed} && --$files_to_delete{$doomed} < 1 && -e $doomed ) { if ( debugging $self ) { my @details ; my $i = 2 ; do { @details = caller($i++) } until $details[0] ne __PACKAGE__ ; debug "vcp: $self unlinking '$doomed' in " . join( '|', @details[0,1,2,3]) ; } unlink $doomed or warn "$! unlinking $doomed\n" unless $ENV{VCPNODELETE}; } $self->{$field} = $fn ; ++$files_to_delete{$self->{$field}} if defined $self->{$field} ; } sub work_path { my VCP::Rev $self = shift ; confess "too many parameters passed" if @_ > 1 ; $self->_set_work_path( 'WORK_PATH', @_ ) if @_ ; return $self->{WORK_PATH} ; } sub dest_work_path { my VCP::Rev $self = shift ; confess "too many parameters passed" if @_ > 1 ; $self->_set_work_path( 'DEST_WORK_PATH', @_ ) if @_ ; return $self->{DEST_WORK_PATH} ; } =item labels $r->labels( @labels ) ; @labels = $r->labels ; Sets/gets labels associated with a revision. If a label is applied multiple times, it will only be returned once. This feature means that the automatic label generation code for r_... revision and ch_... change labels won't add additional copies of labels that were already applied to this revision in the source repository. Returns labels in an unpredictible order, which happens to be sorted for now. This sorting is purely for logging purposes and may disappear at any moment. =item add_label $r->add_label( $label ) ; $r->add_label( @labels ) ; Marks one or more labels as being associated with this revision of a file. =cut sub add_label { my VCP::Rev $self = shift ; @{$self->{LABELS}}{@_} = (undef) x @_ ; return ; } sub _branch_id { my VCP::Rev $self = shift; for ( $self->branch_id ) { return "" if empty $_; return "($_)"; } } sub _name_branch_id { my VCP::Rev $self = shift; $self->name . $self->_branch_id; } =item iso8601format VCP::Rev::iso8601format( $time ); Takes a seconds-since-the-epoch time value and converts it to an ISO8601 formatted date. Exportable: use VCP::Rev qw( iso8601format ); =cut sub iso8601format { die "time parameter missing" unless @_; my @f = reverse( (gmtime shift)[0..5] ) ; $f[0] += 1900 ; $f[1] ++ ; ## Month of year needs to be 1..12 return sprintf( "%04d-%02d-%02d %02d:%02d:%02dZ", @f ) ; } =item as_string Prints out a string representation of the name, rev_id, change_id, type, time, and a bit of the comment. base revisions are flagged as such (and don't have fields like time and comment). =cut sub as_string { my VCP::Rev $self = shift ; my @v = map( defined $_ ? $_ : "<undef>", $self->is_base_rev || $self->is_placeholder_rev ? map $self->$_(), qw( name _branch_id rev_id change_id type ) : map( $_ eq 'time' && defined $self->$_() ? iso8601format $self->$_() : $_ eq 'comment' && defined $self->$_() ? do { my $c = $self->$_(); $c =~ s/\n/\\n/g; $c =~ s/\r/\\r/g; $c =~ s/\t/\\t/g; $c =~ s/\l/\\l/g; $c = substr( $c, 0, 32 ) if length( $c ) > 32; $c; } : $_ eq 'action' && defined $self->$_() ? sprintf "%-6s", $self->$_() # 6 == length "delete" : $self->$_(), qw(name _branch_id rev_id change_id type action time user_id comment ) ) ) ; return $self->is_base_rev ? sprintf( qq{%s%s#%s @%s (%s) -- base rev --}, @v ) : $self->is_placeholder_rev ? sprintf( qq{%s%s#%s @%s (%s) -- placeholder rev --}, @v ) : sprintf( qq{%s%s#%s @%s (%s) %s %s %s "%s"}, @v ) ; } sub DESTROY { return if $ENV{VCPNODELETE}; my VCP::Rev $self = shift ; my $doomed = $self->work_path ; $self->work_path( undef ) ; $self->dest_work_path( undef ) ; if ( defined $doomed && -e $doomed ) { debug "vcp: $self unlinking '$doomed'" if debugging $self ; unlink $doomed or warn "$! unlinking $doomed\n"; } } =back =head1 SUBCLASSING This class uses the fields pragma, so you'll need to use base and possibly fields in any subclasses. =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>. =head1 AUTHOR Barrie Slaymaker <barries@slaysys.com> =cut 1
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#78 | 5404 | Barrie Slaymaker |
- SVN support added - Makefile gives clearer notices about missing optional prereqs. - VCP::Filter::labelmap and VCP::Filter::map: <<skip>> replaces deprecated <<delete>> to be clearer that no revisions are deleted from either repository but some just are skipped and not inserted. - VCP::Filter::map: support added for SVN-like branch labels - VCP::Source: support added for ISO8601 timestamps emitted by SVN. |
||
#77 | 5086 | Barrie Slaymaker |
- Prevent infinite recursion in as_string so VCP_DEBUG=1 and partially constructed revs in test suite don't cause infinite recursion. |
||
#76 | 5082 | Barrie Slaymaker |
- VCP::Source tells VCP::Rev to uncache the source to allow the source instance to be DESTROYed and thus clean up its working files. |
||
#75 | 4514 | Barrie Slaymaker | - VCP::Rev::earlier_ids and <release_id> added | ||
#74 | 4511 | Barrie Slaymaker | - iso8691 formatted time returns undef when passed in an undef | ||
#73 | 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 |
||
#72 | 4487 | Barrie Slaymaker | - dead code removal (thanks to clkao's coverage report) | ||
#71 | 4077 | Barrie Slaymaker |
- VCP on Win32 no longer whines about permission denied errors for some disk file cleanup tasks. |
||
#70 | 4021 | Barrie Slaymaker |
- Remove all phashes and all base & fields pragmas - Work around SWASHGET error |
||
#69 | 4012 | Barrie Slaymaker | - Remove dependance on pseudohashes (deprecated Perl feature) | ||
#68 | 3970 | Barrie Slaymaker |
- VCP::Source handles rev queing, uses disk to reduce RAM - Lots of other fixes |
||
#67 | 3942 | Barrie Slaymaker | - ChangeSets now passes tests | ||
#66 | 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 |
||
#65 | 3850 | Barrie Slaymaker | - No longer stores all revs in memory | ||
#64 | 3827 | Barrie Slaymaker | - VCP::Rev supports better debugging and csv-ification | ||
#63 | 3817 | Barrie Slaymaker | - Minor reformatting & error identification | ||
#62 | 3813 | Barrie Slaymaker | - VCP::Rev::previous() is no more | ||
#61 | 3811 | Barrie Slaymaker | - fetch_*() and get_rev() renamed get_source_file() | ||
#60 | 3804 | Barrie Slaymaker | - Refactored to prepare way for reducing memory footprint | ||
#59 | 3775 | Barrie Slaymaker | - VCP::Rev now support serialization/deserialization | ||
#58 | 3769 | Barrie Slaymaker | - avg_comment_time sort key removed | ||
#57 | 3755 | Barrie Slaymaker | - VCP::Rev dies if an empty label is set | ||
#56 | 3737 | Barrie Slaymaker |
- Missing / empty data fields other than branch_id no longer affect changeset aggregation - Needed for VSS, which lacks time information on deletes - If all revs have change_ids, they are now sorted by change_id and name (as opposed to change_id, rev_id) - VCP::Rev::sort_time() removed - VCP::Filter::changesets has better debugging - TestUtils now dumps large diffs |
||
#55 | 3704 | Barrie Slaymaker | - Whitespace tweaked | ||
#54 | 3680 | Barrie Slaymaker | - Comments are more properly escaped in debugging messages | ||
#53 | 3496 | Barrie Slaymaker | - VSS branching | ||
#52 | 3475 | Barrie Slaymaker | - Add VCP::Dest::data_dump | ||
#51 | 3441 | Barrie Slaymaker | - Add some debugging code | ||
#50 | 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. |
||
#49 | 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). |
||
#48 | 3127 | Barrie Slaymaker | Minor cleanups. | ||
#47 | 3117 | Barrie Slaymaker |
Cut over to faster VCP::Rev::new, remove symbolic method calls. |
||
#46 | 3116 | Barrie Slaymaker | Cleanup, test tweaks | ||
#45 | 3115 | Barrie Slaymaker |
Move sorting function to the new VCP::Filter::sort; it's for testing and reporting only and the code was bloating VCP::Dest and limiting VCP::Rev and VCP::Dest optimizations. Breaks test suite in minor way. |
||
#44 | 3112 | Barrie Slaymaker |
Reduce memory footprint when handling large numbers of revisions. |
||
#43 | 3110 | Barrie Slaymaker | Optimize label handling. | ||
#42 | 3106 | Barrie Slaymaker |
Remove an unused field (state) from VCP::Rev optimize and bugfix labelmap |
||
#41 | 3096 | Barrie Slaymaker | Tuning | ||
#40 | 3086 | Barrie Slaymaker |
Optimize change aggregation from something like O(N^2) down to something more reasonable. Noticable only on large transfers. |
||
#39 | 3073 | Barrie Slaymaker | Improve debugging output | ||
#38 | 3060 | Barrie Slaymaker | Note arglist too long error in p4->p4 conversion | ||
#37 | 3049 | Barrie Slaymaker |
Fix minor bug that caused lots of failing tests (undef branch_id handling). |
||
#36 | 3047 | Barrie Slaymaker | Fold branch_ids, improve debug & error (as_string()) output. | ||
#35 | 3038 | Barrie Slaymaker | Get proper identification of founding revisions implemented. | ||
#34 | 3027 | Barrie Slaymaker | VCP::Filter::labelmap | ||
#33 | 2972 | Barrie Slaymaker | Interim checkin | ||
#32 | 2935 | John Fetkovich | added empty() calls | ||
#31 | 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. |
||
#30 | 2743 | John Fetkovich |
Add fields to vcp: source_name, source_filebranch_id, source_branch_id, source_rev_id, source_change_id 1. Alter revml.dtd to include the fields 2. Alter bin/gentrevml to emit legal RevML 3. Extend VCP::Rev to have the fields 4. Extend VCP::{Source,Dest}::revml to read/write the fields (VCP::Dest::revml should die() if VCP tries to emit illegal RevML) 5. Extend VCP::{Source,Dest}::{cvs,p4} to read the fields 7. Get all tests through t/91*.t to pass except those that rely on ch_4 labels |
||
#29 | 2725 | Barrie Slaymaker | Start using HeadRevs.pm. | ||
#28 | 2372 | John Fetkovich | Remove time, sort_time methods, allow them to be autogenerated. | ||
#27 | 2357 | John Fetkovich | removed debugging message left in BEGIN block. | ||
#26 | 2356 | John Fetkovich |
Changed BEGIN block so all accessor functions autogenerated in a single eval, rather than individually. |
||
#25 | 2340 | Barrie Slaymaker | Update manifest, comment out some debugging stuff in VCP::Rev | ||
#24 | 2245 | Barrie Slaymaker | cvs -r (re)implemented for direct reads, passes all cvs-only tests | ||
#23 | 2241 | Barrie Slaymaker | RCS file scanning improvements, implement some of -r | ||
#22 | 2240 | Barrie Slaymaker | Start on cvs -r option support. | ||
#21 | 2233 | Barrie Slaymaker | debug | ||
#20 | 2232 | Barrie Slaymaker | Major memory and sort speed enhancements. | ||
#19 | 2154 | Barrie Slaymaker | Speed up sorting | ||
#18 | 2042 | Barrie Slaymaker | Basic source::p4 branching support | ||
#17 | 2026 | Barrie Slaymaker | VCP::8::cvs now supoprt branching | ||
#16 | 2017 | Barrie Slaymaker |
Interim checkin of id=/base_version_id for revml: and branch_diagram: |
||
#15 | 2015 | Barrie Slaymaker | submit changes | ||
#14 | 1998 | Barrie Slaymaker | Initial, revml and core VCP support for branches | ||
#13 | 1855 | Barrie Slaymaker |
Major VSS checkin. Works on Win32 |
||
#12 | 1822 | Barrie Slaymaker |
Get all other tests passing but VSS. Add agvcommenttime sort field. |
||
#11 | 1809 | Barrie Slaymaker | VCP::Patch should ignore lineends | ||
#10 | 1756 | Barrie Slaymaker | Extend VCPNODELETE to revs' cleanup | ||
#9 | 1358 | Barrie Slaymaker | Win32 changes | ||
#8 | 1055 | Barrie Slaymaker |
add sorting, revamp test suite, misc cleanup. Dest/revml is not portable off my system yet (need to release ...::Diff) |
||
#7 | 628 | Barrie Slaymaker | Cleaned up POD in bin/vcp, added BSD-style license. | ||
#6 | 620 | Barrie Slaymaker |
Underscorify CVS tags, only warn about undeleted files if debugging. |
||
#5 | 608 | Barrie Slaymaker |
Lots of changes to get vcp to install better, now up to 0.066. Many thanks to Matthew Attaway for testing & suggestions. |
||
#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. |