I found a glitch in the Dumpfile::_move_handler. I forgot to track the "new" move target as a valid item path. This was problematic in situations, where the move target was used as a copy_from rev, e.g. in a subsequent share.

Here is the full patch again

Dirk
Index: vss2svn.pl
===================================================================
--- vss2svn.pl  (revision 300)
+++ vss2svn.pl  (working copy)
@@ -611,49 +611,61 @@
     $rows = $sth->fetchall_arrayref( {} );
 
     my($childrecs, $child, $id);
-    my @delchild = ();
 
     foreach $row (@$rows) {
-        $row->{actiontype} = 'MOVE';
+        $row->{actiontype} = 'MOVE_TO';
         $childrecs = &GetChildRecs($row, 1);
 
+        my $source = undef;
+        my $target = $row->{parentphys};
+
         if (scalar @$childrecs > 1) {
-            &ThrowWarning("Multiple chidl recs for parent MOVE rec "
+            &ThrowWarning("Multiple child recs for parent MOVE rec "
                           . "'$row->{action_id}'");
         }
 
-        foreach $child (@$childrecs) {
-            my $update;
-            $update = $gCfg{dbh}->prepare('UPDATE PhysicalAction SET info = ?'
-                                          . 'WHERE action_id = ?');
-            
-            $update->execute( $row->{parentphys}, $child->{action_id} );
+        if (scalar @$childrecs >= 1) {
+            # only merge MOVE records that have the same timestamp
+            if ($row->{timestamp} == @$childrecs[0]->{timestamp}) {
+                $source = @$childrecs[0]->{parentphys};
+                &DeleteChildRec(@$childrecs[0]->{action_id});
+            }
         }
-
-        if (scalar @$childrecs == 0) {
-            my $sql = <<"EOSQL";
+        
+        my $sql = <<"EOSQL";
 UPDATE
     PhysicalAction
 SET
+    actiontype = 'MOVE',
     parentphys = ?,
-    actiontype = 'MOVE',
     info = ?
 WHERE
     action_id = ?
 EOSQL
-            my $update;
-            $update = $gCfg{dbh}->prepare($sql);
-            $update->execute( undef, $row->{parentphys},
-            $row->{action_id});
-        } else {
-            push(@delchild, $row->{action_id});
-        }
+        my $update;
+        $update = $gCfg{dbh}->prepare($sql);
+        
+        $update->execute( $target, $source, $row->{action_id});
     }
 
-    foreach $id (@delchild) {
-        &DeleteChildRec($id);
+
+    # change all remaining MOVE_TO records into MOVE records and swap the src 
and target
+    $sth = $gCfg{dbh}->prepare('SELECT * FROM PhysicalAction '
+                               . 'WHERE actiontype = "MOVE_TO"');
+    $sth->execute();
+    $rows = $sth->fetchall_arrayref( {} );
+
+    foreach $row (@$rows) {
+        my $update;
+        $update = $gCfg{dbh}->prepare('UPDATE PhysicalAction SET '
+                                      . 'actiontype = "MOVE", '
+                                      . 'parentphys = ?, '
+                                      . 'info = ? '
+                                      . 'WHERE action_id = ?');
+        $update->execute($row->{info}, $row->{parentphys}, $row->{action_id});
     }
 
+
     1;
 
 }  #  End MergeMoveData
@@ -764,7 +776,7 @@
         # May contain add'l info for the action depending on type:
         # RENAME: the new name (without path)
         # SHARE: the source path which was shared
-        # MOVE: the new path
+        # MOVE: the old path
         # PIN: the path of the version that was pinned      
         # LABEL: the name of the label
         $row->{info} = $handler->{info};
@@ -1333,7 +1345,7 @@
         AddedProject => {type => 1, action => 'ADD'},
         RestoredProject => {type => 1, action => 'RESTOREDPROJECT'},
         RenamedProject => {type => 1, action => 'RENAME'},
-        MovedProjectTo => {type => 1, action => 'MOVE'},
+        MovedProjectTo => {type => 1, action => 'MOVE_TO'},
         MovedProjectFrom => {type => 1, action => 'MOVE_FROM'},
         DeletedProject => {type => 1, action => 'DELETE'},
         DestroyedProject => {type => 1, action => 'DELETE'},
Index: Vss2Svn/ActionHandler.pm
===================================================================
--- Vss2Svn/ActionHandler.pm    (revision 300)
+++ Vss2Svn/ActionHandler.pm    (working copy)
@@ -251,13 +251,6 @@
         return 0;
     }
 
-#    # if this is not a share+pin action, then add this item to the sharedphys
-#    # list. Otherwise, this item is pinned to a specific version and does not
-#    # participate in shared actions
-#    if (!defined $row->{version}) {
-#        push @{ $physinfo->{sharedphys} }, $row->{parentphys};
-#    }
-    
     my $version = $row->{version};
     $version = $physinfo->{last_version} if (!defined $version);
 
@@ -283,13 +276,23 @@
 #        return $self->_add_handler();
     }
 
+    # if this is a share from orphan, and not a share+pin action either, we 
can treat it as a move
+    elsif (!defined $row->{version} &&        # share+pin?
+           defined $physinfo->{orphaned}      # orphaned?
+#          scalar @{$physinfo->{order}} == 1  # only one parent?
+       ) {
+        $physinfo->{parents}->{'_' . $row->{physname}}->{deleted} = 1;
+        undef $physinfo->{orphaned};
+        $self->{action} = 'MOVE';
+    }
+    
     # track the addition of the new parent
     $self->_add_parent ($physname, $row->{parentphys});
     
     # if this is a share+pin action, then remember the pin version
     if (defined $row->{version}) {
         $physinfo->{parents}->{$row->{parentphys}}->{pinned} = $row->{version};
-    } 
+    }
 
     $self->{itempaths} = [$itempath];
     $self->{info} = $sourceinfo;
@@ -410,8 +413,6 @@
     my($self) = @_;
     my $row = $self->{row};
 
-    # Get the existing paths before the move; parent sub will get the new
-    # name
     my $physname = $row->{physname};
     my $physinfo = $gPhysInfo{$physname};
   
@@ -422,58 +423,61 @@
         return 0;
     }
 
-    if (!defined $row->{parentphys}) {
+    # row->{info} contains the source parent
+    # row->{parentphys} contains the target parent
+
+    # check the source path    
+    if (!defined $row->{info}) {
       # Check if this is an orphaned item
-      if (scalar @{$physinfo->{order}} == 1) {
-        $row->{parentphys} = $physinfo->{order}[0];
+      if (defined $physinfo->{orphaned}) {
+        $row->{info} = '_' . $physname;
+        undef $physinfo->{orphaned};
       } else {
         # Don't know from where to move. Share it there instead
-        $row->{parentphys} = $row->{info};
-        $row->{info} = undef;
         $self->{action} = 'SHARE';
         return $self->_share_handler();
       }
     }
 
     # '$sourceinfo' is the path for the old location (the move source);
-    my $parentpath = $self->_get_current_parent_path ();
-    my $sourceinfo = $parentpath . $physinfo->{name}; # $row->{itemname};
+    my $sourceparent = $self->_get_parent_path ($row->{info});
+    my $sourceinfo = $sourceparent . $row->{itemname};
 
-    if (!defined ($row->{info})) {
+
+    # check the target path
+    if (!defined ($row->{parentphys})) {
         # the target directory was destroyed, so there is no apropriate move
         # target information. Fall back to a move to the orphaned cache
-        $row->{info} = '_' . $row->{physname};
+        $physinfo->{orphaned} = 1;
+        $row->{parentphys} = '_' . $row->{physname};
     }
 
     # '$itempath' contains the move target path
-    my $itempath = $self->_get_parent_path ($row->{info}) . $row->{itemname};
+    my $parentpath = $self->_get_current_parent_path ();
+    my $itempath = $parentpath . $physinfo->{name}; # $row->{itemname};
 
-    if (!defined($parentpath)) {
+
+    if (!defined($sourceparent)) {
         # We can't figure out the path for the parent that this move came from,
         # so it was either destroyed or corrupted. That means that this isn't
         # a move anymore; it's a new add.
 
         $self->{action} = 'ADD';
-#        $self->{version} = $version;
-#        return $self->_add_handler();
-        
-        # we need to swap the source and the target path
-        $sourceinfo = $itempath;
-        undef $itempath;
+        undef $sourceinfo;
     }
     else {
         # set the old parent inactive
-        $physinfo->{parents}->{$row->{parentphys}}->{deleted} = 1;
+        $physinfo->{parents}->{$row->{info}}->{deleted} = 1;
     }
 
     # if the item mysteriously changed name during the move
     $physinfo->{name} = $row->{itemname};
 
     # track the addition of the new parent
-    $self->_add_parent ($physname, $row->{info});
+    $self->_add_parent ($physname, $row->{parentphys});
     
-    $self->{itempaths} = [$sourceinfo];
-    $self->{info} = $itempath;
+    $self->{itempaths} = [$itempath];
+    $self->{info} = $sourceinfo;
 
     # the move target is now also a valid "copy from" itempath
     $self->_track_item_path ($physname, $row->{parentphys}, 
$physinfo->{last_version}, $itempath);
@@ -745,11 +749,6 @@
         return undef;
     }
 
-    #todo: make the behavoir of orphaned file tracking configurable
-#    if ($physinfo->{orphaned}) {
-#        return undef;
-#    }
-
     $self->{physname_seen} .= "$physname, ";
 
     # In a move szenario, we can have one deleted and one active parent. We
@@ -878,12 +877,6 @@
         return undef;
     }
 
-    #todo: make the behavoir of orphaned file tracking configurable
-#    if ($physinfo->{orphaned})
-#    {
-#        return undef;
-#       }
-
     $self->{physname_seen} .= "$physname, ";
 
 #    my @pathstoget =
@@ -1169,9 +1162,7 @@
     my($self, $physname, $parentphys, $version, $deleted) = @_;
 
     my $physinfo = $gPhysInfo{$physname};
-    if (!defined $physinfo) {
-        return undef;
-    }
+ 
     # 1. check the parent requested, if there was an item name for this version
     #    we can use this item name, since it was valid in that time
     my $parent = $physinfo->{parents}->{$parentphys};
Index: Vss2Svn/Dumpfile.pm
===================================================================
--- Vss2Svn/Dumpfile.pm (revision 300)
+++ Vss2Svn/Dumpfile.pm (working copy)
@@ -385,44 +385,50 @@
 
     # moving in SVN is the same as renaming; add the new and delete the old
 
-    my $newpath = $data->{info};
+    my $oldpath = $data->{info};
 
-    if ($self->{repository}->exists ($newpath)) {
-        $self->add_error("Attempt to move item '$itempath' to '$newpath' at "
+    if ($self->{repository}->exists ($itempath)) {
+        $self->add_error("Attempt to move item '$oldpath' to '$itempath' at "
             . "revision $data->{revision_id}, but destination already exists: 
possibly "
             . "missing delete; skipping");
         return 0;
     }
 
-    if (!$self->{repository}->exists ($itempath)) {
-        $self->add_error("Attempt to move item '$itempath' to '$newpath' at "
+    if (!$self->{repository}->exists ($oldpath)) {
+        $self->add_error("Attempt to move item '$oldpath' to '$itempath' at "
             . "revision $data->{revision_id}, but source doesn't exists: 
possibly "
             . "missing recover; skipping");
         return 0;
     }
     
     my $node = Vss2Svn::Dumpfile::Node->new();
-    $node->set_initial_props($newpath, $data);
+    $node->set_initial_props($itempath, $data);
     $node->{action} = 'add';
 
     my($copyrev, $copypath);
 
     $copyrev = $data->{revision_id} - 1;
-    $copypath = $itempath;
+    $copypath = $oldpath;
 
     $node->{copyrev} = $copyrev;
     $node->{copypath} = $copypath;
 
     push @$nodes, $node;
 
-#    $self->track_modified($data->{physname}, $data->{revision_id}, $newpath);
-#    $self->track_version ($data->{physname}, $data->{version}, $newpath);
+    # the new move target is a valid path.
+    $self->track_version ($data->{physname}, $data->{version}, $itempath);
 
     $node = Vss2Svn::Dumpfile::Node->new();
-    $node->set_initial_props($itempath, $data);
+    $node->set_initial_props($oldpath, $data);
     $node->{action} = 'delete';
     $node->{hideprops} = 1;
 
+#   Deleted tracking is only necessary to be able to recover the item. But a 
move
+#   does not set a recover point, so we don't need to track the delete here. 
Additionally
+#   we do not have enough information for this operation.
+#   $self->track_deleted($data->{oldparentphys}, $data->{physname},
+#                        $data->{revision_id}, $oldpath);
+
     push @$nodes, $node;
 
 }  #  End _move_handler
@@ -559,7 +565,7 @@
     # as a valid share source.
     if (defined ($label)) {
         $label =~ s:/:_:g;
-    
+        
         my $vssitempath = $itempath;
         $vssitempath =~ s/^$main::gCfg{trunkdir}//;
         my $labelpath = "$main::gCfg{labeldir}/$label$vssitempath";
_______________________________________________
vss2svn-users mailing list
Project homepage:
http://www.pumacode.org/projects/vss2svn/
Subscribe/Unsubscribe/Admin:
http://lists.pumacode.org/mailman/listinfo/vss2svn-users-lists.pumacode.org
Mailing list web interface (with searchable archives):
http://dir.gmane.org/gmane.comp.version-control.subversion.vss2svn.user

Reply via email to