2 # This file is part of App::CPAN2Pkg.
3 # Copyright (c) 2009 Jerome Quelin, all rights reserved.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the same terms as Perl itself.
10 package App
::CPAN2Pkg
::Module
;
17 constructor
=> '_new',
20 shortname
=> 'shortname',
22 _prereqs
=> '_prereqs',
26 use POE
::Filter
::Line
;
29 my $rpm_locked = ''; # only one rpm transaction at a time
33 # $ apt-file find Audio/MPD.pm
34 # libaudio-mpd-perl: /usr/share/perl5/Audio/MPD.pm
36 # - find dist hosting module
37 # - computing dependencies
38 # - installing dependencies
39 # - check cooker availability
42 # - check local availability
45 # - wait for kenobi build
55 my ($class, $module) = @_;
60 $short =~ s/[[:lower:]]//g;
61 my $obj = App
::CPAN2Pkg
::Module
->_new(
68 # spawning the session
69 my $session = POE
::Session
->create(
72 cpan2dist
=> \
&cpan2dist
,
73 find_prereqs
=> \
&find_prereqs
,
74 install_from_dist
=> \
&install_from_dist
,
75 is_in_dist
=> \
&is_in_dist
,
76 is_installed
=> \
&is_installed
,
78 _find_prereqs
=> \
&_find_prereqs
,
79 _install_from_dist
=> \
&_install_from_dist
,
80 _is_in_dist
=> \
&_is_in_dist
,
85 #_stop => sub { warn "stop " . $_[HEAP]->name . "\n"; },
99 my ($k, $self) = @_[KERNEL
, HEAP
];
100 my $name = $self->name;
101 warn "running: cpan2dist $name\n";
105 my ($k, $self) = @_[KERNEL
, HEAP
];
108 my $module = $self->name;
109 my $cmd = "cpanp /prereqs show $module";
110 $self->_log_new_step('Finding module prereqs', "Running command: $cmd" );
115 my $wheel = POE
::Wheel
::Run
->new(
117 CloseEvent
=> '_find_prereqs',
118 StdoutEvent
=> '_stdout',
119 StderrEvent
=> '_stderr',
120 StdoutFilter
=> POE
::Filter
::Line
->new,
121 StderrFilter
=> POE
::Filter
::Line
->new,
124 # need to store the wheel, otherwise the process goes woo!
125 $self->_wheel($wheel);
128 sub install_from_dist
{
129 my ($k, $self) = @_[KERNEL
, HEAP
];
130 my $name = $self->name;
132 # check whether there's another rpm transaction
134 $self->_log_prefixed_lines("waiting for rpm lock... (owned by $rpm_locked)");
135 $k->delay( install_from_dist
=> 1 );
141 my $cmd = "sudo urpmi --auto 'perl($name)'";
142 $self->_log_new_step('Installing from upstream', "Running command: $cmd" );
147 my $wheel = POE
::Wheel
::Run
->new(
149 StdoutEvent
=> '_stdout',
150 StderrEvent
=> '_stderr',
151 Conduit
=> 'pty-pipe', # urpmi wants a pty
152 StdoutFilter
=> POE
::Filter
::Line
->new,
153 StderrFilter
=> POE
::Filter
::Line
->new,
155 $k->sig( CHLD
=> '_install_from_dist' );
157 # need to store the wheel, otherwise the process goes woo!
158 $self->_wheel($wheel);
162 my ($k, $self) = @_[KERNEL
, HEAP
];
165 my $name = $self->name;
166 my $cmd = "urpmq --whatprovides 'perl($name)'";
167 $self->_log_new_step('Checking if packaged upstream', "Running command: $cmd" );
172 my $wheel = POE
::Wheel
::Run
->new(
174 #CloseEvent => '_is_in_dist', # FIXME: cf rt#42757
175 StdoutEvent
=> '_stdout',
176 StderrEvent
=> '_stderr',
177 Conduit
=> 'pty-pipe', # urpmq wants a pty
178 StdoutFilter
=> POE
::Filter
::Line
->new,
179 StderrFilter
=> POE
::Filter
::Line
->new,
181 $k->sig( CHLD
=> '_is_in_dist' );
183 # need to store the wheel, otherwise the process goes woo!
184 $self->_wheel($wheel);
189 my ($k, $self) = @_[KERNEL
, HEAP
];
191 my $name = $self->name;
192 my $cmd = qq{ require $name };
193 $self->_log_new_step(
194 'Checking if module is installed',
195 "Evaluating command: $cmd"
199 my $what = $@
|| "$name loaded successfully\n";
200 $k->post('ui', 'append', $self, $what);
202 my $is_installed = $@
eq '';
203 my $status = $is_installed ?
'installed' : 'not installed';
204 $self->_log_result("$name is $status locally.");
205 $k->post('app', 'local_status', $self, $is_installed);
211 my ($k, $self, $id) = @_[KERNEL
, HEAP
, ARG0
];
214 my $wheel = $self->_wheel;
215 $self->_wheel(undef);
220 split /\n/, $self->_output;
221 shift @lines; # remove the title line
223 map { (split /\s+/, $_)[0] }
228 ?
map { "prereq found: $_" } @prereqs
229 : 'No prereqs found.';
230 $self->_log_result(@logs);
231 $k->post('app', 'prereqs', $self, @prereqs);
234 sub _install_from_dist
{
235 my($k, $self, $pid, $rv) = @_[KERNEL
, HEAP
, ARG1
, ARG2
];
237 # since it's a sigchld handler, it also gets called for other
238 # spawned processes. therefore, screen out processes that are
239 # not related to this object.
240 return unless defined $self->_wheel;
241 return unless $self->_wheel->PID == $pid;
244 $self->_wheel(undef);
250 my $name = $self->name;
251 my $exval = $rv >> 8;
252 my $status = $exval ?
'not been' : 'been';
253 $self->_log_result( "$name has $status installed from upstream." );
254 $k->post('app', 'upstream_install', $self, !$exval);
258 my($k, $self, $pid, $rv) = @_[KERNEL
, HEAP
, ARG1
, ARG2
];
260 # since it's a sigchld handler, it also gets called for other
261 # spawned processes. therefore, screen out processes that are
262 # not related to this object.
263 return unless defined $self->_wheel;
264 return unless $self->_wheel->PID == $pid;
267 # FIXME: should be done in CloseEvent
268 $self->_wheel(undef);
270 # check if we got a hit
271 # urpmq returns 0 if found, 1 otherwise.
272 my $name = $self->name;
273 my $exval = $rv >> 8;
275 my $status = $exval ?
'not' : 'already';
276 $self->_log_result( "$name is $status packaged upstream." );
277 $k->post('app', 'upstream_status', $self, !$exval);
281 my ($k, $self, $line) = @_[KERNEL
, HEAP
, ARG0
];
282 $k->post('ui', 'append', $self, "stderr: $line\n");
286 my ($k, $self, $line) = @_[KERNEL
, HEAP
, ARG0
];
288 $self->_output( $self->_output . $line );
289 $k->post('ui', 'append', $self, "stdout: $line");
293 # -- poe inline states
296 my ($k, $self) = @_[KERNEL
, HEAP
];
298 $k->alias_set($self);
299 $k->post('ui', 'module_spawned', $self);
300 $k->post('app', 'module_spawned', $self);
309 sub _log_empty_line
{
310 my ($self, $nb) = @_;
311 $nb //= 1; #/ FIXME padre syntaxic color glitch
312 POE
::Kernel
->post('ui', 'append', $self, "\n" x
$nb);
315 sub _log_prefixed_lines
{
316 my ($self, @lines) = @_;
319 POE
::Kernel
->post('ui', 'append', $self, $_)
320 for map { "$prefix $_\n" } @lines;
324 my ($self, $step, $comment) = @_;
326 $self->_log_prefixed_lines('-' x
10, $step, '', $comment, '');
327 $self->_log_empty_line;
331 my ($self, @lines) = @_;
333 $self->_log_empty_line;
334 $self->_log_prefixed_lines( '', @lines, '', '' );
344 App::CPAN2Pkg::Module - poe session to drive a module packaging
350 C<App::CPAN2Pkg::Module> implements a POE session driving the whole
351 packaging process of a given module.
353 It is spawned by C<App::CPAN2Pkg> and implements the logic related to
354 the module availability in the distribution.
358 =head1 PUBLIC PACKAGE METHODS
360 =head2 my $id = App::CPAN2Pkg::Module->spawn( $module )
362 This method will create a POE session responsible for packaging &
363 installing the wanted C<$module>.
365 It will return the POE id of the session newly created.
369 =head1 PUBLIC EVENTS ACCEPTED
371 =head2 find_prereqs()
373 Start looking for any other module needed by current module.
376 =head2 install_from_dist()
378 Try to install module from upstream distribution.
383 Check whether the package is provided by an existing upstream package.
386 =head2 is_installed()
388 Check whether the package is installed locally.
393 This package is also a class, used B<internally> to store private data
394 needed for the packaging stuff. The following accessors are therefore
395 available, but should not be used directly:
399 =item name() - the module name
401 =item shortname() - the module shortname (only capital letters)
409 For all related information (bug reporting, source code repository,
410 etc.), refer to C<App::CPAN2Pkg>'s pod, section C<SEE ALSO>.
416 Jerome Quelin, C<< <jquelin@cpan.org> >>
420 =head1 COPYRIGHT & LICENSE
422 Copyright (c) 2009 Jerome Quelin, all rights reserved.
424 This program is free software; you can redistribute it and/or modify
425 it under the same terms as Perl itself.