File Coverage

blib/lib/Doit/Brew.pm
Criterion Covered Total %
statement 13 67 19.4
branch 1 30 3.3
condition 0 17 0.0
subroutine 6 11 54.5
pod 0 7 0.0
total 20 132 15.1


line stmt bran cond sub pod time code
1             # -*- perl -*-
2              
3             #
4             # Author: Slaven Rezic
5             #
6             # Copyright (C) 2017,2018,2022,2024,2025,2026 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             # WWW: https://github.com/eserte/Doit
11             #
12              
13             package Doit::Brew; # Convention: all commands here should be prefixed with 'brew_'
14              
15 1     1   5 use strict;
  1         2  
  1         27  
16 1     1   4 use warnings;
  1         1  
  1         42  
17             our $VERSION = '0.016';
18              
19 1     1   4 use Doit::Log;
  1         0  
  1         798  
20              
21 1     1 0 9 sub new { bless {}, shift }
22 1     1 0 4 sub functions { qw(brew_install_packages brew_missing_packages can_brew brew_get_cellar brew_without) }
23              
24             sub can_brew {
25 1     1 0 2 my($self) = @_;
26 1 50       3 $self->which('brew') ? 1 : 0;
27             }
28              
29             sub brew_install_packages {
30 0     0 0   my($self, @packages) = @_;
31 0           my @missing_packages = $self->brew_missing_packages(@packages);
32 0 0         if (@missing_packages) {
33 0           $self->system('brew', 'install', @missing_packages);
34             }
35 0           @missing_packages;
36             }
37              
38             {
39             my $cached_cellar;
40              
41             sub brew_missing_packages {
42 0     0 0   my($self, @packages) = @_;
43              
44 0   0       $cached_cellar ||= $self->brew_get_cellar;
45              
46 0           my @missing_packages;
47 0           for my $package (@packages) {
48 0 0         my $formula_name = $package =~ m{.*/(.+)$} ? $1 : $package;
49 0 0 0       if (!defined $cached_cellar || !-d "$cached_cellar/$formula_name") {
50 0           push @missing_packages, $package;
51             }
52             }
53 0           @missing_packages;
54             }
55             }
56              
57             sub brew_get_cellar {
58 0     0 0   my($self) = @_;
59              
60             # First try environment variables (fastest, no external command called)
61 0 0 0       return $ENV{HOMEBREW_CELLAR} if defined $ENV{HOMEBREW_CELLAR} && -d $ENV{HOMEBREW_CELLAR};
62 0 0 0       return "$ENV{HOMEBREW_PREFIX}/Cellar" if defined $ENV{HOMEBREW_PREFIX} && -d "$ENV{HOMEBREW_PREFIX}/Cellar";
63              
64             # Heuristics depending on architcture
65 0           chomp(my $arch = eval { $self->info_qx({quiet => 1}, qw(uname -m)) });
  0            
66 0 0         my @cellar_candidates = ($arch eq 'arm64' ? ('/opt/homebrew/Cellar', '/usr/local/Cellar') : ('/usr/local/Cellar', '/opt/homebrew/Cellar'));
67 0           for my $cellar_candidate (@cellar_candidates) {
68 0 0         return $cellar_candidate if -d $cellar_candidate;
69             }
70              
71             # use brew config (maybe slow?)
72 0           for my $line (split /\n/, eval { $self->info_qx({quiet=>1}, 'brew', 'config') }) {
  0            
73 0 0         if ($line =~ /^\s*HOMEBREW_PREFIX:\s*(.*)/) {
74 0           my $cellar = "$1/Cellar";
75 0 0         return $cellar if -d $cellar;
76 0           last;
77             }
78             }
79              
80 0           warning "Can't find homebrew cellar, expect homebrew-related things to fail.";
81 0           return undef;
82             }
83              
84             sub brew_without {
85 0     0 0   my($self, @args) = @_;
86              
87 0 0 0       my %options; if (@args && ref $args[0] eq 'HASH') { %options = %{ shift @args } }
  0            
  0            
  0            
88 0           my $quiet = delete $options{quiet};
89 0 0         error "Unhandled options: " . join(" ", %options) if %options;
90              
91 0           my $code = shift @args;
92              
93 0 0         error "Too many arguments to brew_without() call" if @args;
94              
95 0 0         my @brew_prefixes = grep { defined && length }
96             $ENV{HOMEBREW_PREFIX},
97 0           '/home/linuxbrew/.linuxbrew', # Linux
98             '/opt/homebrew', # macOS Apple Silicon
99             ## not activated --- /usr/local may be used for non-brew stuff
100             # '/usr/local', # macOS Intel
101             ;
102 0           @brew_prefixes = do { my %seen; grep { !$seen{$_}++ } @brew_prefixes }; # dedup
  0            
  0            
  0            
103              
104             my $new_path = join ':',
105             grep {
106 0           my $p = $_;
107 0           !grep { $p =~ m{^\Q$_\E(?:/|$)} } @brew_prefixes
  0            
108             }
109 0   0       split /:/, ($ENV{PATH} || '');
110              
111 0           local %ENV = %ENV;
112              
113             {
114             # XXX hack: setenv+unsetenv do not have a quiet options, so make info() temporarily silent
115 0 0   0     local *Doit::Log::info = $quiet ? sub {} : \&Doit::Log::info;
  0            
116 0           $self->setenv(PATH => $new_path);
117 0           $self->unsetenv($_) for qw(
118             HOMEBREW_PREFIX
119             HOMEBREW_CELLAR
120             HOMEBREW_REPOSITORY
121             );
122             }
123              
124 0           $code->();
125             }
126              
127             1;
128              
129             __END__