App-Pods2Site

 view release on metacpan or  search on metacpan

lib/App/Pods2Site/Args.pm  view on Meta::CPAN

# Parses a commandline packaged as a list (e.g. normally just pass @ARGV)
# and processes it into real objects for later use by various functions
# in the Pods2Site universe
#
package App::Pods2Site::Args;

use strict;
use warnings;

our $VERSION = '1.003';
my $version = $VERSION;
$VERSION = eval $VERSION;

use App::Pods2Site::Util qw(slashify trim readData writeData expandAts $IS_PACKED $IS_WINDOWS $SHELL_ARG_DELIM $PATH_SEP);
use App::Pods2Site::SiteBuilderFactory;

use Config;
use FindBin qw($RealBin $Script);
use Getopt::Long qw(GetOptionsFromArray :config require_order no_ignore_case bundling);
use File::Spec;
use File::Basename;
use File::Temp qw(tempdir);
use File::Path qw(make_path);
use Config qw(%Config);
use Pod::Usage;
use Pod::Simple::Search;
use List::MoreUtils qw(uniq);
use Grep::Query;
use POSIX;

# CTOR
#
sub new
{
	my $class = shift;
	my $version = shift;

	my $self = bless( {}, $class);
	$self->__parseArgv($version, @_);

	return $self;
}

sub getSiteDir
{
	my $self = shift;
	
	return $self->{sitedir};
}

sub getBinDirs
{
	my $self = shift;
	
	return @{$self->{bindirs}};
}

sub getLibDirs
{
	my $self = shift;
	
	return @{$self->{libdirs}};
}

sub getTitle
{
	my $self = shift;
	
	return $self->{title};
}

sub getMainpage
{
	my $self = shift;

	return $self->{mainpage};
}

sub getStyle
{
	my $self = shift;
	
	return $self->{style};
}

sub getUpdating
{
	my $self = shift;

	return $self->{updating};
}

sub getWorkDir
{
	my $self = shift;
	
	return $self->{workdir};
}

sub getGroupDefs
{
	my $self = shift;
	
	return $self->{groupdefs};
}

sub getCSS
{
	my $self = shift;
	
	return $self->{css};
}

sub getSiteBuilder
{
	my $self = shift;
	
	return $self->{sitebuilder};
}

sub isVerboseLevel
{
	my $self = shift;
	my $level = shift;
	
	return $self->{verbose} >= $level;	
}

# PRIVATE
#

# these options are persisted to the site
# and can't be used when updating
#
my @STICKYOPTS =
	qw
		(
			bindirectory
			libdirectory
			group
			css
			style
			title
			mainpage
		);

sub __parseArgv
{
	my $self = shift;
	my $version = shift;
	my @argv = @_;

	my %rawOpts =
		(
			usage => 0,
			help => 0,
			manual => 0,
			v => 0,
			workdirectory => undef,
			quiet => 0,
			
			# hidden
			#
			_help => 0,
			_pp => 0,					# print basic PAR::Packer 'pp' command line
		);
		
	my @specs =
		(
			'usage|?',
			'help',
			'manual',
			'version',
			'v|verbose+',
			'workdirectory=s',
			'quiet',
			'bindirectory=s@',
			'libdirectory=s@',
			'group=s@',
			'css=s',
			'style=s',
			'title=s',
			'mainpage=s',
			
			# hidden
			#
			'_help',
			'_pp',
		);

	my $_argsPodName = 'App/Pods2Site/_Args.pod';
	my $_argsPodInput = Pod::Simple::Search->find($_argsPodName);
	my $argsPodName = 'App/Pods2Site/Args.pod';
	my $argsPodInput = Pod::Simple::Search->find($argsPodName);
	my $manualPodName = 'App/Pods2Site.pod';
	my $manualPodInput = Pod::Simple::Search->find($manualPodName);

	# for consistent error handling below, trap getopts problems
	# 
	eval
	{
		@argv = expandAts('.', @argv);
		local $SIG{__WARN__} = sub { die(@_) };
		GetOptionsFromArray(\@argv, \%rawOpts, @specs)
	};
	if ($@)
	{
		pod2usage(-input => $argsPodInput, -message => "Failure parsing options:\n  $@", -exitval => 255, -verbose => 0);
	}

	# help with the hidden flags...
	#
	pod2usage(-input => $_argsPodInput, -exitval => 0, -verbose => 2, -noperldoc => 1) if $rawOpts{_help};

	# for the special selection of using --_pp, print command line and exit
	#
	if ($rawOpts{_pp})
	{
		$self->__print_pp_cmdline
					(
						$version,
						$argsPodName, $argsPodInput,
						$manualPodName, $manualPodInput
					);
		exit(0);
	}

	# if any of the doc switches made, display the pod
	#
	pod2usage(-input => $manualPodInput, -exitval => 0, -verbose => 2, -noperldoc => 1) if $rawOpts{manual};
	pod2usage(-input => $argsPodInput, -exitval => 0, -verbose => 2, -noperldoc => 1) if $rawOpts{help};
	pod2usage(-input => $argsPodInput, -exitval => 0, -verbose => 0) if $rawOpts{usage};
	pod2usage(-message => slashify($0) . " version $App::Pods2Site::VERSION", -exitval => 0, -verbose => 99, -sections => '_') if $rawOpts{version};

	# if -quiet has been given, it trumps any verbosity
	#	
	$self->{verbose} = $rawOpts{quiet} ? -1 : $rawOpts{v};

	# manage the sitedir
	# assume we need to create it
	#
	$self->{newsitedir} = 1;
	my $sitedir = $self->__getSiteDir($argv[0]);
	die("You must provide a sitedir (use ':std' for a default location)\n") unless $sitedir;
	$sitedir = slashify(File::Spec->rel2abs($sitedir));
	if (-e $sitedir)
	{
		$self->{newsitedir} = 0;
		
		# if the sitedir exists as a dir, our sticky opts better be found in it
		# otherwise it's not a sitedir
		#
		die("The output '$sitedir' exists, but is not a directory\n") unless -d $sitedir;
		my $savedOpts = readData($sitedir, 'opts');
		die("The sitedir '$sitedir' exists, but is missing our marker file\n") unless $savedOpts;
		$self->{updating} = 1;
		# clean up any sticky opts given by the user
		#
		print "NOTE: updating '$sitedir' - reusing options used when created!\n" if $self->isVerboseLevel(0);
		foreach my $opt (@STICKYOPTS)
		{
			warn("WARNING: The option '$opt' ignored when updating the existing site '$sitedir'\n") if exists($rawOpts{$opt});
			delete($rawOpts{$opt});
		}
		%rawOpts = ( %rawOpts, %$savedOpts );
	}
	else
	{
		print "Creating '$sitedir'...\n" if $self->isVerboseLevel(0);
		$self->{updating} = 0;
	}
	
	# fix up any user given bindir locations or get us the standard ones
	#
	my @bindirs = uniq($self->__getBinLocations($rawOpts{bindirectory}));
	warn("WARNING: No bin directories found\n") unless @bindirs;
	$self->{bindirs} = $rawOpts{bindirectory} = \@bindirs;

	# fix up any user given libdir locations or get us the standard ones
	#
	my @libdirs = uniq($self->__getLibLocations($rawOpts{libdirectory}));
	warn("WARNING: No lib directories found\n") unless @libdirs;
	$self->{libdirs} = $rawOpts{libdirectory} = \@libdirs;

	my $workdir;
	if ($rawOpts{workdirectory})
	{
		# if user specifies a workdir this implies that it should be kept
		# just make sure there is no such directory beforehand, and create it here
		# (similar to below; tempdir() will also create one)
		#
		$workdir = slashify(File::Spec->rel2abs($rawOpts{workdirectory}));
		die("The workdir '$workdir' already exists\n") if -e $workdir;
		make_path($workdir) or die("Failed to create workdir '$workdir': $!\n");
	}
	else
	{
		# create a temp dir; use automatic cleanup
		#
		$workdir = slashify(tempdir("pods2site-XXXX", TMPDIR => 1, CLEANUP => 1));
	}
	$self->{workdir} = $workdir;

	# Ensure we have group definitions, and test queries before storing
	# 
	my @rawGroupDefs  = $self->__getRawGroupDefs($rawOpts{group});
	my @groupDefs;
	my %groupsSeen;
	foreach my $rawGroupDef (@rawGroupDefs)
	{
		eval
		{
			die("Group definition not in form 'name=query': '$rawGroupDef'\n") unless $rawGroupDef =~ /^([^=]*)=(.+)/s;
			my ($name, $query) = (trim($1 || ''), trim($2));
			die("Group '$name' multiply defined\n") if $groupsSeen{$name};
			$groupsSeen{$name} = 1;
			push(@groupDefs, { name => $name, query => Grep::Query->new($query) });
		};
		pod2usage(-message => "Problem with group definition '$rawGroupDef':\n  $@", -exitval => 255, -verbose => 0) if $@;
	}
	$rawOpts{group} = \@rawGroupDefs;
	$self->{groupdefs} = \@groupDefs;

	# fix up any css path given by user
	#	
	if ($rawOpts{css})
	{
		my $css = slashify(File::Spec->rel2abs($rawOpts{css}));
		die("No such file: -css '$css'\n") unless -f $css;
		$self->{css} = $css;
	}

	$rawOpts{title} = $rawOpts{title} || 'Pods2Site';
	$self->{title} = $rawOpts{title};
	
	$rawOpts{mainpage} = $rawOpts{mainpage} || ':std';
	$self->{mainpage} = $rawOpts{mainpage};



( run in 1.595 second using v1.01-cache-2.11-cpan-2398b32b56e )