File Coverage

blib/lib/LedgerSMB/Installer/OS/unix.pm
Criterion Covered Total %
statement 23 139 16.5
branch 0 34 0.0
condition n/a
subroutine 8 19 42.1
pod 0 11 0.0
total 31 203 15.2


line stmt bran cond sub pod time code
1             package LedgerSMB::Installer::OS::unix v0.999.11;
2              
3 1     1   1792 use v5.20;
  1         4  
4 1     1   6 use experimental qw(signatures);
  1         4  
  1         7  
5 1     1   157 use parent qw(LedgerSMB::Installer::OS);
  1         2  
  1         9  
6              
7 1     1   68 use Carp qw( croak );
  1         2  
  1         89  
8 1     1   7 use File::Path qw( make_path remove_tree );
  1         2  
  1         63  
9 1     1   6 use File::Spec;
  1         2  
  1         20  
10 1     1   4 use HTTP::Tiny;
  1         3  
  1         25  
11 1     1   5 use Log::Any qw($log);
  1         2  
  1         6  
12              
13              
14 0     0 0   sub pg_config_extra_paths($self) {
  0            
  0            
15 0           my @paths = qw(
16             /opt/pgsql/bin
17             /usr/lib/postgresql/bin
18             /usr/local/pgsql/bin
19             /usr/local/postgres/bin
20             );
21             push @paths, File::Spec->catdir( $ENV{POSTGRES_HOME}, 'bin' )
22 0 0         if $ENV{POSTGRES_HOME};
23             push @paths, File::Spec->catdir( $ENV{POSTGRES_LIB}, File::Spec->updir, 'bin' )
24 0 0         if $ENV{POSTTGRES_LIB};
25 0           return @paths;
26             }
27              
28 0     0 0   sub am_system_perl($self) {
  0            
  0            
29 0           return ($^X eq '/usr/bin/perl');
30             }
31              
32 0     0 0   sub prepare_builder_env($self, $config) {
  0            
  0            
  0            
33 0           warn $log->warning( 'generic Unix/Linux support does not install required module build tools' );
34             }
35              
36 0     0 0   sub prepare_extraction_env($self, $config) {
  0            
  0            
  0            
37 0           $self->have_cmd('gzip'); # fatal, used by 'tar'
38 0           $self->have_cmd('tar'); # fatal
39 0           $self->have_cmd('gpg', $config->verify_sig); # fatal, when verification required
40             }
41              
42 0     0 0   sub prepare_installer_env($self, $config) {
  0            
  0            
  0            
43 0           $self->have_cmd('cpanm', 0);
44 0           $self->have_cmd('make'); # fatal
45             }
46              
47 0     0 0   sub cpanm_install($self, $installpath, $locallib, $unmapped_mods) {
  0            
  0            
  0            
  0            
  0            
48 0 0         unless ($self->{cmd}->{cpanm}) {
49 0           make_path( File::Spec->catdir( $installpath, 'tmp' ) );
50              
51 0           my $http = HTTP::Tiny->new;
52 0           my $r = $http->get( 'https://cpanmin.us/' );
53 0 0         if ($r->{status} == 599) {
    0          
54 0           croak $log->fatal( "Unable to request https://cpanmin.us/: " . $r->{content} );
55             }
56             elsif (not $r->{success}) {
57 0           croak $log->fatal( "Unable to request https://cpanmin.us/: $r->{status} - $r->{reason}" );
58             }
59             else {
60 0           my $cpanm = File::Spec->catfile( $installpath, 'tmp', 'cpanm' );
61 0 0         open( my $fh, '>', $cpanm )
62             or croak $log->fatal( "Unable to open output file tmp/cpanm" );
63 0           binmode $fh, ':raw';
64 0           print $fh $r->{content};
65 0 0         close( $fh ) or warn $log->warning( "Failure closing file tmp/cpanm" );
66 0 0         chmod( 0755, $cpanm ) or warn $log->warning( "Failure making tmp/cpanm executable" );
67 0           $self->{cmd}->{cpanm} = $cpanm;
68             }
69             }
70              
71 0           local $ENV{PERL_CPANM_HOME} = File::Spec->catdir( $installpath, 'tmp' );
72             my @cmd = (
73             $self->{cmd}->{cpanm},
74 0           '--notest',
75             '--metacpan',
76             '--without-recommends',
77             '--local-lib', $locallib,
78             );
79              
80             # install dependencies from 'cpanfile' because that includes
81             # version range restrictions
82 0           my @deps_cmd = (@cmd, '--installdeps', $installpath);
83 0           $log->debug( "system(): " . join(' ', map { "'$_'" } @deps_cmd ) );
  0            
84 0 0         system(@deps_cmd) == 0
85             or croak $log->fatal( "Failure running cpanm - exit code: $?" );
86              
87             # only install modules which were not satisfied from cpanfile
88             # as fallback, because we're missing version range restrictions
89 0           my @mods_cmd = (@cmd, '--skip-satisfied', $unmapped_mods->@*);
90 0           $log->debug( "system(): " . join(' ', map { "'$_'" } @mods_cmd ) );
  0            
91 0 0         system(@mods_cmd) == 0
92             or croak $log->fatal( "Failure running cpanm - exit code: $?" );
93              
94 0           remove_tree( File::Spec->catdir( $installpath, 'tmp' ) );
95             }
96              
97 0     0 0   sub pkgs_from_modules($self, $mods) {
  0            
  0            
  0            
98 0           croak $log->fatal( 'Generic Unix support does not include package installers' );
99             }
100              
101 0     0 0   sub pkg_install($self, $pkgs) {
  0            
  0            
  0            
102 0           croak $log->error( 'Generic linux support does not include package installers' );
103             }
104              
105 0     0 0   sub untar($self, $tar, $target, %options) {
  0            
  0            
  0            
  0            
  0            
106 0           my @cmd = ($self->{cmd}->{tar}, 'xzf', $tar, '-C', $target);
107             push @cmd, ('--strip-components', $options{strip_components})
108 0 0         if $options{strip_components};
109             push @cmd, '--no-same-owner'
110 0 0         if $options{no_same_owner};
111 0           $log->debug( 'system(): ' . join(' ', map { "'$_'" } @cmd ) );
  0            
112 0 0         system(@cmd) == 0
113             or croak $log->fatal( "Failure executing tar - exit code: $?" );
114             }
115              
116 0     0 0   sub verify_sig($self, $installpath, $tar, $sig, $key) {
  0            
  0            
  0            
  0            
  0            
  0            
117 0           my $tempdir = File::Spec->catdir( $installpath, 'tmp' );
118 0           my $gpgdir = File::Spec->catdir( $tempdir, 'gnupg' );
119 0           make_path( $tempdir, $gpgdir );
120 0 0         chmod( 0700, $gpgdir )
121             or warn $log->warning( "Unable to protect $gpgdir: $!" );
122              
123             my @cmd = (
124             $self->{cmd}->{gpg},
125 0           '--quiet',
126             '--homedir', $gpgdir,
127             '--no-autostart',
128             '--batch',
129             '--no-tty',
130             '--yes',
131             '--trust-model', 'always',
132             '--no-default-keyring',
133             '--keyring',
134             File::Spec->catfile( $tempdir, 'verification-keyring.kbx' ),
135             );
136              
137 0           $log->trace( "Importing key:\n$key" );
138 0           $log->debug( 'system(): ' . join( ' ', map { "'$_'" } (@cmd, '--import') ) );
  0            
139 0 0         open(my $fh, '|-', @cmd, '--import')
140             or die "Can't open pipe to gpg for download verification: $!";
141 0           print $fh $key;
142 0 0         close($fh) or warn "Error closing pipe to gpg on key import: $!";
143              
144 0           $log->debug( 'system(): ' . join( ' ', map { "'$_'" } (@cmd, '--verify', $sig, $tar) ) );
  0            
145 0 0         system( @cmd, '--verify', $sig, $tar ) == 0
146             or croak $log->fatal( "Failure to verify gpg signature - exit code: $?" );
147              
148 0           remove_tree( $tempdir );
149              
150 0           $log->info( 'gpg signature validated correctly' );
151             }
152              
153 0     0 0   sub generate_start_script($self, $installpath, $locallib) {
  0            
  0            
  0            
  0            
154             ###TODO: capture file open error
155 0           my $script = File::Spec->catfile( $installpath, 'server-start' );
156 0           open( my $fh, '>', $script );
157 0           my $starman = $self->have_cmd( 'starman', 0, [ File::Spec->catdir( $locallib, 'bin' ) ] );
158 0           my $locallib_lib = File::Spec->catdir( $locallib, 'lib', 'perl5' );
159              
160 0           say $fh <<~EOF;
161             #!/usr/bin/bash
162              
163             cd $installpath
164             exec $^X \\
165             -I $installpath/lib \\
166             -I $installpath/old/lib \\
167             -I $locallib_lib \\
168             $starman \\
169             --listen 0.0.0.0:5762 \\
170             --workers \${LSMB_WORKERS:-5} \\
171             --preload-app bin/ledgersmb-server.psgi
172             EOF
173             ###TODO: capture mode change error
174 0           chmod( 0755, $script );
175             }
176              
177             1;