File Coverage

blib/lib/IPC/RunSession/Simple.pm
Criterion Covered Total %
statement 55 62 88.7
branch 9 18 50.0
condition n/a
subroutine 12 14 85.7
pod 1 3 33.3
total 77 97 79.3


line stmt bran cond sub pod time code
1             package IPC::RunSession::Simple;
2              
3 1     1   94743 use warnings;
  1         2  
  1         22  
4 1     1   3 use strict;
  1         2  
  1         41  
5              
6             =head1 NAME
7              
8             IPC::RunSession::Simple - Run a simple IPC session in the same vein as IPC::Run & Expect
9              
10             =head1 VERSION
11              
12             Version 0.002
13              
14             =cut
15              
16             our $VERSION = '0.002';
17              
18             =head1 SYNOPSIS
19              
20             use IPC::RunSession::Simple
21              
22             $session = IPC::RunSession::Simple->open( "fcsh" )
23              
24             # Read until the prompt (which doesn't end in a newline)
25             # Timeout after 5 seconds
26             $result = $session->read_until( qr/\(fcsh\) /, 5 )
27              
28             if ( $result->closed ) {
29             # We encountered an (abnormal) EOF...
30             }
31             elsif ( $result->expired ) {
32             # The timeout got triggered...
33             }
34             else {
35             print $result->content
36             }
37              
38             # Tell 'fcsh' we want to quit
39             $session->write( "quit\n" )
40              
41             =head1 DESCRIPTION
42              
43             A simple IPC session with read/write capability using L and L
44              
45             =cut
46              
47 1     1   2548 use IPC::Open3 qw/ open3 /;
  1         4718  
  1         61  
48 1     1   8 use Carp;
  1         2  
  1         201  
49              
50             =head1 USAGE
51              
52             =head2 $session = IPC::RunSession::Simple->open( $cmd )
53              
54             Create a new session by calling C on $cmd
55              
56             =cut
57              
58             sub open {
59 1     1 1 69 my $class = shift;
60 1         2 my $cmd = shift;
61            
62 1         3 my ( $writer, $reader );
63              
64             # .., undef, ... means that the output (reader) and error handle will be on the same "stream"
65 1 50       4 $cmd = [ $cmd ] unless ref $cmd eq 'ARRAY';
66 1 50       7 open3 $writer, $reader, undef, @$cmd or croak "Unable to open3 \"$cmd\": $!";
67              
68 1         5005 return IPC::RunSession::Simple::Session->new( writer => $writer, reader => $reader );
69             }
70              
71             sub new {
72 0     0 0 0 return shift->open( @_ );
73             }
74              
75             sub run {
76 0     0 0 0 return shift->open( @_ );
77             }
78              
79             package IPC::RunSession::Simple::Session;
80              
81 1     1   1042 use Any::Moose;
  1         42142  
  1         8  
82              
83 1     1   3188 use IO::Select;
  1         2495  
  1         567  
84              
85             has [qw/ writer reader /] => qw/is ro required 1/;
86             has _selector => qw/is ro lazy_build 1/;
87             sub _build__selector {
88 1     1   2 my $self = shift;
89 1         20 my $selector = IO::Select->new;
90 1         23 $selector->add( $self->reader );
91 1         183 return $selector;
92             }
93             has _read_amount => qw/is rw/, default => 10_000;
94              
95             =head2 $result = $session->read( [ $timeout ] )
96              
97             Read (blocking) until some output is gotten
98              
99             If $timeout is given, then wait until output is gotten OR the timeout expires (setting $result->expired appropiately)
100              
101             =cut
102              
103             sub read {
104 2     2   866 my $self = shift;
105 2         4 my $timeout = shift;
106              
107 2         7 return $self->read_until( undef, $timeout );
108             }
109              
110             =head2 $result = $session->read_until( $marker, [ $timeout ] )
111              
112             Read (blocking) until some output matching $marker is gotten
113              
114             $marker can either be a regular expression or a code block. If a code block is given, the content accumulated will be available as the first argument and as C<$_>
115              
116             If $timeout is given, then wait until output is gotten OR the timeout expires (setting $result->expired appropiately). Any content collected up to the timeout will be included in $result->content
117              
118             =cut
119              
120             sub read_until {
121 4     4   340 my $self = shift;
122 4         25 my $marker = shift;
123 4         9 my $timeout = shift;
124              
125 4         43 my $result = IPC::RunSession::Simple::Session::Result->new;
126 4         62 my $content = '';
127              
128 4         6 while ( 1 ) {
129 4 50       32 if ( $self->_selector->can_read( $timeout ) ) {
130              
131 4         7256 my $read_size = sysread $self->reader, my $read, $self->_read_amount;
132 4 100       12 if ( ! $read_size ) { # Reached EOF...
133 1         4 $result->closed( 1 );
134 1         2 last;
135             }
136             else {
137 3         9 $content .= $read;
138 3 100       14 last unless $marker;
139            
140 2 50       16 if ( ref $marker eq 'Regexp' ) {
    0          
141 2 50       19 last if $content =~ $marker;
142             }
143             elsif ( ref $marker eq 'CODE' ) {
144 0         0 local $_ = $content;
145 0 0       0 last if $marker->( $content );
146             }
147             else {
148 0         0 die "Don't understand marker ($marker)";
149             }
150             }
151             }
152             else {
153 0         0 $result->expired( 1 );
154 0         0 last;
155             }
156             }
157              
158 4         18 $result->content( $content );
159              
160 4         12 return $result;
161             }
162              
163             =head2 $session->write( $content )
164              
165             Write $content to the input of the opened process
166              
167             =cut
168              
169             sub write {
170 2     2   1913 my $self = shift;
171 2         3 my $content = shift;
172              
173 2         8 my $writer = $self->writer;
174 2         40 print $writer $content;
175             }
176              
177             =head2 $reader = $session->reader
178              
179             Return the reader filehandle (the STDOUT/STDERR of the process)
180              
181             =head2 $writer = $session->writer
182              
183             Return the writer filehandle (the STDIN of the process)
184              
185             =cut
186              
187             package IPC::RunSession::Simple::Session::Result;
188              
189 1     1   11 use Any::Moose;
  1         2  
  1         9  
190              
191             =head2 $result->content
192              
193             The content read via C or C
194              
195             =head2 $result->expired
196              
197             True if a read returned as a result of taking longer than the specified timeout value
198              
199             =head2 $result->closed
200              
201             True if the process closed during the read
202              
203             =cut
204              
205             has [qw/ content closed expired /] => qw/is rw/;
206              
207             =head1 SEE ALSO
208              
209             L
210              
211             L
212              
213             =head1 AUTHOR
214              
215             Robert Krimen, C<< >>
216              
217             =head1 BUGS
218              
219             Please report any bugs or feature requests to C, or through
220             the web interface at L. I will be notified, and then you'll
221             automatically be notified of progress on your bug as I make changes.
222              
223              
224              
225              
226             =head1 SUPPORT
227              
228             You can find documentation for this module with the perldoc command.
229              
230             perldoc IPC::RunSession::Simple
231              
232              
233             You can also look for information at:
234              
235             =over 4
236              
237             =item * RT: CPAN's request tracker
238              
239             L
240              
241             =item * AnnoCPAN: Annotated CPAN documentation
242              
243             L
244              
245             =item * CPAN Ratings
246              
247             L
248              
249             =item * Search CPAN
250              
251             L
252              
253             =back
254              
255              
256             =head1 ACKNOWLEDGEMENTS
257              
258              
259             =head1 COPYRIGHT & LICENSE
260              
261             Copyright 2009 Robert Krimen.
262              
263             This program is free software; you can redistribute it and/or modify it
264             under the terms of either: the GNU General Public License as published
265             by the Free Software Foundation; or the Artistic License.
266              
267             See http://dev.perl.org/licenses/ for more information.
268              
269              
270             =cut
271              
272             1; # End of IPC::RunSession::Simple