File Coverage

blib/lib/Doit/Pip.pm
Criterion Covered Total %
statement 16 35 45.7
branch 1 8 12.5
condition n/a
subroutine 7 9 77.7
pod 3 5 60.0
total 27 57 47.3


line stmt bran cond sub pod time code
1             # -*- perl -*-
2              
3             #
4             # Author: Slaven Rezic
5             #
6             # Copyright (C) 2020,2022 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         1  
  1         31  
17 1     1   5 use warnings;
  1         2  
  1         46  
18              
19             our $VERSION = '0.012';
20              
21 1     1   5 use Doit::Log;
  1         2  
  1         330  
22              
23 1     1 0 9 sub new { bless {}, shift }
24 1     1 0 4 sub functions { qw(pip_install_packages pip_missing_packages can_pip) }
25              
26             sub can_pip {
27 1     1 1 2 my($self) = @_;
28 1 50       4 $self->which('pip3') ? 1 : 0;
29             }
30              
31             sub pip_install_packages {
32 0     0 1   my($self, @packages) = @_;
33 0           my @missing_packages = $self->pip_missing_packages(@packages);
34 0 0         if (@missing_packages) {
35 0           $self->system('pip3', 'install', @missing_packages);
36             }
37 0           @missing_packages;
38             }
39              
40             sub pip_missing_packages {
41 0     0 1   my($self, @packages) = @_;
42 0           my @missing_packages;
43 0           if (0) { # XXX this is only possible with newer pip versions --- how new?
44             my $stderr;
45             eval {
46             $self->info_open3({
47             quiet => 1,
48             errref => \$stderr,
49             }, 'pip3', 'show', '-q', '--no-color', @packages); # note: --no-color is only available in newer pip versions
50             };
51             if ($stderr) {
52             if ($stderr =~ m{\QWARNING: Package(s) not found:\E\s+(.+)}) {
53             @missing_packages = split /,\s+/, $1;
54             } else {
55             error "Unable to parse stderr output of 'pip3 show': '$stderr'";
56             }
57             }
58             } else {
59 0           if (0) { # XXX this solution would be straightforward --- unfortunately some pip3 versions do not exit with a non-zero status for missing packages
60             for my $package (@packages) {
61             if (!eval { $self->info_open3({quiet=>1}, 'pip3', 'show', '-q', $package); 1 }) {
62             push @missing_packages, $package;
63             }
64             }
65             } else {
66 0           my %seen_package;
67 1     1   7 for my $line (do { no warnings "uninitialized"; split /\n/, eval { $self->info_open3({quiet=>1}, 'pip3', 'show', @packages) } }) {
  1         2  
  1         157  
  0            
  0            
  0            
68 0 0         if ($line =~ /^Name:\s+(\S+)/) {
69 0           $seen_package{$1}++;
70             }
71             }
72 0           for my $package (@packages) {
73 0 0         if (!$seen_package{$package}) {
74 0           push @missing_packages, $package;
75             }
76             }
77             }
78             }
79 0           @missing_packages;
80             }
81              
82             1;
83              
84             __END__