AFS-Command
view release on metacpan or search on metacpan
lib/AFS/Command/Base.pm view on Meta::CPAN
# This hack is necessary to support the offline/online "hidden"
# vos commands. These won't show up in the normal help output,
# so we have to check for them individually. Since offline and
# online are implemented as a pair, we can just check one of
# them, and assume the other is there, too.
#
foreach my $type ( qw(default hidden) ) {
if ( $type eq 'hidden' ) {
next unless $self->isa("AFS::Command::VOS");
}
my $pipe = IO::Pipe->new() || do {
$self->_Carp("Unable to create pipe: $ERRNO\n");
return;
};
my $pid = fork();
unless ( defined $pid ) {
$self->_Carp("Unable to fork: $ERRNO\n");
return;
}
if ( $pid == 0 ) {
STDERR->fdopen( STDOUT->fileno(), "w" ) ||
$self->_Croak("Unable to redirect stderr: $ERRNO\n");
STDOUT->fdopen( $pipe->writer()->fileno(), "w" ) ||
$self->_Croak("Unable to redirect stdout: $ERRNO\n");
if ( $type eq 'default' ) {
exec @{$self->{command}}, 'help';
} else {
exec @{$self->{command}}, 'offline', '-help';
}
die "Unable to exec @{$self->{command}} help: $ERRNO\n";
} else {
$pipe->reader();
while ( defined($_ = $pipe->getline()) ) {
if ( $type eq 'default' ) {
next if /Commands are:/;
my ($command) = split;
next if $command =~ /^(apropos|help)$/;
$operations{$command}++;
} else {
if ( /^Usage:/ ) {
$operations{offline}++;
$operations{online}++;
}
}
}
}
unless ( waitpid($pid,0) ) {
$self->_Carp("Unable to get status of child process ($pid)");
return;
}
if ( $? ) {
$self->_Carp("Error running @{$self->{command}} help. Unable to configure $class");
return;
}
}
$self->{_operations} = \%operations;
}
return $self->{_operations}->{$operation};
}
sub _arguments {
my $self = shift;
my $operation = shift;
my $arguments =
{
optional => {},
required => {},
aliases => {},
};
my @command;
push (@command, @{$self->{command}});
unless ( $self->_operations($operation) ) {
$self->_Carp("Unsupported @command operation '$operation'\n");
return;
}
return $self->{_arguments}->{$operation}
if ref $self->{_arguments}->{$operation} eq 'HASH';
my $pipe = IO::Pipe->new() || do {
$self->_Carp("Unable to create pipe: $ERRNO");
return;
};
my $pid = fork();
my $errors = 0;
unless ( defined $pid ) {
$self->_Carp("Unable to fork: $ERRNO");
return;
}
if ( $pid == 0 ) {
STDERR->fdopen( STDOUT->fileno(), "w" ) ||
die "Unable to redirect stderr: $ERRNO\n";
STDOUT->fdopen( $pipe->writer()->fileno(), "w" ) ||
lib/AFS/Command/Base.pm view on Meta::CPAN
$pipe->reader();
while ( <$pipe> ) {
if ( /Unrecognized operation '$operation'/ ) {
$self->_Carp("Unsupported @command operation '$operation'\n");
$errors++;
last;
}
next unless s/^Usage:.*\s+$operation\s+//;
while ( $_ ) {
if ( s/^\[\s*-(\w+?)\s*\]\s*// ) {
$arguments->{optional}->{$1} = 0
unless $1 eq 'help'; # Yeah, skip it...
} elsif ( s/^\[\s*-(\w+?)\s+<[^>]*?>\+\s*]\s*// ) {
$arguments->{optional}->{$1} = [];
} elsif ( s/^\[\s*-(\w+?)\s+<[^>]*?>\s*]\s*// ) {
$arguments->{optional}->{$1} = 1;
} elsif ( s/^\s*-(\w+?)\s+<[^>]*?>\+\s*// ) {
$arguments->{required}->{$1} = [];
} elsif ( s/^\s*-(\w+?)\s+<[^>]*?>\s*// ) {
$arguments->{required}->{$1} = 1;
} elsif ( s/^\s*-(\w+?)\s*// ) {
$arguments->{required}->{$1} = 0;
} else {
$self->_Carp("Unable to parse @command help for $operation\n" .
"Unrecognized string: '$_'");
$errors++;
last;
}
}
last;
}
}
#
# XXX -- Hack Alert!!!
#
# Because some asshole decided to change the force option to vos
# release from -f to -force, you can't use the API tranparently
# with 2 different vos binaries that support the 2 different options.
#
# If we need more of these, we can add them, as this let's us
# alias one argument to another.
#
if ( $self->isa("AFS::Command::VOS") && $operation eq 'release' ) {
if ( exists $arguments->{optional}->{f} ) {
$arguments->{aliases}->{force} = 'f';
} elsif ( exists $arguments->{optional}->{force} ) {
$arguments->{aliases}->{f} = 'force';
}
}
unless ( waitpid($pid,0) ) {
$self->_Carp("Unable to get status of child process ($pid)");
$errors++;
}
if ( $? ) {
$self->_Carp("Error running @command $operation -help. Unable to configure @command $operation");
$errors++;
}
return if $errors;
return $self->{_arguments}->{$operation} = $arguments;
}
sub _save_stderr {
my $self = shift;
$self->{olderr} = IO::File->new(">&STDERR") || do {
$self->_Carp("Unable to dup stderr: $ERRNO");
return;
};
my $command = basename((split /\s+/,@{$self->{command}})[0]);
$self->{tmpfile} = "/tmp/.$command.$self->{operation}.$$";
my $newerr = IO::File->new(">$self->{tmpfile}") || do {
$self->_Carp("Unable to open $self->{tmpfile}: $ERRNO");
return;
};
STDERR->fdopen( $newerr->fileno(), "w" ) || do {
$self->_Carp("Unable to reopen stderr: $ERRNO");
return;
};
$newerr->close() || do {
$self->_Carp("Unable to close $self->{tmpfile}: $ERRNO");
return;
};
return 1;
}
sub _restore_stderr {
my $self = shift;
STDERR->fdopen( $self->{olderr}->fileno(), "w") || do {
$self->_Carp("Unable to restore stderr: $ERRNO");
return;
};
$self->{olderr}->close() || do {
$self->_Carp("Unable to close saved stderr: $ERRNO");
return;
};
delete $self->{olderr};
( run in 0.424 second using v1.01-cache-2.11-cpan-39bf76dae61 )