File Coverage

blib/lib/Doit/Pip.pm
Criterion Covered Total %
statement 16 36 44.4
branch 1 8 12.5
condition n/a
subroutine 7 10 70.0
pod 3 6 50.0
total 27 60 45.0


line stmt bran cond sub pod time code
1             # -*- perl -*-
2              
3             #
4             # Author: Slaven Rezic
5             #
6             # Copyright (C) 2020 Slaven Rezic. All rights reserved.
7             # This package is free software; you can redistribute it and/or
8             # modify it under the same terms as Perl itself.
9             #
10             # Mail: slaven@rezic.de
11             # WWW: https://github.com/eserte/Doit
12             #
13              
14             package Doit::Pip; # Convention: all commands here should be prefixed with 'pip_'
15              
16 1     1   6 use strict;
  1         2  
  1         27  
17 1     1   4 use warnings;
  1         3  
  1         44  
18              
19             our $VERSION = '0.011';
20              
21 1     1   4 use Doit::Log;
  1         2  
  1         381  
22              
23 1     1 0 8 sub new { bless {}, shift }
24 1     1 0 4 sub functions { qw(pip_install_packages pip_missing_packages can_pip) }
25 0     0 0 0 sub add_component { qw(extcmd) }
26              
27             sub can_pip {
28 1     1 1 318 require Doit::Extcmd;
29 1 50       4 Doit::Extcmd::is_in_path('pip3') ? 1 : 0;
30             }
31              
32             sub pip_install_packages {
33 0     0 1   my($self, @packages) = @_;
34 0           my @missing_packages = $self->pip_missing_packages(@packages);
35 0 0         if (@missing_packages) {
36 0           $self->system('pip3', 'install', @missing_packages);
37             }
38 0           @missing_packages;
39             }
40              
41             sub pip_missing_packages {
42 0     0 1   my($self, @packages) = @_;
43 0           my @missing_packages;
44 0           if (0) { # XXX this is only possible with newer pip versions --- how new?
45             my $stderr;
46             eval {
47             $self->info_open3({
48             quiet => 1,
49             errref => \$stderr,
50             }, 'pip3', 'show', '-q', '--no-color', @packages); # note: --no-color is only available in newer pip versions
51             };
52             if ($stderr) {
53             if ($stderr =~ m{\QWARNING: Package(s) not found:\E\s+(.+)}) {
54             @missing_packages = split /,\s+/, $1;
55             } else {
56             error "Unable to parse stderr output of 'pip3 show': '$stderr'";
57             }
58             }
59             } else {
60 0           if (0) { # XXX this solution would be straightforward --- unfortunately some pip3 versions do not exit with a non-zero status for missing packages
61             for my $package (@packages) {
62             if (!eval { $self->info_open3({quiet=>1}, 'pip3', 'show', '-q', $package); 1 }) {
63             push @missing_packages, $package;
64             }
65             }
66             } else {
67 0           my %seen_package;
68 1     1   7 for my $line (do { no warnings "uninitialized"; split /\n/, eval { $self->info_open3({quiet=>1}, 'pip3', 'show', @packages) } }) {
  1         3  
  1         193  
  0            
  0            
  0            
69 0 0         if ($line =~ /^Name:\s+(\S+)/) {
70 0           $seen_package{$1}++;
71             }
72             }
73 0           for my $package (@packages) {
74 0 0         if (!$seen_package{$package}) {
75 0           push @missing_packages, $package;
76             }
77             }
78             }
79             }
80 0           @missing_packages;
81             }
82              
83             1;
84              
85             __END__