File Coverage

blib/lib/Ixchel.pm
Criterion Covered Total %
statement 23 102 22.5
branch 0 30 0.0
condition 0 24 0.0
subroutine 8 19 42.1
pod 2 2 100.0
total 33 177 18.6


line stmt bran cond sub pod time code
1             package Ixchel;
2              
3 1     1   90204 use 5.006;
  1         4  
4 1     1   5 use strict;
  1         15  
  1         64  
5 1     1   6 use warnings;
  1         4  
  1         101  
6 1     1   761 use Template;
  1         21448  
  1         38  
7 1     1   516 use File::ShareDir ":ALL";
  1         28913  
  1         172  
8 1     1   648 use Getopt::Long;
  1         10167  
  1         5  
9 1     1   645 use Ixchel::DefaultConfig;
  1         2  
  1         34  
10 1     1   573 use Hash::Merge;
  1         7802  
  1         1506  
11              
12             =head1 NAME
13              
14             Ixchel - Automate various sys admin stuff.
15              
16             =head1 VERSION
17              
18             Version 0.13.0
19              
20             =cut
21              
22             our $VERSION = '0.13.0';
23              
24             =head1 METHODS
25              
26             =head2 new
27              
28             Initiates a new instance of Ixchel.
29              
30             One option argument is taken and that is a hash ref
31             named config.
32              
33             my $ixchel=Ixchel->new( config=>$config );
34              
35             If config is defined, it will be merged with Ixchel::DefaultConfig via
36             Hash::Merge using the following behavior.
37              
38             {
39             'SCALAR' => {
40             'SCALAR' => sub { $_[1] },
41             'ARRAY' => sub { [ $_[0], @{ $_[1] } ] },
42             'HASH' => sub { $_[1] },
43             },
44             'ARRAY' => {
45             'SCALAR' => sub { $_[1] },
46             'ARRAY' => sub { [ @{ $_[1] } ] },
47             'HASH' => sub { $_[1] },
48             },
49             'HASH' => {
50             'SCALAR' => sub { $_[1] },
51             'ARRAY' => sub { [ values %{ $_[0] }, @{ $_[1] } ] },
52             'HASH' => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) },
53             },
54             }
55              
56             Using this, the passed config will be merged into the default config. Worth noting
57             that any arrays in the default config will be completely replaced by the array from
58             the passed config.
59              
60             =cut
61              
62             sub new {
63 0     0 1   my ( $empty, %opts ) = @_;
64              
65 0           my $self = {
66             t => Template->new(
67             {
68             EVAL_PERL => 1,
69             INTERPOLATE => 0,
70             POST_CHOMP => 1,
71             ABSOLUTE => 1,
72             RELATIVE => 1,
73             INCLUDE_PATH => dist_dir("Ixchel") . '/templates/',
74             }
75             ),
76             share_dir => dist_dir("Ixchel"),
77             options_array => undef,
78             errors_count => 0,
79             };
80 0           bless $self;
81              
82 0           my %default_config = %{ Ixchel::DefaultConfig->get };
  0            
83 0 0         if ( defined( $opts{config} ) ) {
84 0           my $merger = Hash::Merge->new('RIGHT_PRECEDENT');
85             # make sure arrays from the actual config replace any arrays in the defaultconfig
86             $merger->add_behavior_spec(
87             {
88             'SCALAR' => {
89 0     0     'SCALAR' => sub { $_[1] },
90 0     0     'ARRAY' => sub { [ $_[0], @{ $_[1] } ] },
  0            
91 0     0     'HASH' => sub { $_[1] },
92             },
93             'ARRAY' => {
94 0     0     'SCALAR' => sub { $_[1] },
95 0     0     'ARRAY' => sub { [ @{ $_[1] } ] },
  0            
96 0     0     'HASH' => sub { $_[1] },
97             },
98             'HASH' => {
99 0     0     'SCALAR' => sub { $_[1] },
100 0     0     'ARRAY' => sub { [ values %{ $_[0] }, @{ $_[1] } ] },
  0            
  0            
101 0     0     'HASH' => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) },
102             },
103             },
104 0           'Ixchel',
105             );
106 0           my %tmp_config = %{ $opts{config} };
  0            
107 0           my %tmp_shash = %{ $merger->merge( \%default_config, \%tmp_config ) };
  0            
108              
109 0           $self->{config} = \%tmp_shash;
110             } else {
111 0           $self->{config} = \%default_config;
112             }
113              
114 0           return $self;
115             } ## end sub new
116              
117             =head2 action
118              
119             The action to perform.
120              
121             - action :: The action to perform. This a required variable.
122             Default :: undef
123              
124             - opts :: What to pass for opts. If not defined, GetOptions will be used to parse the options
125             based on the options as defined by the action in question. If passing one manually this
126             should be be a hash ref as would be return via GetOptions.
127             Default :: undef
128              
129             - argv :: What to use for ARGV instead of @ARGV.
130             Default :: undef
131              
132             - no_die_on_error :: If the return from the action is a hash ref, check if $returned->{errors} is a array
133             if it is then it will die with those be used in the die message.
134             Default :: 1
135              
136             So if you want to render the template akin to '-a template -t extend_logsize' you can do it like below.
137              
138             my $rendered_template=$ixchel->action( action=>'template', opts=>{ t=>'extend_logsize' });
139              
140             Now if we want to pass '--np' to not print it, we would do it like below.
141              
142             my $rendered_template=$ixchel->action( action=>'template', opts=>{ t=>'extend_logsize', np=>1 });
143              
144             If the following values are defined, the matching ENVs are set.
145              
146             .proxy.ftp -> FTP_PROXY, ftp_proxy
147             .proxy.http -> HTTP_PROXY, http_proxy
148             .proxy.https -> HTTPS_PROXY, https_proxy
149             .perl.cpanm_home -> PERL_CPANM_HOME
150              
151             Additionally any of the variables defined under .env will also be
152             set. So .env.TMPDIR will set $ENV{TMPDIR}.
153              
154             =cut
155              
156             sub action {
157 0     0 1   my ( $self, %opts ) = @_;
158              
159 0 0         if ( !defined( $opts{action} ) ) {
160 0           die('No action defined');
161             }
162 0           my $action = $opts{action};
163              
164 0 0         if ( !defined( $opts{no_die_on_error} ) ) {
165 0           $opts{no_die_on_error} = 1;
166             }
167              
168             # if custom opts are not defined, read the commandline args and fetch what we should use
169 0           my $opts_to_use;
170 0 0         if ( !defined( $opts{opts} ) ) {
171 0           my %parsed_options;
172             # split it appart and remove comments and blank lines
173             my $opts_data;
174 0           my $to_eval = 'use Ixchel::Actions::' . $action . '; $opts_data=Ixchel::Actions::' . $action . '->opts_data;';
175 0           eval($to_eval);
176 0 0         if ( defined($opts_data) ) {
177 0           my @options = split( /\n/, $opts_data );
178 0           @options = grep( !/^#/, @options );
179 0           @options = grep( !/^$/, @options );
180 0           GetOptions( \%parsed_options, @options );
181             }
182 0           $opts_to_use = \%parsed_options;
183             } else {
184 0           $opts_to_use = $opts{opts};
185             }
186              
187             # if custom ARGV is specified, use taht
188 0           my $argv_to_use;
189 0 0         if ( defined( $opts{ARGV} ) ) {
190 0           $argv_to_use = $opts{ARGV};
191             } else {
192 0           $argv_to_use = \@ARGV;
193             }
194              
195             # pass various vars if specified
196 0           my $vars;
197 0 0         if ( defined( $opts{vars} ) ) {
198 0           $vars = $opts{vars};
199             }
200              
201             # set the enviromental variables if needed
202 0 0 0       if ( defined( $self->{config}{proxy}{ftp} ) && $self->{config}{proxy}{ftp} ne '' ) {
203 0           $ENV{FTP_PROXY} = $self->{config}{proxy}{ftp};
204 0           $ENV{ftp_proxy} = $self->{config}{proxy}{ftp};
205             }
206 0 0 0       if ( defined( $self->{config}{proxy}{http} ) && $self->{config}{proxy}{http} ne '' ) {
207 0           $ENV{HTTP_PROXY} = $self->{config}{proxy}{http};
208 0           $ENV{http_proxy} = $self->{config}{proxy}{http};
209             }
210 0 0 0       if ( defined( $self->{config}{proxy}{https} ) && $self->{config}{proxy}{https} ne '' ) {
211 0           $ENV{HTTPS_PROXY} = $self->{config}{proxy}{https};
212 0           $ENV{https_proxy} = $self->{config}{proxy}{https};
213             }
214 0 0 0       if ( defined( $self->{config}{perl}{cpanm_home} ) && $self->{config}{perl}{cpanm_home} ne '' ) {
215 0           $ENV{PERL_CPANM_HOME} = $self->{config}{perl}{cpanm_home};
216             }
217 0           my @env_keys = keys( %{ $self->{config}{env} } );
  0            
218 0           foreach my $env_key (@env_keys) {
219 0 0 0       if ( defined( $self->{config}{env}{$env_key} ) && ref( $self->{config}{env}{$env_key} ) eq '' ) {
220 0           $ENV{$env_key} = $self->{config}{env}{$env_key};
221             }
222             }
223              
224 0           my $action_return;
225             my $action_obj;
226 0           my $to_eval
227             = 'use Ixchel::Actions::'
228             . $action
229             . '; $action_obj=Ixchel::Actions::'
230             . $action
231             . '->new(config=>$self->{config}, t=>$self->{t}, share_dir=>$self->{share_dir}, opts=>$opts_to_use, argv=>$argv_to_use, ixchel=>$self, vars=>$vars,);'
232             . '$action_return=$action_obj->action;';
233 0           eval($to_eval);
234 0 0         if ($@) {
235 0           die( 'Action eval failed... ' . $@ );
236             }
237              
238 0 0         if ( $opts{no_die_on_error} ) {
239 0 0 0       if ( ref($action_return) eq 'HASH'
      0        
      0        
240             && defined( $action_return->{errors} )
241             && ref( $action_return->{errors} ) eq 'ARRAY'
242             && defined( $action_return->{errors}[0] ) )
243             {
244 0           die( 'Action returned one or more errors... ' . join( "\n", @{ $action_return->{errors} } ) );
  0            
245             }
246             }
247              
248 0           return $action_return;
249             } ## end sub action
250              
251             =head1 AUTHOR
252              
253             Zane C. Bowers-Hadley, C<< >>
254              
255             =head1 BUGS
256              
257             Please report any bugs or feature requests to C, or through
258             the web interface at L. I will be notified, and then you'll
259             automatically be notified of progress on your bug as I make changes.
260              
261              
262              
263              
264             =head1 SUPPORT
265              
266             You can find documentation for this module with the perldoc command.
267              
268             perldoc Ixchel
269              
270              
271             You can also look for information at:
272              
273             =over 4
274              
275             =item * RT: CPAN's request tracker (report bugs here)
276              
277             L
278              
279             =item * Search CPAN
280              
281             L
282              
283             =item * Github
284              
285             L
286              
287             =back
288              
289             =head1 ACKNOWLEDGEMENTS
290              
291              
292             =head1 LICENSE AND COPYRIGHT
293              
294             This software is Copyright (c) 2023 by Zane C. Bowers-Hadley.
295              
296             This is free software, licensed under:
297              
298             The GNU General Public License, Version 3, June 2007
299              
300              
301             =cut
302              
303             1; # End of Ixchel