Alt-Math-Prime-FastSieve-Inline
view release on metacpan or search on metacpan
inc/Capture/Tiny.pm view on Meta::CPAN
464748495051525354555657585960616263646566# constants and fixtures
#--------------------------------------------------------------------------#
my
$IS_WIN32
= $^O eq
'MSWin32'
;
##our $DEBUG = $ENV{PERL_CAPTURE_TINY_DEBUG};
##
##my $DEBUGFH;
##open $DEBUGFH, "> DEBUG" if $DEBUG;
##
##*_debug = $DEBUG ? sub(@) { print {$DEBUGFH} @_ } : sub(){0};
our
$TIMEOUT
= 30;
#--------------------------------------------------------------------------#
# command to tee output -- the argument is a filename that must
# be opened to signal that the process is ready to receive input.
# This is annoying, but seems to be the best that can be done
# as a simple, portable IPC technique
#--------------------------------------------------------------------------#
my
@cmd
= ($^X,
'-C0'
,
'-e'
,
'$SIG{HUP}=sub{exit}; '
inc/Capture/Tiny.pm view on Meta::CPAN
6869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
.
'my $buf; while (sysread(STDIN, $buf, 2048)) { '
.
'syswrite(STDOUT, $buf); syswrite(STDERR, $buf)}'
);
#--------------------------------------------------------------------------#
# filehandle manipulation
#--------------------------------------------------------------------------#
sub
_relayer {
my
(
$fh
,
$layers
) =
@_
;
# _debug("# requested layers (@{$layers}) for @{[fileno $fh]}\n");
my
%seen
= (
unix
=> 1,
perlio
=> 1 );
# filter these out
my
@unique
=
grep
{ !
$seen
{
$_
}++ }
@$layers
;
# _debug("# applying unique layers (@unique) to @{[fileno $fh]}\n");
binmode
(
$fh
,
join
(
":"
,
":raw"
,
@unique
));
}
sub
_name {
my
$glob
=
shift
;
no
strict
'refs'
;
## no critic
return
*{
$glob
}{NAME};
}
sub
_open {
open
$_
[0],
$_
[1] or Carp::confess
"Error from open("
.
join
(
q{, }
,
@_
) .
"): $!"
;
# _debug( "# open " . join( ", " , map { defined $_ ? _name($_) : 'undef' } @_ ) . " as " . fileno( $_[0] ) . "\n" );
}
sub
_close {
# _debug( "# closing " . ( defined $_[0] ? _name($_[0]) : 'undef' ) . " on " . fileno( $_[0] ) . "\n" );
close
$_
[0] or Carp::confess
"Error from close("
.
join
(
q{, }
,
@_
) .
"): $!"
;
}
my
%dup
;
# cache this so STDIN stays fd0
my
%proxy_count
;
sub
_proxy_std {
my
%proxies
;
if
( !
defined
fileno
STDIN ) {
$proxy_count
{stdin}++;
if
(
defined
$dup
{stdin}) {
_open \
*STDIN
,
"<&="
.
fileno
(
$dup
{stdin});
# _debug( "# restored proxy STDIN as " . (defined fileno STDIN ? fileno STDIN : 'undef' ) . "\n" );
}
else
{
_open \
*STDIN
,
"<"
. File::Spec->devnull;
# _debug( "# proxied STDIN as " . (defined fileno STDIN ? fileno STDIN : 'undef' ) . "\n" );
_open
$dup
{stdin} = IO::Handle->new,
"<&=STDIN"
;
}
$proxies
{stdin} = \
*STDIN
;
binmode
(STDIN,
':utf8'
)
if
$] >= 5.008;
}
if
( !
defined
fileno
STDOUT ) {
$proxy_count
{stdout}++;
if
(
defined
$dup
{stdout}) {
_open \
*STDOUT
,
">&="
.
fileno
(
$dup
{stdout});
# _debug( "# restored proxy STDOUT as " . (defined fileno STDOUT ? fileno STDOUT : 'undef' ) . "\n" );
}
else
{
_open \
*STDOUT
,
">"
. File::Spec->devnull;
# _debug( "# proxied STDOUT as " . (defined fileno STDOUT ? fileno STDOUT : 'undef' ) . "\n" );
_open
$dup
{stdout} = IO::Handle->new,
">&=STDOUT"
;
}
$proxies
{stdout} = \
*STDOUT
;
binmode
(STDOUT,
':utf8'
)
if
$] >= 5.008;
}
if
( !
defined
fileno
STDERR ) {
$proxy_count
{stderr}++;
if
(
defined
$dup
{stderr}) {
_open \
*STDERR
,
">&="
.
fileno
(
$dup
{stderr});
# _debug( "# restored proxy STDERR as " . (defined fileno STDERR ? fileno STDERR : 'undef' ) . "\n" );
}
else
{
_open \
*STDERR
,
">"
. File::Spec->devnull;
# _debug( "# proxied STDERR as " . (defined fileno STDERR ? fileno STDERR : 'undef' ) . "\n" );
_open
$dup
{stderr} = IO::Handle->new,
">&=STDERR"
;
}
$proxies
{stderr} = \
*STDERR
;
binmode
(STDERR,
':utf8'
)
if
$] >= 5.008;
}
return
%proxies
;
}
sub
_unproxy {
my
(
%proxies
) =
@_
;
# _debug( "# unproxying: " . join(" ", keys %proxies) . "\n" );
for
my
$p
(
keys
%proxies
) {
$proxy_count
{
$p
}--;
# _debug( "# unproxied " . uc($p) . " ($proxy_count{$p} left)\n" );
if
( !
$proxy_count
{
$p
} ) {
_close
$proxies
{
$p
};
_close
$dup
{
$p
}
unless
$] < 5.008;
# 5.6 will have already closed this as dup
delete
$dup
{
$p
};
}
}
}
sub
_copy_std {
my
%handles
;
inc/Capture/Tiny.pm view on Meta::CPAN
182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243#--------------------------------------------------------------------------#
# private subs
#--------------------------------------------------------------------------#
sub
_start_tee {
my
(
$which
,
$stash
) =
@_
;
# $which is "stdout" or "stderr"
# setup pipes
$stash
->{
$_
}{
$which
} = IO::Handle->new
for
qw/tee reader/
;
pipe
$stash
->{reader}{
$which
},
$stash
->{tee}{
$which
};
# _debug( "# pipe for $which\: " . _name($stash->{tee}{$which}) . " " . fileno( $stash->{tee}{$which} ) . " => " . _name($stash->{reader}{$which}) . " " . fileno( $stash->{reader}{$which}) . "\n" );
select
((
select
(
$stash
->{tee}{
$which
}), $|=1)[0]);
# autoflush
# setup desired redirection for parent and child
$stash
->{new}{
$which
} =
$stash
->{tee}{
$which
};
$stash
->{child}{
$which
} = {
stdin
=>
$stash
->{reader}{
$which
},
stdout
=>
$stash
->{old}{
$which
},
stderr
=>
$stash
->{capture}{
$which
},
};
# flag file is used to signal the child is ready
$stash
->{flag_files}{
$which
} =
scalar
tmpnam();
# execute @cmd as a separate process
if
(
$IS_WIN32
) {
local
$@;
eval
"use Win32API::File qw/CloseHandle GetOsFHandle SetHandleInformation fileLastError HANDLE_FLAG_INHERIT INVALID_HANDLE_VALUE/ "
;
# _debug( "# Win32API::File loaded\n") unless $@;
my
$os_fhandle
= GetOsFHandle(
$stash
->{tee}{
$which
} );
# _debug( "# Couldn't get OS handle: " . fileLastError() . "\n") if ! defined $os_fhandle || $os_fhandle == INVALID_HANDLE_VALUE();
my
$result
= SetHandleInformation(
$os_fhandle
, HANDLE_FLAG_INHERIT(), 0);
# _debug( $result ? "# set no-inherit flag on $which tee\n" : ("# can't disable tee handle flag inherit: " . fileLastError() . "\n"));
_open_std(
$stash
->{child}{
$which
} );
$stash
->{pid}{
$which
} =
system
(1,
@cmd
,
$stash
->{flag_files}{
$which
});
# not restoring std here as it all gets redirected again shortly anyway
}
else
{
# use fork
_fork_exec(
$which
,
$stash
);
}
}
sub
_fork_exec {
my
(
$which
,
$stash
) =
@_
;
# $which is "stdout" or "stderr"
my
$pid
=
fork
;
if
( not
defined
$pid
) {
Carp::confess
"Couldn't fork(): $!"
;
}
elsif
(
$pid
== 0) {
# child
# _debug( "# in child process ...\n" );
untie
*STDIN
;
untie
*STDOUT
;
untie
*STDERR
;
_close
$stash
->{tee}{
$which
};
# _debug( "# redirecting handles in child ...\n" );
_open_std(
$stash
->{child}{
$which
} );
# _debug( "# calling exec on command ...\n" );
exec
@cmd
,
$stash
->{flag_files}{
$which
};
}
$stash
->{pid}{
$which
} =
$pid
}
my
$have_usleep
=
eval
"use Time::HiRes 'usleep'; 1"
;
sub
_files_exist {
return
1
if
@_
==
grep
{ -f }
@_
;
Time::HiRes::usleep(1000)
if
$have_usleep
;
return
0;
inc/Capture/Tiny.pm view on Meta::CPAN
250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
my
$timeout
=
defined
$ENV
{PERL_CAPTURE_TINY_TIMEOUT}
?
$ENV
{PERL_CAPTURE_TINY_TIMEOUT} :
$TIMEOUT
;
1
until
_files_exist(
@files
) || (
$timeout
&& (
time
-
$start
>
$timeout
));
Carp::confess
"Timed out waiting for subprocesses to start"
if
! _files_exist(
@files
);
unlink
$_
for
@files
;
}
sub
_kill_tees {
my
(
$stash
) =
@_
;
if
(
$IS_WIN32
) {
# _debug( "# closing handles with CloseHandle\n");
CloseHandle( GetOsFHandle(
$_
) )
for
values
%{
$stash
->{tee} };
# _debug( "# waiting for subprocesses to finish\n");
my
$start
=
time
;
1
until
wait
== -1 || (
time
-
$start
> 30);
}
else
{
_close
$_
for
values
%{
$stash
->{tee} };
waitpid
$_
, 0
for
values
%{
$stash
->{pid} };
}
}
sub
_slurp {
my
(
$name
,
$stash
) =
@_
;
my
(
$fh
,
$pos
) =
map
{
$stash
->{
$_
}{
$name
} }
qw/capture pos/
;
# _debug( "# slurping captured $name from " . fileno($fh) . " at pos $pos with layers: @{[PerlIO::get_layers($fh)]}\n");
seek
(
$fh
,
$pos
, 0 ) or
die
"Couldn't seek on capture handle for $name\n"
;
my
$text
=
do
{
local
$/;
scalar
readline
$fh
};
return
defined
(
$text
) ?
$text
:
""
;
}
#--------------------------------------------------------------------------#
# _capture_tee() -- generic main sub for capturing or teeing
#--------------------------------------------------------------------------#
sub
_capture_tee {
# _debug( "# starting _capture_tee with (@_)...\n" );
my
(
$do_stdout
,
$do_stderr
,
$do_merge
,
$do_tee
,
$code
,
@opts
) =
@_
;
my
%do
= (
$do_stdout
? (
stdout
=> 1) : (),
$do_stderr
? (
stderr
=> 1) : ());
Carp::confess(
"Custom capture options must be given as key/value pairs\n"
)
unless
@opts
% 2 == 0;
my
$stash
= {
capture
=> {
@opts
} };
for
(
keys
%{
$stash
->{capture}} ) {
my
$fh
=
$stash
->{capture}{
$_
};
Carp::confess
"Custom handle for $_ must be seekable\n"
unless
ref
(
$fh
) eq
'GLOB'
|| (blessed(
$fh
) &&
$fh
->isa(
"IO::Seekable"
));
}
# save existing filehandles and setup captures
local
*CT_ORIG_STDIN
=
*STDIN
;
local
*CT_ORIG_STDOUT
=
*STDOUT
;
local
*CT_ORIG_STDERR
=
*STDERR
;
# find initial layers
my
%layers
= (
stdin
=> [PerlIO::get_layers(\
*STDIN
) ],
stdout
=> [PerlIO::get_layers(\
*STDOUT
,
output
=> 1)],
stderr
=> [PerlIO::get_layers(\
*STDERR
,
output
=> 1)],
);
# _debug( "# existing layers for $_\: @{$layers{$_}}\n" ) for qw/stdin stdout stderr/;
# get layers from underlying glob of tied filehandles if we can
# (this only works for things that work like Tie::StdHandle)
$layers
{stdout} = [PerlIO::get_layers(
tied
*STDOUT
)]
if
tied
(
*STDOUT
) && (reftype
tied
*STDOUT
eq
'GLOB'
);
$layers
{stderr} = [PerlIO::get_layers(
tied
*STDERR
)]
if
tied
(
*STDERR
) && (reftype
tied
*STDERR
eq
'GLOB'
);
# _debug( "# tied object corrected layers for $_\: @{$layers{$_}}\n" ) for qw/stdin stdout stderr/;
# bypass scalar filehandles and tied handles
# localize scalar STDIN to get a proxy to pick up FD0, then restore later to CT_ORIG_STDIN
my
%localize
;
$localize
{stdin}++,
local
(
*STDIN
)
if
grep
{
$_
eq
'scalar'
} @{
$layers
{stdin}};
$localize
{stdout}++,
local
(
*STDOUT
)
if
$do_stdout
&&
grep
{
$_
eq
'scalar'
} @{
$layers
{stdout}};
$localize
{stderr}++,
local
(
*STDERR
)
if
(
$do_stderr
||
$do_merge
) &&
grep
{
$_
eq
'scalar'
} @{
$layers
{stderr}};
$localize
{stdin}++,
local
(
*STDIN
), _open( \
*STDIN
,
"<&=0"
)
if
tied
*STDIN
&& $] >= 5.008;
$localize
{stdout}++,
local
(
*STDOUT
), _open( \
*STDOUT
,
">&=1"
)
if
$do_stdout
&&
tied
*STDOUT
&& $] >= 5.008;
$localize
{stderr}++,
local
(
*STDERR
), _open( \
*STDERR
,
">&=2"
)
if
(
$do_stderr
||
$do_merge
) &&
tied
*STDERR
&& $] >= 5.008;
# _debug( "# localized $_\n" ) for keys %localize;
# proxy any closed/localized handles so we don't use fds 0, 1 or 2
my
%proxy_std
= _proxy_std();
# _debug( "# proxy std: @{ [%proxy_std] }\n" );
# update layers after any proxying
$layers
{stdout} = [PerlIO::get_layers(\
*STDOUT
,
output
=> 1)]
if
$proxy_std
{stdout};
$layers
{stderr} = [PerlIO::get_layers(\
*STDERR
,
output
=> 1)]
if
$proxy_std
{stderr};
# _debug( "# post-proxy layers for $_\: @{$layers{$_}}\n" ) for qw/stdin stdout stderr/;
# store old handles and setup handles for capture
$stash
->{old} = _copy_std();
$stash
->{new} = { %{
$stash
->{old}} };
# default to originals
for
(
keys
%do
) {
$stash
->{new}{
$_
} = (
$stash
->{capture}{
$_
} ||= File::Temp->new);
seek
(
$stash
->{capture}{
$_
}, 0, 2 ) or
die
"Could not seek on capture handle for $_\n"
;
$stash
->{
pos
}{
$_
} =
tell
$stash
->{capture}{
$_
};
# _debug("# will capture $_ on " . fileno($stash->{capture}{$_})."\n" );
_start_tee(
$_
=>
$stash
)
if
$do_tee
;
# tees may change $stash->{new}
}
_wait_for_tees(
$stash
)
if
$do_tee
;
# finalize redirection
$stash
->{new}{stderr} =
$stash
->{new}{stdout}
if
$do_merge
;
# _debug( "# redirecting in parent ...\n" );
_open_std(
$stash
->{new} );
# execute user provided code
my
(
$exit_code
,
$inner_error
,
$outer_error
,
@result
);
{
local
*STDIN
=
*CT_ORIG_STDIN
if
$localize
{stdin};
# get original, not proxy STDIN
# _debug( "# finalizing layers ...\n" );
_relayer(\
*STDOUT
,
$layers
{stdout})
if
$do_stdout
;
_relayer(\
*STDERR
,
$layers
{stderr})
if
$do_stderr
;
# _debug( "# running code $code ...\n" );
local
$@;
eval
{
@result
=
$code
->();
$inner_error
= $@ };
$exit_code
= $?;
# save this for later
$outer_error
= $@;
# save this for later
}
# restore prior filehandles and shut down tees
# _debug( "# restoring filehandles ...\n" );
_open_std(
$stash
->{old} );
_close(
$_
)
for
values
%{
$stash
->{old}};
# don't leak fds
# shouldn't need relayering originals, but see rt.perl.org #114404
_relayer(\
*STDOUT
,
$layers
{stdout})
if
$do_stdout
;
_relayer(\
*STDERR
,
$layers
{stderr})
if
$do_stderr
;
_unproxy(
%proxy_std
);
# _debug( "# killing tee subprocesses ...\n" ) if $do_tee;
_kill_tees(
$stash
)
if
$do_tee
;
# return captured output, but shortcut in void context
# unless we have to echo output to tied/scalar handles;
my
%got
;
if
(
defined
wantarray
or (
$do_tee
&&
keys
%localize
) ) {
for
(
keys
%do
) {
_relayer(
$stash
->{capture}{
$_
},
$layers
{
$_
});
$got
{
$_
} = _slurp(
$_
,
$stash
);
# _debug("# slurped " . length($got{$_}) . " bytes from $_\n");
}
CT_ORIG_STDOUT
$got
{stdout}
if
$do_stdout
&&
$do_tee
&&
$localize
{stdout};
CT_ORIG_STDERR
$got
{stderr}
if
$do_stderr
&&
$do_tee
&&
$localize
{stderr};
}
$? =
$exit_code
;
$@ =
$inner_error
if
$inner_error
;
die
$outer_error
if
$outer_error
;
# _debug( "# ending _capture_tee with (@_)...\n" );
return
unless
defined
wantarray
;
my
@return
;
push
@return
,
$got
{stdout}
if
$do_stdout
;
push
@return
,
$got
{stderr}
if
$do_stderr
&& !
$do_merge
;
push
@return
,
@result
;
return
wantarray
?
@return
:
$return
[0];
}
1;
inc/Inline/C.pm view on Meta::CPAN
925926927928929930931932933934935936937938939940941942943944
my
$errcode
= $? >> 8;
$output
.=
<<END;
A problem was encountered while attempting to compile and install your Inline
$o->{API}{language} code. The command that failed was:
\"$cmd\" with error code $errcode
The build directory was:
$build_dir
To debug the problem, cd to the build directory, and inspect the output files.
END
if
(
$cmd
=~ /^make >/) {
for
(
sort
keys
%ENV
) {
$output
.=
"Environment $_ = '$ENV{$_}'\n"
if
/^(?:MAKE|PATH)/;
}
}
return
$output
;
}
( run in 0.538 second using v1.01-cache-2.11-cpan-95122f20152 )