#-*- 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;