1#! /usr/bin/perl 2# Copyright (c) 2005-2010 Marc Espie <espie@openbsd.org> 3# $OpenBSD: pkg_mklocatedb,v 1.48 2023/05/29 07:35:39 espie Exp $ 4# 5# Permission to use, copy, modify, and distribute this software for any 6# purpose with or without fee is hereby granted, provided that the above 7# copyright notice and this permission notice appear in all copies. 8# 9# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 17use v5.36; 18no lib ('/usr/local/libdata/perl5/site_perl'); 19 20use OpenBSD::PackageInfo; 21use OpenBSD::PackingList; 22use OpenBSD::Getopt; 23use OpenBSD::Error; 24use OpenBSD::Paths; 25use OpenBSD::AddCreateDelete; 26 27package OpenBSD::Pkgmklocatedb::State; 28our @ISA = qw(OpenBSD::AddCreateDelete::State); 29 30sub handle_options($state) 31{ 32 $state->{no_exports} = 1; 33 $state->SUPER::handle_options('ad:Knqp:Pu', 34 '[-aKnPqu] [-d repository] [-p portsdir] [pkg-name ...]'); 35 $state->{portsdir} = $state->opt('p'); 36 $state->{pkgdir} = $state->opt('d'); 37 $state->{quiet} = $state->opt('q'); 38 $state->{pkgpath} = $state->opt('P'); 39 $state->{allinfo} = $state->opt('a'); 40 $state->{nopipe} = $state->opt('n'); 41 $state->{full} = $state->opt('K'); 42 $state->{update} = $state->opt('u'); 43} 44 45package OpenBSD::PackingElement; 46sub print_name($, $) {} 47sub set_header($, $) {} 48 49package OpenBSD::PackingElement::Name; 50sub set_header($self, $state) 51{ 52 $state->{currentheader} = $self->{name}.':'; 53} 54 55package OpenBSD::PackingElement::ExtraInfo; 56sub set_header($self, $state) 57{ 58 if ($state->{allinfo}) { 59 $state->{currentheader} .= $self->{subdir}.':'; 60 } elsif ($state->{pkgpath}) { 61 $state->{currentheader} = $self->{subdir}.':'; 62 } 63 $state->{done}{$self->{subdir}} = 1; 64 $state->errsay($state->{currentheader}) unless $state->{quiet}; 65} 66 67package OpenBSD::PackingElement::FileObject; 68sub object_name($self, $state) 69{ 70 if ($state->{full}) { 71 if ($self->needs_keyword) { 72 return "\@".$self->keyword." ".$self->fullname; 73 } 74 } 75 return $self->fullname; 76} 77 78sub print_name($self, $state) 79{ 80 print {$state->{out}} $state->{currentheader}, 81 $self->object_name($state), "\n"; 82} 83 84package OpenBSD::PackingElement::Action; 85sub print_name($self, $state) 86{ 87 print {$state->{out}} $state->{currentheader}, $self->fullstring, "\n"; 88} 89 90package OpenBSD::PackingElement::ExeclikeAction; 91sub print_name($self, $state) 92{ 93 print {$state->{out}} $state->{currentheader}, "\@". 94 $self->keyword, " ", $self->{expanded}, "\n"; 95} 96 97package OpenBSD::PackingElement::Conflict; 98sub print_name 99{ 100 &OpenBSD::PackingElement::Action::print_name; 101} 102 103package OpenBSD::PackingElement::NoDefaultConflict; 104sub print_name 105{ 106 &OpenBSD::PackingElement::Action::print_name; 107} 108 109package OpenBSD::PackingElement::TagBase; 110sub print_name($self, $state) 111{ 112 print {$state->{out}} $state->{currentheader}, "\@". 113 join(' ', $self->keyword, $self->name, $self->{params}), "\n"; 114} 115 116package OpenBSD::PackingElement::Tag; 117sub print_name($self, $state) 118{ 119 print {$state->{out}} $state->{currentheader}, "\@". 120 join(' ', $self->keyword, $self->name, $self->{expanded}), "\n"; 121} 122 123package OpenBSD::PackingElement::DirBase; 124sub print_name($self, $state) 125{ 126 print {$state->{out}} $state->{currentheader}, 127 $self->object_name($state), "/\n"; 128} 129 130package main; 131 132sub open_output($state) 133{ 134 if ($state->{nopipe} or -t STDOUT) { 135 $state->{out} = \*STDOUT; 136 } else { 137 my $MKLOCATEDB = OpenBSD::Paths->mklocatedb; 138 139 open $state->{out}, "|-", $MKLOCATEDB, $MKLOCATEDB or 140 $state->fatal("couldn't open pipe to mklocatedb: #1", $!); 141 } 142} 143 144sub print_out($plist, $state) 145{ 146 $plist->set_header($state); 147 $plist->print_name($state); 148} 149 150sub do_portsdir($state) 151{ 152 my $make = $ENV{MAKE} || 'make'; 153 my $target = defined $ENV{SUBDIRLIST} ? 154 'print-plist' : 'print-plist-all'; 155 delete $ENV{FLAVOR}; 156 delete $ENV{SUBPACKAGE}; 157 open my $in, "cd $state->{portsdir} && $make $target |"; 158 my $done = 0; 159 while (!$done) { 160 my $plist = OpenBSD::PackingList->read($in, 161 sub { 162 my ($fh, $cont) = @_; 163 while (<$fh>) { 164 return if m/^\=\=\=\> /o; 165 &$cont($_); 166 } 167 $done = 1; 168 }); 169 if (defined $plist && defined $plist->pkgname) { 170 print_out($plist, $state); 171 } 172 } 173 close($in); 174} 175 176sub do_pkgdir($state) 177{ 178 require File::Find; 179 no warnings qw(once); 180 $state->fatal("Bad argument: #1 is not a directory", $state->{pkgdir}) 181 unless -d $state->{pkgdir}; 182 File::Find::find( 183 sub() { 184 return unless -f $_; 185 my $plist = $state->repo->grabPlist($File::Find::name); 186 return unless defined $plist; 187 print_out($plist, $state); 188 }, $state->{pkgdir}); 189} 190 191sub copy_stdin($state) 192{ 193 while (<STDIN>) { 194 # if we find something that looks like a pkgpath we've done 195 # assume we were updating it 196 if (m,([^:]*/[^:]*)\:,) { 197 next if defined $state->{done}{$1}; 198 } 199 print {$state->{out}} $_; 200 } 201} 202 203my $state = OpenBSD::Pkgmklocatedb::State->new; 204$state->handle_options; 205 206open_output($state); 207 208if ($state->{fatals}) { 209 $state->fatal("Files not found, can't continue"); 210} 211 212if ($state->{portsdir}) { 213 do_portsdir($state); 214} elsif ($state->{pkgdir}) { 215 do_pkgdir($state); 216} elsif (@ARGV == 0) { 217 if (!$state->{update}) { 218 $state->progress->for_list("Scanning installation", 219 [installed_packages()], sub { 220 my $pkgname = shift; 221 my $plist = 222 OpenBSD::PackingList->from_installation($pkgname); 223 return unless defined $plist; 224 print_out($plist, $state); 225 }); 226 } 227} else { 228 $state->progress->for_list("Scanning packages", \@ARGV, 229 sub { 230 my $pkgname = shift; 231 my $plist = $state->repo->grabPlist($pkgname); 232 next unless $plist; 233 print_out($plist, $state); 234 }); 235} 236if ($state->{update}) { 237 copy_stdin($state); 238} 239