1 package Vss2Svn
::ActionHandler
;
9 COMMIT
=> \
&_commit_handler
,
10 RENAME
=> \
&_rename_handler
,
11 SHARE
=> \
&_share_handler
,
12 BRANCH
=> \
&_branch_handler
,
13 MOVE
=> \
&_move_handler
,
14 RESTORE
=> \
&_restore_handler
,
15 DELETE
=> \
&_delete_handler
,
16 RECOVER
=> \
&_recover_handler
,
17 PIN
=> \
&_pin_handler
,
18 LABEL
=> \
&_label_handler
,
24 ###############################################################################
26 ###############################################################################
28 my($class, $row) = @_;
43 return bless($self, $class);
46 ###############################################################################
48 ###############################################################################
50 my($self, $action) = @_;
52 $self->{action
} = $action;
53 my $handler = $gHandlers{$action};
55 if (!defined($handler)) {
56 $self->{errmsg
} .= "Unknown action '$action'";
60 if ($self->{verbose
}) {
61 my $physprint = (defined $self->{row
}->{physname
})?
62 $self->{row
}->{physname
} : '!UNDEF';
63 my $parentprint = (defined $self->{row
}->{parentphys
})?
64 $self->{row
}->{parentphys
} : '!UNDEF';
65 print "$action: $physprint, $parentprint \@ $self->{row}->{timestamp}\n";
68 my $rv = $self->$handler;
70 $self->{errmsg
} =~ s/\n$//;
75 ###############################################################################
77 ###############################################################################
81 return $gPhysInfo{ $self->{row
}->{physname
} };
84 ###############################################################################
86 ###############################################################################
89 my $row = $self->{row
};
91 # For each physical item, we store its "real" physical parent in the
92 # 'parentphys' property, then keep a list of additional shared parents in
93 # the 'sharedphys' array.
95 my $parentphys = $row->{parentphys
};
98 if (!defined $parentphys) {
99 # '_' is used as a magic marker for orphaned files
100 $row->{parentphys
} = '_' . $row->{physname
};
101 # $row->{itemname} = $row->{physname} . '_' . $row->{itemname};
105 # the version number could have been changed by the share handler
106 # or in the branch handler, this is the version we branch.
107 my $version = defined $row->{version
} ?
$row->{version
}
110 # if the item to be added was destroyed, then we don't have a version
111 # number here. So we don't need to add the item anyway.
112 if (!defined $version ) {
113 $self->{errmsg
} .= "Attempt to add entry '$row->{physname}' with "
114 . "unknown version number (probably destroyed)\n";
116 $gOrphanedInfo {$row->{physname
} } = 1;
120 $gPhysInfo{ $row->{physname
} } =
122 type
=> $row->{itemtype
},
123 name
=> $row->{itemname
},
124 # parentphys => $row->{parentphys},
127 last_version
=> $version,
128 orphaned
=> $orphaned,
131 $self->_add_parent ($row->{physname
}, $row->{parentphys
});
132 $self->_track_item_paths ($version);
134 # File was just created so no need to look for shares
135 $self->{itempaths
} = [$self->_get_current_item_path()];
137 # don't convert orphaned items
138 # return $orphaned ? 0 : 1;
142 ###############################################################################
144 ###############################################################################
145 sub _commit_handler
{
147 my $row = $self->{row
};
149 my $physname = $row->{physname
};
150 my $physinfo = $gPhysInfo{$physname};
152 if (!defined $physinfo) {
153 $self->{errmsg
} .= "Attempt to commit unknown item '$physname':\n"
154 . "$self->{physname_seen}\n";
159 # We need to track at least the version number, even if there is no
160 # active parent. This is necessary, if we later share this item, we need
161 # to share from the latest seen version.
163 # remember the last version, in which the file was modified
164 $physinfo->{last_version
} = $row->{version
};
166 # and track all itempaths for the new version
167 $self->_track_item_paths ($row->{version
});
169 my $itempaths = $self->_get_active_item_paths();
170 if (!defined $itempaths && defined $physinfo->{orphaned
}) {
171 $self->{errmsg
} .= "No more active itempath to commit to orphaned item '$physname':\n"
172 . "$self->{physname_seen}\n";
177 $self->{itempaths
} = $itempaths;
179 if (!defined $self->{itempaths
}) {
180 $self->{errmsg
} .= "No more active itempath to commit to '$physname':\n"
181 . "$self->{physname_seen}\n";
187 } # End _commit_handler
189 ###############################################################################
191 ###############################################################################
192 sub _rename_handler
{
194 my $row = $self->{row
};
196 my $physname = $row->{physname
};
197 my $physinfo = $gPhysInfo{$physname};
199 if (!defined $physinfo) {
200 # only report an error, if the file wasn't detected as orphaned.
201 if (!defined $gOrphanedInfo {$physname}) {
202 $self->{errmsg
} .= "Attempt to rename unknown item '$physname':\n"
203 . "$self->{physname_seen}\n";
209 # Get the existing paths before the rename; info will contain the new name
210 my $itempaths = $self->_get_vivid_item_paths();
212 # Renames on shares may show up once for each share, which we don't want
213 # since one rename takes care of all locations. If the "new" name is
214 # already the same as the old, just ignore it.
215 if ($physinfo->{name
} eq $row->{info
}) {
219 # A rename of an item renames it in all its shares
220 $physinfo->{name
} = $row->{info
};
222 # no need to track the itempathes, since a rename doesn't create a new
225 $self->{itempaths
} = $itempaths;
226 $self->{info
} = $row->{info
};
229 } # End _rename_handler
231 ###############################################################################
233 ###############################################################################
236 my $row = $self->{row
};
238 my $physname = $row->{physname
};
239 my $physinfo = $gPhysInfo{$physname};
241 if (!defined $physinfo) {
242 $self->{errmsg
} .= "Attempt to share unknown item '$physname':\n"
243 . "$self->{physname_seen}\n";
248 # # if this is not a share+pin action, then add this item to the sharedphys
249 # # list. Otherwise, this item is pinned to a specific version and does not
250 # # participate in shared actions
251 # if (!defined $row->{version}) {
252 # push @{ $physinfo->{sharedphys} }, $row->{parentphys};
255 my $version = $row->{version
};
256 $version = $physinfo->{last_version
} if (!defined $version);
258 # 'itempath' is the path for this new location (the share target);
259 # note: since we can share from a orphaned item, we use the itemname that
260 # is provided in the row information for the share target and not the
261 # current name of the item. The orphaned name is mangeled to make it unique
262 my $parentpath = $self->_get_current_parent_path ();
263 my $itempath = $parentpath . $row->{itemname
};
265 # 'sourceinfo' contains the source path
266 my $sourceinfo = $self->_get_valid_path ($physname, $row->{parentphys
}, $version);
268 if (!defined($sourceinfo)) {
269 # We can't figure out the path for the parent that this share came from,
270 # so it was either destroyed or corrupted. That means that this isn't
271 # a share anymore; it's a new add.
273 $self->{action
} = 'ADD';
274 # $self->{version} = $version;
275 # return $self->_add_handler();
278 # track the addition of the new parent
279 $self->_add_parent ($physname, $row->{parentphys
});
281 # if this is a share+pin action, then remember the pin version
282 if (defined $row->{version
}) {
283 $physinfo->{parents
}->{$row->{parentphys
}}->{pinned
} = $row->{version
};
286 $self->{itempaths
} = [$itempath];
287 $self->{info
} = $sourceinfo;
288 $self->{version
} = $version;
290 # the share target is now also a valid "copy from" itempath
291 $self->_track_item_path ($physname, $row->{parentphys
}, $version, $itempath);
294 } # End _share_handler
296 ###############################################################################
298 ###############################################################################
299 sub _branch_handler
{
301 my $row = $self->{row
};
303 # Branching a file is actually a null action in SVN; it simply means we
304 # stop duplicating checkins. Return the existing path, but internally
305 # we'll remove this parent from the list of shared physical parents from
306 # the old location, then create a new one with the pertinent info. The row's
307 # 'physname' is that of the new file; 'info' is the formerly shared file.
309 my $physname = $row->{physname
};
310 my $oldphysname = $row->{info
};
312 my $oldphysinfo = $gPhysInfo{$oldphysname};
314 if (!defined $oldphysinfo) {
315 $self->{errmsg
} .= "Attempt to branch unknown item '$oldphysname':\n"
316 . "$self->{physname_seen}\n";
321 # # First delete this parentphys from the old shared object; see
322 # # _delete_handler for details
323 # if ($oldphysinfo->{parentphys} eq $row->{parentphys}) {
324 # $oldphysinfo->{parentphys} = shift( @{ $oldphysinfo->{sharedphys} } );
326 # my $sharedphys = [];
328 # foreach my $oldparent (@{ $oldphysinfo->{sharedphys} }) {
329 # push @$sharedphys, $oldparent
330 # unless $oldparent eq $row->{parentphys};
333 # $oldphysinfo->{sharedphys} = $sharedphys;
336 # treat the old path as deleted
337 # we can't branch an item, that doesn't have a parent. This happens when the
338 # parent was destroyed.
339 if (defined $row->{parentphys
}) {
340 $oldphysinfo->{parents
}->{$row->{parentphys
}}->{deleted
} = 1;
343 # since we have the "orphaned" handling, we can map this action to an
344 # addition, so that this item will show up in the orphaned cache.
345 # TODO: To keep the history of the item we can try to ShareBranch
346 # from original item if it is also somewhere accessible.
348 # my $copypath = $self->_get_valid_path ($oldphysinfo, $row->{parentphys}, $row->{version});
350 $self->{action
} = 'ADD';
353 # Now treat the new entry as a new addition
354 return $self->_add_handler();
356 # # Now create a new entry for this branched item
357 # $gPhysInfo{$physname} =
359 # type => $row->{itemtype},
360 # name => $row->{itemname},
361 ## parentphys => $row->{parentphys},
366 # $self->_add_parent ($physname, $row->{parentphys});
367 # $self->{itempaths} = $self->_get_current_item_paths(1);
371 } # End _branch_handler
373 ###############################################################################
375 ###############################################################################
378 my $row = $self->{row
};
380 # Get the existing paths before the move; parent sub will get the new
382 my $physname = $row->{physname
};
383 my $physinfo = $gPhysInfo{$physname};
385 if (!defined $physinfo) {
386 $self->{errmsg
} .= "Attempt to move unknown item '$physname':\n"
387 . "$self->{physname_seen}\n";
392 # '$sourceinfo' is the path for the old location (the move source);
393 my $parentpath = $self->_get_current_parent_path ();
394 my $sourceinfo = $parentpath . $row->{itemname
};
396 # '$itempath' contains the move target path
397 my $itempath = $self->_get_parent_path ($row->{info
}) . $row->{itemname
};
399 if (!defined($sourceinfo)) {
400 # We can't figure out the path for the parent that this move came from,
401 # so it was either destroyed or corrupted. That means that this isn't
402 # a move anymore; it's a new add.
404 $self->{action
} = 'ADD';
405 # $self->{version} = $version;
406 # return $self->_add_handler();
408 # we need to swap the source and the target path
409 $sourceinfo = $itempath;
413 # set the old parent inactive
414 $physinfo->{parents
}->{$row->{parentphys
}}->{deleted
} = 1;
417 # track the addition of the new parent
418 $self->_add_parent ($physname, $row->{info
});
420 $self->{itempaths
} = [$sourceinfo];
421 $self->{info
} = $itempath;
423 # the move target is now also a valid "copy from" itempath
424 $self->_track_item_path ($physname, $row->{parentphys
}, $physinfo->{last_version
}, $itempath);
427 } # End _move_handler
429 ###############################################################################
431 ###############################################################################
432 sub _restore_handler
{
434 my $row = $self->{row
};
436 $self->{action
} = 'MOVE';
437 $row->{actiontype
} = 'MOVE';
438 $row->{info
} = $row->{parentphys
};
439 $row->{parentphys
} = '_' . $row->{physname
};
440 return $self->_move_handler ();
443 ###############################################################################
445 ###############################################################################
446 sub _delete_handler
{
448 my $row = $self->{row
};
450 # For a delete operation we return the path of the item to be deleted
452 my $physname = $row->{physname
};
453 my $physinfo = $gPhysInfo{$physname};
455 if (!defined $physinfo) {
456 # only report an error, if the file wasn't detected as orphaned.
457 if (!defined $gOrphanedInfo {$physname}) {
458 $self->{errmsg
} .= "Attempt to delete unknown item '$physname':\n"
459 . "$self->{physname_seen}\n";
464 my $parentpath = $self->_get_current_parent_path ();
465 my $itempaths = [$parentpath . $physinfo->{name
}];
467 # if ($physinfo->{parentphys} eq $row->{parentphys}) {
468 # # Deleting from the "main" parent; find a new one by shifting off the
469 # # first shared path, if any; if none exists this will leave a null
470 # # parent entry. We could probably just delete the whole node at this
473 # $physinfo->{parentphys} = shift( @{ $physinfo->{sharedphys} } );
476 # my $sharedphys = [];
478 # foreach my $parent (@{ $physinfo->{sharedphys} }) {
479 # push @$sharedphys, $parent
480 # unless $parent eq $row->{parentphys};
483 # $physinfo->{sharedphys} = $sharedphys;
486 # protect for delete/purge cycles: if the parentphys isn't in the shares
487 # anymore, the file was already deleted from the parent and is now purged
488 if (defined $physinfo->{parents
}->{$row->{parentphys
}}->{deleted
}) {
492 # set the parent inactive
493 $physinfo->{parents
}->{$row->{parentphys
}}->{deleted
} = 1;
495 $self->{itempaths
} = $itempaths;
499 } # End _delete_handler
501 ###############################################################################
503 ###############################################################################
504 sub _recover_handler
{
506 my $row = $self->{row
};
508 my $physname = $row->{physname
};
509 my $physinfo = $gPhysInfo{$physname};
511 if (!defined $physinfo) {
512 # only report an error, if the file wasn't detected as orphaned.
513 if (!defined $gOrphanedInfo {$physname}) {
514 $self->{errmsg
} .= "Attempt to recover unknown item '$physname':\n"
515 . "$self->{physname_seen}\n";
521 # if (defined $physinfo->{parentphys}) {
522 # # Item still has other shares, so recover it by pushing this parent
523 # # onto its shared list
525 # push( @{ $physinfo->{sharedphys} }, $row->{parentphys} );
528 # # Recovering its only location; set the main parent back to this
529 # $physinfo->{parentphys} = $row->{parentphys};
532 # recover this item within the current parent
533 my $parentinfo = $physinfo->{parents
}->{$row->{parentphys
}};
534 if (undef $parentinfo->{deleted
}) {
535 $self->{errmsg
} .= "Attempt to recover an active item '$physname':\n"
536 . "$self->{physname_seen}\n";
540 undef $parentinfo->{deleted
};
542 # We only recover the path explicitly set in this row, so build the path
543 # ourself by taking the path of this parent and appending the name
544 my $parentpath = $self->_get_current_parent_path();
545 my $itempath = $parentpath . $physinfo->{name
};
547 # Since the item could be modified between the delete and the recovery,
548 # we need to find a valid source for the recover
550 $self->_get_valid_path ($physname, $row->{parentphys
}, $row->{version
});
551 $self->{itempaths
} = [$itempath];
553 # We only set the version number, if this item is a file item. If it is a
554 # project item, we must recover from the last known revision, which is
555 # determined in the dumpfile handler
556 if ($row->{itemtype
} == 2) {
557 $self->{version
} = $physinfo->{last_version
};
561 } # End _recover_handler
563 ###############################################################################
565 ###############################################################################
568 my $row = $self->{row
};
570 my $physname = $row->{physname
};
571 my $physinfo = $gPhysInfo{$physname};
573 if (!defined $physinfo) {
574 $self->{errmsg
} .= "Attempt to pin unknown item '$physname':\n"
575 . "$self->{physname_seen}\n";
580 my $parentpath = $self->_get_current_parent_path();
581 my $itempath = $parentpath . $physinfo->{name
};
583 my $parentinfo = \
%{$physinfo->{parents
}->{$row->{parentphys
}}};
585 my $version = $row->{version
};
586 if (!defined $row->{version
}) {
587 # this is the unpin handler
588 undef $parentinfo->{pinned
};
589 $version = $physinfo->{last_version
};
592 $parentinfo->{pinned
} = $row->{version
};
595 $self->{itempaths
} = [$itempath];
597 $self->_get_valid_path ($physname, $row->{parentphys
}, $row->{version
});
598 $self->{version
} = $version;
600 # the unpinned target is now also a valid "copy from" itempath
601 $self->_track_item_path ($physname, $row->{parentphys
}, $version, $itempath);
606 ###############################################################################
608 ###############################################################################
610 # currently the handler only tracks labels that where assigned to files
611 # we need this for the item name tracking
613 my $row = $self->{row
};
615 my $itempaths = $self->_get_active_item_paths();
617 $self->_track_item_paths ($row->{version
});
619 $self->{itempaths
} = $itempaths;
620 $self->{info
} = $row->{label
};
623 } # End _label_handler
625 ###############################################################################
626 # _get_current_parent_path
627 ###############################################################################
628 sub _get_current_parent_path
{
631 return $self->_get_parent_path($self->{row
}->{parentphys
});
632 } # End _get_current_parent_path
635 ###############################################################################
637 ###############################################################################
638 sub _get_parent_path
{
639 my($self, $physname) = @_;
641 # Uses recursion to determine the current full paths for an item based on
642 # the name of its physical file. We can't cache this information because
643 # a rename in a parent folder would not immediately trigger a rename in
644 # all of the child items.
646 # By default, we return an anonymous array of all paths in which the item
647 # is shared, unless $mainonly is true. Luckily, only files can be shared,
648 # not projects, so once we start recursing we can set $mainonly to true.
650 if ($self->{verbose
}) {
651 my $physprint = (defined $physname)?
$physname : '!UNDEF';
652 my $space = ($self->{recursed
})?
' ' : '';
653 print "${space}_get_item_paths($physprint)\n";
656 if (++($self->{recursed
}) >= 1000) {
657 $self->{errmsg
} .= "Infinite recursion detected while looking up "
658 . "parent for '$physname':\n$self->{physname_seen}\n";
663 if (!defined($physname)) {
667 if ($physname eq '') {
671 if ($physname eq 'AAAAAAAA') {
672 # End of recursion; all items must go back to 'AAAAAAAA', which was so
673 # named because that's what most VSS users yell after using it much. :-)
677 if ($physname =~ m/^_.*/) {
678 # End of recursion; this is the orphaned node
679 # return the name of the orphaned directory + the name of the orphaned
680 # file in order to make the path unique
681 return '/orphaned/' . $physname . '/';
684 my $physinfo = $gPhysInfo{$physname};
686 if (!defined $physinfo) {
687 $self->{errmsg
} .= "Could not determine real path for '$physname':\n"
688 . "$self->{physname_seen}\n";
693 #todo: make the behavoir of orphaned file tracking configurable
694 # if ($physinfo->{orphaned}) {
698 $self->{physname_seen
} .= "$physname, ";
700 # In a move szenario, we can have one deleted and one active parent. We
701 # are only interested in the active ones here.
702 my @pathstoget = $self->_get_active_parents ($physname);
704 # TODO: For projects there should be only one active parent
705 my $parent = $pathstoget[0];
707 # if we don't have any active parents, the item path itself is deleted
708 if (!defined ($parent)) {
714 $result = $self->_get_parent_path($pathstoget[0], 1);
716 if(!defined($result)) {
720 return $result . $physinfo->{name
};
722 } # End _get_parent_path
724 ###############################################################################
725 # _get_current_item_paths
726 ###############################################################################
727 sub _get_current_item_paths
{
728 my($self, $mainonly) = @_;
730 my @parents = $self->_get_parents ($self->{row
}->{physname
});
731 return $self->_get_item_paths($self->{row
}->{physname
}, @parents);
732 } # End _get_current_item_paths
734 ###############################################################################
735 # _get_vivid_item_paths
736 ###############################################################################
737 sub _get_vivid_item_paths
{
738 my($self, $mainonly) = @_;
740 my @parents = $self->_get_vivid_parents ($self->{row
}->{physname
});
741 return $self->_get_item_paths($self->{row
}->{physname
}, @parents);
742 } # End _get_vivid_item_paths
744 ###############################################################################
745 # _get_active_item_paths
746 ###############################################################################
747 sub _get_active_item_paths
{
748 my($self, $mainonly) = @_;
750 my @parents = $self->_get_active_parents ($self->{row
}->{physname
});
751 return $self->_get_item_paths($self->{row
}->{physname
}, @parents);
752 } # End _get_active_item_paths
754 ###############################################################################
755 # _get_current_item_path
756 ###############################################################################
757 sub _get_current_item_path
{
760 my @parents = $self->_get_parents ($self->{row
}->{physname
});
762 if (scalar @parents == 0) {
766 my $physname = $self->{row
}->{physname
};
767 my $paths = $self->_get_item_paths($physname, $parents[0]);
769 if (!defined $paths) {
770 $self->{errmsg
} .= "Could not retrieve item path for '$physname': "
771 . "(probably bogous timestamp in parent and child action)\n";
776 } # End _get_current_item_path
778 ###############################################################################
780 ###############################################################################
781 sub _get_item_paths
{
782 my($self, $physname, @parents) = @_;
784 # Uses recursion to determine the current full paths for an item based on
785 # the name of its physical file. We can't cache this information because
786 # a rename in a parent folder would not immediately trigger a rename in
787 # all of the child items.
789 # By default, we return an anonymous array of all paths in which the item
790 # is shared, unless $mainonly is true. Luckily, only files can be shared,
791 # not projects, so once we start recursing we can set $mainonly to true.
793 if ($self->{verbose
}) {
794 my $physprint = (defined $physname)?
$physname : '!UNDEF';
795 my $space = ($self->{recursed
})?
' ' : '';
796 print "${space}_get_item_paths($physprint)\n";
800 if (!defined($physname)) {
804 if ($physname eq 'AAAAAAAA') {
805 # End of recursion; all items must go back to 'AAAAAAAA', which was so
806 # named because that's what most VSS users yell after using it much. :-)
810 if ($physname =~ m/^_.*/) {
811 # End of recursion; this is the orphaned node
812 # return the name of the orphaned directory + the name of the orphaned
813 # file in order to make the path unique
814 return '/orphaned/' . $physname . '/';
817 my $physinfo = $gPhysInfo{$physname};
819 if (!defined $physinfo) {
820 $self->{errmsg
} .= "Could not determine real path for '$physname':\n"
821 . "$self->{physname_seen}\n";
826 #todo: make the behavoir of orphaned file tracking configurable
827 # if ($physinfo->{orphaned})
832 $self->{physname_seen
} .= "$physname, ";
835 # ($physinfo->{parentphys}, @{ $physinfo->{sharedphys} } );
836 my @pathstoget = @parents;
840 # if (defined $physinfo->{parents}->{$row->{parentphys}}->{deleted}) {
845 foreach my $parent (@pathstoget) {
846 if (!defined $parent) {
849 $result = $self->_get_parent_path($parent);
851 if(!defined($result)) {
855 push @
$paths, $result . $physinfo->{name
};
860 } # End _get_item_paths
864 ###############################################################################
866 # This function maintains a map that records the itempath that was valid for
867 # each version of the physical file in the context of the different parents.
868 # This map is needed, e.g. during pinning when a file is pinned to a previous
869 # version. Since the file, could have renamed in between, we need to know the
870 # previous itempath that was valid in the previous version.
872 # This map does not replace the recursive lookup of the itempath in teh function
873 # _get_item_paths. The itempathes stored here are "historic" item pathes.
874 # A rename e.g. is not reflectected in the version history of the physical file
875 # and therefor does not have a distinct version as in subversion.
876 ###############################################################################
877 sub _track_item_paths
{
878 my($self, $version) = @_;
880 my $row = $self->{row
};
882 # we only need to track the path for actions that deal with a specific
884 if (defined $version) {
886 my $physinfo = $gPhysInfo{ $row->{physname
} };
888 my @parents = $self->_get_active_parents ($row->{physname
});
892 foreach my $parent (@parents) {
894 my $parentpath = $self->_get_parent_path ($parent);
895 if (!defined $parentpath) {
898 $result = $parentpath . $physinfo->{name
};
900 $self->_track_item_path ($row->{physname
}, $parent, $row->{version
}, $result);
902 # my $versions = \@{$physinfo->{parents}->{$parent}->{versions}};
904 # # in the case of pinning and sharing with pinning, the version number
905 # # denotes a version in the past. So if there is already an entry for
906 # # this version number skip this parent.
907 # if (exists $versions->[$row->{version}]) {
911 # # remember the last version, in which the file was modified
912 # $physinfo->{last_version} = $row->{version};
914 # $result = $self->_get_parent_path ($parent) . $physinfo->{name};
916 # if(!defined($result)) {
920 # $versions->[$row->{version}] = $result;
923 } # End _track_item_paths
926 ###############################################################################
928 ###############################################################################
929 sub _track_item_path
{
930 my($self, $physname, $parent, $version, $itempath) = @_;
932 if (defined $version && defined $itempath) {
934 my $physinfo = $gPhysInfo{ $physname };
936 my $versions = \@
{$physinfo->{parents
}->{$parent}->{versions
}};
938 # in the case of pinning and sharing with pinning, the version number
939 # denotes a version in the past. So if there is already an entry for
940 # this version number skip this parent.
941 if (exists $versions->[$version]) {
945 $versions->[$version] = $itempath;
947 } # End _track_item_path
950 ###############################################################################
952 # This function returns all parents where the physical file is not deleted,
953 # r all active projects. If a file is deleted, the file
954 # does nor take place in any further rename activity, so it is
956 ###############################################################################
957 sub _get_vivid_parents
{
958 my($self, $physname) = @_;
960 my $physinfo = $gPhysInfo{$physname};
963 if (defined $physinfo) {
966 foreach my $parentphys (@
{$physinfo->{order
}}) {
968 # skip orphaned parents
969 # if ($parentphys eq '99999999' ) {
973 my $parent = $physinfo->{parents
}->{$parentphys};
974 if (!defined $parent)
979 # skip deleted parents, since these parents do not
980 # participate in specific vss action
981 if (defined $parent->{deleted
} ) {
985 push @parents, $parentphys;
990 } # End _get_vivid_parents
992 ###############################################################################
993 # _get_active_parents
994 # This function returns all parents where the physical file is not deleted
995 # or pinned, or all active projects. If a file is pinned or deleted, the file
996 # does nor take place in any further checkin or rename activity, so it is
998 ###############################################################################
999 sub _get_active_parents
{
1000 my($self, $physname) = @_;
1002 my $physinfo = $gPhysInfo{$physname};
1005 if (defined $physinfo) {
1008 foreach my $parentphys (@
{$physinfo->{order
}}) {
1010 # skip orphaned parents
1011 # if ($parentphys eq '99999999' ) {
1015 my $parent = $physinfo->{parents
}->{$parentphys};
1016 if (!defined $parent)
1021 # skip deleted or pinned parents, since these parents do not
1022 # participate in any vss action
1023 if (defined $parent->{deleted
} || defined $parent->{pinned
} ) {
1027 push @parents, $parentphys;
1032 } # End _get_active_parents
1034 ###############################################################################
1036 # This function returns all parents for the physical file
1037 ###############################################################################
1039 my($self, $physname) = @_;
1041 my $physinfo = $gPhysInfo{$physname};
1044 if (defined $physinfo) {
1047 foreach my $parentphys (@
{$physinfo->{order
}}) {
1049 # skip orphaned parents
1050 # if ($parentphys eq '99999999' ) {
1054 my $parent = $physinfo->{parents
}->{$parentphys};
1055 if (!defined $parent)
1060 push @parents, $parentphys;
1065 } # End _get_active_parents
1067 ###############################################################################
1069 # This function returns an itempath for the physical file, that was valid in
1070 # the previous version. Since all activities that create a new version of a file
1071 # must be done on at least one active path, there should be at least one valid
1072 # item path for the version.
1073 # If we can't find any valid itempath, we can not perform a "copy from" revision
1074 # In this case, we need to recheckin the current content of the item
1075 ###############################################################################
1076 sub _get_valid_path
{
1077 my($self, $physname, $parentphys, $version) = @_;
1079 my $physinfo = $gPhysInfo{$physname};
1080 if (!defined $physinfo) {
1084 if (!defined $version) {
1085 $version = $physinfo->{last_version
};
1088 # 1. check the parent requested, if there was an item name for this version
1089 # we can use this item name, since it was valid in that time
1090 my $parent = $physinfo->{parents
}->{$parentphys};
1091 if (defined $parent &&
1092 # $parentphys ne '99999999' &&
1093 $parent->{versions
}->[$version]) {
1094 return $parent->{versions
}->[$version];
1097 # 2. check all other parents in the order, the where added
1101 foreach $parentphys (@
{$physinfo->{order
}}) {
1103 $parent = $physinfo->{parents
}->{$parentphys};
1104 if (defined $parent &&
1105 # $parentphys ne '99999999' &&
1106 $parent->{versions
}->[$version]) {
1107 return $parent->{versions
}->[$version];
1112 } # End _get_valid_path
1114 ###############################################################################
1116 # Track the addition of a new parent to this itempath. This will also track the
1117 # order, in which the parents where added to the physical file. The valid
1118 # itempath lookup will search for valid pathes in the order the parents where
1119 # added to the project.
1120 ###############################################################################
1122 my($self, $physname, $parentphys) = @_;
1124 my $physinfo = $gPhysInfo{$physname};
1125 if (defined $physinfo) {
1126 $physinfo->{parents
}->{$parentphys} = {};
1127 push @
{ $physinfo->{order
} }, $parentphys;