Astro-App-Satpass2
view release on metacpan or search on metacpan
lib/Astro/App/Satpass2.pm view on Meta::CPAN
use strict;
use warnings;
use Astro::App::Satpass2::Locale qw{ __localize };
use Astro::App::Satpass2::Macro::Command;
use Astro::App::Satpass2::Macro::Code;
use Astro::App::Satpass2::ParseTime;
use Astro::App::Satpass2::Utils qw{
:os
:ref
__arguments __legal_options
expand_tilde find_package_pod
has_method instance load_package
my_dist_config quoter
__parse_class_and_args
};
use Astro::Coord::ECI 0.077; # This needs at least 0.049.
use Astro::Coord::ECI::Moon 0.077;
use Astro::Coord::ECI::Star 0.077;
use Astro::Coord::ECI::Sun 0.077;
use Astro::Coord::ECI::TLE 0.077 qw{:constants}; # This needs at least 0.059.
use Astro::Coord::ECI::TLE::Set 0.077;
# The following includes @CARP_NOT.
use Astro::Coord::ECI::Utils 0.112 qw{ :all }; # This needs at least 0.112.
{
local $@ = undef;
use constant HAVE_TLE_IRIDIUM => eval {
require Astro::Coord::ECI::TLE::Iridium;
Astro::Coord::ECI::TLE::Iridium->VERSION( 0.077 );
1;
} || 0;
# Unfortunately the alias code creates the alias even if the version
# is unacceptable; so we may have to just delete the Iridium aliases
unless( HAVE_TLE_IRIDIUM ) {
my %type_map = Astro::Coord::ECI::TLE->alias();
foreach my $name ( keys %type_map ) {
$type_map{$name} eq 'Astro::Coord::ECI::TLE::Iridium'
and Astro::Coord::ECI::TLE->alias( $name, undef );
}
}
}
use Attribute::Handlers;
use Clone ();
use Cwd ();
use File::Glob qw{ :glob };
use File::HomeDir;
use File::Spec;
use File::Temp;
use Getopt::Long 2.33;
use IO::File 1.14;
use IO::Handle;
use POSIX qw{ floor };
use Scalar::Util 1.26 qw{ blessed isdual openhandle };
use Text::Abbrev;
use Text::ParseWords (); # Used only for {level1} stuff.
use constant ASTRO_SPACETRACK_VERSION => 0.105;
use constant DEFAULT_STDOUT_LAYERS => ':encoding(utf-8)';
BEGIN {
eval {
load_package( 'Time::y2038' )
and Time::y2038->import();
1;
}
or do {
require Time::Local;
Time::Local->import();
};
}
# The following is returned by method _attribute_value() when a
# non-existent attribute is specified. We can't use undef for this,
# because the attribute might really be undef.
# NOTE that this used to be just bless \( $x = undef ) ..., but blead
# Perl 6a011f13d7690dbe2e03ad7500756c983bcb1834 did not like this
# (modificatoin of read-only variable).
use constant NULL => do {
my $x = undef;
bless \$x, 'Null';
};
# The canonical way to see if $rslt actually contains the above is
# NULL_REF eq ref $rslt
use constant NULL_REF => ref NULL;
use constant SUN_CLASS_DEFAULT => 'Astro::Coord::ECI::Sun';
our $VERSION = '0.058';
# The following 'cute' code is so that we do not determine whether we
# actually have optional modules until we really need them, and yet do
# not repeat the process once it is done.
my $have_time_hires;
$have_time_hires = sub {
my $value = load_package( 'Time::HiRes' );
$have_time_hires = sub { return $value };
return $value;
};
my $have_astro_spacetrack;
$have_astro_spacetrack = sub {
my $value = load_package( { lib => undef }, 'Astro::SpaceTrack' ) && eval {
Astro::SpaceTrack->VERSION( ASTRO_SPACETRACK_VERSION );
1;
};
$have_astro_spacetrack = sub { $value };
return $value;
};
my $default_geocoder;
$default_geocoder = sub {
my $value =
_can_use_geocoder( 'Astro::App::Satpass2::Geocode::OSM'
);
$default_geocoder = sub { return $value };
return $value;
};
sub _can_use_geocoder {
my ( $geocoder ) = @_;
my $pkg = load_package( $geocoder )
or return;
load_package( $pkg->GEOCODER_CLASS() )
or return;
return $pkg;
}
my $interrupted = 'Interrupted by user.';
my %twilight_def = (
civil => deg2rad (-6),
nautical => deg2rad (-12),
astronomical => deg2rad (-18),
);
my %twilight_abbr = abbrev (keys %twilight_def);
# Individual commands are defined by subroutines of the same name,
# and having the Verb attribute. You can specify additional
# attributes if you need to. Following are descriptions of the
# attributes used by this script.
#
# Configure(configurations)
#
# The 'Configure' attribute specifies options to be passed to
# Getopt::Long::Configure before the options are parsed. For
# example, if a command wants to keep unrecognized options on the
# command you would specify:
# sub foo : Configure(pass_through) Verb
#
# Tokenize(options)
#
# The 'Tokenize' attribute specifies tokenizatino options. These
# can not take effect until fairly late in the parse when the
# tokens are known. These options are parsed by Getopt::Long, and
# the value of the attribute is a reference to the options hash
# thus generated. Possible options are:
# -expand_tilde - Expand tildes in the tokens. For historical
# reasons this is the default, but it can be negated by
# specifying -noexpand_tilde. Tildes in redirect
# specifications are always expanded.
#
# Tweak(options)
#
lib/Astro/App/Satpass2.pm view on Meta::CPAN
sub _set_pass_variant {
my ( $self, $name, $val ) = @_;
if ( $val =~ m/ \A (?: 0 x? ) [0-9]* \z /smx ) {
$val = oct $val;
} elsif ( $val !~ m/ \A [0-9]+ \z /smx ) {
my @args = split qr{ [^\w-] }smx, $val;
foreach ( @args ) {
s/ \A (?! - ) /-/smx;
}
$go ||= Getopt::Long::Parser->new();
$val = $self->get( $name );
$go->getoptionsfromarray( \@args,
none => sub { $val = PASS_VARIANT_NONE },
map { $_ => sub {
my ( $name, $value ) = @_;
my $mask = $variant_def{$name};
if ( $value ) {
$val |= $mask;
} else {
$val &= ~ $mask;
}
return;
}
} @option_names )
or $self->wail( "Invalid $name value '$val'" );
}
return ( $self->{$name} = $val );
}
sub _show_pass_variant {
my ( $self, $name ) = @_;
my $val = $self->get( $name );
my @options;
foreach my $key ( keys %variant_def ) {
$val & $variant_def{$key}
and push @options, "$key";
}
@options
or push @options, 'none';
return ( set => $name, join ',', @options );
}
sub want_pass_variant {
my ( $self, $variant ) = @_;
$variant_def{$variant}
or $self->wail( "Invalid pass_variant name '$variant'" );
my $val = $self->get( 'pass_variant' ) & $variant_def{$variant};
return $val;
}
}
sub _set_spacetrack {
my ($self, $name, $val) = @_;
if (defined $val) {
instance($val, 'Astro::SpaceTrack')
or $self->wail("$name must be an Astro::SpaceTrack instance");
my $version = $val->VERSION();
$version =~ s/ _ //smxg;
$version >= ASTRO_SPACETRACK_VERSION
or $self->wail("$name must be Astro::SpaceTrack version ",
ASTRO_SPACETRACK_VERSION, ' or greater' );
}
return ($self->{$name} = $val);
}
sub _set_stdout {
my ($self, $name, $val) = @_;
$self->{frame}
and $self->{frame}[-1]{$name} = $val;
return ($self->{$name} = $val);
}
sub _set_sun_class {
my ( $self, $name, $val ) = @_;
$self->_attribute_exists( $name );
return $self->sky( class => $name, $val );
}
sub _set_time_parser {
my ( $self, $name, $val ) = @_;
if ( CODE_REF eq ref $val ) {
$val = _set_time_parser_code( $val );
} elsif ( defined $val and my $macro = $self->{macro}{$val} ) {
$val = _set_time_parser_code(
$macro->implements( $val, required => 1 ),
$val,
);
}
return $self->_set_copyable(
name => $name,
value => $val,
class => 'Astro::App::Satpass2::ParseTime',
message => 'Unknown time parser',
default => 'Astro::App::Satpass2::ParseTime',
nocopy => 1,
prefix => [ 'Astro::App::Satpass2::ParseTime' ],
);
}
sub _set_time_parser_attribute {
my ( $self, $name, $val ) = @_;
defined $val and $val eq 'undef' and $val = undef;
$self->{time_parser}->$name( $val );
return $val;
}
sub _set_time_parser_code {
my ( $code, $name ) = @_;
require Astro::App::Satpass2::ParseTime::Code;
my $obj = Astro::App::Satpass2::ParseTime::Code->new();
return $obj->code( $code, $name );
}
_frame_pop_force_set ( 'twilight' ); # Force use of the set() method
# in _frame_pop(), because we
# need to set {_twilight} as
# well.
sub _set_twilight {
my ($self, $name, $val) = @_;
lib/Astro/App/Satpass2.pm view on Meta::CPAN
if ( ARRAY_REF eq ref $status ) {
Astro::Coord::ECI::TLE->status (clear => 'iridium');
foreach (@$status) {
Astro::Coord::ECI::TLE->status (add => $_->[0], iridium =>
$_->[4], $_->[1], $_->[3]);
}
} else {
$self->weep(
'Portable status not passed, and unavailable from Astro::SpaceTrack'
);
}
foreach my $tle (@{$self->{bodies}}) {
$tle->rebless ();
}
return;
}
# _is_case_tolerant()
# Returns true if the OS supports case-tolerant file names. Yes, I know
# it's the file system that is important, but I don't have access to
# that level of detail.
{
my %os = map { $_ => 1 } qw{ darwin };
sub _is_case_tolerant {
exists $os{$^O}
and return $os{$^O};
return File::Spec->case_tolerant();
}
}
# _is_interactive()
#
# Returns true if the dispatch() method is above us on the call
# stack, otherwise returns false.
use constant INTERACTIVE_CALLER => __PACKAGE__ . '::dispatch';
sub _is_interactive {
my $level = 0;
while ( my @info = caller( $level ) ) {
INTERACTIVE_CALLER eq $info[3]
and return $level;
$level++;
}
return;
}
# $self->_load_module ($module_name)
# Loads the module if it has not yet been loaded. Dies if it
# can not be loaded.
{ # Begin local symbol block
my %version;
BEGIN {
%version = (
'Astro::SpaceTrack' => ASTRO_SPACETRACK_VERSION,
);
}
sub _load_module {
my ($self, @module) = @_;
ARRAY_REF eq ref $module[0]
and @module = @{$module[0]};
@module or $self->weep( 'No module specified' );
my @probs;
foreach my $module (@module) {
load_package ($module) or do {
push @probs, "$module needed";
next;
};
my $modver;
($version{$module} && ($modver = $module->VERSION)) and do {
$modver =~ s/_//g;
$modver < $version{$module} and do {
push @probs,
"$module version $version{$module} needed";
next;
};
};
return $module;
}
{
my $inx = 1;
while (my @clr = caller($inx++)) {
$clr[3] eq '(eval)' and next;
my @raw = split '::', $clr[3];
substr ($raw[-1], 0, 1) eq '_' and next;
push @probs, "for method $raw[-1]";
last;
}
}
my $pfx = 'Error -';
$self->wail(map {my $x = "$pfx $_\n"; $pfx = ' ' x 7; $x} @probs);
return; # Can't get here, but Perl::Critic does not know this.
}
} # end local symbol block.
# $output = $self->_macro($name,@args)
#
# Execute the named macro. The @args are of course optional.
sub _macro {
my ($self, $name, @args) = @_;
$self->{macro}{$name} or $self->wail("No such macro as '$name'");
my $frames = $self->_frame_push(macro => [@args]);
my $macro = $self->{frame}[-1]{macro}{$name} =
delete $self->{macro}{$name};
my $output;
my $err;
my $ok = eval {
$output = $macro->execute( $name, @args );
1;
} or $err = $@;
$self->_frame_pop($frames);
$ok or $self->wail($err);
( run in 1.235 second using v1.01-cache-2.11-cpan-e1769b4cff6 )