#-*- perl -*- # # Copyright (C) 2003,2004,2005,2006 Ken'ichi Fukamachi # All rights reserved. # # $FML: Spool.pm,v 1.14 2006/04/16 07:03:48 fukachan Exp $ # package FML::Article::Spool; use strict; use Carp; use vars qw($debug @ISA @EXPORT @EXPORT_OK); use FML::Config; my $debug = 0; =head1 NAME FML::Article::Spool -- utilities to maintain the spool directory. =head1 SYNOPSIS =head1 DESCRIPTION This class provides utilitiy functions to maintain the spool directory. =head1 METHODS =head2 new($curproc) constructor. =cut # Descriptions: constructor. # Arguments: OBJ($self) OBJ($curproc) # Side Effects: none # Return Value: OBJ sub new { my ($self, $curproc) = @_; my ($type) = ref($self) || $self; # we use methods provided by article object. use FML::Article; my $article = new FML::Article $curproc; my $me = { _curproc => $curproc, _article => $article, }; return bless $me, $type; } # Descriptions: return lock channel name. # Arguments: OBJ($self) # Side Effects: none # Return Value: STR sub get_lock_channel_name { my ($self) = @_; my $obj = $self->{ _article }; # inherit lock channel name from FML::Article; return $obj->get_lock_channel_name(); } # Descriptions: convert files at src_dir/ into dst_dir/. # Arguments: OBJ($self) OBJ($curproc) OBJ($command_context) # Side Effects: none # Return Value: none sub convert { my ($self, $curproc, $command_context) = @_; my $wh = $command_context->{ _output_channel } || \*STDOUT; my $article = $self->{ _article }; my $src_dir = $command_context->{ _src_dir } || ''; my $dst_dir = $command_context->{ _dst_dir } || ''; my $ml_name = $command_context->get_ml_name(); my $channel = $self->get_lock_channel_name(); my $use_link = 0; $curproc->lock($channel); print $wh "convert $ml_name ML spool.\n\n"; # sanity unless ($src_dir) { croak("\$src_dir not defined.");} unless ($dst_dir) { croak("\$dst_dir not defined.");} unless ($src_dir && -d $src_dir) { croak("\$src_dir not found.");} unless ($dst_dir && -d $dst_dir) { croak("\$dst_dir not found.");} if ($src_dir eq $dst_dir) { $src_dir .= ".old"; rename($dst_dir, $src_dir); $curproc->mkdir($dst_dir, "mode=private"); $use_link = 1; } print $wh "converting $dst_dir from $src_dir\n"; use File::Spec; use DirHandle; my $dh = new DirHandle $src_dir; if (defined $dh) { my $source = ''; my $entry; ENTRY: while (defined($entry = $dh->read)) { next ENTRY if $entry =~ /^\./o; $source = File::Spec->catfile($src_dir, $entry); # XXX-TODO: incorrect logic ??? (we can handle subdir properly?) if (-d $source) { print $wh " $source is a subdir.\n"; } elsif (-f $source) { my $subdirpath = $article->subdirpath($entry); my $filepath = $article->filepath($entry); next ENTRY if -f $filepath; # may conflict $subdirpath (directory) name with # $source file name. e.g. spool/1 (file) vs spool/1 (subdir) if (-f $subdirpath) { croak("$subdirpath file/dir conflict"); } else { unless (-d $subdirpath) { $curproc->mkdir($subdirpath, "mode=private"); } if (-d $subdirpath) { if ($use_link) { link($source, $filepath); } else { $curproc->copy($source, $filepath); } } else { croak("cannot mkdir $filepath\n"); } } if (-f $filepath) { print $wh " $source -> $filepath\n"; } else { print $wh " Error: fail to move $source -> $filepath\n"; } } } } print $wh "done.\n\n"; $curproc->unlock($channel); } # Descriptions: show information on spool and articles. # Arguments: OBJ($self) OBJ($curproc) OBJ($command_context) # Side Effects: none # Return Value: none sub status { my ($self, $curproc, $command_context) = @_; my $wh = $command_context->{ _output_channel } || \*STDOUT; my $dst_dir = $command_context->{ _dst_dir }; my $suffix = ''; my ($num_files, $num_dirs) = $self->_scan_dir( $dst_dir ); print $wh "spool directory = $dst_dir\n"; $suffix = $num_files > 1 ? 's' : ''; printf $wh "%20d %s\n", $num_files, "file$suffix"; $suffix = $num_dirs > 1 ? 's' : ''; printf $wh "%20d %s\n", $num_dirs, "subdir$suffix"; } # Descriptions: return directory information. # Arguments: OBJ($self) STR($dir) # Side Effects: none # Return Value: ARRAY(NUM, NUM) sub _scan_dir { my ($self, $dir) = @_; my $num_dirs = 0; my $num_files = 0; use File::Spec; use DirHandle; my $dh = new DirHandle $dir; if (defined $dh) { my ($file, $entry); ENTRY: while (defined($entry = $dh->read)) { next ENTRY if $entry =~ /^\./o; $file = File::Spec->catfile($dir, $entry); if (-f $file) { $num_files++; } elsif (-d $file) { $num_dirs++; my ($x_num_files, $x_num_dirs) = $self->_scan_dir( $file ); $num_files += $x_num_files; $num_dirs += $x_num_dirs; } } } return ($num_files, $num_dirs); } =head1 CODING STYLE See C on fml coding style guide. =head1 AUTHOR Ken'ichi Fukamachi =head1 COPYRIGHT Copyright (C) 2003,2004,2005,2006 Ken'ichi Fukamachi All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 HISTORY Core functions of FML::Process::Spool is moved to FML::Article::Spool at 2003/03. FML::Article::Spool first appeared in fml8 mailing list driver package. See C for more details. =cut 1;