1# ex:ts=8 sw=4:
2# $OpenBSD: AddCreateDelete.pm,v 1.57 2023/10/23 08:38:14 espie Exp $
3#
4# Copyright (c) 2007-2014 Marc Espie <espie@openbsd.org>
5#
6# Permission to use, copy, modify, and distribute this software for any
7# purpose with or without fee is hereby granted, provided that the above
8# copyright notice and this permission notice appear in all copies.
9#
10# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17#
18
19use v5.36;
20
21# common behavior to pkg_add, pkg_delete, pkg_create
22
23package OpenBSD::AddCreateDelete::State;
24our @ISA = qw(OpenBSD::State);
25
26use OpenBSD::State;
27use OpenBSD::ProgressMeter;
28
29sub init($self, @p)
30{
31	$self->{progressmeter} = OpenBSD::ProgressMeter->new;
32	$self->{bad} = 0;
33	$self->SUPER::init(@p);
34	$self->{export_level}++;
35}
36
37sub progress($self)
38{
39	return $self->{progressmeter};
40}
41
42sub not($self)
43{
44	return $self->{not};
45}
46
47sub sync_display($self)
48{
49	$self->progress->clear;
50}
51
52sub add_interactive_options($self)
53{
54	$self->{has_interactive_options} = 1;
55	return $self;
56}
57
58my $setup = {
59	nowantlib => q'
60	    	use OpenBSD::Dependencies::SolverBase;
61		no warnings qw(redefine);
62		package OpenBSD::Dependencies::SolverBase;
63		sub solve_wantlibs($, $) { 1 }
64	    ',
65	nosystemwantlib => q'
66	    	use OpenBSD::LibSpec;
67		package OpenBSD::Library::System;
68		sub no_match_dispatch($library, $spec, $base)
69		{
70			return $spec->no_match_name($library, $base);
71		}
72	    ',
73	norun => q'
74		package OpenBSD::State;
75		sub _system(@) { 0 }
76	    ',
77};
78
79
80sub handle_options($state, $opt_string, @usage)
81{
82	my $i;
83
84	if ($state->{has_interactive_options}) {
85		$opt_string .= 'iI';
86		$state->{opt}{i} = sub() {
87			$i++;
88		};
89	};
90
91	$state->SUPER::handle_options($opt_string.'L:mnx', @usage);
92
93	$state->progress->setup($state->opt('x'), $state->opt('m'), $state);
94	$state->{not} = $state->opt('n');
95	if ($state->{has_interactive_options}) {
96		if ($state->opt('I')) {
97			$i = 0;
98		} elsif (!defined $i) {
99			$i = -t STDIN;
100		}
101	}
102	$state->{interactive} = $state->interactive_class($i)->new($state, $i);
103	if ($state->defines('REGRESSION_TESTING')) {
104		for my $i (split(/[,\s]/,
105		    $state->defines('REGRESSION_TESTING'))) {
106			$state->{regression}{$i} = 1;
107			if (defined $setup->{$i}) {
108				eval "$setup->{$i}";
109				if ($@) {
110					$state->fatal(
111					    "Regression testing #1: #2",
112					    $i, $@);
113				}
114			}
115		}
116	}
117}
118
119sub interactive_class($, $i)
120{
121	if ($i) {
122		require OpenBSD::Interactive;
123		return 'OpenBSD::Interactive';
124	} else {
125		return 'OpenBSD::InteractiveStub';
126	}
127}
128
129sub is_interactive($self)
130{
131	return $self->{interactive}->is_interactive;
132}
133
134sub find_window_size($state)
135{
136	$state->SUPER::find_window_size;
137	$state->{progressmeter}->compute_playfield;
138}
139
140sub handle_continue($state)
141{
142	$state->SUPER::handle_continue;
143	$state->{progressmeter}->handle_continue;
144}
145
146sub confirm_defaults_to_no($self, @p)
147{
148	return $self->{interactive}->confirm($self->f(@p), 0);
149}
150
151sub confirm_defaults_to_yes($self, @p)
152{
153	return $self->{interactive}->confirm($self->f(@p), 1);
154}
155
156sub ask_list($self, @p)
157{
158	return $self->{interactive}->ask_list(@p);
159}
160
161sub vsystem($self, @p)
162{
163	if ($self->verbose < 2) {
164		$self->system(@p);
165	} else {
166		$self->verbose_system(@p);
167	}
168}
169
170sub system($self, @p)
171{
172	$self->SUPER::system(@p);
173}
174
175sub run_makewhatis($state, $opts, $l)
176{
177	my $braindead = sub() { chdir('/'); };
178	while (@$l > 1000) {
179		my @b = splice(@$l, 0, 1000);
180		$state->vsystem($braindead,
181		    OpenBSD::Paths->makewhatis, @$opts, '--', @b);
182	}
183	$state->vsystem($braindead,
184	    OpenBSD::Paths->makewhatis, @$opts, '--', @$l);
185}
186
187# TODO this stuff is definitely not as clear as it could be
188sub ntogo($self, $offset = 0)
189{
190	return $self->{wantntogo} ?
191	    $self->progress->ntogo($self, $offset) :
192	    $self->f("ok");
193}
194
195sub ntogo_string($self, $offset = 0)
196{
197	return $self->{wantntogo} ?
198	    $self->f(" (#1)", $self->ntodo($offset)) :
199	    $self->f("");
200}
201
202sub solve_dependency($self, $solver, $dep, $package)
203{
204	return $solver->really_solve_dependency($self, $dep, $package);
205}
206
207package OpenBSD::AddCreateDelete;
208use OpenBSD::Error;
209
210sub handle_options($self, $opt_string, $state, @usage)
211{
212	$state->handle_options($opt_string, $self, @usage);
213}
214
215sub try_and_run_command($self, $state)
216{
217	if ($state->defines('pkg-debug')) {
218		$self->run_command($state);
219	} else {
220		try {
221			$self->run_command($state);
222		} catch {
223			$state->errsay("#1: #2", $state->{cmd}, $_);
224			OpenBSD::Handler->reset;
225			if ($_ =~ m/^Caught SIG(\w+)/o) {
226				kill $1, $$;
227			}
228			$state->{bad}++;
229		};
230	}
231}
232
233package OpenBSD::InteractiveStub;
234sub new($class, $, $)
235{
236	bless {}, $class;
237}
238
239sub ask_list($, $, @values)
240{
241	return $values[0];
242}
243
244sub confirm($, $, $yesno)
245{
246	return $yesno;
247}
248
249sub is_interactive($)
250{
251	return 0;
252}
2531;
254