Skip to content

Commit

Permalink
Item13313: Report pub attachement subdirectories
Browse files Browse the repository at this point in the history
This patch modifies the Store API to allow the caller to request
subdirectory names along with attachmnent names. When a stream is opened
on a directory, Store throws an error so that change_store can
report a subdirectory that was not copied.
  • Loading branch information
gac410 committed Apr 12, 2015
1 parent 5844822 commit c438434
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 49 deletions.
20 changes: 17 additions & 3 deletions RCSStoreContrib/lib/Foswiki/Store/Rcs/Handler.pm
Expand Up @@ -1285,6 +1285,12 @@ sub openStream {
if ( $mode =~ />/ ) {
$this->mkPathTo( $this->{file} );
}
if ( -d $this->{file} ) {
throw Error::Simple( 'Rcs::Handler: stream open '
. $this->{file}
. ' failed: '
. 'Read requested on directory.' );
}
unless ( open( $stream, $mode, $this->{file} ) ) {
throw Error::Simple( 'Rcs::Handler: stream open '
. $this->{file}
Expand Down Expand Up @@ -1386,18 +1392,26 @@ sub synchroniseAttachmentsList {

=begin TML
---++ ObjectMethod getAttachmentList() -> @list
---++ ObjectMethod getAttachmentList( $incDir ) -> @list
Get list of attachment names actually stored for topic.
$incDir, if true, will cause subdirectories of the pub attachment directory
to be included in the list. This is used by change_store to report
sub-directories that were not copied into the new store. This is not used in
normal Foswiki operation.
=cut

sub getAttachmentList {
my $this = shift;
my $dir = "$Foswiki::cfg{PubDir}/$this->{web}/$this->{topic}";
my $incDir =
shift; # Internal flag for change_store, returns directory names.
my $dir = "$Foswiki::cfg{PubDir}/$this->{web}/$this->{topic}";
my $dh;
opendir( $dh, $dir ) || return ();
my @files = grep { !/^[.*_]/ && !/,v$/ && -f "$dir/$_" } readdir($dh);
my @files =
grep { !/^[.*_]/ && !/,v$/ && ( $incDir || -f "$dir/$_" ) } readdir($dh);
closedir($dh);
return @files;
}
Expand Down
8 changes: 6 additions & 2 deletions RCSStoreContrib/lib/Foswiki/Store/Rcs/Store.pm
Expand Up @@ -687,10 +687,14 @@ sub getApproxRevTime {
}

sub eachAttachment {
my ( $this, $topicObject ) = @_;
my ( $this, $topicObject, $incDir ) = @_;

# $incDir flag is used by change_store.pl to find subdirectories that
# cannot be converted into the new store. It is not used during normal
# Foswiki operation

my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
my @list = $handler->getAttachmentList();
my @list = $handler->getAttachmentList($incDir);
require Foswiki::ListIterator;
return new Foswiki::ListIterator( \@list );
}
Expand Down
8 changes: 7 additions & 1 deletion core/lib/Foswiki/Store.pm
Expand Up @@ -766,7 +766,7 @@ sub recordChange {
=begin TML
---++ ObjectMethod eachAttachment( $topicObject ) -> \$iterator
---++ ObjectMethod eachAttachment( $topicObject, $incDir ) -> \$iterator
Return an iterator over the list of attachments stored for the given
topic. This will get a list of the attachments actually stored for the
Expand All @@ -776,6 +776,12 @@ visible to the user.
the iterator iterates over attachment names.
$incDir is an internal flag used by the change_store utility. When set,
the store will also return directory names, not just filenames. When read,
Store will throw an error. This allows convert_store to warn of subdirectories
that exist on disk, and are not changed. Note that $incDir is only
implemented by the RCS based store. It is ignored by PlainFile store
=cut
sub eachAttachment {
Expand Down
102 changes: 59 additions & 43 deletions core/tools/change_store.pl
Expand Up @@ -3,6 +3,7 @@
use warnings;

use Assert;
use Error qw( :try );

use Foswiki ();
use Foswiki::Users::BaseUserMapping ();
Expand Down Expand Up @@ -328,7 +329,7 @@ sub validate_info {
# it iterates over all files in the pub dir in these file-based
# stores.
#
my $att_it = $source_store->eachAttachment($top_meta);
my $att_it = $source_store->eachAttachment( $top_meta, 1 );
die $source_store unless defined $att_it;
while ( $att_it->hasNext() ) {
my $att_name = $att_it->next();
Expand Down Expand Up @@ -381,52 +382,67 @@ sub validate_info {
}

# avoid copying the same rev twice
no warnings 'uninitialized';
next if $att_tx{"$att_name:$att_version"};
$att_tx{"$att_name:$att_version"} = 1;
use warnings 'uninitialized';

try {
my $stream =
$source_store->openAttachment( $top_meta, $att_name, '<',
version => $att_version );

if ($validate) {
my $path = $top_meta->getPath() . ":$topic_version";
no warnings 'uninitialized';
$path .= "/$att_name:$att_version";
use warnings 'uninitialized';

# Ensure getVersionInfo are consistent
my $source_info =
$source_store->getVersionInfo( $top_meta,
$att_version, $att_name );

switch_dirs(1);

# Reread the meta from the target store
my $target_info =
$target_store->getVersionInfo( $top_meta,
$att_version, $att_name );
switch_dirs(0);

# Case 3: The META:FILEATTACHMENT carries date and author
# fields. However these can drift from the history due
# to changes to attachments not reflected in the topic
# meta-data. So the only source we trust is
# getVersionInfo().
validate_info( $path, $source_info, $target_info );

my $stream =
$source_store->openAttachment( $top_meta, $att_name, '<',
version => $att_version );

if ($validate) {
my $path = $top_meta->getPath() . ":$topic_version";
$path .= "/$att_name:$att_version";

# Ensure getVersionInfo are consistent
my $source_info =
$source_store->getVersionInfo( $top_meta, $att_version,
$att_name );

switch_dirs(1);

# Reread the meta from the target store
my $target_info =
$target_store->getVersionInfo( $top_meta, $att_version,
$att_name );
switch_dirs(0);

# Case 3: The META:FILEATTACHMENT carries date and author
# fields. However these can drift from the history due
# to changes to attachments not reflected in the topic
# meta-data. So the only source we trust is
# getVersionInfo().
validate_info( $path, $source_info, $target_info );

}
else {
switch_dirs(1);

# Save attachment
print "... copy attachment $att_name rev $att_version"
. " as $att_user\n"
if $verbose;

# SMELL: there's no way to force the date of the
# copied attachment
$target_store->saveAttachment( $top_meta, $att_name,
$stream, $att_user );
switch_dirs(0);
}
else {
switch_dirs(1);

# Save attachment
no warnings 'uninitialized';
print "... copy attachment $att_name rev $att_version"
. " as $att_user\n"
if $verbose;
use warnings 'uninitialized';

# SMELL: there's no way to force the date of the
# copied attachment
$target_store->saveAttachment( $top_meta, $att_name,
$stream, $att_user );
switch_dirs(0);
}
}
catch Error::Simple with {
my $e = shift;

#print STDERR $e->stringify();
print STDERR
"ATTACHMENT IS A DIRECTORY: Sub-directory $att_name of $web_name.$top_name NOT COPIED!\n";
};
}
}
}
Expand Down

0 comments on commit c438434

Please sign in to comment.