# ex:ts=8 sw=4: # $OpenBSD: Handle.pm,v 1.42 2017/03/07 16:21:28 espie Exp $ # # Copyright (c) 2007-2009 Marc Espie # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # fairly non-descriptive name. Used to store various package information # during installs and updates. use strict; use warnings; package OpenBSD::Handle; use OpenBSD::PackageInfo; use OpenBSD::Error; use constant { BAD_PACKAGE => 1, CANT_INSTALL => 2, ALREADY_INSTALLED => 3, NOT_FOUND => 4, CANT_DELETE => 5, }; sub is_real { return 1; } sub cleanup { my ($self, $error, $errorinfo) = @_; if (defined $error) { $self->{error} //= $error; $self->{errorinfo} //= $errorinfo; } if (defined $self->location) { if (defined $self->{error} && $self->{error} == BAD_PACKAGE) { $self->location->close_with_client_error; } else { $self->location->close_now; } $self->location->wipe_info; } delete $self->{plist}; delete $self->{db}; delete $self->{conflict_list}; } sub new { my $class = shift; return bless {}, $class; } sub system { my $class = shift; return OpenBSD::Handle::BaseSystem->new; } sub pkgname { my $self = shift; if (!defined $self->{pkgname}) { if (defined $self->{plist}) { $self->{pkgname} = $self->{plist}->pkgname; } elsif (defined $self->{location}) { $self->{pkgname} = $self->{location}->name; } elsif (defined $self->{name}) { require OpenBSD::PackageName; $self->{pkgname} = OpenBSD::PackageName::url2pkgname($self->{name}); } } return $self->{pkgname}; } sub location { return shift->{location}; } sub plist { return shift->{plist}; } sub dependency_info { my $self = shift; if (defined $self->{plist}) { return $self->{plist}; } elsif (defined $self->{location} && defined $self->{location}{update_info}) { return $self->{location}{update_info}; } else { return undef; } } OpenBSD::Auto::cache(conflict_list, sub { require OpenBSD::PkgCfl; return OpenBSD::PkgCfl->make_conflict_list(shift->dependency_info); }); sub set_error { my ($self, $error) = @_; $self->{error} = $error; } sub has_error { my ($self, $error) = @_; if (!defined $self->{error}) { return undef; } if (defined $error) { return $self->{error} eq $error; } return $self->{error}; } sub has_reported_error { my $self = shift; return $self->{error_reported}; } sub error_message { my $self = shift; my $error = $self->{error}; if ($error == BAD_PACKAGE) { return "bad package"; } elsif ($error == CANT_INSTALL) { if ($self->{errorinfo}) { return "$self->{errorinfo}"; } else { return "can't install"; } } elsif ($error == NOT_FOUND) { return "not found"; } elsif ($error == ALREADY_INSTALLED) { return "already installed"; } else { return "no error"; } } sub complete_old { my $self = shift; my $location = $self->{location}; if (!defined $location) { $self->set_error(NOT_FOUND); } else { my $plist = $location->plist; if (!defined $plist) { $self->set_error(BAD_PACKAGE); } else { $self->{plist} = $plist; delete $location->{contents}; delete $location->{update_info}; } } } sub complete_dependency_info { my $self = shift; my $location = $self->{location}; if (!defined $location) { $self->set_error(NOT_FOUND); } else { if (!defined $self->{plist}) { # trigger build $location->update_info; } } } sub create_old { my ($class, $pkgname, $state) = @_; my $self= $class->new; $self->{name} = $pkgname; my $location = $state->repo->installed->find($pkgname); if (defined $location) { $self->{location} = $location; } $self->complete_dependency_info; return $self; } sub create_new { my ($class, $pkg) = @_; my $handle = $class->new; $handle->{name} = $pkg; $handle->{tweaked} = 0; return $handle; } sub from_location { my ($class, $location) = @_; my $handle = $class->new; $handle->{location} = $location; $handle->{tweaked} = 0; return $handle; } sub get_plist { my ($handle, $state) = @_; my $location = $handle->{location}; my $pkg = $handle->pkgname; if ($state->verbose >= 2) { $state->say("#1parsing #2", $state->deptree_header($pkg), $pkg); } my $plist = $location->plist; unless (defined $plist) { $state->say("Can't find CONTENTS from #1", $location->url) unless $location->{error_reported}; $location->close_with_client_error; $location->wipe_info; $handle->set_error(BAD_PACKAGE); $handle->{error_reported} = 1; return; } delete $location->{update_info}; unless ($plist->has('url')) { OpenBSD::PackingElement::Url->add($plist, $location->url); } if ($plist->localbase ne $state->{localbase}) { $state->say("Localbase mismatch: package has: #1, user wants: #2", $plist->localbase, $state->{localbase}); $location->close_with_client_error; $location->wipe_info; $handle->set_error(BAD_PACKAGE); return; } my $pkgname = $handle->{pkgname} = $plist->pkgname; if ($pkg ne '-') { if (!defined $pkgname or $pkg ne $pkgname) { $state->say("Package name is not consistent ???"); $location->close_with_client_error; $location->wipe_info; $handle->set_error(BAD_PACKAGE); return; } } $handle->{plist} = $plist; } sub get_location { my ($handle, $state) = @_; my $name = $handle->{name}; my $location = $state->repo->find($name); if (!$location) { $state->print("#1", $state->deptree_header($name)); $handle->set_error(NOT_FOUND); $handle->{tweaked} = OpenBSD::Add::tweak_package_status($handle->pkgname, $state); if (!$handle->{tweaked}) { $state->say("Can't find #1", $name); $handle->{error_reported} = 1; eval { my $r = [$name]; $state->quirks->filter_obsolete($r, $state); } } return; } $handle->{location} = $location; $handle->{pkgname} = $location->name; } sub complete { my ($handle, $state) = @_; return if $handle->has_error; if (!defined $handle->{location}) { $handle->get_location($state); } return if $handle->has_error; if (!defined $handle->{plist}) { $handle->get_plist($state); } } package OpenBSD::Handle::BaseSystem; our @ISA = qw(OpenBSD::Handle); sub pkgname { return "BaseSystem"; } sub is_real { return 0; } 1;