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 DELETE
=> \
&_delete_handler
,
15 RECOVER
=> \
&_recover_handler
,
20 ###############################################################################
22 ###############################################################################
24 my($class, $row) = @_;
36 return bless($self, $class);
39 ###############################################################################
41 ###############################################################################
43 my($self, $action) = @_;
45 my $handler = $handlers{$action};
47 if (!defined($handler)) {
48 $self->{errmsg
} = "Unknown action '$action'";
52 return $self->$handler;
56 ###############################################################################
58 ###############################################################################
62 return $gPhysInfo{ $self->{row
}->{physname
} };
65 ###############################################################################
67 ###############################################################################
70 my $row = $self->{row
};
72 # For each physical item, we store its "real" physical parent in the
73 # 'parentphys' property, then keep a list of additional shared parents in
74 # the 'sharedphys' array.
76 $gPhysInfo{ $row->{physname
} } =
78 type
=> $row->{itemtype
},
79 name
=> $row->{itemname
},
80 parentphys
=> $row->{parentphys
},
84 # File was just created so no need to look for shares
85 $self->{itempaths
} = $self->_get_current_item_paths(1);
91 ###############################################################################
93 ###############################################################################
96 my $row = $self->{row
};
98 $self->{itempaths
} = $self->_get_current_item_paths();
100 } # End _commit_handler
102 ###############################################################################
104 ###############################################################################
105 sub _rename_handler
{
107 my $row = $self->{row
};
109 # Get the existing paths before the rename; info will contain the new name
110 my $physname = $row->{physname
};
111 my $itempaths = $self->_get_current_item_paths();
113 my $physinfo = $gPhysInfo{$physname};
115 if (!defined $physinfo) {
116 $self->{errmsg
} = "Attempt to rename unknown item '$physname':\n"
117 . $self->{nameResolveSeen
};
122 # A rename of an item renames it in all its shares
123 $physinfo->{name
} = $row->{info
};
125 $self->{itempaths
} = $itempaths;
126 $self->{info
} = $self->_get_current_item_name();
129 } # End _rename_handler
131 ###############################################################################
133 ###############################################################################
136 my $row = $self->{row
};
138 my $physname = $row->{physname
};
139 my $physinfo = $gPhysInfo{$physname};
141 if (!defined $physinfo) {
142 $self->{errmsg
} = "Attempt to share unknown item '$physname':\n"
143 . $self->{physname_seen
};
148 push @
{ $physinfo->{sharedphys
} }, $row->{parentphys
};
150 # 'itempaths' is the path for this new location (the share target);
151 # 'info' contains the source path
152 my $parentpaths = $self->_get_item_paths($row->{parentphys
}, 1);
154 $self->{itempaths
} = [$parentpaths->[0] . $physinfo->{name
}];
155 $self->{info
} = $self->_get_current_item_paths(1)->[0];
159 } # End _share_handler
161 ###############################################################################
163 ###############################################################################
164 sub _branch_handler
{
166 my $row = $self->{row
};
168 # Branching a file is actually a null action in SVN; it simply means we
169 # stop duplicating checkins. Return the existing path, but internally
170 # we'll remove this parent from the list of shared physical parents from
171 # the old location, then create a new one with the pertinent info. The row's
172 # 'physname' is that of the new file; 'info' is the formerly shared file.
174 my $physname = $row->{physname
};
175 my $oldphysname = $row->{info
};
177 my $oldphysinfo = $gPhysInfo{$oldphysname};
179 # First delete this parentphys from the old shared object; see
180 # _delete_handler for details
181 if ($oldphysinfo->{parentphys
} eq $row->{parentphys
}) {
182 $oldphysinfo->{parentphys
} = shift( @
{ $oldphysinfo->{sharedphys
} } );
186 foreach my $oldparent (@
{ $oldphysinfo->{sharedphys
} }) {
187 push @
$sharedphys, $oldparent
188 unless $oldparent eq $row->{parentphys
};
191 $oldphysinfo->{sharedphys
} = $sharedphys;
194 # Now create a new entry for this branched item
195 $gPhysInfo{$physname} =
197 type
=> $row->{itemtype
},
198 name
=> $row->{itemname
},
199 parentphys
=> $row->{parentphys
},
203 $self->{itempaths
} = $self->_get_current_item_paths(1);
207 } # End _branch_handler
209 ###############################################################################
211 ###############################################################################
214 my $row = $self->{row
};
216 # Get the existing paths before the move; parent sub will get the new
218 my $physname = $row->{physname
};
219 my $itempaths = $self->_get_current_item_paths();
221 my $physinfo = $gPhysInfo{$physname};
223 if (!defined $physinfo) {
224 $self->{errmsg
} = "Attempt to rename unknown item '$physname':\n"
225 . $self->{physname_seen
};
230 # Only projects can have true "moves", and projects don't have shares, so
231 # we don't need to worry about any shared paths
232 $physinfo->{parentphys
} = $row->{parentphys
};
234 # 'itempaths' has the original path; 'info' has the new
235 $self->{itempaths
} = $itempaths;
236 $self->{info
} = $self->_get_current_item_paths(1)->[0];
240 } # End _move_handler
242 ###############################################################################
244 ###############################################################################
245 sub _delete_handler
{
247 my $row = $self->{row
};
249 # For a delete operation we return only the "main" path, since any deletion
250 # of shared paths will have their own entry
252 my $physname = $row->{physname
};
254 my $itempaths = $self->_get_current_item_paths(1);
256 my $physinfo = $gPhysInfo{$physname};
258 if (!defined $physinfo) {
259 $self->{errmsg
} = "Attempt to delete unknown item '$physname':\n"
260 . $self->{physname_seen
};
264 if ($physinfo->{parentphys
} eq $row->{parentphys
}) {
265 # Deleting from the "main" parent; find a new one by shifting off the
266 # first shared path, if any; if none exists this will leave a null
267 # parent entry. We could probably just delete the whole node at this
270 $physinfo->{parentphys
} = shift( @
{ $physinfo->{sharedphys
} } );
275 foreach my $parent (@
{ $physinfo->{sharedphys
} }) {
276 push @
$sharedphys, $parent
277 unless $parent eq $row->{parentphys
};
280 $physinfo->{sharedphys
} = $sharedphys;
283 $self->{itempaths
} = $itempaths;
287 } # End _delete_handler
289 ###############################################################################
291 ###############################################################################
292 sub _recover_handler
{
294 my $row = $self->{row
};
296 my $physname = $row->{physname
};
298 my $physinfo = $gPhysInfo{$physname};
300 if (!defined $physinfo) {
301 $self->{errmsg
} = "Attempt to recover unknown item '$physname':\n"
302 . $self->{physname_seen
};
307 if (defined $physinfo->{parentphys
}) {
308 # Item still has other shares, so recover it by pushing this parent
309 # onto its shared list
311 push( @
{ $physinfo->{sharedphys
} }, $row->{parentphys
} );
314 # Recovering its only location; set the main parent back to this
315 $physinfo->{parentphys
} = $row->{parentphys
};
318 # We only recover the path explicitly set in this row, so build the path
319 # ourself by taking the path of this parent and appending the name
320 my $parentpaths = $self->_get_item_paths($row->{parentphys
}, 1);
321 $self->{itempaths
} = [$parentpaths->[0] . $physinfo->{name
}];
325 } # End _recover_handler
327 ###############################################################################
328 # _get_current_item_paths
329 ###############################################################################
330 sub _get_current_item_paths
{
331 my($self, $mainonly) = @_;
333 return $self->_get_item_paths($self->{row
}->{physname
}, $mainonly);
334 } # End _get_current_item_paths
336 ###############################################################################
338 ###############################################################################
339 sub _get_item_paths
{
340 my($self, $physname, $mainonly) = @_;
342 # Uses recursion to determine the current full paths for an item based on
343 # the name of its physical file. We can't cache this information because
344 # a rename in a parent folder would not immediately trigger a rename in
345 # all of the child items.
347 # By default, we return an anonymous array of all paths in which the item
348 # is shared, unless $mainonly is true. Luckily, only files can be shared,
349 # not projects, so once we start recursing we can set $mainonly to true.
351 if (++($self->{recursed
}) >= 1000) {
352 $self->{errmsg
} = "Infinite recursion detected while looking up "
353 . "parent for '$physname':\n$self->{physname_seen}";
358 if ($physname eq 'AAAAAAAA') {
359 # End of recursion; all items must go back to 'AAAAAAAA', which was so
360 # named because that's what most VSS users yell after using it much. :-)
364 my $physinfo = $gPhysInfo{$physname};
366 if (!defined $physinfo) {
367 $self->{errmsg
} = "Could not determine real path for '$physname':\n"
368 . $self->{physname_seen
};
373 $self->{physname_seen
} .= "$physname, ";
375 my @pathstoget = $mainonly?
($physinfo->{parentphys
}) :
376 ($physinfo->{parentphys
}, @
{ $physinfo->{sharedphys
} } );
381 foreach my $parent (@pathstoget) {
382 if (!defined $parent) {
385 $result = $self->_get_item_paths($parent, 1, 1);
387 if(!defined $result) {
391 push @
$paths, $result->[0] . $physinfo->{name
};
396 } # End _get_item_paths
398 ###############################################################################
399 # _get_current_item_name
400 ###############################################################################
401 sub _get_current_item_name
{
404 my $physname = $self->{row
}->{physname
};
405 my $physinfo = $gPhysInfo{$physname};
407 if (!defined $physinfo) {
408 $self->{errmsg
} = "Could not determine real name for '$physname':\n"
409 . $self->{physname_seen
};
413 return $physinfo->{name
};
414 } # End _get_current_item_name