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 )