1package Magus::Port;
2#
3# Copyright (c) 2007,2008 Chris Reinhardt. All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9# 1. Redistributions of source code must retain the above copyright notice
10#    this list of conditions and the following disclaimer.
11#
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
17# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27
28#
29# MAINTAINER=   ctriv@MidnightBSD.org
30#
31
32use strict;
33use warnings;
34
35use base 'Magus::DBI';
36
37__PACKAGE__->table('ports');
38
39__PACKAGE__->columns(Essential => qw(id run name version status pkgname flavor));
40__PACKAGE__->columns(All       => qw(description license restricted www updated default_flavor cpe));
41__PACKAGE__->columns(Stringify => qw(pkgname));
42
43__PACKAGE__->has_a(run => 'Magus::Run');
44
45__PACKAGE__->has_many(depends => [ 'Magus::Depend' => 'dependency' ] => 'port');
46__PACKAGE__->has_many(categories => [ 'Magus::PortCategory' => 'category' ]);
47__PACKAGE__->has_many(perms => [ 'Magus::PortLicensePerms' => 'perm' ]);
48__PACKAGE__->has_many(events => 'Magus::Event');
49__PACKAGE__->has_many(master_sites => 'Magus::MasterSite');
50__PACKAGE__->has_many(distfiles => 'Magus::Distfile');
51__PACKAGE__->has_many(restricted_distfiles => 'Magus::RestrictedDistfile');
52__PACKAGE__->has_many(critical => ['Magus::CriticalPorts' => 'pkgname' ] => 'pkgname' );
53
54
55__PACKAGE__->set_sql(ready_ports => 'SELECT __ESSENTIAL__ FROM ready_ports WHERE run=?');
56__PACKAGE__->set_sql(single_ready_port => 'SELECT __ESSENTIAL__ FROM ready_ports WHERE run=? LIMIT 1');
57__PACKAGE__->set_sql(last_twenty => qq{
58      SELECT __ESSENTIAL__
59      FROM __TABLE__
60      WHERE status!='untested'
61      ORDER BY updated DESC LIMIT 20
62  });
63
64=head2 Magus::Port->get_ready_port($run);
65
66Return a port that is ready to be tested for the given run.
67Ready is defined as:
68
69=over 4
70
71=item 1
72
73The port is unlocked
74
75=item 2
76
77The port has not been tested.
78
79=item 3
80
81All the port's depends are tested and unlocked.
82
83=back
84
85=cut
86
87sub get_ready_port {
88  my ($class, $run) = @_;
89  return shift->search_single_ready_port($run)->next;
90}
91
92
93=head2 $port->origin
94
95Return the absolute directory where this port lives, such as:
96
97  /usr/mports/foo/bar
98
99=cut  
100
101sub origin {
102  return join('/', $Mport::Globals::ROOT, $_[0]->name);
103}
104
105
106# POD removed as method is deprecated.
107sub current_result {
108  require Carp;
109  Carp::confess("Use of deprecated method: Magus::Port->current_result.  There is no replacement.");
110}
111
112=head2 $port->all_depends
113
114Returns a list of every port in this port's dependency tree.
115
116=cut 
117
118sub all_depends {
119  my ($self) = @_;
120
121  my %depends;
122  _walk($self, \%depends);
123  delete $depends{$self};
124  return sort values %depends;
125}
126
127sub _walk {
128  my ($port, $depends) = @_;
129
130  foreach my $dep ($port->depends) {
131    if (!$depends->{$dep}) {
132      $depends->{$dep} = $dep;
133      _walk($dep, $depends);
134    }
135  }
136
137}
138
139=head2 $port->bundle_name
140
141Returns the bundle filename for this port.
142
143=cut
144
145sub bundle_name {
146  my ($self) = @_;
147  return sprintf("%s-%s.%s", $self->pkgname, $self->version, $Magus::Config{'PkgExtension'});
148}
149
150
151
152=head2 $port->set_result_pass($message);
153
154A convience method for setting a port as passed.
155
156=cut
157
158sub set_result_pass {
159  my ($self, $msg) = @_;
160
161  $self->_set_result('pass', $msg, 'info');
162}
163
164
165=head2 $port->set_result_skip($message);
166
167A convience method for setting a port as skipped.
168
169=cut
170
171sub set_result_skip {
172  my ($self, $msg) = @_;
173
174  $self->_set_result('skip', $msg, 'skip');
175}
176
177
178=head2 $port->set_result_internal($message);
179
180A convience method for setting a port as internalled.
181
182=cut
183
184sub set_result_internal {
185  my ($self, $msg) = @_;
186
187  $self->_set_result('internal', $msg, 'internal');
188}
189
190
191=head2 $port->set_result_fail($message);
192
193A convience method for setting a port as failed.
194
195=cut
196
197sub set_result_fail {
198  my ($self, $msg) = @_;
199
200  $self->_set_result('fail', $msg, 'fail');
201}
202
203
204
205sub _set_result {
206  my ($self, $status, $msg, $type) = @_;
207
208  $self->status($status);
209  $self->update;
210
211  $self->note_event($type, $msg);
212}
213
214=head2 $port->reset();
215
216Returns the port to a pristine untested state.
217
218=cut
219
220sub reset {
221  my ($self) = @_;
222
223  $self->events->delete_all;
224
225  if (my $log = Magus::Log->retrieve(port => $self)) {
226    $log->delete;
227  }
228
229  $self->status('untested');
230  $self->update;
231}
232
233=head2 $port->can_reset
234
235Returns true is reseting this port makes sense (the port is tested
236and its run is active).  Returns false otherwise.
237
238=cut
239
240sub can_reset {
241  return if $_[0]->status eq 'untested'
242         || $_[0]->run->status ne 'active';
243  return 1;
244}
245
246=head2 $port->log
247
248Returns the log data for this port, if any.  Returns undef if there is no log.
249
250=cut
251
252sub log {
253  require Magus::Log;
254
255  my ($self) = @_;
256  return $self->{__log} if exists $self->{__log};
257  my $log = Magus::Log->retrieve(port => $self) or return;
258  return $self->{__log} = $log->data;
259}
260
261=head2 $port->note_event(type => $msg);
262
263Add an event to the port of the given type with the given message
264
265=cut
266
267sub note_event {
268  my ($self, $type, $msg) = @_;
269
270  $self->add_to_events({
271    machine => $Magus::Machine,
272    type    => $type,
273    msg     => $msg,
274  });
275}
276
2771;
278__END__
279