Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- my_container_sandbox/usr/share/perl/5.30.0/Archive/Tar/File.pm +716 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Base.pm +405 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Platform/Unix.pm +40 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Platform/VMS.pm +290 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Platform/android.pm +39 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Platform/cygwin.pm +33 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Platform/darwin.pm +22 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Command/MM.pm +323 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Constant/Base.pm +1019 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Constant/ProxySubs.pm +682 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Constant/XS.pm +259 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/MakeMaker/FAQ.pod +666 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/ParseXS/Constants.pm +44 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/ParseXS/CountLines.pm +54 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/ParseXS/Eval.pm +97 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/ParseXS/Utilities.pm +821 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Typemaps/Cmd.pm +168 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Typemaps/InputMap.pm +116 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Typemaps/OutputMap.pm +209 -0
- my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Typemaps/Type.pm +121 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/API/Breakage.pm +178 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/API/Context.pm +1013 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/API/Instance.pm +822 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/API/Stack.pm +220 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Diag.pm +99 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Encoding.pm +97 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Fail.pm +118 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Generic.pm +280 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Note.pm +97 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Pass.pm +114 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Plan.pm +169 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Skip.pm +127 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Subtest.pm +160 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/V2.pm +238 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Waiting.pm +76 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/About.pm +92 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Amnesty.pm +91 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Assert.pm +93 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Control.pm +100 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Error.pm +93 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Hub.pm +109 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Info.pm +132 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Meta.pm +104 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Parent.pm +98 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Plan.pm +94 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Render.pm +106 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Trace.pm +279 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Formatter/TAP.pm +524 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Tools/Tiny.pm +435 -0
- my_container_sandbox/usr/share/perl/5.30.0/Test2/Util/HashBase.pm +435 -0
my_container_sandbox/usr/share/perl/5.30.0/Archive/Tar/File.pm
ADDED
|
@@ -0,0 +1,716 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Archive::Tar::File;
|
| 2 |
+
use strict;
|
| 3 |
+
|
| 4 |
+
use Carp ();
|
| 5 |
+
use IO::File;
|
| 6 |
+
use File::Spec::Unix ();
|
| 7 |
+
use File::Spec ();
|
| 8 |
+
use File::Basename ();
|
| 9 |
+
|
| 10 |
+
### avoid circular use, so only require;
|
| 11 |
+
require Archive::Tar;
|
| 12 |
+
use Archive::Tar::Constant;
|
| 13 |
+
|
| 14 |
+
use vars qw[@ISA $VERSION];
|
| 15 |
+
#@ISA = qw[Archive::Tar];
|
| 16 |
+
$VERSION = '2.32';
|
| 17 |
+
|
| 18 |
+
### set value to 1 to oct() it during the unpack ###
|
| 19 |
+
|
| 20 |
+
my $tmpl = [
|
| 21 |
+
name => 0, # string A100
|
| 22 |
+
mode => 1, # octal A8
|
| 23 |
+
uid => 1, # octal A8
|
| 24 |
+
gid => 1, # octal A8
|
| 25 |
+
size => 0, # octal # cdrake - not *always* octal.. A12
|
| 26 |
+
mtime => 1, # octal A12
|
| 27 |
+
chksum => 1, # octal A8
|
| 28 |
+
type => 0, # character A1
|
| 29 |
+
linkname => 0, # string A100
|
| 30 |
+
magic => 0, # string A6
|
| 31 |
+
version => 0, # 2 bytes A2
|
| 32 |
+
uname => 0, # string A32
|
| 33 |
+
gname => 0, # string A32
|
| 34 |
+
devmajor => 1, # octal A8
|
| 35 |
+
devminor => 1, # octal A8
|
| 36 |
+
prefix => 0, # A155 x 12
|
| 37 |
+
|
| 38 |
+
### end UNPACK items ###
|
| 39 |
+
raw => 0, # the raw data chunk
|
| 40 |
+
data => 0, # the data associated with the file --
|
| 41 |
+
# This might be very memory intensive
|
| 42 |
+
];
|
| 43 |
+
|
| 44 |
+
### install get/set accessors for this object.
|
| 45 |
+
for ( my $i=0; $i<scalar @$tmpl ; $i+=2 ) {
|
| 46 |
+
my $key = $tmpl->[$i];
|
| 47 |
+
no strict 'refs';
|
| 48 |
+
*{__PACKAGE__."::$key"} = sub {
|
| 49 |
+
my $self = shift;
|
| 50 |
+
$self->{$key} = $_[0] if @_;
|
| 51 |
+
|
| 52 |
+
### just in case the key is not there or undef or something ###
|
| 53 |
+
{ local $^W = 0;
|
| 54 |
+
return $self->{$key};
|
| 55 |
+
}
|
| 56 |
+
}
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
=head1 NAME
|
| 60 |
+
|
| 61 |
+
Archive::Tar::File - a subclass for in-memory extracted file from Archive::Tar
|
| 62 |
+
|
| 63 |
+
=head1 SYNOPSIS
|
| 64 |
+
|
| 65 |
+
my @items = $tar->get_files;
|
| 66 |
+
|
| 67 |
+
print $_->name, ' ', $_->size, "\n" for @items;
|
| 68 |
+
|
| 69 |
+
print $object->get_content;
|
| 70 |
+
$object->replace_content('new content');
|
| 71 |
+
|
| 72 |
+
$object->rename( 'new/full/path/to/file.c' );
|
| 73 |
+
|
| 74 |
+
=head1 DESCRIPTION
|
| 75 |
+
|
| 76 |
+
Archive::Tar::Files provides a neat little object layer for in-memory
|
| 77 |
+
extracted files. It's mostly used internally in Archive::Tar to tidy
|
| 78 |
+
up the code, but there's no reason users shouldn't use this API as
|
| 79 |
+
well.
|
| 80 |
+
|
| 81 |
+
=head2 Accessors
|
| 82 |
+
|
| 83 |
+
A lot of the methods in this package are accessors to the various
|
| 84 |
+
fields in the tar header:
|
| 85 |
+
|
| 86 |
+
=over 4
|
| 87 |
+
|
| 88 |
+
=item name
|
| 89 |
+
|
| 90 |
+
The file's name
|
| 91 |
+
|
| 92 |
+
=item mode
|
| 93 |
+
|
| 94 |
+
The file's mode
|
| 95 |
+
|
| 96 |
+
=item uid
|
| 97 |
+
|
| 98 |
+
The user id owning the file
|
| 99 |
+
|
| 100 |
+
=item gid
|
| 101 |
+
|
| 102 |
+
The group id owning the file
|
| 103 |
+
|
| 104 |
+
=item size
|
| 105 |
+
|
| 106 |
+
File size in bytes
|
| 107 |
+
|
| 108 |
+
=item mtime
|
| 109 |
+
|
| 110 |
+
Modification time. Adjusted to mac-time on MacOS if required
|
| 111 |
+
|
| 112 |
+
=item chksum
|
| 113 |
+
|
| 114 |
+
Checksum field for the tar header
|
| 115 |
+
|
| 116 |
+
=item type
|
| 117 |
+
|
| 118 |
+
File type -- numeric, but comparable to exported constants -- see
|
| 119 |
+
Archive::Tar's documentation
|
| 120 |
+
|
| 121 |
+
=item linkname
|
| 122 |
+
|
| 123 |
+
If the file is a symlink, the file it's pointing to
|
| 124 |
+
|
| 125 |
+
=item magic
|
| 126 |
+
|
| 127 |
+
Tar magic string -- not useful for most users
|
| 128 |
+
|
| 129 |
+
=item version
|
| 130 |
+
|
| 131 |
+
Tar version string -- not useful for most users
|
| 132 |
+
|
| 133 |
+
=item uname
|
| 134 |
+
|
| 135 |
+
The user name that owns the file
|
| 136 |
+
|
| 137 |
+
=item gname
|
| 138 |
+
|
| 139 |
+
The group name that owns the file
|
| 140 |
+
|
| 141 |
+
=item devmajor
|
| 142 |
+
|
| 143 |
+
Device major number in case of a special file
|
| 144 |
+
|
| 145 |
+
=item devminor
|
| 146 |
+
|
| 147 |
+
Device minor number in case of a special file
|
| 148 |
+
|
| 149 |
+
=item prefix
|
| 150 |
+
|
| 151 |
+
Any directory to prefix to the extraction path, if any
|
| 152 |
+
|
| 153 |
+
=item raw
|
| 154 |
+
|
| 155 |
+
Raw tar header -- not useful for most users
|
| 156 |
+
|
| 157 |
+
=back
|
| 158 |
+
|
| 159 |
+
=head1 Methods
|
| 160 |
+
|
| 161 |
+
=head2 Archive::Tar::File->new( file => $path )
|
| 162 |
+
|
| 163 |
+
Returns a new Archive::Tar::File object from an existing file.
|
| 164 |
+
|
| 165 |
+
Returns undef on failure.
|
| 166 |
+
|
| 167 |
+
=head2 Archive::Tar::File->new( data => $path, $data, $opt )
|
| 168 |
+
|
| 169 |
+
Returns a new Archive::Tar::File object from data.
|
| 170 |
+
|
| 171 |
+
C<$path> defines the file name (which need not exist), C<$data> the
|
| 172 |
+
file contents, and C<$opt> is a reference to a hash of attributes
|
| 173 |
+
which may be used to override the default attributes (fields in the
|
| 174 |
+
tar header), which are described above in the Accessors section.
|
| 175 |
+
|
| 176 |
+
Returns undef on failure.
|
| 177 |
+
|
| 178 |
+
=head2 Archive::Tar::File->new( chunk => $chunk )
|
| 179 |
+
|
| 180 |
+
Returns a new Archive::Tar::File object from a raw 512-byte tar
|
| 181 |
+
archive chunk.
|
| 182 |
+
|
| 183 |
+
Returns undef on failure.
|
| 184 |
+
|
| 185 |
+
=cut
|
| 186 |
+
|
| 187 |
+
sub new {
|
| 188 |
+
my $class = shift;
|
| 189 |
+
my $what = shift;
|
| 190 |
+
|
| 191 |
+
my $obj = ($what eq 'chunk') ? __PACKAGE__->_new_from_chunk( @_ ) :
|
| 192 |
+
($what eq 'file' ) ? __PACKAGE__->_new_from_file( @_ ) :
|
| 193 |
+
($what eq 'data' ) ? __PACKAGE__->_new_from_data( @_ ) :
|
| 194 |
+
undef;
|
| 195 |
+
|
| 196 |
+
return $obj;
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
### copies the data, creates a clone ###
|
| 200 |
+
sub clone {
|
| 201 |
+
my $self = shift;
|
| 202 |
+
return bless { %$self }, ref $self;
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
sub _new_from_chunk {
|
| 206 |
+
my $class = shift;
|
| 207 |
+
my $chunk = shift or return; # 512 bytes of tar header
|
| 208 |
+
my %hash = @_;
|
| 209 |
+
|
| 210 |
+
### filter any arguments on defined-ness of values.
|
| 211 |
+
### this allows overriding from what the tar-header is saying
|
| 212 |
+
### about this tar-entry. Particularly useful for @LongLink files
|
| 213 |
+
my %args = map { $_ => $hash{$_} } grep { defined $hash{$_} } keys %hash;
|
| 214 |
+
|
| 215 |
+
### makes it start at 0 actually... :) ###
|
| 216 |
+
my $i = -1;
|
| 217 |
+
my %entry = map {
|
| 218 |
+
my ($s,$v)=($tmpl->[++$i],$tmpl->[++$i]); # cdrake
|
| 219 |
+
($_)=($_=~/^([^\0]*)/) unless($s eq 'size'); # cdrake
|
| 220 |
+
$s=> $v ? oct $_ : $_ # cdrake
|
| 221 |
+
# $tmpl->[++$i] => $tmpl->[++$i] ? oct $_ : $_ # removed by cdrake - mucks up binary sizes >8gb
|
| 222 |
+
} unpack( UNPACK, $chunk ); # cdrake
|
| 223 |
+
# } map { /^([^\0]*)/ } unpack( UNPACK, $chunk ); # old - replaced now by cdrake
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
if(substr($entry{'size'}, 0, 1) eq "\x80") { # binary size extension for files >8gigs (> octal 77777777777777) # cdrake
|
| 227 |
+
my @sz=unpack("aCSNN",$entry{'size'}); $entry{'size'}=$sz[4]+(2**32)*$sz[3]+$sz[2]*(2**64); # Use the low 80 bits (should use the upper 15 as well, but as at year 2011, that seems unlikely to ever be needed - the numbers are just too big...) # cdrake
|
| 228 |
+
} else { # cdrake
|
| 229 |
+
($entry{'size'})=($entry{'size'}=~/^([^\0]*)/); $entry{'size'}=oct $entry{'size'}; # cdrake
|
| 230 |
+
} # cdrake
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
my $obj = bless { %entry, %args }, $class;
|
| 234 |
+
|
| 235 |
+
### magic is a filetype string.. it should have something like 'ustar' or
|
| 236 |
+
### something similar... if the chunk is garbage, skip it
|
| 237 |
+
return unless $obj->magic !~ /\W/;
|
| 238 |
+
|
| 239 |
+
### store the original chunk ###
|
| 240 |
+
$obj->raw( $chunk );
|
| 241 |
+
|
| 242 |
+
$obj->type(FILE) if ( (!length $obj->type) or ($obj->type =~ /\W/) );
|
| 243 |
+
$obj->type(DIR) if ( ($obj->is_file) && ($obj->name =~ m|/$|) );
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
return $obj;
|
| 247 |
+
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
sub _new_from_file {
|
| 251 |
+
my $class = shift;
|
| 252 |
+
my $path = shift;
|
| 253 |
+
|
| 254 |
+
### path has to at least exist
|
| 255 |
+
return unless defined $path;
|
| 256 |
+
|
| 257 |
+
my $type = __PACKAGE__->_filetype($path);
|
| 258 |
+
my $data = '';
|
| 259 |
+
|
| 260 |
+
READ: {
|
| 261 |
+
unless ($type == DIR ) {
|
| 262 |
+
my $fh = IO::File->new;
|
| 263 |
+
|
| 264 |
+
unless( $fh->open($path) ) {
|
| 265 |
+
### dangling symlinks are fine, stop reading but continue
|
| 266 |
+
### creating the object
|
| 267 |
+
last READ if $type == SYMLINK;
|
| 268 |
+
|
| 269 |
+
### otherwise, return from this function --
|
| 270 |
+
### anything that's *not* a symlink should be
|
| 271 |
+
### resolvable
|
| 272 |
+
return;
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
### binmode needed to read files properly on win32 ###
|
| 276 |
+
binmode $fh;
|
| 277 |
+
$data = do { local $/; <$fh> };
|
| 278 |
+
close $fh;
|
| 279 |
+
}
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
my @items = qw[mode uid gid size mtime];
|
| 283 |
+
my %hash = map { shift(@items), $_ } (lstat $path)[2,4,5,7,9];
|
| 284 |
+
|
| 285 |
+
if (ON_VMS) {
|
| 286 |
+
### VMS has two UID modes, traditional and POSIX. Normally POSIX is
|
| 287 |
+
### not used. We currently do not have an easy way to see if we are in
|
| 288 |
+
### POSIX mode. In traditional mode, the UID is actually the VMS UIC.
|
| 289 |
+
### The VMS UIC has the upper 16 bits is the GID, which in many cases
|
| 290 |
+
### the VMS UIC will be larger than 209715, the largest that TAR can
|
| 291 |
+
### handle. So for now, assume it is traditional if the UID is larger
|
| 292 |
+
### than 0x10000.
|
| 293 |
+
|
| 294 |
+
if ($hash{uid} > 0x10000) {
|
| 295 |
+
$hash{uid} = $hash{uid} & 0xFFFF;
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
### The file length from stat() is the physical length of the file
|
| 299 |
+
### However the amount of data read in may be more for some file types.
|
| 300 |
+
### Fixed length files are read past the logical EOF to end of the block
|
| 301 |
+
### containing. Other file types get expanded on read because record
|
| 302 |
+
### delimiters are added.
|
| 303 |
+
|
| 304 |
+
my $data_len = length $data;
|
| 305 |
+
$hash{size} = $data_len if $hash{size} < $data_len;
|
| 306 |
+
|
| 307 |
+
}
|
| 308 |
+
### you *must* set size == 0 on symlinks, or the next entry will be
|
| 309 |
+
### though of as the contents of the symlink, which is wrong.
|
| 310 |
+
### this fixes bug #7937
|
| 311 |
+
$hash{size} = 0 if ($type == DIR or $type == SYMLINK);
|
| 312 |
+
$hash{mtime} -= TIME_OFFSET;
|
| 313 |
+
|
| 314 |
+
### strip the high bits off the mode, which we don't need to store
|
| 315 |
+
$hash{mode} = STRIP_MODE->( $hash{mode} );
|
| 316 |
+
|
| 317 |
+
|
| 318 |
+
### probably requires some file path munging here ... ###
|
| 319 |
+
### name and prefix are set later
|
| 320 |
+
my $obj = {
|
| 321 |
+
%hash,
|
| 322 |
+
name => '',
|
| 323 |
+
chksum => CHECK_SUM,
|
| 324 |
+
type => $type,
|
| 325 |
+
linkname => ($type == SYMLINK and CAN_READLINK)
|
| 326 |
+
? readlink $path
|
| 327 |
+
: '',
|
| 328 |
+
magic => MAGIC,
|
| 329 |
+
version => TAR_VERSION,
|
| 330 |
+
uname => UNAME->( $hash{uid} ),
|
| 331 |
+
gname => GNAME->( $hash{gid} ),
|
| 332 |
+
devmajor => 0, # not handled
|
| 333 |
+
devminor => 0, # not handled
|
| 334 |
+
prefix => '',
|
| 335 |
+
data => $data,
|
| 336 |
+
};
|
| 337 |
+
|
| 338 |
+
bless $obj, $class;
|
| 339 |
+
|
| 340 |
+
### fix up the prefix and file from the path
|
| 341 |
+
my($prefix,$file) = $obj->_prefix_and_file( $path );
|
| 342 |
+
$obj->prefix( $prefix );
|
| 343 |
+
$obj->name( $file );
|
| 344 |
+
|
| 345 |
+
return $obj;
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
sub _new_from_data {
|
| 349 |
+
my $class = shift;
|
| 350 |
+
my $path = shift; return unless defined $path;
|
| 351 |
+
my $data = shift; return unless defined $data;
|
| 352 |
+
my $opt = shift;
|
| 353 |
+
|
| 354 |
+
my $obj = {
|
| 355 |
+
data => $data,
|
| 356 |
+
name => '',
|
| 357 |
+
mode => MODE,
|
| 358 |
+
uid => UID,
|
| 359 |
+
gid => GID,
|
| 360 |
+
size => length $data,
|
| 361 |
+
mtime => time - TIME_OFFSET,
|
| 362 |
+
chksum => CHECK_SUM,
|
| 363 |
+
type => FILE,
|
| 364 |
+
linkname => '',
|
| 365 |
+
magic => MAGIC,
|
| 366 |
+
version => TAR_VERSION,
|
| 367 |
+
uname => UNAME->( UID ),
|
| 368 |
+
gname => GNAME->( GID ),
|
| 369 |
+
devminor => 0,
|
| 370 |
+
devmajor => 0,
|
| 371 |
+
prefix => '',
|
| 372 |
+
};
|
| 373 |
+
|
| 374 |
+
### overwrite with user options, if provided ###
|
| 375 |
+
if( $opt and ref $opt eq 'HASH' ) {
|
| 376 |
+
for my $key ( keys %$opt ) {
|
| 377 |
+
|
| 378 |
+
### don't write bogus options ###
|
| 379 |
+
next unless exists $obj->{$key};
|
| 380 |
+
$obj->{$key} = $opt->{$key};
|
| 381 |
+
}
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
bless $obj, $class;
|
| 385 |
+
|
| 386 |
+
### fix up the prefix and file from the path
|
| 387 |
+
my($prefix,$file) = $obj->_prefix_and_file( $path );
|
| 388 |
+
$obj->prefix( $prefix );
|
| 389 |
+
$obj->name( $file );
|
| 390 |
+
|
| 391 |
+
return $obj;
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
+
sub _prefix_and_file {
|
| 395 |
+
my $self = shift;
|
| 396 |
+
my $path = shift;
|
| 397 |
+
|
| 398 |
+
my ($vol, $dirs, $file) = File::Spec->splitpath( $path, $self->is_dir );
|
| 399 |
+
my @dirs = File::Spec->splitdir( File::Spec->canonpath($dirs) );
|
| 400 |
+
|
| 401 |
+
### if it's a directory, then $file might be empty
|
| 402 |
+
$file = pop @dirs if $self->is_dir and not length $file;
|
| 403 |
+
|
| 404 |
+
### splitting ../ gives you the relative path in native syntax
|
| 405 |
+
### Remove the root (000000) directory
|
| 406 |
+
### The volume from splitpath will also be in native syntax
|
| 407 |
+
if (ON_VMS) {
|
| 408 |
+
map { $_ = '..' if $_ eq '-'; $_ = '' if $_ eq '000000' } @dirs;
|
| 409 |
+
if (length($vol)) {
|
| 410 |
+
$vol = VMS::Filespec::unixify($vol);
|
| 411 |
+
unshift @dirs, $vol;
|
| 412 |
+
}
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
my $prefix = File::Spec::Unix->catdir(@dirs);
|
| 416 |
+
return( $prefix, $file );
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
sub _filetype {
|
| 420 |
+
my $self = shift;
|
| 421 |
+
my $file = shift;
|
| 422 |
+
|
| 423 |
+
return unless defined $file;
|
| 424 |
+
|
| 425 |
+
return SYMLINK if (-l $file); # Symlink
|
| 426 |
+
|
| 427 |
+
return FILE if (-f _); # Plain file
|
| 428 |
+
|
| 429 |
+
return DIR if (-d _); # Directory
|
| 430 |
+
|
| 431 |
+
return FIFO if (-p _); # Named pipe
|
| 432 |
+
|
| 433 |
+
return SOCKET if (-S _); # Socket
|
| 434 |
+
|
| 435 |
+
return BLOCKDEV if (-b _); # Block special
|
| 436 |
+
|
| 437 |
+
return CHARDEV if (-c _); # Character special
|
| 438 |
+
|
| 439 |
+
### shouldn't happen, this is when making archives, not reading ###
|
| 440 |
+
return LONGLINK if ( $file eq LONGLINK_NAME );
|
| 441 |
+
|
| 442 |
+
return UNKNOWN; # Something else (like what?)
|
| 443 |
+
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
### this method 'downgrades' a file to plain file -- this is used for
|
| 447 |
+
### symlinks when FOLLOW_SYMLINKS is true.
|
| 448 |
+
sub _downgrade_to_plainfile {
|
| 449 |
+
my $entry = shift;
|
| 450 |
+
$entry->type( FILE );
|
| 451 |
+
$entry->mode( MODE );
|
| 452 |
+
$entry->linkname('');
|
| 453 |
+
|
| 454 |
+
return 1;
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
=head2 $bool = $file->extract( [ $alternative_name ] )
|
| 458 |
+
|
| 459 |
+
Extract this object, optionally to an alternative name.
|
| 460 |
+
|
| 461 |
+
See C<< Archive::Tar->extract_file >> for details.
|
| 462 |
+
|
| 463 |
+
Returns true on success and false on failure.
|
| 464 |
+
|
| 465 |
+
=cut
|
| 466 |
+
|
| 467 |
+
sub extract {
|
| 468 |
+
my $self = shift;
|
| 469 |
+
|
| 470 |
+
local $Carp::CarpLevel += 1;
|
| 471 |
+
|
| 472 |
+
return Archive::Tar->_extract_file( $self, @_ );
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
=head2 $path = $file->full_path
|
| 476 |
+
|
| 477 |
+
Returns the full path from the tar header; this is basically a
|
| 478 |
+
concatenation of the C<prefix> and C<name> fields.
|
| 479 |
+
|
| 480 |
+
=cut
|
| 481 |
+
|
| 482 |
+
sub full_path {
|
| 483 |
+
my $self = shift;
|
| 484 |
+
|
| 485 |
+
### if prefix field is empty
|
| 486 |
+
return $self->name unless defined $self->prefix and length $self->prefix;
|
| 487 |
+
|
| 488 |
+
### or otherwise, catfile'd
|
| 489 |
+
return File::Spec::Unix->catfile( $self->prefix, $self->name );
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
|
| 493 |
+
=head2 $bool = $file->validate
|
| 494 |
+
|
| 495 |
+
Done by Archive::Tar internally when reading the tar file:
|
| 496 |
+
validate the header against the checksum to ensure integer tar file.
|
| 497 |
+
|
| 498 |
+
Returns true on success, false on failure
|
| 499 |
+
|
| 500 |
+
=cut
|
| 501 |
+
|
| 502 |
+
sub validate {
|
| 503 |
+
my $self = shift;
|
| 504 |
+
|
| 505 |
+
my $raw = $self->raw;
|
| 506 |
+
|
| 507 |
+
### don't know why this one is different from the one we /write/ ###
|
| 508 |
+
substr ($raw, 148, 8) = " ";
|
| 509 |
+
|
| 510 |
+
### bug #43513: [PATCH] Accept wrong checksums from SunOS and HP-UX tar
|
| 511 |
+
### like GNU tar does. See here for details:
|
| 512 |
+
### http://www.gnu.org/software/tar/manual/tar.html#SEC139
|
| 513 |
+
### so we do both a signed AND unsigned validate. if one succeeds, that's
|
| 514 |
+
### good enough
|
| 515 |
+
return ( (unpack ("%16C*", $raw) == $self->chksum)
|
| 516 |
+
or (unpack ("%16c*", $raw) == $self->chksum)) ? 1 : 0;
|
| 517 |
+
}
|
| 518 |
+
|
| 519 |
+
=head2 $bool = $file->has_content
|
| 520 |
+
|
| 521 |
+
Returns a boolean to indicate whether the current object has content.
|
| 522 |
+
Some special files like directories and so on never will have any
|
| 523 |
+
content. This method is mainly to make sure you don't get warnings
|
| 524 |
+
for using uninitialized values when looking at an object's content.
|
| 525 |
+
|
| 526 |
+
=cut
|
| 527 |
+
|
| 528 |
+
sub has_content {
|
| 529 |
+
my $self = shift;
|
| 530 |
+
return defined $self->data() && length $self->data() ? 1 : 0;
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
=head2 $content = $file->get_content
|
| 534 |
+
|
| 535 |
+
Returns the current content for the in-memory file
|
| 536 |
+
|
| 537 |
+
=cut
|
| 538 |
+
|
| 539 |
+
sub get_content {
|
| 540 |
+
my $self = shift;
|
| 541 |
+
$self->data( );
|
| 542 |
+
}
|
| 543 |
+
|
| 544 |
+
=head2 $cref = $file->get_content_by_ref
|
| 545 |
+
|
| 546 |
+
Returns the current content for the in-memory file as a scalar
|
| 547 |
+
reference. Normal users won't need this, but it will save memory if
|
| 548 |
+
you are dealing with very large data files in your tar archive, since
|
| 549 |
+
it will pass the contents by reference, rather than make a copy of it
|
| 550 |
+
first.
|
| 551 |
+
|
| 552 |
+
=cut
|
| 553 |
+
|
| 554 |
+
sub get_content_by_ref {
|
| 555 |
+
my $self = shift;
|
| 556 |
+
|
| 557 |
+
return \$self->{data};
|
| 558 |
+
}
|
| 559 |
+
|
| 560 |
+
=head2 $bool = $file->replace_content( $content )
|
| 561 |
+
|
| 562 |
+
Replace the current content of the file with the new content. This
|
| 563 |
+
only affects the in-memory archive, not the on-disk version until
|
| 564 |
+
you write it.
|
| 565 |
+
|
| 566 |
+
Returns true on success, false on failure.
|
| 567 |
+
|
| 568 |
+
=cut
|
| 569 |
+
|
| 570 |
+
sub replace_content {
|
| 571 |
+
my $self = shift;
|
| 572 |
+
my $data = shift || '';
|
| 573 |
+
|
| 574 |
+
$self->data( $data );
|
| 575 |
+
$self->size( length $data );
|
| 576 |
+
return 1;
|
| 577 |
+
}
|
| 578 |
+
|
| 579 |
+
=head2 $bool = $file->rename( $new_name )
|
| 580 |
+
|
| 581 |
+
Rename the current file to $new_name.
|
| 582 |
+
|
| 583 |
+
Note that you must specify a Unix path for $new_name, since per tar
|
| 584 |
+
standard, all files in the archive must be Unix paths.
|
| 585 |
+
|
| 586 |
+
Returns true on success and false on failure.
|
| 587 |
+
|
| 588 |
+
=cut
|
| 589 |
+
|
| 590 |
+
sub rename {
|
| 591 |
+
my $self = shift;
|
| 592 |
+
my $path = shift;
|
| 593 |
+
|
| 594 |
+
return unless defined $path;
|
| 595 |
+
|
| 596 |
+
my ($prefix,$file) = $self->_prefix_and_file( $path );
|
| 597 |
+
|
| 598 |
+
$self->name( $file );
|
| 599 |
+
$self->prefix( $prefix );
|
| 600 |
+
|
| 601 |
+
return 1;
|
| 602 |
+
}
|
| 603 |
+
|
| 604 |
+
=head2 $bool = $file->chmod $mode)
|
| 605 |
+
|
| 606 |
+
Change mode of $file to $mode. The mode can be a string or a number
|
| 607 |
+
which is interpreted as octal whether or not a leading 0 is given.
|
| 608 |
+
|
| 609 |
+
Returns true on success and false on failure.
|
| 610 |
+
|
| 611 |
+
=cut
|
| 612 |
+
|
| 613 |
+
sub chmod {
|
| 614 |
+
my $self = shift;
|
| 615 |
+
my $mode = shift; return unless defined $mode && $mode =~ /^[0-7]{1,4}$/;
|
| 616 |
+
$self->{mode} = oct($mode);
|
| 617 |
+
return 1;
|
| 618 |
+
}
|
| 619 |
+
|
| 620 |
+
=head2 $bool = $file->chown( $user [, $group])
|
| 621 |
+
|
| 622 |
+
Change owner of $file to $user. If a $group is given that is changed
|
| 623 |
+
as well. You can also pass a single parameter with a colon separating the
|
| 624 |
+
use and group as in 'root:wheel'.
|
| 625 |
+
|
| 626 |
+
Returns true on success and false on failure.
|
| 627 |
+
|
| 628 |
+
=cut
|
| 629 |
+
|
| 630 |
+
sub chown {
|
| 631 |
+
my $self = shift;
|
| 632 |
+
my $uname = shift;
|
| 633 |
+
return unless defined $uname;
|
| 634 |
+
my $gname;
|
| 635 |
+
if (-1 != index($uname, ':')) {
|
| 636 |
+
($uname, $gname) = split(/:/, $uname);
|
| 637 |
+
} else {
|
| 638 |
+
$gname = shift if @_ > 0;
|
| 639 |
+
}
|
| 640 |
+
|
| 641 |
+
$self->uname( $uname );
|
| 642 |
+
$self->gname( $gname ) if $gname;
|
| 643 |
+
return 1;
|
| 644 |
+
}
|
| 645 |
+
|
| 646 |
+
=head1 Convenience methods
|
| 647 |
+
|
| 648 |
+
To quickly check the type of a C<Archive::Tar::File> object, you can
|
| 649 |
+
use the following methods:
|
| 650 |
+
|
| 651 |
+
=over 4
|
| 652 |
+
|
| 653 |
+
=item $file->is_file
|
| 654 |
+
|
| 655 |
+
Returns true if the file is of type C<file>
|
| 656 |
+
|
| 657 |
+
=item $file->is_dir
|
| 658 |
+
|
| 659 |
+
Returns true if the file is of type C<dir>
|
| 660 |
+
|
| 661 |
+
=item $file->is_hardlink
|
| 662 |
+
|
| 663 |
+
Returns true if the file is of type C<hardlink>
|
| 664 |
+
|
| 665 |
+
=item $file->is_symlink
|
| 666 |
+
|
| 667 |
+
Returns true if the file is of type C<symlink>
|
| 668 |
+
|
| 669 |
+
=item $file->is_chardev
|
| 670 |
+
|
| 671 |
+
Returns true if the file is of type C<chardev>
|
| 672 |
+
|
| 673 |
+
=item $file->is_blockdev
|
| 674 |
+
|
| 675 |
+
Returns true if the file is of type C<blockdev>
|
| 676 |
+
|
| 677 |
+
=item $file->is_fifo
|
| 678 |
+
|
| 679 |
+
Returns true if the file is of type C<fifo>
|
| 680 |
+
|
| 681 |
+
=item $file->is_socket
|
| 682 |
+
|
| 683 |
+
Returns true if the file is of type C<socket>
|
| 684 |
+
|
| 685 |
+
=item $file->is_longlink
|
| 686 |
+
|
| 687 |
+
Returns true if the file is of type C<LongLink>.
|
| 688 |
+
Should not happen after a successful C<read>.
|
| 689 |
+
|
| 690 |
+
=item $file->is_label
|
| 691 |
+
|
| 692 |
+
Returns true if the file is of type C<Label>.
|
| 693 |
+
Should not happen after a successful C<read>.
|
| 694 |
+
|
| 695 |
+
=item $file->is_unknown
|
| 696 |
+
|
| 697 |
+
Returns true if the file type is C<unknown>
|
| 698 |
+
|
| 699 |
+
=back
|
| 700 |
+
|
| 701 |
+
=cut
|
| 702 |
+
|
| 703 |
+
#stupid perl5.5.3 needs to warn if it's not numeric
|
| 704 |
+
sub is_file { local $^W; FILE == $_[0]->type }
|
| 705 |
+
sub is_dir { local $^W; DIR == $_[0]->type }
|
| 706 |
+
sub is_hardlink { local $^W; HARDLINK == $_[0]->type }
|
| 707 |
+
sub is_symlink { local $^W; SYMLINK == $_[0]->type }
|
| 708 |
+
sub is_chardev { local $^W; CHARDEV == $_[0]->type }
|
| 709 |
+
sub is_blockdev { local $^W; BLOCKDEV == $_[0]->type }
|
| 710 |
+
sub is_fifo { local $^W; FIFO == $_[0]->type }
|
| 711 |
+
sub is_socket { local $^W; SOCKET == $_[0]->type }
|
| 712 |
+
sub is_unknown { local $^W; UNKNOWN == $_[0]->type }
|
| 713 |
+
sub is_longlink { local $^W; LONGLINK eq $_[0]->type }
|
| 714 |
+
sub is_label { local $^W; LABEL eq $_[0]->type }
|
| 715 |
+
|
| 716 |
+
1;
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Base.pm
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::CBuilder::Base;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
use File::Spec;
|
| 5 |
+
use File::Basename;
|
| 6 |
+
use Cwd ();
|
| 7 |
+
use Config;
|
| 8 |
+
use Text::ParseWords;
|
| 9 |
+
use IPC::Cmd qw(can_run);
|
| 10 |
+
use File::Temp qw(tempfile);
|
| 11 |
+
|
| 12 |
+
our $VERSION = '0.280231'; # VERSION
|
| 13 |
+
|
| 14 |
+
# More details about C/C++ compilers:
|
| 15 |
+
# http://developers.sun.com/sunstudio/documentation/product/compiler.jsp
|
| 16 |
+
# http://gcc.gnu.org/
|
| 17 |
+
# http://publib.boulder.ibm.com/infocenter/comphelp/v101v121/index.jsp
|
| 18 |
+
# http://msdn.microsoft.com/en-us/vstudio/default.aspx
|
| 19 |
+
|
| 20 |
+
my %cc2cxx = (
|
| 21 |
+
# first line order is important to support wrappers like in pkgsrc
|
| 22 |
+
cc => [ 'c++', 'CC', 'aCC', 'cxx', ], # Sun Studio, HP ANSI C/C++ Compilers
|
| 23 |
+
gcc => [ 'g++' ], # GNU Compiler Collection
|
| 24 |
+
xlc => [ 'xlC' ], # IBM C/C++ Set, xlc without thread-safety
|
| 25 |
+
xlc_r => [ 'xlC_r' ], # IBM C/C++ Set, xlc with thread-safety
|
| 26 |
+
cl => [ 'cl' ], # Microsoft Visual Studio
|
| 27 |
+
);
|
| 28 |
+
|
| 29 |
+
sub new {
|
| 30 |
+
my $class = shift;
|
| 31 |
+
my $self = bless {@_}, $class;
|
| 32 |
+
|
| 33 |
+
$self->{properties}{perl} = $class->find_perl_interpreter
|
| 34 |
+
or warn "Warning: Can't locate your perl binary";
|
| 35 |
+
|
| 36 |
+
while (my ($k,$v) = each %Config) {
|
| 37 |
+
$self->{config}{$k} = $v unless exists $self->{config}{$k};
|
| 38 |
+
}
|
| 39 |
+
$self->{config}{cc} = $ENV{CC} if defined $ENV{CC};
|
| 40 |
+
$self->{config}{ccflags} = join(" ", $self->{config}{ccflags}, $ENV{CFLAGS})
|
| 41 |
+
if defined $ENV{CFLAGS};
|
| 42 |
+
$self->{config}{cxx} = $ENV{CXX} if defined $ENV{CXX};
|
| 43 |
+
$self->{config}{cxxflags} = $ENV{CXXFLAGS} if defined $ENV{CXXFLAGS};
|
| 44 |
+
$self->{config}{ld} = $ENV{LD} if defined $ENV{LD};
|
| 45 |
+
$self->{config}{ldflags} = join(" ", $self->{config}{ldflags}, $ENV{LDFLAGS})
|
| 46 |
+
if defined $ENV{LDFLAGS};
|
| 47 |
+
|
| 48 |
+
unless ( exists $self->{config}{cxx} ) {
|
| 49 |
+
|
| 50 |
+
my ($ccbase, $ccpath, $ccsfx ) = fileparse($self->{config}{cc}, qr/\.[^.]*/);
|
| 51 |
+
|
| 52 |
+
## If the path is just "cc", fileparse returns $ccpath as "./"
|
| 53 |
+
$ccpath = "" if $self->{config}{cc} =~ /^\Q$ccbase$ccsfx\E$/;
|
| 54 |
+
|
| 55 |
+
foreach my $cxx (@{$cc2cxx{$ccbase}}) {
|
| 56 |
+
my $cxx1 = File::Spec->catfile( $ccpath, $cxx . $ccsfx);
|
| 57 |
+
|
| 58 |
+
if( can_run( $cxx1 ) ) {
|
| 59 |
+
$self->{config}{cxx} = $cxx1;
|
| 60 |
+
last;
|
| 61 |
+
}
|
| 62 |
+
my $cxx2 = $cxx . $ccsfx;
|
| 63 |
+
|
| 64 |
+
if( can_run( $cxx2 ) ) {
|
| 65 |
+
$self->{config}{cxx} = $cxx2;
|
| 66 |
+
last;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
if( can_run( $cxx ) ) {
|
| 70 |
+
$self->{config}{cxx} = $cxx;
|
| 71 |
+
last;
|
| 72 |
+
}
|
| 73 |
+
}
|
| 74 |
+
unless ( exists $self->{config}{cxx} ) {
|
| 75 |
+
$self->{config}{cxx} = $self->{config}{cc};
|
| 76 |
+
my $cflags = $self->{config}{ccflags};
|
| 77 |
+
$self->{config}{cxxflags} = '-x c++';
|
| 78 |
+
$self->{config}{cxxflags} .= " $cflags" if defined $cflags;
|
| 79 |
+
}
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
return $self;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
sub find_perl_interpreter {
|
| 86 |
+
my $perl;
|
| 87 |
+
File::Spec->file_name_is_absolute($perl = $^X)
|
| 88 |
+
or -f ($perl = $Config::Config{perlpath})
|
| 89 |
+
or ($perl = $^X); # XXX how about using IPC::Cmd::can_run here?
|
| 90 |
+
return $perl;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
sub add_to_cleanup {
|
| 94 |
+
my $self = shift;
|
| 95 |
+
foreach (@_) {
|
| 96 |
+
$self->{files_to_clean}{$_} = 1;
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
sub cleanup {
|
| 101 |
+
my $self = shift;
|
| 102 |
+
foreach my $file (keys %{$self->{files_to_clean}}) {
|
| 103 |
+
unlink $file;
|
| 104 |
+
}
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
sub get_config {
|
| 108 |
+
return %{ $_[0]->{config} };
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
sub object_file {
|
| 112 |
+
my ($self, $filename) = @_;
|
| 113 |
+
|
| 114 |
+
# File name, minus the suffix
|
| 115 |
+
(my $file_base = $filename) =~ s/\.[^.]+$//;
|
| 116 |
+
return "$file_base$self->{config}{obj_ext}";
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
sub arg_include_dirs {
|
| 120 |
+
my $self = shift;
|
| 121 |
+
return map {"-I$_"} @_;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
sub arg_nolink { '-c' }
|
| 125 |
+
|
| 126 |
+
sub arg_object_file {
|
| 127 |
+
my ($self, $file) = @_;
|
| 128 |
+
return ('-o', $file);
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
sub arg_share_object_file {
|
| 132 |
+
my ($self, $file) = @_;
|
| 133 |
+
return ($self->split_like_shell($self->{config}{lddlflags}), '-o', $file);
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
sub arg_exec_file {
|
| 137 |
+
my ($self, $file) = @_;
|
| 138 |
+
return ('-o', $file);
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
sub arg_defines {
|
| 142 |
+
my ($self, %args) = @_;
|
| 143 |
+
return map "-D$_=$args{$_}", sort keys %args;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
sub compile {
|
| 147 |
+
my ($self, %args) = @_;
|
| 148 |
+
die "Missing 'source' argument to compile()" unless defined $args{source};
|
| 149 |
+
|
| 150 |
+
my $cf = $self->{config}; # For convenience
|
| 151 |
+
|
| 152 |
+
my $object_file = $args{object_file}
|
| 153 |
+
? $args{object_file}
|
| 154 |
+
: $self->object_file($args{source});
|
| 155 |
+
|
| 156 |
+
my $include_dirs_ref =
|
| 157 |
+
(exists($args{include_dirs}) && ref($args{include_dirs}) ne "ARRAY")
|
| 158 |
+
? [ $args{include_dirs} ]
|
| 159 |
+
: $args{include_dirs};
|
| 160 |
+
my @include_dirs = $self->arg_include_dirs(
|
| 161 |
+
@{ $include_dirs_ref || [] },
|
| 162 |
+
$self->perl_inc(),
|
| 163 |
+
);
|
| 164 |
+
|
| 165 |
+
my @defines = $self->arg_defines( %{$args{defines} || {}} );
|
| 166 |
+
|
| 167 |
+
my @extra_compiler_flags =
|
| 168 |
+
$self->split_like_shell($args{extra_compiler_flags});
|
| 169 |
+
my @cccdlflags = $self->split_like_shell($cf->{cccdlflags});
|
| 170 |
+
my @ccflags = $self->split_like_shell($args{'C++'} ? $cf->{cxxflags} : $cf->{ccflags});
|
| 171 |
+
my @optimize = $self->split_like_shell($cf->{optimize});
|
| 172 |
+
my @flags = (
|
| 173 |
+
@include_dirs,
|
| 174 |
+
@defines,
|
| 175 |
+
@cccdlflags,
|
| 176 |
+
@extra_compiler_flags,
|
| 177 |
+
$self->arg_nolink,
|
| 178 |
+
@ccflags,
|
| 179 |
+
@optimize,
|
| 180 |
+
$self->arg_object_file($object_file),
|
| 181 |
+
);
|
| 182 |
+
my @cc = $self->split_like_shell($args{'C++'} ? $cf->{cxx} : $cf->{cc});
|
| 183 |
+
|
| 184 |
+
$self->do_system(@cc, @flags, $args{source})
|
| 185 |
+
or die "error building $object_file from '$args{source}'";
|
| 186 |
+
|
| 187 |
+
return $object_file;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
sub have_compiler {
|
| 191 |
+
my ($self, $is_cplusplus) = @_;
|
| 192 |
+
my $have_compiler_flag = $is_cplusplus ? "have_cxx" : "have_cc";
|
| 193 |
+
my $suffix = $is_cplusplus ? ".cc" : ".c";
|
| 194 |
+
return $self->{$have_compiler_flag} if defined $self->{$have_compiler_flag};
|
| 195 |
+
|
| 196 |
+
my $result;
|
| 197 |
+
my $attempts = 3;
|
| 198 |
+
# tmpdir has issues for some people so fall back to current dir
|
| 199 |
+
|
| 200 |
+
# don't clobber existing files (rare, but possible)
|
| 201 |
+
my ( $FH, $tmpfile ) = tempfile( "compilet-XXXXX", SUFFIX => $suffix );
|
| 202 |
+
binmode $FH;
|
| 203 |
+
|
| 204 |
+
if ( $is_cplusplus ) {
|
| 205 |
+
print $FH "class Bogus { public: int boot_compilet() { return 1; } };\n";
|
| 206 |
+
}
|
| 207 |
+
else {
|
| 208 |
+
print $FH "int boot_compilet() { return 1; }\n";
|
| 209 |
+
}
|
| 210 |
+
close $FH;
|
| 211 |
+
|
| 212 |
+
my ($obj_file, @lib_files);
|
| 213 |
+
eval {
|
| 214 |
+
local $^W = 0;
|
| 215 |
+
local $self->{quiet} = 1;
|
| 216 |
+
$obj_file = $self->compile('C++' => $is_cplusplus, source => $tmpfile);
|
| 217 |
+
@lib_files = $self->link(objects => $obj_file, module_name => 'compilet');
|
| 218 |
+
};
|
| 219 |
+
$result = $@ ? 0 : 1;
|
| 220 |
+
|
| 221 |
+
foreach (grep defined, $tmpfile, $obj_file, @lib_files) {
|
| 222 |
+
1 while unlink;
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
return $self->{$have_compiler_flag} = $result;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
sub have_cplusplus {
|
| 229 |
+
push @_, 1;
|
| 230 |
+
goto &have_compiler;
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
sub lib_file {
|
| 234 |
+
my ($self, $dl_file, %args) = @_;
|
| 235 |
+
$dl_file =~ s/\.[^.]+$//;
|
| 236 |
+
$dl_file =~ tr/"//d;
|
| 237 |
+
|
| 238 |
+
if (defined $args{module_name} and length $args{module_name}) {
|
| 239 |
+
# Need to create with the same name as DynaLoader will load with.
|
| 240 |
+
require DynaLoader;
|
| 241 |
+
if (defined &DynaLoader::mod2fname) {
|
| 242 |
+
my $lib = DynaLoader::mod2fname([split /::/, $args{module_name}]);
|
| 243 |
+
my ($dev, $lib_dir, undef) = File::Spec->splitpath($dl_file);
|
| 244 |
+
$dl_file = File::Spec->catpath($dev, $lib_dir, $lib);
|
| 245 |
+
}
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
$dl_file .= ".$self->{config}{dlext}";
|
| 249 |
+
|
| 250 |
+
return $dl_file;
|
| 251 |
+
}
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
sub exe_file {
|
| 255 |
+
my ($self, $dl_file) = @_;
|
| 256 |
+
$dl_file =~ s/\.[^.]+$//;
|
| 257 |
+
$dl_file =~ tr/"//d;
|
| 258 |
+
return "$dl_file$self->{config}{_exe}";
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
sub need_prelink { 0 }
|
| 262 |
+
|
| 263 |
+
sub extra_link_args_after_prelink { return }
|
| 264 |
+
|
| 265 |
+
sub prelink {
|
| 266 |
+
my ($self, %args) = @_;
|
| 267 |
+
|
| 268 |
+
my ($dl_file_out, $mksymlists_args) = _prepare_mksymlists_args(\%args);
|
| 269 |
+
|
| 270 |
+
require ExtUtils::Mksymlists;
|
| 271 |
+
# dl. abbrev for dynamic library
|
| 272 |
+
ExtUtils::Mksymlists::Mksymlists( %{ $mksymlists_args } );
|
| 273 |
+
|
| 274 |
+
# Mksymlists will create one of these files
|
| 275 |
+
return grep -e, map "$dl_file_out.$_", qw(ext def opt);
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
sub _prepare_mksymlists_args {
|
| 279 |
+
my $args = shift;
|
| 280 |
+
($args->{dl_file} = $args->{dl_name}) =~ s/.*::// unless $args->{dl_file};
|
| 281 |
+
|
| 282 |
+
my %mksymlists_args = (
|
| 283 |
+
DL_VARS => $args->{dl_vars} || [],
|
| 284 |
+
DL_FUNCS => $args->{dl_funcs} || {},
|
| 285 |
+
FUNCLIST => $args->{dl_func_list} || [],
|
| 286 |
+
IMPORTS => $args->{dl_imports} || {},
|
| 287 |
+
NAME => $args->{dl_name}, # Name of the Perl module
|
| 288 |
+
DLBASE => $args->{dl_base}, # Basename of DLL file
|
| 289 |
+
FILE => $args->{dl_file}, # Dir + Basename of symlist file
|
| 290 |
+
VERSION => (defined $args->{dl_version} ? $args->{dl_version} : '0.0'),
|
| 291 |
+
);
|
| 292 |
+
return ($args->{dl_file}, \%mksymlists_args);
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
sub link {
|
| 296 |
+
my ($self, %args) = @_;
|
| 297 |
+
return $self->_do_link('lib_file', lddl => 1, %args);
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
sub link_executable {
|
| 301 |
+
my ($self, %args) = @_;
|
| 302 |
+
return $self->_do_link('exe_file', lddl => 0, %args);
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
sub _do_link {
|
| 306 |
+
my ($self, $type, %args) = @_;
|
| 307 |
+
|
| 308 |
+
my $cf = $self->{config}; # For convenience
|
| 309 |
+
|
| 310 |
+
my $objects = delete $args{objects};
|
| 311 |
+
$objects = [$objects] unless ref $objects;
|
| 312 |
+
my $out = $args{$type} || $self->$type($objects->[0], %args);
|
| 313 |
+
|
| 314 |
+
my @temp_files;
|
| 315 |
+
@temp_files =
|
| 316 |
+
$self->prelink(%args, dl_name => $args{module_name})
|
| 317 |
+
if $args{lddl} && $self->need_prelink;
|
| 318 |
+
|
| 319 |
+
my @linker_flags = (
|
| 320 |
+
$self->split_like_shell($args{extra_linker_flags}),
|
| 321 |
+
$self->extra_link_args_after_prelink(
|
| 322 |
+
%args, dl_name => $args{module_name}, prelink_res => \@temp_files
|
| 323 |
+
)
|
| 324 |
+
);
|
| 325 |
+
|
| 326 |
+
my @output = $args{lddl}
|
| 327 |
+
? $self->arg_share_object_file($out)
|
| 328 |
+
: $self->arg_exec_file($out);
|
| 329 |
+
my @shrp = $self->split_like_shell($cf->{shrpenv});
|
| 330 |
+
my @ld = $self->split_like_shell($cf->{ld});
|
| 331 |
+
|
| 332 |
+
$self->do_system(@shrp, @ld, @output, @$objects, @linker_flags)
|
| 333 |
+
or die "error building $out from @$objects";
|
| 334 |
+
|
| 335 |
+
return wantarray ? ($out, @temp_files) : $out;
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
|
| 339 |
+
sub do_system {
|
| 340 |
+
my ($self, @cmd) = @_;
|
| 341 |
+
print "@cmd\n" if !$self->{quiet};
|
| 342 |
+
return !system(@cmd);
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
sub split_like_shell {
|
| 346 |
+
my ($self, $string) = @_;
|
| 347 |
+
|
| 348 |
+
return () unless defined($string);
|
| 349 |
+
return @$string if UNIVERSAL::isa($string, 'ARRAY');
|
| 350 |
+
$string =~ s/^\s+|\s+$//g;
|
| 351 |
+
return () unless length($string);
|
| 352 |
+
|
| 353 |
+
# Text::ParseWords replaces all 'escaped' characters with themselves, which completely
|
| 354 |
+
# breaks paths under windows. As such, we forcibly replace backwards slashes with forward
|
| 355 |
+
# slashes on windows.
|
| 356 |
+
$string =~ s@\\@/@g if $^O eq 'MSWin32';
|
| 357 |
+
|
| 358 |
+
return Text::ParseWords::shellwords($string);
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
# if building perl, perl's main source directory
|
| 362 |
+
sub perl_src {
|
| 363 |
+
# N.B. makemaker actually searches regardless of PERL_CORE, but
|
| 364 |
+
# only squawks at not finding it if PERL_CORE is set
|
| 365 |
+
|
| 366 |
+
return unless $ENV{PERL_CORE};
|
| 367 |
+
|
| 368 |
+
my $Updir = File::Spec->updir;
|
| 369 |
+
my $dir = File::Spec->curdir;
|
| 370 |
+
|
| 371 |
+
# Try up to 5 levels upwards
|
| 372 |
+
for (0..10) {
|
| 373 |
+
if (
|
| 374 |
+
-f File::Spec->catfile($dir,"config_h.SH")
|
| 375 |
+
&&
|
| 376 |
+
-f File::Spec->catfile($dir,"perl.h")
|
| 377 |
+
&&
|
| 378 |
+
-f File::Spec->catfile($dir,"lib","Exporter.pm")
|
| 379 |
+
) {
|
| 380 |
+
return Cwd::realpath( $dir );
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
$dir = File::Spec->catdir($dir, $Updir);
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
warn "PERL_CORE is set but I can't find your perl source!\n";
|
| 387 |
+
return ''; # return empty string if $ENV{PERL_CORE} but can't find dir ???
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
# directory of perl's include files
|
| 391 |
+
sub perl_inc {
|
| 392 |
+
my $self = shift;
|
| 393 |
+
|
| 394 |
+
$self->perl_src() || File::Spec->catdir($self->{config}{archlibexp},"CORE");
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
sub DESTROY {
|
| 398 |
+
my $self = shift;
|
| 399 |
+
local($., $@, $!, $^E, $?);
|
| 400 |
+
$self->cleanup();
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
1;
|
| 404 |
+
|
| 405 |
+
# vim: ts=2 sw=2 et:
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Platform/Unix.pm
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::CBuilder::Platform::Unix;
|
| 2 |
+
|
| 3 |
+
use warnings;
|
| 4 |
+
use strict;
|
| 5 |
+
use ExtUtils::CBuilder::Base;
|
| 6 |
+
|
| 7 |
+
our $VERSION = '0.280231'; # VERSION
|
| 8 |
+
our @ISA = qw(ExtUtils::CBuilder::Base);
|
| 9 |
+
|
| 10 |
+
sub link_executable {
|
| 11 |
+
my $self = shift;
|
| 12 |
+
|
| 13 |
+
# On some platforms (which ones??) $Config{cc} seems to be a better
|
| 14 |
+
# bet for linking executables than $Config{ld}. Cygwin is a notable
|
| 15 |
+
# exception.
|
| 16 |
+
local $self->{config}{ld} =
|
| 17 |
+
$self->{config}{cc} . " " . $self->{config}{ldflags};
|
| 18 |
+
return $self->SUPER::link_executable(@_);
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
sub link {
|
| 22 |
+
my $self = shift;
|
| 23 |
+
my $cf = $self->{config};
|
| 24 |
+
|
| 25 |
+
# Some platforms (notably Mac OS X 10.3, but some others too) expect
|
| 26 |
+
# the syntax "FOO=BAR /bin/command arg arg" to work in %Config
|
| 27 |
+
# (notably $Config{ld}). It usually works in system(SCALAR), but we
|
| 28 |
+
# use system(LIST). We fix it up here with 'env'.
|
| 29 |
+
|
| 30 |
+
local $cf->{ld} = $cf->{ld};
|
| 31 |
+
if (ref $cf->{ld}) {
|
| 32 |
+
unshift @{$cf->{ld}}, 'env' if $cf->{ld}[0] =~ /^\s*\w+=/;
|
| 33 |
+
} else {
|
| 34 |
+
$cf->{ld} =~ s/^(\s*\w+=)/env $1/;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
return $self->SUPER::link(@_);
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
1;
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Platform/VMS.pm
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::CBuilder::Platform::VMS;
|
| 2 |
+
|
| 3 |
+
use warnings;
|
| 4 |
+
use strict;
|
| 5 |
+
use ExtUtils::CBuilder::Base;
|
| 6 |
+
|
| 7 |
+
our $VERSION = '0.280231'; # VERSION
|
| 8 |
+
our @ISA = qw(ExtUtils::CBuilder::Base);
|
| 9 |
+
|
| 10 |
+
use File::Spec::Functions qw(catfile catdir);
|
| 11 |
+
use Config;
|
| 12 |
+
|
| 13 |
+
# We do prelink, but don't want the parent to redo it.
|
| 14 |
+
|
| 15 |
+
sub need_prelink { 0 }
|
| 16 |
+
|
| 17 |
+
sub arg_defines {
|
| 18 |
+
my ($self, %args) = @_;
|
| 19 |
+
|
| 20 |
+
s/"/""/g foreach values %args;
|
| 21 |
+
|
| 22 |
+
my @config_defines;
|
| 23 |
+
|
| 24 |
+
# VMS can only have one define qualifier; add the one from config, if any.
|
| 25 |
+
if ($self->{config}{ccflags} =~ s{/ def[^=]+ =+ \(? ([^\/\)]*) } {}ix) {
|
| 26 |
+
push @config_defines, $1;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
return '' unless keys(%args) || @config_defines;
|
| 30 |
+
|
| 31 |
+
return ('/define=('
|
| 32 |
+
. join(',',
|
| 33 |
+
@config_defines,
|
| 34 |
+
map "\"$_" . ( length($args{$_}) ? "=$args{$_}" : '') . "\"",
|
| 35 |
+
sort keys %args)
|
| 36 |
+
. ')');
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
sub arg_include_dirs {
|
| 40 |
+
my ($self, @dirs) = @_;
|
| 41 |
+
|
| 42 |
+
# VMS can only have one include list, add the one from config.
|
| 43 |
+
if ($self->{config}{ccflags} =~ s{/inc[^=]+(?:=)+(?:\()?([^\/\)]*)} {}i) {
|
| 44 |
+
unshift @dirs, $1;
|
| 45 |
+
}
|
| 46 |
+
return unless @dirs;
|
| 47 |
+
|
| 48 |
+
return ('/include=(' . join(',', @dirs) . ')');
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
# We override the compile method because we consume the includes and defines
|
| 52 |
+
# parts of ccflags in the process of compiling but don't save those parts
|
| 53 |
+
# anywhere, so $self->{config}{ccflags} needs to be reset for each compile
|
| 54 |
+
# operation.
|
| 55 |
+
|
| 56 |
+
sub compile {
|
| 57 |
+
my ($self, %args) = @_;
|
| 58 |
+
|
| 59 |
+
$self->{config}{ccflags} = $Config{ccflags};
|
| 60 |
+
$self->{config}{ccflags} = $ENV{CFLAGS} if defined $ENV{CFLAGS};
|
| 61 |
+
|
| 62 |
+
return $self->SUPER::compile(%args);
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
sub _do_link {
|
| 66 |
+
my ($self, $type, %args) = @_;
|
| 67 |
+
|
| 68 |
+
my $objects = delete $args{objects};
|
| 69 |
+
$objects = [$objects] unless ref $objects;
|
| 70 |
+
|
| 71 |
+
if ($args{lddl}) {
|
| 72 |
+
|
| 73 |
+
# prelink will call Mksymlists, which creates the extension-specific
|
| 74 |
+
# linker options file and populates it with the boot symbol.
|
| 75 |
+
|
| 76 |
+
my @temp_files = $self->prelink(%args, dl_name => $args{module_name});
|
| 77 |
+
|
| 78 |
+
# We now add the rest of what we need to the linker options file. We
|
| 79 |
+
# should replicate the functionality of C<ExtUtils::MM_VMS::dlsyms>,
|
| 80 |
+
# but there is as yet no infrastructure for handling object libraries,
|
| 81 |
+
# so for now we depend on object files being listed individually on the
|
| 82 |
+
# command line, which should work for simple cases. We do bring in our
|
| 83 |
+
# own version of C<ExtUtils::Liblist::Kid::ext> so that any additional
|
| 84 |
+
# libraries (including PERLSHR) can be added to the options file.
|
| 85 |
+
|
| 86 |
+
my @optlibs = $self->_liblist_ext( $args{'libs'} );
|
| 87 |
+
|
| 88 |
+
my $optfile = 'sys$disk:[]' . $temp_files[0];
|
| 89 |
+
open my $opt_fh, '>>', $optfile
|
| 90 |
+
or die "_do_link: Unable to open $optfile: $!";
|
| 91 |
+
for my $lib (@optlibs) {print $opt_fh "$lib\n" if length $lib }
|
| 92 |
+
close $opt_fh;
|
| 93 |
+
|
| 94 |
+
$objects->[-1] .= ',';
|
| 95 |
+
push @$objects, $optfile . '/OPTIONS,';
|
| 96 |
+
|
| 97 |
+
# This one not needed for DEC C, but leave for completeness.
|
| 98 |
+
push @$objects, $self->perl_inc() . 'perlshr_attr.opt/OPTIONS';
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
return $self->SUPER::_do_link($type, %args, objects => $objects);
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
sub arg_nolink { return; }
|
| 105 |
+
|
| 106 |
+
sub arg_object_file {
|
| 107 |
+
my ($self, $file) = @_;
|
| 108 |
+
return "/obj=$file";
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
sub arg_exec_file {
|
| 112 |
+
my ($self, $file) = @_;
|
| 113 |
+
return ("/exe=$file");
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
sub arg_share_object_file {
|
| 117 |
+
my ($self, $file) = @_;
|
| 118 |
+
return ("$self->{config}{lddlflags}=$file");
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
# The following is reproduced almost verbatim from ExtUtils::Liblist::Kid::_vms_ext.
|
| 122 |
+
# We can't just call that because it's tied up with the MakeMaker object hierarchy.
|
| 123 |
+
|
| 124 |
+
sub _liblist_ext {
|
| 125 |
+
my($self, $potential_libs,$verbose,$give_libs) = @_;
|
| 126 |
+
$verbose ||= 0;
|
| 127 |
+
|
| 128 |
+
my(@crtls,$crtlstr);
|
| 129 |
+
@crtls = ( ($self->{'config'}{'ldflags'} =~ m-/Debug-i ? $self->{'config'}{'dbgprefix'} : '')
|
| 130 |
+
. 'PerlShr/Share' );
|
| 131 |
+
push(@crtls, grep { not /\(/ } split /\s+/, $self->{'config'}{'perllibs'});
|
| 132 |
+
push(@crtls, grep { not /\(/ } split /\s+/, $self->{'config'}{'libc'});
|
| 133 |
+
# In general, we pass through the basic libraries from %Config unchanged.
|
| 134 |
+
# The one exception is that if we're building in the Perl source tree, and
|
| 135 |
+
# a library spec could be resolved via a logical name, we go to some trouble
|
| 136 |
+
# to ensure that the copy in the local tree is used, rather than one to
|
| 137 |
+
# which a system-wide logical may point.
|
| 138 |
+
if ($self->perl_src) {
|
| 139 |
+
my($lib,$locspec,$type);
|
| 140 |
+
foreach $lib (@crtls) {
|
| 141 |
+
if (($locspec,$type) = $lib =~ m{^([\w\$-]+)(/\w+)?} and $locspec =~ /perl/i) {
|
| 142 |
+
if (lc $type eq '/share') { $locspec .= $self->{'config'}{'exe_ext'}; }
|
| 143 |
+
elsif (lc $type eq '/library') { $locspec .= $self->{'config'}{'lib_ext'}; }
|
| 144 |
+
else { $locspec .= $self->{'config'}{'obj_ext'}; }
|
| 145 |
+
$locspec = catfile($self->perl_src, $locspec);
|
| 146 |
+
$lib = "$locspec$type" if -e $locspec;
|
| 147 |
+
}
|
| 148 |
+
}
|
| 149 |
+
}
|
| 150 |
+
$crtlstr = @crtls ? join(' ',@crtls) : '';
|
| 151 |
+
|
| 152 |
+
unless ($potential_libs) {
|
| 153 |
+
warn "Result:\n\tEXTRALIBS: \n\tLDLOADLIBS: $crtlstr\n" if $verbose;
|
| 154 |
+
return ('', '', $crtlstr, '', ($give_libs ? [] : ()));
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
my(@dirs,@libs,$dir,$lib,%found,@fndlibs,$ldlib);
|
| 158 |
+
my $cwd = cwd();
|
| 159 |
+
my($so,$lib_ext,$obj_ext) = @{$self->{'config'}}{'so','lib_ext','obj_ext'};
|
| 160 |
+
# List of common Unix library names and their VMS equivalents
|
| 161 |
+
# (VMS equivalent of '' indicates that the library is automatically
|
| 162 |
+
# searched by the linker, and should be skipped here.)
|
| 163 |
+
my(@flibs, %libs_seen);
|
| 164 |
+
my %libmap = ( 'm' => '', 'f77' => '', 'F77' => '', 'V77' => '', 'c' => '',
|
| 165 |
+
'malloc' => '', 'crypt' => '', 'resolv' => '', 'c_s' => '',
|
| 166 |
+
'socket' => '', 'X11' => 'DECW$XLIBSHR',
|
| 167 |
+
'Xt' => 'DECW$XTSHR', 'Xm' => 'DECW$XMLIBSHR',
|
| 168 |
+
'Xmu' => 'DECW$XMULIBSHR');
|
| 169 |
+
|
| 170 |
+
warn "Potential libraries are '$potential_libs'\n" if $verbose;
|
| 171 |
+
|
| 172 |
+
# First, sort out directories and library names in the input
|
| 173 |
+
foreach $lib (split ' ',$potential_libs) {
|
| 174 |
+
push(@dirs,$1), next if $lib =~ /^-L(.*)/;
|
| 175 |
+
push(@dirs,$lib), next if $lib =~ /[:>\]]$/;
|
| 176 |
+
push(@dirs,$lib), next if -d $lib;
|
| 177 |
+
push(@libs,$1), next if $lib =~ /^-l(.*)/;
|
| 178 |
+
push(@libs,$lib);
|
| 179 |
+
}
|
| 180 |
+
push(@dirs,split(' ',$self->{'config'}{'libpth'}));
|
| 181 |
+
|
| 182 |
+
# Now make sure we've got VMS-syntax absolute directory specs
|
| 183 |
+
# (We don't, however, check whether someone's hidden a relative
|
| 184 |
+
# path in a logical name.)
|
| 185 |
+
foreach $dir (@dirs) {
|
| 186 |
+
unless (-d $dir) {
|
| 187 |
+
warn "Skipping nonexistent Directory $dir\n" if $verbose > 1;
|
| 188 |
+
$dir = '';
|
| 189 |
+
next;
|
| 190 |
+
}
|
| 191 |
+
warn "Resolving directory $dir\n" if $verbose;
|
| 192 |
+
if (!File::Spec->file_name_is_absolute($dir)) {
|
| 193 |
+
$dir = catdir($cwd,$dir);
|
| 194 |
+
}
|
| 195 |
+
}
|
| 196 |
+
@dirs = grep { length($_) } @dirs;
|
| 197 |
+
unshift(@dirs,''); # Check each $lib without additions first
|
| 198 |
+
|
| 199 |
+
LIB: foreach $lib (@libs) {
|
| 200 |
+
if (exists $libmap{$lib}) {
|
| 201 |
+
next unless length $libmap{$lib};
|
| 202 |
+
$lib = $libmap{$lib};
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
my(@variants,$variant,$cand);
|
| 206 |
+
my($ctype) = '';
|
| 207 |
+
|
| 208 |
+
# If we don't have a file type, consider it a possibly abbreviated name and
|
| 209 |
+
# check for common variants. We try these first to grab libraries before
|
| 210 |
+
# a like-named executable image (e.g. -lperl resolves to perlshr.exe
|
| 211 |
+
# before perl.exe).
|
| 212 |
+
if ($lib !~ /\.[^:>\]]*$/) {
|
| 213 |
+
push(@variants,"${lib}shr","${lib}rtl","${lib}lib");
|
| 214 |
+
push(@variants,"lib$lib") if $lib !~ /[:>\]]/;
|
| 215 |
+
}
|
| 216 |
+
push(@variants,$lib);
|
| 217 |
+
warn "Looking for $lib\n" if $verbose;
|
| 218 |
+
foreach $variant (@variants) {
|
| 219 |
+
my($fullname, $name);
|
| 220 |
+
|
| 221 |
+
foreach $dir (@dirs) {
|
| 222 |
+
my($type);
|
| 223 |
+
|
| 224 |
+
$name = "$dir$variant";
|
| 225 |
+
warn "\tChecking $name\n" if $verbose > 2;
|
| 226 |
+
$fullname = VMS::Filespec::rmsexpand($name);
|
| 227 |
+
if (defined $fullname and -f $fullname) {
|
| 228 |
+
# It's got its own suffix, so we'll have to figure out the type
|
| 229 |
+
if ($fullname =~ /(?:$so|exe)$/i) { $type = 'SHR'; }
|
| 230 |
+
elsif ($fullname =~ /(?:$lib_ext|olb)$/i) { $type = 'OLB'; }
|
| 231 |
+
elsif ($fullname =~ /(?:$obj_ext|obj)$/i) {
|
| 232 |
+
warn "Note (probably harmless): "
|
| 233 |
+
."Plain object file $fullname found in library list\n";
|
| 234 |
+
$type = 'OBJ';
|
| 235 |
+
}
|
| 236 |
+
else {
|
| 237 |
+
warn "Note (probably harmless): "
|
| 238 |
+
."Unknown library type for $fullname; assuming shared\n";
|
| 239 |
+
$type = 'SHR';
|
| 240 |
+
}
|
| 241 |
+
}
|
| 242 |
+
elsif (-f ($fullname = VMS::Filespec::rmsexpand($name,$so)) or
|
| 243 |
+
-f ($fullname = VMS::Filespec::rmsexpand($name,'.exe'))) {
|
| 244 |
+
$type = 'SHR';
|
| 245 |
+
$name = $fullname unless $fullname =~ /exe;?\d*$/i;
|
| 246 |
+
}
|
| 247 |
+
elsif (not length($ctype) and # If we've got a lib already,
|
| 248 |
+
# don't bother
|
| 249 |
+
( -f ($fullname = VMS::Filespec::rmsexpand($name,$lib_ext)) or
|
| 250 |
+
-f ($fullname = VMS::Filespec::rmsexpand($name,'.olb')))) {
|
| 251 |
+
$type = 'OLB';
|
| 252 |
+
$name = $fullname unless $fullname =~ /olb;?\d*$/i;
|
| 253 |
+
}
|
| 254 |
+
elsif (not length($ctype) and # If we've got a lib already,
|
| 255 |
+
# don't bother
|
| 256 |
+
( -f ($fullname = VMS::Filespec::rmsexpand($name,$obj_ext)) or
|
| 257 |
+
-f ($fullname = VMS::Filespec::rmsexpand($name,'.obj')))) {
|
| 258 |
+
warn "Note (probably harmless): "
|
| 259 |
+
."Plain object file $fullname found in library list\n";
|
| 260 |
+
$type = 'OBJ';
|
| 261 |
+
$name = $fullname unless $fullname =~ /obj;?\d*$/i;
|
| 262 |
+
}
|
| 263 |
+
if (defined $type) {
|
| 264 |
+
$ctype = $type; $cand = $name;
|
| 265 |
+
last if $ctype eq 'SHR';
|
| 266 |
+
}
|
| 267 |
+
}
|
| 268 |
+
if ($ctype) {
|
| 269 |
+
push @{$found{$ctype}}, $cand;
|
| 270 |
+
warn "\tFound as $cand (really $fullname), type $ctype\n"
|
| 271 |
+
if $verbose > 1;
|
| 272 |
+
push @flibs, $name unless $libs_seen{$fullname}++;
|
| 273 |
+
next LIB;
|
| 274 |
+
}
|
| 275 |
+
}
|
| 276 |
+
warn "Note (probably harmless): "
|
| 277 |
+
."No library found for $lib\n";
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
push @fndlibs, @{$found{OBJ}} if exists $found{OBJ};
|
| 281 |
+
push @fndlibs, map { "$_/Library" } @{$found{OLB}} if exists $found{OLB};
|
| 282 |
+
push @fndlibs, map { "$_/Share" } @{$found{SHR}} if exists $found{SHR};
|
| 283 |
+
$lib = join(' ',@fndlibs);
|
| 284 |
+
|
| 285 |
+
$ldlib = $crtlstr ? "$lib $crtlstr" : $lib;
|
| 286 |
+
warn "Result:\n\tEXTRALIBS: $lib\n\tLDLOADLIBS: $ldlib\n" if $verbose;
|
| 287 |
+
wantarray ? ($lib, '', $ldlib, '', ($give_libs ? \@flibs : ())) : $lib;
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
1;
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Platform/android.pm
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::CBuilder::Platform::android;
|
| 2 |
+
|
| 3 |
+
use warnings;
|
| 4 |
+
use strict;
|
| 5 |
+
use File::Spec;
|
| 6 |
+
use ExtUtils::CBuilder::Platform::Unix;
|
| 7 |
+
use Config;
|
| 8 |
+
|
| 9 |
+
our $VERSION = '0.280231'; # VERSION
|
| 10 |
+
our @ISA = qw(ExtUtils::CBuilder::Platform::Unix);
|
| 11 |
+
|
| 12 |
+
# The Android linker will not recognize symbols from
|
| 13 |
+
# libperl unless the module explicitly depends on it.
|
| 14 |
+
sub link {
|
| 15 |
+
my ($self, %args) = @_;
|
| 16 |
+
|
| 17 |
+
if ($self->{config}{useshrplib} eq 'true') {
|
| 18 |
+
$args{extra_linker_flags} = [
|
| 19 |
+
$self->split_like_shell($args{extra_linker_flags}),
|
| 20 |
+
'-L' . $self->perl_inc(),
|
| 21 |
+
'-lperl',
|
| 22 |
+
$self->split_like_shell($Config{perllibs}),
|
| 23 |
+
];
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
# Several modules on CPAN rather rightfully expect being
|
| 27 |
+
# able to pass $so_file to DynaLoader::dl_load_file and
|
| 28 |
+
# have it Just Work. However, $so_file will more likely
|
| 29 |
+
# than not be a relative path, and unless the module
|
| 30 |
+
# author subclasses MakeMaker/Module::Build to modify
|
| 31 |
+
# LD_LIBRARY_PATH, which would be insane, Android's linker
|
| 32 |
+
# won't find the .so
|
| 33 |
+
# So we make this all work by returning an absolute path.
|
| 34 |
+
my($so_file, @so_tmps) = $self->SUPER::link(%args);
|
| 35 |
+
$so_file = File::Spec->rel2abs($so_file);
|
| 36 |
+
return wantarray ? ($so_file, @so_tmps) : $so_file;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
1;
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Platform/cygwin.pm
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::CBuilder::Platform::cygwin;
|
| 2 |
+
|
| 3 |
+
use warnings;
|
| 4 |
+
use strict;
|
| 5 |
+
use File::Spec;
|
| 6 |
+
use ExtUtils::CBuilder::Platform::Unix;
|
| 7 |
+
|
| 8 |
+
our $VERSION = '0.280231'; # VERSION
|
| 9 |
+
our @ISA = qw(ExtUtils::CBuilder::Platform::Unix);
|
| 10 |
+
|
| 11 |
+
# TODO: If a specific exe_file name is requested, if the exe created
|
| 12 |
+
# doesn't have that name, we might want to rename it. Apparently asking
|
| 13 |
+
# for an exe of "foo" might result in "foo.exe". Alternatively, we should
|
| 14 |
+
# make sure the return value is correctly "foo.exe".
|
| 15 |
+
# C.f http://rt.cpan.org/Public/Bug/Display.html?id=41003
|
| 16 |
+
sub link_executable {
|
| 17 |
+
my $self = shift;
|
| 18 |
+
return $self->SUPER::link_executable(@_);
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
sub link {
|
| 22 |
+
my ($self, %args) = @_;
|
| 23 |
+
|
| 24 |
+
my $lib = $self->{config}{useshrplib} ? 'libperl.dll.a' : 'libperl.a';
|
| 25 |
+
$args{extra_linker_flags} = [
|
| 26 |
+
File::Spec->catfile($self->perl_inc(), $lib),
|
| 27 |
+
$self->split_like_shell($args{extra_linker_flags})
|
| 28 |
+
];
|
| 29 |
+
|
| 30 |
+
return $self->SUPER::link(%args);
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
1;
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/CBuilder/Platform/darwin.pm
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::CBuilder::Platform::darwin;
|
| 2 |
+
|
| 3 |
+
use warnings;
|
| 4 |
+
use strict;
|
| 5 |
+
use ExtUtils::CBuilder::Platform::Unix;
|
| 6 |
+
|
| 7 |
+
our $VERSION = '0.280231'; # VERSION
|
| 8 |
+
our @ISA = qw(ExtUtils::CBuilder::Platform::Unix);
|
| 9 |
+
|
| 10 |
+
sub compile {
|
| 11 |
+
my $self = shift;
|
| 12 |
+
my $cf = $self->{config};
|
| 13 |
+
|
| 14 |
+
# -flat_namespace isn't a compile flag, it's a linker flag. But
|
| 15 |
+
# it's mistakenly in Config.pm as both. Make the correction here.
|
| 16 |
+
local $cf->{ccflags} = $cf->{ccflags};
|
| 17 |
+
$cf->{ccflags} =~ s/-flat_namespace//;
|
| 18 |
+
$self->SUPER::compile(@_);
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
1;
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Command/MM.pm
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::Command::MM;
|
| 2 |
+
|
| 3 |
+
require 5.006;
|
| 4 |
+
|
| 5 |
+
use strict;
|
| 6 |
+
use warnings;
|
| 7 |
+
|
| 8 |
+
require Exporter;
|
| 9 |
+
our @ISA = qw(Exporter);
|
| 10 |
+
|
| 11 |
+
our @EXPORT = qw(test_harness pod2man perllocal_install uninstall
|
| 12 |
+
warn_if_old_packlist test_s cp_nonempty);
|
| 13 |
+
our $VERSION = '7.34';
|
| 14 |
+
$VERSION = eval $VERSION;
|
| 15 |
+
|
| 16 |
+
my $Is_VMS = $^O eq 'VMS';
|
| 17 |
+
|
| 18 |
+
sub mtime {
|
| 19 |
+
no warnings 'redefine';
|
| 20 |
+
local $@;
|
| 21 |
+
*mtime = (eval { require Time::HiRes } && defined &Time::HiRes::stat)
|
| 22 |
+
? sub { (Time::HiRes::stat($_[0]))[9] }
|
| 23 |
+
: sub { ( stat($_[0]))[9] }
|
| 24 |
+
;
|
| 25 |
+
goto &mtime;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
=head1 NAME
|
| 29 |
+
|
| 30 |
+
ExtUtils::Command::MM - Commands for the MM's to use in Makefiles
|
| 31 |
+
|
| 32 |
+
=head1 SYNOPSIS
|
| 33 |
+
|
| 34 |
+
perl "-MExtUtils::Command::MM" -e "function" "--" arguments...
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
=head1 DESCRIPTION
|
| 38 |
+
|
| 39 |
+
B<FOR INTERNAL USE ONLY!> The interface is not stable.
|
| 40 |
+
|
| 41 |
+
ExtUtils::Command::MM encapsulates code which would otherwise have to
|
| 42 |
+
be done with large "one" liners.
|
| 43 |
+
|
| 44 |
+
Any $(FOO) used in the examples are make variables, not Perl.
|
| 45 |
+
|
| 46 |
+
=over 4
|
| 47 |
+
|
| 48 |
+
=item B<test_harness>
|
| 49 |
+
|
| 50 |
+
test_harness($verbose, @test_libs);
|
| 51 |
+
|
| 52 |
+
Runs the tests on @ARGV via Test::Harness passing through the $verbose
|
| 53 |
+
flag. Any @test_libs will be unshifted onto the test's @INC.
|
| 54 |
+
|
| 55 |
+
@test_libs are run in alphabetical order.
|
| 56 |
+
|
| 57 |
+
=cut
|
| 58 |
+
|
| 59 |
+
sub test_harness {
|
| 60 |
+
require Test::Harness;
|
| 61 |
+
require File::Spec;
|
| 62 |
+
|
| 63 |
+
$Test::Harness::verbose = shift;
|
| 64 |
+
|
| 65 |
+
# Because Windows doesn't do this for us and listing all the *.t files
|
| 66 |
+
# out on the command line can blow over its exec limit.
|
| 67 |
+
require ExtUtils::Command;
|
| 68 |
+
my @argv = ExtUtils::Command::expand_wildcards(@ARGV);
|
| 69 |
+
|
| 70 |
+
local @INC = @INC;
|
| 71 |
+
unshift @INC, map { File::Spec->rel2abs($_) } @_;
|
| 72 |
+
Test::Harness::runtests(sort { lc $a cmp lc $b } @argv);
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
=item B<pod2man>
|
| 78 |
+
|
| 79 |
+
pod2man( '--option=value',
|
| 80 |
+
$podfile1 => $manpage1,
|
| 81 |
+
$podfile2 => $manpage2,
|
| 82 |
+
...
|
| 83 |
+
);
|
| 84 |
+
|
| 85 |
+
# or args on @ARGV
|
| 86 |
+
|
| 87 |
+
pod2man() is a function performing most of the duties of the pod2man
|
| 88 |
+
program. Its arguments are exactly the same as pod2man as of 5.8.0
|
| 89 |
+
with the addition of:
|
| 90 |
+
|
| 91 |
+
--perm_rw octal permission to set the resulting manpage to
|
| 92 |
+
|
| 93 |
+
And the removal of:
|
| 94 |
+
|
| 95 |
+
--verbose/-v
|
| 96 |
+
--help/-h
|
| 97 |
+
|
| 98 |
+
If no arguments are given to pod2man it will read from @ARGV.
|
| 99 |
+
|
| 100 |
+
If Pod::Man is unavailable, this function will warn and return undef.
|
| 101 |
+
|
| 102 |
+
=cut
|
| 103 |
+
|
| 104 |
+
sub pod2man {
|
| 105 |
+
local @ARGV = @_ ? @_ : @ARGV;
|
| 106 |
+
|
| 107 |
+
{
|
| 108 |
+
local $@;
|
| 109 |
+
if( !eval { require Pod::Man } ) {
|
| 110 |
+
warn "Pod::Man is not available: $@".
|
| 111 |
+
"Man pages will not be generated during this install.\n";
|
| 112 |
+
return 0;
|
| 113 |
+
}
|
| 114 |
+
}
|
| 115 |
+
require Getopt::Long;
|
| 116 |
+
|
| 117 |
+
# We will cheat and just use Getopt::Long. We fool it by putting
|
| 118 |
+
# our arguments into @ARGV. Should be safe.
|
| 119 |
+
my %options = ();
|
| 120 |
+
Getopt::Long::config ('bundling_override');
|
| 121 |
+
Getopt::Long::GetOptions (\%options,
|
| 122 |
+
'section|s=s', 'release|r=s', 'center|c=s',
|
| 123 |
+
'date|d=s', 'fixed=s', 'fixedbold=s', 'fixeditalic=s',
|
| 124 |
+
'fixedbolditalic=s', 'official|o', 'quotes|q=s', 'lax|l',
|
| 125 |
+
'name|n=s', 'perm_rw=i', 'utf8|u'
|
| 126 |
+
);
|
| 127 |
+
delete $options{utf8} unless $Pod::Man::VERSION >= 2.17;
|
| 128 |
+
|
| 129 |
+
# If there's no files, don't bother going further.
|
| 130 |
+
return 0 unless @ARGV;
|
| 131 |
+
|
| 132 |
+
# Official sets --center, but don't override things explicitly set.
|
| 133 |
+
if ($options{official} && !defined $options{center}) {
|
| 134 |
+
$options{center} = q[Perl Programmer's Reference Guide];
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
# This isn't a valid Pod::Man option and is only accepted for backwards
|
| 138 |
+
# compatibility.
|
| 139 |
+
delete $options{lax};
|
| 140 |
+
my $count = scalar @ARGV / 2;
|
| 141 |
+
my $plural = $count == 1 ? 'document' : 'documents';
|
| 142 |
+
print "Manifying $count pod $plural\n";
|
| 143 |
+
|
| 144 |
+
do {{ # so 'next' works
|
| 145 |
+
my ($pod, $man) = splice(@ARGV, 0, 2);
|
| 146 |
+
|
| 147 |
+
next if ((-e $man) &&
|
| 148 |
+
(mtime($man) > mtime($pod)) &&
|
| 149 |
+
(mtime($man) > mtime("Makefile")));
|
| 150 |
+
|
| 151 |
+
my $parser = Pod::Man->new(%options);
|
| 152 |
+
$parser->parse_from_file($pod, $man)
|
| 153 |
+
or do { warn("Could not install $man\n"); next };
|
| 154 |
+
|
| 155 |
+
if (exists $options{perm_rw}) {
|
| 156 |
+
chmod(oct($options{perm_rw}), $man)
|
| 157 |
+
or do { warn("chmod $options{perm_rw} $man: $!\n"); next };
|
| 158 |
+
}
|
| 159 |
+
}} while @ARGV;
|
| 160 |
+
|
| 161 |
+
return 1;
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
=item B<warn_if_old_packlist>
|
| 166 |
+
|
| 167 |
+
perl "-MExtUtils::Command::MM" -e warn_if_old_packlist <somefile>
|
| 168 |
+
|
| 169 |
+
Displays a warning that an old packlist file was found. Reads the
|
| 170 |
+
filename from @ARGV.
|
| 171 |
+
|
| 172 |
+
=cut
|
| 173 |
+
|
| 174 |
+
sub warn_if_old_packlist {
|
| 175 |
+
my $packlist = $ARGV[0];
|
| 176 |
+
|
| 177 |
+
return unless -f $packlist;
|
| 178 |
+
print <<"PACKLIST_WARNING";
|
| 179 |
+
WARNING: I have found an old package in
|
| 180 |
+
$packlist.
|
| 181 |
+
Please make sure the two installations are not conflicting
|
| 182 |
+
PACKLIST_WARNING
|
| 183 |
+
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
=item B<perllocal_install>
|
| 188 |
+
|
| 189 |
+
perl "-MExtUtils::Command::MM" -e perllocal_install
|
| 190 |
+
<type> <module name> <key> <value> ...
|
| 191 |
+
|
| 192 |
+
# VMS only, key|value pairs come on STDIN
|
| 193 |
+
perl "-MExtUtils::Command::MM" -e perllocal_install
|
| 194 |
+
<type> <module name> < <key>|<value> ...
|
| 195 |
+
|
| 196 |
+
Prints a fragment of POD suitable for appending to perllocal.pod.
|
| 197 |
+
Arguments are read from @ARGV.
|
| 198 |
+
|
| 199 |
+
'type' is the type of what you're installing. Usually 'Module'.
|
| 200 |
+
|
| 201 |
+
'module name' is simply the name of your module. (Foo::Bar)
|
| 202 |
+
|
| 203 |
+
Key/value pairs are extra information about the module. Fields include:
|
| 204 |
+
|
| 205 |
+
installed into which directory your module was out into
|
| 206 |
+
LINKTYPE dynamic or static linking
|
| 207 |
+
VERSION module version number
|
| 208 |
+
EXE_FILES any executables installed in a space separated
|
| 209 |
+
list
|
| 210 |
+
|
| 211 |
+
=cut
|
| 212 |
+
|
| 213 |
+
sub perllocal_install {
|
| 214 |
+
my($type, $name) = splice(@ARGV, 0, 2);
|
| 215 |
+
|
| 216 |
+
# VMS feeds args as a piped file on STDIN since it usually can't
|
| 217 |
+
# fit all the args on a single command line.
|
| 218 |
+
my @mod_info = $Is_VMS ? split /\|/, <STDIN>
|
| 219 |
+
: @ARGV;
|
| 220 |
+
|
| 221 |
+
my $pod;
|
| 222 |
+
my $time = gmtime($ENV{SOURCE_DATE_EPOCH} || time);
|
| 223 |
+
$pod = sprintf <<'POD', scalar($time), $type, $name, $name;
|
| 224 |
+
=head2 %s: C<%s> L<%s|%s>
|
| 225 |
+
|
| 226 |
+
=over 4
|
| 227 |
+
|
| 228 |
+
POD
|
| 229 |
+
|
| 230 |
+
do {
|
| 231 |
+
my($key, $val) = splice(@mod_info, 0, 2);
|
| 232 |
+
|
| 233 |
+
$pod .= <<POD
|
| 234 |
+
=item *
|
| 235 |
+
|
| 236 |
+
C<$key: $val>
|
| 237 |
+
|
| 238 |
+
POD
|
| 239 |
+
|
| 240 |
+
} while(@mod_info);
|
| 241 |
+
|
| 242 |
+
$pod .= "=back\n\n";
|
| 243 |
+
$pod =~ s/^ //mg;
|
| 244 |
+
print $pod;
|
| 245 |
+
|
| 246 |
+
return 1;
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
=item B<uninstall>
|
| 250 |
+
|
| 251 |
+
perl "-MExtUtils::Command::MM" -e uninstall <packlist>
|
| 252 |
+
|
| 253 |
+
A wrapper around ExtUtils::Install::uninstall(). Warns that
|
| 254 |
+
uninstallation is deprecated and doesn't actually perform the
|
| 255 |
+
uninstallation.
|
| 256 |
+
|
| 257 |
+
=cut
|
| 258 |
+
|
| 259 |
+
sub uninstall {
|
| 260 |
+
my($packlist) = shift @ARGV;
|
| 261 |
+
|
| 262 |
+
require ExtUtils::Install;
|
| 263 |
+
|
| 264 |
+
print <<'WARNING';
|
| 265 |
+
|
| 266 |
+
Uninstall is unsafe and deprecated, the uninstallation was not performed.
|
| 267 |
+
We will show what would have been done.
|
| 268 |
+
|
| 269 |
+
WARNING
|
| 270 |
+
|
| 271 |
+
ExtUtils::Install::uninstall($packlist, 1, 1);
|
| 272 |
+
|
| 273 |
+
print <<'WARNING';
|
| 274 |
+
|
| 275 |
+
Uninstall is unsafe and deprecated, the uninstallation was not performed.
|
| 276 |
+
Please check the list above carefully, there may be errors.
|
| 277 |
+
Remove the appropriate files manually.
|
| 278 |
+
Sorry for the inconvenience.
|
| 279 |
+
|
| 280 |
+
WARNING
|
| 281 |
+
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
=item B<test_s>
|
| 285 |
+
|
| 286 |
+
perl "-MExtUtils::Command::MM" -e test_s <file>
|
| 287 |
+
|
| 288 |
+
Tests if a file exists and is not empty (size > 0).
|
| 289 |
+
I<Exits> with 0 if it does, 1 if it does not.
|
| 290 |
+
|
| 291 |
+
=cut
|
| 292 |
+
|
| 293 |
+
sub test_s {
|
| 294 |
+
exit(-s $ARGV[0] ? 0 : 1);
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
=item B<cp_nonempty>
|
| 298 |
+
|
| 299 |
+
perl "-MExtUtils::Command::MM" -e cp_nonempty <srcfile> <dstfile> <perm>
|
| 300 |
+
|
| 301 |
+
Tests if the source file exists and is not empty (size > 0). If it is not empty
|
| 302 |
+
it copies it to the given destination with the given permissions.
|
| 303 |
+
|
| 304 |
+
=back
|
| 305 |
+
|
| 306 |
+
=cut
|
| 307 |
+
|
| 308 |
+
sub cp_nonempty {
|
| 309 |
+
my @args = @ARGV;
|
| 310 |
+
return 0 unless -s $args[0];
|
| 311 |
+
require ExtUtils::Command;
|
| 312 |
+
{
|
| 313 |
+
local @ARGV = @args[0,1];
|
| 314 |
+
ExtUtils::Command::cp(@ARGV);
|
| 315 |
+
}
|
| 316 |
+
{
|
| 317 |
+
local @ARGV = @args[2,1];
|
| 318 |
+
ExtUtils::Command::chmod(@ARGV);
|
| 319 |
+
}
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
|
| 323 |
+
1;
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Constant/Base.pm
ADDED
|
@@ -0,0 +1,1019 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::Constant::Base;
|
| 2 |
+
|
| 3 |
+
use strict;
|
| 4 |
+
use vars qw($VERSION);
|
| 5 |
+
use Carp;
|
| 6 |
+
use Text::Wrap;
|
| 7 |
+
use ExtUtils::Constant::Utils qw(C_stringify perl_stringify);
|
| 8 |
+
$VERSION = '0.06';
|
| 9 |
+
|
| 10 |
+
use constant is_perl56 => ($] < 5.007 && $] > 5.005_50);
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
=head1 NAME
|
| 14 |
+
|
| 15 |
+
ExtUtils::Constant::Base - base class for ExtUtils::Constant objects
|
| 16 |
+
|
| 17 |
+
=head1 SYNOPSIS
|
| 18 |
+
|
| 19 |
+
require ExtUtils::Constant::Base;
|
| 20 |
+
@ISA = 'ExtUtils::Constant::Base';
|
| 21 |
+
|
| 22 |
+
=head1 DESCRIPTION
|
| 23 |
+
|
| 24 |
+
ExtUtils::Constant::Base provides a base implementation of methods to
|
| 25 |
+
generate C code to give fast constant value lookup by named string. Currently
|
| 26 |
+
it's mostly used ExtUtils::Constant::XS, which generates the lookup code
|
| 27 |
+
for the constant() subroutine found in many XS modules.
|
| 28 |
+
|
| 29 |
+
=head1 USAGE
|
| 30 |
+
|
| 31 |
+
ExtUtils::Constant::Base exports no subroutines. The following methods are
|
| 32 |
+
available
|
| 33 |
+
|
| 34 |
+
=over 4
|
| 35 |
+
|
| 36 |
+
=cut
|
| 37 |
+
|
| 38 |
+
sub valid_type {
|
| 39 |
+
# Default to assuming that you don't need different types of return data.
|
| 40 |
+
1;
|
| 41 |
+
}
|
| 42 |
+
sub default_type {
|
| 43 |
+
'';
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
=item header
|
| 47 |
+
|
| 48 |
+
A method returning a scalar containing definitions needed, typically for a
|
| 49 |
+
C header file.
|
| 50 |
+
|
| 51 |
+
=cut
|
| 52 |
+
|
| 53 |
+
sub header {
|
| 54 |
+
''
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
# This might actually be a return statement. Note that you are responsible
|
| 58 |
+
# for any space you might need before your value, as it lets to perform
|
| 59 |
+
# "tricks" such as "return KEY_" and have strings appended.
|
| 60 |
+
sub assignment_clause_for_type;
|
| 61 |
+
# In which case this might be an empty string
|
| 62 |
+
sub return_statement_for_type {undef};
|
| 63 |
+
sub return_statement_for_notdef;
|
| 64 |
+
sub return_statement_for_notfound;
|
| 65 |
+
|
| 66 |
+
# "#if 1" is true to a C pre-processor
|
| 67 |
+
sub macro_from_name {
|
| 68 |
+
1;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
sub macro_from_item {
|
| 72 |
+
1;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
sub macro_to_ifdef {
|
| 76 |
+
my ($self, $macro) = @_;
|
| 77 |
+
if (ref $macro) {
|
| 78 |
+
return $macro->[0];
|
| 79 |
+
}
|
| 80 |
+
if (defined $macro && $macro ne "" && $macro ne "1") {
|
| 81 |
+
return $macro ? "#ifdef $macro\n" : "#if 0\n";
|
| 82 |
+
}
|
| 83 |
+
return "";
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
sub macro_to_ifndef {
|
| 87 |
+
my ($self, $macro) = @_;
|
| 88 |
+
if (ref $macro) {
|
| 89 |
+
# Can't invert these stylishly, so "bodge it"
|
| 90 |
+
return "$macro->[0]#else\n";
|
| 91 |
+
}
|
| 92 |
+
if (defined $macro && $macro ne "" && $macro ne "1") {
|
| 93 |
+
return $macro ? "#ifndef $macro\n" : "#if 1\n";
|
| 94 |
+
}
|
| 95 |
+
croak "Can't generate an ifndef for unconditional code";
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
sub macro_to_endif {
|
| 99 |
+
my ($self, $macro) = @_;
|
| 100 |
+
|
| 101 |
+
if (ref $macro) {
|
| 102 |
+
return $macro->[1];
|
| 103 |
+
}
|
| 104 |
+
if (defined $macro && $macro ne "" && $macro ne "1") {
|
| 105 |
+
return "#endif\n";
|
| 106 |
+
}
|
| 107 |
+
return "";
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
sub name_param {
|
| 111 |
+
'name';
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
# This is possibly buggy, in that it's not mandatory (below, in the main
|
| 115 |
+
# C_constant parameters, but is expected to exist here, if it's needed)
|
| 116 |
+
# Buggy because if you're definitely pure 8 bit only, and will never be
|
| 117 |
+
# presented with your constants in utf8, the default form of C_constant can't
|
| 118 |
+
# be told not to do the utf8 version.
|
| 119 |
+
|
| 120 |
+
sub is_utf8_param {
|
| 121 |
+
'utf8';
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
sub memEQ {
|
| 125 |
+
"!memcmp";
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
=item memEQ_clause args_hashref
|
| 129 |
+
|
| 130 |
+
A method to return a suitable C C<if> statement to check whether I<name>
|
| 131 |
+
is equal to the C variable C<name>. If I<checked_at> is defined, then it
|
| 132 |
+
is used to avoid C<memEQ> for short names, or to generate a comment to
|
| 133 |
+
highlight the position of the character in the C<switch> statement.
|
| 134 |
+
|
| 135 |
+
If i<checked_at> is a reference to a scalar, then instead it gives
|
| 136 |
+
the characters pre-checked at the beginning, (and the number of chars by
|
| 137 |
+
which the C variable name has been advanced. These need to be chopped from
|
| 138 |
+
the front of I<name>).
|
| 139 |
+
|
| 140 |
+
=cut
|
| 141 |
+
|
| 142 |
+
sub memEQ_clause {
|
| 143 |
+
# if (memEQ(name, "thingy", 6)) {
|
| 144 |
+
# Which could actually be a character comparison or even ""
|
| 145 |
+
my ($self, $args) = @_;
|
| 146 |
+
my ($name, $checked_at, $indent) = @{$args}{qw(name checked_at indent)};
|
| 147 |
+
$indent = ' ' x ($indent || 4);
|
| 148 |
+
my $front_chop;
|
| 149 |
+
if (ref $checked_at) {
|
| 150 |
+
# regexp won't work on 5.6.1 without use utf8; in turn that won't work
|
| 151 |
+
# on 5.005_03.
|
| 152 |
+
substr ($name, 0, length $$checked_at,) = '';
|
| 153 |
+
$front_chop = C_stringify ($$checked_at);
|
| 154 |
+
undef $checked_at;
|
| 155 |
+
}
|
| 156 |
+
my $len = length $name;
|
| 157 |
+
|
| 158 |
+
if ($len < 2) {
|
| 159 |
+
return $indent . "{\n"
|
| 160 |
+
if (defined $checked_at and $checked_at == 0) or $len == 0;
|
| 161 |
+
# We didn't switch, drop through to the code for the 2 character string
|
| 162 |
+
$checked_at = 1;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
my $name_param = $self->name_param;
|
| 166 |
+
|
| 167 |
+
if ($len < 3 and defined $checked_at) {
|
| 168 |
+
my $check;
|
| 169 |
+
if ($checked_at == 1) {
|
| 170 |
+
$check = 0;
|
| 171 |
+
} elsif ($checked_at == 0) {
|
| 172 |
+
$check = 1;
|
| 173 |
+
}
|
| 174 |
+
if (defined $check) {
|
| 175 |
+
my $char = C_stringify (substr $name, $check, 1);
|
| 176 |
+
# Placate 5.005 with a break in the string. I can't see a good way of
|
| 177 |
+
# getting it to not take [ as introducing an array lookup, even with
|
| 178 |
+
# ${name_param}[$check]
|
| 179 |
+
return $indent . "if ($name_param" . "[$check] == '$char') {\n";
|
| 180 |
+
}
|
| 181 |
+
}
|
| 182 |
+
if (($len == 2 and !defined $checked_at)
|
| 183 |
+
or ($len == 3 and defined ($checked_at) and $checked_at == 2)) {
|
| 184 |
+
my $char1 = C_stringify (substr $name, 0, 1);
|
| 185 |
+
my $char2 = C_stringify (substr $name, 1, 1);
|
| 186 |
+
return $indent .
|
| 187 |
+
"if ($name_param" . "[0] == '$char1' && $name_param" . "[1] == '$char2') {\n";
|
| 188 |
+
}
|
| 189 |
+
if (($len == 3 and defined ($checked_at) and $checked_at == 1)) {
|
| 190 |
+
my $char1 = C_stringify (substr $name, 0, 1);
|
| 191 |
+
my $char2 = C_stringify (substr $name, 2, 1);
|
| 192 |
+
return $indent .
|
| 193 |
+
"if ($name_param" . "[0] == '$char1' && $name_param" . "[2] == '$char2') {\n";
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
my $pointer = '^';
|
| 197 |
+
my $have_checked_last = defined ($checked_at) && $len == $checked_at + 1;
|
| 198 |
+
if ($have_checked_last) {
|
| 199 |
+
# Checked at the last character, so no need to memEQ it.
|
| 200 |
+
$pointer = C_stringify (chop $name);
|
| 201 |
+
$len--;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
$name = C_stringify ($name);
|
| 205 |
+
my $memEQ = $self->memEQ();
|
| 206 |
+
my $body = $indent . "if ($memEQ($name_param, \"$name\", $len)) {\n";
|
| 207 |
+
# Put a little ^ under the letter we checked at
|
| 208 |
+
# Screws up for non printable and non-7 bit stuff, but that's too hard to
|
| 209 |
+
# get right.
|
| 210 |
+
if (defined $checked_at) {
|
| 211 |
+
$body .= $indent . "/* " . (' ' x length $memEQ)
|
| 212 |
+
. (' ' x length $name_param)
|
| 213 |
+
. (' ' x $checked_at) . $pointer
|
| 214 |
+
. (' ' x ($len - $checked_at + length $len)) . " */\n";
|
| 215 |
+
} elsif (defined $front_chop) {
|
| 216 |
+
$body .= $indent . "/* $front_chop"
|
| 217 |
+
. (' ' x ($len + 1 + length $len)) . " */\n";
|
| 218 |
+
}
|
| 219 |
+
return $body;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
=item dump_names arg_hashref, ITEM...
|
| 223 |
+
|
| 224 |
+
An internal function to generate the embedded perl code that will regenerate
|
| 225 |
+
the constant subroutines. I<default_type>, I<types> and I<ITEM>s are the
|
| 226 |
+
same as for C_constant. I<indent> is treated as number of spaces to indent
|
| 227 |
+
by. If C<declare_types> is true a C<$types> is always declared in the perl
|
| 228 |
+
code generated, if defined and false never declared, and if undefined C<$types>
|
| 229 |
+
is only declared if the values in I<types> as passed in cannot be inferred from
|
| 230 |
+
I<default_types> and the I<ITEM>s.
|
| 231 |
+
|
| 232 |
+
=cut
|
| 233 |
+
|
| 234 |
+
sub dump_names {
|
| 235 |
+
my ($self, $args, @items) = @_;
|
| 236 |
+
my ($default_type, $what, $indent, $declare_types)
|
| 237 |
+
= @{$args}{qw(default_type what indent declare_types)};
|
| 238 |
+
$indent = ' ' x ($indent || 0);
|
| 239 |
+
|
| 240 |
+
my $result;
|
| 241 |
+
my (@simple, @complex, %used_types);
|
| 242 |
+
foreach (@items) {
|
| 243 |
+
my $type;
|
| 244 |
+
if (ref $_) {
|
| 245 |
+
$type = $_->{type} || $default_type;
|
| 246 |
+
if ($_->{utf8}) {
|
| 247 |
+
# For simplicity always skip the bytes case, and reconstitute this entry
|
| 248 |
+
# from its utf8 twin.
|
| 249 |
+
next if $_->{utf8} eq 'no';
|
| 250 |
+
# Copy the hashref, as we don't want to mess with the caller's hashref.
|
| 251 |
+
$_ = {%$_};
|
| 252 |
+
unless (is_perl56) {
|
| 253 |
+
utf8::decode ($_->{name});
|
| 254 |
+
} else {
|
| 255 |
+
$_->{name} = pack 'U*', unpack 'U0U*', $_->{name};
|
| 256 |
+
}
|
| 257 |
+
delete $_->{utf8};
|
| 258 |
+
}
|
| 259 |
+
} else {
|
| 260 |
+
$_ = {name=>$_};
|
| 261 |
+
$type = $default_type;
|
| 262 |
+
}
|
| 263 |
+
$used_types{$type}++;
|
| 264 |
+
if ($type eq $default_type
|
| 265 |
+
# grr 5.6.1
|
| 266 |
+
and length $_->{name}
|
| 267 |
+
and length $_->{name} == ($_->{name} =~ tr/A-Za-z0-9_//)
|
| 268 |
+
and !defined ($_->{macro}) and !defined ($_->{value})
|
| 269 |
+
and !defined ($_->{default}) and !defined ($_->{pre})
|
| 270 |
+
and !defined ($_->{post}) and !defined ($_->{def_pre})
|
| 271 |
+
and !defined ($_->{def_post}) and !defined ($_->{weight})) {
|
| 272 |
+
# It's the default type, and the name consists only of A-Za-z0-9_
|
| 273 |
+
push @simple, $_->{name};
|
| 274 |
+
} else {
|
| 275 |
+
push @complex, $_;
|
| 276 |
+
}
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
if (!defined $declare_types) {
|
| 280 |
+
# Do they pass in any types we weren't already using?
|
| 281 |
+
foreach (keys %$what) {
|
| 282 |
+
next if $used_types{$_};
|
| 283 |
+
$declare_types++; # Found one in $what that wasn't used.
|
| 284 |
+
last; # And one is enough to terminate this loop
|
| 285 |
+
}
|
| 286 |
+
}
|
| 287 |
+
if ($declare_types) {
|
| 288 |
+
$result = $indent . 'my $types = {map {($_, 1)} qw('
|
| 289 |
+
. join (" ", sort keys %$what) . ")};\n";
|
| 290 |
+
}
|
| 291 |
+
local $Text::Wrap::huge = 'overflow';
|
| 292 |
+
local $Text::Wrap::columns = 80;
|
| 293 |
+
$result .= wrap ($indent . "my \@names = (qw(",
|
| 294 |
+
$indent . " ", join (" ", sort @simple) . ")");
|
| 295 |
+
if (@complex) {
|
| 296 |
+
foreach my $item (sort {$a->{name} cmp $b->{name}} @complex) {
|
| 297 |
+
my $name = perl_stringify $item->{name};
|
| 298 |
+
my $line = ",\n$indent {name=>\"$name\"";
|
| 299 |
+
$line .= ", type=>\"$item->{type}\"" if defined $item->{type};
|
| 300 |
+
foreach my $thing (qw (macro value default pre post def_pre def_post)) {
|
| 301 |
+
my $value = $item->{$thing};
|
| 302 |
+
if (defined $value) {
|
| 303 |
+
if (ref $value) {
|
| 304 |
+
$line .= ", $thing=>[\""
|
| 305 |
+
. join ('", "', map {perl_stringify $_} @$value) . '"]';
|
| 306 |
+
} else {
|
| 307 |
+
$line .= ", $thing=>\"" . perl_stringify($value) . "\"";
|
| 308 |
+
}
|
| 309 |
+
}
|
| 310 |
+
}
|
| 311 |
+
$line .= "}";
|
| 312 |
+
# Ensure that the enclosing C comment doesn't end
|
| 313 |
+
# by turning */ into *" . "/
|
| 314 |
+
$line =~ s!\*\/!\*" . "/!gs;
|
| 315 |
+
# gcc -Wall doesn't like finding /* inside a comment
|
| 316 |
+
$line =~ s!\/\*!/" . "\*!gs;
|
| 317 |
+
$result .= $line;
|
| 318 |
+
}
|
| 319 |
+
}
|
| 320 |
+
$result .= ");\n";
|
| 321 |
+
|
| 322 |
+
$result;
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
=item assign arg_hashref, VALUE...
|
| 326 |
+
|
| 327 |
+
A method to return a suitable assignment clause. If I<type> is aggregate
|
| 328 |
+
(eg I<PVN> expects both pointer and length) then there should be multiple
|
| 329 |
+
I<VALUE>s for the components. I<pre> and I<post> if defined give snippets
|
| 330 |
+
of C code to proceed and follow the assignment. I<pre> will be at the start
|
| 331 |
+
of a block, so variables may be defined in it.
|
| 332 |
+
|
| 333 |
+
=cut
|
| 334 |
+
# Hmm. value undef to do NOTDEF? value () to do NOTFOUND?
|
| 335 |
+
|
| 336 |
+
sub assign {
|
| 337 |
+
my $self = shift;
|
| 338 |
+
my $args = shift;
|
| 339 |
+
my ($indent, $type, $pre, $post, $item)
|
| 340 |
+
= @{$args}{qw(indent type pre post item)};
|
| 341 |
+
$post ||= '';
|
| 342 |
+
my $clause;
|
| 343 |
+
my $close;
|
| 344 |
+
if ($pre) {
|
| 345 |
+
chomp $pre;
|
| 346 |
+
$close = "$indent}\n";
|
| 347 |
+
$clause = $indent . "{\n";
|
| 348 |
+
$indent .= " ";
|
| 349 |
+
$clause .= "$indent$pre";
|
| 350 |
+
$clause .= ";" unless $pre =~ /;$/;
|
| 351 |
+
$clause .= "\n";
|
| 352 |
+
}
|
| 353 |
+
confess "undef \$type" unless defined $type;
|
| 354 |
+
confess "Can't generate code for type $type"
|
| 355 |
+
unless $self->valid_type($type);
|
| 356 |
+
|
| 357 |
+
$clause .= join '', map {"$indent$_\n"}
|
| 358 |
+
$self->assignment_clause_for_type({type=>$type,item=>$item}, @_);
|
| 359 |
+
chomp $post;
|
| 360 |
+
if (length $post) {
|
| 361 |
+
$clause .= "$post";
|
| 362 |
+
$clause .= ";" unless $post =~ /;$/;
|
| 363 |
+
$clause .= "\n";
|
| 364 |
+
}
|
| 365 |
+
my $return = $self->return_statement_for_type($type);
|
| 366 |
+
$clause .= "$indent$return\n" if defined $return;
|
| 367 |
+
$clause .= $close if $close;
|
| 368 |
+
return $clause;
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
=item return_clause arg_hashref, ITEM
|
| 372 |
+
|
| 373 |
+
A method to return a suitable C<#ifdef> clause. I<ITEM> is a hashref
|
| 374 |
+
(as passed to C<C_constant> and C<match_clause>. I<indent> is the number
|
| 375 |
+
of spaces to indent, defaulting to 6.
|
| 376 |
+
|
| 377 |
+
=cut
|
| 378 |
+
|
| 379 |
+
sub return_clause {
|
| 380 |
+
|
| 381 |
+
##ifdef thingy
|
| 382 |
+
# *iv_return = thingy;
|
| 383 |
+
# return PERL_constant_ISIV;
|
| 384 |
+
##else
|
| 385 |
+
# return PERL_constant_NOTDEF;
|
| 386 |
+
##endif
|
| 387 |
+
my ($self, $args, $item) = @_;
|
| 388 |
+
my $indent = $args->{indent};
|
| 389 |
+
|
| 390 |
+
my ($name, $value, $default, $pre, $post, $def_pre, $def_post, $type)
|
| 391 |
+
= @$item{qw (name value default pre post def_pre def_post type)};
|
| 392 |
+
$value = $name unless defined $value;
|
| 393 |
+
my $macro = $self->macro_from_item($item);
|
| 394 |
+
$indent = ' ' x ($indent || 6);
|
| 395 |
+
unless (defined $type) {
|
| 396 |
+
# use Data::Dumper; print STDERR Dumper ($item);
|
| 397 |
+
confess "undef \$type";
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
##ifdef thingy
|
| 401 |
+
my $clause = $self->macro_to_ifdef($macro);
|
| 402 |
+
|
| 403 |
+
# *iv_return = thingy;
|
| 404 |
+
# return PERL_constant_ISIV;
|
| 405 |
+
$clause
|
| 406 |
+
.= $self->assign ({indent=>$indent, type=>$type, pre=>$pre, post=>$post,
|
| 407 |
+
item=>$item}, ref $value ? @$value : $value);
|
| 408 |
+
|
| 409 |
+
if (defined $macro && $macro ne "" && $macro ne "1") {
|
| 410 |
+
##else
|
| 411 |
+
$clause .= "#else\n";
|
| 412 |
+
|
| 413 |
+
# return PERL_constant_NOTDEF;
|
| 414 |
+
if (!defined $default) {
|
| 415 |
+
my $notdef = $self->return_statement_for_notdef();
|
| 416 |
+
$clause .= "$indent$notdef\n" if defined $notdef;
|
| 417 |
+
} else {
|
| 418 |
+
my @default = ref $default ? @$default : $default;
|
| 419 |
+
$type = shift @default;
|
| 420 |
+
$clause .= $self->assign ({indent=>$indent, type=>$type, pre=>$pre,
|
| 421 |
+
post=>$post, item=>$item}, @default);
|
| 422 |
+
}
|
| 423 |
+
}
|
| 424 |
+
##endif
|
| 425 |
+
$clause .= $self->macro_to_endif($macro);
|
| 426 |
+
|
| 427 |
+
return $clause;
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
sub match_clause {
|
| 431 |
+
# $offset defined if we have checked an offset.
|
| 432 |
+
my ($self, $args, $item) = @_;
|
| 433 |
+
my ($offset, $indent) = @{$args}{qw(checked_at indent)};
|
| 434 |
+
$indent = ' ' x ($indent || 4);
|
| 435 |
+
my $body = '';
|
| 436 |
+
my ($no, $yes, $either, $name, $inner_indent);
|
| 437 |
+
if (ref $item eq 'ARRAY') {
|
| 438 |
+
($yes, $no) = @$item;
|
| 439 |
+
$either = $yes || $no;
|
| 440 |
+
confess "$item is $either expecting hashref in [0] || [1]"
|
| 441 |
+
unless ref $either eq 'HASH';
|
| 442 |
+
$name = $either->{name};
|
| 443 |
+
} else {
|
| 444 |
+
confess "$item->{name} has utf8 flag '$item->{utf8}', should be false"
|
| 445 |
+
if $item->{utf8};
|
| 446 |
+
$name = $item->{name};
|
| 447 |
+
$inner_indent = $indent;
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
$body .= $self->memEQ_clause ({name => $name, checked_at => $offset,
|
| 451 |
+
indent => length $indent});
|
| 452 |
+
# If we've been presented with an arrayref for $item, then the user string
|
| 453 |
+
# contains in the range 128-255, and we need to check whether it was utf8
|
| 454 |
+
# (or not).
|
| 455 |
+
# In the worst case we have two named constants, where one's name happens
|
| 456 |
+
# encoded in UTF8 happens to be the same byte sequence as the second's
|
| 457 |
+
# encoded in (say) ISO-8859-1.
|
| 458 |
+
# In this case, $yes and $no both have item hashrefs.
|
| 459 |
+
if ($yes) {
|
| 460 |
+
$body .= $indent . " if (" . $self->is_utf8_param . ") {\n";
|
| 461 |
+
} elsif ($no) {
|
| 462 |
+
$body .= $indent . " if (!" . $self->is_utf8_param . ") {\n";
|
| 463 |
+
}
|
| 464 |
+
if ($either) {
|
| 465 |
+
$body .= $self->return_clause ({indent=>4 + length $indent}, $either);
|
| 466 |
+
if ($yes and $no) {
|
| 467 |
+
$body .= $indent . " } else {\n";
|
| 468 |
+
$body .= $self->return_clause ({indent=>4 + length $indent}, $no);
|
| 469 |
+
}
|
| 470 |
+
$body .= $indent . " }\n";
|
| 471 |
+
} else {
|
| 472 |
+
$body .= $self->return_clause ({indent=>2 + length $indent}, $item);
|
| 473 |
+
}
|
| 474 |
+
$body .= $indent . "}\n";
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
|
| 478 |
+
=item switch_clause arg_hashref, NAMELEN, ITEMHASH, ITEM...
|
| 479 |
+
|
| 480 |
+
An internal method to generate a suitable C<switch> clause, called by
|
| 481 |
+
C<C_constant> I<ITEM>s are in the hash ref format as given in the description
|
| 482 |
+
of C<C_constant>, and must all have the names of the same length, given by
|
| 483 |
+
I<NAMELEN>. I<ITEMHASH> is a reference to a hash, keyed by name, values being
|
| 484 |
+
the hashrefs in the I<ITEM> list. (No parameters are modified, and there can
|
| 485 |
+
be keys in the I<ITEMHASH> that are not in the list of I<ITEM>s without
|
| 486 |
+
causing problems - the hash is passed in to save generating it afresh for
|
| 487 |
+
each call).
|
| 488 |
+
|
| 489 |
+
=cut
|
| 490 |
+
|
| 491 |
+
sub switch_clause {
|
| 492 |
+
my ($self, $args, $namelen, $items, @items) = @_;
|
| 493 |
+
my ($indent, $comment) = @{$args}{qw(indent comment)};
|
| 494 |
+
$indent = ' ' x ($indent || 2);
|
| 495 |
+
|
| 496 |
+
local $Text::Wrap::huge = 'overflow';
|
| 497 |
+
local $Text::Wrap::columns = 80;
|
| 498 |
+
|
| 499 |
+
my @names = sort map {$_->{name}} @items;
|
| 500 |
+
my $leader = $indent . '/* ';
|
| 501 |
+
my $follower = ' ' x length $leader;
|
| 502 |
+
my $body = $indent . "/* Names all of length $namelen. */\n";
|
| 503 |
+
if (defined $comment) {
|
| 504 |
+
$body = wrap ($leader, $follower, $comment) . "\n";
|
| 505 |
+
$leader = $follower;
|
| 506 |
+
}
|
| 507 |
+
my @safe_names = @names;
|
| 508 |
+
foreach (@safe_names) {
|
| 509 |
+
confess sprintf "Name '$_' is length %d, not $namelen", length
|
| 510 |
+
unless length == $namelen;
|
| 511 |
+
# Argh. 5.6.1
|
| 512 |
+
# next unless tr/A-Za-z0-9_//c;
|
| 513 |
+
next if tr/A-Za-z0-9_// == length;
|
| 514 |
+
$_ = '"' . perl_stringify ($_) . '"';
|
| 515 |
+
# Ensure that the enclosing C comment doesn't end
|
| 516 |
+
# by turning */ into *" . "/
|
| 517 |
+
s!\*\/!\*"."/!gs;
|
| 518 |
+
# gcc -Wall doesn't like finding /* inside a comment
|
| 519 |
+
s!\/\*!/"."\*!gs;
|
| 520 |
+
}
|
| 521 |
+
$body .= wrap ($leader, $follower, join (" ", @safe_names) . " */") . "\n";
|
| 522 |
+
# Figure out what to switch on.
|
| 523 |
+
# (RMS, Spread of jump table, Position, Hashref)
|
| 524 |
+
my @best = (1e38, ~0);
|
| 525 |
+
# Prefer the last character over the others. (As it lets us shorten the
|
| 526 |
+
# memEQ clause at no cost).
|
| 527 |
+
foreach my $i ($namelen - 1, 0 .. ($namelen - 2)) {
|
| 528 |
+
my ($min, $max) = (~0, 0);
|
| 529 |
+
my %spread;
|
| 530 |
+
if (is_perl56) {
|
| 531 |
+
# Need proper Unicode preserving hash keys for bytes in range 128-255
|
| 532 |
+
# here too, for some reason. grr 5.6.1 yet again.
|
| 533 |
+
tie %spread, 'ExtUtils::Constant::Aaargh56Hash';
|
| 534 |
+
}
|
| 535 |
+
foreach (@names) {
|
| 536 |
+
my $char = substr $_, $i, 1;
|
| 537 |
+
my $ord = ord $char;
|
| 538 |
+
confess "char $ord is out of range" if $ord > 255;
|
| 539 |
+
$max = $ord if $ord > $max;
|
| 540 |
+
$min = $ord if $ord < $min;
|
| 541 |
+
push @{$spread{$char}}, $_;
|
| 542 |
+
# warn "$_ $char";
|
| 543 |
+
}
|
| 544 |
+
# I'm going to pick the character to split on that minimises the root
|
| 545 |
+
# mean square of the number of names in each case. Normally this should
|
| 546 |
+
# be the one with the most keys, but it may pick a 7 where the 8 has
|
| 547 |
+
# one long linear search. I'm not sure if RMS or just sum of squares is
|
| 548 |
+
# actually better.
|
| 549 |
+
# $max and $min are for the tie-breaker if the root mean squares match.
|
| 550 |
+
# Assuming that the compiler may be building a jump table for the
|
| 551 |
+
# switch() then try to minimise the size of that jump table.
|
| 552 |
+
# Finally use < not <= so that if it still ties the earliest part of
|
| 553 |
+
# the string wins. Because if that passes but the memEQ fails, it may
|
| 554 |
+
# only need the start of the string to bin the choice.
|
| 555 |
+
# I think. But I'm micro-optimising. :-)
|
| 556 |
+
# OK. Trump that. Now favour the last character of the string, before the
|
| 557 |
+
# rest.
|
| 558 |
+
my $ss;
|
| 559 |
+
$ss += @$_ * @$_ foreach values %spread;
|
| 560 |
+
my $rms = sqrt ($ss / keys %spread);
|
| 561 |
+
if ($rms < $best[0] || ($rms == $best[0] && ($max - $min) < $best[1])) {
|
| 562 |
+
@best = ($rms, $max - $min, $i, \%spread);
|
| 563 |
+
}
|
| 564 |
+
}
|
| 565 |
+
confess "Internal error. Failed to pick a switch point for @names"
|
| 566 |
+
unless defined $best[2];
|
| 567 |
+
# use Data::Dumper; print Dumper (@best);
|
| 568 |
+
my ($offset, $best) = @best[2,3];
|
| 569 |
+
$body .= $indent . "/* Offset $offset gives the best switch position. */\n";
|
| 570 |
+
|
| 571 |
+
my $do_front_chop = $offset == 0 && $namelen > 2;
|
| 572 |
+
if ($do_front_chop) {
|
| 573 |
+
$body .= $indent . "switch (*" . $self->name_param() . "++) {\n";
|
| 574 |
+
} else {
|
| 575 |
+
$body .= $indent . "switch (" . $self->name_param() . "[$offset]) {\n";
|
| 576 |
+
}
|
| 577 |
+
foreach my $char (sort keys %$best) {
|
| 578 |
+
confess sprintf "'$char' is %d bytes long, not 1", length $char
|
| 579 |
+
if length ($char) != 1;
|
| 580 |
+
confess sprintf "char %#X is out of range", ord $char if ord ($char) > 255;
|
| 581 |
+
$body .= $indent . "case '" . C_stringify ($char) . "':\n";
|
| 582 |
+
foreach my $thisone (sort {
|
| 583 |
+
# Deal with the case of an item actually being an array ref to 1 or 2
|
| 584 |
+
# hashrefs. Don't assign to $a or $b, as they're aliases to the
|
| 585 |
+
# original
|
| 586 |
+
my $l = ref $a eq 'ARRAY' ? ($a->[0] || $->[1]) : $a;
|
| 587 |
+
my $r = ref $b eq 'ARRAY' ? ($b->[0] || $->[1]) : $b;
|
| 588 |
+
# Sort by weight first
|
| 589 |
+
($r->{weight} || 0) <=> ($l->{weight} || 0)
|
| 590 |
+
# Sort equal weights by name
|
| 591 |
+
or $l->{name} cmp $r->{name}}
|
| 592 |
+
# If this looks evil, maybe it is. $items is a
|
| 593 |
+
# hashref, and we're doing a hash slice on it
|
| 594 |
+
@{$items}{@{$best->{$char}}}) {
|
| 595 |
+
# warn "You are here";
|
| 596 |
+
if ($do_front_chop) {
|
| 597 |
+
$body .= $self->match_clause ({indent => 2 + length $indent,
|
| 598 |
+
checked_at => \$char}, $thisone);
|
| 599 |
+
} else {
|
| 600 |
+
$body .= $self->match_clause ({indent => 2 + length $indent,
|
| 601 |
+
checked_at => $offset}, $thisone);
|
| 602 |
+
}
|
| 603 |
+
}
|
| 604 |
+
$body .= $indent . " break;\n";
|
| 605 |
+
}
|
| 606 |
+
$body .= $indent . "}\n";
|
| 607 |
+
return $body;
|
| 608 |
+
}
|
| 609 |
+
|
| 610 |
+
sub C_constant_return_type {
|
| 611 |
+
"static int";
|
| 612 |
+
}
|
| 613 |
+
|
| 614 |
+
sub C_constant_prefix_param {
|
| 615 |
+
'';
|
| 616 |
+
}
|
| 617 |
+
|
| 618 |
+
sub C_constant_prefix_param_defintion {
|
| 619 |
+
'';
|
| 620 |
+
}
|
| 621 |
+
|
| 622 |
+
sub name_param_definition {
|
| 623 |
+
"const char *" . $_[0]->name_param;
|
| 624 |
+
}
|
| 625 |
+
|
| 626 |
+
sub namelen_param {
|
| 627 |
+
'len';
|
| 628 |
+
}
|
| 629 |
+
|
| 630 |
+
sub namelen_param_definition {
|
| 631 |
+
'size_t ' . $_[0]->namelen_param;
|
| 632 |
+
}
|
| 633 |
+
|
| 634 |
+
sub C_constant_other_params {
|
| 635 |
+
'';
|
| 636 |
+
}
|
| 637 |
+
|
| 638 |
+
sub C_constant_other_params_defintion {
|
| 639 |
+
'';
|
| 640 |
+
}
|
| 641 |
+
|
| 642 |
+
=item params WHAT
|
| 643 |
+
|
| 644 |
+
An "internal" method, subject to change, currently called to allow an
|
| 645 |
+
overriding class to cache information that will then be passed into all
|
| 646 |
+
the C<*param*> calls. (Yes, having to read the source to make sense of this is
|
| 647 |
+
considered a known bug). I<WHAT> is be a hashref of types the constant
|
| 648 |
+
function will return. In ExtUtils::Constant::XS this method is used to
|
| 649 |
+
returns a hashref keyed IV NV PV SV to show which combination of pointers will
|
| 650 |
+
be needed in the C argument list generated by
|
| 651 |
+
C_constant_other_params_definition and C_constant_other_params
|
| 652 |
+
|
| 653 |
+
=cut
|
| 654 |
+
|
| 655 |
+
sub params {
|
| 656 |
+
'';
|
| 657 |
+
}
|
| 658 |
+
|
| 659 |
+
|
| 660 |
+
=item dogfood arg_hashref, ITEM...
|
| 661 |
+
|
| 662 |
+
An internal function to generate the embedded perl code that will regenerate
|
| 663 |
+
the constant subroutines. Parameters are the same as for C_constant.
|
| 664 |
+
|
| 665 |
+
Currently the base class does nothing and returns an empty string.
|
| 666 |
+
|
| 667 |
+
=cut
|
| 668 |
+
|
| 669 |
+
sub dogfood {
|
| 670 |
+
''
|
| 671 |
+
}
|
| 672 |
+
|
| 673 |
+
=item normalise_items args, default_type, seen_types, seen_items, ITEM...
|
| 674 |
+
|
| 675 |
+
Convert the items to a normalised form. For 8 bit and Unicode values converts
|
| 676 |
+
the item to an array of 1 or 2 items, both 8 bit and UTF-8 encoded.
|
| 677 |
+
|
| 678 |
+
=cut
|
| 679 |
+
|
| 680 |
+
sub normalise_items
|
| 681 |
+
{
|
| 682 |
+
my $self = shift;
|
| 683 |
+
my $args = shift;
|
| 684 |
+
my $default_type = shift;
|
| 685 |
+
my $what = shift;
|
| 686 |
+
my $items = shift;
|
| 687 |
+
my @new_items;
|
| 688 |
+
foreach my $orig (@_) {
|
| 689 |
+
my ($name, $item);
|
| 690 |
+
if (ref $orig) {
|
| 691 |
+
# Make a copy which is a normalised version of the ref passed in.
|
| 692 |
+
$name = $orig->{name};
|
| 693 |
+
my ($type, $macro, $value) = @$orig{qw (type macro value)};
|
| 694 |
+
$type ||= $default_type;
|
| 695 |
+
$what->{$type} = 1;
|
| 696 |
+
$item = {name=>$name, type=>$type};
|
| 697 |
+
|
| 698 |
+
undef $macro if defined $macro and $macro eq $name;
|
| 699 |
+
$item->{macro} = $macro if defined $macro;
|
| 700 |
+
undef $value if defined $value and $value eq $name;
|
| 701 |
+
$item->{value} = $value if defined $value;
|
| 702 |
+
foreach my $key (qw(default pre post def_pre def_post weight
|
| 703 |
+
not_constant)) {
|
| 704 |
+
my $value = $orig->{$key};
|
| 705 |
+
$item->{$key} = $value if defined $value;
|
| 706 |
+
# warn "$key $value";
|
| 707 |
+
}
|
| 708 |
+
} else {
|
| 709 |
+
$name = $orig;
|
| 710 |
+
$item = {name=>$name, type=>$default_type};
|
| 711 |
+
$what->{$default_type} = 1;
|
| 712 |
+
}
|
| 713 |
+
warn +(ref ($self) || $self)
|
| 714 |
+
. "doesn't know how to handle values of type $_ used in macro $name"
|
| 715 |
+
unless $self->valid_type ($item->{type});
|
| 716 |
+
# tr///c is broken on 5.6.1 for utf8, so my original tr/\0-\177//c
|
| 717 |
+
# doesn't work. Upgrade to 5.8
|
| 718 |
+
# if ($name !~ tr/\0-\177//c || $] < 5.005_50) {
|
| 719 |
+
if ($name =~ tr/\0-\177// == length $name || $] < 5.005_50
|
| 720 |
+
|| $args->{disable_utf8_duplication}) {
|
| 721 |
+
# No characters outside 7 bit ASCII.
|
| 722 |
+
if (exists $items->{$name}) {
|
| 723 |
+
die "Multiple definitions for macro $name";
|
| 724 |
+
}
|
| 725 |
+
$items->{$name} = $item;
|
| 726 |
+
} else {
|
| 727 |
+
# No characters outside 8 bit. This is hardest.
|
| 728 |
+
if (exists $items->{$name} and ref $items->{$name} ne 'ARRAY') {
|
| 729 |
+
confess "Unexpected ASCII definition for macro $name";
|
| 730 |
+
}
|
| 731 |
+
# Again, 5.6.1 tr broken, so s/5\.6.*/5\.8\.0/;
|
| 732 |
+
# if ($name !~ tr/\0-\377//c) {
|
| 733 |
+
if ($name =~ tr/\0-\377// == length $name) {
|
| 734 |
+
# if ($] < 5.007) {
|
| 735 |
+
# $name = pack "C*", unpack "U*", $name;
|
| 736 |
+
# }
|
| 737 |
+
$item->{utf8} = 'no';
|
| 738 |
+
$items->{$name}[1] = $item;
|
| 739 |
+
push @new_items, $item;
|
| 740 |
+
# Copy item, to create the utf8 variant.
|
| 741 |
+
$item = {%$item};
|
| 742 |
+
}
|
| 743 |
+
# Encode the name as utf8 bytes.
|
| 744 |
+
unless (is_perl56) {
|
| 745 |
+
utf8::encode($name);
|
| 746 |
+
} else {
|
| 747 |
+
# warn "Was >$name< " . length ${name};
|
| 748 |
+
$name = pack 'C*', unpack 'C*', $name . pack 'U*';
|
| 749 |
+
# warn "Now '${name}' " . length ${name};
|
| 750 |
+
}
|
| 751 |
+
if ($items->{$name}[0]) {
|
| 752 |
+
die "Multiple definitions for macro $name";
|
| 753 |
+
}
|
| 754 |
+
$item->{utf8} = 'yes';
|
| 755 |
+
$item->{name} = $name;
|
| 756 |
+
$items->{$name}[0] = $item;
|
| 757 |
+
# We have need for the utf8 flag.
|
| 758 |
+
$what->{''} = 1;
|
| 759 |
+
}
|
| 760 |
+
push @new_items, $item;
|
| 761 |
+
}
|
| 762 |
+
@new_items;
|
| 763 |
+
}
|
| 764 |
+
|
| 765 |
+
=item C_constant arg_hashref, ITEM...
|
| 766 |
+
|
| 767 |
+
A function that returns a B<list> of C subroutine definitions that return
|
| 768 |
+
the value and type of constants when passed the name by the XS wrapper.
|
| 769 |
+
I<ITEM...> gives a list of constant names. Each can either be a string,
|
| 770 |
+
which is taken as a C macro name, or a reference to a hash with the following
|
| 771 |
+
keys
|
| 772 |
+
|
| 773 |
+
=over 8
|
| 774 |
+
|
| 775 |
+
=item name
|
| 776 |
+
|
| 777 |
+
The name of the constant, as seen by the perl code.
|
| 778 |
+
|
| 779 |
+
=item type
|
| 780 |
+
|
| 781 |
+
The type of the constant (I<IV>, I<NV> etc)
|
| 782 |
+
|
| 783 |
+
=item value
|
| 784 |
+
|
| 785 |
+
A C expression for the value of the constant, or a list of C expressions if
|
| 786 |
+
the type is aggregate. This defaults to the I<name> if not given.
|
| 787 |
+
|
| 788 |
+
=item macro
|
| 789 |
+
|
| 790 |
+
The C pre-processor macro to use in the C<#ifdef>. This defaults to the
|
| 791 |
+
I<name>, and is mainly used if I<value> is an C<enum>. If a reference an
|
| 792 |
+
array is passed then the first element is used in place of the C<#ifdef>
|
| 793 |
+
line, and the second element in place of the C<#endif>. This allows
|
| 794 |
+
pre-processor constructions such as
|
| 795 |
+
|
| 796 |
+
#if defined (foo)
|
| 797 |
+
#if !defined (bar)
|
| 798 |
+
...
|
| 799 |
+
#endif
|
| 800 |
+
#endif
|
| 801 |
+
|
| 802 |
+
to be used to determine if a constant is to be defined.
|
| 803 |
+
|
| 804 |
+
A "macro" 1 signals that the constant is always defined, so the C<#if>/C<#endif>
|
| 805 |
+
test is omitted.
|
| 806 |
+
|
| 807 |
+
=item default
|
| 808 |
+
|
| 809 |
+
Default value to use (instead of C<croak>ing with "your vendor has not
|
| 810 |
+
defined...") to return if the macro isn't defined. Specify a reference to
|
| 811 |
+
an array with type followed by value(s).
|
| 812 |
+
|
| 813 |
+
=item pre
|
| 814 |
+
|
| 815 |
+
C code to use before the assignment of the value of the constant. This allows
|
| 816 |
+
you to use temporary variables to extract a value from part of a C<struct>
|
| 817 |
+
and return this as I<value>. This C code is places at the start of a block,
|
| 818 |
+
so you can declare variables in it.
|
| 819 |
+
|
| 820 |
+
=item post
|
| 821 |
+
|
| 822 |
+
C code to place between the assignment of value (to a temporary) and the
|
| 823 |
+
return from the function. This allows you to clear up anything in I<pre>.
|
| 824 |
+
Rarely needed.
|
| 825 |
+
|
| 826 |
+
=item def_pre
|
| 827 |
+
|
| 828 |
+
=item def_post
|
| 829 |
+
|
| 830 |
+
Equivalents of I<pre> and I<post> for the default value.
|
| 831 |
+
|
| 832 |
+
=item utf8
|
| 833 |
+
|
| 834 |
+
Generated internally. Is zero or undefined if name is 7 bit ASCII,
|
| 835 |
+
"no" if the name is 8 bit (and so should only match if SvUTF8() is false),
|
| 836 |
+
"yes" if the name is utf8 encoded.
|
| 837 |
+
|
| 838 |
+
The internals automatically clone any name with characters 128-255 but none
|
| 839 |
+
256+ (ie one that could be either in bytes or utf8) into a second entry
|
| 840 |
+
which is utf8 encoded.
|
| 841 |
+
|
| 842 |
+
=item weight
|
| 843 |
+
|
| 844 |
+
Optional sorting weight for names, to determine the order of
|
| 845 |
+
linear testing when multiple names fall in the same case of a switch clause.
|
| 846 |
+
Higher comes earlier, undefined defaults to zero.
|
| 847 |
+
|
| 848 |
+
=back
|
| 849 |
+
|
| 850 |
+
In the argument hashref, I<package> is the name of the package, and is only
|
| 851 |
+
used in comments inside the generated C code. I<subname> defaults to
|
| 852 |
+
C<constant> if undefined.
|
| 853 |
+
|
| 854 |
+
I<default_type> is the type returned by C<ITEM>s that don't specify their
|
| 855 |
+
type. It defaults to the value of C<default_type()>. I<types> should be given
|
| 856 |
+
either as a comma separated list of types that the C subroutine I<subname>
|
| 857 |
+
will generate or as a reference to a hash. I<default_type> will be added to
|
| 858 |
+
the list if not present, as will any types given in the list of I<ITEM>s. The
|
| 859 |
+
resultant list should be the same list of types that C<XS_constant> is
|
| 860 |
+
given. [Otherwise C<XS_constant> and C<C_constant> may differ in the number of
|
| 861 |
+
parameters to the constant function. I<indent> is currently unused and
|
| 862 |
+
ignored. In future it may be used to pass in information used to change the C
|
| 863 |
+
indentation style used.] The best way to maintain consistency is to pass in a
|
| 864 |
+
hash reference and let this function update it.
|
| 865 |
+
|
| 866 |
+
I<breakout> governs when child functions of I<subname> are generated. If there
|
| 867 |
+
are I<breakout> or more I<ITEM>s with the same length of name, then the code
|
| 868 |
+
to switch between them is placed into a function named I<subname>_I<len>, for
|
| 869 |
+
example C<constant_5> for names 5 characters long. The default I<breakout> is
|
| 870 |
+
3. A single C<ITEM> is always inlined.
|
| 871 |
+
|
| 872 |
+
=cut
|
| 873 |
+
|
| 874 |
+
# The parameter now BREAKOUT was previously documented as:
|
| 875 |
+
#
|
| 876 |
+
# I<NAMELEN> if defined signals that all the I<name>s of the I<ITEM>s are of
|
| 877 |
+
# this length, and that the constant name passed in by perl is checked and
|
| 878 |
+
# also of this length. It is used during recursion, and should be C<undef>
|
| 879 |
+
# unless the caller has checked all the lengths during code generation, and
|
| 880 |
+
# the generated subroutine is only to be called with a name of this length.
|
| 881 |
+
#
|
| 882 |
+
# As you can see it now performs this function during recursion by being a
|
| 883 |
+
# scalar reference.
|
| 884 |
+
|
| 885 |
+
sub C_constant {
|
| 886 |
+
my ($self, $args, @items) = @_;
|
| 887 |
+
my ($package, $subname, $default_type, $what, $indent, $breakout) =
|
| 888 |
+
@{$args}{qw(package subname default_type types indent breakout)};
|
| 889 |
+
$package ||= 'Foo';
|
| 890 |
+
$subname ||= 'constant';
|
| 891 |
+
# I'm not using this. But a hashref could be used for full formatting without
|
| 892 |
+
# breaking this API
|
| 893 |
+
# $indent ||= 0;
|
| 894 |
+
|
| 895 |
+
my ($namelen, $items);
|
| 896 |
+
if (ref $breakout) {
|
| 897 |
+
# We are called recursively. We trust @items to be normalised, $what to
|
| 898 |
+
# be a hashref, and pinch %$items from our parent to save recalculation.
|
| 899 |
+
($namelen, $items) = @$breakout;
|
| 900 |
+
} else {
|
| 901 |
+
$items = {};
|
| 902 |
+
if (is_perl56) {
|
| 903 |
+
# Need proper Unicode preserving hash keys.
|
| 904 |
+
require ExtUtils::Constant::Aaargh56Hash;
|
| 905 |
+
tie %$items, 'ExtUtils::Constant::Aaargh56Hash';
|
| 906 |
+
}
|
| 907 |
+
$breakout ||= 3;
|
| 908 |
+
$default_type ||= $self->default_type();
|
| 909 |
+
if (!ref $what) {
|
| 910 |
+
# Convert line of the form IV,UV,NV to hash
|
| 911 |
+
$what = {map {$_ => 1} split /,\s*/, ($what || '')};
|
| 912 |
+
# Figure out what types we're dealing with, and assign all unknowns to the
|
| 913 |
+
# default type
|
| 914 |
+
}
|
| 915 |
+
@items = $self->normalise_items ({}, $default_type, $what, $items, @items);
|
| 916 |
+
# use Data::Dumper; print Dumper @items;
|
| 917 |
+
}
|
| 918 |
+
my $params = $self->params ($what);
|
| 919 |
+
|
| 920 |
+
# Probably "static int"
|
| 921 |
+
my ($body, @subs);
|
| 922 |
+
$body = $self->C_constant_return_type($params) . "\n$subname ("
|
| 923 |
+
# Eg "pTHX_ "
|
| 924 |
+
. $self->C_constant_prefix_param_defintion($params)
|
| 925 |
+
# Probably "const char *name"
|
| 926 |
+
. $self->name_param_definition($params);
|
| 927 |
+
# Something like ", STRLEN len"
|
| 928 |
+
$body .= ", " . $self->namelen_param_definition($params)
|
| 929 |
+
unless defined $namelen;
|
| 930 |
+
$body .= $self->C_constant_other_params_defintion($params);
|
| 931 |
+
$body .= ") {\n";
|
| 932 |
+
|
| 933 |
+
if (defined $namelen) {
|
| 934 |
+
# We are a child subroutine. Print the simple description
|
| 935 |
+
my $comment = 'When generated this function returned values for the list'
|
| 936 |
+
. ' of names given here. However, subsequent manual editing may have'
|
| 937 |
+
. ' added or removed some.';
|
| 938 |
+
$body .= $self->switch_clause ({indent=>2, comment=>$comment},
|
| 939 |
+
$namelen, $items, @items);
|
| 940 |
+
} else {
|
| 941 |
+
# We are the top level.
|
| 942 |
+
$body .= " /* Initially switch on the length of the name. */\n";
|
| 943 |
+
$body .= $self->dogfood ({package => $package, subname => $subname,
|
| 944 |
+
default_type => $default_type, what => $what,
|
| 945 |
+
indent => $indent, breakout => $breakout},
|
| 946 |
+
@items);
|
| 947 |
+
$body .= ' switch ('.$self->namelen_param().") {\n";
|
| 948 |
+
# Need to group names of the same length
|
| 949 |
+
my @by_length;
|
| 950 |
+
foreach (@items) {
|
| 951 |
+
push @{$by_length[length $_->{name}]}, $_;
|
| 952 |
+
}
|
| 953 |
+
foreach my $i (0 .. $#by_length) {
|
| 954 |
+
next unless $by_length[$i]; # None of this length
|
| 955 |
+
$body .= " case $i:\n";
|
| 956 |
+
if (@{$by_length[$i]} == 1) {
|
| 957 |
+
my $only_thing = $by_length[$i]->[0];
|
| 958 |
+
if ($only_thing->{utf8}) {
|
| 959 |
+
if ($only_thing->{utf8} eq 'yes') {
|
| 960 |
+
# With utf8 on flag item is passed in element 0
|
| 961 |
+
$body .= $self->match_clause (undef, [$only_thing]);
|
| 962 |
+
} else {
|
| 963 |
+
# With utf8 off flag item is passed in element 1
|
| 964 |
+
$body .= $self->match_clause (undef, [undef, $only_thing]);
|
| 965 |
+
}
|
| 966 |
+
} else {
|
| 967 |
+
$body .= $self->match_clause (undef, $only_thing);
|
| 968 |
+
}
|
| 969 |
+
} elsif (@{$by_length[$i]} < $breakout) {
|
| 970 |
+
$body .= $self->switch_clause ({indent=>4},
|
| 971 |
+
$i, $items, @{$by_length[$i]});
|
| 972 |
+
} else {
|
| 973 |
+
# Only use the minimal set of parameters actually needed by the types
|
| 974 |
+
# of the names of this length.
|
| 975 |
+
my $what = {};
|
| 976 |
+
foreach (@{$by_length[$i]}) {
|
| 977 |
+
$what->{$_->{type}} = 1;
|
| 978 |
+
$what->{''} = 1 if $_->{utf8};
|
| 979 |
+
}
|
| 980 |
+
$params = $self->params ($what);
|
| 981 |
+
push @subs, $self->C_constant ({package=>$package,
|
| 982 |
+
subname=>"${subname}_$i",
|
| 983 |
+
default_type => $default_type,
|
| 984 |
+
types => $what, indent => $indent,
|
| 985 |
+
breakout => [$i, $items]},
|
| 986 |
+
@{$by_length[$i]});
|
| 987 |
+
$body .= " return ${subname}_$i ("
|
| 988 |
+
# Eg "aTHX_ "
|
| 989 |
+
. $self->C_constant_prefix_param($params)
|
| 990 |
+
# Probably "name"
|
| 991 |
+
. $self->name_param($params);
|
| 992 |
+
$body .= $self->C_constant_other_params($params);
|
| 993 |
+
$body .= ");\n";
|
| 994 |
+
}
|
| 995 |
+
$body .= " break;\n";
|
| 996 |
+
}
|
| 997 |
+
$body .= " }\n";
|
| 998 |
+
}
|
| 999 |
+
my $notfound = $self->return_statement_for_notfound();
|
| 1000 |
+
$body .= " $notfound\n" if $notfound;
|
| 1001 |
+
$body .= "}\n";
|
| 1002 |
+
return (@subs, $body);
|
| 1003 |
+
}
|
| 1004 |
+
|
| 1005 |
+
1;
|
| 1006 |
+
__END__
|
| 1007 |
+
|
| 1008 |
+
=back
|
| 1009 |
+
|
| 1010 |
+
=head1 BUGS
|
| 1011 |
+
|
| 1012 |
+
Not everything is documented yet.
|
| 1013 |
+
|
| 1014 |
+
Probably others.
|
| 1015 |
+
|
| 1016 |
+
=head1 AUTHOR
|
| 1017 |
+
|
| 1018 |
+
Nicholas Clark <[email protected]> based on the code in C<h2xs> by Larry Wall and
|
| 1019 |
+
others
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Constant/ProxySubs.pm
ADDED
|
@@ -0,0 +1,682 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::Constant::ProxySubs;
|
| 2 |
+
|
| 3 |
+
use strict;
|
| 4 |
+
use vars qw($VERSION @ISA %type_to_struct %type_from_struct %type_to_sv
|
| 5 |
+
%type_to_C_value %type_is_a_problem %type_num_args
|
| 6 |
+
%type_temporary);
|
| 7 |
+
use Carp;
|
| 8 |
+
require ExtUtils::Constant::XS;
|
| 9 |
+
use ExtUtils::Constant::Utils qw(C_stringify);
|
| 10 |
+
use ExtUtils::Constant::XS qw(%XS_TypeSet);
|
| 11 |
+
|
| 12 |
+
$VERSION = '0.09';
|
| 13 |
+
@ISA = 'ExtUtils::Constant::XS';
|
| 14 |
+
|
| 15 |
+
%type_to_struct =
|
| 16 |
+
(
|
| 17 |
+
IV => '{const char *name; I32 namelen; IV value;}',
|
| 18 |
+
NV => '{const char *name; I32 namelen; NV value;}',
|
| 19 |
+
UV => '{const char *name; I32 namelen; UV value;}',
|
| 20 |
+
PV => '{const char *name; I32 namelen; const char *value;}',
|
| 21 |
+
PVN => '{const char *name; I32 namelen; const char *value; STRLEN len;}',
|
| 22 |
+
YES => '{const char *name; I32 namelen;}',
|
| 23 |
+
NO => '{const char *name; I32 namelen;}',
|
| 24 |
+
UNDEF => '{const char *name; I32 namelen;}',
|
| 25 |
+
'' => '{const char *name; I32 namelen;} ',
|
| 26 |
+
);
|
| 27 |
+
|
| 28 |
+
%type_from_struct =
|
| 29 |
+
(
|
| 30 |
+
IV => sub { $_[0] . '->value' },
|
| 31 |
+
NV => sub { $_[0] . '->value' },
|
| 32 |
+
UV => sub { $_[0] . '->value' },
|
| 33 |
+
PV => sub { $_[0] . '->value' },
|
| 34 |
+
PVN => sub { $_[0] . '->value', $_[0] . '->len' },
|
| 35 |
+
YES => sub {},
|
| 36 |
+
NO => sub {},
|
| 37 |
+
UNDEF => sub {},
|
| 38 |
+
'' => sub {},
|
| 39 |
+
);
|
| 40 |
+
|
| 41 |
+
%type_to_sv =
|
| 42 |
+
(
|
| 43 |
+
IV => sub { "newSViv($_[0])" },
|
| 44 |
+
NV => sub { "newSVnv($_[0])" },
|
| 45 |
+
UV => sub { "newSVuv($_[0])" },
|
| 46 |
+
PV => sub { "newSVpv($_[0], 0)" },
|
| 47 |
+
PVN => sub { "newSVpvn($_[0], $_[1])" },
|
| 48 |
+
YES => sub { '&PL_sv_yes' },
|
| 49 |
+
NO => sub { '&PL_sv_no' },
|
| 50 |
+
UNDEF => sub { '&PL_sv_undef' },
|
| 51 |
+
'' => sub { '&PL_sv_yes' },
|
| 52 |
+
SV => sub {"SvREFCNT_inc($_[0])"},
|
| 53 |
+
);
|
| 54 |
+
|
| 55 |
+
%type_to_C_value =
|
| 56 |
+
(
|
| 57 |
+
YES => sub {},
|
| 58 |
+
NO => sub {},
|
| 59 |
+
UNDEF => sub {},
|
| 60 |
+
'' => sub {},
|
| 61 |
+
);
|
| 62 |
+
|
| 63 |
+
sub type_to_C_value {
|
| 64 |
+
my ($self, $type) = @_;
|
| 65 |
+
return $type_to_C_value{$type} || sub {return map {ref $_ ? @$_ : $_} @_};
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
# TODO - figure out if there is a clean way for the type_to_sv code to
|
| 69 |
+
# attempt s/sv_2mortal// and if it succeeds tell type_to_sv not to add
|
| 70 |
+
# SvREFCNT_inc
|
| 71 |
+
%type_is_a_problem =
|
| 72 |
+
(
|
| 73 |
+
# The documentation says *mortal SV*, but we now need a non-mortal copy.
|
| 74 |
+
SV => 1,
|
| 75 |
+
);
|
| 76 |
+
|
| 77 |
+
%type_temporary =
|
| 78 |
+
(
|
| 79 |
+
SV => ['SV *'],
|
| 80 |
+
PV => ['const char *'],
|
| 81 |
+
PVN => ['const char *', 'STRLEN'],
|
| 82 |
+
);
|
| 83 |
+
$type_temporary{$_} = [$_] foreach qw(IV UV NV);
|
| 84 |
+
|
| 85 |
+
while (my ($type, $value) = each %XS_TypeSet) {
|
| 86 |
+
$type_num_args{$type}
|
| 87 |
+
= defined $value ? ref $value ? scalar @$value : 1 : 0;
|
| 88 |
+
}
|
| 89 |
+
$type_num_args{''} = 0;
|
| 90 |
+
|
| 91 |
+
sub partition_names {
|
| 92 |
+
my ($self, $default_type, @items) = @_;
|
| 93 |
+
my (%found, @notfound, @trouble);
|
| 94 |
+
|
| 95 |
+
while (my $item = shift @items) {
|
| 96 |
+
my $default = delete $item->{default};
|
| 97 |
+
if ($default) {
|
| 98 |
+
# If we find a default value, convert it into a regular item and
|
| 99 |
+
# append it to the queue of items to process
|
| 100 |
+
my $default_item = {%$item};
|
| 101 |
+
$default_item->{invert_macro} = 1;
|
| 102 |
+
$default_item->{pre} = delete $item->{def_pre};
|
| 103 |
+
$default_item->{post} = delete $item->{def_post};
|
| 104 |
+
$default_item->{type} = shift @$default;
|
| 105 |
+
$default_item->{value} = $default;
|
| 106 |
+
push @items, $default_item;
|
| 107 |
+
} else {
|
| 108 |
+
# It can be "not found" unless it's the default (invert the macro)
|
| 109 |
+
# or the "macro" is an empty string (ie no macro)
|
| 110 |
+
push @notfound, $item unless $item->{invert_macro}
|
| 111 |
+
or !$self->macro_to_ifdef($self->macro_from_item($item));
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
if ($item->{pre} or $item->{post} or $item->{not_constant}
|
| 115 |
+
or $type_is_a_problem{$item->{type}}) {
|
| 116 |
+
push @trouble, $item;
|
| 117 |
+
} else {
|
| 118 |
+
push @{$found{$item->{type}}}, $item;
|
| 119 |
+
}
|
| 120 |
+
}
|
| 121 |
+
# use Data::Dumper; print Dumper \%found;
|
| 122 |
+
(\%found, \@notfound, \@trouble);
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
sub boottime_iterator {
|
| 126 |
+
my ($self, $type, $iterator, $hash, $subname, $push) = @_;
|
| 127 |
+
my $extractor = $type_from_struct{$type};
|
| 128 |
+
die "Can't find extractor code for type $type"
|
| 129 |
+
unless defined $extractor;
|
| 130 |
+
my $generator = $type_to_sv{$type};
|
| 131 |
+
die "Can't find generator code for type $type"
|
| 132 |
+
unless defined $generator;
|
| 133 |
+
|
| 134 |
+
my $athx = $self->C_constant_prefix_param();
|
| 135 |
+
|
| 136 |
+
if ($push) {
|
| 137 |
+
return sprintf <<"EOBOOT", &$generator(&$extractor($iterator));
|
| 138 |
+
while ($iterator->name) {
|
| 139 |
+
he = $subname($athx $hash, $iterator->name,
|
| 140 |
+
$iterator->namelen, %s);
|
| 141 |
+
av_push(push, newSVhek(HeKEY_hek(he)));
|
| 142 |
+
++$iterator;
|
| 143 |
+
}
|
| 144 |
+
EOBOOT
|
| 145 |
+
} else {
|
| 146 |
+
return sprintf <<"EOBOOT", &$generator(&$extractor($iterator));
|
| 147 |
+
while ($iterator->name) {
|
| 148 |
+
$subname($athx $hash, $iterator->name,
|
| 149 |
+
$iterator->namelen, %s);
|
| 150 |
+
++$iterator;
|
| 151 |
+
}
|
| 152 |
+
EOBOOT
|
| 153 |
+
}
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
sub name_len_value_macro {
|
| 157 |
+
my ($self, $item) = @_;
|
| 158 |
+
my $name = $item->{name};
|
| 159 |
+
my $value = $item->{value};
|
| 160 |
+
$value = $item->{name} unless defined $value;
|
| 161 |
+
|
| 162 |
+
my $namelen = length $name;
|
| 163 |
+
if ($name =~ tr/\0-\377// != $namelen) {
|
| 164 |
+
# the hash API signals UTF-8 by passing the length negated.
|
| 165 |
+
utf8::encode($name);
|
| 166 |
+
$namelen = -length $name;
|
| 167 |
+
}
|
| 168 |
+
$name = C_stringify($name);
|
| 169 |
+
|
| 170 |
+
my $macro = $self->macro_from_item($item);
|
| 171 |
+
($name, $namelen, $value, $macro);
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
sub WriteConstants {
|
| 175 |
+
my $self = shift;
|
| 176 |
+
my $ARGS = {@_};
|
| 177 |
+
|
| 178 |
+
my ($c_fh, $xs_fh, $c_subname, $default_type, $package)
|
| 179 |
+
= @{$ARGS}{qw(C_FH XS_FH C_SUBNAME DEFAULT_TYPE NAME)};
|
| 180 |
+
|
| 181 |
+
my $xs_subname
|
| 182 |
+
= exists $ARGS->{XS_SUBNAME} ? $ARGS->{XS_SUBNAME} : 'constant';
|
| 183 |
+
|
| 184 |
+
my $options = $ARGS->{PROXYSUBS};
|
| 185 |
+
$options = {} unless ref $options;
|
| 186 |
+
my $push = $options->{push};
|
| 187 |
+
my $explosives = $options->{croak_on_read};
|
| 188 |
+
my $croak_on_error = $options->{croak_on_error};
|
| 189 |
+
my $autoload = $options->{autoload};
|
| 190 |
+
{
|
| 191 |
+
my $exclusive = 0;
|
| 192 |
+
++$exclusive if $explosives;
|
| 193 |
+
++$exclusive if $croak_on_error;
|
| 194 |
+
++$exclusive if $autoload;
|
| 195 |
+
|
| 196 |
+
# Until someone patches this (with test cases):
|
| 197 |
+
carp ("PROXYSUBS options 'autoload', 'croak_on_read' and 'croak_on_error' cannot be used together")
|
| 198 |
+
if $exclusive > 1;
|
| 199 |
+
}
|
| 200 |
+
# Strictly it requires Perl_caller_cx
|
| 201 |
+
carp ("PROXYSUBS option 'croak_on_error' requires v5.13.5 or later")
|
| 202 |
+
if $croak_on_error && $^V < v5.13.5;
|
| 203 |
+
# Strictly this is actually 5.8.9, but it's not well tested there
|
| 204 |
+
my $can_do_pcs = $] >= 5.009;
|
| 205 |
+
# Until someone patches this (with test cases)
|
| 206 |
+
carp ("PROXYSUBS option 'push' requires v5.10 or later")
|
| 207 |
+
if $push && !$can_do_pcs;
|
| 208 |
+
# Until someone patches this (with test cases)
|
| 209 |
+
carp ("PROXYSUBS options 'push' and 'croak_on_read' cannot be used together")
|
| 210 |
+
if $explosives && $push;
|
| 211 |
+
|
| 212 |
+
# If anyone is insane enough to suggest a package name containing %
|
| 213 |
+
my $package_sprintf_safe = $package;
|
| 214 |
+
$package_sprintf_safe =~ s/%/%%/g;
|
| 215 |
+
|
| 216 |
+
# All the types we see
|
| 217 |
+
my $what = {};
|
| 218 |
+
# A hash to lookup items with.
|
| 219 |
+
my $items = {};
|
| 220 |
+
|
| 221 |
+
my @items = $self->normalise_items ({disable_utf8_duplication => 1},
|
| 222 |
+
$default_type, $what, $items,
|
| 223 |
+
@{$ARGS->{NAMES}});
|
| 224 |
+
|
| 225 |
+
# Partition the values by type. Also include any defaults in here
|
| 226 |
+
# Everything that doesn't have a default needs alternative code for
|
| 227 |
+
# "I'm missing"
|
| 228 |
+
# And everything that has pre or post code ends up in a private block
|
| 229 |
+
my ($found, $notfound, $trouble)
|
| 230 |
+
= $self->partition_names($default_type, @items);
|
| 231 |
+
|
| 232 |
+
my $pthx = $self->C_constant_prefix_param_defintion();
|
| 233 |
+
my $athx = $self->C_constant_prefix_param();
|
| 234 |
+
my $symbol_table = C_stringify($package) . '::';
|
| 235 |
+
$push = C_stringify($package . '::' . $push) if $push;
|
| 236 |
+
my $cast_CONSTSUB = $] < 5.010 ? '(char *)' : '';
|
| 237 |
+
|
| 238 |
+
print $c_fh $self->header();
|
| 239 |
+
if ($autoload || $croak_on_error) {
|
| 240 |
+
print $c_fh <<'EOC';
|
| 241 |
+
|
| 242 |
+
/* This allows slightly more efficient code on !USE_ITHREADS: */
|
| 243 |
+
#ifdef USE_ITHREADS
|
| 244 |
+
# define COP_FILE(c) CopFILE(c)
|
| 245 |
+
# define COP_FILE_F "s"
|
| 246 |
+
#else
|
| 247 |
+
# define COP_FILE(c) CopFILESV(c)
|
| 248 |
+
# define COP_FILE_F SVf
|
| 249 |
+
#endif
|
| 250 |
+
EOC
|
| 251 |
+
}
|
| 252 |
+
|
| 253 |
+
my $return_type = $push ? 'HE *' : 'void';
|
| 254 |
+
|
| 255 |
+
print $c_fh <<"EOADD";
|
| 256 |
+
|
| 257 |
+
static $return_type
|
| 258 |
+
${c_subname}_add_symbol($pthx HV *hash, const char *name, I32 namelen, SV *value) {
|
| 259 |
+
EOADD
|
| 260 |
+
if (!$can_do_pcs) {
|
| 261 |
+
print $c_fh <<'EO_NOPCS';
|
| 262 |
+
if (namelen == namelen) {
|
| 263 |
+
EO_NOPCS
|
| 264 |
+
} else {
|
| 265 |
+
print $c_fh <<"EO_PCS";
|
| 266 |
+
HE *he = (HE*) hv_common_key_len(hash, name, namelen, HV_FETCH_LVALUE, NULL,
|
| 267 |
+
0);
|
| 268 |
+
SV *sv;
|
| 269 |
+
|
| 270 |
+
if (!he) {
|
| 271 |
+
croak("Couldn't add key '%s' to %%$package_sprintf_safe\::",
|
| 272 |
+
name);
|
| 273 |
+
}
|
| 274 |
+
sv = HeVAL(he);
|
| 275 |
+
if (SvOK(sv) || SvTYPE(sv) == SVt_PVGV) {
|
| 276 |
+
/* Someone has been here before us - have to make a real sub. */
|
| 277 |
+
EO_PCS
|
| 278 |
+
}
|
| 279 |
+
# This piece of code is common to both
|
| 280 |
+
print $c_fh <<"EOADD";
|
| 281 |
+
newCONSTSUB(hash, ${cast_CONSTSUB}name, value);
|
| 282 |
+
EOADD
|
| 283 |
+
if ($can_do_pcs) {
|
| 284 |
+
print $c_fh <<'EO_PCS';
|
| 285 |
+
} else {
|
| 286 |
+
SvUPGRADE(sv, SVt_RV);
|
| 287 |
+
SvRV_set(sv, value);
|
| 288 |
+
SvROK_on(sv);
|
| 289 |
+
SvREADONLY_on(value);
|
| 290 |
+
}
|
| 291 |
+
EO_PCS
|
| 292 |
+
} else {
|
| 293 |
+
print $c_fh <<'EO_NOPCS';
|
| 294 |
+
}
|
| 295 |
+
EO_NOPCS
|
| 296 |
+
}
|
| 297 |
+
print $c_fh " return he;\n" if $push;
|
| 298 |
+
print $c_fh <<'EOADD';
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
EOADD
|
| 302 |
+
|
| 303 |
+
print $c_fh $explosives ? <<"EXPLODE" : "\n";
|
| 304 |
+
|
| 305 |
+
static int
|
| 306 |
+
Im_sorry_Dave(pTHX_ SV *sv, MAGIC *mg)
|
| 307 |
+
{
|
| 308 |
+
PERL_UNUSED_ARG(mg);
|
| 309 |
+
croak("Your vendor has not defined $package_sprintf_safe macro %"SVf
|
| 310 |
+
" used", sv);
|
| 311 |
+
NORETURN_FUNCTION_END;
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
static MGVTBL not_defined_vtbl = {
|
| 315 |
+
Im_sorry_Dave, /* get - I'm afraid I can't do that */
|
| 316 |
+
Im_sorry_Dave, /* set */
|
| 317 |
+
0, /* len */
|
| 318 |
+
0, /* clear */
|
| 319 |
+
0, /* free */
|
| 320 |
+
0, /* copy */
|
| 321 |
+
0, /* dup */
|
| 322 |
+
};
|
| 323 |
+
|
| 324 |
+
EXPLODE
|
| 325 |
+
|
| 326 |
+
{
|
| 327 |
+
my $key = $symbol_table;
|
| 328 |
+
# Just seems tidier (and slightly more space efficient) not to have keys
|
| 329 |
+
# such as Fcntl::
|
| 330 |
+
$key =~ s/::$//;
|
| 331 |
+
my $key_len = length $key;
|
| 332 |
+
|
| 333 |
+
print $c_fh <<"MISSING";
|
| 334 |
+
|
| 335 |
+
#ifndef SYMBIAN
|
| 336 |
+
|
| 337 |
+
/* Store a hash of all symbols missing from the package. To avoid trampling on
|
| 338 |
+
the package namespace (uninvited) put each package's hash in our namespace.
|
| 339 |
+
To avoid creating lots of typeblogs and symbol tables for sub-packages, put
|
| 340 |
+
each package's hash into one hash in our namespace. */
|
| 341 |
+
|
| 342 |
+
static HV *
|
| 343 |
+
get_missing_hash(pTHX) {
|
| 344 |
+
HV *const parent
|
| 345 |
+
= get_hv("ExtUtils::Constant::ProxySubs::Missing", GVf_MULTI);
|
| 346 |
+
/* We could make a hash of hashes directly, but this would confuse anything
|
| 347 |
+
at Perl space that looks at us, and as we're visible in Perl space,
|
| 348 |
+
best to play nice. */
|
| 349 |
+
SV *const *const ref
|
| 350 |
+
= hv_fetch(parent, "$key", $key_len, TRUE);
|
| 351 |
+
HV *new_hv;
|
| 352 |
+
|
| 353 |
+
if (!ref)
|
| 354 |
+
return NULL;
|
| 355 |
+
|
| 356 |
+
if (SvROK(*ref))
|
| 357 |
+
return (HV*) SvRV(*ref);
|
| 358 |
+
|
| 359 |
+
new_hv = newHV();
|
| 360 |
+
SvUPGRADE(*ref, SVt_RV);
|
| 361 |
+
SvRV_set(*ref, (SV *)new_hv);
|
| 362 |
+
SvROK_on(*ref);
|
| 363 |
+
return new_hv;
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
#endif
|
| 367 |
+
|
| 368 |
+
MISSING
|
| 369 |
+
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
print $xs_fh <<"EOBOOT";
|
| 373 |
+
BOOT:
|
| 374 |
+
{
|
| 375 |
+
#if defined(dTHX) && !defined(PERL_NO_GET_CONTEXT)
|
| 376 |
+
dTHX;
|
| 377 |
+
#endif
|
| 378 |
+
HV *symbol_table = get_hv("$symbol_table", GV_ADD);
|
| 379 |
+
EOBOOT
|
| 380 |
+
if ($push) {
|
| 381 |
+
print $xs_fh <<"EOC";
|
| 382 |
+
AV *push = get_av(\"$push\", GV_ADD);
|
| 383 |
+
HE *he;
|
| 384 |
+
EOC
|
| 385 |
+
}
|
| 386 |
+
|
| 387 |
+
my %iterator;
|
| 388 |
+
|
| 389 |
+
$found->{''}
|
| 390 |
+
= [map {{%$_, type=>'', invert_macro => 1}} @$notfound];
|
| 391 |
+
|
| 392 |
+
foreach my $type (sort keys %$found) {
|
| 393 |
+
my $struct = $type_to_struct{$type};
|
| 394 |
+
my $type_to_value = $self->type_to_C_value($type);
|
| 395 |
+
my $number_of_args = $type_num_args{$type};
|
| 396 |
+
die "Can't find structure definition for type $type"
|
| 397 |
+
unless defined $struct;
|
| 398 |
+
|
| 399 |
+
my $lc_type = $type ? lc($type) : 'notfound';
|
| 400 |
+
my $struct_type = $lc_type . '_s';
|
| 401 |
+
my $array_name = 'values_for_' . $lc_type;
|
| 402 |
+
$iterator{$type} = 'value_for_' . $lc_type;
|
| 403 |
+
# Give the notfound struct file scope. The others are scoped within the
|
| 404 |
+
# BOOT block
|
| 405 |
+
my $struct_fh = $type ? $xs_fh : $c_fh;
|
| 406 |
+
|
| 407 |
+
print $c_fh "struct $struct_type $struct;\n";
|
| 408 |
+
|
| 409 |
+
print $struct_fh <<"EOBOOT";
|
| 410 |
+
|
| 411 |
+
static const struct $struct_type $array_name\[] =
|
| 412 |
+
{
|
| 413 |
+
EOBOOT
|
| 414 |
+
|
| 415 |
+
|
| 416 |
+
foreach my $item (@{$found->{$type}}) {
|
| 417 |
+
my ($name, $namelen, $value, $macro)
|
| 418 |
+
= $self->name_len_value_macro($item);
|
| 419 |
+
|
| 420 |
+
my $ifdef = $self->macro_to_ifdef($macro);
|
| 421 |
+
if (!$ifdef && $item->{invert_macro}) {
|
| 422 |
+
carp("Attempting to supply a default for '$name' which has no conditional macro");
|
| 423 |
+
next;
|
| 424 |
+
}
|
| 425 |
+
if ($item->{invert_macro}) {
|
| 426 |
+
print $struct_fh $self->macro_to_ifndef($macro);
|
| 427 |
+
print $struct_fh
|
| 428 |
+
" /* This is the default value: */\n" if $type;
|
| 429 |
+
} else {
|
| 430 |
+
print $struct_fh $ifdef;
|
| 431 |
+
}
|
| 432 |
+
print $struct_fh " { ", join (', ', "\"$name\"", $namelen,
|
| 433 |
+
&$type_to_value($value)),
|
| 434 |
+
" },\n",
|
| 435 |
+
$self->macro_to_endif($macro);
|
| 436 |
+
}
|
| 437 |
+
|
| 438 |
+
# Terminate the list with a NULL
|
| 439 |
+
print $struct_fh " { NULL, 0", (", 0" x $number_of_args), " } };\n";
|
| 440 |
+
|
| 441 |
+
print $xs_fh <<"EOBOOT" if $type;
|
| 442 |
+
const struct $struct_type *$iterator{$type} = $array_name;
|
| 443 |
+
EOBOOT
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
delete $found->{''};
|
| 447 |
+
|
| 448 |
+
my $add_symbol_subname = $c_subname . '_add_symbol';
|
| 449 |
+
foreach my $type (sort keys %$found) {
|
| 450 |
+
print $xs_fh $self->boottime_iterator($type, $iterator{$type},
|
| 451 |
+
'symbol_table',
|
| 452 |
+
$add_symbol_subname, $push);
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
print $xs_fh <<"EOBOOT";
|
| 456 |
+
if (C_ARRAY_LENGTH(values_for_notfound) > 1) {
|
| 457 |
+
#ifndef SYMBIAN
|
| 458 |
+
HV *const ${c_subname}_missing = get_missing_hash(aTHX);
|
| 459 |
+
#endif
|
| 460 |
+
const struct notfound_s *value_for_notfound = values_for_notfound;
|
| 461 |
+
do {
|
| 462 |
+
EOBOOT
|
| 463 |
+
|
| 464 |
+
print $xs_fh $explosives ? <<"EXPLODE" : << "DONT";
|
| 465 |
+
SV *tripwire = newSV(0);
|
| 466 |
+
|
| 467 |
+
sv_magicext(tripwire, 0, PERL_MAGIC_ext, ¬_defined_vtbl, 0, 0);
|
| 468 |
+
SvPV_set(tripwire, (char *)value_for_notfound->name);
|
| 469 |
+
if(value_for_notfound->namelen >= 0) {
|
| 470 |
+
SvCUR_set(tripwire, value_for_notfound->namelen);
|
| 471 |
+
} else {
|
| 472 |
+
SvCUR_set(tripwire, -value_for_notfound->namelen);
|
| 473 |
+
SvUTF8_on(tripwire);
|
| 474 |
+
}
|
| 475 |
+
SvPOKp_on(tripwire);
|
| 476 |
+
SvREADONLY_on(tripwire);
|
| 477 |
+
assert(SvLEN(tripwire) == 0);
|
| 478 |
+
|
| 479 |
+
$add_symbol_subname($athx symbol_table, value_for_notfound->name,
|
| 480 |
+
value_for_notfound->namelen, tripwire);
|
| 481 |
+
EXPLODE
|
| 482 |
+
|
| 483 |
+
/* Need to add prototypes, else parsing will vary by platform. */
|
| 484 |
+
HE *he = (HE*) hv_common_key_len(symbol_table,
|
| 485 |
+
value_for_notfound->name,
|
| 486 |
+
value_for_notfound->namelen,
|
| 487 |
+
HV_FETCH_LVALUE, NULL, 0);
|
| 488 |
+
SV *sv;
|
| 489 |
+
#ifndef SYMBIAN
|
| 490 |
+
HEK *hek;
|
| 491 |
+
#endif
|
| 492 |
+
if (!he) {
|
| 493 |
+
croak("Couldn't add key '%s' to %%$package_sprintf_safe\::",
|
| 494 |
+
value_for_notfound->name);
|
| 495 |
+
}
|
| 496 |
+
sv = HeVAL(he);
|
| 497 |
+
if (!SvOK(sv) && SvTYPE(sv) != SVt_PVGV) {
|
| 498 |
+
/* Nothing was here before, so mark a prototype of "" */
|
| 499 |
+
sv_setpvn(sv, "", 0);
|
| 500 |
+
} else if (SvPOK(sv) && SvCUR(sv) == 0) {
|
| 501 |
+
/* There is already a prototype of "" - do nothing */
|
| 502 |
+
} else {
|
| 503 |
+
/* Someone has been here before us - have to make a real
|
| 504 |
+
typeglob. */
|
| 505 |
+
/* It turns out to be incredibly hard to deal with all the
|
| 506 |
+
corner cases of sub foo (); and reporting errors correctly,
|
| 507 |
+
so lets cheat a bit. Start with a constant subroutine */
|
| 508 |
+
CV *cv = newCONSTSUB(symbol_table,
|
| 509 |
+
${cast_CONSTSUB}value_for_notfound->name,
|
| 510 |
+
&PL_sv_yes);
|
| 511 |
+
/* and then turn it into a non constant declaration only. */
|
| 512 |
+
SvREFCNT_dec(CvXSUBANY(cv).any_ptr);
|
| 513 |
+
CvCONST_off(cv);
|
| 514 |
+
CvXSUB(cv) = NULL;
|
| 515 |
+
CvXSUBANY(cv).any_ptr = NULL;
|
| 516 |
+
}
|
| 517 |
+
#ifndef SYMBIAN
|
| 518 |
+
hek = HeKEY_hek(he);
|
| 519 |
+
if (!hv_common(${c_subname}_missing, NULL, HEK_KEY(hek),
|
| 520 |
+
HEK_LEN(hek), HEK_FLAGS(hek), HV_FETCH_ISSTORE,
|
| 521 |
+
&PL_sv_yes, HEK_HASH(hek)))
|
| 522 |
+
croak("Couldn't add key '%s' to missing_hash",
|
| 523 |
+
value_for_notfound->name);
|
| 524 |
+
#endif
|
| 525 |
+
DONT
|
| 526 |
+
|
| 527 |
+
print $xs_fh " av_push(push, newSVhek(hek));\n"
|
| 528 |
+
if $push;
|
| 529 |
+
|
| 530 |
+
print $xs_fh <<"EOBOOT";
|
| 531 |
+
} while ((++value_for_notfound)->name);
|
| 532 |
+
}
|
| 533 |
+
EOBOOT
|
| 534 |
+
|
| 535 |
+
foreach my $item (@$trouble) {
|
| 536 |
+
my ($name, $namelen, $value, $macro)
|
| 537 |
+
= $self->name_len_value_macro($item);
|
| 538 |
+
my $ifdef = $self->macro_to_ifdef($macro);
|
| 539 |
+
my $type = $item->{type};
|
| 540 |
+
my $type_to_value = $self->type_to_C_value($type);
|
| 541 |
+
|
| 542 |
+
print $xs_fh $ifdef;
|
| 543 |
+
if ($item->{invert_macro}) {
|
| 544 |
+
print $xs_fh
|
| 545 |
+
" /* This is the default value: */\n" if $type;
|
| 546 |
+
print $xs_fh "#else\n";
|
| 547 |
+
}
|
| 548 |
+
my $generator = $type_to_sv{$type};
|
| 549 |
+
die "Can't find generator code for type $type"
|
| 550 |
+
unless defined $generator;
|
| 551 |
+
|
| 552 |
+
print $xs_fh " {\n";
|
| 553 |
+
# We need to use a temporary value because some really troublesome
|
| 554 |
+
# items use C pre processor directives in their values, and in turn
|
| 555 |
+
# these don't fit nicely in the macro-ised generator functions
|
| 556 |
+
my $counter = 0;
|
| 557 |
+
printf $xs_fh " %s temp%d;\n", $_, $counter++
|
| 558 |
+
foreach @{$type_temporary{$type}};
|
| 559 |
+
|
| 560 |
+
print $xs_fh " $item->{pre}\n" if $item->{pre};
|
| 561 |
+
|
| 562 |
+
# And because the code in pre might be both declarations and
|
| 563 |
+
# statements, we can't declare and assign to the temporaries in one.
|
| 564 |
+
$counter = 0;
|
| 565 |
+
printf $xs_fh " temp%d = %s;\n", $counter++, $_
|
| 566 |
+
foreach &$type_to_value($value);
|
| 567 |
+
|
| 568 |
+
my @tempvarnames = map {sprintf 'temp%d', $_} 0 .. $counter - 1;
|
| 569 |
+
printf $xs_fh <<"EOBOOT", $name, &$generator(@tempvarnames);
|
| 570 |
+
${c_subname}_add_symbol($athx symbol_table, "%s",
|
| 571 |
+
$namelen, %s);
|
| 572 |
+
EOBOOT
|
| 573 |
+
print $xs_fh " $item->{post}\n" if $item->{post};
|
| 574 |
+
print $xs_fh " }\n";
|
| 575 |
+
|
| 576 |
+
print $xs_fh $self->macro_to_endif($macro);
|
| 577 |
+
}
|
| 578 |
+
|
| 579 |
+
if ($] >= 5.009) {
|
| 580 |
+
print $xs_fh <<EOBOOT;
|
| 581 |
+
/* As we've been creating subroutines, we better invalidate any cached
|
| 582 |
+
methods */
|
| 583 |
+
mro_method_changed_in(symbol_table);
|
| 584 |
+
}
|
| 585 |
+
EOBOOT
|
| 586 |
+
} else {
|
| 587 |
+
print $xs_fh <<EOBOOT;
|
| 588 |
+
/* As we've been creating subroutines, we better invalidate any cached
|
| 589 |
+
methods */
|
| 590 |
+
++PL_sub_generation;
|
| 591 |
+
}
|
| 592 |
+
EOBOOT
|
| 593 |
+
}
|
| 594 |
+
|
| 595 |
+
return if !defined $xs_subname;
|
| 596 |
+
|
| 597 |
+
if ($croak_on_error || $autoload) {
|
| 598 |
+
print $xs_fh $croak_on_error ? <<"EOC" : <<'EOA';
|
| 599 |
+
|
| 600 |
+
void
|
| 601 |
+
$xs_subname(sv)
|
| 602 |
+
INPUT:
|
| 603 |
+
SV * sv;
|
| 604 |
+
PREINIT:
|
| 605 |
+
const PERL_CONTEXT *cx = caller_cx(0, NULL);
|
| 606 |
+
/* cx is NULL if we've been called from the top level. PL_curcop isn't
|
| 607 |
+
ideal, but it's much cheaper than other ways of not going SEGV. */
|
| 608 |
+
const COP *cop = cx ? cx->blk_oldcop : PL_curcop;
|
| 609 |
+
EOC
|
| 610 |
+
|
| 611 |
+
void
|
| 612 |
+
AUTOLOAD()
|
| 613 |
+
PROTOTYPE: DISABLE
|
| 614 |
+
PREINIT:
|
| 615 |
+
SV *sv = newSVpvn_flags(SvPVX(cv), SvCUR(cv), SVs_TEMP | SvUTF8(cv));
|
| 616 |
+
const COP *cop = PL_curcop;
|
| 617 |
+
EOA
|
| 618 |
+
print $xs_fh <<"EOC";
|
| 619 |
+
PPCODE:
|
| 620 |
+
#ifndef SYMBIAN
|
| 621 |
+
/* It's not obvious how to calculate this at C pre-processor time.
|
| 622 |
+
However, any compiler optimiser worth its salt should be able to
|
| 623 |
+
remove the dead code, and hopefully the now-obviously-unused static
|
| 624 |
+
function too. */
|
| 625 |
+
HV *${c_subname}_missing = (C_ARRAY_LENGTH(values_for_notfound) > 1)
|
| 626 |
+
? get_missing_hash(aTHX) : NULL;
|
| 627 |
+
if ((C_ARRAY_LENGTH(values_for_notfound) > 1)
|
| 628 |
+
? hv_exists_ent(${c_subname}_missing, sv, 0) : 0) {
|
| 629 |
+
sv = newSVpvf("Your vendor has not defined $package_sprintf_safe macro %" SVf
|
| 630 |
+
", used at %" COP_FILE_F " line %" UVuf "\\n",
|
| 631 |
+
sv, COP_FILE(cop), (UV)CopLINE(cop));
|
| 632 |
+
} else
|
| 633 |
+
#endif
|
| 634 |
+
{
|
| 635 |
+
sv = newSVpvf("%" SVf
|
| 636 |
+
" is not a valid $package_sprintf_safe macro at %"
|
| 637 |
+
COP_FILE_F " line %" UVuf "\\n",
|
| 638 |
+
sv, COP_FILE(cop), (UV)CopLINE(cop));
|
| 639 |
+
}
|
| 640 |
+
croak_sv(sv_2mortal(sv));
|
| 641 |
+
EOC
|
| 642 |
+
} else {
|
| 643 |
+
print $xs_fh $explosives ? <<"EXPLODE" : <<"DONT";
|
| 644 |
+
|
| 645 |
+
void
|
| 646 |
+
$xs_subname(sv)
|
| 647 |
+
INPUT:
|
| 648 |
+
SV * sv;
|
| 649 |
+
PPCODE:
|
| 650 |
+
sv = newSVpvf("Your vendor has not defined $package_sprintf_safe macro %" SVf
|
| 651 |
+
", used", sv);
|
| 652 |
+
PUSHs(sv_2mortal(sv));
|
| 653 |
+
EXPLODE
|
| 654 |
+
|
| 655 |
+
void
|
| 656 |
+
$xs_subname(sv)
|
| 657 |
+
INPUT:
|
| 658 |
+
SV * sv;
|
| 659 |
+
PPCODE:
|
| 660 |
+
#ifndef SYMBIAN
|
| 661 |
+
/* It's not obvious how to calculate this at C pre-processor time.
|
| 662 |
+
However, any compiler optimiser worth its salt should be able to
|
| 663 |
+
remove the dead code, and hopefully the now-obviously-unused static
|
| 664 |
+
function too. */
|
| 665 |
+
HV *${c_subname}_missing = (C_ARRAY_LENGTH(values_for_notfound) > 1)
|
| 666 |
+
? get_missing_hash(aTHX) : NULL;
|
| 667 |
+
if ((C_ARRAY_LENGTH(values_for_notfound) > 1)
|
| 668 |
+
? hv_exists_ent(${c_subname}_missing, sv, 0) : 0) {
|
| 669 |
+
sv = newSVpvf("Your vendor has not defined $package_sprintf_safe macro %" SVf
|
| 670 |
+
", used", sv);
|
| 671 |
+
} else
|
| 672 |
+
#endif
|
| 673 |
+
{
|
| 674 |
+
sv = newSVpvf("%" SVf " is not a valid $package_sprintf_safe macro",
|
| 675 |
+
sv);
|
| 676 |
+
}
|
| 677 |
+
PUSHs(sv_2mortal(sv));
|
| 678 |
+
DONT
|
| 679 |
+
}
|
| 680 |
+
}
|
| 681 |
+
|
| 682 |
+
1;
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Constant/XS.pm
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::Constant::XS;
|
| 2 |
+
|
| 3 |
+
use strict;
|
| 4 |
+
use vars qw($VERSION %XS_Constant %XS_TypeSet @ISA @EXPORT_OK $is_perl56);
|
| 5 |
+
use Carp;
|
| 6 |
+
use ExtUtils::Constant::Utils 'perl_stringify';
|
| 7 |
+
require ExtUtils::Constant::Base;
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@ISA = qw(ExtUtils::Constant::Base Exporter);
|
| 11 |
+
@EXPORT_OK = qw(%XS_Constant %XS_TypeSet);
|
| 12 |
+
|
| 13 |
+
$VERSION = '0.03';
|
| 14 |
+
|
| 15 |
+
$is_perl56 = ($] < 5.007 && $] > 5.005_50);
|
| 16 |
+
|
| 17 |
+
=head1 NAME
|
| 18 |
+
|
| 19 |
+
ExtUtils::Constant::XS - generate C code for XS modules' constants.
|
| 20 |
+
|
| 21 |
+
=head1 SYNOPSIS
|
| 22 |
+
|
| 23 |
+
require ExtUtils::Constant::XS;
|
| 24 |
+
|
| 25 |
+
=head1 DESCRIPTION
|
| 26 |
+
|
| 27 |
+
ExtUtils::Constant::XS overrides ExtUtils::Constant::Base to generate C
|
| 28 |
+
code for XS modules' constants.
|
| 29 |
+
|
| 30 |
+
=head1 BUGS
|
| 31 |
+
|
| 32 |
+
Nothing is documented.
|
| 33 |
+
|
| 34 |
+
Probably others.
|
| 35 |
+
|
| 36 |
+
=head1 AUTHOR
|
| 37 |
+
|
| 38 |
+
Nicholas Clark <[email protected]> based on the code in C<h2xs> by Larry Wall and
|
| 39 |
+
others
|
| 40 |
+
|
| 41 |
+
=cut
|
| 42 |
+
|
| 43 |
+
# '' is used as a flag to indicate non-ascii macro names, and hence the need
|
| 44 |
+
# to pass in the utf8 on/off flag.
|
| 45 |
+
%XS_Constant = (
|
| 46 |
+
'' => '',
|
| 47 |
+
IV => 'PUSHi(iv)',
|
| 48 |
+
UV => 'PUSHu((UV)iv)',
|
| 49 |
+
NV => 'PUSHn(nv)',
|
| 50 |
+
PV => 'PUSHp(pv, strlen(pv))',
|
| 51 |
+
PVN => 'PUSHp(pv, iv)',
|
| 52 |
+
SV => 'PUSHs(sv)',
|
| 53 |
+
YES => 'PUSHs(&PL_sv_yes)',
|
| 54 |
+
NO => 'PUSHs(&PL_sv_no)',
|
| 55 |
+
UNDEF => '', # implicit undef
|
| 56 |
+
);
|
| 57 |
+
|
| 58 |
+
%XS_TypeSet = (
|
| 59 |
+
IV => '*iv_return = ',
|
| 60 |
+
UV => '*iv_return = (IV)',
|
| 61 |
+
NV => '*nv_return = ',
|
| 62 |
+
PV => '*pv_return = ',
|
| 63 |
+
PVN => ['*pv_return = ', '*iv_return = (IV)'],
|
| 64 |
+
SV => '*sv_return = ',
|
| 65 |
+
YES => undef,
|
| 66 |
+
NO => undef,
|
| 67 |
+
UNDEF => undef,
|
| 68 |
+
);
|
| 69 |
+
|
| 70 |
+
sub header {
|
| 71 |
+
my $start = 1;
|
| 72 |
+
my @lines;
|
| 73 |
+
push @lines, "#define PERL_constant_NOTFOUND\t$start\n"; $start++;
|
| 74 |
+
push @lines, "#define PERL_constant_NOTDEF\t$start\n"; $start++;
|
| 75 |
+
foreach (sort keys %XS_Constant) {
|
| 76 |
+
next if $_ eq '';
|
| 77 |
+
push @lines, "#define PERL_constant_IS$_\t$start\n"; $start++;
|
| 78 |
+
}
|
| 79 |
+
push @lines, << 'EOT';
|
| 80 |
+
|
| 81 |
+
#ifndef NVTYPE
|
| 82 |
+
typedef double NV; /* 5.6 and later define NVTYPE, and typedef NV to it. */
|
| 83 |
+
#endif
|
| 84 |
+
#ifndef aTHX_
|
| 85 |
+
#define aTHX_ /* 5.6 or later define this for threading support. */
|
| 86 |
+
#endif
|
| 87 |
+
#ifndef pTHX_
|
| 88 |
+
#define pTHX_ /* 5.6 or later define this for threading support. */
|
| 89 |
+
#endif
|
| 90 |
+
EOT
|
| 91 |
+
|
| 92 |
+
return join '', @lines;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
sub valid_type {
|
| 96 |
+
my ($self, $type) = @_;
|
| 97 |
+
return exists $XS_TypeSet{$type};
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
# This might actually be a return statement
|
| 101 |
+
sub assignment_clause_for_type {
|
| 102 |
+
my $self = shift;
|
| 103 |
+
my $args = shift;
|
| 104 |
+
my $type = $args->{type};
|
| 105 |
+
my $typeset = $XS_TypeSet{$type};
|
| 106 |
+
if (ref $typeset) {
|
| 107 |
+
die "Type $type is aggregate, but only single value given"
|
| 108 |
+
if @_ == 1;
|
| 109 |
+
return map {"$typeset->[$_]$_[$_];"} 0 .. $#$typeset;
|
| 110 |
+
} elsif (defined $typeset) {
|
| 111 |
+
confess "Aggregate value given for type $type"
|
| 112 |
+
if @_ > 1;
|
| 113 |
+
return "$typeset$_[0];";
|
| 114 |
+
}
|
| 115 |
+
return ();
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
sub return_statement_for_type {
|
| 119 |
+
my ($self, $type) = @_;
|
| 120 |
+
# In the future may pass in an options hash
|
| 121 |
+
$type = $type->{type} if ref $type;
|
| 122 |
+
"return PERL_constant_IS$type;";
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
sub return_statement_for_notdef {
|
| 126 |
+
# my ($self) = @_;
|
| 127 |
+
"return PERL_constant_NOTDEF;";
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
sub return_statement_for_notfound {
|
| 131 |
+
# my ($self) = @_;
|
| 132 |
+
"return PERL_constant_NOTFOUND;";
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
sub default_type {
|
| 136 |
+
'IV';
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
sub macro_from_name {
|
| 140 |
+
my ($self, $item) = @_;
|
| 141 |
+
my $macro = $item->{name};
|
| 142 |
+
$macro = $item->{value} unless defined $macro;
|
| 143 |
+
$macro;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
sub macro_from_item {
|
| 147 |
+
my ($self, $item) = @_;
|
| 148 |
+
my $macro = $item->{macro};
|
| 149 |
+
$macro = $self->macro_from_name($item) unless defined $macro;
|
| 150 |
+
$macro;
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
# Keep to the traditional perl source macro
|
| 154 |
+
sub memEQ {
|
| 155 |
+
"memEQ";
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
sub params {
|
| 159 |
+
my ($self, $what) = @_;
|
| 160 |
+
foreach (sort keys %$what) {
|
| 161 |
+
warn "ExtUtils::Constant doesn't know how to handle values of type $_" unless defined $XS_Constant{$_};
|
| 162 |
+
}
|
| 163 |
+
my $params = {};
|
| 164 |
+
$params->{''} = 1 if $what->{''};
|
| 165 |
+
$params->{IV} = 1 if $what->{IV} || $what->{UV} || $what->{PVN};
|
| 166 |
+
$params->{NV} = 1 if $what->{NV};
|
| 167 |
+
$params->{PV} = 1 if $what->{PV} || $what->{PVN};
|
| 168 |
+
$params->{SV} = 1 if $what->{SV};
|
| 169 |
+
return $params;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
sub C_constant_prefix_param {
|
| 174 |
+
"aTHX_ ";
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
sub C_constant_prefix_param_defintion {
|
| 178 |
+
"pTHX_ ";
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
sub namelen_param_definition {
|
| 182 |
+
'STRLEN ' . $_[0] -> namelen_param;
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
sub C_constant_other_params_defintion {
|
| 186 |
+
my ($self, $params) = @_;
|
| 187 |
+
my $body = '';
|
| 188 |
+
$body .= ", int utf8" if $params->{''};
|
| 189 |
+
$body .= ", IV *iv_return" if $params->{IV};
|
| 190 |
+
$body .= ", NV *nv_return" if $params->{NV};
|
| 191 |
+
$body .= ", const char **pv_return" if $params->{PV};
|
| 192 |
+
$body .= ", SV **sv_return" if $params->{SV};
|
| 193 |
+
$body;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
sub C_constant_other_params {
|
| 197 |
+
my ($self, $params) = @_;
|
| 198 |
+
my $body = '';
|
| 199 |
+
$body .= ", utf8" if $params->{''};
|
| 200 |
+
$body .= ", iv_return" if $params->{IV};
|
| 201 |
+
$body .= ", nv_return" if $params->{NV};
|
| 202 |
+
$body .= ", pv_return" if $params->{PV};
|
| 203 |
+
$body .= ", sv_return" if $params->{SV};
|
| 204 |
+
$body;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
sub dogfood {
|
| 208 |
+
my ($self, $args, @items) = @_;
|
| 209 |
+
my ($package, $subname, $default_type, $what, $indent, $breakout) =
|
| 210 |
+
@{$args}{qw(package subname default_type what indent breakout)};
|
| 211 |
+
my $result = <<"EOT";
|
| 212 |
+
/* When generated this function returned values for the list of names given
|
| 213 |
+
in this section of perl code. Rather than manually editing these functions
|
| 214 |
+
to add or remove constants, which would result in this comment and section
|
| 215 |
+
of code becoming inaccurate, we recommend that you edit this section of
|
| 216 |
+
code, and use it to regenerate a new set of constant functions which you
|
| 217 |
+
then use to replace the originals.
|
| 218 |
+
|
| 219 |
+
Regenerate these constant functions by feeding this entire source file to
|
| 220 |
+
perl -x
|
| 221 |
+
|
| 222 |
+
#!$^X -w
|
| 223 |
+
use ExtUtils::Constant qw (constant_types C_constant XS_constant);
|
| 224 |
+
|
| 225 |
+
EOT
|
| 226 |
+
$result .= $self->dump_names ({default_type=>$default_type, what=>$what,
|
| 227 |
+
indent=>0, declare_types=>1},
|
| 228 |
+
@items);
|
| 229 |
+
$result .= <<'EOT';
|
| 230 |
+
|
| 231 |
+
print constant_types(), "\n"; # macro defs
|
| 232 |
+
EOT
|
| 233 |
+
$package = perl_stringify($package);
|
| 234 |
+
$result .=
|
| 235 |
+
"foreach (C_constant (\"$package\", '$subname', '$default_type', \$types, ";
|
| 236 |
+
# The form of the indent parameter isn't defined. (Yet)
|
| 237 |
+
if (defined $indent) {
|
| 238 |
+
require Data::Dumper;
|
| 239 |
+
$Data::Dumper::Terse=1;
|
| 240 |
+
$Data::Dumper::Terse=1; # Not used once. :-)
|
| 241 |
+
chomp ($indent = Data::Dumper::Dumper ($indent));
|
| 242 |
+
$result .= $indent;
|
| 243 |
+
} else {
|
| 244 |
+
$result .= 'undef';
|
| 245 |
+
}
|
| 246 |
+
$result .= ", $breakout" . ', @names) ) {
|
| 247 |
+
print $_, "\n"; # C constant subs
|
| 248 |
+
}
|
| 249 |
+
print "\n#### XS Section:\n";
|
| 250 |
+
print XS_constant ("' . $package . '", $types);
|
| 251 |
+
__END__
|
| 252 |
+
*/
|
| 253 |
+
|
| 254 |
+
';
|
| 255 |
+
|
| 256 |
+
$result;
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
1;
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/MakeMaker/FAQ.pod
ADDED
|
@@ -0,0 +1,666 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::MakeMaker::FAQ;
|
| 2 |
+
|
| 3 |
+
our $VERSION = '7.34';
|
| 4 |
+
$VERSION = eval $VERSION;
|
| 5 |
+
|
| 6 |
+
1;
|
| 7 |
+
__END__
|
| 8 |
+
|
| 9 |
+
=head1 NAME
|
| 10 |
+
|
| 11 |
+
ExtUtils::MakeMaker::FAQ - Frequently Asked Questions About MakeMaker
|
| 12 |
+
|
| 13 |
+
=head1 DESCRIPTION
|
| 14 |
+
|
| 15 |
+
FAQs, tricks and tips for C<ExtUtils::MakeMaker>.
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
=head2 Module Installation
|
| 19 |
+
|
| 20 |
+
=over 4
|
| 21 |
+
|
| 22 |
+
=item How do I install a module into my home directory?
|
| 23 |
+
|
| 24 |
+
If you're not the Perl administrator you probably don't have
|
| 25 |
+
permission to install a module to its default location. Ways of handling
|
| 26 |
+
this with a B<lot> less manual effort on your part are L<perlbrew>
|
| 27 |
+
and L<local::lib>.
|
| 28 |
+
|
| 29 |
+
Otherwise, you can install it for your own use into your home directory
|
| 30 |
+
like so:
|
| 31 |
+
|
| 32 |
+
# Non-unix folks, replace ~ with /path/to/your/home/dir
|
| 33 |
+
perl Makefile.PL INSTALL_BASE=~
|
| 34 |
+
|
| 35 |
+
This will put modules into F<~/lib/perl5>, man pages into F<~/man> and
|
| 36 |
+
programs into F<~/bin>.
|
| 37 |
+
|
| 38 |
+
To ensure your Perl programs can see these newly installed modules,
|
| 39 |
+
set your C<PERL5LIB> environment variable to F<~/lib/perl5> or tell
|
| 40 |
+
each of your programs to look in that directory with the following:
|
| 41 |
+
|
| 42 |
+
use lib "$ENV{HOME}/lib/perl5";
|
| 43 |
+
|
| 44 |
+
or if $ENV{HOME} isn't set and you don't want to set it for some
|
| 45 |
+
reason, do it the long way.
|
| 46 |
+
|
| 47 |
+
use lib "/path/to/your/home/dir/lib/perl5";
|
| 48 |
+
|
| 49 |
+
=item How do I get MakeMaker and Module::Build to install to the same place?
|
| 50 |
+
|
| 51 |
+
Module::Build, as of 0.28, supports two ways to install to the same
|
| 52 |
+
location as MakeMaker.
|
| 53 |
+
|
| 54 |
+
We highly recommend the install_base method, its the simplest and most
|
| 55 |
+
closely approximates the expected behavior of an installation prefix.
|
| 56 |
+
|
| 57 |
+
1) Use INSTALL_BASE / C<--install_base>
|
| 58 |
+
|
| 59 |
+
MakeMaker (as of 6.31) and Module::Build (as of 0.28) both can install
|
| 60 |
+
to the same locations using the "install_base" concept. See
|
| 61 |
+
L<ExtUtils::MakeMaker/INSTALL_BASE> for details. To get MM and MB to
|
| 62 |
+
install to the same location simply set INSTALL_BASE in MM and
|
| 63 |
+
C<--install_base> in MB to the same location.
|
| 64 |
+
|
| 65 |
+
perl Makefile.PL INSTALL_BASE=/whatever
|
| 66 |
+
perl Build.PL --install_base /whatever
|
| 67 |
+
|
| 68 |
+
This works most like other language's behavior when you specify a
|
| 69 |
+
prefix. We recommend this method.
|
| 70 |
+
|
| 71 |
+
2) Use PREFIX / C<--prefix>
|
| 72 |
+
|
| 73 |
+
Module::Build 0.28 added support for C<--prefix> which works like
|
| 74 |
+
MakeMaker's PREFIX.
|
| 75 |
+
|
| 76 |
+
perl Makefile.PL PREFIX=/whatever
|
| 77 |
+
perl Build.PL --prefix /whatever
|
| 78 |
+
|
| 79 |
+
We highly discourage this method. It should only be used if you know
|
| 80 |
+
what you're doing and specifically need the PREFIX behavior. The
|
| 81 |
+
PREFIX algorithm is complicated and focused on matching the system
|
| 82 |
+
installation.
|
| 83 |
+
|
| 84 |
+
=item How do I keep from installing man pages?
|
| 85 |
+
|
| 86 |
+
Recent versions of MakeMaker will only install man pages on Unix-like
|
| 87 |
+
operating systems.
|
| 88 |
+
|
| 89 |
+
For an individual module:
|
| 90 |
+
|
| 91 |
+
perl Makefile.PL INSTALLMAN1DIR=none INSTALLMAN3DIR=none
|
| 92 |
+
|
| 93 |
+
If you want to suppress man page installation for all modules you have
|
| 94 |
+
to reconfigure Perl and tell it 'none' when it asks where to install
|
| 95 |
+
man pages.
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
=item How do I use a module without installing it?
|
| 99 |
+
|
| 100 |
+
Two ways. One is to build the module normally...
|
| 101 |
+
|
| 102 |
+
perl Makefile.PL
|
| 103 |
+
make
|
| 104 |
+
make test
|
| 105 |
+
|
| 106 |
+
...and then use L<blib> to point Perl at the built but uninstalled module:
|
| 107 |
+
|
| 108 |
+
perl -Mblib script.pl
|
| 109 |
+
perl -Mblib -e '...'
|
| 110 |
+
|
| 111 |
+
The other is to install the module in a temporary location.
|
| 112 |
+
|
| 113 |
+
perl Makefile.PL INSTALL_BASE=~/tmp
|
| 114 |
+
make
|
| 115 |
+
make test
|
| 116 |
+
make install
|
| 117 |
+
|
| 118 |
+
And then set PERL5LIB to F<~/tmp/lib/perl5>. This works well when you
|
| 119 |
+
have multiple modules to work with. It also ensures that the module
|
| 120 |
+
goes through its full installation process which may modify it.
|
| 121 |
+
Again, L<local::lib> may assist you here.
|
| 122 |
+
|
| 123 |
+
=item How can I organize tests into subdirectories and have them run?
|
| 124 |
+
|
| 125 |
+
Let's take the following test directory structure:
|
| 126 |
+
|
| 127 |
+
t/foo/sometest.t
|
| 128 |
+
t/bar/othertest.t
|
| 129 |
+
t/bar/baz/anothertest.t
|
| 130 |
+
|
| 131 |
+
Now, inside of the C<WriteMakeFile()> function in your F<Makefile.PL>, specify
|
| 132 |
+
where your tests are located with the C<test> directive:
|
| 133 |
+
|
| 134 |
+
test => {TESTS => 't/*.t t/*/*.t t/*/*/*.t'}
|
| 135 |
+
|
| 136 |
+
The first entry in the string will run all tests in the top-level F<t/>
|
| 137 |
+
directory. The second will run all test files located in any subdirectory under
|
| 138 |
+
F<t/>. The third, runs all test files within any subdirectory within any other
|
| 139 |
+
subdirectory located under F<t/>.
|
| 140 |
+
|
| 141 |
+
Note that you do not have to use wildcards. You can specify explicitly which
|
| 142 |
+
subdirectories to run tests in:
|
| 143 |
+
|
| 144 |
+
test => {TESTS => 't/*.t t/foo/*.t t/bar/baz/*.t'}
|
| 145 |
+
|
| 146 |
+
=item PREFIX vs INSTALL_BASE from Module::Build::Cookbook
|
| 147 |
+
|
| 148 |
+
The behavior of PREFIX is complicated and depends closely on how your
|
| 149 |
+
Perl is configured. The resulting installation locations will vary
|
| 150 |
+
from machine to machine and even different installations of Perl on the
|
| 151 |
+
same machine. Because of this, its difficult to document where prefix
|
| 152 |
+
will place your modules.
|
| 153 |
+
|
| 154 |
+
In contrast, INSTALL_BASE has predictable, easy to explain installation
|
| 155 |
+
locations. Now that Module::Build and MakeMaker both have INSTALL_BASE
|
| 156 |
+
there is little reason to use PREFIX other than to preserve your existing
|
| 157 |
+
installation locations. If you are starting a fresh Perl installation we
|
| 158 |
+
encourage you to use INSTALL_BASE. If you have an existing installation
|
| 159 |
+
installed via PREFIX, consider moving it to an installation structure
|
| 160 |
+
matching INSTALL_BASE and using that instead.
|
| 161 |
+
|
| 162 |
+
=item Generating *.pm files with substitutions eg of $VERSION
|
| 163 |
+
|
| 164 |
+
If you want to configure your module files for local conditions, or to
|
| 165 |
+
automatically insert a version number, you can use EUMM's C<PL_FILES>
|
| 166 |
+
capability, where it will automatically run each F<*.PL> it finds to
|
| 167 |
+
generate its basename. For instance:
|
| 168 |
+
|
| 169 |
+
# Makefile.PL:
|
| 170 |
+
require 'common.pl';
|
| 171 |
+
my $version = get_version();
|
| 172 |
+
my @pms = qw(Foo.pm);
|
| 173 |
+
WriteMakefile(
|
| 174 |
+
NAME => 'Foo',
|
| 175 |
+
VERSION => $version,
|
| 176 |
+
PM => { map { ($_ => "\$(INST_LIB)/$_") } @pms },
|
| 177 |
+
clean => { FILES => join ' ', @pms },
|
| 178 |
+
);
|
| 179 |
+
|
| 180 |
+
# common.pl:
|
| 181 |
+
sub get_version { '0.04' }
|
| 182 |
+
sub process { my $v = get_version(); s/__VERSION__/$v/g; }
|
| 183 |
+
1;
|
| 184 |
+
|
| 185 |
+
# Foo.pm.PL:
|
| 186 |
+
require 'common.pl';
|
| 187 |
+
$_ = join '', <DATA>;
|
| 188 |
+
process();
|
| 189 |
+
my $file = shift;
|
| 190 |
+
open my $fh, '>', $file or die "$file: $!";
|
| 191 |
+
print $fh $_;
|
| 192 |
+
__DATA__
|
| 193 |
+
package Foo;
|
| 194 |
+
our $VERSION = '__VERSION__';
|
| 195 |
+
1;
|
| 196 |
+
|
| 197 |
+
You may notice that C<PL_FILES> is not specified above, since the default
|
| 198 |
+
of mapping each .PL file to its basename works well.
|
| 199 |
+
|
| 200 |
+
If the generated module were architecture-specific, you could replace
|
| 201 |
+
C<$(INST_LIB)> above with C<$(INST_ARCHLIB)>, although if you locate
|
| 202 |
+
modules under F<lib>, that would involve ensuring any C<lib/> in front
|
| 203 |
+
of the module location were removed.
|
| 204 |
+
|
| 205 |
+
=back
|
| 206 |
+
|
| 207 |
+
=head2 Common errors and problems
|
| 208 |
+
|
| 209 |
+
=over 4
|
| 210 |
+
|
| 211 |
+
=item "No rule to make target `/usr/lib/perl5/CORE/config.h', needed by `Makefile'"
|
| 212 |
+
|
| 213 |
+
Just what it says, you're missing that file. MakeMaker uses it to
|
| 214 |
+
determine if perl has been rebuilt since the Makefile was made. It's
|
| 215 |
+
a bit of a bug that it halts installation.
|
| 216 |
+
|
| 217 |
+
Some operating systems don't ship the CORE directory with their base
|
| 218 |
+
perl install. To solve the problem, you likely need to install a perl
|
| 219 |
+
development package such as perl-devel (CentOS, Fedora and other
|
| 220 |
+
Redhat systems) or perl (Ubuntu and other Debian systems).
|
| 221 |
+
|
| 222 |
+
=back
|
| 223 |
+
|
| 224 |
+
=head2 Philosophy and History
|
| 225 |
+
|
| 226 |
+
=over 4
|
| 227 |
+
|
| 228 |
+
=item Why not just use <insert other build config tool here>?
|
| 229 |
+
|
| 230 |
+
Why did MakeMaker reinvent the build configuration wheel? Why not
|
| 231 |
+
just use autoconf or automake or ppm or Ant or ...
|
| 232 |
+
|
| 233 |
+
There are many reasons, but the major one is cross-platform
|
| 234 |
+
compatibility.
|
| 235 |
+
|
| 236 |
+
Perl is one of the most ported pieces of software ever. It works on
|
| 237 |
+
operating systems I've never even heard of (see perlport for details).
|
| 238 |
+
It needs a build tool that can work on all those platforms and with
|
| 239 |
+
any wacky C compilers and linkers they might have.
|
| 240 |
+
|
| 241 |
+
No such build tool exists. Even make itself has wildly different
|
| 242 |
+
dialects. So we have to build our own.
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
=item What is Module::Build and how does it relate to MakeMaker?
|
| 246 |
+
|
| 247 |
+
Module::Build is a project by Ken Williams to supplant MakeMaker.
|
| 248 |
+
Its primary advantages are:
|
| 249 |
+
|
| 250 |
+
=over 8
|
| 251 |
+
|
| 252 |
+
=item * pure perl. no make, no shell commands
|
| 253 |
+
|
| 254 |
+
=item * easier to customize
|
| 255 |
+
|
| 256 |
+
=item * cleaner internals
|
| 257 |
+
|
| 258 |
+
=item * less cruft
|
| 259 |
+
|
| 260 |
+
=back
|
| 261 |
+
|
| 262 |
+
Module::Build was long the official heir apparent to MakeMaker. The
|
| 263 |
+
rate of both its development and adoption has slowed in recent years,
|
| 264 |
+
though, and it is unclear what the future holds for it. That said,
|
| 265 |
+
Module::Build set the stage for I<something> to become the heir to
|
| 266 |
+
MakeMaker. MakeMaker's maintainers have long said that it is a dead
|
| 267 |
+
end and should be kept functioning, while being cautious about extending
|
| 268 |
+
with new features.
|
| 269 |
+
|
| 270 |
+
=back
|
| 271 |
+
|
| 272 |
+
=head2 Module Writing
|
| 273 |
+
|
| 274 |
+
=over 4
|
| 275 |
+
|
| 276 |
+
=item How do I keep my $VERSION up to date without resetting it manually?
|
| 277 |
+
|
| 278 |
+
Often you want to manually set the $VERSION in the main module
|
| 279 |
+
distribution because this is the version that everybody sees on CPAN
|
| 280 |
+
and maybe you want to customize it a bit. But for all the other
|
| 281 |
+
modules in your dist, $VERSION is really just bookkeeping and all that's
|
| 282 |
+
important is it goes up every time the module is changed. Doing this
|
| 283 |
+
by hand is a pain and you often forget.
|
| 284 |
+
|
| 285 |
+
Probably the easiest way to do this is using F<perl-reversion> in
|
| 286 |
+
L<Perl::Version>:
|
| 287 |
+
|
| 288 |
+
perl-reversion -bump
|
| 289 |
+
|
| 290 |
+
If your version control system supports revision numbers (git doesn't
|
| 291 |
+
easily), the simplest way to do it automatically is to use its revision
|
| 292 |
+
number (you are using version control, right?).
|
| 293 |
+
|
| 294 |
+
In CVS, RCS and SVN you use $Revision$ (see the documentation of your
|
| 295 |
+
version control system for details). Every time the file is checked
|
| 296 |
+
in the $Revision$ will be updated, updating your $VERSION.
|
| 297 |
+
|
| 298 |
+
SVN uses a simple integer for $Revision$ so you can adapt it for your
|
| 299 |
+
$VERSION like so:
|
| 300 |
+
|
| 301 |
+
($VERSION) = q$Revision$ =~ /(\d+)/;
|
| 302 |
+
|
| 303 |
+
In CVS and RCS version 1.9 is followed by 1.10. Since CPAN compares
|
| 304 |
+
version numbers numerically we use a sprintf() to convert 1.9 to 1.009
|
| 305 |
+
and 1.10 to 1.010 which compare properly.
|
| 306 |
+
|
| 307 |
+
$VERSION = sprintf "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/g;
|
| 308 |
+
|
| 309 |
+
If branches are involved (ie. $Revision: 1.5.3.4$) it's a little more
|
| 310 |
+
complicated.
|
| 311 |
+
|
| 312 |
+
# must be all on one line or MakeMaker will get confused.
|
| 313 |
+
$VERSION = do { my @r = (q$Revision$ =~ /\d+/g); sprintf "%d."."%03d" x $#r, @r };
|
| 314 |
+
|
| 315 |
+
In SVN, $Revision$ should be the same for every file in the project so
|
| 316 |
+
they would all have the same $VERSION. CVS and RCS have a different
|
| 317 |
+
$Revision$ per file so each file will have a different $VERSION.
|
| 318 |
+
Distributed version control systems, such as SVK, may have a different
|
| 319 |
+
$Revision$ based on who checks out the file, leading to a different $VERSION
|
| 320 |
+
on each machine! Finally, some distributed version control systems, such
|
| 321 |
+
as darcs, have no concept of revision number at all.
|
| 322 |
+
|
| 323 |
+
|
| 324 |
+
=item What's this F<META.yml> thing and how did it get in my F<MANIFEST>?!
|
| 325 |
+
|
| 326 |
+
F<META.yml> is a module meta-data file pioneered by Module::Build and
|
| 327 |
+
automatically generated as part of the 'distdir' target (and thus
|
| 328 |
+
'dist'). See L<ExtUtils::MakeMaker/"Module Meta-Data">.
|
| 329 |
+
|
| 330 |
+
To shut off its generation, pass the C<NO_META> flag to C<WriteMakefile()>.
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
=item How do I delete everything not in my F<MANIFEST>?
|
| 334 |
+
|
| 335 |
+
Some folks are surprised that C<make distclean> does not delete
|
| 336 |
+
everything not listed in their MANIFEST (thus making a clean
|
| 337 |
+
distribution) but only tells them what they need to delete. This is
|
| 338 |
+
done because it is considered too dangerous. While developing your
|
| 339 |
+
module you might write a new file, not add it to the MANIFEST, then
|
| 340 |
+
run a C<distclean> and be sad because your new work was deleted.
|
| 341 |
+
|
| 342 |
+
If you really want to do this, you can use
|
| 343 |
+
C<ExtUtils::Manifest::manifind()> to read the MANIFEST and File::Find
|
| 344 |
+
to delete the files. But you have to be careful. Here's a script to
|
| 345 |
+
do that. Use at your own risk. Have fun blowing holes in your foot.
|
| 346 |
+
|
| 347 |
+
#!/usr/bin/perl -w
|
| 348 |
+
|
| 349 |
+
use strict;
|
| 350 |
+
|
| 351 |
+
use File::Spec;
|
| 352 |
+
use File::Find;
|
| 353 |
+
use ExtUtils::Manifest qw(maniread);
|
| 354 |
+
|
| 355 |
+
my %manifest = map {( $_ => 1 )}
|
| 356 |
+
grep { File::Spec->canonpath($_) }
|
| 357 |
+
keys %{ maniread() };
|
| 358 |
+
|
| 359 |
+
if( !keys %manifest ) {
|
| 360 |
+
print "No files found in MANIFEST. Stopping.\n";
|
| 361 |
+
exit;
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
find({
|
| 365 |
+
wanted => sub {
|
| 366 |
+
my $path = File::Spec->canonpath($_);
|
| 367 |
+
|
| 368 |
+
return unless -f $path;
|
| 369 |
+
return if exists $manifest{ $path };
|
| 370 |
+
|
| 371 |
+
print "unlink $path\n";
|
| 372 |
+
unlink $path;
|
| 373 |
+
},
|
| 374 |
+
no_chdir => 1
|
| 375 |
+
},
|
| 376 |
+
"."
|
| 377 |
+
);
|
| 378 |
+
|
| 379 |
+
|
| 380 |
+
=item Which tar should I use on Windows?
|
| 381 |
+
|
| 382 |
+
We recommend ptar from Archive::Tar not older than 1.66 with '-C' option.
|
| 383 |
+
|
| 384 |
+
=item Which zip should I use on Windows for '[ndg]make zipdist'?
|
| 385 |
+
|
| 386 |
+
We recommend InfoZIP: L<http://www.info-zip.org/Zip.html>
|
| 387 |
+
|
| 388 |
+
|
| 389 |
+
=back
|
| 390 |
+
|
| 391 |
+
=head2 XS
|
| 392 |
+
|
| 393 |
+
=over 4
|
| 394 |
+
|
| 395 |
+
=item How do I prevent "object version X.XX does not match bootstrap parameter Y.YY" errors?
|
| 396 |
+
|
| 397 |
+
XS code is very sensitive to the module version number and will
|
| 398 |
+
complain if the version number in your Perl module doesn't match. If
|
| 399 |
+
you change your module's version # without rerunning Makefile.PL the old
|
| 400 |
+
version number will remain in the Makefile, causing the XS code to be built
|
| 401 |
+
with the wrong number.
|
| 402 |
+
|
| 403 |
+
To avoid this, you can force the Makefile to be rebuilt whenever you
|
| 404 |
+
change the module containing the version number by adding this to your
|
| 405 |
+
WriteMakefile() arguments.
|
| 406 |
+
|
| 407 |
+
depend => { '$(FIRST_MAKEFILE)' => '$(VERSION_FROM)' }
|
| 408 |
+
|
| 409 |
+
|
| 410 |
+
=item How do I make two or more XS files coexist in the same directory?
|
| 411 |
+
|
| 412 |
+
Sometimes you need to have two and more XS files in the same package.
|
| 413 |
+
There are three ways: C<XSMULTI>, separate directories, and bootstrapping
|
| 414 |
+
one XS from another.
|
| 415 |
+
|
| 416 |
+
=over 8
|
| 417 |
+
|
| 418 |
+
=item XSMULTI
|
| 419 |
+
|
| 420 |
+
Structure your modules so they are all located under F<lib>, such that
|
| 421 |
+
C<Foo::Bar> is in F<lib/Foo/Bar.pm> and F<lib/Foo/Bar.xs>, etc. Have your
|
| 422 |
+
top-level C<WriteMakefile> set the variable C<XSMULTI> to a true value.
|
| 423 |
+
|
| 424 |
+
Er, that's it.
|
| 425 |
+
|
| 426 |
+
=item Separate directories
|
| 427 |
+
|
| 428 |
+
Put each XS files into separate directories, each with their own
|
| 429 |
+
F<Makefile.PL>. Make sure each of those F<Makefile.PL>s has the correct
|
| 430 |
+
C<CFLAGS>, C<INC>, C<LIBS> etc. You will need to make sure the top-level
|
| 431 |
+
F<Makefile.PL> refers to each of these using C<DIR>.
|
| 432 |
+
|
| 433 |
+
=item Bootstrapping
|
| 434 |
+
|
| 435 |
+
Let's assume that we have a package C<Cool::Foo>, which includes
|
| 436 |
+
C<Cool::Foo> and C<Cool::Bar> modules each having a separate XS
|
| 437 |
+
file. First we use the following I<Makefile.PL>:
|
| 438 |
+
|
| 439 |
+
use ExtUtils::MakeMaker;
|
| 440 |
+
|
| 441 |
+
WriteMakefile(
|
| 442 |
+
NAME => 'Cool::Foo',
|
| 443 |
+
VERSION_FROM => 'Foo.pm',
|
| 444 |
+
OBJECT => q/$(O_FILES)/,
|
| 445 |
+
# ... other attrs ...
|
| 446 |
+
);
|
| 447 |
+
|
| 448 |
+
Notice the C<OBJECT> attribute. MakeMaker generates the following
|
| 449 |
+
variables in I<Makefile>:
|
| 450 |
+
|
| 451 |
+
# Handy lists of source code files:
|
| 452 |
+
XS_FILES= Bar.xs \
|
| 453 |
+
Foo.xs
|
| 454 |
+
C_FILES = Bar.c \
|
| 455 |
+
Foo.c
|
| 456 |
+
O_FILES = Bar.o \
|
| 457 |
+
Foo.o
|
| 458 |
+
|
| 459 |
+
Therefore we can use the C<O_FILES> variable to tell MakeMaker to use
|
| 460 |
+
these objects into the shared library.
|
| 461 |
+
|
| 462 |
+
That's pretty much it. Now write I<Foo.pm> and I<Foo.xs>, I<Bar.pm>
|
| 463 |
+
and I<Bar.xs>, where I<Foo.pm> bootstraps the shared library and
|
| 464 |
+
I<Bar.pm> simply loading I<Foo.pm>.
|
| 465 |
+
|
| 466 |
+
The only issue left is to how to bootstrap I<Bar.xs>. This is done
|
| 467 |
+
from I<Foo.xs>:
|
| 468 |
+
|
| 469 |
+
MODULE = Cool::Foo PACKAGE = Cool::Foo
|
| 470 |
+
|
| 471 |
+
BOOT:
|
| 472 |
+
# boot the second XS file
|
| 473 |
+
boot_Cool__Bar(aTHX_ cv);
|
| 474 |
+
|
| 475 |
+
If you have more than two files, this is the place where you should
|
| 476 |
+
boot extra XS files from.
|
| 477 |
+
|
| 478 |
+
The following four files sum up all the details discussed so far.
|
| 479 |
+
|
| 480 |
+
Foo.pm:
|
| 481 |
+
-------
|
| 482 |
+
package Cool::Foo;
|
| 483 |
+
|
| 484 |
+
require DynaLoader;
|
| 485 |
+
|
| 486 |
+
our @ISA = qw(DynaLoader);
|
| 487 |
+
our $VERSION = '0.01';
|
| 488 |
+
bootstrap Cool::Foo $VERSION;
|
| 489 |
+
|
| 490 |
+
1;
|
| 491 |
+
|
| 492 |
+
Bar.pm:
|
| 493 |
+
-------
|
| 494 |
+
package Cool::Bar;
|
| 495 |
+
|
| 496 |
+
use Cool::Foo; # bootstraps Bar.xs
|
| 497 |
+
|
| 498 |
+
1;
|
| 499 |
+
|
| 500 |
+
Foo.xs:
|
| 501 |
+
-------
|
| 502 |
+
#include "EXTERN.h"
|
| 503 |
+
#include "perl.h"
|
| 504 |
+
#include "XSUB.h"
|
| 505 |
+
|
| 506 |
+
MODULE = Cool::Foo PACKAGE = Cool::Foo
|
| 507 |
+
|
| 508 |
+
BOOT:
|
| 509 |
+
# boot the second XS file
|
| 510 |
+
boot_Cool__Bar(aTHX_ cv);
|
| 511 |
+
|
| 512 |
+
MODULE = Cool::Foo PACKAGE = Cool::Foo PREFIX = cool_foo_
|
| 513 |
+
|
| 514 |
+
void
|
| 515 |
+
cool_foo_perl_rules()
|
| 516 |
+
|
| 517 |
+
CODE:
|
| 518 |
+
fprintf(stderr, "Cool::Foo says: Perl Rules\n");
|
| 519 |
+
|
| 520 |
+
Bar.xs:
|
| 521 |
+
-------
|
| 522 |
+
#include "EXTERN.h"
|
| 523 |
+
#include "perl.h"
|
| 524 |
+
#include "XSUB.h"
|
| 525 |
+
|
| 526 |
+
MODULE = Cool::Bar PACKAGE = Cool::Bar PREFIX = cool_bar_
|
| 527 |
+
|
| 528 |
+
void
|
| 529 |
+
cool_bar_perl_rules()
|
| 530 |
+
|
| 531 |
+
CODE:
|
| 532 |
+
fprintf(stderr, "Cool::Bar says: Perl Rules\n");
|
| 533 |
+
|
| 534 |
+
And of course a very basic test:
|
| 535 |
+
|
| 536 |
+
t/cool.t:
|
| 537 |
+
--------
|
| 538 |
+
use Test;
|
| 539 |
+
BEGIN { plan tests => 1 };
|
| 540 |
+
use Cool::Foo;
|
| 541 |
+
use Cool::Bar;
|
| 542 |
+
Cool::Foo::perl_rules();
|
| 543 |
+
Cool::Bar::perl_rules();
|
| 544 |
+
ok 1;
|
| 545 |
+
|
| 546 |
+
This tip has been brought to you by Nick Ing-Simmons and Stas Bekman.
|
| 547 |
+
|
| 548 |
+
An alternative way to achieve this can be seen in L<Gtk2::CodeGen>
|
| 549 |
+
and L<Glib::CodeGen>.
|
| 550 |
+
|
| 551 |
+
=back
|
| 552 |
+
|
| 553 |
+
=back
|
| 554 |
+
|
| 555 |
+
=head1 DESIGN
|
| 556 |
+
|
| 557 |
+
=head2 MakeMaker object hierarchy (simplified)
|
| 558 |
+
|
| 559 |
+
What most people need to know (superclasses on top.)
|
| 560 |
+
|
| 561 |
+
ExtUtils::MM_Any
|
| 562 |
+
|
|
| 563 |
+
ExtUtils::MM_Unix
|
| 564 |
+
|
|
| 565 |
+
ExtUtils::MM_{Current OS}
|
| 566 |
+
|
|
| 567 |
+
ExtUtils::MakeMaker
|
| 568 |
+
|
|
| 569 |
+
MY
|
| 570 |
+
|
| 571 |
+
The object actually used is of the class MY which allows you to
|
| 572 |
+
override bits of MakeMaker inside your Makefile.PL by declaring
|
| 573 |
+
MY::foo() methods.
|
| 574 |
+
|
| 575 |
+
=head2 MakeMaker object hierarchy (real)
|
| 576 |
+
|
| 577 |
+
Here's how it really works:
|
| 578 |
+
|
| 579 |
+
ExtUtils::MM_Any
|
| 580 |
+
|
|
| 581 |
+
ExtUtils::MM_Unix
|
| 582 |
+
|
|
| 583 |
+
ExtUtils::Liblist::Kid ExtUtils::MM_{Current OS} (if necessary)
|
| 584 |
+
| |
|
| 585 |
+
ExtUtils::Liblist ExtUtils::MakeMaker |
|
| 586 |
+
| | |
|
| 587 |
+
| | |-----------------------
|
| 588 |
+
ExtUtils::MM
|
| 589 |
+
| |
|
| 590 |
+
ExtUtils::MY MM (created by ExtUtils::MM)
|
| 591 |
+
| |
|
| 592 |
+
MY (created by ExtUtils::MY) |
|
| 593 |
+
. |
|
| 594 |
+
(mixin) |
|
| 595 |
+
. |
|
| 596 |
+
PACK### (created each call to ExtUtils::MakeMaker->new)
|
| 597 |
+
|
| 598 |
+
NOTE: Yes, this is a mess. See
|
| 599 |
+
L<http://archive.develooper.com/[email protected]/msg00134.html>
|
| 600 |
+
for some history.
|
| 601 |
+
|
| 602 |
+
NOTE: When ExtUtils::MM is loaded it chooses a superclass for MM from
|
| 603 |
+
amongst the ExtUtils::MM_* modules based on the current operating
|
| 604 |
+
system.
|
| 605 |
+
|
| 606 |
+
NOTE: ExtUtils::MM_{Current OS} represents one of the ExtUtils::MM_*
|
| 607 |
+
modules except ExtUtils::MM_Any chosen based on your operating system.
|
| 608 |
+
|
| 609 |
+
NOTE: The main object used by MakeMaker is a PACK### object, *not*
|
| 610 |
+
ExtUtils::MakeMaker. It is, effectively, a subclass of MY,
|
| 611 |
+
ExtUtils::Makemaker, ExtUtils::Liblist and ExtUtils::MM_{Current OS}
|
| 612 |
+
|
| 613 |
+
NOTE: The methods in MY are simply copied into PACK### rather than
|
| 614 |
+
MY being a superclass of PACK###. I don't remember the rationale.
|
| 615 |
+
|
| 616 |
+
NOTE: ExtUtils::Liblist should be removed from the inheritance hiearchy
|
| 617 |
+
and simply be called as functions.
|
| 618 |
+
|
| 619 |
+
NOTE: Modules like File::Spec and Exporter have been omitted for clarity.
|
| 620 |
+
|
| 621 |
+
|
| 622 |
+
=head2 The MM_* hierarchy
|
| 623 |
+
|
| 624 |
+
MM_Win95 MM_NW5
|
| 625 |
+
\ /
|
| 626 |
+
MM_BeOS MM_Cygwin MM_OS2 MM_VMS MM_Win32 MM_DOS MM_UWIN
|
| 627 |
+
\ | | | / / /
|
| 628 |
+
------------------------------------------------
|
| 629 |
+
| |
|
| 630 |
+
MM_Unix |
|
| 631 |
+
| |
|
| 632 |
+
MM_Any
|
| 633 |
+
|
| 634 |
+
NOTE: Each direct MM_Unix subclass is also an MM_Any subclass. This
|
| 635 |
+
is a temporary hack because MM_Unix overrides some MM_Any methods with
|
| 636 |
+
Unix specific code. It allows the non-Unix modules to see the
|
| 637 |
+
original MM_Any implementations.
|
| 638 |
+
|
| 639 |
+
NOTE: Modules like File::Spec and Exporter have been omitted for clarity.
|
| 640 |
+
|
| 641 |
+
=head1 PATCHING
|
| 642 |
+
|
| 643 |
+
If you have a question you'd like to see added to the FAQ (whether or
|
| 644 |
+
not you have the answer) please either:
|
| 645 |
+
|
| 646 |
+
=over 2
|
| 647 |
+
|
| 648 |
+
=item * make a pull request on the MakeMaker github repository
|
| 649 |
+
|
| 650 |
+
=item * raise a issue on the MakeMaker github repository
|
| 651 |
+
|
| 652 |
+
=item * file an RT ticket
|
| 653 |
+
|
| 654 |
+
=item * email [email protected]
|
| 655 |
+
|
| 656 |
+
=back
|
| 657 |
+
|
| 658 |
+
=head1 AUTHOR
|
| 659 |
+
|
| 660 |
+
The denizens of [email protected].
|
| 661 |
+
|
| 662 |
+
=head1 SEE ALSO
|
| 663 |
+
|
| 664 |
+
L<ExtUtils::MakeMaker>
|
| 665 |
+
|
| 666 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/ParseXS/Constants.pm
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::ParseXS::Constants;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
use Symbol;
|
| 5 |
+
|
| 6 |
+
our $VERSION = '3.40';
|
| 7 |
+
|
| 8 |
+
=head1 NAME
|
| 9 |
+
|
| 10 |
+
ExtUtils::ParseXS::Constants - Initialization values for some globals
|
| 11 |
+
|
| 12 |
+
=head1 SYNOPSIS
|
| 13 |
+
|
| 14 |
+
use ExtUtils::ParseXS::Constants ();
|
| 15 |
+
|
| 16 |
+
$PrototypeRegexp = $ExtUtils::ParseXS::Constants::PrototypeRegexp;
|
| 17 |
+
|
| 18 |
+
=head1 DESCRIPTION
|
| 19 |
+
|
| 20 |
+
Initialization of certain non-subroutine variables in ExtUtils::ParseXS and some of its
|
| 21 |
+
supporting packages has been moved into this package so that those values can
|
| 22 |
+
be defined exactly once and then re-used in any package.
|
| 23 |
+
|
| 24 |
+
Nothing is exported. Use fully qualified variable names.
|
| 25 |
+
|
| 26 |
+
=cut
|
| 27 |
+
|
| 28 |
+
# FIXME: THESE ARE NOT CONSTANTS!
|
| 29 |
+
our @InitFileCode;
|
| 30 |
+
|
| 31 |
+
# Note that to reduce maintenance, $PrototypeRegexp is used
|
| 32 |
+
# by ExtUtils::Typemaps, too!
|
| 33 |
+
our $PrototypeRegexp = "[" . quotemeta('\$%&*@;[]_') . "]";
|
| 34 |
+
our @XSKeywords = qw(
|
| 35 |
+
REQUIRE BOOT CASE PREINIT INPUT INIT CODE PPCODE
|
| 36 |
+
OUTPUT CLEANUP ALIAS ATTRS PROTOTYPES PROTOTYPE
|
| 37 |
+
VERSIONCHECK INCLUDE INCLUDE_COMMAND SCOPE INTERFACE
|
| 38 |
+
INTERFACE_MACRO C_ARGS POSTCALL OVERLOAD FALLBACK
|
| 39 |
+
EXPORT_XSUB_SYMBOLS
|
| 40 |
+
);
|
| 41 |
+
|
| 42 |
+
our $XSKeywordsAlternation = join('|', @XSKeywords);
|
| 43 |
+
|
| 44 |
+
1;
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/ParseXS/CountLines.pm
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::ParseXS::CountLines;
|
| 2 |
+
use strict;
|
| 3 |
+
|
| 4 |
+
our $VERSION = '3.40';
|
| 5 |
+
|
| 6 |
+
our $SECTION_END_MARKER;
|
| 7 |
+
|
| 8 |
+
sub TIEHANDLE {
|
| 9 |
+
my ($class, $cfile, $fh) = @_;
|
| 10 |
+
$cfile =~ s/\\/\\\\/g;
|
| 11 |
+
$cfile =~ s/"/\\"/g;
|
| 12 |
+
$SECTION_END_MARKER = qq{#line --- "$cfile"};
|
| 13 |
+
|
| 14 |
+
return bless {
|
| 15 |
+
buffer => '',
|
| 16 |
+
fh => $fh,
|
| 17 |
+
line_no => 1,
|
| 18 |
+
}, $class;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
sub PRINT {
|
| 22 |
+
my $self = shift;
|
| 23 |
+
for (@_) {
|
| 24 |
+
$self->{buffer} .= $_;
|
| 25 |
+
while ($self->{buffer} =~ s/^([^\n]*\n)//) {
|
| 26 |
+
my $line = $1;
|
| 27 |
+
++$self->{line_no};
|
| 28 |
+
$line =~ s|^\#line\s+---(?=\s)|#line $self->{line_no}|;
|
| 29 |
+
print {$self->{fh}} $line;
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
sub PRINTF {
|
| 35 |
+
my $self = shift;
|
| 36 |
+
my $fmt = shift;
|
| 37 |
+
$self->PRINT(sprintf($fmt, @_));
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
sub DESTROY {
|
| 41 |
+
# Not necessary if we're careful to end with a "\n"
|
| 42 |
+
my $self = shift;
|
| 43 |
+
print {$self->{fh}} $self->{buffer};
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
sub UNTIE {
|
| 47 |
+
# This sub does nothing, but is necessary for references to be released.
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
sub end_marker {
|
| 51 |
+
return $SECTION_END_MARKER;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
1;
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/ParseXS/Eval.pm
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::ParseXS::Eval;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '3.40';
|
| 6 |
+
|
| 7 |
+
=head1 NAME
|
| 8 |
+
|
| 9 |
+
ExtUtils::ParseXS::Eval - Clean package to evaluate code in
|
| 10 |
+
|
| 11 |
+
=head1 SYNOPSIS
|
| 12 |
+
|
| 13 |
+
use ExtUtils::ParseXS::Eval;
|
| 14 |
+
my $rv = ExtUtils::ParseXS::Eval::eval_typemap_code(
|
| 15 |
+
$parsexs_obj, "some Perl code"
|
| 16 |
+
);
|
| 17 |
+
|
| 18 |
+
=head1 SUBROUTINES
|
| 19 |
+
|
| 20 |
+
=head2 $pxs->eval_output_typemap_code($typemapcode, $other_hashref)
|
| 21 |
+
|
| 22 |
+
Sets up various bits of previously global state
|
| 23 |
+
(formerly ExtUtils::ParseXS package variables)
|
| 24 |
+
for eval'ing output typemap code that may refer to these
|
| 25 |
+
variables.
|
| 26 |
+
|
| 27 |
+
Warns the contents of C<$@> if any.
|
| 28 |
+
|
| 29 |
+
Not all these variables are necessarily considered "public" wrt. use in
|
| 30 |
+
typemaps, so beware. Variables set up from the ExtUtils::ParseXS object:
|
| 31 |
+
|
| 32 |
+
$Package $ALIAS $func_name $Full_func_name $pname
|
| 33 |
+
|
| 34 |
+
Variables set up from C<$other_hashref>:
|
| 35 |
+
|
| 36 |
+
$var $type $ntype $subtype $arg
|
| 37 |
+
|
| 38 |
+
=cut
|
| 39 |
+
|
| 40 |
+
sub eval_output_typemap_code {
|
| 41 |
+
my ($_pxs, $_code, $_other) = @_;
|
| 42 |
+
|
| 43 |
+
my ($Package, $ALIAS, $func_name, $Full_func_name, $pname)
|
| 44 |
+
= @{$_pxs}{qw(Package ALIAS func_name Full_func_name pname)};
|
| 45 |
+
|
| 46 |
+
my ($var, $type, $ntype, $subtype, $arg)
|
| 47 |
+
= @{$_other}{qw(var type ntype subtype arg)};
|
| 48 |
+
|
| 49 |
+
my $rv = eval $_code;
|
| 50 |
+
warn $@ if $@;
|
| 51 |
+
return $rv;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
=head2 $pxs->eval_input_typemap_code($typemapcode, $other_hashref)
|
| 55 |
+
|
| 56 |
+
Sets up various bits of previously global state
|
| 57 |
+
(formerly ExtUtils::ParseXS package variables)
|
| 58 |
+
for eval'ing output typemap code that may refer to these
|
| 59 |
+
variables.
|
| 60 |
+
|
| 61 |
+
Warns the contents of C<$@> if any.
|
| 62 |
+
|
| 63 |
+
Not all these variables are necessarily considered "public" wrt. use in
|
| 64 |
+
typemaps, so beware. Variables set up from the ExtUtils::ParseXS object:
|
| 65 |
+
|
| 66 |
+
$Package $ALIAS $func_name $Full_func_name $pname
|
| 67 |
+
|
| 68 |
+
Variables set up from C<$other_hashref>:
|
| 69 |
+
|
| 70 |
+
$var $type $ntype $subtype $num $init $printed_name $arg $argoff
|
| 71 |
+
|
| 72 |
+
=cut
|
| 73 |
+
|
| 74 |
+
sub eval_input_typemap_code {
|
| 75 |
+
my ($_pxs, $_code, $_other) = @_;
|
| 76 |
+
|
| 77 |
+
my ($Package, $ALIAS, $func_name, $Full_func_name, $pname)
|
| 78 |
+
= @{$_pxs}{qw(Package ALIAS func_name Full_func_name pname)};
|
| 79 |
+
|
| 80 |
+
my ($var, $type, $num, $init, $printed_name, $arg, $ntype, $argoff, $subtype)
|
| 81 |
+
= @{$_other}{qw(var type num init printed_name arg ntype argoff subtype)};
|
| 82 |
+
|
| 83 |
+
my $rv = eval $_code;
|
| 84 |
+
warn $@ if $@;
|
| 85 |
+
return $rv;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
=head1 TODO
|
| 89 |
+
|
| 90 |
+
Eventually, with better documentation and possible some cleanup,
|
| 91 |
+
this could be part of C<ExtUtils::Typemaps>.
|
| 92 |
+
|
| 93 |
+
=cut
|
| 94 |
+
|
| 95 |
+
1;
|
| 96 |
+
|
| 97 |
+
# vim: ts=2 sw=2 et:
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/ParseXS/Utilities.pm
ADDED
|
@@ -0,0 +1,821 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::ParseXS::Utilities;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
use Exporter;
|
| 5 |
+
use File::Spec;
|
| 6 |
+
use ExtUtils::ParseXS::Constants ();
|
| 7 |
+
|
| 8 |
+
our $VERSION = '3.40';
|
| 9 |
+
|
| 10 |
+
our (@ISA, @EXPORT_OK);
|
| 11 |
+
@ISA = qw(Exporter);
|
| 12 |
+
@EXPORT_OK = qw(
|
| 13 |
+
standard_typemap_locations
|
| 14 |
+
trim_whitespace
|
| 15 |
+
C_string
|
| 16 |
+
valid_proto_string
|
| 17 |
+
process_typemaps
|
| 18 |
+
map_type
|
| 19 |
+
standard_XS_defs
|
| 20 |
+
assign_func_args
|
| 21 |
+
analyze_preprocessor_statements
|
| 22 |
+
set_cond
|
| 23 |
+
Warn
|
| 24 |
+
current_line_number
|
| 25 |
+
blurt
|
| 26 |
+
death
|
| 27 |
+
check_conditional_preprocessor_statements
|
| 28 |
+
escape_file_for_line_directive
|
| 29 |
+
report_typemap_failure
|
| 30 |
+
);
|
| 31 |
+
|
| 32 |
+
=head1 NAME
|
| 33 |
+
|
| 34 |
+
ExtUtils::ParseXS::Utilities - Subroutines used with ExtUtils::ParseXS
|
| 35 |
+
|
| 36 |
+
=head1 SYNOPSIS
|
| 37 |
+
|
| 38 |
+
use ExtUtils::ParseXS::Utilities qw(
|
| 39 |
+
standard_typemap_locations
|
| 40 |
+
trim_whitespace
|
| 41 |
+
C_string
|
| 42 |
+
valid_proto_string
|
| 43 |
+
process_typemaps
|
| 44 |
+
map_type
|
| 45 |
+
standard_XS_defs
|
| 46 |
+
assign_func_args
|
| 47 |
+
analyze_preprocessor_statements
|
| 48 |
+
set_cond
|
| 49 |
+
Warn
|
| 50 |
+
blurt
|
| 51 |
+
death
|
| 52 |
+
check_conditional_preprocessor_statements
|
| 53 |
+
escape_file_for_line_directive
|
| 54 |
+
report_typemap_failure
|
| 55 |
+
);
|
| 56 |
+
|
| 57 |
+
=head1 SUBROUTINES
|
| 58 |
+
|
| 59 |
+
The following functions are not considered to be part of the public interface.
|
| 60 |
+
They are documented here for the benefit of future maintainers of this module.
|
| 61 |
+
|
| 62 |
+
=head2 C<standard_typemap_locations()>
|
| 63 |
+
|
| 64 |
+
=over 4
|
| 65 |
+
|
| 66 |
+
=item * Purpose
|
| 67 |
+
|
| 68 |
+
Provide a list of filepaths where F<typemap> files may be found. The
|
| 69 |
+
filepaths -- relative paths to files (not just directory paths) -- appear in this list in lowest-to-highest priority.
|
| 70 |
+
|
| 71 |
+
The highest priority is to look in the current directory.
|
| 72 |
+
|
| 73 |
+
'typemap'
|
| 74 |
+
|
| 75 |
+
The second and third highest priorities are to look in the parent of the
|
| 76 |
+
current directory and a directory called F<lib/ExtUtils> underneath the parent
|
| 77 |
+
directory.
|
| 78 |
+
|
| 79 |
+
'../typemap',
|
| 80 |
+
'../lib/ExtUtils/typemap',
|
| 81 |
+
|
| 82 |
+
The fourth through ninth highest priorities are to look in the corresponding
|
| 83 |
+
grandparent, great-grandparent and great-great-grandparent directories.
|
| 84 |
+
|
| 85 |
+
'../../typemap',
|
| 86 |
+
'../../lib/ExtUtils/typemap',
|
| 87 |
+
'../../../typemap',
|
| 88 |
+
'../../../lib/ExtUtils/typemap',
|
| 89 |
+
'../../../../typemap',
|
| 90 |
+
'../../../../lib/ExtUtils/typemap',
|
| 91 |
+
|
| 92 |
+
The tenth and subsequent priorities are to look in directories named
|
| 93 |
+
F<ExtUtils> which are subdirectories of directories found in C<@INC> --
|
| 94 |
+
I<provided> a file named F<typemap> actually exists in such a directory.
|
| 95 |
+
Example:
|
| 96 |
+
|
| 97 |
+
'/usr/local/lib/perl5/5.10.1/ExtUtils/typemap',
|
| 98 |
+
|
| 99 |
+
However, these filepaths appear in the list returned by
|
| 100 |
+
C<standard_typemap_locations()> in reverse order, I<i.e.>, lowest-to-highest.
|
| 101 |
+
|
| 102 |
+
'/usr/local/lib/perl5/5.10.1/ExtUtils/typemap',
|
| 103 |
+
'../../../../lib/ExtUtils/typemap',
|
| 104 |
+
'../../../../typemap',
|
| 105 |
+
'../../../lib/ExtUtils/typemap',
|
| 106 |
+
'../../../typemap',
|
| 107 |
+
'../../lib/ExtUtils/typemap',
|
| 108 |
+
'../../typemap',
|
| 109 |
+
'../lib/ExtUtils/typemap',
|
| 110 |
+
'../typemap',
|
| 111 |
+
'typemap'
|
| 112 |
+
|
| 113 |
+
=item * Arguments
|
| 114 |
+
|
| 115 |
+
my @stl = standard_typemap_locations( \@INC );
|
| 116 |
+
|
| 117 |
+
Reference to C<@INC>.
|
| 118 |
+
|
| 119 |
+
=item * Return Value
|
| 120 |
+
|
| 121 |
+
Array holding list of directories to be searched for F<typemap> files.
|
| 122 |
+
|
| 123 |
+
=back
|
| 124 |
+
|
| 125 |
+
=cut
|
| 126 |
+
|
| 127 |
+
SCOPE: {
|
| 128 |
+
my @tm_template;
|
| 129 |
+
|
| 130 |
+
sub standard_typemap_locations {
|
| 131 |
+
my $include_ref = shift;
|
| 132 |
+
|
| 133 |
+
if (not @tm_template) {
|
| 134 |
+
@tm_template = qw(typemap);
|
| 135 |
+
|
| 136 |
+
my $updir = File::Spec->updir();
|
| 137 |
+
foreach my $dir (
|
| 138 |
+
File::Spec->catdir(($updir) x 1),
|
| 139 |
+
File::Spec->catdir(($updir) x 2),
|
| 140 |
+
File::Spec->catdir(($updir) x 3),
|
| 141 |
+
File::Spec->catdir(($updir) x 4),
|
| 142 |
+
) {
|
| 143 |
+
unshift @tm_template, File::Spec->catfile($dir, 'typemap');
|
| 144 |
+
unshift @tm_template, File::Spec->catfile($dir, lib => ExtUtils => 'typemap');
|
| 145 |
+
}
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
my @tm = @tm_template;
|
| 149 |
+
foreach my $dir (@{ $include_ref}) {
|
| 150 |
+
my $file = File::Spec->catfile($dir, ExtUtils => 'typemap');
|
| 151 |
+
unshift @tm, $file if -e $file;
|
| 152 |
+
}
|
| 153 |
+
return @tm;
|
| 154 |
+
}
|
| 155 |
+
} # end SCOPE
|
| 156 |
+
|
| 157 |
+
=head2 C<trim_whitespace()>
|
| 158 |
+
|
| 159 |
+
=over 4
|
| 160 |
+
|
| 161 |
+
=item * Purpose
|
| 162 |
+
|
| 163 |
+
Perform an in-place trimming of leading and trailing whitespace from the
|
| 164 |
+
first argument provided to the function.
|
| 165 |
+
|
| 166 |
+
=item * Argument
|
| 167 |
+
|
| 168 |
+
trim_whitespace($arg);
|
| 169 |
+
|
| 170 |
+
=item * Return Value
|
| 171 |
+
|
| 172 |
+
None. Remember: this is an I<in-place> modification of the argument.
|
| 173 |
+
|
| 174 |
+
=back
|
| 175 |
+
|
| 176 |
+
=cut
|
| 177 |
+
|
| 178 |
+
sub trim_whitespace {
|
| 179 |
+
$_[0] =~ s/^\s+|\s+$//go;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
=head2 C<C_string()>
|
| 183 |
+
|
| 184 |
+
=over 4
|
| 185 |
+
|
| 186 |
+
=item * Purpose
|
| 187 |
+
|
| 188 |
+
Escape backslashes (C<\>) in prototype strings.
|
| 189 |
+
|
| 190 |
+
=item * Arguments
|
| 191 |
+
|
| 192 |
+
$ProtoThisXSUB = C_string($_);
|
| 193 |
+
|
| 194 |
+
String needing escaping.
|
| 195 |
+
|
| 196 |
+
=item * Return Value
|
| 197 |
+
|
| 198 |
+
Properly escaped string.
|
| 199 |
+
|
| 200 |
+
=back
|
| 201 |
+
|
| 202 |
+
=cut
|
| 203 |
+
|
| 204 |
+
sub C_string {
|
| 205 |
+
my($string) = @_;
|
| 206 |
+
|
| 207 |
+
$string =~ s[\\][\\\\]g;
|
| 208 |
+
$string;
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
=head2 C<valid_proto_string()>
|
| 212 |
+
|
| 213 |
+
=over 4
|
| 214 |
+
|
| 215 |
+
=item * Purpose
|
| 216 |
+
|
| 217 |
+
Validate prototype string.
|
| 218 |
+
|
| 219 |
+
=item * Arguments
|
| 220 |
+
|
| 221 |
+
String needing checking.
|
| 222 |
+
|
| 223 |
+
=item * Return Value
|
| 224 |
+
|
| 225 |
+
Upon success, returns the same string passed as argument.
|
| 226 |
+
|
| 227 |
+
Upon failure, returns C<0>.
|
| 228 |
+
|
| 229 |
+
=back
|
| 230 |
+
|
| 231 |
+
=cut
|
| 232 |
+
|
| 233 |
+
sub valid_proto_string {
|
| 234 |
+
my ($string) = @_;
|
| 235 |
+
|
| 236 |
+
if ( $string =~ /^$ExtUtils::ParseXS::Constants::PrototypeRegexp+$/ ) {
|
| 237 |
+
return $string;
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
return 0;
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
=head2 C<process_typemaps()>
|
| 244 |
+
|
| 245 |
+
=over 4
|
| 246 |
+
|
| 247 |
+
=item * Purpose
|
| 248 |
+
|
| 249 |
+
Process all typemap files.
|
| 250 |
+
|
| 251 |
+
=item * Arguments
|
| 252 |
+
|
| 253 |
+
my $typemaps_object = process_typemaps( $args{typemap}, $pwd );
|
| 254 |
+
|
| 255 |
+
List of two elements: C<typemap> element from C<%args>; current working
|
| 256 |
+
directory.
|
| 257 |
+
|
| 258 |
+
=item * Return Value
|
| 259 |
+
|
| 260 |
+
Upon success, returns an L<ExtUtils::Typemaps> object.
|
| 261 |
+
|
| 262 |
+
=back
|
| 263 |
+
|
| 264 |
+
=cut
|
| 265 |
+
|
| 266 |
+
sub process_typemaps {
|
| 267 |
+
my ($tmap, $pwd) = @_;
|
| 268 |
+
|
| 269 |
+
my @tm = ref $tmap ? @{$tmap} : ($tmap);
|
| 270 |
+
|
| 271 |
+
foreach my $typemap (@tm) {
|
| 272 |
+
die "Can't find $typemap in $pwd\n" unless -r $typemap;
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
push @tm, standard_typemap_locations( \@INC );
|
| 276 |
+
|
| 277 |
+
require ExtUtils::Typemaps;
|
| 278 |
+
my $typemap = ExtUtils::Typemaps->new;
|
| 279 |
+
foreach my $typemap_loc (@tm) {
|
| 280 |
+
next unless -f $typemap_loc;
|
| 281 |
+
# skip directories, binary files etc.
|
| 282 |
+
warn("Warning: ignoring non-text typemap file '$typemap_loc'\n"), next
|
| 283 |
+
unless -T $typemap_loc;
|
| 284 |
+
|
| 285 |
+
$typemap->merge(file => $typemap_loc, replace => 1);
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
return $typemap;
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
=head2 C<map_type()>
|
| 292 |
+
|
| 293 |
+
=over 4
|
| 294 |
+
|
| 295 |
+
=item * Purpose
|
| 296 |
+
|
| 297 |
+
Performs a mapping at several places inside C<PARAGRAPH> loop.
|
| 298 |
+
|
| 299 |
+
=item * Arguments
|
| 300 |
+
|
| 301 |
+
$type = map_type($self, $type, $varname);
|
| 302 |
+
|
| 303 |
+
List of three arguments.
|
| 304 |
+
|
| 305 |
+
=item * Return Value
|
| 306 |
+
|
| 307 |
+
String holding augmented version of second argument.
|
| 308 |
+
|
| 309 |
+
=back
|
| 310 |
+
|
| 311 |
+
=cut
|
| 312 |
+
|
| 313 |
+
sub map_type {
|
| 314 |
+
my ($self, $type, $varname) = @_;
|
| 315 |
+
|
| 316 |
+
# C++ has :: in types too so skip this
|
| 317 |
+
$type =~ tr/:/_/ unless $self->{RetainCplusplusHierarchicalTypes};
|
| 318 |
+
$type =~ s/^array\(([^,]*),(.*)\).*/$1 */s;
|
| 319 |
+
if ($varname) {
|
| 320 |
+
if ($type =~ / \( \s* \* (?= \s* \) ) /xg) {
|
| 321 |
+
(substr $type, pos $type, 0) = " $varname ";
|
| 322 |
+
}
|
| 323 |
+
else {
|
| 324 |
+
$type .= "\t$varname";
|
| 325 |
+
}
|
| 326 |
+
}
|
| 327 |
+
return $type;
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
=head2 C<standard_XS_defs()>
|
| 331 |
+
|
| 332 |
+
=over 4
|
| 333 |
+
|
| 334 |
+
=item * Purpose
|
| 335 |
+
|
| 336 |
+
Writes to the C<.c> output file certain preprocessor directives and function
|
| 337 |
+
headers needed in all such files.
|
| 338 |
+
|
| 339 |
+
=item * Arguments
|
| 340 |
+
|
| 341 |
+
None.
|
| 342 |
+
|
| 343 |
+
=item * Return Value
|
| 344 |
+
|
| 345 |
+
Returns true.
|
| 346 |
+
|
| 347 |
+
=back
|
| 348 |
+
|
| 349 |
+
=cut
|
| 350 |
+
|
| 351 |
+
sub standard_XS_defs {
|
| 352 |
+
print <<"EOF";
|
| 353 |
+
#ifndef PERL_UNUSED_VAR
|
| 354 |
+
# define PERL_UNUSED_VAR(var) if (0) var = var
|
| 355 |
+
#endif
|
| 356 |
+
|
| 357 |
+
#ifndef dVAR
|
| 358 |
+
# define dVAR dNOOP
|
| 359 |
+
#endif
|
| 360 |
+
|
| 361 |
+
|
| 362 |
+
/* This stuff is not part of the API! You have been warned. */
|
| 363 |
+
#ifndef PERL_VERSION_DECIMAL
|
| 364 |
+
# define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
|
| 365 |
+
#endif
|
| 366 |
+
#ifndef PERL_DECIMAL_VERSION
|
| 367 |
+
# define PERL_DECIMAL_VERSION \\
|
| 368 |
+
PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
|
| 369 |
+
#endif
|
| 370 |
+
#ifndef PERL_VERSION_GE
|
| 371 |
+
# define PERL_VERSION_GE(r,v,s) \\
|
| 372 |
+
(PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
|
| 373 |
+
#endif
|
| 374 |
+
#ifndef PERL_VERSION_LE
|
| 375 |
+
# define PERL_VERSION_LE(r,v,s) \\
|
| 376 |
+
(PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s))
|
| 377 |
+
#endif
|
| 378 |
+
|
| 379 |
+
/* XS_INTERNAL is the explicit static-linkage variant of the default
|
| 380 |
+
* XS macro.
|
| 381 |
+
*
|
| 382 |
+
* XS_EXTERNAL is the same as XS_INTERNAL except it does not include
|
| 383 |
+
* "STATIC", ie. it exports XSUB symbols. You probably don't want that
|
| 384 |
+
* for anything but the BOOT XSUB.
|
| 385 |
+
*
|
| 386 |
+
* See XSUB.h in core!
|
| 387 |
+
*/
|
| 388 |
+
|
| 389 |
+
|
| 390 |
+
/* TODO: This might be compatible further back than 5.10.0. */
|
| 391 |
+
#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1)
|
| 392 |
+
# undef XS_EXTERNAL
|
| 393 |
+
# undef XS_INTERNAL
|
| 394 |
+
# if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
|
| 395 |
+
# define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
|
| 396 |
+
# define XS_INTERNAL(name) STATIC XSPROTO(name)
|
| 397 |
+
# endif
|
| 398 |
+
# if defined(__SYMBIAN32__)
|
| 399 |
+
# define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
|
| 400 |
+
# define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name)
|
| 401 |
+
# endif
|
| 402 |
+
# ifndef XS_EXTERNAL
|
| 403 |
+
# if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
|
| 404 |
+
# define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
|
| 405 |
+
# define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__)
|
| 406 |
+
# else
|
| 407 |
+
# ifdef __cplusplus
|
| 408 |
+
# define XS_EXTERNAL(name) extern "C" XSPROTO(name)
|
| 409 |
+
# define XS_INTERNAL(name) static XSPROTO(name)
|
| 410 |
+
# else
|
| 411 |
+
# define XS_EXTERNAL(name) XSPROTO(name)
|
| 412 |
+
# define XS_INTERNAL(name) STATIC XSPROTO(name)
|
| 413 |
+
# endif
|
| 414 |
+
# endif
|
| 415 |
+
# endif
|
| 416 |
+
#endif
|
| 417 |
+
|
| 418 |
+
/* perl >= 5.10.0 && perl <= 5.15.1 */
|
| 419 |
+
|
| 420 |
+
|
| 421 |
+
/* The XS_EXTERNAL macro is used for functions that must not be static
|
| 422 |
+
* like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL
|
| 423 |
+
* macro defined, the best we can do is assume XS is the same.
|
| 424 |
+
* Dito for XS_INTERNAL.
|
| 425 |
+
*/
|
| 426 |
+
#ifndef XS_EXTERNAL
|
| 427 |
+
# define XS_EXTERNAL(name) XS(name)
|
| 428 |
+
#endif
|
| 429 |
+
#ifndef XS_INTERNAL
|
| 430 |
+
# define XS_INTERNAL(name) XS(name)
|
| 431 |
+
#endif
|
| 432 |
+
|
| 433 |
+
/* Now, finally, after all this mess, we want an ExtUtils::ParseXS
|
| 434 |
+
* internal macro that we're free to redefine for varying linkage due
|
| 435 |
+
* to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use
|
| 436 |
+
* XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to!
|
| 437 |
+
*/
|
| 438 |
+
|
| 439 |
+
#undef XS_EUPXS
|
| 440 |
+
#if defined(PERL_EUPXS_ALWAYS_EXPORT)
|
| 441 |
+
# define XS_EUPXS(name) XS_EXTERNAL(name)
|
| 442 |
+
#else
|
| 443 |
+
/* default to internal */
|
| 444 |
+
# define XS_EUPXS(name) XS_INTERNAL(name)
|
| 445 |
+
#endif
|
| 446 |
+
|
| 447 |
+
EOF
|
| 448 |
+
|
| 449 |
+
print <<"EOF";
|
| 450 |
+
#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
|
| 451 |
+
#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)
|
| 452 |
+
|
| 453 |
+
/* prototype to pass -Wmissing-prototypes */
|
| 454 |
+
STATIC void
|
| 455 |
+
S_croak_xs_usage(const CV *const cv, const char *const params);
|
| 456 |
+
|
| 457 |
+
STATIC void
|
| 458 |
+
S_croak_xs_usage(const CV *const cv, const char *const params)
|
| 459 |
+
{
|
| 460 |
+
const GV *const gv = CvGV(cv);
|
| 461 |
+
|
| 462 |
+
PERL_ARGS_ASSERT_CROAK_XS_USAGE;
|
| 463 |
+
|
| 464 |
+
if (gv) {
|
| 465 |
+
const char *const gvname = GvNAME(gv);
|
| 466 |
+
const HV *const stash = GvSTASH(gv);
|
| 467 |
+
const char *const hvname = stash ? HvNAME(stash) : NULL;
|
| 468 |
+
|
| 469 |
+
if (hvname)
|
| 470 |
+
Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
|
| 471 |
+
else
|
| 472 |
+
Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
|
| 473 |
+
} else {
|
| 474 |
+
/* Pants. I don't think that it should be possible to get here. */
|
| 475 |
+
Perl_croak_nocontext("Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
|
| 476 |
+
}
|
| 477 |
+
}
|
| 478 |
+
#undef PERL_ARGS_ASSERT_CROAK_XS_USAGE
|
| 479 |
+
|
| 480 |
+
#define croak_xs_usage S_croak_xs_usage
|
| 481 |
+
|
| 482 |
+
#endif
|
| 483 |
+
|
| 484 |
+
/* NOTE: the prototype of newXSproto() is different in versions of perls,
|
| 485 |
+
* so we define a portable version of newXSproto()
|
| 486 |
+
*/
|
| 487 |
+
#ifdef newXS_flags
|
| 488 |
+
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
|
| 489 |
+
#else
|
| 490 |
+
#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
|
| 491 |
+
#endif /* !defined(newXS_flags) */
|
| 492 |
+
|
| 493 |
+
#if PERL_VERSION_LE(5, 21, 5)
|
| 494 |
+
# define newXS_deffile(a,b) Perl_newXS(aTHX_ a,b,file)
|
| 495 |
+
#else
|
| 496 |
+
# define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b)
|
| 497 |
+
#endif
|
| 498 |
+
|
| 499 |
+
EOF
|
| 500 |
+
return 1;
|
| 501 |
+
}
|
| 502 |
+
|
| 503 |
+
=head2 C<assign_func_args()>
|
| 504 |
+
|
| 505 |
+
=over 4
|
| 506 |
+
|
| 507 |
+
=item * Purpose
|
| 508 |
+
|
| 509 |
+
Perform assignment to the C<func_args> attribute.
|
| 510 |
+
|
| 511 |
+
=item * Arguments
|
| 512 |
+
|
| 513 |
+
$string = assign_func_args($self, $argsref, $class);
|
| 514 |
+
|
| 515 |
+
List of three elements. Second is an array reference; third is a string.
|
| 516 |
+
|
| 517 |
+
=item * Return Value
|
| 518 |
+
|
| 519 |
+
String.
|
| 520 |
+
|
| 521 |
+
=back
|
| 522 |
+
|
| 523 |
+
=cut
|
| 524 |
+
|
| 525 |
+
sub assign_func_args {
|
| 526 |
+
my ($self, $argsref, $class) = @_;
|
| 527 |
+
my @func_args = @{$argsref};
|
| 528 |
+
shift @func_args if defined($class);
|
| 529 |
+
|
| 530 |
+
for my $arg (@func_args) {
|
| 531 |
+
$arg =~ s/^/&/ if $self->{in_out}->{$arg};
|
| 532 |
+
}
|
| 533 |
+
return join(", ", @func_args);
|
| 534 |
+
}
|
| 535 |
+
|
| 536 |
+
=head2 C<analyze_preprocessor_statements()>
|
| 537 |
+
|
| 538 |
+
=over 4
|
| 539 |
+
|
| 540 |
+
=item * Purpose
|
| 541 |
+
|
| 542 |
+
Within each function inside each Xsub, print to the F<.c> output file certain
|
| 543 |
+
preprocessor statements.
|
| 544 |
+
|
| 545 |
+
=item * Arguments
|
| 546 |
+
|
| 547 |
+
( $self, $XSS_work_idx, $BootCode_ref ) =
|
| 548 |
+
analyze_preprocessor_statements(
|
| 549 |
+
$self, $statement, $XSS_work_idx, $BootCode_ref
|
| 550 |
+
);
|
| 551 |
+
|
| 552 |
+
List of four elements.
|
| 553 |
+
|
| 554 |
+
=item * Return Value
|
| 555 |
+
|
| 556 |
+
Modifed values of three of the arguments passed to the function. In
|
| 557 |
+
particular, the C<XSStack> and C<InitFileCode> attributes are modified.
|
| 558 |
+
|
| 559 |
+
=back
|
| 560 |
+
|
| 561 |
+
=cut
|
| 562 |
+
|
| 563 |
+
sub analyze_preprocessor_statements {
|
| 564 |
+
my ($self, $statement, $XSS_work_idx, $BootCode_ref) = @_;
|
| 565 |
+
|
| 566 |
+
if ($statement eq 'if') {
|
| 567 |
+
$XSS_work_idx = @{ $self->{XSStack} };
|
| 568 |
+
push(@{ $self->{XSStack} }, {type => 'if'});
|
| 569 |
+
}
|
| 570 |
+
else {
|
| 571 |
+
$self->death("Error: '$statement' with no matching 'if'")
|
| 572 |
+
if $self->{XSStack}->[-1]{type} ne 'if';
|
| 573 |
+
if ($self->{XSStack}->[-1]{varname}) {
|
| 574 |
+
push(@{ $self->{InitFileCode} }, "#endif\n");
|
| 575 |
+
push(@{ $BootCode_ref }, "#endif");
|
| 576 |
+
}
|
| 577 |
+
|
| 578 |
+
my(@fns) = keys %{$self->{XSStack}->[-1]{functions}};
|
| 579 |
+
if ($statement ne 'endif') {
|
| 580 |
+
# Hide the functions defined in other #if branches, and reset.
|
| 581 |
+
@{$self->{XSStack}->[-1]{other_functions}}{@fns} = (1) x @fns;
|
| 582 |
+
@{$self->{XSStack}->[-1]}{qw(varname functions)} = ('', {});
|
| 583 |
+
}
|
| 584 |
+
else {
|
| 585 |
+
my($tmp) = pop(@{ $self->{XSStack} });
|
| 586 |
+
0 while (--$XSS_work_idx
|
| 587 |
+
&& $self->{XSStack}->[$XSS_work_idx]{type} ne 'if');
|
| 588 |
+
# Keep all new defined functions
|
| 589 |
+
push(@fns, keys %{$tmp->{other_functions}});
|
| 590 |
+
@{$self->{XSStack}->[$XSS_work_idx]{functions}}{@fns} = (1) x @fns;
|
| 591 |
+
}
|
| 592 |
+
}
|
| 593 |
+
return ($self, $XSS_work_idx, $BootCode_ref);
|
| 594 |
+
}
|
| 595 |
+
|
| 596 |
+
=head2 C<set_cond()>
|
| 597 |
+
|
| 598 |
+
=over 4
|
| 599 |
+
|
| 600 |
+
=item * Purpose
|
| 601 |
+
|
| 602 |
+
=item * Arguments
|
| 603 |
+
|
| 604 |
+
=item * Return Value
|
| 605 |
+
|
| 606 |
+
=back
|
| 607 |
+
|
| 608 |
+
=cut
|
| 609 |
+
|
| 610 |
+
sub set_cond {
|
| 611 |
+
my ($ellipsis, $min_args, $num_args) = @_;
|
| 612 |
+
my $cond;
|
| 613 |
+
if ($ellipsis) {
|
| 614 |
+
$cond = ($min_args ? qq(items < $min_args) : 0);
|
| 615 |
+
}
|
| 616 |
+
elsif ($min_args == $num_args) {
|
| 617 |
+
$cond = qq(items != $min_args);
|
| 618 |
+
}
|
| 619 |
+
else {
|
| 620 |
+
$cond = qq(items < $min_args || items > $num_args);
|
| 621 |
+
}
|
| 622 |
+
return $cond;
|
| 623 |
+
}
|
| 624 |
+
|
| 625 |
+
=head2 C<current_line_number()>
|
| 626 |
+
|
| 627 |
+
=over 4
|
| 628 |
+
|
| 629 |
+
=item * Purpose
|
| 630 |
+
|
| 631 |
+
Figures out the current line number in the XS file.
|
| 632 |
+
|
| 633 |
+
=item * Arguments
|
| 634 |
+
|
| 635 |
+
C<$self>
|
| 636 |
+
|
| 637 |
+
=item * Return Value
|
| 638 |
+
|
| 639 |
+
The current line number.
|
| 640 |
+
|
| 641 |
+
=back
|
| 642 |
+
|
| 643 |
+
=cut
|
| 644 |
+
|
| 645 |
+
sub current_line_number {
|
| 646 |
+
my $self = shift;
|
| 647 |
+
my $line_number = $self->{line_no}->[@{ $self->{line_no} } - @{ $self->{line} } -1];
|
| 648 |
+
return $line_number;
|
| 649 |
+
}
|
| 650 |
+
|
| 651 |
+
=head2 C<Warn()>
|
| 652 |
+
|
| 653 |
+
=over 4
|
| 654 |
+
|
| 655 |
+
=item * Purpose
|
| 656 |
+
|
| 657 |
+
=item * Arguments
|
| 658 |
+
|
| 659 |
+
=item * Return Value
|
| 660 |
+
|
| 661 |
+
=back
|
| 662 |
+
|
| 663 |
+
=cut
|
| 664 |
+
|
| 665 |
+
sub Warn {
|
| 666 |
+
my $self = shift;
|
| 667 |
+
my $warn_line_number = $self->current_line_number();
|
| 668 |
+
print STDERR "@_ in $self->{filename}, line $warn_line_number\n";
|
| 669 |
+
}
|
| 670 |
+
|
| 671 |
+
=head2 C<blurt()>
|
| 672 |
+
|
| 673 |
+
=over 4
|
| 674 |
+
|
| 675 |
+
=item * Purpose
|
| 676 |
+
|
| 677 |
+
=item * Arguments
|
| 678 |
+
|
| 679 |
+
=item * Return Value
|
| 680 |
+
|
| 681 |
+
=back
|
| 682 |
+
|
| 683 |
+
=cut
|
| 684 |
+
|
| 685 |
+
sub blurt {
|
| 686 |
+
my $self = shift;
|
| 687 |
+
$self->Warn(@_);
|
| 688 |
+
$self->{errors}++
|
| 689 |
+
}
|
| 690 |
+
|
| 691 |
+
=head2 C<death()>
|
| 692 |
+
|
| 693 |
+
=over 4
|
| 694 |
+
|
| 695 |
+
=item * Purpose
|
| 696 |
+
|
| 697 |
+
=item * Arguments
|
| 698 |
+
|
| 699 |
+
=item * Return Value
|
| 700 |
+
|
| 701 |
+
=back
|
| 702 |
+
|
| 703 |
+
=cut
|
| 704 |
+
|
| 705 |
+
sub death {
|
| 706 |
+
my $self = shift;
|
| 707 |
+
$self->Warn(@_);
|
| 708 |
+
exit 1;
|
| 709 |
+
}
|
| 710 |
+
|
| 711 |
+
=head2 C<check_conditional_preprocessor_statements()>
|
| 712 |
+
|
| 713 |
+
=over 4
|
| 714 |
+
|
| 715 |
+
=item * Purpose
|
| 716 |
+
|
| 717 |
+
=item * Arguments
|
| 718 |
+
|
| 719 |
+
=item * Return Value
|
| 720 |
+
|
| 721 |
+
=back
|
| 722 |
+
|
| 723 |
+
=cut
|
| 724 |
+
|
| 725 |
+
sub check_conditional_preprocessor_statements {
|
| 726 |
+
my ($self) = @_;
|
| 727 |
+
my @cpp = grep(/^\#\s*(?:if|e\w+)/, @{ $self->{line} });
|
| 728 |
+
if (@cpp) {
|
| 729 |
+
my $cpplevel;
|
| 730 |
+
for my $cpp (@cpp) {
|
| 731 |
+
if ($cpp =~ /^\#\s*if/) {
|
| 732 |
+
$cpplevel++;
|
| 733 |
+
}
|
| 734 |
+
elsif (!$cpplevel) {
|
| 735 |
+
$self->Warn("Warning: #else/elif/endif without #if in this function");
|
| 736 |
+
print STDERR " (precede it with a blank line if the matching #if is outside the function)\n"
|
| 737 |
+
if $self->{XSStack}->[-1]{type} eq 'if';
|
| 738 |
+
return;
|
| 739 |
+
}
|
| 740 |
+
elsif ($cpp =~ /^\#\s*endif/) {
|
| 741 |
+
$cpplevel--;
|
| 742 |
+
}
|
| 743 |
+
}
|
| 744 |
+
$self->Warn("Warning: #if without #endif in this function") if $cpplevel;
|
| 745 |
+
}
|
| 746 |
+
}
|
| 747 |
+
|
| 748 |
+
=head2 C<escape_file_for_line_directive()>
|
| 749 |
+
|
| 750 |
+
=over 4
|
| 751 |
+
|
| 752 |
+
=item * Purpose
|
| 753 |
+
|
| 754 |
+
Escapes a given code source name (typically a file name but can also
|
| 755 |
+
be a command that was read from) so that double-quotes and backslashes are escaped.
|
| 756 |
+
|
| 757 |
+
=item * Arguments
|
| 758 |
+
|
| 759 |
+
A string.
|
| 760 |
+
|
| 761 |
+
=item * Return Value
|
| 762 |
+
|
| 763 |
+
A string with escapes for double-quotes and backslashes.
|
| 764 |
+
|
| 765 |
+
=back
|
| 766 |
+
|
| 767 |
+
=cut
|
| 768 |
+
|
| 769 |
+
sub escape_file_for_line_directive {
|
| 770 |
+
my $string = shift;
|
| 771 |
+
$string =~ s/\\/\\\\/g;
|
| 772 |
+
$string =~ s/"/\\"/g;
|
| 773 |
+
return $string;
|
| 774 |
+
}
|
| 775 |
+
|
| 776 |
+
=head2 C<report_typemap_failure>
|
| 777 |
+
|
| 778 |
+
=over 4
|
| 779 |
+
|
| 780 |
+
=item * Purpose
|
| 781 |
+
|
| 782 |
+
Do error reporting for missing typemaps.
|
| 783 |
+
|
| 784 |
+
=item * Arguments
|
| 785 |
+
|
| 786 |
+
The C<ExtUtils::ParseXS> object.
|
| 787 |
+
|
| 788 |
+
An C<ExtUtils::Typemaps> object.
|
| 789 |
+
|
| 790 |
+
The string that represents the C type that was not found in the typemap.
|
| 791 |
+
|
| 792 |
+
Optionally, the string C<death> or C<blurt> to choose
|
| 793 |
+
whether the error is immediately fatal or not. Default: C<blurt>
|
| 794 |
+
|
| 795 |
+
=item * Return Value
|
| 796 |
+
|
| 797 |
+
Returns nothing. Depending on the arguments, this
|
| 798 |
+
may call C<death> or C<blurt>, the former of which is
|
| 799 |
+
fatal.
|
| 800 |
+
|
| 801 |
+
=back
|
| 802 |
+
|
| 803 |
+
=cut
|
| 804 |
+
|
| 805 |
+
sub report_typemap_failure {
|
| 806 |
+
my ($self, $tm, $ctype, $error_method) = @_;
|
| 807 |
+
$error_method ||= 'blurt';
|
| 808 |
+
|
| 809 |
+
my @avail_ctypes = $tm->list_mapped_ctypes;
|
| 810 |
+
|
| 811 |
+
my $err = "Could not find a typemap for C type '$ctype'.\n"
|
| 812 |
+
. "The following C types are mapped by the current typemap:\n'"
|
| 813 |
+
. join("', '", @avail_ctypes) . "'\n";
|
| 814 |
+
|
| 815 |
+
$self->$error_method($err);
|
| 816 |
+
return();
|
| 817 |
+
}
|
| 818 |
+
|
| 819 |
+
1;
|
| 820 |
+
|
| 821 |
+
# vim: ts=2 sw=2 et:
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Typemaps/Cmd.pm
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::Typemaps::Cmd;
|
| 2 |
+
use 5.006001;
|
| 3 |
+
use strict;
|
| 4 |
+
use warnings;
|
| 5 |
+
our $VERSION = '3.38';
|
| 6 |
+
|
| 7 |
+
use ExtUtils::Typemaps;
|
| 8 |
+
|
| 9 |
+
require Exporter;
|
| 10 |
+
|
| 11 |
+
our @ISA = qw(Exporter);
|
| 12 |
+
our @EXPORT = qw(embeddable_typemap);
|
| 13 |
+
our %EXPORT_TAGS = (all => \@EXPORT);
|
| 14 |
+
|
| 15 |
+
sub embeddable_typemap {
|
| 16 |
+
my @tms = @_;
|
| 17 |
+
|
| 18 |
+
# Get typemap objects
|
| 19 |
+
my @tm_objs = map [$_, _intuit_typemap_source($_)], @tms;
|
| 20 |
+
|
| 21 |
+
# merge or short-circuit
|
| 22 |
+
my $final_tm;
|
| 23 |
+
if (@tm_objs == 1) {
|
| 24 |
+
# just one, merge would be pointless
|
| 25 |
+
$final_tm = shift(@tm_objs)->[1];
|
| 26 |
+
}
|
| 27 |
+
else {
|
| 28 |
+
# multiple, need merge
|
| 29 |
+
$final_tm = ExtUtils::Typemaps->new;
|
| 30 |
+
foreach my $other_tm (@tm_objs) {
|
| 31 |
+
my ($tm_ident, $tm_obj) = @$other_tm;
|
| 32 |
+
eval {
|
| 33 |
+
$final_tm->merge(typemap => $tm_obj);
|
| 34 |
+
1
|
| 35 |
+
} or do {
|
| 36 |
+
my $err = $@ || 'Zombie error';
|
| 37 |
+
die "Failed to merge typ";
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
# stringify for embedding
|
| 43 |
+
return $final_tm->as_embedded_typemap();
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
sub _load_module {
|
| 47 |
+
my $name = shift;
|
| 48 |
+
return eval "require $name; 1";
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
SCOPE: {
|
| 52 |
+
my %sources = (
|
| 53 |
+
module => sub {
|
| 54 |
+
my $ident = shift;
|
| 55 |
+
my $tm;
|
| 56 |
+
if (/::/) { # looks like FQ module name, try that first
|
| 57 |
+
foreach my $module ($ident, "ExtUtils::Typemaps::$ident") {
|
| 58 |
+
if (_load_module($module)) {
|
| 59 |
+
eval { $tm = $module->new }
|
| 60 |
+
and return $tm;
|
| 61 |
+
}
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
else {
|
| 65 |
+
foreach my $module ("ExtUtils::Typemaps::$ident", "$ident") {
|
| 66 |
+
if (_load_module($module)) {
|
| 67 |
+
eval { $tm = $module->new }
|
| 68 |
+
and return $tm;
|
| 69 |
+
}
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
return();
|
| 73 |
+
},
|
| 74 |
+
file => sub {
|
| 75 |
+
my $ident = shift;
|
| 76 |
+
return unless -e $ident and -r _;
|
| 77 |
+
return ExtUtils::Typemaps->new(file => $ident);
|
| 78 |
+
},
|
| 79 |
+
);
|
| 80 |
+
# Try to find typemap either from module or file
|
| 81 |
+
sub _intuit_typemap_source {
|
| 82 |
+
my $identifier = shift;
|
| 83 |
+
|
| 84 |
+
my @locate_attempts;
|
| 85 |
+
if ($identifier =~ /::/ || $identifier !~ /[^\w_]/) {
|
| 86 |
+
@locate_attempts = qw(module file);
|
| 87 |
+
}
|
| 88 |
+
else {
|
| 89 |
+
@locate_attempts = qw(file module);
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
foreach my $source (@locate_attempts) {
|
| 93 |
+
my $tm = $sources{$source}->($identifier);
|
| 94 |
+
return $tm if defined $tm;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
die "Unable to find typemap for '$identifier': "
|
| 98 |
+
. "Tried to load both as file or module and failed.\n";
|
| 99 |
+
}
|
| 100 |
+
} # end SCOPE
|
| 101 |
+
|
| 102 |
+
=head1 NAME
|
| 103 |
+
|
| 104 |
+
ExtUtils::Typemaps::Cmd - Quick commands for handling typemaps
|
| 105 |
+
|
| 106 |
+
=head1 SYNOPSIS
|
| 107 |
+
|
| 108 |
+
From XS:
|
| 109 |
+
|
| 110 |
+
INCLUDE_COMMAND: $^X -MExtUtils::Typemaps::Cmd \
|
| 111 |
+
-e "print embeddable_typemap(q{Excommunicated})"
|
| 112 |
+
|
| 113 |
+
Loads C<ExtUtils::Typemaps::Excommunicated>, instantiates an object,
|
| 114 |
+
and dumps it as an embeddable typemap for use directly in your XS file.
|
| 115 |
+
|
| 116 |
+
=head1 DESCRIPTION
|
| 117 |
+
|
| 118 |
+
This is a helper module for L<ExtUtils::Typemaps> for quick
|
| 119 |
+
one-liners, specifically for inclusion of shared typemaps
|
| 120 |
+
that live on CPAN into an XS file (see SYNOPSIS).
|
| 121 |
+
|
| 122 |
+
For this reason, the following functions are exported by default:
|
| 123 |
+
|
| 124 |
+
=head1 EXPORTED FUNCTIONS
|
| 125 |
+
|
| 126 |
+
=head2 embeddable_typemap
|
| 127 |
+
|
| 128 |
+
Given a list of identifiers, C<embeddable_typemap>
|
| 129 |
+
tries to load typemaps from a file of the given name(s),
|
| 130 |
+
or from a module that is an C<ExtUtils::Typemaps> subclass.
|
| 131 |
+
|
| 132 |
+
Returns a string representation of the merged typemaps that can
|
| 133 |
+
be included verbatim into XS. Example:
|
| 134 |
+
|
| 135 |
+
print embeddable_typemap(
|
| 136 |
+
"Excommunicated", "ExtUtils::Typemaps::Basic", "./typemap"
|
| 137 |
+
);
|
| 138 |
+
|
| 139 |
+
This will try to load a module C<ExtUtils::Typemaps::Excommunicated>
|
| 140 |
+
and use it as an C<ExtUtils::Typemaps> subclass. If that fails, it'll
|
| 141 |
+
try loading C<Excommunicated> as a module, if that fails, it'll try to
|
| 142 |
+
read a file called F<Excommunicated>. It'll work similarly for the
|
| 143 |
+
second argument, but the third will be loaded as a file first.
|
| 144 |
+
|
| 145 |
+
After loading all typemap files or modules, it will merge them in the
|
| 146 |
+
specified order and dump the result as an embeddable typemap.
|
| 147 |
+
|
| 148 |
+
=head1 SEE ALSO
|
| 149 |
+
|
| 150 |
+
L<ExtUtils::Typemaps>
|
| 151 |
+
|
| 152 |
+
L<perlxs>
|
| 153 |
+
|
| 154 |
+
=head1 AUTHOR
|
| 155 |
+
|
| 156 |
+
Steffen Mueller C<<[email protected]>>
|
| 157 |
+
|
| 158 |
+
=head1 COPYRIGHT & LICENSE
|
| 159 |
+
|
| 160 |
+
Copyright 2012 Steffen Mueller
|
| 161 |
+
|
| 162 |
+
This program is free software; you can redistribute it and/or
|
| 163 |
+
modify it under the same terms as Perl itself.
|
| 164 |
+
|
| 165 |
+
=cut
|
| 166 |
+
|
| 167 |
+
1;
|
| 168 |
+
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Typemaps/InputMap.pm
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::Typemaps::InputMap;
|
| 2 |
+
use 5.006001;
|
| 3 |
+
use strict;
|
| 4 |
+
use warnings;
|
| 5 |
+
our $VERSION = '3.38';
|
| 6 |
+
|
| 7 |
+
=head1 NAME
|
| 8 |
+
|
| 9 |
+
ExtUtils::Typemaps::InputMap - Entry in the INPUT section of a typemap
|
| 10 |
+
|
| 11 |
+
=head1 SYNOPSIS
|
| 12 |
+
|
| 13 |
+
use ExtUtils::Typemaps;
|
| 14 |
+
...
|
| 15 |
+
my $input = $typemap->get_input_map('T_NV');
|
| 16 |
+
my $code = $input->code();
|
| 17 |
+
$input->code("...");
|
| 18 |
+
|
| 19 |
+
=head1 DESCRIPTION
|
| 20 |
+
|
| 21 |
+
Refer to L<ExtUtils::Typemaps> for details.
|
| 22 |
+
|
| 23 |
+
=head1 METHODS
|
| 24 |
+
|
| 25 |
+
=cut
|
| 26 |
+
|
| 27 |
+
=head2 new
|
| 28 |
+
|
| 29 |
+
Requires C<xstype> and C<code> parameters.
|
| 30 |
+
|
| 31 |
+
=cut
|
| 32 |
+
|
| 33 |
+
sub new {
|
| 34 |
+
my $prot = shift;
|
| 35 |
+
my $class = ref($prot)||$prot;
|
| 36 |
+
my %args = @_;
|
| 37 |
+
|
| 38 |
+
if (!ref($prot)) {
|
| 39 |
+
if (not defined $args{xstype} or not defined $args{code}) {
|
| 40 |
+
die("Need xstype and code parameters");
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
my $self = bless(
|
| 45 |
+
(ref($prot) ? {%$prot} : {})
|
| 46 |
+
=> $class
|
| 47 |
+
);
|
| 48 |
+
|
| 49 |
+
$self->{xstype} = $args{xstype} if defined $args{xstype};
|
| 50 |
+
$self->{code} = $args{code} if defined $args{code};
|
| 51 |
+
$self->{code} =~ s/^(?=\S)/\t/mg;
|
| 52 |
+
|
| 53 |
+
return $self;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
=head2 code
|
| 57 |
+
|
| 58 |
+
Returns or sets the INPUT mapping code for this entry.
|
| 59 |
+
|
| 60 |
+
=cut
|
| 61 |
+
|
| 62 |
+
sub code {
|
| 63 |
+
$_[0]->{code} = $_[1] if @_ > 1;
|
| 64 |
+
return $_[0]->{code};
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
=head2 xstype
|
| 68 |
+
|
| 69 |
+
Returns the name of the XS type of the INPUT map.
|
| 70 |
+
|
| 71 |
+
=cut
|
| 72 |
+
|
| 73 |
+
sub xstype {
|
| 74 |
+
return $_[0]->{xstype};
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
=head2 cleaned_code
|
| 78 |
+
|
| 79 |
+
Returns a cleaned-up copy of the code to which certain transformations
|
| 80 |
+
have been applied to make it more ANSI compliant.
|
| 81 |
+
|
| 82 |
+
=cut
|
| 83 |
+
|
| 84 |
+
sub cleaned_code {
|
| 85 |
+
my $self = shift;
|
| 86 |
+
my $code = $self->code;
|
| 87 |
+
|
| 88 |
+
$code =~ s/(?:;+\s*|;*\s+)\z//s;
|
| 89 |
+
|
| 90 |
+
# Move C pre-processor instructions to column 1 to be strictly ANSI
|
| 91 |
+
# conformant. Some pre-processors are fussy about this.
|
| 92 |
+
$code =~ s/^\s+#/#/mg;
|
| 93 |
+
$code =~ s/\s*\z/\n/;
|
| 94 |
+
|
| 95 |
+
return $code;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
=head1 SEE ALSO
|
| 99 |
+
|
| 100 |
+
L<ExtUtils::Typemaps>
|
| 101 |
+
|
| 102 |
+
=head1 AUTHOR
|
| 103 |
+
|
| 104 |
+
Steffen Mueller C<<[email protected]>>
|
| 105 |
+
|
| 106 |
+
=head1 COPYRIGHT & LICENSE
|
| 107 |
+
|
| 108 |
+
Copyright 2009, 2010, 2011, 2012 Steffen Mueller
|
| 109 |
+
|
| 110 |
+
This program is free software; you can redistribute it and/or
|
| 111 |
+
modify it under the same terms as Perl itself.
|
| 112 |
+
|
| 113 |
+
=cut
|
| 114 |
+
|
| 115 |
+
1;
|
| 116 |
+
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Typemaps/OutputMap.pm
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::Typemaps::OutputMap;
|
| 2 |
+
use 5.006001;
|
| 3 |
+
use strict;
|
| 4 |
+
use warnings;
|
| 5 |
+
our $VERSION = '3.38';
|
| 6 |
+
|
| 7 |
+
=head1 NAME
|
| 8 |
+
|
| 9 |
+
ExtUtils::Typemaps::OutputMap - Entry in the OUTPUT section of a typemap
|
| 10 |
+
|
| 11 |
+
=head1 SYNOPSIS
|
| 12 |
+
|
| 13 |
+
use ExtUtils::Typemaps;
|
| 14 |
+
...
|
| 15 |
+
my $output = $typemap->get_output_map('T_NV');
|
| 16 |
+
my $code = $output->code();
|
| 17 |
+
$output->code("...");
|
| 18 |
+
|
| 19 |
+
=head1 DESCRIPTION
|
| 20 |
+
|
| 21 |
+
Refer to L<ExtUtils::Typemaps> for details.
|
| 22 |
+
|
| 23 |
+
=head1 METHODS
|
| 24 |
+
|
| 25 |
+
=cut
|
| 26 |
+
|
| 27 |
+
=head2 new
|
| 28 |
+
|
| 29 |
+
Requires C<xstype> and C<code> parameters.
|
| 30 |
+
|
| 31 |
+
=cut
|
| 32 |
+
|
| 33 |
+
sub new {
|
| 34 |
+
my $prot = shift;
|
| 35 |
+
my $class = ref($prot)||$prot;
|
| 36 |
+
my %args = @_;
|
| 37 |
+
|
| 38 |
+
if (!ref($prot)) {
|
| 39 |
+
if (not defined $args{xstype} or not defined $args{code}) {
|
| 40 |
+
die("Need xstype and code parameters");
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
my $self = bless(
|
| 45 |
+
(ref($prot) ? {%$prot} : {})
|
| 46 |
+
=> $class
|
| 47 |
+
);
|
| 48 |
+
|
| 49 |
+
$self->{xstype} = $args{xstype} if defined $args{xstype};
|
| 50 |
+
$self->{code} = $args{code} if defined $args{code};
|
| 51 |
+
$self->{code} =~ s/^(?=\S)/\t/mg;
|
| 52 |
+
|
| 53 |
+
return $self;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
=head2 code
|
| 57 |
+
|
| 58 |
+
Returns or sets the OUTPUT mapping code for this entry.
|
| 59 |
+
|
| 60 |
+
=cut
|
| 61 |
+
|
| 62 |
+
sub code {
|
| 63 |
+
$_[0]->{code} = $_[1] if @_ > 1;
|
| 64 |
+
return $_[0]->{code};
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
=head2 xstype
|
| 68 |
+
|
| 69 |
+
Returns the name of the XS type of the OUTPUT map.
|
| 70 |
+
|
| 71 |
+
=cut
|
| 72 |
+
|
| 73 |
+
sub xstype {
|
| 74 |
+
return $_[0]->{xstype};
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
=head2 cleaned_code
|
| 78 |
+
|
| 79 |
+
Returns a cleaned-up copy of the code to which certain transformations
|
| 80 |
+
have been applied to make it more ANSI compliant.
|
| 81 |
+
|
| 82 |
+
=cut
|
| 83 |
+
|
| 84 |
+
sub cleaned_code {
|
| 85 |
+
my $self = shift;
|
| 86 |
+
my $code = $self->code;
|
| 87 |
+
|
| 88 |
+
# Move C pre-processor instructions to column 1 to be strictly ANSI
|
| 89 |
+
# conformant. Some pre-processors are fussy about this.
|
| 90 |
+
$code =~ s/^\s+#/#/mg;
|
| 91 |
+
$code =~ s/\s*\z/\n/;
|
| 92 |
+
|
| 93 |
+
return $code;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
=head2 targetable
|
| 97 |
+
|
| 98 |
+
This is an obscure but effective optimization that used to
|
| 99 |
+
live in C<ExtUtils::ParseXS> directly. Not implementing it
|
| 100 |
+
should never result in incorrect use of typemaps, just less
|
| 101 |
+
efficient code.
|
| 102 |
+
|
| 103 |
+
In a nutshell, this will check whether the output code
|
| 104 |
+
involves calling C<sv_setiv>, C<sv_setuv>, C<sv_setnv>, C<sv_setpv> or
|
| 105 |
+
C<sv_setpvn> to set the special C<$arg> placeholder to a new value
|
| 106 |
+
B<AT THE END OF THE OUTPUT CODE>. If that is the case, the code is
|
| 107 |
+
eligible for using the C<TARG>-related macros to optimize this.
|
| 108 |
+
Thus the name of the method: C<targetable>.
|
| 109 |
+
|
| 110 |
+
If this optimization is applicable, C<ExtUtils::ParseXS> will
|
| 111 |
+
emit a C<dXSTARG;> definition at the start of the generated XSUB code,
|
| 112 |
+
and type (see below) dependent code to set C<TARG> and push it on
|
| 113 |
+
the stack at the end of the generated XSUB code.
|
| 114 |
+
|
| 115 |
+
If the optimization can not be applied, this returns undef.
|
| 116 |
+
If it can be applied, this method returns a hash reference containing
|
| 117 |
+
the following information:
|
| 118 |
+
|
| 119 |
+
type: Any of the characters i, u, n, p
|
| 120 |
+
with_size: Bool indicating whether this is the sv_setpvn variant
|
| 121 |
+
what: The code that actually evaluates to the output scalar
|
| 122 |
+
what_size: If "with_size", this has the string length (as code,
|
| 123 |
+
not constant, including leading comma)
|
| 124 |
+
|
| 125 |
+
=cut
|
| 126 |
+
|
| 127 |
+
sub targetable {
|
| 128 |
+
my $self = shift;
|
| 129 |
+
return $self->{targetable} if exists $self->{targetable};
|
| 130 |
+
|
| 131 |
+
our $bal; # ()-balanced
|
| 132 |
+
$bal = qr[
|
| 133 |
+
(?:
|
| 134 |
+
(?>[^()]+)
|
| 135 |
+
|
|
| 136 |
+
\( (??{ $bal }) \)
|
| 137 |
+
)*
|
| 138 |
+
]x;
|
| 139 |
+
my $bal_no_comma = qr[
|
| 140 |
+
(?:
|
| 141 |
+
(?>[^(),]+)
|
| 142 |
+
|
|
| 143 |
+
\( (??{ $bal }) \)
|
| 144 |
+
)+
|
| 145 |
+
]x;
|
| 146 |
+
|
| 147 |
+
# matches variations on (SV*)
|
| 148 |
+
my $sv_cast = qr[
|
| 149 |
+
(?:
|
| 150 |
+
\( \s* SV \s* \* \s* \) \s*
|
| 151 |
+
)?
|
| 152 |
+
]x;
|
| 153 |
+
|
| 154 |
+
my $size = qr[ # Third arg (to setpvn)
|
| 155 |
+
, \s* (??{ $bal })
|
| 156 |
+
]xo;
|
| 157 |
+
|
| 158 |
+
my $code = $self->code;
|
| 159 |
+
|
| 160 |
+
# We can still bootstrap compile 're', because in code re.pm is
|
| 161 |
+
# available to miniperl, and does not attempt to load the XS code.
|
| 162 |
+
use re 'eval';
|
| 163 |
+
|
| 164 |
+
my ($type, $with_size, $arg, $sarg) =
|
| 165 |
+
($code =~
|
| 166 |
+
m[^
|
| 167 |
+
\s+
|
| 168 |
+
sv_set([iunp])v(n)? # Type, is_setpvn
|
| 169 |
+
\s*
|
| 170 |
+
\( \s*
|
| 171 |
+
$sv_cast \$arg \s* , \s*
|
| 172 |
+
( $bal_no_comma ) # Set from
|
| 173 |
+
( $size )? # Possible sizeof set-from
|
| 174 |
+
\s* \) \s* ; \s* $
|
| 175 |
+
]xo
|
| 176 |
+
);
|
| 177 |
+
|
| 178 |
+
my $rv = undef;
|
| 179 |
+
if ($type) {
|
| 180 |
+
$rv = {
|
| 181 |
+
type => $type,
|
| 182 |
+
with_size => $with_size,
|
| 183 |
+
what => $arg,
|
| 184 |
+
what_size => $sarg,
|
| 185 |
+
};
|
| 186 |
+
}
|
| 187 |
+
$self->{targetable} = $rv;
|
| 188 |
+
return $rv;
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
=head1 SEE ALSO
|
| 192 |
+
|
| 193 |
+
L<ExtUtils::Typemaps>
|
| 194 |
+
|
| 195 |
+
=head1 AUTHOR
|
| 196 |
+
|
| 197 |
+
Steffen Mueller C<<[email protected]>>
|
| 198 |
+
|
| 199 |
+
=head1 COPYRIGHT & LICENSE
|
| 200 |
+
|
| 201 |
+
Copyright 2009, 2010, 2011, 2012 Steffen Mueller
|
| 202 |
+
|
| 203 |
+
This program is free software; you can redistribute it and/or
|
| 204 |
+
modify it under the same terms as Perl itself.
|
| 205 |
+
|
| 206 |
+
=cut
|
| 207 |
+
|
| 208 |
+
1;
|
| 209 |
+
|
my_container_sandbox/usr/share/perl/5.30.0/ExtUtils/Typemaps/Type.pm
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package ExtUtils::Typemaps::Type;
|
| 2 |
+
use 5.006001;
|
| 3 |
+
use strict;
|
| 4 |
+
use warnings;
|
| 5 |
+
require ExtUtils::Typemaps;
|
| 6 |
+
|
| 7 |
+
our $VERSION = '3.38';
|
| 8 |
+
|
| 9 |
+
=head1 NAME
|
| 10 |
+
|
| 11 |
+
ExtUtils::Typemaps::Type - Entry in the TYPEMAP section of a typemap
|
| 12 |
+
|
| 13 |
+
=head1 SYNOPSIS
|
| 14 |
+
|
| 15 |
+
use ExtUtils::Typemaps;
|
| 16 |
+
...
|
| 17 |
+
my $type = $typemap->get_type_map('char*');
|
| 18 |
+
my $input = $typemap->get_input_map($type->xstype);
|
| 19 |
+
|
| 20 |
+
=head1 DESCRIPTION
|
| 21 |
+
|
| 22 |
+
Refer to L<ExtUtils::Typemaps> for details.
|
| 23 |
+
Object associates C<ctype> with C<xstype>, which is the index
|
| 24 |
+
into the in- and output mapping tables.
|
| 25 |
+
|
| 26 |
+
=head1 METHODS
|
| 27 |
+
|
| 28 |
+
=cut
|
| 29 |
+
|
| 30 |
+
=head2 new
|
| 31 |
+
|
| 32 |
+
Requires C<xstype> and C<ctype> parameters.
|
| 33 |
+
|
| 34 |
+
Optionally takes C<prototype> parameter.
|
| 35 |
+
|
| 36 |
+
=cut
|
| 37 |
+
|
| 38 |
+
sub new {
|
| 39 |
+
my $prot = shift;
|
| 40 |
+
my $class = ref($prot)||$prot;
|
| 41 |
+
my %args = @_;
|
| 42 |
+
|
| 43 |
+
if (!ref($prot)) {
|
| 44 |
+
if (not defined $args{xstype} or not defined $args{ctype}) {
|
| 45 |
+
die("Need xstype and ctype parameters");
|
| 46 |
+
}
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
my $self = bless(
|
| 50 |
+
(ref($prot) ? {%$prot} : {proto => ''})
|
| 51 |
+
=> $class
|
| 52 |
+
);
|
| 53 |
+
|
| 54 |
+
$self->{xstype} = $args{xstype} if defined $args{xstype};
|
| 55 |
+
$self->{ctype} = $args{ctype} if defined $args{ctype};
|
| 56 |
+
$self->{tidy_ctype} = ExtUtils::Typemaps::tidy_type($self->{ctype});
|
| 57 |
+
$self->{proto} = $args{'prototype'} if defined $args{'prototype'};
|
| 58 |
+
|
| 59 |
+
return $self;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
=head2 proto
|
| 63 |
+
|
| 64 |
+
Returns or sets the prototype.
|
| 65 |
+
|
| 66 |
+
=cut
|
| 67 |
+
|
| 68 |
+
sub proto {
|
| 69 |
+
$_[0]->{proto} = $_[1] if @_ > 1;
|
| 70 |
+
return $_[0]->{proto};
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
=head2 xstype
|
| 74 |
+
|
| 75 |
+
Returns the name of the XS type that this C type is associated to.
|
| 76 |
+
|
| 77 |
+
=cut
|
| 78 |
+
|
| 79 |
+
sub xstype {
|
| 80 |
+
return $_[0]->{xstype};
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
=head2 ctype
|
| 84 |
+
|
| 85 |
+
Returns the name of the C type as it was set on construction.
|
| 86 |
+
|
| 87 |
+
=cut
|
| 88 |
+
|
| 89 |
+
sub ctype {
|
| 90 |
+
return defined($_[0]->{ctype}) ? $_[0]->{ctype} : $_[0]->{tidy_ctype};
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
=head2 tidy_ctype
|
| 94 |
+
|
| 95 |
+
Returns the canonicalized name of the C type.
|
| 96 |
+
|
| 97 |
+
=cut
|
| 98 |
+
|
| 99 |
+
sub tidy_ctype {
|
| 100 |
+
return $_[0]->{tidy_ctype};
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
=head1 SEE ALSO
|
| 104 |
+
|
| 105 |
+
L<ExtUtils::Typemaps>
|
| 106 |
+
|
| 107 |
+
=head1 AUTHOR
|
| 108 |
+
|
| 109 |
+
Steffen Mueller C<<[email protected]>>
|
| 110 |
+
|
| 111 |
+
=head1 COPYRIGHT & LICENSE
|
| 112 |
+
|
| 113 |
+
Copyright 2009, 2010, 2011, 2012 Steffen Mueller
|
| 114 |
+
|
| 115 |
+
This program is free software; you can redistribute it and/or
|
| 116 |
+
modify it under the same terms as Perl itself.
|
| 117 |
+
|
| 118 |
+
=cut
|
| 119 |
+
|
| 120 |
+
1;
|
| 121 |
+
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/API/Breakage.pm
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::API::Breakage;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
use Test2::Util qw/pkg_to_file/;
|
| 9 |
+
|
| 10 |
+
our @EXPORT_OK = qw{
|
| 11 |
+
upgrade_suggested
|
| 12 |
+
upgrade_required
|
| 13 |
+
known_broken
|
| 14 |
+
};
|
| 15 |
+
BEGIN { require Exporter; our @ISA = qw(Exporter) }
|
| 16 |
+
|
| 17 |
+
sub upgrade_suggested {
|
| 18 |
+
return (
|
| 19 |
+
'Test::Exception' => '0.42',
|
| 20 |
+
'Test::FITesque' => '0.04',
|
| 21 |
+
'Test::Module::Used' => '0.2.5',
|
| 22 |
+
'Test::Moose::More' => '0.025',
|
| 23 |
+
);
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
sub upgrade_required {
|
| 27 |
+
return (
|
| 28 |
+
'Test::Builder::Clutch' => '0.07',
|
| 29 |
+
'Test::Dist::VersionSync' => '1.1.4',
|
| 30 |
+
'Test::Modern' => '0.012',
|
| 31 |
+
'Test::SharedFork' => '0.34',
|
| 32 |
+
'Test::Alien' => '0.04',
|
| 33 |
+
'Test::UseAllModules' => '0.14',
|
| 34 |
+
'Test::More::Prefix' => '0.005',
|
| 35 |
+
|
| 36 |
+
'Test2::Tools::EventDumper' => 0.000007,
|
| 37 |
+
'Test2::Harness' => 0.000013,
|
| 38 |
+
|
| 39 |
+
'Test::DBIx::Class::Schema' => '1.0.9',
|
| 40 |
+
'Test::Clustericious::Cluster' => '0.30',
|
| 41 |
+
);
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
sub known_broken {
|
| 45 |
+
return (
|
| 46 |
+
'Net::BitTorrent' => '0.052',
|
| 47 |
+
'Test::Able' => '0.11',
|
| 48 |
+
'Test::Aggregate' => '0.373',
|
| 49 |
+
'Test::Flatten' => '0.11',
|
| 50 |
+
'Test::Group' => '0.20',
|
| 51 |
+
'Test::ParallelSubtest' => '0.05',
|
| 52 |
+
'Test::Pretty' => '0.32',
|
| 53 |
+
'Test::Wrapper' => '0.3.0',
|
| 54 |
+
|
| 55 |
+
'Log::Dispatch::Config::TestLog' => '0.02',
|
| 56 |
+
);
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
# Not reportable:
|
| 60 |
+
# Device::Chip => 0.07 - Tests will not pass, but not broken if already installed, also no fixed version we can upgrade to.
|
| 61 |
+
|
| 62 |
+
sub report {
|
| 63 |
+
my $class = shift;
|
| 64 |
+
my ($require) = @_;
|
| 65 |
+
|
| 66 |
+
my %suggest = __PACKAGE__->upgrade_suggested();
|
| 67 |
+
my %required = __PACKAGE__->upgrade_required();
|
| 68 |
+
my %broken = __PACKAGE__->known_broken();
|
| 69 |
+
|
| 70 |
+
my @warn;
|
| 71 |
+
for my $mod (keys %suggest) {
|
| 72 |
+
my $file = pkg_to_file($mod);
|
| 73 |
+
next unless $INC{$file} || ($require && eval { require $file; 1 });
|
| 74 |
+
my $want = $suggest{$mod};
|
| 75 |
+
next if eval { $mod->VERSION($want); 1 };
|
| 76 |
+
push @warn => " * Module '$mod' is outdated, we recommed updating above $want.";
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
for my $mod (keys %required) {
|
| 80 |
+
my $file = pkg_to_file($mod);
|
| 81 |
+
next unless $INC{$file} || ($require && eval { require $file; 1 });
|
| 82 |
+
my $want = $required{$mod};
|
| 83 |
+
next if eval { $mod->VERSION($want); 1 };
|
| 84 |
+
push @warn => " * Module '$mod' is outdated and known to be broken, please update to $want or higher.";
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
for my $mod (keys %broken) {
|
| 88 |
+
my $file = pkg_to_file($mod);
|
| 89 |
+
next unless $INC{$file} || ($require && eval { require $file; 1 });
|
| 90 |
+
my $tested = $broken{$mod};
|
| 91 |
+
push @warn => " * Module '$mod' is known to be broken in version $tested and below, newer versions have not been tested. You have: " . $mod->VERSION;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
return @warn;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
1;
|
| 98 |
+
|
| 99 |
+
__END__
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
=pod
|
| 103 |
+
|
| 104 |
+
=encoding UTF-8
|
| 105 |
+
|
| 106 |
+
=head1 NAME
|
| 107 |
+
|
| 108 |
+
Test2::API::Breakage - What breaks at what version
|
| 109 |
+
|
| 110 |
+
=head1 DESCRIPTION
|
| 111 |
+
|
| 112 |
+
This module provides lists of modules that are broken, or have been broken in
|
| 113 |
+
the past, when upgrading L<Test::Builder> to use L<Test2>.
|
| 114 |
+
|
| 115 |
+
=head1 FUNCTIONS
|
| 116 |
+
|
| 117 |
+
These can be imported, or called as methods on the class.
|
| 118 |
+
|
| 119 |
+
=over 4
|
| 120 |
+
|
| 121 |
+
=item %mod_ver = upgrade_suggested()
|
| 122 |
+
|
| 123 |
+
=item %mod_ver = Test2::API::Breakage->upgrade_suggested()
|
| 124 |
+
|
| 125 |
+
This returns key/value pairs. The key is the module name, the value is the
|
| 126 |
+
version number. If the installed version of the module is at or below the
|
| 127 |
+
specified one then an upgrade would be a good idea, but not strictly necessary.
|
| 128 |
+
|
| 129 |
+
=item %mod_ver = upgrade_required()
|
| 130 |
+
|
| 131 |
+
=item %mod_ver = Test2::API::Breakage->upgrade_required()
|
| 132 |
+
|
| 133 |
+
This returns key/value pairs. The key is the module name, the value is the
|
| 134 |
+
version number. If the installed version of the module is at or below the
|
| 135 |
+
specified one then an upgrade is required for the module to work properly.
|
| 136 |
+
|
| 137 |
+
=item %mod_ver = known_broken()
|
| 138 |
+
|
| 139 |
+
=item %mod_ver = Test2::API::Breakage->known_broken()
|
| 140 |
+
|
| 141 |
+
This returns key/value pairs. The key is the module name, the value is the
|
| 142 |
+
version number. If the installed version of the module is at or below the
|
| 143 |
+
specified one then the module will not work. A newer version may work, but is
|
| 144 |
+
not tested or verified.
|
| 145 |
+
|
| 146 |
+
=back
|
| 147 |
+
|
| 148 |
+
=head1 SOURCE
|
| 149 |
+
|
| 150 |
+
The source code repository for Test2 can be found at
|
| 151 |
+
F<http://github.com/Test-More/test-more/>.
|
| 152 |
+
|
| 153 |
+
=head1 MAINTAINERS
|
| 154 |
+
|
| 155 |
+
=over 4
|
| 156 |
+
|
| 157 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 158 |
+
|
| 159 |
+
=back
|
| 160 |
+
|
| 161 |
+
=head1 AUTHORS
|
| 162 |
+
|
| 163 |
+
=over 4
|
| 164 |
+
|
| 165 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 166 |
+
|
| 167 |
+
=back
|
| 168 |
+
|
| 169 |
+
=head1 COPYRIGHT
|
| 170 |
+
|
| 171 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 172 |
+
|
| 173 |
+
This program is free software; you can redistribute it and/or
|
| 174 |
+
modify it under the same terms as Perl itself.
|
| 175 |
+
|
| 176 |
+
See F<http://dev.perl.org/licenses/>
|
| 177 |
+
|
| 178 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/API/Context.pm
ADDED
|
@@ -0,0 +1,1013 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::API::Context;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
use Carp qw/confess croak/;
|
| 9 |
+
use Scalar::Util qw/weaken blessed/;
|
| 10 |
+
use Test2::Util qw/get_tid try pkg_to_file get_tid/;
|
| 11 |
+
|
| 12 |
+
use Test2::EventFacet::Trace();
|
| 13 |
+
use Test2::API();
|
| 14 |
+
|
| 15 |
+
# Preload some key event types
|
| 16 |
+
my %LOADED = (
|
| 17 |
+
map {
|
| 18 |
+
my $pkg = "Test2::Event::$_";
|
| 19 |
+
my $file = "Test2/Event/$_.pm";
|
| 20 |
+
require $file unless $INC{$file};
|
| 21 |
+
( $pkg => $pkg, $_ => $pkg )
|
| 22 |
+
} qw/Ok Diag Note Plan Bail Exception Waiting Skip Subtest Pass Fail V2/
|
| 23 |
+
);
|
| 24 |
+
|
| 25 |
+
use Test2::Util::ExternalMeta qw/meta get_meta set_meta delete_meta/;
|
| 26 |
+
use Test2::Util::HashBase qw{
|
| 27 |
+
stack hub trace _on_release _depth _is_canon _is_spawn _aborted
|
| 28 |
+
errno eval_error child_error thrown
|
| 29 |
+
};
|
| 30 |
+
|
| 31 |
+
# Private, not package vars
|
| 32 |
+
# It is safe to cache these.
|
| 33 |
+
my $ON_RELEASE = Test2::API::_context_release_callbacks_ref();
|
| 34 |
+
my $CONTEXTS = Test2::API::_contexts_ref();
|
| 35 |
+
|
| 36 |
+
sub init {
|
| 37 |
+
my $self = shift;
|
| 38 |
+
|
| 39 |
+
confess "The 'trace' attribute is required"
|
| 40 |
+
unless $self->{+TRACE};
|
| 41 |
+
|
| 42 |
+
confess "The 'hub' attribute is required"
|
| 43 |
+
unless $self->{+HUB};
|
| 44 |
+
|
| 45 |
+
$self->{+_DEPTH} = 0 unless defined $self->{+_DEPTH};
|
| 46 |
+
|
| 47 |
+
$self->{+ERRNO} = $! unless exists $self->{+ERRNO};
|
| 48 |
+
$self->{+EVAL_ERROR} = $@ unless exists $self->{+EVAL_ERROR};
|
| 49 |
+
$self->{+CHILD_ERROR} = $? unless exists $self->{+CHILD_ERROR};
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
sub snapshot { bless {%{$_[0]}, _is_canon => undef, _is_spawn => undef, _aborted => undef}, __PACKAGE__ }
|
| 53 |
+
|
| 54 |
+
sub restore_error_vars {
|
| 55 |
+
my $self = shift;
|
| 56 |
+
($!, $@, $?) = @$self{+ERRNO, +EVAL_ERROR, +CHILD_ERROR};
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
sub DESTROY {
|
| 60 |
+
return unless $_[0]->{+_IS_CANON} || $_[0]->{+_IS_SPAWN};
|
| 61 |
+
return if $_[0]->{+_ABORTED} && ${$_[0]->{+_ABORTED}};
|
| 62 |
+
my ($self) = @_;
|
| 63 |
+
|
| 64 |
+
my $hub = $self->{+HUB};
|
| 65 |
+
my $hid = $hub->{hid};
|
| 66 |
+
|
| 67 |
+
# Do not show the warning if it looks like an exception has been thrown, or
|
| 68 |
+
# if the context is not local to this process or thread.
|
| 69 |
+
{
|
| 70 |
+
# Sometimes $@ is uninitialized, not a problem in this case so do not
|
| 71 |
+
# show the warning about using eq.
|
| 72 |
+
no warnings 'uninitialized';
|
| 73 |
+
if($self->{+EVAL_ERROR} eq $@ && $hub->is_local) {
|
| 74 |
+
my $frame = $self->{+_IS_SPAWN} || $self->{+TRACE}->frame;
|
| 75 |
+
warn <<" EOT";
|
| 76 |
+
A context appears to have been destroyed without first calling release().
|
| 77 |
+
Based on \$@ it does not look like an exception was thrown (this is not always
|
| 78 |
+
a reliable test)
|
| 79 |
+
|
| 80 |
+
This is a problem because the global error variables (\$!, \$@, and \$?) will
|
| 81 |
+
not be restored. In addition some release callbacks will not work properly from
|
| 82 |
+
inside a DESTROY method.
|
| 83 |
+
|
| 84 |
+
Here are the context creation details, just in case a tool forgot to call
|
| 85 |
+
release():
|
| 86 |
+
File: $frame->[1]
|
| 87 |
+
Line: $frame->[2]
|
| 88 |
+
Tool: $frame->[3]
|
| 89 |
+
|
| 90 |
+
Cleaning up the CONTEXT stack...
|
| 91 |
+
EOT
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
return if $self->{+_IS_SPAWN};
|
| 96 |
+
|
| 97 |
+
# Remove the key itself to avoid a slow memory leak
|
| 98 |
+
delete $CONTEXTS->{$hid};
|
| 99 |
+
$self->{+_IS_CANON} = undef;
|
| 100 |
+
|
| 101 |
+
if (my $cbk = $self->{+_ON_RELEASE}) {
|
| 102 |
+
$_->($self) for reverse @$cbk;
|
| 103 |
+
}
|
| 104 |
+
if (my $hcbk = $hub->{_context_release}) {
|
| 105 |
+
$_->($self) for reverse @$hcbk;
|
| 106 |
+
}
|
| 107 |
+
$_->($self) for reverse @$ON_RELEASE;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
# release exists to implement behaviors like die-on-fail. In die-on-fail you
|
| 111 |
+
# want to die after a failure, but only after diagnostics have been reported.
|
| 112 |
+
# The ideal time for the die to happen is when the context is released.
|
| 113 |
+
# Unfortunately die does not work in a DESTROY block.
|
| 114 |
+
sub release {
|
| 115 |
+
my ($self) = @_;
|
| 116 |
+
|
| 117 |
+
($!, $@, $?) = @$self{+ERRNO, +EVAL_ERROR, +CHILD_ERROR} and return if $self->{+THROWN};
|
| 118 |
+
|
| 119 |
+
($!, $@, $?) = @$self{+ERRNO, +EVAL_ERROR, +CHILD_ERROR} and return $self->{+_IS_SPAWN} = undef
|
| 120 |
+
if $self->{+_IS_SPAWN};
|
| 121 |
+
|
| 122 |
+
croak "release() should not be called on context that is neither canon nor a child"
|
| 123 |
+
unless $self->{+_IS_CANON};
|
| 124 |
+
|
| 125 |
+
my $hub = $self->{+HUB};
|
| 126 |
+
my $hid = $hub->{hid};
|
| 127 |
+
|
| 128 |
+
croak "context thinks it is canon, but it is not"
|
| 129 |
+
unless $CONTEXTS->{$hid} && $CONTEXTS->{$hid} == $self;
|
| 130 |
+
|
| 131 |
+
# Remove the key itself to avoid a slow memory leak
|
| 132 |
+
$self->{+_IS_CANON} = undef;
|
| 133 |
+
delete $CONTEXTS->{$hid};
|
| 134 |
+
|
| 135 |
+
if (my $cbk = $self->{+_ON_RELEASE}) {
|
| 136 |
+
$_->($self) for reverse @$cbk;
|
| 137 |
+
}
|
| 138 |
+
if (my $hcbk = $hub->{_context_release}) {
|
| 139 |
+
$_->($self) for reverse @$hcbk;
|
| 140 |
+
}
|
| 141 |
+
$_->($self) for reverse @$ON_RELEASE;
|
| 142 |
+
|
| 143 |
+
# Do this last so that nothing else changes them.
|
| 144 |
+
# If one of the hooks dies then these do not get restored, this is
|
| 145 |
+
# intentional
|
| 146 |
+
($!, $@, $?) = @$self{+ERRNO, +EVAL_ERROR, +CHILD_ERROR};
|
| 147 |
+
|
| 148 |
+
return;
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
sub do_in_context {
|
| 152 |
+
my $self = shift;
|
| 153 |
+
my ($sub, @args) = @_;
|
| 154 |
+
|
| 155 |
+
# We need to update the pid/tid and error vars.
|
| 156 |
+
my $clone = $self->snapshot;
|
| 157 |
+
@$clone{+ERRNO, +EVAL_ERROR, +CHILD_ERROR} = ($!, $@, $?);
|
| 158 |
+
$clone->{+TRACE} = $clone->{+TRACE}->snapshot(pid => $$, tid => get_tid());
|
| 159 |
+
|
| 160 |
+
my $hub = $clone->{+HUB};
|
| 161 |
+
my $hid = $hub->hid;
|
| 162 |
+
|
| 163 |
+
my $old = $CONTEXTS->{$hid};
|
| 164 |
+
|
| 165 |
+
$clone->{+_IS_CANON} = 1;
|
| 166 |
+
$CONTEXTS->{$hid} = $clone;
|
| 167 |
+
weaken($CONTEXTS->{$hid});
|
| 168 |
+
my ($ok, $err) = &try($sub, @args);
|
| 169 |
+
my ($rok, $rerr) = try { $clone->release };
|
| 170 |
+
delete $clone->{+_IS_CANON};
|
| 171 |
+
|
| 172 |
+
if ($old) {
|
| 173 |
+
$CONTEXTS->{$hid} = $old;
|
| 174 |
+
weaken($CONTEXTS->{$hid});
|
| 175 |
+
}
|
| 176 |
+
else {
|
| 177 |
+
delete $CONTEXTS->{$hid};
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
die $err unless $ok;
|
| 181 |
+
die $rerr unless $rok;
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
sub done_testing {
|
| 185 |
+
my $self = shift;
|
| 186 |
+
$self->hub->finalize($self->trace, 1);
|
| 187 |
+
return;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
sub throw {
|
| 191 |
+
my ($self, $msg) = @_;
|
| 192 |
+
$self->{+THROWN} = 1;
|
| 193 |
+
${$self->{+_ABORTED}}++ if $self->{+_ABORTED};
|
| 194 |
+
$self->release if $self->{+_IS_CANON} || $self->{+_IS_SPAWN};
|
| 195 |
+
$self->trace->throw($msg);
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
sub alert {
|
| 199 |
+
my ($self, $msg) = @_;
|
| 200 |
+
$self->trace->alert($msg);
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
sub send_ev2_and_release {
|
| 204 |
+
my $self = shift;
|
| 205 |
+
my $out = $self->send_ev2(@_);
|
| 206 |
+
$self->release;
|
| 207 |
+
return $out;
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
sub send_ev2 {
|
| 211 |
+
my $self = shift;
|
| 212 |
+
|
| 213 |
+
my $e;
|
| 214 |
+
{
|
| 215 |
+
local $Carp::CarpLevel = $Carp::CarpLevel + 1;
|
| 216 |
+
$e = Test2::Event::V2->new(
|
| 217 |
+
trace => $self->{+TRACE}->snapshot,
|
| 218 |
+
@_,
|
| 219 |
+
);
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
if ($self->{+_ABORTED}) {
|
| 223 |
+
my $f = $e->facet_data;
|
| 224 |
+
${$self->{+_ABORTED}}++ if $f->{control}->{halt} || defined($f->{control}->{terminate}) || defined($e->terminate);
|
| 225 |
+
}
|
| 226 |
+
$self->{+HUB}->send($e);
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
sub build_ev2 {
|
| 230 |
+
my $self = shift;
|
| 231 |
+
|
| 232 |
+
local $Carp::CarpLevel = $Carp::CarpLevel + 1;
|
| 233 |
+
Test2::Event::V2->new(
|
| 234 |
+
trace => $self->{+TRACE}->snapshot,
|
| 235 |
+
@_,
|
| 236 |
+
);
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
sub send_event_and_release {
|
| 240 |
+
my $self = shift;
|
| 241 |
+
my $out = $self->send_event(@_);
|
| 242 |
+
$self->release;
|
| 243 |
+
return $out;
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
sub send_event {
|
| 247 |
+
my $self = shift;
|
| 248 |
+
my $event = shift;
|
| 249 |
+
my %args = @_;
|
| 250 |
+
|
| 251 |
+
my $pkg = $LOADED{$event} || $self->_parse_event($event);
|
| 252 |
+
|
| 253 |
+
my $e;
|
| 254 |
+
{
|
| 255 |
+
local $Carp::CarpLevel = $Carp::CarpLevel + 1;
|
| 256 |
+
$e = $pkg->new(
|
| 257 |
+
trace => $self->{+TRACE}->snapshot,
|
| 258 |
+
%args,
|
| 259 |
+
);
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
if ($self->{+_ABORTED}) {
|
| 263 |
+
my $f = $e->facet_data;
|
| 264 |
+
${$self->{+_ABORTED}}++ if $f->{control}->{halt} || defined($f->{control}->{terminate}) || defined($e->terminate);
|
| 265 |
+
}
|
| 266 |
+
$self->{+HUB}->send($e);
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
sub build_event {
|
| 270 |
+
my $self = shift;
|
| 271 |
+
my $event = shift;
|
| 272 |
+
my %args = @_;
|
| 273 |
+
|
| 274 |
+
my $pkg = $LOADED{$event} || $self->_parse_event($event);
|
| 275 |
+
|
| 276 |
+
local $Carp::CarpLevel = $Carp::CarpLevel + 1;
|
| 277 |
+
$pkg->new(
|
| 278 |
+
trace => $self->{+TRACE}->snapshot,
|
| 279 |
+
%args,
|
| 280 |
+
);
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
sub pass {
|
| 284 |
+
my $self = shift;
|
| 285 |
+
my ($name) = @_;
|
| 286 |
+
|
| 287 |
+
my $e = bless(
|
| 288 |
+
{
|
| 289 |
+
trace => bless({%{$self->{+TRACE}}}, 'Test2::EventFacet::Trace'),
|
| 290 |
+
name => $name,
|
| 291 |
+
},
|
| 292 |
+
"Test2::Event::Pass"
|
| 293 |
+
);
|
| 294 |
+
|
| 295 |
+
$self->{+HUB}->send($e);
|
| 296 |
+
return $e;
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
sub pass_and_release {
|
| 300 |
+
my $self = shift;
|
| 301 |
+
my ($name) = @_;
|
| 302 |
+
|
| 303 |
+
my $e = bless(
|
| 304 |
+
{
|
| 305 |
+
trace => bless({%{$self->{+TRACE}}}, 'Test2::EventFacet::Trace'),
|
| 306 |
+
name => $name,
|
| 307 |
+
},
|
| 308 |
+
"Test2::Event::Pass"
|
| 309 |
+
);
|
| 310 |
+
|
| 311 |
+
$self->{+HUB}->send($e);
|
| 312 |
+
$self->release;
|
| 313 |
+
return 1;
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
sub fail {
|
| 317 |
+
my $self = shift;
|
| 318 |
+
my ($name, @diag) = @_;
|
| 319 |
+
|
| 320 |
+
my $e = bless(
|
| 321 |
+
{
|
| 322 |
+
trace => bless({%{$self->{+TRACE}}}, 'Test2::EventFacet::Trace'),
|
| 323 |
+
name => $name,
|
| 324 |
+
},
|
| 325 |
+
"Test2::Event::Fail"
|
| 326 |
+
);
|
| 327 |
+
|
| 328 |
+
for my $msg (@diag) {
|
| 329 |
+
if (ref($msg) eq 'Test2::EventFacet::Info::Table') {
|
| 330 |
+
$e->add_info({tag => 'DIAG', debug => 1, $msg->info_args});
|
| 331 |
+
}
|
| 332 |
+
else {
|
| 333 |
+
$e->add_info({tag => 'DIAG', debug => 1, details => $msg});
|
| 334 |
+
}
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
$self->{+HUB}->send($e);
|
| 338 |
+
return $e;
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
sub fail_and_release {
|
| 342 |
+
my $self = shift;
|
| 343 |
+
my ($name, @diag) = @_;
|
| 344 |
+
|
| 345 |
+
my $e = bless(
|
| 346 |
+
{
|
| 347 |
+
trace => bless({%{$self->{+TRACE}}}, 'Test2::EventFacet::Trace'),
|
| 348 |
+
name => $name,
|
| 349 |
+
},
|
| 350 |
+
"Test2::Event::Fail"
|
| 351 |
+
);
|
| 352 |
+
|
| 353 |
+
for my $msg (@diag) {
|
| 354 |
+
if (ref($msg) eq 'Test2::EventFacet::Info::Table') {
|
| 355 |
+
$e->add_info({tag => 'DIAG', debug => 1, $msg->info_args});
|
| 356 |
+
}
|
| 357 |
+
else {
|
| 358 |
+
$e->add_info({tag => 'DIAG', debug => 1, details => $msg});
|
| 359 |
+
}
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
$self->{+HUB}->send($e);
|
| 363 |
+
$self->release;
|
| 364 |
+
return 0;
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
sub ok {
|
| 368 |
+
my $self = shift;
|
| 369 |
+
my ($pass, $name, $on_fail) = @_;
|
| 370 |
+
|
| 371 |
+
my $hub = $self->{+HUB};
|
| 372 |
+
|
| 373 |
+
my $e = bless {
|
| 374 |
+
trace => bless( {%{$self->{+TRACE}}}, 'Test2::EventFacet::Trace'),
|
| 375 |
+
pass => $pass,
|
| 376 |
+
name => $name,
|
| 377 |
+
}, 'Test2::Event::Ok';
|
| 378 |
+
$e->init;
|
| 379 |
+
|
| 380 |
+
$hub->send($e);
|
| 381 |
+
return $e if $pass;
|
| 382 |
+
|
| 383 |
+
$self->failure_diag($e);
|
| 384 |
+
|
| 385 |
+
if ($on_fail && @$on_fail) {
|
| 386 |
+
$self->diag($_) for @$on_fail;
|
| 387 |
+
}
|
| 388 |
+
|
| 389 |
+
return $e;
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
sub failure_diag {
|
| 393 |
+
my $self = shift;
|
| 394 |
+
my ($e) = @_;
|
| 395 |
+
|
| 396 |
+
# Figure out the debug info, this is typically the file name and line
|
| 397 |
+
# number, but can also be a custom message. If no trace object is provided
|
| 398 |
+
# then we have nothing useful to display.
|
| 399 |
+
my $name = $e->name;
|
| 400 |
+
my $trace = $e->trace;
|
| 401 |
+
my $debug = $trace ? $trace->debug : "[No trace info available]";
|
| 402 |
+
|
| 403 |
+
# Create the initial diagnostics. If the test has a name we put the debug
|
| 404 |
+
# info on a second line, this behavior is inherited from Test::Builder.
|
| 405 |
+
my $msg = defined($name)
|
| 406 |
+
? qq[Failed test '$name'\n$debug.\n]
|
| 407 |
+
: qq[Failed test $debug.\n];
|
| 408 |
+
|
| 409 |
+
$self->diag($msg);
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
sub skip {
|
| 413 |
+
my $self = shift;
|
| 414 |
+
my ($name, $reason, @extra) = @_;
|
| 415 |
+
$self->send_event(
|
| 416 |
+
'Skip',
|
| 417 |
+
name => $name,
|
| 418 |
+
reason => $reason,
|
| 419 |
+
pass => 1,
|
| 420 |
+
@extra,
|
| 421 |
+
);
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
sub note {
|
| 425 |
+
my $self = shift;
|
| 426 |
+
my ($message) = @_;
|
| 427 |
+
$self->send_event('Note', message => $message);
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
sub diag {
|
| 431 |
+
my $self = shift;
|
| 432 |
+
my ($message) = @_;
|
| 433 |
+
my $hub = $self->{+HUB};
|
| 434 |
+
$self->send_event(
|
| 435 |
+
'Diag',
|
| 436 |
+
message => $message,
|
| 437 |
+
);
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
sub plan {
|
| 441 |
+
my ($self, $max, $directive, $reason) = @_;
|
| 442 |
+
$self->send_event('Plan', max => $max, directive => $directive, reason => $reason);
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
sub bail {
|
| 446 |
+
my ($self, $reason) = @_;
|
| 447 |
+
$self->send_event('Bail', reason => $reason);
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
sub _parse_event {
|
| 451 |
+
my $self = shift;
|
| 452 |
+
my $event = shift;
|
| 453 |
+
|
| 454 |
+
my $pkg;
|
| 455 |
+
if ($event =~ m/^\+(.*)/) {
|
| 456 |
+
$pkg = $1;
|
| 457 |
+
}
|
| 458 |
+
else {
|
| 459 |
+
$pkg = "Test2::Event::$event";
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
unless ($LOADED{$pkg}) {
|
| 463 |
+
my $file = pkg_to_file($pkg);
|
| 464 |
+
my ($ok, $err) = try { require $file };
|
| 465 |
+
$self->throw("Could not load event module '$pkg': $err")
|
| 466 |
+
unless $ok;
|
| 467 |
+
|
| 468 |
+
$LOADED{$pkg} = $pkg;
|
| 469 |
+
}
|
| 470 |
+
|
| 471 |
+
confess "'$pkg' is not a subclass of 'Test2::Event'"
|
| 472 |
+
unless $pkg->isa('Test2::Event');
|
| 473 |
+
|
| 474 |
+
$LOADED{$event} = $pkg;
|
| 475 |
+
|
| 476 |
+
return $pkg;
|
| 477 |
+
}
|
| 478 |
+
|
| 479 |
+
1;
|
| 480 |
+
|
| 481 |
+
__END__
|
| 482 |
+
|
| 483 |
+
=pod
|
| 484 |
+
|
| 485 |
+
=encoding UTF-8
|
| 486 |
+
|
| 487 |
+
=head1 NAME
|
| 488 |
+
|
| 489 |
+
Test2::API::Context - Object to represent a testing context.
|
| 490 |
+
|
| 491 |
+
=head1 DESCRIPTION
|
| 492 |
+
|
| 493 |
+
The context object is the primary interface for authors of testing tools
|
| 494 |
+
written with L<Test2>. The context object represents the context in
|
| 495 |
+
which a test takes place (File and Line Number), and provides a quick way to
|
| 496 |
+
generate events from that context. The context object also takes care of
|
| 497 |
+
sending events to the correct L<Test2::Hub> instance.
|
| 498 |
+
|
| 499 |
+
=head1 SYNOPSIS
|
| 500 |
+
|
| 501 |
+
In general you will not be creating contexts directly. To obtain a context you
|
| 502 |
+
should always use C<context()> which is exported by the L<Test2::API> module.
|
| 503 |
+
|
| 504 |
+
use Test2::API qw/context/;
|
| 505 |
+
|
| 506 |
+
sub my_ok {
|
| 507 |
+
my ($bool, $name) = @_;
|
| 508 |
+
my $ctx = context();
|
| 509 |
+
|
| 510 |
+
if ($bool) {
|
| 511 |
+
$ctx->pass($name);
|
| 512 |
+
}
|
| 513 |
+
else {
|
| 514 |
+
$ctx->fail($name);
|
| 515 |
+
}
|
| 516 |
+
|
| 517 |
+
$ctx->release; # You MUST do this!
|
| 518 |
+
return $bool;
|
| 519 |
+
}
|
| 520 |
+
|
| 521 |
+
Context objects make it easy to wrap other tools that also use context. Once
|
| 522 |
+
you grab a context, any tool you call before releasing your context will
|
| 523 |
+
inherit it:
|
| 524 |
+
|
| 525 |
+
sub wrapper {
|
| 526 |
+
my ($bool, $name) = @_;
|
| 527 |
+
my $ctx = context();
|
| 528 |
+
$ctx->diag("wrapping my_ok");
|
| 529 |
+
|
| 530 |
+
my $out = my_ok($bool, $name);
|
| 531 |
+
$ctx->release; # You MUST do this!
|
| 532 |
+
return $out;
|
| 533 |
+
}
|
| 534 |
+
|
| 535 |
+
=head1 CRITICAL DETAILS
|
| 536 |
+
|
| 537 |
+
=over 4
|
| 538 |
+
|
| 539 |
+
=item you MUST always use the context() sub from Test2::API
|
| 540 |
+
|
| 541 |
+
Creating your own context via C<< Test2::API::Context->new() >> will almost never
|
| 542 |
+
produce a desirable result. Use C<context()> which is exported by L<Test2::API>.
|
| 543 |
+
|
| 544 |
+
There are a handful of cases where a tool author may want to create a new
|
| 545 |
+
context by hand, which is why the C<new> method exists. Unless you really know
|
| 546 |
+
what you are doing you should avoid this.
|
| 547 |
+
|
| 548 |
+
=item You MUST always release the context when done with it
|
| 549 |
+
|
| 550 |
+
Releasing the context tells the system you are done with it. This gives it a
|
| 551 |
+
chance to run any necessary callbacks or cleanup tasks. If you forget to
|
| 552 |
+
release the context it will try to detect the problem and warn you about it.
|
| 553 |
+
|
| 554 |
+
=item You MUST NOT pass context objects around
|
| 555 |
+
|
| 556 |
+
When you obtain a context object it is made specifically for your tool and any
|
| 557 |
+
tools nested within. If you pass a context around you run the risk of polluting
|
| 558 |
+
other tools with incorrect context information.
|
| 559 |
+
|
| 560 |
+
If you are certain that you want a different tool to use the same context you
|
| 561 |
+
may pass it a snapshot. C<< $ctx->snapshot >> will give you a shallow clone of
|
| 562 |
+
the context that is safe to pass around or store.
|
| 563 |
+
|
| 564 |
+
=item You MUST NOT store or cache a context for later
|
| 565 |
+
|
| 566 |
+
As long as a context exists for a given hub, all tools that try to get a
|
| 567 |
+
context will get the existing instance. If you try to store the context you
|
| 568 |
+
will pollute other tools with incorrect context information.
|
| 569 |
+
|
| 570 |
+
If you are certain that you want to save the context for later, you can use a
|
| 571 |
+
snapshot. C<< $ctx->snapshot >> will give you a shallow clone of the context
|
| 572 |
+
that is safe to pass around or store.
|
| 573 |
+
|
| 574 |
+
C<context()> has some mechanisms to protect you if you do cause a context to
|
| 575 |
+
persist beyond the scope in which it was obtained. In practice you should not
|
| 576 |
+
rely on these protections, and they are fairly noisy with warnings.
|
| 577 |
+
|
| 578 |
+
=item You SHOULD obtain your context as soon as possible in a given tool
|
| 579 |
+
|
| 580 |
+
You never know what tools you call from within your own tool will need a
|
| 581 |
+
context. Obtaining the context early ensures that nested tools can find the
|
| 582 |
+
context you want them to find.
|
| 583 |
+
|
| 584 |
+
=back
|
| 585 |
+
|
| 586 |
+
=head1 METHODS
|
| 587 |
+
|
| 588 |
+
=over 4
|
| 589 |
+
|
| 590 |
+
=item $ctx->done_testing;
|
| 591 |
+
|
| 592 |
+
Note that testing is finished. If no plan has been set this will generate a
|
| 593 |
+
Plan event.
|
| 594 |
+
|
| 595 |
+
=item $clone = $ctx->snapshot()
|
| 596 |
+
|
| 597 |
+
This will return a shallow clone of the context. The shallow clone is safe to
|
| 598 |
+
store for later.
|
| 599 |
+
|
| 600 |
+
=item $ctx->release()
|
| 601 |
+
|
| 602 |
+
This will release the context. This runs cleanup tasks, and several important
|
| 603 |
+
hooks. It will also restore C<$!>, C<$?>, and C<$@> to what they were when the
|
| 604 |
+
context was created.
|
| 605 |
+
|
| 606 |
+
B<Note:> If a context is acquired more than once an internal refcount is kept.
|
| 607 |
+
C<release()> decrements the ref count, none of the other actions of
|
| 608 |
+
C<release()> will occur unless the refcount hits 0. This means only the last
|
| 609 |
+
call to C<release()> will reset C<$?>, C<$!>, C<$@>,and run the cleanup tasks.
|
| 610 |
+
|
| 611 |
+
=item $ctx->throw($message)
|
| 612 |
+
|
| 613 |
+
This will throw an exception reporting to the file and line number of the
|
| 614 |
+
context. This will also release the context for you.
|
| 615 |
+
|
| 616 |
+
=item $ctx->alert($message)
|
| 617 |
+
|
| 618 |
+
This will issue a warning from the file and line number of the context.
|
| 619 |
+
|
| 620 |
+
=item $stack = $ctx->stack()
|
| 621 |
+
|
| 622 |
+
This will return the L<Test2::API::Stack> instance the context used to find
|
| 623 |
+
the current hub.
|
| 624 |
+
|
| 625 |
+
=item $hub = $ctx->hub()
|
| 626 |
+
|
| 627 |
+
This will return the L<Test2::Hub> instance the context recognizes as the
|
| 628 |
+
current one to which all events should be sent.
|
| 629 |
+
|
| 630 |
+
=item $dbg = $ctx->trace()
|
| 631 |
+
|
| 632 |
+
This will return the L<Test2::EventFacet::Trace> instance used by the context.
|
| 633 |
+
|
| 634 |
+
=item $ctx->do_in_context(\&code, @args);
|
| 635 |
+
|
| 636 |
+
Sometimes you have a context that is not current, and you want things to use it
|
| 637 |
+
as the current one. In these cases you can call
|
| 638 |
+
C<< $ctx->do_in_context(sub { ... }) >>. The codeblock will be run, and
|
| 639 |
+
anything inside of it that looks for a context will find the one on which the
|
| 640 |
+
method was called.
|
| 641 |
+
|
| 642 |
+
This B<DOES NOT> affect context on other hubs, only the hub used by the context
|
| 643 |
+
will be affected.
|
| 644 |
+
|
| 645 |
+
my $ctx = ...;
|
| 646 |
+
$ctx->do_in_context(sub {
|
| 647 |
+
my $ctx = context(); # returns the $ctx the sub is called on
|
| 648 |
+
});
|
| 649 |
+
|
| 650 |
+
B<Note:> The context will actually be cloned, the clone will be used instead of
|
| 651 |
+
the original. This allows the thread id, process id, and error variables to be correct without
|
| 652 |
+
modifying the original context.
|
| 653 |
+
|
| 654 |
+
=item $ctx->restore_error_vars()
|
| 655 |
+
|
| 656 |
+
This will set C<$!>, C<$?>, and C<$@> to what they were when the context was
|
| 657 |
+
created. There is no localization or anything done here, calling this method
|
| 658 |
+
will actually set these vars.
|
| 659 |
+
|
| 660 |
+
=item $! = $ctx->errno()
|
| 661 |
+
|
| 662 |
+
The (numeric) value of C<$!> when the context was created.
|
| 663 |
+
|
| 664 |
+
=item $? = $ctx->child_error()
|
| 665 |
+
|
| 666 |
+
The value of C<$?> when the context was created.
|
| 667 |
+
|
| 668 |
+
=item $@ = $ctx->eval_error()
|
| 669 |
+
|
| 670 |
+
The value of C<$@> when the context was created.
|
| 671 |
+
|
| 672 |
+
=back
|
| 673 |
+
|
| 674 |
+
=head2 EVENT PRODUCTION METHODS
|
| 675 |
+
|
| 676 |
+
B<Which one do I use?>
|
| 677 |
+
|
| 678 |
+
The C<pass*> and C<fail*> are optimal if they meet your situation, using one of
|
| 679 |
+
them will always be the most optimal. That said they are optimal by eliminating
|
| 680 |
+
many features.
|
| 681 |
+
|
| 682 |
+
Method such as C<ok>, and C<note> are shortcuts for generating common 1-task
|
| 683 |
+
events based on the old API, however they are forward compatible, and easy to
|
| 684 |
+
use. If these meet your needs then go ahead and use them, but please check back
|
| 685 |
+
often for alternatives that may be added.
|
| 686 |
+
|
| 687 |
+
If you want to generate new style events, events that do many things at once,
|
| 688 |
+
then you want the C<*ev2*> methods. These let you directly specify which facets
|
| 689 |
+
you wish to use.
|
| 690 |
+
|
| 691 |
+
=over 4
|
| 692 |
+
|
| 693 |
+
=item $event = $ctx->pass()
|
| 694 |
+
|
| 695 |
+
=item $event = $ctx->pass($name)
|
| 696 |
+
|
| 697 |
+
This will send and return an L<Test2::Event::Pass> event. You may optionally
|
| 698 |
+
provide a C<$name> for the assertion.
|
| 699 |
+
|
| 700 |
+
The L<Test2::Event::Pass> is a specially crafted and optimized event, using
|
| 701 |
+
this will help the performance of passing tests.
|
| 702 |
+
|
| 703 |
+
=item $true = $ctx->pass_and_release()
|
| 704 |
+
|
| 705 |
+
=item $true = $ctx->pass_and_release($name)
|
| 706 |
+
|
| 707 |
+
This is a combination of C<pass()> and C<release()>. You can use this if you do
|
| 708 |
+
not plan to do anything with the context after sending the event. This helps
|
| 709 |
+
write more clear and compact code.
|
| 710 |
+
|
| 711 |
+
sub shorthand {
|
| 712 |
+
my ($bool, $name) = @_;
|
| 713 |
+
my $ctx = context();
|
| 714 |
+
return $ctx->pass_and_release($name) if $bool;
|
| 715 |
+
|
| 716 |
+
... Handle a failure ...
|
| 717 |
+
}
|
| 718 |
+
|
| 719 |
+
sub longform {
|
| 720 |
+
my ($bool, $name) = @_;
|
| 721 |
+
my $ctx = context();
|
| 722 |
+
|
| 723 |
+
if ($bool) {
|
| 724 |
+
$ctx->pass($name);
|
| 725 |
+
$ctx->release;
|
| 726 |
+
return 1;
|
| 727 |
+
}
|
| 728 |
+
|
| 729 |
+
... Handle a failure ...
|
| 730 |
+
}
|
| 731 |
+
|
| 732 |
+
=item my $event = $ctx->fail()
|
| 733 |
+
|
| 734 |
+
=item my $event = $ctx->fail($name)
|
| 735 |
+
|
| 736 |
+
=item my $event = $ctx->fail($name, @diagnostics)
|
| 737 |
+
|
| 738 |
+
This lets you send an L<Test2::Event::Fail> event. You may optionally provide a
|
| 739 |
+
C<$name> and C<@diagnostics> messages.
|
| 740 |
+
|
| 741 |
+
Diagnostics messages can be simple strings, data structures, or instances of
|
| 742 |
+
L<Test2::EventFacet::Info::Table> (which are converted inline into the
|
| 743 |
+
L<Test2::EventFacet::Info> structure).
|
| 744 |
+
|
| 745 |
+
=item my $false = $ctx->fail_and_release()
|
| 746 |
+
|
| 747 |
+
=item my $false = $ctx->fail_and_release($name)
|
| 748 |
+
|
| 749 |
+
=item my $false = $ctx->fail_and_release($name, @diagnostics)
|
| 750 |
+
|
| 751 |
+
This is a combination of C<fail()> and C<release()>. This can be used to write
|
| 752 |
+
clearer and shorter code.
|
| 753 |
+
|
| 754 |
+
sub shorthand {
|
| 755 |
+
my ($bool, $name) = @_;
|
| 756 |
+
my $ctx = context();
|
| 757 |
+
return $ctx->fail_and_release($name) unless $bool;
|
| 758 |
+
|
| 759 |
+
... Handle a success ...
|
| 760 |
+
}
|
| 761 |
+
|
| 762 |
+
sub longform {
|
| 763 |
+
my ($bool, $name) = @_;
|
| 764 |
+
my $ctx = context();
|
| 765 |
+
|
| 766 |
+
unless ($bool) {
|
| 767 |
+
$ctx->pass($name);
|
| 768 |
+
$ctx->release;
|
| 769 |
+
return 1;
|
| 770 |
+
}
|
| 771 |
+
|
| 772 |
+
... Handle a success ...
|
| 773 |
+
}
|
| 774 |
+
|
| 775 |
+
|
| 776 |
+
=item $event = $ctx->ok($bool, $name)
|
| 777 |
+
|
| 778 |
+
=item $event = $ctx->ok($bool, $name, \@on_fail)
|
| 779 |
+
|
| 780 |
+
B<NOTE:> Use of this method is discouraged in favor of C<pass()> and C<fail()>
|
| 781 |
+
which produce L<Test2::Event::Pass> and L<Test2::Event::Fail> events. These
|
| 782 |
+
newer event types are faster and less crufty.
|
| 783 |
+
|
| 784 |
+
This will create an L<Test2::Event::Ok> object for you. If C<$bool> is false
|
| 785 |
+
then an L<Test2::Event::Diag> event will be sent as well with details about the
|
| 786 |
+
failure. If you do not want automatic diagnostics you should use the
|
| 787 |
+
C<send_event()> method directly.
|
| 788 |
+
|
| 789 |
+
The third argument C<\@on_fail>) is an optional set of diagnostics to be sent in
|
| 790 |
+
the event of a test failure. Unlike with C<fail()> these diagnostics must be
|
| 791 |
+
plain strings, data structures are not supported.
|
| 792 |
+
|
| 793 |
+
=item $event = $ctx->note($message)
|
| 794 |
+
|
| 795 |
+
Send an L<Test2::Event::Note>. This event prints a message to STDOUT.
|
| 796 |
+
|
| 797 |
+
=item $event = $ctx->diag($message)
|
| 798 |
+
|
| 799 |
+
Send an L<Test2::Event::Diag>. This event prints a message to STDERR.
|
| 800 |
+
|
| 801 |
+
=item $event = $ctx->plan($max)
|
| 802 |
+
|
| 803 |
+
=item $event = $ctx->plan(0, 'SKIP', $reason)
|
| 804 |
+
|
| 805 |
+
This can be used to send an L<Test2::Event::Plan> event. This event
|
| 806 |
+
usually takes either a number of tests you expect to run. Optionally you can
|
| 807 |
+
set the expected count to 0 and give the 'SKIP' directive with a reason to
|
| 808 |
+
cause all tests to be skipped.
|
| 809 |
+
|
| 810 |
+
=item $event = $ctx->skip($name, $reason);
|
| 811 |
+
|
| 812 |
+
Send an L<Test2::Event::Skip> event.
|
| 813 |
+
|
| 814 |
+
=item $event = $ctx->bail($reason)
|
| 815 |
+
|
| 816 |
+
This sends an L<Test2::Event::Bail> event. This event will completely
|
| 817 |
+
terminate all testing.
|
| 818 |
+
|
| 819 |
+
=item $event = $ctx->send_ev2(%facets)
|
| 820 |
+
|
| 821 |
+
This lets you build and send a V2 event directly from facets. The event is
|
| 822 |
+
returned after it is sent.
|
| 823 |
+
|
| 824 |
+
This example sends a single assertion, a note (comment for stdout in
|
| 825 |
+
Test::Builder talk) and sets the plan to 1.
|
| 826 |
+
|
| 827 |
+
my $event = $ctx->send_event(
|
| 828 |
+
plan => {count => 1},
|
| 829 |
+
assert => {pass => 1, details => "A passing assert"},
|
| 830 |
+
info => [{tag => 'NOTE', details => "This is a note"}],
|
| 831 |
+
);
|
| 832 |
+
|
| 833 |
+
=item $event = $ctx->build_e2(%facets)
|
| 834 |
+
|
| 835 |
+
This is the same as C<send_ev2()>, except it builds and returns the event
|
| 836 |
+
without sending it.
|
| 837 |
+
|
| 838 |
+
=item $event = $ctx->send_ev2_and_release($Type, %parameters)
|
| 839 |
+
|
| 840 |
+
This is a combination of C<send_ev2()> and C<release()>.
|
| 841 |
+
|
| 842 |
+
sub shorthand {
|
| 843 |
+
my $ctx = context();
|
| 844 |
+
return $ctx->send_ev2_and_release(assert => {pass => 1, details => 'foo'});
|
| 845 |
+
}
|
| 846 |
+
|
| 847 |
+
sub longform {
|
| 848 |
+
my $ctx = context();
|
| 849 |
+
my $event = $ctx->send_ev2(assert => {pass => 1, details => 'foo'});
|
| 850 |
+
$ctx->release;
|
| 851 |
+
return $event;
|
| 852 |
+
}
|
| 853 |
+
|
| 854 |
+
=item $event = $ctx->send_event($Type, %parameters)
|
| 855 |
+
|
| 856 |
+
B<It is better to use send_ev2() in new code.>
|
| 857 |
+
|
| 858 |
+
This lets you build and send an event of any type. The C<$Type> argument should
|
| 859 |
+
be the event package name with C<Test2::Event::> left off, or a fully
|
| 860 |
+
qualified package name prefixed with a '+'. The event is returned after it is
|
| 861 |
+
sent.
|
| 862 |
+
|
| 863 |
+
my $event = $ctx->send_event('Ok', ...);
|
| 864 |
+
|
| 865 |
+
or
|
| 866 |
+
|
| 867 |
+
my $event = $ctx->send_event('+Test2::Event::Ok', ...);
|
| 868 |
+
|
| 869 |
+
=item $event = $ctx->build_event($Type, %parameters)
|
| 870 |
+
|
| 871 |
+
B<It is better to use build_ev2() in new code.>
|
| 872 |
+
|
| 873 |
+
This is the same as C<send_event()>, except it builds and returns the event
|
| 874 |
+
without sending it.
|
| 875 |
+
|
| 876 |
+
=item $event = $ctx->send_event_and_release($Type, %parameters)
|
| 877 |
+
|
| 878 |
+
B<It is better to use send_ev2_and_release() in new code.>
|
| 879 |
+
|
| 880 |
+
This is a combination of C<send_event()> and C<release()>.
|
| 881 |
+
|
| 882 |
+
sub shorthand {
|
| 883 |
+
my $ctx = context();
|
| 884 |
+
return $ctx->send_event_and_release(Pass => { name => 'foo' });
|
| 885 |
+
}
|
| 886 |
+
|
| 887 |
+
sub longform {
|
| 888 |
+
my $ctx = context();
|
| 889 |
+
my $event = $ctx->send_event(Pass => { name => 'foo' });
|
| 890 |
+
$ctx->release;
|
| 891 |
+
return $event;
|
| 892 |
+
}
|
| 893 |
+
|
| 894 |
+
=back
|
| 895 |
+
|
| 896 |
+
=head1 HOOKS
|
| 897 |
+
|
| 898 |
+
There are 2 types of hooks, init hooks, and release hooks. As the names
|
| 899 |
+
suggest, these hooks are triggered when contexts are created or released.
|
| 900 |
+
|
| 901 |
+
=head2 INIT HOOKS
|
| 902 |
+
|
| 903 |
+
These are called whenever a context is initialized. That means when a new
|
| 904 |
+
instance is created. These hooks are B<NOT> called every time something
|
| 905 |
+
requests a context, just when a new one is created.
|
| 906 |
+
|
| 907 |
+
=head3 GLOBAL
|
| 908 |
+
|
| 909 |
+
This is how you add a global init callback. Global callbacks happen for every
|
| 910 |
+
context for any hub or stack.
|
| 911 |
+
|
| 912 |
+
Test2::API::test2_add_callback_context_init(sub {
|
| 913 |
+
my $ctx = shift;
|
| 914 |
+
...
|
| 915 |
+
});
|
| 916 |
+
|
| 917 |
+
=head3 PER HUB
|
| 918 |
+
|
| 919 |
+
This is how you add an init callback for all contexts created for a given hub.
|
| 920 |
+
These callbacks will not run for other hubs.
|
| 921 |
+
|
| 922 |
+
$hub->add_context_init(sub {
|
| 923 |
+
my $ctx = shift;
|
| 924 |
+
...
|
| 925 |
+
});
|
| 926 |
+
|
| 927 |
+
=head3 PER CONTEXT
|
| 928 |
+
|
| 929 |
+
This is how you specify an init hook that will only run if your call to
|
| 930 |
+
C<context()> generates a new context. The callback will be ignored if
|
| 931 |
+
C<context()> is returning an existing context.
|
| 932 |
+
|
| 933 |
+
my $ctx = context(on_init => sub {
|
| 934 |
+
my $ctx = shift;
|
| 935 |
+
...
|
| 936 |
+
});
|
| 937 |
+
|
| 938 |
+
=head2 RELEASE HOOKS
|
| 939 |
+
|
| 940 |
+
These are called whenever a context is released. That means when the last
|
| 941 |
+
reference to the instance is about to be destroyed. These hooks are B<NOT>
|
| 942 |
+
called every time C<< $ctx->release >> is called.
|
| 943 |
+
|
| 944 |
+
=head3 GLOBAL
|
| 945 |
+
|
| 946 |
+
This is how you add a global release callback. Global callbacks happen for every
|
| 947 |
+
context for any hub or stack.
|
| 948 |
+
|
| 949 |
+
Test2::API::test2_add_callback_context_release(sub {
|
| 950 |
+
my $ctx = shift;
|
| 951 |
+
...
|
| 952 |
+
});
|
| 953 |
+
|
| 954 |
+
=head3 PER HUB
|
| 955 |
+
|
| 956 |
+
This is how you add a release callback for all contexts created for a given
|
| 957 |
+
hub. These callbacks will not run for other hubs.
|
| 958 |
+
|
| 959 |
+
$hub->add_context_release(sub {
|
| 960 |
+
my $ctx = shift;
|
| 961 |
+
...
|
| 962 |
+
});
|
| 963 |
+
|
| 964 |
+
=head3 PER CONTEXT
|
| 965 |
+
|
| 966 |
+
This is how you add release callbacks directly to a context. The callback will
|
| 967 |
+
B<ALWAYS> be added to the context that gets returned, it does not matter if a
|
| 968 |
+
new one is generated, or if an existing one is returned.
|
| 969 |
+
|
| 970 |
+
my $ctx = context(on_release => sub {
|
| 971 |
+
my $ctx = shift;
|
| 972 |
+
...
|
| 973 |
+
});
|
| 974 |
+
|
| 975 |
+
=head1 THIRD PARTY META-DATA
|
| 976 |
+
|
| 977 |
+
This object consumes L<Test2::Util::ExternalMeta> which provides a consistent
|
| 978 |
+
way for you to attach meta-data to instances of this class. This is useful for
|
| 979 |
+
tools, plugins, and other extensions.
|
| 980 |
+
|
| 981 |
+
=head1 SOURCE
|
| 982 |
+
|
| 983 |
+
The source code repository for Test2 can be found at
|
| 984 |
+
F<http://github.com/Test-More/test-more/>.
|
| 985 |
+
|
| 986 |
+
=head1 MAINTAINERS
|
| 987 |
+
|
| 988 |
+
=over 4
|
| 989 |
+
|
| 990 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 991 |
+
|
| 992 |
+
=back
|
| 993 |
+
|
| 994 |
+
=head1 AUTHORS
|
| 995 |
+
|
| 996 |
+
=over 4
|
| 997 |
+
|
| 998 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 999 |
+
|
| 1000 |
+
=item Kent Fredric E<lt>[email protected]<gt>
|
| 1001 |
+
|
| 1002 |
+
=back
|
| 1003 |
+
|
| 1004 |
+
=head1 COPYRIGHT
|
| 1005 |
+
|
| 1006 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 1007 |
+
|
| 1008 |
+
This program is free software; you can redistribute it and/or
|
| 1009 |
+
modify it under the same terms as Perl itself.
|
| 1010 |
+
|
| 1011 |
+
See F<http://dev.perl.org/licenses/>
|
| 1012 |
+
|
| 1013 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/API/Instance.pm
ADDED
|
@@ -0,0 +1,822 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::API::Instance;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
our @CARP_NOT = qw/Test2::API Test2::API::Instance Test2::IPC::Driver Test2::Formatter/;
|
| 8 |
+
use Carp qw/confess carp/;
|
| 9 |
+
use Scalar::Util qw/reftype/;
|
| 10 |
+
|
| 11 |
+
use Test2::Util qw/get_tid USE_THREADS CAN_FORK pkg_to_file try CAN_SIGSYS/;
|
| 12 |
+
|
| 13 |
+
use Test2::EventFacet::Trace();
|
| 14 |
+
use Test2::API::Stack();
|
| 15 |
+
|
| 16 |
+
use Test2::Util::HashBase qw{
|
| 17 |
+
_pid _tid
|
| 18 |
+
no_wait
|
| 19 |
+
finalized loaded
|
| 20 |
+
ipc stack formatter
|
| 21 |
+
contexts
|
| 22 |
+
|
| 23 |
+
add_uuid_via
|
| 24 |
+
|
| 25 |
+
-preload
|
| 26 |
+
|
| 27 |
+
ipc_disabled
|
| 28 |
+
ipc_polling
|
| 29 |
+
ipc_drivers
|
| 30 |
+
ipc_timeout
|
| 31 |
+
formatters
|
| 32 |
+
|
| 33 |
+
exit_callbacks
|
| 34 |
+
post_load_callbacks
|
| 35 |
+
context_acquire_callbacks
|
| 36 |
+
context_init_callbacks
|
| 37 |
+
context_release_callbacks
|
| 38 |
+
pre_subtest_callbacks
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
sub DEFAULT_IPC_TIMEOUT() { 30 }
|
| 42 |
+
|
| 43 |
+
sub pid { $_[0]->{+_PID} }
|
| 44 |
+
sub tid { $_[0]->{+_TID} }
|
| 45 |
+
|
| 46 |
+
# Wrap around the getters that should call _finalize.
|
| 47 |
+
BEGIN {
|
| 48 |
+
for my $finalizer (IPC, FORMATTER) {
|
| 49 |
+
my $orig = __PACKAGE__->can($finalizer);
|
| 50 |
+
my $new = sub {
|
| 51 |
+
my $self = shift;
|
| 52 |
+
$self->_finalize unless $self->{+FINALIZED};
|
| 53 |
+
$self->$orig;
|
| 54 |
+
};
|
| 55 |
+
|
| 56 |
+
no strict 'refs';
|
| 57 |
+
no warnings 'redefine';
|
| 58 |
+
*{$finalizer} = $new;
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
sub has_ipc { !!$_[0]->{+IPC} }
|
| 63 |
+
|
| 64 |
+
sub import {
|
| 65 |
+
my $class = shift;
|
| 66 |
+
return unless @_;
|
| 67 |
+
my ($ref) = @_;
|
| 68 |
+
$$ref = $class->new;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
sub init { $_[0]->reset }
|
| 72 |
+
|
| 73 |
+
sub start_preload {
|
| 74 |
+
my $self = shift;
|
| 75 |
+
|
| 76 |
+
confess "preload cannot be started, Test2::API has already been initialized"
|
| 77 |
+
if $self->{+FINALIZED} || $self->{+LOADED};
|
| 78 |
+
|
| 79 |
+
return $self->{+PRELOAD} = 1;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
sub stop_preload {
|
| 83 |
+
my $self = shift;
|
| 84 |
+
|
| 85 |
+
return 0 unless $self->{+PRELOAD};
|
| 86 |
+
$self->{+PRELOAD} = 0;
|
| 87 |
+
|
| 88 |
+
$self->post_preload_reset();
|
| 89 |
+
|
| 90 |
+
return 1;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
sub post_preload_reset {
|
| 94 |
+
my $self = shift;
|
| 95 |
+
|
| 96 |
+
delete $self->{+_PID};
|
| 97 |
+
delete $self->{+_TID};
|
| 98 |
+
|
| 99 |
+
$self->{+ADD_UUID_VIA} = undef unless exists $self->{+ADD_UUID_VIA};
|
| 100 |
+
|
| 101 |
+
$self->{+CONTEXTS} = {};
|
| 102 |
+
|
| 103 |
+
$self->{+FORMATTERS} = [];
|
| 104 |
+
|
| 105 |
+
$self->{+FINALIZED} = undef;
|
| 106 |
+
$self->{+IPC} = undef;
|
| 107 |
+
$self->{+IPC_DISABLED} = $ENV{T2_NO_IPC} ? 1 : 0;
|
| 108 |
+
|
| 109 |
+
$self->{+IPC_TIMEOUT} = DEFAULT_IPC_TIMEOUT() unless defined $self->{+IPC_TIMEOUT};
|
| 110 |
+
|
| 111 |
+
$self->{+LOADED} = 0;
|
| 112 |
+
|
| 113 |
+
$self->{+STACK} ||= Test2::API::Stack->new;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
sub reset {
|
| 117 |
+
my $self = shift;
|
| 118 |
+
|
| 119 |
+
delete $self->{+_PID};
|
| 120 |
+
delete $self->{+_TID};
|
| 121 |
+
|
| 122 |
+
$self->{+ADD_UUID_VIA} = undef;
|
| 123 |
+
|
| 124 |
+
$self->{+CONTEXTS} = {};
|
| 125 |
+
|
| 126 |
+
$self->{+IPC_DRIVERS} = [];
|
| 127 |
+
$self->{+IPC_POLLING} = undef;
|
| 128 |
+
|
| 129 |
+
$self->{+FORMATTERS} = [];
|
| 130 |
+
$self->{+FORMATTER} = undef;
|
| 131 |
+
|
| 132 |
+
$self->{+FINALIZED} = undef;
|
| 133 |
+
$self->{+IPC} = undef;
|
| 134 |
+
$self->{+IPC_DISABLED} = $ENV{T2_NO_IPC} ? 1 : 0;
|
| 135 |
+
|
| 136 |
+
$self->{+IPC_TIMEOUT} = DEFAULT_IPC_TIMEOUT() unless defined $self->{+IPC_TIMEOUT};
|
| 137 |
+
|
| 138 |
+
$self->{+NO_WAIT} = 0;
|
| 139 |
+
$self->{+LOADED} = 0;
|
| 140 |
+
|
| 141 |
+
$self->{+EXIT_CALLBACKS} = [];
|
| 142 |
+
$self->{+POST_LOAD_CALLBACKS} = [];
|
| 143 |
+
$self->{+CONTEXT_ACQUIRE_CALLBACKS} = [];
|
| 144 |
+
$self->{+CONTEXT_INIT_CALLBACKS} = [];
|
| 145 |
+
$self->{+CONTEXT_RELEASE_CALLBACKS} = [];
|
| 146 |
+
$self->{+PRE_SUBTEST_CALLBACKS} = [];
|
| 147 |
+
|
| 148 |
+
$self->{+STACK} = Test2::API::Stack->new;
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
sub _finalize {
|
| 152 |
+
my $self = shift;
|
| 153 |
+
my ($caller) = @_;
|
| 154 |
+
$caller ||= [caller(1)];
|
| 155 |
+
|
| 156 |
+
confess "Attempt to initialize Test2::API during preload"
|
| 157 |
+
if $self->{+PRELOAD};
|
| 158 |
+
|
| 159 |
+
$self->{+FINALIZED} = $caller;
|
| 160 |
+
|
| 161 |
+
$self->{+_PID} = $$ unless defined $self->{+_PID};
|
| 162 |
+
$self->{+_TID} = get_tid() unless defined $self->{+_TID};
|
| 163 |
+
|
| 164 |
+
unless ($self->{+FORMATTER}) {
|
| 165 |
+
my ($formatter, $source);
|
| 166 |
+
if ($ENV{T2_FORMATTER}) {
|
| 167 |
+
$source = "set by the 'T2_FORMATTER' environment variable";
|
| 168 |
+
|
| 169 |
+
if ($ENV{T2_FORMATTER} =~ m/^(\+)?(.*)$/) {
|
| 170 |
+
$formatter = $1 ? $2 : "Test2::Formatter::$2"
|
| 171 |
+
}
|
| 172 |
+
else {
|
| 173 |
+
$formatter = '';
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
+
elsif (@{$self->{+FORMATTERS}}) {
|
| 177 |
+
($formatter) = @{$self->{+FORMATTERS}};
|
| 178 |
+
$source = "Most recently added";
|
| 179 |
+
}
|
| 180 |
+
else {
|
| 181 |
+
$formatter = 'Test2::Formatter::TAP';
|
| 182 |
+
$source = 'default formatter';
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
unless (ref($formatter) || $formatter->can('write')) {
|
| 186 |
+
my $file = pkg_to_file($formatter);
|
| 187 |
+
my ($ok, $err) = try { require $file };
|
| 188 |
+
unless ($ok) {
|
| 189 |
+
my $line = "* COULD NOT LOAD FORMATTER '$formatter' ($source) *";
|
| 190 |
+
my $border = '*' x length($line);
|
| 191 |
+
die "\n\n $border\n $line\n $border\n\n$err";
|
| 192 |
+
}
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
$self->{+FORMATTER} = $formatter;
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
# Turn on IPC if threads are on, drivers are registered, or the Test2::IPC
|
| 199 |
+
# module is loaded.
|
| 200 |
+
return if $self->{+IPC_DISABLED};
|
| 201 |
+
return unless USE_THREADS || $INC{'Test2/IPC.pm'} || @{$self->{+IPC_DRIVERS}};
|
| 202 |
+
|
| 203 |
+
# Turn on polling by default, people expect it.
|
| 204 |
+
$self->enable_ipc_polling;
|
| 205 |
+
|
| 206 |
+
unless (@{$self->{+IPC_DRIVERS}}) {
|
| 207 |
+
my ($ok, $error) = try { require Test2::IPC::Driver::Files };
|
| 208 |
+
die $error unless $ok;
|
| 209 |
+
push @{$self->{+IPC_DRIVERS}} => 'Test2::IPC::Driver::Files';
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
for my $driver (@{$self->{+IPC_DRIVERS}}) {
|
| 213 |
+
next unless $driver->can('is_viable') && $driver->is_viable;
|
| 214 |
+
$self->{+IPC} = $driver->new or next;
|
| 215 |
+
return;
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
die "IPC has been requested, but no viable drivers were found. Aborting...\n";
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
sub formatter_set { $_[0]->{+FORMATTER} ? 1 : 0 }
|
| 222 |
+
|
| 223 |
+
sub add_formatter {
|
| 224 |
+
my $self = shift;
|
| 225 |
+
my ($formatter) = @_;
|
| 226 |
+
unshift @{$self->{+FORMATTERS}} => $formatter;
|
| 227 |
+
|
| 228 |
+
return unless $self->{+FINALIZED};
|
| 229 |
+
|
| 230 |
+
# Why is the @CARP_NOT entry not enough?
|
| 231 |
+
local %Carp::Internal = %Carp::Internal;
|
| 232 |
+
$Carp::Internal{'Test2::Formatter'} = 1;
|
| 233 |
+
|
| 234 |
+
carp "Formatter $formatter loaded too late to be used as the global formatter";
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
sub add_context_acquire_callback {
|
| 238 |
+
my $self = shift;
|
| 239 |
+
my ($code) = @_;
|
| 240 |
+
|
| 241 |
+
my $rtype = reftype($code) || "";
|
| 242 |
+
|
| 243 |
+
confess "Context-acquire callbacks must be coderefs"
|
| 244 |
+
unless $code && $rtype eq 'CODE';
|
| 245 |
+
|
| 246 |
+
push @{$self->{+CONTEXT_ACQUIRE_CALLBACKS}} => $code;
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
sub add_context_init_callback {
|
| 250 |
+
my $self = shift;
|
| 251 |
+
my ($code) = @_;
|
| 252 |
+
|
| 253 |
+
my $rtype = reftype($code) || "";
|
| 254 |
+
|
| 255 |
+
confess "Context-init callbacks must be coderefs"
|
| 256 |
+
unless $code && $rtype eq 'CODE';
|
| 257 |
+
|
| 258 |
+
push @{$self->{+CONTEXT_INIT_CALLBACKS}} => $code;
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
sub add_context_release_callback {
|
| 262 |
+
my $self = shift;
|
| 263 |
+
my ($code) = @_;
|
| 264 |
+
|
| 265 |
+
my $rtype = reftype($code) || "";
|
| 266 |
+
|
| 267 |
+
confess "Context-release callbacks must be coderefs"
|
| 268 |
+
unless $code && $rtype eq 'CODE';
|
| 269 |
+
|
| 270 |
+
push @{$self->{+CONTEXT_RELEASE_CALLBACKS}} => $code;
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
sub add_post_load_callback {
|
| 274 |
+
my $self = shift;
|
| 275 |
+
my ($code) = @_;
|
| 276 |
+
|
| 277 |
+
my $rtype = reftype($code) || "";
|
| 278 |
+
|
| 279 |
+
confess "Post-load callbacks must be coderefs"
|
| 280 |
+
unless $code && $rtype eq 'CODE';
|
| 281 |
+
|
| 282 |
+
push @{$self->{+POST_LOAD_CALLBACKS}} => $code;
|
| 283 |
+
$code->() if $self->{+LOADED};
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
sub add_pre_subtest_callback {
|
| 287 |
+
my $self = shift;
|
| 288 |
+
my ($code) = @_;
|
| 289 |
+
|
| 290 |
+
my $rtype = reftype($code) || "";
|
| 291 |
+
|
| 292 |
+
confess "Pre-subtest callbacks must be coderefs"
|
| 293 |
+
unless $code && $rtype eq 'CODE';
|
| 294 |
+
|
| 295 |
+
push @{$self->{+PRE_SUBTEST_CALLBACKS}} => $code;
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
sub load {
|
| 299 |
+
my $self = shift;
|
| 300 |
+
unless ($self->{+LOADED}) {
|
| 301 |
+
confess "Attempt to initialize Test2::API during preload"
|
| 302 |
+
if $self->{+PRELOAD};
|
| 303 |
+
|
| 304 |
+
$self->{+_PID} = $$ unless defined $self->{+_PID};
|
| 305 |
+
$self->{+_TID} = get_tid() unless defined $self->{+_TID};
|
| 306 |
+
|
| 307 |
+
# This is for https://github.com/Test-More/test-more/issues/16
|
| 308 |
+
# and https://rt.perl.org/Public/Bug/Display.html?id=127774
|
| 309 |
+
# END blocks run in reverse order. This insures the END block is loaded
|
| 310 |
+
# as late as possible. It will not solve all cases, but it helps.
|
| 311 |
+
eval "END { Test2::API::test2_set_is_end() }; 1" or die $@;
|
| 312 |
+
|
| 313 |
+
$self->{+LOADED} = 1;
|
| 314 |
+
$_->() for @{$self->{+POST_LOAD_CALLBACKS}};
|
| 315 |
+
}
|
| 316 |
+
return $self->{+LOADED};
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
sub add_exit_callback {
|
| 320 |
+
my $self = shift;
|
| 321 |
+
my ($code) = @_;
|
| 322 |
+
my $rtype = reftype($code) || "";
|
| 323 |
+
|
| 324 |
+
confess "End callbacks must be coderefs"
|
| 325 |
+
unless $code && $rtype eq 'CODE';
|
| 326 |
+
|
| 327 |
+
push @{$self->{+EXIT_CALLBACKS}} => $code;
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
sub ipc_disable {
|
| 331 |
+
my $self = shift;
|
| 332 |
+
|
| 333 |
+
confess "Attempt to disable IPC after it has been initialized"
|
| 334 |
+
if $self->{+IPC};
|
| 335 |
+
|
| 336 |
+
$self->{+IPC_DISABLED} = 1;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
sub add_ipc_driver {
|
| 340 |
+
my $self = shift;
|
| 341 |
+
my ($driver) = @_;
|
| 342 |
+
unshift @{$self->{+IPC_DRIVERS}} => $driver;
|
| 343 |
+
|
| 344 |
+
return unless $self->{+FINALIZED};
|
| 345 |
+
|
| 346 |
+
# Why is the @CARP_NOT entry not enough?
|
| 347 |
+
local %Carp::Internal = %Carp::Internal;
|
| 348 |
+
$Carp::Internal{'Test2::IPC::Driver'} = 1;
|
| 349 |
+
|
| 350 |
+
carp "IPC driver $driver loaded too late to be used as the global ipc driver";
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
sub enable_ipc_polling {
|
| 354 |
+
my $self = shift;
|
| 355 |
+
|
| 356 |
+
$self->{+_PID} = $$ unless defined $self->{+_PID};
|
| 357 |
+
$self->{+_TID} = get_tid() unless defined $self->{+_TID};
|
| 358 |
+
|
| 359 |
+
$self->add_context_init_callback(
|
| 360 |
+
# This is called every time a context is created, it needs to be fast.
|
| 361 |
+
# $_[0] is a context object
|
| 362 |
+
sub {
|
| 363 |
+
return unless $self->{+IPC_POLLING};
|
| 364 |
+
return unless $self->{+IPC};
|
| 365 |
+
return unless $self->{+IPC}->pending();
|
| 366 |
+
return $_[0]->{hub}->cull;
|
| 367 |
+
}
|
| 368 |
+
) unless defined $self->ipc_polling;
|
| 369 |
+
|
| 370 |
+
$self->set_ipc_polling(1);
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
sub get_ipc_pending {
|
| 374 |
+
my $self = shift;
|
| 375 |
+
return -1 unless $self->{+IPC};
|
| 376 |
+
$self->{+IPC}->pending();
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
sub _check_pid {
|
| 380 |
+
my $self = shift;
|
| 381 |
+
my ($pid) = @_;
|
| 382 |
+
return kill(0, $pid);
|
| 383 |
+
}
|
| 384 |
+
|
| 385 |
+
sub set_ipc_pending {
|
| 386 |
+
my $self = shift;
|
| 387 |
+
return unless $self->{+IPC};
|
| 388 |
+
my ($val) = @_;
|
| 389 |
+
|
| 390 |
+
confess "value is required for set_ipc_pending"
|
| 391 |
+
unless $val;
|
| 392 |
+
|
| 393 |
+
$self->{+IPC}->set_pending($val);
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
sub disable_ipc_polling {
|
| 397 |
+
my $self = shift;
|
| 398 |
+
return unless defined $self->{+IPC_POLLING};
|
| 399 |
+
$self->{+IPC_POLLING} = 0;
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
sub _ipc_wait {
|
| 403 |
+
my ($timeout) = @_;
|
| 404 |
+
my $fail = 0;
|
| 405 |
+
|
| 406 |
+
$timeout = DEFAULT_IPC_TIMEOUT() unless defined $timeout;
|
| 407 |
+
|
| 408 |
+
my $ok = eval {
|
| 409 |
+
if (CAN_FORK) {
|
| 410 |
+
local $SIG{ALRM} = sub { die "Timeout waiting on child processes" };
|
| 411 |
+
alarm $timeout;
|
| 412 |
+
|
| 413 |
+
while (1) {
|
| 414 |
+
my $pid = CORE::wait();
|
| 415 |
+
my $err = $?;
|
| 416 |
+
last if $pid == -1;
|
| 417 |
+
next unless $err;
|
| 418 |
+
$fail++;
|
| 419 |
+
|
| 420 |
+
my $sig = $err & 127;
|
| 421 |
+
my $exit = $err >> 8;
|
| 422 |
+
warn "Process $pid did not exit cleanly (wstat: $err, exit: $exit, sig: $sig)\n";
|
| 423 |
+
}
|
| 424 |
+
|
| 425 |
+
alarm 0;
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
if (USE_THREADS) {
|
| 429 |
+
my $start = time;
|
| 430 |
+
|
| 431 |
+
while (1) {
|
| 432 |
+
last unless threads->list();
|
| 433 |
+
die "Timeout waiting on child thread" if time - $start >= $timeout;
|
| 434 |
+
sleep 1;
|
| 435 |
+
for my $t (threads->list) {
|
| 436 |
+
# threads older than 1.34 do not have this :-(
|
| 437 |
+
next if $t->can('is_joinable') && !$t->is_joinable;
|
| 438 |
+
$t->join;
|
| 439 |
+
# In older threads we cannot check if a thread had an error unless
|
| 440 |
+
# we control it and its return.
|
| 441 |
+
my $err = $t->can('error') ? $t->error : undef;
|
| 442 |
+
next unless $err;
|
| 443 |
+
my $tid = $t->tid();
|
| 444 |
+
$fail++;
|
| 445 |
+
chomp($err);
|
| 446 |
+
warn "Thread $tid did not end cleanly: $err\n";
|
| 447 |
+
}
|
| 448 |
+
}
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
1;
|
| 452 |
+
};
|
| 453 |
+
my $error = $@;
|
| 454 |
+
|
| 455 |
+
return 0 if $ok && !$fail;
|
| 456 |
+
warn $error unless $ok;
|
| 457 |
+
return 255;
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
sub set_exit {
|
| 461 |
+
my $self = shift;
|
| 462 |
+
|
| 463 |
+
return if $self->{+PRELOAD};
|
| 464 |
+
|
| 465 |
+
my $exit = $?;
|
| 466 |
+
my $new_exit = $exit;
|
| 467 |
+
|
| 468 |
+
if ($INC{'Test/Builder.pm'} && $Test::Builder::VERSION ne $Test2::API::VERSION) {
|
| 469 |
+
print STDERR <<" EOT";
|
| 470 |
+
|
| 471 |
+
********************************************************************************
|
| 472 |
+
* *
|
| 473 |
+
* Test::Builder -- Test2::API version mismatch detected *
|
| 474 |
+
* *
|
| 475 |
+
********************************************************************************
|
| 476 |
+
Test2::API Version: $Test2::API::VERSION
|
| 477 |
+
Test::Builder Version: $Test::Builder::VERSION
|
| 478 |
+
|
| 479 |
+
This is not a supported configuration, you will have problems.
|
| 480 |
+
|
| 481 |
+
EOT
|
| 482 |
+
}
|
| 483 |
+
|
| 484 |
+
for my $ctx (values %{$self->{+CONTEXTS}}) {
|
| 485 |
+
next unless $ctx;
|
| 486 |
+
|
| 487 |
+
next if $ctx->_aborted && ${$ctx->_aborted};
|
| 488 |
+
|
| 489 |
+
# Only worry about contexts in this PID
|
| 490 |
+
my $trace = $ctx->trace || next;
|
| 491 |
+
next unless $trace->pid && $trace->pid == $$;
|
| 492 |
+
|
| 493 |
+
# Do not worry about contexts that have no hub
|
| 494 |
+
my $hub = $ctx->hub || next;
|
| 495 |
+
|
| 496 |
+
# Do not worry if the state came to a sudden end.
|
| 497 |
+
next if $hub->bailed_out;
|
| 498 |
+
next if defined $hub->skip_reason;
|
| 499 |
+
|
| 500 |
+
# now we worry
|
| 501 |
+
$trace->alert("context object was never released! This means a testing tool is behaving very badly");
|
| 502 |
+
|
| 503 |
+
$exit = 255;
|
| 504 |
+
$new_exit = 255;
|
| 505 |
+
}
|
| 506 |
+
|
| 507 |
+
if (!defined($self->{+_PID}) or !defined($self->{+_TID}) or $self->{+_PID} != $$ or $self->{+_TID} != get_tid()) {
|
| 508 |
+
$? = $exit;
|
| 509 |
+
return;
|
| 510 |
+
}
|
| 511 |
+
|
| 512 |
+
my @hubs = $self->{+STACK} ? $self->{+STACK}->all : ();
|
| 513 |
+
|
| 514 |
+
if (@hubs and $self->{+IPC} and !$self->{+NO_WAIT}) {
|
| 515 |
+
local $?;
|
| 516 |
+
my %seen;
|
| 517 |
+
for my $hub (reverse @hubs) {
|
| 518 |
+
my $ipc = $hub->ipc or next;
|
| 519 |
+
next if $seen{$ipc}++;
|
| 520 |
+
$ipc->waiting();
|
| 521 |
+
}
|
| 522 |
+
|
| 523 |
+
my $ipc_exit = _ipc_wait($self->{+IPC_TIMEOUT});
|
| 524 |
+
$new_exit ||= $ipc_exit;
|
| 525 |
+
}
|
| 526 |
+
|
| 527 |
+
# None of this is necessary if we never got a root hub
|
| 528 |
+
if(my $root = shift @hubs) {
|
| 529 |
+
my $trace = Test2::EventFacet::Trace->new(
|
| 530 |
+
frame => [__PACKAGE__, __FILE__, 0, __PACKAGE__ . '::END'],
|
| 531 |
+
detail => __PACKAGE__ . ' END Block finalization',
|
| 532 |
+
);
|
| 533 |
+
my $ctx = Test2::API::Context->new(
|
| 534 |
+
trace => $trace,
|
| 535 |
+
hub => $root,
|
| 536 |
+
);
|
| 537 |
+
|
| 538 |
+
if (@hubs) {
|
| 539 |
+
$ctx->diag("Test ended with extra hubs on the stack!");
|
| 540 |
+
$new_exit = 255;
|
| 541 |
+
}
|
| 542 |
+
|
| 543 |
+
unless ($root->no_ending) {
|
| 544 |
+
local $?;
|
| 545 |
+
$root->finalize($trace) unless $root->ended;
|
| 546 |
+
$_->($ctx, $exit, \$new_exit) for @{$self->{+EXIT_CALLBACKS}};
|
| 547 |
+
$new_exit ||= $root->failed;
|
| 548 |
+
$new_exit ||= 255 unless $root->is_passing;
|
| 549 |
+
}
|
| 550 |
+
}
|
| 551 |
+
|
| 552 |
+
$new_exit = 255 if $new_exit > 255;
|
| 553 |
+
|
| 554 |
+
if ($new_exit && eval { require Test2::API::Breakage; 1 }) {
|
| 555 |
+
my @warn = Test2::API::Breakage->report();
|
| 556 |
+
|
| 557 |
+
if (@warn) {
|
| 558 |
+
print STDERR "\nYou have loaded versions of test modules known to have problems with Test2.\nThis could explain some test failures.\n";
|
| 559 |
+
print STDERR "$_\n" for @warn;
|
| 560 |
+
print STDERR "\n";
|
| 561 |
+
}
|
| 562 |
+
}
|
| 563 |
+
|
| 564 |
+
$? = $new_exit;
|
| 565 |
+
}
|
| 566 |
+
|
| 567 |
+
1;
|
| 568 |
+
|
| 569 |
+
__END__
|
| 570 |
+
|
| 571 |
+
=pod
|
| 572 |
+
|
| 573 |
+
=encoding UTF-8
|
| 574 |
+
|
| 575 |
+
=head1 NAME
|
| 576 |
+
|
| 577 |
+
Test2::API::Instance - Object used by Test2::API under the hood
|
| 578 |
+
|
| 579 |
+
=head1 DESCRIPTION
|
| 580 |
+
|
| 581 |
+
This object encapsulates the global shared state tracked by
|
| 582 |
+
L<Test2>. A single global instance of this package is stored (and
|
| 583 |
+
obscured) by the L<Test2::API> package.
|
| 584 |
+
|
| 585 |
+
There is no reason to directly use this package. This package is documented for
|
| 586 |
+
completeness. This package can change, or go away completely at any time.
|
| 587 |
+
Directly using, or monkeypatching this package is not supported in any way
|
| 588 |
+
shape or form.
|
| 589 |
+
|
| 590 |
+
=head1 SYNOPSIS
|
| 591 |
+
|
| 592 |
+
use Test2::API::Instance;
|
| 593 |
+
|
| 594 |
+
my $obj = Test2::API::Instance->new;
|
| 595 |
+
|
| 596 |
+
=over 4
|
| 597 |
+
|
| 598 |
+
=item $pid = $obj->pid
|
| 599 |
+
|
| 600 |
+
PID of this instance.
|
| 601 |
+
|
| 602 |
+
=item $obj->tid
|
| 603 |
+
|
| 604 |
+
Thread ID of this instance.
|
| 605 |
+
|
| 606 |
+
=item $obj->reset()
|
| 607 |
+
|
| 608 |
+
Reset the object to defaults.
|
| 609 |
+
|
| 610 |
+
=item $obj->load()
|
| 611 |
+
|
| 612 |
+
Set the internal state to loaded, and run and stored post-load callbacks.
|
| 613 |
+
|
| 614 |
+
=item $bool = $obj->loaded
|
| 615 |
+
|
| 616 |
+
Check if the state is set to loaded.
|
| 617 |
+
|
| 618 |
+
=item $arrayref = $obj->post_load_callbacks
|
| 619 |
+
|
| 620 |
+
Get the post-load callbacks.
|
| 621 |
+
|
| 622 |
+
=item $obj->add_post_load_callback(sub { ... })
|
| 623 |
+
|
| 624 |
+
Add a post-load callback. If C<load()> has already been called then the callback will
|
| 625 |
+
be immediately executed. If C<load()> has not been called then the callback will be
|
| 626 |
+
stored and executed later when C<load()> is called.
|
| 627 |
+
|
| 628 |
+
=item $hashref = $obj->contexts()
|
| 629 |
+
|
| 630 |
+
Get a hashref of all active contexts keyed by hub id.
|
| 631 |
+
|
| 632 |
+
=item $arrayref = $obj->context_acquire_callbacks
|
| 633 |
+
|
| 634 |
+
Get all context acquire callbacks.
|
| 635 |
+
|
| 636 |
+
=item $arrayref = $obj->context_init_callbacks
|
| 637 |
+
|
| 638 |
+
Get all context init callbacks.
|
| 639 |
+
|
| 640 |
+
=item $arrayref = $obj->context_release_callbacks
|
| 641 |
+
|
| 642 |
+
Get all context release callbacks.
|
| 643 |
+
|
| 644 |
+
=item $arrayref = $obj->pre_subtest_callbacks
|
| 645 |
+
|
| 646 |
+
Get all pre-subtest callbacks.
|
| 647 |
+
|
| 648 |
+
=item $obj->add_context_init_callback(sub { ... })
|
| 649 |
+
|
| 650 |
+
Add a context init callback. Subs are called every time a context is created. Subs
|
| 651 |
+
get the newly created context as their only argument.
|
| 652 |
+
|
| 653 |
+
=item $obj->add_context_release_callback(sub { ... })
|
| 654 |
+
|
| 655 |
+
Add a context release callback. Subs are called every time a context is released. Subs
|
| 656 |
+
get the released context as their only argument. These callbacks should not
|
| 657 |
+
call release on the context.
|
| 658 |
+
|
| 659 |
+
=item $obj->add_pre_subtest_callback(sub { ... })
|
| 660 |
+
|
| 661 |
+
Add a pre-subtest callback. Subs are called every time a subtest is
|
| 662 |
+
going to be run. Subs get the subtest name, coderef, and any
|
| 663 |
+
arguments.
|
| 664 |
+
|
| 665 |
+
=item $obj->set_exit()
|
| 666 |
+
|
| 667 |
+
This is intended to be called in an C<END { ... }> block. This will look at
|
| 668 |
+
test state and set $?. This will also call any end callbacks, and wait on child
|
| 669 |
+
processes/threads.
|
| 670 |
+
|
| 671 |
+
=item $obj->set_ipc_pending($val)
|
| 672 |
+
|
| 673 |
+
Tell other processes and threads there is a pending event. C<$val> should be a
|
| 674 |
+
unique value no other thread/process will generate.
|
| 675 |
+
|
| 676 |
+
B<Note:> This will also make the current process see a pending event.
|
| 677 |
+
|
| 678 |
+
=item $pending = $obj->get_ipc_pending()
|
| 679 |
+
|
| 680 |
+
This returns -1 if it is not possible to know.
|
| 681 |
+
|
| 682 |
+
This returns 0 if there are no pending events.
|
| 683 |
+
|
| 684 |
+
This returns 1 if there are pending events.
|
| 685 |
+
|
| 686 |
+
=item $timeout = $obj->ipc_timeout;
|
| 687 |
+
|
| 688 |
+
=item $obj->set_ipc_timeout($timeout);
|
| 689 |
+
|
| 690 |
+
How long to wait for child processes and threads before aborting.
|
| 691 |
+
|
| 692 |
+
=item $drivers = $obj->ipc_drivers
|
| 693 |
+
|
| 694 |
+
Get the list of IPC drivers.
|
| 695 |
+
|
| 696 |
+
=item $obj->add_ipc_driver($DRIVER_CLASS)
|
| 697 |
+
|
| 698 |
+
Add an IPC driver to the list. The most recently added IPC driver will become
|
| 699 |
+
the global one during initialization. If a driver is added after initialization
|
| 700 |
+
has occurred a warning will be generated:
|
| 701 |
+
|
| 702 |
+
"IPC driver $driver loaded too late to be used as the global ipc driver"
|
| 703 |
+
|
| 704 |
+
=item $bool = $obj->ipc_polling
|
| 705 |
+
|
| 706 |
+
Check if polling is enabled.
|
| 707 |
+
|
| 708 |
+
=item $obj->enable_ipc_polling
|
| 709 |
+
|
| 710 |
+
Turn on polling. This will cull events from other processes and threads every
|
| 711 |
+
time a context is created.
|
| 712 |
+
|
| 713 |
+
=item $obj->disable_ipc_polling
|
| 714 |
+
|
| 715 |
+
Turn off IPC polling.
|
| 716 |
+
|
| 717 |
+
=item $bool = $obj->no_wait
|
| 718 |
+
|
| 719 |
+
=item $bool = $obj->set_no_wait($bool)
|
| 720 |
+
|
| 721 |
+
Get/Set no_wait. This option is used to turn off process/thread waiting at exit.
|
| 722 |
+
|
| 723 |
+
=item $arrayref = $obj->exit_callbacks
|
| 724 |
+
|
| 725 |
+
Get the exit callbacks.
|
| 726 |
+
|
| 727 |
+
=item $obj->add_exit_callback(sub { ... })
|
| 728 |
+
|
| 729 |
+
Add an exit callback. This callback will be called by C<set_exit()>.
|
| 730 |
+
|
| 731 |
+
=item $bool = $obj->finalized
|
| 732 |
+
|
| 733 |
+
Check if the object is finalized. Finalization happens when either C<ipc()>,
|
| 734 |
+
C<stack()>, or C<format()> are called on the object. Once finalization happens
|
| 735 |
+
these fields are considered unchangeable (not enforced here, enforced by
|
| 736 |
+
L<Test2>).
|
| 737 |
+
|
| 738 |
+
=item $ipc = $obj->ipc
|
| 739 |
+
|
| 740 |
+
Get the one true IPC instance.
|
| 741 |
+
|
| 742 |
+
=item $obj->ipc_disable
|
| 743 |
+
|
| 744 |
+
Turn IPC off
|
| 745 |
+
|
| 746 |
+
=item $bool = $obj->ipc_disabled
|
| 747 |
+
|
| 748 |
+
Check if IPC is disabled
|
| 749 |
+
|
| 750 |
+
=item $stack = $obj->stack
|
| 751 |
+
|
| 752 |
+
Get the one true hub stack.
|
| 753 |
+
|
| 754 |
+
=item $formatter = $obj->formatter
|
| 755 |
+
|
| 756 |
+
Get the global formatter. By default this is the C<'Test2::Formatter::TAP'>
|
| 757 |
+
package. This could be any package that implements the C<write()> method. This
|
| 758 |
+
can also be an instantiated object.
|
| 759 |
+
|
| 760 |
+
=item $bool = $obj->formatter_set()
|
| 761 |
+
|
| 762 |
+
Check if a formatter has been set.
|
| 763 |
+
|
| 764 |
+
=item $obj->add_formatter($class)
|
| 765 |
+
|
| 766 |
+
=item $obj->add_formatter($obj)
|
| 767 |
+
|
| 768 |
+
Add a formatter. The most recently added formatter will become the global one
|
| 769 |
+
during initialization. If a formatter is added after initialization has occurred
|
| 770 |
+
a warning will be generated:
|
| 771 |
+
|
| 772 |
+
"Formatter $formatter loaded too late to be used as the global formatter"
|
| 773 |
+
|
| 774 |
+
=item $obj->set_add_uuid_via(sub { ... })
|
| 775 |
+
|
| 776 |
+
=item $sub = $obj->add_uuid_via()
|
| 777 |
+
|
| 778 |
+
This allows you to provide a UUID generator. If provided UUIDs will be attached
|
| 779 |
+
to all events, hubs, and contexts. This is useful for storing, tracking, and
|
| 780 |
+
linking these objects.
|
| 781 |
+
|
| 782 |
+
The sub you provide should always return a unique identifier. Most things will
|
| 783 |
+
expect a proper UUID string, however nothing in Test2::API enforces this.
|
| 784 |
+
|
| 785 |
+
The sub will receive exactly 1 argument, the type of thing being tagged
|
| 786 |
+
'context', 'hub', or 'event'. In the future additional things may be tagged, in
|
| 787 |
+
which case new strings will be passed in. These are purely informative, you can
|
| 788 |
+
(and usually should) ignore them.
|
| 789 |
+
|
| 790 |
+
=back
|
| 791 |
+
|
| 792 |
+
=head1 SOURCE
|
| 793 |
+
|
| 794 |
+
The source code repository for Test2 can be found at
|
| 795 |
+
F<http://github.com/Test-More/test-more/>.
|
| 796 |
+
|
| 797 |
+
=head1 MAINTAINERS
|
| 798 |
+
|
| 799 |
+
=over 4
|
| 800 |
+
|
| 801 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 802 |
+
|
| 803 |
+
=back
|
| 804 |
+
|
| 805 |
+
=head1 AUTHORS
|
| 806 |
+
|
| 807 |
+
=over 4
|
| 808 |
+
|
| 809 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 810 |
+
|
| 811 |
+
=back
|
| 812 |
+
|
| 813 |
+
=head1 COPYRIGHT
|
| 814 |
+
|
| 815 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 816 |
+
|
| 817 |
+
This program is free software; you can redistribute it and/or
|
| 818 |
+
modify it under the same terms as Perl itself.
|
| 819 |
+
|
| 820 |
+
See F<http://dev.perl.org/licenses/>
|
| 821 |
+
|
| 822 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/API/Stack.pm
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::API::Stack;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
use Test2::Hub();
|
| 9 |
+
|
| 10 |
+
use Carp qw/confess/;
|
| 11 |
+
|
| 12 |
+
sub new {
|
| 13 |
+
my $class = shift;
|
| 14 |
+
return bless [], $class;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
sub new_hub {
|
| 18 |
+
my $self = shift;
|
| 19 |
+
my %params = @_;
|
| 20 |
+
|
| 21 |
+
my $class = delete $params{class} || 'Test2::Hub';
|
| 22 |
+
|
| 23 |
+
my $hub = $class->new(%params);
|
| 24 |
+
|
| 25 |
+
if (@$self) {
|
| 26 |
+
$hub->inherit($self->[-1], %params);
|
| 27 |
+
}
|
| 28 |
+
else {
|
| 29 |
+
require Test2::API;
|
| 30 |
+
$hub->format(Test2::API::test2_formatter()->new_root)
|
| 31 |
+
unless $hub->format || exists($params{formatter});
|
| 32 |
+
|
| 33 |
+
my $ipc = Test2::API::test2_ipc();
|
| 34 |
+
if ($ipc && !$hub->ipc && !exists($params{ipc})) {
|
| 35 |
+
$hub->set_ipc($ipc);
|
| 36 |
+
$ipc->add_hub($hub->hid);
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
push @$self => $hub;
|
| 41 |
+
|
| 42 |
+
$hub;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
sub top {
|
| 46 |
+
my $self = shift;
|
| 47 |
+
return $self->new_hub unless @$self;
|
| 48 |
+
return $self->[-1];
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
sub peek {
|
| 52 |
+
my $self = shift;
|
| 53 |
+
return @$self ? $self->[-1] : undef;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
sub cull {
|
| 57 |
+
my $self = shift;
|
| 58 |
+
$_->cull for reverse @$self;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
sub all {
|
| 62 |
+
my $self = shift;
|
| 63 |
+
return @$self;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
sub clear {
|
| 67 |
+
my $self = shift;
|
| 68 |
+
@$self = ();
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
# Do these last without keywords in order to prevent them from getting used
|
| 72 |
+
# when we want the real push/pop.
|
| 73 |
+
|
| 74 |
+
{
|
| 75 |
+
no warnings 'once';
|
| 76 |
+
|
| 77 |
+
*push = sub {
|
| 78 |
+
my $self = shift;
|
| 79 |
+
my ($hub) = @_;
|
| 80 |
+
$hub->inherit($self->[-1]) if @$self;
|
| 81 |
+
push @$self => $hub;
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
*pop = sub {
|
| 85 |
+
my $self = shift;
|
| 86 |
+
my ($hub) = @_;
|
| 87 |
+
confess "No hubs on the stack"
|
| 88 |
+
unless @$self;
|
| 89 |
+
confess "You cannot pop the root hub"
|
| 90 |
+
if 1 == @$self;
|
| 91 |
+
confess "Hub stack mismatch, attempted to pop incorrect hub"
|
| 92 |
+
unless $self->[-1] == $hub;
|
| 93 |
+
pop @$self;
|
| 94 |
+
};
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
1;
|
| 98 |
+
|
| 99 |
+
__END__
|
| 100 |
+
|
| 101 |
+
=pod
|
| 102 |
+
|
| 103 |
+
=encoding UTF-8
|
| 104 |
+
|
| 105 |
+
=head1 NAME
|
| 106 |
+
|
| 107 |
+
Test2::API::Stack - Object to manage a stack of L<Test2::Hub>
|
| 108 |
+
instances.
|
| 109 |
+
|
| 110 |
+
=head1 ***INTERNALS NOTE***
|
| 111 |
+
|
| 112 |
+
B<The internals of this package are subject to change at any time!> The public
|
| 113 |
+
methods provided will not change in backwards incompatible ways, but the
|
| 114 |
+
underlying implementation details might. B<Do not break encapsulation here!>
|
| 115 |
+
|
| 116 |
+
=head1 DESCRIPTION
|
| 117 |
+
|
| 118 |
+
This module is used to represent and manage a stack of L<Test2::Hub>
|
| 119 |
+
objects. Hubs are usually in a stack so that you can push a new hub into place
|
| 120 |
+
that can intercept and handle events differently than the primary hub.
|
| 121 |
+
|
| 122 |
+
=head1 SYNOPSIS
|
| 123 |
+
|
| 124 |
+
my $stack = Test2::API::Stack->new;
|
| 125 |
+
my $hub = $stack->top;
|
| 126 |
+
|
| 127 |
+
=head1 METHODS
|
| 128 |
+
|
| 129 |
+
=over 4
|
| 130 |
+
|
| 131 |
+
=item $stack = Test2::API::Stack->new()
|
| 132 |
+
|
| 133 |
+
This will create a new empty stack instance. All arguments are ignored.
|
| 134 |
+
|
| 135 |
+
=item $hub = $stack->new_hub()
|
| 136 |
+
|
| 137 |
+
=item $hub = $stack->new_hub(%params)
|
| 138 |
+
|
| 139 |
+
=item $hub = $stack->new_hub(%params, class => $class)
|
| 140 |
+
|
| 141 |
+
This will generate a new hub and push it to the top of the stack. Optionally
|
| 142 |
+
you can provide arguments that will be passed into the constructor for the
|
| 143 |
+
L<Test2::Hub> object.
|
| 144 |
+
|
| 145 |
+
If you specify the C<< 'class' => $class >> argument, the new hub will be an
|
| 146 |
+
instance of the specified class.
|
| 147 |
+
|
| 148 |
+
Unless your parameters specify C<'formatter'> or C<'ipc'> arguments, the
|
| 149 |
+
formatter and IPC instance will be inherited from the current top hub. You can
|
| 150 |
+
set the parameters to C<undef> to avoid having a formatter or IPC instance.
|
| 151 |
+
|
| 152 |
+
If there is no top hub, and you do not ask to leave IPC and formatter undef,
|
| 153 |
+
then a new formatter will be created, and the IPC instance from
|
| 154 |
+
L<Test2::API> will be used.
|
| 155 |
+
|
| 156 |
+
=item $hub = $stack->top()
|
| 157 |
+
|
| 158 |
+
This will return the top hub from the stack. If there is no top hub yet this
|
| 159 |
+
will create it.
|
| 160 |
+
|
| 161 |
+
=item $hub = $stack->peek()
|
| 162 |
+
|
| 163 |
+
This will return the top hub from the stack. If there is no top hub yet this
|
| 164 |
+
will return undef.
|
| 165 |
+
|
| 166 |
+
=item $stack->cull
|
| 167 |
+
|
| 168 |
+
This will call C<< $hub->cull >> on all hubs in the stack.
|
| 169 |
+
|
| 170 |
+
=item @hubs = $stack->all
|
| 171 |
+
|
| 172 |
+
This will return all the hubs in the stack as a list.
|
| 173 |
+
|
| 174 |
+
=item $stack->clear
|
| 175 |
+
|
| 176 |
+
This will completely remove all hubs from the stack. Normally you do not want
|
| 177 |
+
to do this, but there are a few valid reasons for it.
|
| 178 |
+
|
| 179 |
+
=item $stack->push($hub)
|
| 180 |
+
|
| 181 |
+
This will push the new hub onto the stack.
|
| 182 |
+
|
| 183 |
+
=item $stack->pop($hub)
|
| 184 |
+
|
| 185 |
+
This will pop a hub from the stack, if the hub at the top of the stack does not
|
| 186 |
+
match the hub you expect (passed in as an argument) it will throw an exception.
|
| 187 |
+
|
| 188 |
+
=back
|
| 189 |
+
|
| 190 |
+
=head1 SOURCE
|
| 191 |
+
|
| 192 |
+
The source code repository for Test2 can be found at
|
| 193 |
+
F<http://github.com/Test-More/test-more/>.
|
| 194 |
+
|
| 195 |
+
=head1 MAINTAINERS
|
| 196 |
+
|
| 197 |
+
=over 4
|
| 198 |
+
|
| 199 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 200 |
+
|
| 201 |
+
=back
|
| 202 |
+
|
| 203 |
+
=head1 AUTHORS
|
| 204 |
+
|
| 205 |
+
=over 4
|
| 206 |
+
|
| 207 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 208 |
+
|
| 209 |
+
=back
|
| 210 |
+
|
| 211 |
+
=head1 COPYRIGHT
|
| 212 |
+
|
| 213 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 214 |
+
|
| 215 |
+
This program is free software; you can redistribute it and/or
|
| 216 |
+
modify it under the same terms as Perl itself.
|
| 217 |
+
|
| 218 |
+
See F<http://dev.perl.org/licenses/>
|
| 219 |
+
|
| 220 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Diag.pm
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Event::Diag;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
BEGIN { require Test2::Event; our @ISA = qw(Test2::Event) }
|
| 9 |
+
use Test2::Util::HashBase qw/message/;
|
| 10 |
+
|
| 11 |
+
sub init {
|
| 12 |
+
$_[0]->{+MESSAGE} = 'undef' unless defined $_[0]->{+MESSAGE};
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
sub summary { $_[0]->{+MESSAGE} }
|
| 16 |
+
|
| 17 |
+
sub diagnostics { 1 }
|
| 18 |
+
|
| 19 |
+
sub facet_data {
|
| 20 |
+
my $self = shift;
|
| 21 |
+
|
| 22 |
+
my $out = $self->common_facet_data;
|
| 23 |
+
|
| 24 |
+
$out->{info} = [
|
| 25 |
+
{
|
| 26 |
+
tag => 'DIAG',
|
| 27 |
+
debug => 1,
|
| 28 |
+
details => $self->{+MESSAGE},
|
| 29 |
+
}
|
| 30 |
+
];
|
| 31 |
+
|
| 32 |
+
return $out;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
1;
|
| 36 |
+
|
| 37 |
+
__END__
|
| 38 |
+
|
| 39 |
+
=pod
|
| 40 |
+
|
| 41 |
+
=encoding UTF-8
|
| 42 |
+
|
| 43 |
+
=head1 NAME
|
| 44 |
+
|
| 45 |
+
Test2::Event::Diag - Diag event type
|
| 46 |
+
|
| 47 |
+
=head1 DESCRIPTION
|
| 48 |
+
|
| 49 |
+
Diagnostics messages, typically rendered to STDERR.
|
| 50 |
+
|
| 51 |
+
=head1 SYNOPSIS
|
| 52 |
+
|
| 53 |
+
use Test2::API qw/context/;
|
| 54 |
+
use Test2::Event::Diag;
|
| 55 |
+
|
| 56 |
+
my $ctx = context();
|
| 57 |
+
my $event = $ctx->diag($message);
|
| 58 |
+
|
| 59 |
+
=head1 ACCESSORS
|
| 60 |
+
|
| 61 |
+
=over 4
|
| 62 |
+
|
| 63 |
+
=item $diag->message
|
| 64 |
+
|
| 65 |
+
The message for the diag.
|
| 66 |
+
|
| 67 |
+
=back
|
| 68 |
+
|
| 69 |
+
=head1 SOURCE
|
| 70 |
+
|
| 71 |
+
The source code repository for Test2 can be found at
|
| 72 |
+
F<http://github.com/Test-More/test-more/>.
|
| 73 |
+
|
| 74 |
+
=head1 MAINTAINERS
|
| 75 |
+
|
| 76 |
+
=over 4
|
| 77 |
+
|
| 78 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 79 |
+
|
| 80 |
+
=back
|
| 81 |
+
|
| 82 |
+
=head1 AUTHORS
|
| 83 |
+
|
| 84 |
+
=over 4
|
| 85 |
+
|
| 86 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 87 |
+
|
| 88 |
+
=back
|
| 89 |
+
|
| 90 |
+
=head1 COPYRIGHT
|
| 91 |
+
|
| 92 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 93 |
+
|
| 94 |
+
This program is free software; you can redistribute it and/or
|
| 95 |
+
modify it under the same terms as Perl itself.
|
| 96 |
+
|
| 97 |
+
See F<http://dev.perl.org/licenses/>
|
| 98 |
+
|
| 99 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Encoding.pm
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Event::Encoding;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
use Carp qw/croak/;
|
| 8 |
+
|
| 9 |
+
BEGIN { require Test2::Event; our @ISA = qw(Test2::Event) }
|
| 10 |
+
use Test2::Util::HashBase qw/encoding/;
|
| 11 |
+
|
| 12 |
+
sub init {
|
| 13 |
+
my $self = shift;
|
| 14 |
+
defined $self->{+ENCODING} or croak "'encoding' is a required attribute";
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
sub summary { 'Encoding set to ' . $_[0]->{+ENCODING} }
|
| 18 |
+
|
| 19 |
+
sub facet_data {
|
| 20 |
+
my $self = shift;
|
| 21 |
+
my $out = $self->common_facet_data;
|
| 22 |
+
$out->{control}->{encoding} = $self->{+ENCODING};
|
| 23 |
+
$out->{about}->{details} = $self->summary;
|
| 24 |
+
return $out;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
1;
|
| 29 |
+
|
| 30 |
+
__END__
|
| 31 |
+
|
| 32 |
+
=pod
|
| 33 |
+
|
| 34 |
+
=encoding UTF-8
|
| 35 |
+
|
| 36 |
+
=head1 NAME
|
| 37 |
+
|
| 38 |
+
Test2::Event::Encoding - Set the encoding for the output stream
|
| 39 |
+
|
| 40 |
+
=head1 DESCRIPTION
|
| 41 |
+
|
| 42 |
+
The encoding event is generated when a test file wants to specify the encoding
|
| 43 |
+
to be used when formatting its output. This event is intended to be produced
|
| 44 |
+
by formatter classes and used for interpreting test names, message contents,
|
| 45 |
+
etc.
|
| 46 |
+
|
| 47 |
+
=head1 SYNOPSIS
|
| 48 |
+
|
| 49 |
+
use Test2::API qw/context/;
|
| 50 |
+
use Test2::Event::Encoding;
|
| 51 |
+
|
| 52 |
+
my $ctx = context();
|
| 53 |
+
my $event = $ctx->send_event('Encoding', encoding => 'UTF-8');
|
| 54 |
+
|
| 55 |
+
=head1 METHODS
|
| 56 |
+
|
| 57 |
+
Inherits from L<Test2::Event>. Also defines:
|
| 58 |
+
|
| 59 |
+
=over 4
|
| 60 |
+
|
| 61 |
+
=item $encoding = $e->encoding
|
| 62 |
+
|
| 63 |
+
The encoding being specified.
|
| 64 |
+
|
| 65 |
+
=back
|
| 66 |
+
|
| 67 |
+
=head1 SOURCE
|
| 68 |
+
|
| 69 |
+
The source code repository for Test2 can be found at
|
| 70 |
+
F<http://github.com/Test-More/test-more/>.
|
| 71 |
+
|
| 72 |
+
=head1 MAINTAINERS
|
| 73 |
+
|
| 74 |
+
=over 4
|
| 75 |
+
|
| 76 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 77 |
+
|
| 78 |
+
=back
|
| 79 |
+
|
| 80 |
+
=head1 AUTHORS
|
| 81 |
+
|
| 82 |
+
=over 4
|
| 83 |
+
|
| 84 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 85 |
+
|
| 86 |
+
=back
|
| 87 |
+
|
| 88 |
+
=head1 COPYRIGHT
|
| 89 |
+
|
| 90 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 91 |
+
|
| 92 |
+
This program is free software; you can redistribute it and/or
|
| 93 |
+
modify it under the same terms as Perl itself.
|
| 94 |
+
|
| 95 |
+
See F<http://dev.perl.org/licenses/>
|
| 96 |
+
|
| 97 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Fail.pm
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Event::Fail;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
use Test2::EventFacet::Info;
|
| 8 |
+
|
| 9 |
+
BEGIN {
|
| 10 |
+
require Test2::Event;
|
| 11 |
+
our @ISA = qw(Test2::Event);
|
| 12 |
+
*META_KEY = \&Test2::Util::ExternalMeta::META_KEY;
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
use Test2::Util::HashBase qw{ -name -info };
|
| 16 |
+
|
| 17 |
+
#############
|
| 18 |
+
# Old API
|
| 19 |
+
sub summary { "fail" }
|
| 20 |
+
sub increments_count { 1 }
|
| 21 |
+
sub diagnostics { 0 }
|
| 22 |
+
sub no_display { 0 }
|
| 23 |
+
sub subtest_id { undef }
|
| 24 |
+
sub terminate { () }
|
| 25 |
+
sub global { () }
|
| 26 |
+
sub sets_plan { () }
|
| 27 |
+
|
| 28 |
+
sub causes_fail {
|
| 29 |
+
my $self = shift;
|
| 30 |
+
return 0 if $self->{+AMNESTY} && @{$self->{+AMNESTY}};
|
| 31 |
+
return 1;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
#############
|
| 35 |
+
# New API
|
| 36 |
+
|
| 37 |
+
sub add_info {
|
| 38 |
+
my $self = shift;
|
| 39 |
+
|
| 40 |
+
for my $in (@_) {
|
| 41 |
+
$in = {%$in} if ref($in) ne 'ARRAY';
|
| 42 |
+
$in = Test2::EventFacet::Info->new($in);
|
| 43 |
+
|
| 44 |
+
push @{$self->{+INFO}} => $in;
|
| 45 |
+
}
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
sub facet_data {
|
| 49 |
+
my $self = shift;
|
| 50 |
+
my $out = $self->common_facet_data;
|
| 51 |
+
|
| 52 |
+
$out->{about}->{details} = 'fail';
|
| 53 |
+
|
| 54 |
+
$out->{assert} = {pass => 0, details => $self->{+NAME}};
|
| 55 |
+
|
| 56 |
+
$out->{info} = [map {{ %{$_} }} @{$self->{+INFO}}] if $self->{+INFO};
|
| 57 |
+
|
| 58 |
+
return $out;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
1;
|
| 62 |
+
|
| 63 |
+
__END__
|
| 64 |
+
|
| 65 |
+
=pod
|
| 66 |
+
|
| 67 |
+
=encoding UTF-8
|
| 68 |
+
|
| 69 |
+
=head1 NAME
|
| 70 |
+
|
| 71 |
+
Test2::Event::Fail - Event for a simple failed assertion
|
| 72 |
+
|
| 73 |
+
=head1 DESCRIPTION
|
| 74 |
+
|
| 75 |
+
This is an optimal representation of a failed assertion.
|
| 76 |
+
|
| 77 |
+
=head1 SYNOPSIS
|
| 78 |
+
|
| 79 |
+
use Test2::API qw/context/;
|
| 80 |
+
|
| 81 |
+
sub fail {
|
| 82 |
+
my ($name) = @_;
|
| 83 |
+
my $ctx = context();
|
| 84 |
+
$ctx->fail($name);
|
| 85 |
+
$ctx->release;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
=head1 SOURCE
|
| 89 |
+
|
| 90 |
+
The source code repository for Test2 can be found at
|
| 91 |
+
F<http://github.com/Test-More/test-more/>.
|
| 92 |
+
|
| 93 |
+
=head1 MAINTAINERS
|
| 94 |
+
|
| 95 |
+
=over 4
|
| 96 |
+
|
| 97 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 98 |
+
|
| 99 |
+
=back
|
| 100 |
+
|
| 101 |
+
=head1 AUTHORS
|
| 102 |
+
|
| 103 |
+
=over 4
|
| 104 |
+
|
| 105 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 106 |
+
|
| 107 |
+
=back
|
| 108 |
+
|
| 109 |
+
=head1 COPYRIGHT
|
| 110 |
+
|
| 111 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 112 |
+
|
| 113 |
+
This program is free software; you can redistribute it and/or
|
| 114 |
+
modify it under the same terms as Perl itself.
|
| 115 |
+
|
| 116 |
+
See F<http://dev.perl.org/licenses/>
|
| 117 |
+
|
| 118 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Generic.pm
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Event::Generic;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
use Carp qw/croak/;
|
| 6 |
+
use Scalar::Util qw/reftype/;
|
| 7 |
+
|
| 8 |
+
our $VERSION = '1.302162';
|
| 9 |
+
|
| 10 |
+
BEGIN { require Test2::Event; our @ISA = qw(Test2::Event) }
|
| 11 |
+
use Test2::Util::HashBase;
|
| 12 |
+
|
| 13 |
+
my @FIELDS = qw{
|
| 14 |
+
causes_fail increments_count diagnostics no_display callback terminate
|
| 15 |
+
global sets_plan summary facet_data
|
| 16 |
+
};
|
| 17 |
+
my %DEFAULTS = (
|
| 18 |
+
causes_fail => 0,
|
| 19 |
+
increments_count => 0,
|
| 20 |
+
diagnostics => 0,
|
| 21 |
+
no_display => 0,
|
| 22 |
+
);
|
| 23 |
+
|
| 24 |
+
sub init {
|
| 25 |
+
my $self = shift;
|
| 26 |
+
|
| 27 |
+
for my $field (@FIELDS) {
|
| 28 |
+
my $val = defined $self->{$field} ? delete $self->{$field} : $DEFAULTS{$field};
|
| 29 |
+
next unless defined $val;
|
| 30 |
+
|
| 31 |
+
my $set = "set_$field";
|
| 32 |
+
$self->$set($val);
|
| 33 |
+
}
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
for my $field (@FIELDS) {
|
| 37 |
+
no strict 'refs';
|
| 38 |
+
|
| 39 |
+
*$field = sub { exists $_[0]->{$field} ? $_[0]->{$field} : () }
|
| 40 |
+
unless exists &{$field};
|
| 41 |
+
|
| 42 |
+
*{"set_$field"} = sub { $_[0]->{$field} = $_[1] }
|
| 43 |
+
unless exists &{"set_$field"};
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
sub can {
|
| 47 |
+
my $self = shift;
|
| 48 |
+
my ($name) = @_;
|
| 49 |
+
return $self->SUPER::can($name) unless $name eq 'callback';
|
| 50 |
+
return $self->{callback} || \&Test2::Event::callback;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
sub facet_data {
|
| 54 |
+
my $self = shift;
|
| 55 |
+
return $self->{facet_data} || $self->SUPER::facet_data();
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
sub summary {
|
| 59 |
+
my $self = shift;
|
| 60 |
+
return $self->{summary} if defined $self->{summary};
|
| 61 |
+
$self->SUPER::summary();
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
sub sets_plan {
|
| 65 |
+
my $self = shift;
|
| 66 |
+
return unless $self->{sets_plan};
|
| 67 |
+
return @{$self->{sets_plan}};
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
sub callback {
|
| 71 |
+
my $self = shift;
|
| 72 |
+
my $cb = $self->{callback} || return;
|
| 73 |
+
$self->$cb(@_);
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
sub set_global {
|
| 77 |
+
my $self = shift;
|
| 78 |
+
my ($bool) = @_;
|
| 79 |
+
|
| 80 |
+
if(!defined $bool) {
|
| 81 |
+
delete $self->{global};
|
| 82 |
+
return undef;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
$self->{global} = $bool;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
sub set_callback {
|
| 89 |
+
my $self = shift;
|
| 90 |
+
my ($cb) = @_;
|
| 91 |
+
|
| 92 |
+
if(!defined $cb) {
|
| 93 |
+
delete $self->{callback};
|
| 94 |
+
return undef;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
croak "callback must be a code reference"
|
| 98 |
+
unless ref($cb) && reftype($cb) eq 'CODE';
|
| 99 |
+
|
| 100 |
+
$self->{callback} = $cb;
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
sub set_terminate {
|
| 104 |
+
my $self = shift;
|
| 105 |
+
my ($exit) = @_;
|
| 106 |
+
|
| 107 |
+
if(!defined $exit) {
|
| 108 |
+
delete $self->{terminate};
|
| 109 |
+
return undef;
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
croak "terminate must be a positive integer"
|
| 113 |
+
unless $exit =~ m/^\d+$/;
|
| 114 |
+
|
| 115 |
+
$self->{terminate} = $exit;
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
sub set_sets_plan {
|
| 119 |
+
my $self = shift;
|
| 120 |
+
my ($plan) = @_;
|
| 121 |
+
|
| 122 |
+
if(!defined $plan) {
|
| 123 |
+
delete $self->{sets_plan};
|
| 124 |
+
return undef;
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
croak "'sets_plan' must be an array reference"
|
| 128 |
+
unless ref($plan) && reftype($plan) eq 'ARRAY';
|
| 129 |
+
|
| 130 |
+
$self->{sets_plan} = $plan;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
1;
|
| 134 |
+
|
| 135 |
+
__END__
|
| 136 |
+
|
| 137 |
+
=pod
|
| 138 |
+
|
| 139 |
+
=encoding UTF-8
|
| 140 |
+
|
| 141 |
+
=head1 NAME
|
| 142 |
+
|
| 143 |
+
Test2::Event::Generic - Generic event type.
|
| 144 |
+
|
| 145 |
+
=head1 DESCRIPTION
|
| 146 |
+
|
| 147 |
+
This is a generic event that lets you customize all fields in the event API.
|
| 148 |
+
This is useful if you have need for a custom event that does not make sense as
|
| 149 |
+
a published reusable event subclass.
|
| 150 |
+
|
| 151 |
+
=head1 SYNOPSIS
|
| 152 |
+
|
| 153 |
+
use Test2::API qw/context/;
|
| 154 |
+
|
| 155 |
+
sub send_custom_fail {
|
| 156 |
+
my $ctx = shift;
|
| 157 |
+
|
| 158 |
+
$ctx->send_event('Generic', causes_fail => 1, summary => 'The sky is falling');
|
| 159 |
+
|
| 160 |
+
$ctx->release;
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
send_custom_fail();
|
| 164 |
+
|
| 165 |
+
=head1 METHODS
|
| 166 |
+
|
| 167 |
+
=over 4
|
| 168 |
+
|
| 169 |
+
=item $e->facet_data($data)
|
| 170 |
+
|
| 171 |
+
=item $data = $e->facet_data
|
| 172 |
+
|
| 173 |
+
Get or set the facet data (see L<Test2::Event>). If no facet_data is set then
|
| 174 |
+
C<< Test2::Event->facet_data >> will be called to produce facets from the other
|
| 175 |
+
data.
|
| 176 |
+
|
| 177 |
+
=item $e->callback($hub)
|
| 178 |
+
|
| 179 |
+
Call the custom callback if one is set, otherwise this does nothing.
|
| 180 |
+
|
| 181 |
+
=item $e->set_callback(sub { ... })
|
| 182 |
+
|
| 183 |
+
Set the custom callback. The custom callback must be a coderef. The first
|
| 184 |
+
argument to your callback will be the event itself, the second will be the
|
| 185 |
+
L<Test2::Event::Hub> that is using the callback.
|
| 186 |
+
|
| 187 |
+
=item $bool = $e->causes_fail
|
| 188 |
+
|
| 189 |
+
=item $e->set_causes_fail($bool)
|
| 190 |
+
|
| 191 |
+
Get/Set the C<causes_fail> attribute. This defaults to C<0>.
|
| 192 |
+
|
| 193 |
+
=item $bool = $e->diagnostics
|
| 194 |
+
|
| 195 |
+
=item $e->set_diagnostics($bool)
|
| 196 |
+
|
| 197 |
+
Get/Set the C<diagnostics> attribute. This defaults to C<0>.
|
| 198 |
+
|
| 199 |
+
=item $bool_or_undef = $e->global
|
| 200 |
+
|
| 201 |
+
=item @bool_or_empty = $e->global
|
| 202 |
+
|
| 203 |
+
=item $e->set_global($bool_or_undef)
|
| 204 |
+
|
| 205 |
+
Get/Set the C<diagnostics> attribute. This defaults to an empty list which is
|
| 206 |
+
undef in scalar context.
|
| 207 |
+
|
| 208 |
+
=item $bool = $e->increments_count
|
| 209 |
+
|
| 210 |
+
=item $e->set_increments_count($bool)
|
| 211 |
+
|
| 212 |
+
Get/Set the C<increments_count> attribute. This defaults to C<0>.
|
| 213 |
+
|
| 214 |
+
=item $bool = $e->no_display
|
| 215 |
+
|
| 216 |
+
=item $e->set_no_display($bool)
|
| 217 |
+
|
| 218 |
+
Get/Set the C<no_display> attribute. This defaults to C<0>.
|
| 219 |
+
|
| 220 |
+
=item @plan = $e->sets_plan
|
| 221 |
+
|
| 222 |
+
Get the plan if this event sets one. The plan is a list of up to 3 items:
|
| 223 |
+
C<($count, $directive, $reason)>. C<$count> must be defined, the others may be
|
| 224 |
+
undef, or may not exist at all.
|
| 225 |
+
|
| 226 |
+
=item $e->set_sets_plan(\@plan)
|
| 227 |
+
|
| 228 |
+
Set the plan. You must pass in an arrayref with up to 3 elements.
|
| 229 |
+
|
| 230 |
+
=item $summary = $e->summary
|
| 231 |
+
|
| 232 |
+
=item $e->set_summary($summary_or_undef)
|
| 233 |
+
|
| 234 |
+
Get/Set the summary. This will default to the event package
|
| 235 |
+
C<'Test2::Event::Generic'>. You can set it to any value. Setting this to
|
| 236 |
+
C<undef> will reset it to the default.
|
| 237 |
+
|
| 238 |
+
=item $int_or_undef = $e->terminate
|
| 239 |
+
|
| 240 |
+
=item @int_or_empty = $e->terminate
|
| 241 |
+
|
| 242 |
+
=item $e->set_terminate($int_or_undef)
|
| 243 |
+
|
| 244 |
+
This will get/set the C<terminate> attribute. This defaults to undef in scalar
|
| 245 |
+
context, or an empty list in list context. Setting this to undef will clear it
|
| 246 |
+
completely. This must be set to a positive integer (0 or larger).
|
| 247 |
+
|
| 248 |
+
=back
|
| 249 |
+
|
| 250 |
+
=head1 SOURCE
|
| 251 |
+
|
| 252 |
+
The source code repository for Test2 can be found at
|
| 253 |
+
F<http://github.com/Test-More/test-more/>.
|
| 254 |
+
|
| 255 |
+
=head1 MAINTAINERS
|
| 256 |
+
|
| 257 |
+
=over 4
|
| 258 |
+
|
| 259 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 260 |
+
|
| 261 |
+
=back
|
| 262 |
+
|
| 263 |
+
=head1 AUTHORS
|
| 264 |
+
|
| 265 |
+
=over 4
|
| 266 |
+
|
| 267 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 268 |
+
|
| 269 |
+
=back
|
| 270 |
+
|
| 271 |
+
=head1 COPYRIGHT
|
| 272 |
+
|
| 273 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 274 |
+
|
| 275 |
+
This program is free software; you can redistribute it and/or
|
| 276 |
+
modify it under the same terms as Perl itself.
|
| 277 |
+
|
| 278 |
+
See F<http://dev.perl.org/licenses/>
|
| 279 |
+
|
| 280 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Note.pm
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Event::Note;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
BEGIN { require Test2::Event; our @ISA = qw(Test2::Event) }
|
| 9 |
+
use Test2::Util::HashBase qw/message/;
|
| 10 |
+
|
| 11 |
+
sub init {
|
| 12 |
+
$_[0]->{+MESSAGE} = 'undef' unless defined $_[0]->{+MESSAGE};
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
sub summary { $_[0]->{+MESSAGE} }
|
| 16 |
+
|
| 17 |
+
sub facet_data {
|
| 18 |
+
my $self = shift;
|
| 19 |
+
|
| 20 |
+
my $out = $self->common_facet_data;
|
| 21 |
+
|
| 22 |
+
$out->{info} = [
|
| 23 |
+
{
|
| 24 |
+
tag => 'NOTE',
|
| 25 |
+
debug => 0,
|
| 26 |
+
details => $self->{+MESSAGE},
|
| 27 |
+
}
|
| 28 |
+
];
|
| 29 |
+
|
| 30 |
+
return $out;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
1;
|
| 34 |
+
|
| 35 |
+
__END__
|
| 36 |
+
|
| 37 |
+
=pod
|
| 38 |
+
|
| 39 |
+
=encoding UTF-8
|
| 40 |
+
|
| 41 |
+
=head1 NAME
|
| 42 |
+
|
| 43 |
+
Test2::Event::Note - Note event type
|
| 44 |
+
|
| 45 |
+
=head1 DESCRIPTION
|
| 46 |
+
|
| 47 |
+
Notes, typically rendered to STDOUT.
|
| 48 |
+
|
| 49 |
+
=head1 SYNOPSIS
|
| 50 |
+
|
| 51 |
+
use Test2::API qw/context/;
|
| 52 |
+
use Test2::Event::Note;
|
| 53 |
+
|
| 54 |
+
my $ctx = context();
|
| 55 |
+
my $event = $ctx->Note($message);
|
| 56 |
+
|
| 57 |
+
=head1 ACCESSORS
|
| 58 |
+
|
| 59 |
+
=over 4
|
| 60 |
+
|
| 61 |
+
=item $note->message
|
| 62 |
+
|
| 63 |
+
The message for the note.
|
| 64 |
+
|
| 65 |
+
=back
|
| 66 |
+
|
| 67 |
+
=head1 SOURCE
|
| 68 |
+
|
| 69 |
+
The source code repository for Test2 can be found at
|
| 70 |
+
F<http://github.com/Test-More/test-more/>.
|
| 71 |
+
|
| 72 |
+
=head1 MAINTAINERS
|
| 73 |
+
|
| 74 |
+
=over 4
|
| 75 |
+
|
| 76 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 77 |
+
|
| 78 |
+
=back
|
| 79 |
+
|
| 80 |
+
=head1 AUTHORS
|
| 81 |
+
|
| 82 |
+
=over 4
|
| 83 |
+
|
| 84 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 85 |
+
|
| 86 |
+
=back
|
| 87 |
+
|
| 88 |
+
=head1 COPYRIGHT
|
| 89 |
+
|
| 90 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 91 |
+
|
| 92 |
+
This program is free software; you can redistribute it and/or
|
| 93 |
+
modify it under the same terms as Perl itself.
|
| 94 |
+
|
| 95 |
+
See F<http://dev.perl.org/licenses/>
|
| 96 |
+
|
| 97 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Pass.pm
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Event::Pass;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
use Test2::EventFacet::Info;
|
| 8 |
+
|
| 9 |
+
BEGIN {
|
| 10 |
+
require Test2::Event;
|
| 11 |
+
our @ISA = qw(Test2::Event);
|
| 12 |
+
*META_KEY = \&Test2::Util::ExternalMeta::META_KEY;
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
use Test2::Util::HashBase qw{ -name -info };
|
| 16 |
+
|
| 17 |
+
##############
|
| 18 |
+
# Old API
|
| 19 |
+
sub summary { "pass" }
|
| 20 |
+
sub increments_count { 1 }
|
| 21 |
+
sub causes_fail { 0 }
|
| 22 |
+
sub diagnostics { 0 }
|
| 23 |
+
sub no_display { 0 }
|
| 24 |
+
sub subtest_id { undef }
|
| 25 |
+
sub terminate { () }
|
| 26 |
+
sub global { () }
|
| 27 |
+
sub sets_plan { () }
|
| 28 |
+
|
| 29 |
+
##############
|
| 30 |
+
# New API
|
| 31 |
+
|
| 32 |
+
sub add_info {
|
| 33 |
+
my $self = shift;
|
| 34 |
+
|
| 35 |
+
for my $in (@_) {
|
| 36 |
+
$in = {%$in} if ref($in) ne 'ARRAY';
|
| 37 |
+
$in = Test2::EventFacet::Info->new($in);
|
| 38 |
+
|
| 39 |
+
push @{$self->{+INFO}} => $in;
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
sub facet_data {
|
| 44 |
+
my $self = shift;
|
| 45 |
+
|
| 46 |
+
my $out = $self->common_facet_data;
|
| 47 |
+
|
| 48 |
+
$out->{about}->{details} = 'pass';
|
| 49 |
+
|
| 50 |
+
$out->{assert} = {pass => 1, details => $self->{+NAME}};
|
| 51 |
+
|
| 52 |
+
$out->{info} = [map {{ %{$_} }} @{$self->{+INFO}}] if $self->{+INFO};
|
| 53 |
+
|
| 54 |
+
return $out;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
1;
|
| 58 |
+
|
| 59 |
+
__END__
|
| 60 |
+
|
| 61 |
+
=pod
|
| 62 |
+
|
| 63 |
+
=encoding UTF-8
|
| 64 |
+
|
| 65 |
+
=head1 NAME
|
| 66 |
+
|
| 67 |
+
Test2::Event::Pass - Event for a simple passing assertion
|
| 68 |
+
|
| 69 |
+
=head1 DESCRIPTION
|
| 70 |
+
|
| 71 |
+
This is an optimal representation of a passing assertion.
|
| 72 |
+
|
| 73 |
+
=head1 SYNOPSIS
|
| 74 |
+
|
| 75 |
+
use Test2::API qw/context/;
|
| 76 |
+
|
| 77 |
+
sub pass {
|
| 78 |
+
my ($name) = @_;
|
| 79 |
+
my $ctx = context();
|
| 80 |
+
$ctx->pass($name);
|
| 81 |
+
$ctx->release;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
=head1 SOURCE
|
| 85 |
+
|
| 86 |
+
The source code repository for Test2 can be found at
|
| 87 |
+
F<http://github.com/Test-More/test-more/>.
|
| 88 |
+
|
| 89 |
+
=head1 MAINTAINERS
|
| 90 |
+
|
| 91 |
+
=over 4
|
| 92 |
+
|
| 93 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 94 |
+
|
| 95 |
+
=back
|
| 96 |
+
|
| 97 |
+
=head1 AUTHORS
|
| 98 |
+
|
| 99 |
+
=over 4
|
| 100 |
+
|
| 101 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 102 |
+
|
| 103 |
+
=back
|
| 104 |
+
|
| 105 |
+
=head1 COPYRIGHT
|
| 106 |
+
|
| 107 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 108 |
+
|
| 109 |
+
This program is free software; you can redistribute it and/or
|
| 110 |
+
modify it under the same terms as Perl itself.
|
| 111 |
+
|
| 112 |
+
See F<http://dev.perl.org/licenses/>
|
| 113 |
+
|
| 114 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Plan.pm
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Event::Plan;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
BEGIN { require Test2::Event; our @ISA = qw(Test2::Event) }
|
| 9 |
+
use Test2::Util::HashBase qw{max directive reason};
|
| 10 |
+
|
| 11 |
+
use Carp qw/confess/;
|
| 12 |
+
|
| 13 |
+
my %ALLOWED = (
|
| 14 |
+
'SKIP' => 1,
|
| 15 |
+
'NO PLAN' => 1,
|
| 16 |
+
);
|
| 17 |
+
|
| 18 |
+
sub init {
|
| 19 |
+
if ($_[0]->{+DIRECTIVE}) {
|
| 20 |
+
$_[0]->{+DIRECTIVE} = 'SKIP' if $_[0]->{+DIRECTIVE} eq 'skip_all';
|
| 21 |
+
$_[0]->{+DIRECTIVE} = 'NO PLAN' if $_[0]->{+DIRECTIVE} eq 'no_plan';
|
| 22 |
+
|
| 23 |
+
confess "'" . $_[0]->{+DIRECTIVE} . "' is not a valid plan directive"
|
| 24 |
+
unless $ALLOWED{$_[0]->{+DIRECTIVE}};
|
| 25 |
+
}
|
| 26 |
+
else {
|
| 27 |
+
confess "Cannot have a reason without a directive!"
|
| 28 |
+
if defined $_[0]->{+REASON};
|
| 29 |
+
|
| 30 |
+
confess "No number of tests specified"
|
| 31 |
+
unless defined $_[0]->{+MAX};
|
| 32 |
+
|
| 33 |
+
confess "Plan test count '" . $_[0]->{+MAX} . "' does not appear to be a valid positive integer"
|
| 34 |
+
unless $_[0]->{+MAX} =~ m/^\d+$/;
|
| 35 |
+
|
| 36 |
+
$_[0]->{+DIRECTIVE} = '';
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
sub sets_plan {
|
| 41 |
+
my $self = shift;
|
| 42 |
+
return (
|
| 43 |
+
$self->{+MAX},
|
| 44 |
+
$self->{+DIRECTIVE},
|
| 45 |
+
$self->{+REASON},
|
| 46 |
+
);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
sub terminate {
|
| 50 |
+
my $self = shift;
|
| 51 |
+
# On skip_all we want to terminate the hub
|
| 52 |
+
return 0 if $self->{+DIRECTIVE} && $self->{+DIRECTIVE} eq 'SKIP';
|
| 53 |
+
return undef;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
sub summary {
|
| 57 |
+
my $self = shift;
|
| 58 |
+
my $max = $self->{+MAX};
|
| 59 |
+
my $directive = $self->{+DIRECTIVE};
|
| 60 |
+
my $reason = $self->{+REASON};
|
| 61 |
+
|
| 62 |
+
return "Plan is $max assertions"
|
| 63 |
+
if $max || !$directive;
|
| 64 |
+
|
| 65 |
+
return "Plan is '$directive', $reason"
|
| 66 |
+
if $reason;
|
| 67 |
+
|
| 68 |
+
return "Plan is '$directive'";
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
sub facet_data {
|
| 72 |
+
my $self = shift;
|
| 73 |
+
|
| 74 |
+
my $out = $self->common_facet_data;
|
| 75 |
+
|
| 76 |
+
$out->{control}->{terminate} = $self->{+DIRECTIVE} eq 'SKIP' ? 0 : undef
|
| 77 |
+
unless defined $out->{control}->{terminate};
|
| 78 |
+
|
| 79 |
+
$out->{plan} = {count => $self->{+MAX}};
|
| 80 |
+
$out->{plan}->{details} = $self->{+REASON} if defined $self->{+REASON};
|
| 81 |
+
|
| 82 |
+
if (my $dir = $self->{+DIRECTIVE}) {
|
| 83 |
+
$out->{plan}->{skip} = 1 if $dir eq 'SKIP';
|
| 84 |
+
$out->{plan}->{none} = 1 if $dir eq 'NO PLAN';
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
return $out;
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
1;
|
| 92 |
+
|
| 93 |
+
__END__
|
| 94 |
+
|
| 95 |
+
=pod
|
| 96 |
+
|
| 97 |
+
=encoding UTF-8
|
| 98 |
+
|
| 99 |
+
=head1 NAME
|
| 100 |
+
|
| 101 |
+
Test2::Event::Plan - The event of a plan
|
| 102 |
+
|
| 103 |
+
=head1 DESCRIPTION
|
| 104 |
+
|
| 105 |
+
Plan events are fired off whenever a plan is declared, done testing is called,
|
| 106 |
+
or a subtext completes.
|
| 107 |
+
|
| 108 |
+
=head1 SYNOPSIS
|
| 109 |
+
|
| 110 |
+
use Test2::API qw/context/;
|
| 111 |
+
use Test2::Event::Plan;
|
| 112 |
+
|
| 113 |
+
my $ctx = context();
|
| 114 |
+
|
| 115 |
+
# Plan for 10 tests to run
|
| 116 |
+
my $event = $ctx->plan(10);
|
| 117 |
+
|
| 118 |
+
# Plan to skip all tests (will exit 0)
|
| 119 |
+
$ctx->plan(0, skip_all => "These tests need to be skipped");
|
| 120 |
+
|
| 121 |
+
=head1 ACCESSORS
|
| 122 |
+
|
| 123 |
+
=over 4
|
| 124 |
+
|
| 125 |
+
=item $num = $plan->max
|
| 126 |
+
|
| 127 |
+
Get the number of expected tests
|
| 128 |
+
|
| 129 |
+
=item $dir = $plan->directive
|
| 130 |
+
|
| 131 |
+
Get the directive (such as TODO, skip_all, or no_plan).
|
| 132 |
+
|
| 133 |
+
=item $reason = $plan->reason
|
| 134 |
+
|
| 135 |
+
Get the reason for the directive.
|
| 136 |
+
|
| 137 |
+
=back
|
| 138 |
+
|
| 139 |
+
=head1 SOURCE
|
| 140 |
+
|
| 141 |
+
The source code repository for Test2 can be found at
|
| 142 |
+
F<http://github.com/Test-More/test-more/>.
|
| 143 |
+
|
| 144 |
+
=head1 MAINTAINERS
|
| 145 |
+
|
| 146 |
+
=over 4
|
| 147 |
+
|
| 148 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 149 |
+
|
| 150 |
+
=back
|
| 151 |
+
|
| 152 |
+
=head1 AUTHORS
|
| 153 |
+
|
| 154 |
+
=over 4
|
| 155 |
+
|
| 156 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 157 |
+
|
| 158 |
+
=back
|
| 159 |
+
|
| 160 |
+
=head1 COPYRIGHT
|
| 161 |
+
|
| 162 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 163 |
+
|
| 164 |
+
This program is free software; you can redistribute it and/or
|
| 165 |
+
modify it under the same terms as Perl itself.
|
| 166 |
+
|
| 167 |
+
See F<http://dev.perl.org/licenses/>
|
| 168 |
+
|
| 169 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Skip.pm
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Event::Skip;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
BEGIN { require Test2::Event::Ok; our @ISA = qw(Test2::Event::Ok) }
|
| 9 |
+
use Test2::Util::HashBase qw{reason};
|
| 10 |
+
|
| 11 |
+
sub init {
|
| 12 |
+
my $self = shift;
|
| 13 |
+
$self->SUPER::init;
|
| 14 |
+
$self->{+EFFECTIVE_PASS} = 1;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
sub causes_fail { 0 }
|
| 18 |
+
|
| 19 |
+
sub summary {
|
| 20 |
+
my $self = shift;
|
| 21 |
+
my $out = $self->SUPER::summary(@_);
|
| 22 |
+
|
| 23 |
+
if (my $reason = $self->reason) {
|
| 24 |
+
$out .= " (SKIP: $reason)";
|
| 25 |
+
}
|
| 26 |
+
else {
|
| 27 |
+
$out .= " (SKIP)";
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
return $out;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
sub extra_amnesty {
|
| 34 |
+
my $self = shift;
|
| 35 |
+
|
| 36 |
+
my @out;
|
| 37 |
+
|
| 38 |
+
push @out => {
|
| 39 |
+
tag => 'TODO',
|
| 40 |
+
details => $self->{+TODO},
|
| 41 |
+
} if defined $self->{+TODO};
|
| 42 |
+
|
| 43 |
+
push @out => {
|
| 44 |
+
tag => 'skip',
|
| 45 |
+
details => $self->{+REASON},
|
| 46 |
+
inherited => 0,
|
| 47 |
+
};
|
| 48 |
+
|
| 49 |
+
return @out;
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
1;
|
| 53 |
+
|
| 54 |
+
__END__
|
| 55 |
+
|
| 56 |
+
=pod
|
| 57 |
+
|
| 58 |
+
=encoding UTF-8
|
| 59 |
+
|
| 60 |
+
=head1 NAME
|
| 61 |
+
|
| 62 |
+
Test2::Event::Skip - Skip event type
|
| 63 |
+
|
| 64 |
+
=head1 DESCRIPTION
|
| 65 |
+
|
| 66 |
+
Skip events bump test counts just like L<Test2::Event::Ok> events, but
|
| 67 |
+
they can never fail.
|
| 68 |
+
|
| 69 |
+
=head1 SYNOPSIS
|
| 70 |
+
|
| 71 |
+
use Test2::API qw/context/;
|
| 72 |
+
use Test2::Event::Skip;
|
| 73 |
+
|
| 74 |
+
my $ctx = context();
|
| 75 |
+
my $event = $ctx->skip($name, $reason);
|
| 76 |
+
|
| 77 |
+
or:
|
| 78 |
+
|
| 79 |
+
my $ctx = context();
|
| 80 |
+
my $event = $ctx->send_event(
|
| 81 |
+
'Skip',
|
| 82 |
+
name => $name,
|
| 83 |
+
reason => $reason,
|
| 84 |
+
);
|
| 85 |
+
|
| 86 |
+
=head1 ACCESSORS
|
| 87 |
+
|
| 88 |
+
=over 4
|
| 89 |
+
|
| 90 |
+
=item $reason = $e->reason
|
| 91 |
+
|
| 92 |
+
The original true/false value of whatever was passed into the event (but
|
| 93 |
+
reduced down to 1 or 0).
|
| 94 |
+
|
| 95 |
+
=back
|
| 96 |
+
|
| 97 |
+
=head1 SOURCE
|
| 98 |
+
|
| 99 |
+
The source code repository for Test2 can be found at
|
| 100 |
+
F<http://github.com/Test-More/test-more/>.
|
| 101 |
+
|
| 102 |
+
=head1 MAINTAINERS
|
| 103 |
+
|
| 104 |
+
=over 4
|
| 105 |
+
|
| 106 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 107 |
+
|
| 108 |
+
=back
|
| 109 |
+
|
| 110 |
+
=head1 AUTHORS
|
| 111 |
+
|
| 112 |
+
=over 4
|
| 113 |
+
|
| 114 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 115 |
+
|
| 116 |
+
=back
|
| 117 |
+
|
| 118 |
+
=head1 COPYRIGHT
|
| 119 |
+
|
| 120 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 121 |
+
|
| 122 |
+
This program is free software; you can redistribute it and/or
|
| 123 |
+
modify it under the same terms as Perl itself.
|
| 124 |
+
|
| 125 |
+
See F<http://www.perl.com/perl/misc/Artistic.html>
|
| 126 |
+
|
| 127 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Subtest.pm
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Event::Subtest;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
BEGIN { require Test2::Event::Ok; our @ISA = qw(Test2::Event::Ok) }
|
| 8 |
+
use Test2::Util::HashBase qw{subevents buffered subtest_id subtest_uuid};
|
| 9 |
+
|
| 10 |
+
sub init {
|
| 11 |
+
my $self = shift;
|
| 12 |
+
$self->SUPER::init();
|
| 13 |
+
$self->{+SUBEVENTS} ||= [];
|
| 14 |
+
if ($self->{+EFFECTIVE_PASS}) {
|
| 15 |
+
$_->set_effective_pass(1) for grep { $_->can('effective_pass') } @{$self->{+SUBEVENTS}};
|
| 16 |
+
}
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
{
|
| 20 |
+
no warnings 'redefine';
|
| 21 |
+
|
| 22 |
+
sub set_subevents {
|
| 23 |
+
my $self = shift;
|
| 24 |
+
my @subevents = @_;
|
| 25 |
+
|
| 26 |
+
if ($self->{+EFFECTIVE_PASS}) {
|
| 27 |
+
$_->set_effective_pass(1) for grep { $_->can('effective_pass') } @subevents;
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
$self->{+SUBEVENTS} = \@subevents;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
sub set_effective_pass {
|
| 34 |
+
my $self = shift;
|
| 35 |
+
my ($pass) = @_;
|
| 36 |
+
|
| 37 |
+
if ($pass) {
|
| 38 |
+
$_->set_effective_pass(1) for grep { $_->can('effective_pass') } @{$self->{+SUBEVENTS}};
|
| 39 |
+
}
|
| 40 |
+
elsif ($self->{+EFFECTIVE_PASS} && !$pass) {
|
| 41 |
+
for my $s (grep { $_->can('effective_pass') } @{$self->{+SUBEVENTS}}) {
|
| 42 |
+
$_->set_effective_pass(0) unless $s->can('todo') && defined $s->todo;
|
| 43 |
+
}
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
$self->{+EFFECTIVE_PASS} = $pass;
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
sub summary {
|
| 51 |
+
my $self = shift;
|
| 52 |
+
|
| 53 |
+
my $name = $self->{+NAME} || "Nameless Subtest";
|
| 54 |
+
|
| 55 |
+
my $todo = $self->{+TODO};
|
| 56 |
+
if ($todo) {
|
| 57 |
+
$name .= " (TODO: $todo)";
|
| 58 |
+
}
|
| 59 |
+
elsif (defined $todo) {
|
| 60 |
+
$name .= " (TODO)";
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
return $name;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
sub facet_data {
|
| 67 |
+
my $self = shift;
|
| 68 |
+
|
| 69 |
+
my $out = $self->SUPER::facet_data();
|
| 70 |
+
|
| 71 |
+
$out->{parent} = {
|
| 72 |
+
hid => $self->subtest_id,
|
| 73 |
+
children => [map {$_->facet_data} @{$self->{+SUBEVENTS}}],
|
| 74 |
+
buffered => $self->{+BUFFERED},
|
| 75 |
+
};
|
| 76 |
+
|
| 77 |
+
return $out;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
sub add_amnesty {
|
| 81 |
+
my $self = shift;
|
| 82 |
+
|
| 83 |
+
for my $am (@_) {
|
| 84 |
+
$am = {%$am} if ref($am) ne 'ARRAY';
|
| 85 |
+
$am = Test2::EventFacet::Amnesty->new($am);
|
| 86 |
+
|
| 87 |
+
push @{$self->{+AMNESTY}} => $am;
|
| 88 |
+
|
| 89 |
+
for my $e (@{$self->{+SUBEVENTS}}) {
|
| 90 |
+
$e->add_amnesty($am->clone(inherited => 1));
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
1;
|
| 97 |
+
|
| 98 |
+
__END__
|
| 99 |
+
|
| 100 |
+
=pod
|
| 101 |
+
|
| 102 |
+
=encoding UTF-8
|
| 103 |
+
|
| 104 |
+
=head1 NAME
|
| 105 |
+
|
| 106 |
+
Test2::Event::Subtest - Event for subtest types
|
| 107 |
+
|
| 108 |
+
=head1 DESCRIPTION
|
| 109 |
+
|
| 110 |
+
This class represents a subtest. This class is a subclass of
|
| 111 |
+
L<Test2::Event::Ok>.
|
| 112 |
+
|
| 113 |
+
=head1 ACCESSORS
|
| 114 |
+
|
| 115 |
+
This class inherits from L<Test2::Event::Ok>.
|
| 116 |
+
|
| 117 |
+
=over 4
|
| 118 |
+
|
| 119 |
+
=item $arrayref = $e->subevents
|
| 120 |
+
|
| 121 |
+
Returns the arrayref containing all the events from the subtest
|
| 122 |
+
|
| 123 |
+
=item $bool = $e->buffered
|
| 124 |
+
|
| 125 |
+
True if the subtest is buffered, that is all subevents render at once. If this
|
| 126 |
+
is false it means all subevents render as they are produced.
|
| 127 |
+
|
| 128 |
+
=back
|
| 129 |
+
|
| 130 |
+
=head1 SOURCE
|
| 131 |
+
|
| 132 |
+
The source code repository for Test2 can be found at
|
| 133 |
+
F<http://github.com/Test-More/test-more/>.
|
| 134 |
+
|
| 135 |
+
=head1 MAINTAINERS
|
| 136 |
+
|
| 137 |
+
=over 4
|
| 138 |
+
|
| 139 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 140 |
+
|
| 141 |
+
=back
|
| 142 |
+
|
| 143 |
+
=head1 AUTHORS
|
| 144 |
+
|
| 145 |
+
=over 4
|
| 146 |
+
|
| 147 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 148 |
+
|
| 149 |
+
=back
|
| 150 |
+
|
| 151 |
+
=head1 COPYRIGHT
|
| 152 |
+
|
| 153 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 154 |
+
|
| 155 |
+
This program is free software; you can redistribute it and/or
|
| 156 |
+
modify it under the same terms as Perl itself.
|
| 157 |
+
|
| 158 |
+
See F<http://dev.perl.org/licenses/>
|
| 159 |
+
|
| 160 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/V2.pm
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Event::V2;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
use Scalar::Util qw/reftype/;
|
| 8 |
+
use Carp qw/croak/;
|
| 9 |
+
|
| 10 |
+
BEGIN { require Test2::Event; our @ISA = qw(Test2::Event) }
|
| 11 |
+
|
| 12 |
+
use Test2::Util::Facets2Legacy qw{
|
| 13 |
+
causes_fail diagnostics global increments_count no_display sets_plan
|
| 14 |
+
subtest_id summary terminate
|
| 15 |
+
};
|
| 16 |
+
|
| 17 |
+
use Test2::Util::HashBase qw/-about/;
|
| 18 |
+
|
| 19 |
+
sub non_facet_keys {
|
| 20 |
+
return (
|
| 21 |
+
+UUID,
|
| 22 |
+
Test2::Util::ExternalMeta::META_KEY(),
|
| 23 |
+
);
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
sub init {
|
| 27 |
+
my $self = shift;
|
| 28 |
+
|
| 29 |
+
my $uuid;
|
| 30 |
+
if ($uuid = $self->{+UUID}) {
|
| 31 |
+
croak "uuid '$uuid' passed to constructor, but uuid '$self->{+ABOUT}->{uuid}' is already set in the 'about' facet"
|
| 32 |
+
if $self->{+ABOUT}->{uuid} && $self->{+ABOUT}->{uuid} ne $uuid;
|
| 33 |
+
|
| 34 |
+
$self->{+ABOUT}->{uuid} = $uuid;
|
| 35 |
+
}
|
| 36 |
+
elsif ($uuid = $self->{+ABOUT}->{uuid}) {
|
| 37 |
+
$self->SUPER::set_uuid($uuid);
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
# Clone the trace, make sure it is blessed
|
| 41 |
+
if (my $trace = $self->{+TRACE}) {
|
| 42 |
+
$self->{+TRACE} = Test2::EventFacet::Trace->new(%$trace);
|
| 43 |
+
}
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
sub set_uuid {
|
| 47 |
+
my $self = shift;
|
| 48 |
+
my ($uuid) = @_;
|
| 49 |
+
$self->{+ABOUT}->{uuid} = $uuid;
|
| 50 |
+
$self->SUPER::set_uuid($uuid);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
sub facet_data {
|
| 54 |
+
my $self = shift;
|
| 55 |
+
my $f = { %{$self} };
|
| 56 |
+
|
| 57 |
+
delete $f->{$_} for $self->non_facet_keys;
|
| 58 |
+
|
| 59 |
+
my %out;
|
| 60 |
+
for my $k (keys %$f) {
|
| 61 |
+
next if substr($k, 0, 1) eq '_';
|
| 62 |
+
|
| 63 |
+
my $data = $f->{$k};
|
| 64 |
+
my $is_list = reftype($data) eq 'ARRAY';
|
| 65 |
+
$out{$k} = $is_list ? [ map { {%{$_}} } @$data ] : {%$data};
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
if (my $meta = $self->meta_facet_data) {
|
| 69 |
+
$out{meta} = {%$meta, %{$out{meta} || {}}};
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
return \%out;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
1;
|
| 76 |
+
|
| 77 |
+
__END__
|
| 78 |
+
|
| 79 |
+
=pod
|
| 80 |
+
|
| 81 |
+
=encoding UTF-8
|
| 82 |
+
|
| 83 |
+
=head1 NAME
|
| 84 |
+
|
| 85 |
+
Test2::Event::V2 - Second generation event.
|
| 86 |
+
|
| 87 |
+
=head1 DESCRIPTION
|
| 88 |
+
|
| 89 |
+
This is the event type that should be used instead of L<Test2::Event> or its
|
| 90 |
+
legacy subclasses.
|
| 91 |
+
|
| 92 |
+
=head1 SYNOPSIS
|
| 93 |
+
|
| 94 |
+
=head2 USING A CONTEXT
|
| 95 |
+
|
| 96 |
+
use Test2::API qw/context/;
|
| 97 |
+
|
| 98 |
+
sub my_tool {
|
| 99 |
+
my $ctx = context();
|
| 100 |
+
|
| 101 |
+
my $event = $ctx->send_ev2(info => [{tag => 'NOTE', details => "This is a note"}]);
|
| 102 |
+
|
| 103 |
+
$ctx->release;
|
| 104 |
+
|
| 105 |
+
return $event;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
=head2 USING THE CONSTRUCTOR
|
| 109 |
+
|
| 110 |
+
use Test2::Event::V2;
|
| 111 |
+
|
| 112 |
+
my $e = Test2::Event::V2->new(
|
| 113 |
+
trace => {frame => [$PKG, $FILE, $LINE, $SUBNAME]},
|
| 114 |
+
info => [{tag => 'NOTE', details => "This is a note"}],
|
| 115 |
+
);
|
| 116 |
+
|
| 117 |
+
=head1 METHODS
|
| 118 |
+
|
| 119 |
+
This class inherits from L<Test2::Event>.
|
| 120 |
+
|
| 121 |
+
=over 4
|
| 122 |
+
|
| 123 |
+
=item $fd = $e->facet_data()
|
| 124 |
+
|
| 125 |
+
This will return a hashref of facet data. Each facet hash will be a shallow
|
| 126 |
+
copy of the original.
|
| 127 |
+
|
| 128 |
+
=item $about = $e->about()
|
| 129 |
+
|
| 130 |
+
This will return the 'about' facet hashref.
|
| 131 |
+
|
| 132 |
+
B<NOTE:> This will return the internal hashref, not a copy.
|
| 133 |
+
|
| 134 |
+
=item $trace = $e->trace()
|
| 135 |
+
|
| 136 |
+
This will return the 'trace' facet, normally blessed (but this is not enforced
|
| 137 |
+
when the trace is set using C<set_trace()>.
|
| 138 |
+
|
| 139 |
+
B<NOTE:> This will return the internal trace, not a copy.
|
| 140 |
+
|
| 141 |
+
=back
|
| 142 |
+
|
| 143 |
+
=head2 MUTATION
|
| 144 |
+
|
| 145 |
+
=over 4
|
| 146 |
+
|
| 147 |
+
=item $e->add_amnesty({...})
|
| 148 |
+
|
| 149 |
+
Inherited from L<Test2::Event>. This can be used to add 'amnesty' facets to an
|
| 150 |
+
existing event. Each new item is added to the B<END> of the list.
|
| 151 |
+
|
| 152 |
+
B<NOTE:> Items B<ARE> blessed when added.
|
| 153 |
+
|
| 154 |
+
=item $e->add_hub({...})
|
| 155 |
+
|
| 156 |
+
Inherited from L<Test2::Event>. This is used by hubs to stamp events as they
|
| 157 |
+
pass through. New items are added to the B<START> of the list.
|
| 158 |
+
|
| 159 |
+
B<NOTE:> Items B<ARE NOT> blessed when added.
|
| 160 |
+
|
| 161 |
+
=item $e->set_uuid($UUID)
|
| 162 |
+
|
| 163 |
+
Inherited from L<Test2::Event>, overridden to also vivify/mutate the 'about'
|
| 164 |
+
facet.
|
| 165 |
+
|
| 166 |
+
=item $e->set_trace($trace)
|
| 167 |
+
|
| 168 |
+
Inherited from L<Test2::Event> which allows you to change the trace.
|
| 169 |
+
|
| 170 |
+
B<Note:> This method does not bless/clone the trace for you. Many things will
|
| 171 |
+
expect the trace to be blessed, so you should probably do that.
|
| 172 |
+
|
| 173 |
+
=back
|
| 174 |
+
|
| 175 |
+
=head2 LEGACY SUPPORT METHODS
|
| 176 |
+
|
| 177 |
+
These are all imported from L<Test2::Util::Facets2Legacy>, see that module or
|
| 178 |
+
L<Test2::Event> for documentation on what they do.
|
| 179 |
+
|
| 180 |
+
=over 4
|
| 181 |
+
|
| 182 |
+
=item causes_fail
|
| 183 |
+
|
| 184 |
+
=item diagnostics
|
| 185 |
+
|
| 186 |
+
=item global
|
| 187 |
+
|
| 188 |
+
=item increments_count
|
| 189 |
+
|
| 190 |
+
=item no_display
|
| 191 |
+
|
| 192 |
+
=item sets_plan
|
| 193 |
+
|
| 194 |
+
=item subtest_id
|
| 195 |
+
|
| 196 |
+
=item summary
|
| 197 |
+
|
| 198 |
+
=item terminate
|
| 199 |
+
|
| 200 |
+
=back
|
| 201 |
+
|
| 202 |
+
=head1 THIRD PARTY META-DATA
|
| 203 |
+
|
| 204 |
+
This object consumes L<Test2::Util::ExternalMeta> which provides a consistent
|
| 205 |
+
way for you to attach meta-data to instances of this class. This is useful for
|
| 206 |
+
tools, plugins, and other extensions.
|
| 207 |
+
|
| 208 |
+
=head1 SOURCE
|
| 209 |
+
|
| 210 |
+
The source code repository for Test2 can be found at
|
| 211 |
+
F<http://github.com/Test-More/test-more/>.
|
| 212 |
+
|
| 213 |
+
=head1 MAINTAINERS
|
| 214 |
+
|
| 215 |
+
=over 4
|
| 216 |
+
|
| 217 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 218 |
+
|
| 219 |
+
=back
|
| 220 |
+
|
| 221 |
+
=head1 AUTHORS
|
| 222 |
+
|
| 223 |
+
=over 4
|
| 224 |
+
|
| 225 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 226 |
+
|
| 227 |
+
=back
|
| 228 |
+
|
| 229 |
+
=head1 COPYRIGHT
|
| 230 |
+
|
| 231 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 232 |
+
|
| 233 |
+
This program is free software; you can redistribute it and/or
|
| 234 |
+
modify it under the same terms as Perl itself.
|
| 235 |
+
|
| 236 |
+
See F<http://dev.perl.org/licenses/>
|
| 237 |
+
|
| 238 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Event/Waiting.pm
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Event::Waiting;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
BEGIN { require Test2::Event; our @ISA = qw(Test2::Event) }
|
| 9 |
+
use Test2::Util::HashBase;
|
| 10 |
+
|
| 11 |
+
sub global { 1 };
|
| 12 |
+
|
| 13 |
+
sub summary { "IPC is waiting for children to finish..." }
|
| 14 |
+
|
| 15 |
+
sub facet_data {
|
| 16 |
+
my $self = shift;
|
| 17 |
+
|
| 18 |
+
my $out = $self->common_facet_data;
|
| 19 |
+
|
| 20 |
+
push @{$out->{info}} => {
|
| 21 |
+
tag => 'INFO',
|
| 22 |
+
debug => 0,
|
| 23 |
+
details => $self->summary,
|
| 24 |
+
};
|
| 25 |
+
|
| 26 |
+
return $out;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
1;
|
| 30 |
+
|
| 31 |
+
__END__
|
| 32 |
+
|
| 33 |
+
=pod
|
| 34 |
+
|
| 35 |
+
=encoding UTF-8
|
| 36 |
+
|
| 37 |
+
=head1 NAME
|
| 38 |
+
|
| 39 |
+
Test2::Event::Waiting - Tell all procs/threads it is time to be done
|
| 40 |
+
|
| 41 |
+
=head1 DESCRIPTION
|
| 42 |
+
|
| 43 |
+
This event has no data of its own. This event is sent out by the IPC system
|
| 44 |
+
when the main process/thread is ready to end.
|
| 45 |
+
|
| 46 |
+
=head1 SOURCE
|
| 47 |
+
|
| 48 |
+
The source code repository for Test2 can be found at
|
| 49 |
+
F<http://github.com/Test-More/test-more/>.
|
| 50 |
+
|
| 51 |
+
=head1 MAINTAINERS
|
| 52 |
+
|
| 53 |
+
=over 4
|
| 54 |
+
|
| 55 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 56 |
+
|
| 57 |
+
=back
|
| 58 |
+
|
| 59 |
+
=head1 AUTHORS
|
| 60 |
+
|
| 61 |
+
=over 4
|
| 62 |
+
|
| 63 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 64 |
+
|
| 65 |
+
=back
|
| 66 |
+
|
| 67 |
+
=head1 COPYRIGHT
|
| 68 |
+
|
| 69 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 70 |
+
|
| 71 |
+
This program is free software; you can redistribute it and/or
|
| 72 |
+
modify it under the same terms as Perl itself.
|
| 73 |
+
|
| 74 |
+
See F<http://dev.perl.org/licenses/>
|
| 75 |
+
|
| 76 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/About.pm
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::About;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 8 |
+
use Test2::Util::HashBase qw{ -package -no_display -uuid -eid };
|
| 9 |
+
|
| 10 |
+
1;
|
| 11 |
+
|
| 12 |
+
__END__
|
| 13 |
+
|
| 14 |
+
=pod
|
| 15 |
+
|
| 16 |
+
=encoding UTF-8
|
| 17 |
+
|
| 18 |
+
=head1 NAME
|
| 19 |
+
|
| 20 |
+
Test2::EventFacet::About - Facet with event details.
|
| 21 |
+
|
| 22 |
+
=head1 DESCRIPTION
|
| 23 |
+
|
| 24 |
+
This facet has information about the event, such as event package.
|
| 25 |
+
|
| 26 |
+
=head1 FIELDS
|
| 27 |
+
|
| 28 |
+
=over 4
|
| 29 |
+
|
| 30 |
+
=item $string = $about->{details}
|
| 31 |
+
|
| 32 |
+
=item $string = $about->details()
|
| 33 |
+
|
| 34 |
+
Summary about the event.
|
| 35 |
+
|
| 36 |
+
=item $package = $about->{package}
|
| 37 |
+
|
| 38 |
+
=item $package = $about->package()
|
| 39 |
+
|
| 40 |
+
Event package name.
|
| 41 |
+
|
| 42 |
+
=item $bool = $about->{no_display}
|
| 43 |
+
|
| 44 |
+
=item $bool = $about->no_display()
|
| 45 |
+
|
| 46 |
+
True if the event should be skipped by formatters.
|
| 47 |
+
|
| 48 |
+
=item $uuid = $about->{uuid}
|
| 49 |
+
|
| 50 |
+
=item $uuid = $about->uuid()
|
| 51 |
+
|
| 52 |
+
Will be set to a uuid if uuid tagging was enabled.
|
| 53 |
+
|
| 54 |
+
=item $uuid = $about->{eid}
|
| 55 |
+
|
| 56 |
+
=item $uuid = $about->eid()
|
| 57 |
+
|
| 58 |
+
A unique (for the test job) identifier for the event.
|
| 59 |
+
|
| 60 |
+
=back
|
| 61 |
+
|
| 62 |
+
=head1 SOURCE
|
| 63 |
+
|
| 64 |
+
The source code repository for Test2 can be found at
|
| 65 |
+
F<http://github.com/Test-More/test-more/>.
|
| 66 |
+
|
| 67 |
+
=head1 MAINTAINERS
|
| 68 |
+
|
| 69 |
+
=over 4
|
| 70 |
+
|
| 71 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 72 |
+
|
| 73 |
+
=back
|
| 74 |
+
|
| 75 |
+
=head1 AUTHORS
|
| 76 |
+
|
| 77 |
+
=over 4
|
| 78 |
+
|
| 79 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 80 |
+
|
| 81 |
+
=back
|
| 82 |
+
|
| 83 |
+
=head1 COPYRIGHT
|
| 84 |
+
|
| 85 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 86 |
+
|
| 87 |
+
This program is free software; you can redistribute it and/or
|
| 88 |
+
modify it under the same terms as Perl itself.
|
| 89 |
+
|
| 90 |
+
See F<http://dev.perl.org/licenses/>
|
| 91 |
+
|
| 92 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Amnesty.pm
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::Amnesty;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
sub is_list { 1 }
|
| 8 |
+
|
| 9 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 10 |
+
use Test2::Util::HashBase qw{ -tag -inherited };
|
| 11 |
+
|
| 12 |
+
1;
|
| 13 |
+
|
| 14 |
+
__END__
|
| 15 |
+
|
| 16 |
+
=pod
|
| 17 |
+
|
| 18 |
+
=encoding UTF-8
|
| 19 |
+
|
| 20 |
+
=head1 NAME
|
| 21 |
+
|
| 22 |
+
Test2::EventFacet::Amnesty - Facet for assertion amnesty.
|
| 23 |
+
|
| 24 |
+
=head1 DESCRIPTION
|
| 25 |
+
|
| 26 |
+
This package represents what is expected in units of amnesty.
|
| 27 |
+
|
| 28 |
+
=head1 NOTES
|
| 29 |
+
|
| 30 |
+
This facet appears in a list instead of being a single item.
|
| 31 |
+
|
| 32 |
+
=head1 FIELDS
|
| 33 |
+
|
| 34 |
+
=over 4
|
| 35 |
+
|
| 36 |
+
=item $string = $amnesty->{details}
|
| 37 |
+
|
| 38 |
+
=item $string = $amnesty->details()
|
| 39 |
+
|
| 40 |
+
Human readable explanation of why amnesty was granted.
|
| 41 |
+
|
| 42 |
+
Example: I<Not implemented yet, will fix>
|
| 43 |
+
|
| 44 |
+
=item $short_string = $amnesty->{tag}
|
| 45 |
+
|
| 46 |
+
=item $short_string = $amnesty->tag()
|
| 47 |
+
|
| 48 |
+
Short string (usually 10 characters or less, not enforced, but may be truncated
|
| 49 |
+
by renderers) categorizing the amnesty.
|
| 50 |
+
|
| 51 |
+
=item $bool = $amnesty->{inherited}
|
| 52 |
+
|
| 53 |
+
=item $bool = $amnesty->inherited()
|
| 54 |
+
|
| 55 |
+
This will be true if the amnesty was granted to a parent event and inherited by
|
| 56 |
+
this event, which is a child, such as an assertion within a subtest that is
|
| 57 |
+
marked todo.
|
| 58 |
+
|
| 59 |
+
=back
|
| 60 |
+
|
| 61 |
+
=head1 SOURCE
|
| 62 |
+
|
| 63 |
+
The source code repository for Test2 can be found at
|
| 64 |
+
F<http://github.com/Test-More/test-more/>.
|
| 65 |
+
|
| 66 |
+
=head1 MAINTAINERS
|
| 67 |
+
|
| 68 |
+
=over 4
|
| 69 |
+
|
| 70 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 71 |
+
|
| 72 |
+
=back
|
| 73 |
+
|
| 74 |
+
=head1 AUTHORS
|
| 75 |
+
|
| 76 |
+
=over 4
|
| 77 |
+
|
| 78 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 79 |
+
|
| 80 |
+
=back
|
| 81 |
+
|
| 82 |
+
=head1 COPYRIGHT
|
| 83 |
+
|
| 84 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 85 |
+
|
| 86 |
+
This program is free software; you can redistribute it and/or
|
| 87 |
+
modify it under the same terms as Perl itself.
|
| 88 |
+
|
| 89 |
+
See F<http://dev.perl.org/licenses/>
|
| 90 |
+
|
| 91 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Assert.pm
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::Assert;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 8 |
+
use Test2::Util::HashBase qw{ -pass -no_debug -number };
|
| 9 |
+
|
| 10 |
+
1;
|
| 11 |
+
|
| 12 |
+
__END__
|
| 13 |
+
|
| 14 |
+
=pod
|
| 15 |
+
|
| 16 |
+
=encoding UTF-8
|
| 17 |
+
|
| 18 |
+
=head1 NAME
|
| 19 |
+
|
| 20 |
+
Test2::EventFacet::Assert - Facet representing an assertion.
|
| 21 |
+
|
| 22 |
+
=head1 DESCRIPTION
|
| 23 |
+
|
| 24 |
+
The assertion facet is provided by any event representing an assertion that was
|
| 25 |
+
made.
|
| 26 |
+
|
| 27 |
+
=head1 FIELDS
|
| 28 |
+
|
| 29 |
+
=over 4
|
| 30 |
+
|
| 31 |
+
=item $string = $assert->{details}
|
| 32 |
+
|
| 33 |
+
=item $string = $assert->details()
|
| 34 |
+
|
| 35 |
+
Human readable description of the assertion.
|
| 36 |
+
|
| 37 |
+
=item $bool = $assert->{pass}
|
| 38 |
+
|
| 39 |
+
=item $bool = $assert->pass()
|
| 40 |
+
|
| 41 |
+
True if the assertion passed.
|
| 42 |
+
|
| 43 |
+
=item $bool = $assert->{no_debug}
|
| 44 |
+
|
| 45 |
+
=item $bool = $assert->no_debug()
|
| 46 |
+
|
| 47 |
+
Set this to true if you have provided custom diagnostics and do not want the
|
| 48 |
+
defaults to be displayed.
|
| 49 |
+
|
| 50 |
+
=item $int = $assert->{number}
|
| 51 |
+
|
| 52 |
+
=item $int = $assert->number()
|
| 53 |
+
|
| 54 |
+
(Optional) assertion number. This may be omitted or ignored. This is usually
|
| 55 |
+
only useful when parsing/processing TAP.
|
| 56 |
+
|
| 57 |
+
B<Note>: This is not set by the Test2 system, assertion number is not known
|
| 58 |
+
until AFTER the assertion has been processed. This attribute is part of the
|
| 59 |
+
spec only for harnesses.
|
| 60 |
+
|
| 61 |
+
=back
|
| 62 |
+
|
| 63 |
+
=head1 SOURCE
|
| 64 |
+
|
| 65 |
+
The source code repository for Test2 can be found at
|
| 66 |
+
F<http://github.com/Test-More/test-more/>.
|
| 67 |
+
|
| 68 |
+
=head1 MAINTAINERS
|
| 69 |
+
|
| 70 |
+
=over 4
|
| 71 |
+
|
| 72 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 73 |
+
|
| 74 |
+
=back
|
| 75 |
+
|
| 76 |
+
=head1 AUTHORS
|
| 77 |
+
|
| 78 |
+
=over 4
|
| 79 |
+
|
| 80 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 81 |
+
|
| 82 |
+
=back
|
| 83 |
+
|
| 84 |
+
=head1 COPYRIGHT
|
| 85 |
+
|
| 86 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 87 |
+
|
| 88 |
+
This program is free software; you can redistribute it and/or
|
| 89 |
+
modify it under the same terms as Perl itself.
|
| 90 |
+
|
| 91 |
+
See F<http://dev.perl.org/licenses/>
|
| 92 |
+
|
| 93 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Control.pm
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::Control;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 8 |
+
use Test2::Util::HashBase qw{ -global -terminate -halt -has_callback -encoding };
|
| 9 |
+
|
| 10 |
+
1;
|
| 11 |
+
|
| 12 |
+
__END__
|
| 13 |
+
|
| 14 |
+
=pod
|
| 15 |
+
|
| 16 |
+
=encoding UTF-8
|
| 17 |
+
|
| 18 |
+
=head1 NAME
|
| 19 |
+
|
| 20 |
+
Test2::EventFacet::Control - Facet for hub actions and behaviors.
|
| 21 |
+
|
| 22 |
+
=head1 DESCRIPTION
|
| 23 |
+
|
| 24 |
+
This facet is used when the event needs to give instructions to the Test2
|
| 25 |
+
internals.
|
| 26 |
+
|
| 27 |
+
=head1 FIELDS
|
| 28 |
+
|
| 29 |
+
=over 4
|
| 30 |
+
|
| 31 |
+
=item $string = $control->{details}
|
| 32 |
+
|
| 33 |
+
=item $string = $control->details()
|
| 34 |
+
|
| 35 |
+
Human readable explanation for the special behavior.
|
| 36 |
+
|
| 37 |
+
=item $bool = $control->{global}
|
| 38 |
+
|
| 39 |
+
=item $bool = $control->global()
|
| 40 |
+
|
| 41 |
+
True if the event is global in nature and should be seen by all hubs.
|
| 42 |
+
|
| 43 |
+
=item $exit = $control->{terminate}
|
| 44 |
+
|
| 45 |
+
=item $exit = $control->terminate()
|
| 46 |
+
|
| 47 |
+
Defined if the test should immediately exit, the value is the exit code and may
|
| 48 |
+
be C<0>.
|
| 49 |
+
|
| 50 |
+
=item $bool = $control->{halt}
|
| 51 |
+
|
| 52 |
+
=item $bool = $control->halt()
|
| 53 |
+
|
| 54 |
+
True if all testing should be halted immediately.
|
| 55 |
+
|
| 56 |
+
=item $bool = $control->{has_callback}
|
| 57 |
+
|
| 58 |
+
=item $bool = $control->has_callback()
|
| 59 |
+
|
| 60 |
+
True if the C<callback($hub)> method on the event should be called.
|
| 61 |
+
|
| 62 |
+
=item $encoding = $control->{encoding}
|
| 63 |
+
|
| 64 |
+
=item $encoding = $control->encoding()
|
| 65 |
+
|
| 66 |
+
This can be used to change the encoding from this event onward.
|
| 67 |
+
|
| 68 |
+
=back
|
| 69 |
+
|
| 70 |
+
=head1 SOURCE
|
| 71 |
+
|
| 72 |
+
The source code repository for Test2 can be found at
|
| 73 |
+
F<http://github.com/Test-More/test-more/>.
|
| 74 |
+
|
| 75 |
+
=head1 MAINTAINERS
|
| 76 |
+
|
| 77 |
+
=over 4
|
| 78 |
+
|
| 79 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 80 |
+
|
| 81 |
+
=back
|
| 82 |
+
|
| 83 |
+
=head1 AUTHORS
|
| 84 |
+
|
| 85 |
+
=over 4
|
| 86 |
+
|
| 87 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 88 |
+
|
| 89 |
+
=back
|
| 90 |
+
|
| 91 |
+
=head1 COPYRIGHT
|
| 92 |
+
|
| 93 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 94 |
+
|
| 95 |
+
This program is free software; you can redistribute it and/or
|
| 96 |
+
modify it under the same terms as Perl itself.
|
| 97 |
+
|
| 98 |
+
See F<http://dev.perl.org/licenses/>
|
| 99 |
+
|
| 100 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Error.pm
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::Error;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
sub facet_key { 'errors' }
|
| 8 |
+
sub is_list { 1 }
|
| 9 |
+
|
| 10 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 11 |
+
use Test2::Util::HashBase qw{ -tag -fail };
|
| 12 |
+
|
| 13 |
+
1;
|
| 14 |
+
|
| 15 |
+
__END__
|
| 16 |
+
|
| 17 |
+
=pod
|
| 18 |
+
|
| 19 |
+
=encoding UTF-8
|
| 20 |
+
|
| 21 |
+
=head1 NAME
|
| 22 |
+
|
| 23 |
+
Test2::EventFacet::Error - Facet for errors that need to be shown.
|
| 24 |
+
|
| 25 |
+
=head1 DESCRIPTION
|
| 26 |
+
|
| 27 |
+
This facet is used when an event needs to convey errors.
|
| 28 |
+
|
| 29 |
+
=head1 NOTES
|
| 30 |
+
|
| 31 |
+
This facet has the hash key C<'errors'>, and is a list of facets instead of a
|
| 32 |
+
single item.
|
| 33 |
+
|
| 34 |
+
=head1 FIELDS
|
| 35 |
+
|
| 36 |
+
=over 4
|
| 37 |
+
|
| 38 |
+
=item $string = $error->{details}
|
| 39 |
+
|
| 40 |
+
=item $string = $error->details()
|
| 41 |
+
|
| 42 |
+
Explanation of the error, or the error itself (such as an exception). In perl
|
| 43 |
+
exceptions may be blessed objects, so this field may contain a blessed object.
|
| 44 |
+
|
| 45 |
+
=item $short_string = $error->{tag}
|
| 46 |
+
|
| 47 |
+
=item $short_string = $error->tag()
|
| 48 |
+
|
| 49 |
+
Short tag to categorize the error. This is usually 10 characters or less,
|
| 50 |
+
formatters may truncate longer tags.
|
| 51 |
+
|
| 52 |
+
=item $bool = $error->{fail}
|
| 53 |
+
|
| 54 |
+
=item $bool = $error->fail()
|
| 55 |
+
|
| 56 |
+
Not all errors are fatal, some are displayed having already been handled. Set
|
| 57 |
+
this to true if you want the error to cause the test to fail. Without this the
|
| 58 |
+
error is simply a diagnostics message that has no effect on the overall
|
| 59 |
+
pass/fail result.
|
| 60 |
+
|
| 61 |
+
=back
|
| 62 |
+
|
| 63 |
+
=head1 SOURCE
|
| 64 |
+
|
| 65 |
+
The source code repository for Test2 can be found at
|
| 66 |
+
F<http://github.com/Test-More/test-more/>.
|
| 67 |
+
|
| 68 |
+
=head1 MAINTAINERS
|
| 69 |
+
|
| 70 |
+
=over 4
|
| 71 |
+
|
| 72 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 73 |
+
|
| 74 |
+
=back
|
| 75 |
+
|
| 76 |
+
=head1 AUTHORS
|
| 77 |
+
|
| 78 |
+
=over 4
|
| 79 |
+
|
| 80 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 81 |
+
|
| 82 |
+
=back
|
| 83 |
+
|
| 84 |
+
=head1 COPYRIGHT
|
| 85 |
+
|
| 86 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 87 |
+
|
| 88 |
+
This program is free software; you can redistribute it and/or
|
| 89 |
+
modify it under the same terms as Perl itself.
|
| 90 |
+
|
| 91 |
+
See F<http://dev.perl.org/licenses/>
|
| 92 |
+
|
| 93 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Hub.pm
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::Hub;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
sub is_list { 1 }
|
| 8 |
+
sub facet_key { 'hubs' }
|
| 9 |
+
|
| 10 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 11 |
+
use Test2::Util::HashBase qw{-pid -tid -hid -nested -buffered -uuid -ipc};
|
| 12 |
+
|
| 13 |
+
1;
|
| 14 |
+
|
| 15 |
+
__END__
|
| 16 |
+
|
| 17 |
+
=pod
|
| 18 |
+
|
| 19 |
+
=encoding UTF-8
|
| 20 |
+
|
| 21 |
+
=head1 NAME
|
| 22 |
+
|
| 23 |
+
Test2::EventFacet::Hub - Facet for the hubs an event passes through.
|
| 24 |
+
|
| 25 |
+
=head1 DESCRIPTION
|
| 26 |
+
|
| 27 |
+
These are a record of the hubs an event passes through. Most recent hub is the
|
| 28 |
+
first one in the list.
|
| 29 |
+
|
| 30 |
+
=head1 FACET FIELDS
|
| 31 |
+
|
| 32 |
+
=over 4
|
| 33 |
+
|
| 34 |
+
=item $string = $trace->{details}
|
| 35 |
+
|
| 36 |
+
=item $string = $trace->details()
|
| 37 |
+
|
| 38 |
+
The hub class or subclass
|
| 39 |
+
|
| 40 |
+
=item $int = $trace->{pid}
|
| 41 |
+
|
| 42 |
+
=item $int = $trace->pid()
|
| 43 |
+
|
| 44 |
+
PID of the hub this event was sent to.
|
| 45 |
+
|
| 46 |
+
=item $int = $trace->{tid}
|
| 47 |
+
|
| 48 |
+
=item $int = $trace->tid()
|
| 49 |
+
|
| 50 |
+
The thread ID of the hub the event was sent to.
|
| 51 |
+
|
| 52 |
+
=item $hid = $trace->{hid}
|
| 53 |
+
|
| 54 |
+
=item $hid = $trace->hid()
|
| 55 |
+
|
| 56 |
+
The ID of the hub that the event was send to.
|
| 57 |
+
|
| 58 |
+
=item $huuid = $trace->{huuid}
|
| 59 |
+
|
| 60 |
+
=item $huuid = $trace->huuid()
|
| 61 |
+
|
| 62 |
+
The UUID of the hub that the event was sent to.
|
| 63 |
+
|
| 64 |
+
=item $int = $trace->{nested}
|
| 65 |
+
|
| 66 |
+
=item $int = $trace->nested()
|
| 67 |
+
|
| 68 |
+
How deeply nested the hub was.
|
| 69 |
+
|
| 70 |
+
=item $bool = $trace->{buffered}
|
| 71 |
+
|
| 72 |
+
=item $bool = $trace->buffered()
|
| 73 |
+
|
| 74 |
+
True if the event was buffered and not sent to the formatter independent of a
|
| 75 |
+
parent (This should never be set when nested is C<0> or C<undef>).
|
| 76 |
+
|
| 77 |
+
=back
|
| 78 |
+
|
| 79 |
+
=head1 SOURCE
|
| 80 |
+
|
| 81 |
+
The source code repository for Test2 can be found at
|
| 82 |
+
F<http://github.com/Test-More/test-more/>.
|
| 83 |
+
|
| 84 |
+
=head1 MAINTAINERS
|
| 85 |
+
|
| 86 |
+
=over 4
|
| 87 |
+
|
| 88 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 89 |
+
|
| 90 |
+
=back
|
| 91 |
+
|
| 92 |
+
=head1 AUTHORS
|
| 93 |
+
|
| 94 |
+
=over 4
|
| 95 |
+
|
| 96 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 97 |
+
|
| 98 |
+
=back
|
| 99 |
+
|
| 100 |
+
=head1 COPYRIGHT
|
| 101 |
+
|
| 102 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 103 |
+
|
| 104 |
+
This program is free software; you can redistribute it and/or
|
| 105 |
+
modify it under the same terms as Perl itself.
|
| 106 |
+
|
| 107 |
+
See F<http://dev.perl.org/licenses/>
|
| 108 |
+
|
| 109 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Info.pm
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::Info;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
sub is_list { 1 }
|
| 8 |
+
|
| 9 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 10 |
+
use Test2::Util::HashBase qw{-tag -debug -important -table};
|
| 11 |
+
|
| 12 |
+
1;
|
| 13 |
+
|
| 14 |
+
__END__
|
| 15 |
+
|
| 16 |
+
=pod
|
| 17 |
+
|
| 18 |
+
=encoding UTF-8
|
| 19 |
+
|
| 20 |
+
=head1 NAME
|
| 21 |
+
|
| 22 |
+
Test2::EventFacet::Info - Facet for information a developer might care about.
|
| 23 |
+
|
| 24 |
+
=head1 DESCRIPTION
|
| 25 |
+
|
| 26 |
+
This facet represents messages intended for humans that will help them either
|
| 27 |
+
understand a result, or diagnose a failure.
|
| 28 |
+
|
| 29 |
+
=head1 NOTES
|
| 30 |
+
|
| 31 |
+
This facet appears in a list instead of being a single item.
|
| 32 |
+
|
| 33 |
+
=head1 FIELDS
|
| 34 |
+
|
| 35 |
+
=over 4
|
| 36 |
+
|
| 37 |
+
=item $string_or_structure = $info->{details}
|
| 38 |
+
|
| 39 |
+
=item $string_or_structure = $info->details()
|
| 40 |
+
|
| 41 |
+
Human readable string or data structure, this is the information to display.
|
| 42 |
+
Formatters are free to render the structures however they please. This may
|
| 43 |
+
contain a blessed object.
|
| 44 |
+
|
| 45 |
+
If the C<table> attribute (see below) is set then a renderer may choose to
|
| 46 |
+
display the table instead of the details.
|
| 47 |
+
|
| 48 |
+
=item $structure = $info->{table}
|
| 49 |
+
|
| 50 |
+
=item $structure = $info->table()
|
| 51 |
+
|
| 52 |
+
If the data the C<info> facet needs to convey can be represented as a table
|
| 53 |
+
then the data may be placed in this attribute in a more raw form for better
|
| 54 |
+
display. The data must also be represented in the C<details> attribute for
|
| 55 |
+
renderers which do not support rendering tables directly.
|
| 56 |
+
|
| 57 |
+
The table structure:
|
| 58 |
+
|
| 59 |
+
my %table = {
|
| 60 |
+
header => [ 'column 1 header', 'column 2 header', ... ], # Optional
|
| 61 |
+
|
| 62 |
+
rows => [
|
| 63 |
+
['row 1 column 1', 'row 1, column 2', ... ],
|
| 64 |
+
['row 2 column 1', 'row 2, column 2', ... ],
|
| 65 |
+
...
|
| 66 |
+
],
|
| 67 |
+
|
| 68 |
+
# Allow the renderer to hide empty columns when true, Optional
|
| 69 |
+
collapse => $BOOL,
|
| 70 |
+
|
| 71 |
+
# List by name or number columns that should never be collapsed
|
| 72 |
+
no_collapse => \@LIST,
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
=item $short_string = $info->{tag}
|
| 76 |
+
|
| 77 |
+
=item $short_string = $info->tag()
|
| 78 |
+
|
| 79 |
+
Short tag to categorize the info. This is usually 10 characters or less,
|
| 80 |
+
formatters may truncate longer tags.
|
| 81 |
+
|
| 82 |
+
=item $bool = $info->{debug}
|
| 83 |
+
|
| 84 |
+
=item $bool = $info->debug()
|
| 85 |
+
|
| 86 |
+
Set this to true if the message is critical, or explains a failure. This is
|
| 87 |
+
info that should be displayed by formatters even in less-verbose modes.
|
| 88 |
+
|
| 89 |
+
When false the information is not considered critical and may not be rendered
|
| 90 |
+
in less-verbose modes.
|
| 91 |
+
|
| 92 |
+
=item $bool = $info->{important}
|
| 93 |
+
|
| 94 |
+
=item $bool = $info->important
|
| 95 |
+
|
| 96 |
+
This should be set for non debug messages that are still important enough to
|
| 97 |
+
show when a formatter is in quiet mode. A formatter should send these to STDOUT
|
| 98 |
+
not STDERR, but should show them even in non-verbose mode.
|
| 99 |
+
|
| 100 |
+
=back
|
| 101 |
+
|
| 102 |
+
=head1 SOURCE
|
| 103 |
+
|
| 104 |
+
The source code repository for Test2 can be found at
|
| 105 |
+
F<http://github.com/Test-More/test-more/>.
|
| 106 |
+
|
| 107 |
+
=head1 MAINTAINERS
|
| 108 |
+
|
| 109 |
+
=over 4
|
| 110 |
+
|
| 111 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 112 |
+
|
| 113 |
+
=back
|
| 114 |
+
|
| 115 |
+
=head1 AUTHORS
|
| 116 |
+
|
| 117 |
+
=over 4
|
| 118 |
+
|
| 119 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 120 |
+
|
| 121 |
+
=back
|
| 122 |
+
|
| 123 |
+
=head1 COPYRIGHT
|
| 124 |
+
|
| 125 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 126 |
+
|
| 127 |
+
This program is free software; you can redistribute it and/or
|
| 128 |
+
modify it under the same terms as Perl itself.
|
| 129 |
+
|
| 130 |
+
See F<http://dev.perl.org/licenses/>
|
| 131 |
+
|
| 132 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Meta.pm
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::Meta;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 8 |
+
use vars qw/$AUTOLOAD/;
|
| 9 |
+
|
| 10 |
+
# replace set_details
|
| 11 |
+
{
|
| 12 |
+
no warnings 'redefine';
|
| 13 |
+
sub set_details { $_[0]->{'set_details'} }
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
sub can {
|
| 17 |
+
my $self = shift;
|
| 18 |
+
my ($name) = @_;
|
| 19 |
+
|
| 20 |
+
my $existing = $self->SUPER::can($name);
|
| 21 |
+
return $existing if $existing;
|
| 22 |
+
|
| 23 |
+
# Only vivify when called on an instance, do not vivify for a class. There
|
| 24 |
+
# are a lot of magic class methods used in things like serialization (or
|
| 25 |
+
# the forks.pm module) which cause problems when vivified.
|
| 26 |
+
return undef unless ref($self);
|
| 27 |
+
|
| 28 |
+
my $sub = sub { $_[0]->{$name} };
|
| 29 |
+
{
|
| 30 |
+
no strict 'refs';
|
| 31 |
+
*$name = $sub;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
return $sub;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
sub AUTOLOAD {
|
| 38 |
+
my $name = $AUTOLOAD;
|
| 39 |
+
$name =~ s/^.*:://g;
|
| 40 |
+
my $sub = $_[0]->can($name);
|
| 41 |
+
goto &$sub;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
1;
|
| 45 |
+
|
| 46 |
+
__END__
|
| 47 |
+
|
| 48 |
+
=pod
|
| 49 |
+
|
| 50 |
+
=encoding UTF-8
|
| 51 |
+
|
| 52 |
+
=head1 NAME
|
| 53 |
+
|
| 54 |
+
Test2::EventFacet::Meta - Facet for meta-data
|
| 55 |
+
|
| 56 |
+
=head1 DESCRIPTION
|
| 57 |
+
|
| 58 |
+
This facet can contain any random meta-data that has been attached to the
|
| 59 |
+
event.
|
| 60 |
+
|
| 61 |
+
=head1 METHODS AND FIELDS
|
| 62 |
+
|
| 63 |
+
Any/all fields and accessors are autovivified into existence. There is no way
|
| 64 |
+
to know what metadata may be added, so any is allowed.
|
| 65 |
+
|
| 66 |
+
=over 4
|
| 67 |
+
|
| 68 |
+
=item $anything = $meta->{anything}
|
| 69 |
+
|
| 70 |
+
=item $anything = $meta->anything()
|
| 71 |
+
|
| 72 |
+
=back
|
| 73 |
+
|
| 74 |
+
=head1 SOURCE
|
| 75 |
+
|
| 76 |
+
The source code repository for Test2 can be found at
|
| 77 |
+
F<http://github.com/Test-More/test-more/>.
|
| 78 |
+
|
| 79 |
+
=head1 MAINTAINERS
|
| 80 |
+
|
| 81 |
+
=over 4
|
| 82 |
+
|
| 83 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 84 |
+
|
| 85 |
+
=back
|
| 86 |
+
|
| 87 |
+
=head1 AUTHORS
|
| 88 |
+
|
| 89 |
+
=over 4
|
| 90 |
+
|
| 91 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 92 |
+
|
| 93 |
+
=back
|
| 94 |
+
|
| 95 |
+
=head1 COPYRIGHT
|
| 96 |
+
|
| 97 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 98 |
+
|
| 99 |
+
This program is free software; you can redistribute it and/or
|
| 100 |
+
modify it under the same terms as Perl itself.
|
| 101 |
+
|
| 102 |
+
See F<http://dev.perl.org/licenses/>
|
| 103 |
+
|
| 104 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Parent.pm
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::Parent;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
use Carp qw/confess/;
|
| 8 |
+
|
| 9 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 10 |
+
use Test2::Util::HashBase qw{ -hid -children -buffered };
|
| 11 |
+
|
| 12 |
+
sub init {
|
| 13 |
+
confess "Attribute 'hid' must be set"
|
| 14 |
+
unless defined $_[0]->{+HID};
|
| 15 |
+
|
| 16 |
+
$_[0]->{+CHILDREN} ||= [];
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
1;
|
| 20 |
+
|
| 21 |
+
__END__
|
| 22 |
+
|
| 23 |
+
=pod
|
| 24 |
+
|
| 25 |
+
=encoding UTF-8
|
| 26 |
+
|
| 27 |
+
=head1 NAME
|
| 28 |
+
|
| 29 |
+
Test2::EventFacet::Parent - Facet for events contains other events
|
| 30 |
+
|
| 31 |
+
=head1 DESCRIPTION
|
| 32 |
+
|
| 33 |
+
This facet is used when an event contains other events, such as a subtest.
|
| 34 |
+
|
| 35 |
+
=head1 FIELDS
|
| 36 |
+
|
| 37 |
+
=over 4
|
| 38 |
+
|
| 39 |
+
=item $string = $parent->{details}
|
| 40 |
+
|
| 41 |
+
=item $string = $parent->details()
|
| 42 |
+
|
| 43 |
+
Human readable description of the event.
|
| 44 |
+
|
| 45 |
+
=item $hid = $parent->{hid}
|
| 46 |
+
|
| 47 |
+
=item $hid = $parent->hid()
|
| 48 |
+
|
| 49 |
+
Hub ID of the hub that is represented in the parent-child relationship.
|
| 50 |
+
|
| 51 |
+
=item $arrayref = $parent->{children}
|
| 52 |
+
|
| 53 |
+
=item $arrayref = $parent->children()
|
| 54 |
+
|
| 55 |
+
Arrayref containing the facet-data hashes of events nested under this one.
|
| 56 |
+
|
| 57 |
+
I<To get the actual events you need to get them from the parent event directly>
|
| 58 |
+
|
| 59 |
+
=item $bool = $parent->{buffered}
|
| 60 |
+
|
| 61 |
+
=item $bool = $parent->buffered()
|
| 62 |
+
|
| 63 |
+
True if the subtest is buffered (meaning the formatter has probably not seen
|
| 64 |
+
them yet).
|
| 65 |
+
|
| 66 |
+
=back
|
| 67 |
+
|
| 68 |
+
=head1 SOURCE
|
| 69 |
+
|
| 70 |
+
The source code repository for Test2 can be found at
|
| 71 |
+
F<http://github.com/Test-More/test-more/>.
|
| 72 |
+
|
| 73 |
+
=head1 MAINTAINERS
|
| 74 |
+
|
| 75 |
+
=over 4
|
| 76 |
+
|
| 77 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 78 |
+
|
| 79 |
+
=back
|
| 80 |
+
|
| 81 |
+
=head1 AUTHORS
|
| 82 |
+
|
| 83 |
+
=over 4
|
| 84 |
+
|
| 85 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 86 |
+
|
| 87 |
+
=back
|
| 88 |
+
|
| 89 |
+
=head1 COPYRIGHT
|
| 90 |
+
|
| 91 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 92 |
+
|
| 93 |
+
This program is free software; you can redistribute it and/or
|
| 94 |
+
modify it under the same terms as Perl itself.
|
| 95 |
+
|
| 96 |
+
See F<http://dev.perl.org/licenses/>
|
| 97 |
+
|
| 98 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Plan.pm
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::Plan;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 8 |
+
use Test2::Util::HashBase qw{ -count -skip -none };
|
| 9 |
+
|
| 10 |
+
1;
|
| 11 |
+
|
| 12 |
+
__END__
|
| 13 |
+
|
| 14 |
+
=pod
|
| 15 |
+
|
| 16 |
+
=encoding UTF-8
|
| 17 |
+
|
| 18 |
+
=head1 NAME
|
| 19 |
+
|
| 20 |
+
Test2::EventFacet::Plan - Facet for setting the plan
|
| 21 |
+
|
| 22 |
+
=head1 DESCRIPTION
|
| 23 |
+
|
| 24 |
+
Events use this facet when they need to set the plan.
|
| 25 |
+
|
| 26 |
+
=head1 FIELDS
|
| 27 |
+
|
| 28 |
+
=over 4
|
| 29 |
+
|
| 30 |
+
=item $string = $plan->{details}
|
| 31 |
+
|
| 32 |
+
=item $string = $plan->details()
|
| 33 |
+
|
| 34 |
+
Human readable explanation for the plan being set. This is normally not
|
| 35 |
+
rendered by most formatters except when the C<skip> field is also set.
|
| 36 |
+
|
| 37 |
+
=item $positive_int = $plan->{count}
|
| 38 |
+
|
| 39 |
+
=item $positive_int = $plan->count()
|
| 40 |
+
|
| 41 |
+
Set the number of expected assertions. This should usually be set to C<0> when
|
| 42 |
+
C<skip> or C<none> are also set.
|
| 43 |
+
|
| 44 |
+
=item $bool = $plan->{skip}
|
| 45 |
+
|
| 46 |
+
=item $bool = $plan->skip()
|
| 47 |
+
|
| 48 |
+
When true the entire test should be skipped. This is usually paired with an
|
| 49 |
+
explanation in the C<details> field, and a C<control> facet that has
|
| 50 |
+
C<terminate> set to C<0>.
|
| 51 |
+
|
| 52 |
+
=item $bool = $plan->{none}
|
| 53 |
+
|
| 54 |
+
=item $bool = $plan->none()
|
| 55 |
+
|
| 56 |
+
This is mainly used by legacy L<Test::Builder> tests which set the plan to C<no
|
| 57 |
+
plan>, a construct that predates the much better C<done_testing()>.
|
| 58 |
+
|
| 59 |
+
If you are using this in non-legacy code you may need to reconsider the course
|
| 60 |
+
of your life, maybe a hermitage would suite you?
|
| 61 |
+
|
| 62 |
+
=back
|
| 63 |
+
|
| 64 |
+
=head1 SOURCE
|
| 65 |
+
|
| 66 |
+
The source code repository for Test2 can be found at
|
| 67 |
+
F<http://github.com/Test-More/test-more/>.
|
| 68 |
+
|
| 69 |
+
=head1 MAINTAINERS
|
| 70 |
+
|
| 71 |
+
=over 4
|
| 72 |
+
|
| 73 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 74 |
+
|
| 75 |
+
=back
|
| 76 |
+
|
| 77 |
+
=head1 AUTHORS
|
| 78 |
+
|
| 79 |
+
=over 4
|
| 80 |
+
|
| 81 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 82 |
+
|
| 83 |
+
=back
|
| 84 |
+
|
| 85 |
+
=head1 COPYRIGHT
|
| 86 |
+
|
| 87 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 88 |
+
|
| 89 |
+
This program is free software; you can redistribute it and/or
|
| 90 |
+
modify it under the same terms as Perl itself.
|
| 91 |
+
|
| 92 |
+
See F<http://dev.perl.org/licenses/>
|
| 93 |
+
|
| 94 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Render.pm
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::Render;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
sub is_list { 1 }
|
| 8 |
+
|
| 9 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 10 |
+
use Test2::Util::HashBase qw{ -tag -facet -mode };
|
| 11 |
+
|
| 12 |
+
1;
|
| 13 |
+
|
| 14 |
+
__END__
|
| 15 |
+
|
| 16 |
+
=pod
|
| 17 |
+
|
| 18 |
+
=encoding UTF-8
|
| 19 |
+
|
| 20 |
+
=head1 NAME
|
| 21 |
+
|
| 22 |
+
Test2::EventFacet::Render - Facet that dictates how to render an event.
|
| 23 |
+
|
| 24 |
+
=head1 DESCRIPTION
|
| 25 |
+
|
| 26 |
+
This facet is used to dictate how the event should be rendered by the standard
|
| 27 |
+
test2 rendering tools. If this facet is present then ONLY what is specified by
|
| 28 |
+
it will be rendered. It is assumed that anything important or note-worthy will
|
| 29 |
+
be present here, no other facets will be considered for rendering/display.
|
| 30 |
+
|
| 31 |
+
This facet is a list type, you can add as many items as needed.
|
| 32 |
+
|
| 33 |
+
=head1 FIELDS
|
| 34 |
+
|
| 35 |
+
=over 4
|
| 36 |
+
|
| 37 |
+
=item $string = $render->[#]->{details}
|
| 38 |
+
|
| 39 |
+
=item $string = $render->[#]->details()
|
| 40 |
+
|
| 41 |
+
Human readable text for display.
|
| 42 |
+
|
| 43 |
+
=item $string = $render->[#]->{tag}
|
| 44 |
+
|
| 45 |
+
=item $string = $render->[#]->tag()
|
| 46 |
+
|
| 47 |
+
Tag that should prefix/identify the main text.
|
| 48 |
+
|
| 49 |
+
=item $string = $render->[#]->{facet}
|
| 50 |
+
|
| 51 |
+
=item $string = $render->[#]->facet()
|
| 52 |
+
|
| 53 |
+
Optional, if the display text was generated from another facet this should
|
| 54 |
+
state what facet it was.
|
| 55 |
+
|
| 56 |
+
=item $mode = $render->[#]->{mode}
|
| 57 |
+
|
| 58 |
+
=item $mode = $render->[#]->mode()
|
| 59 |
+
|
| 60 |
+
=over 4
|
| 61 |
+
|
| 62 |
+
=item calculated
|
| 63 |
+
|
| 64 |
+
Calculated means the facet was generated from another facet. Calculated facets
|
| 65 |
+
may be cleared and regenerated whenever the event state changes.
|
| 66 |
+
|
| 67 |
+
=item replace
|
| 68 |
+
|
| 69 |
+
Replace means the facet is intended to replace the normal rendering of the
|
| 70 |
+
event.
|
| 71 |
+
|
| 72 |
+
=back
|
| 73 |
+
|
| 74 |
+
=back
|
| 75 |
+
|
| 76 |
+
=head1 SOURCE
|
| 77 |
+
|
| 78 |
+
The source code repository for Test2 can be found at
|
| 79 |
+
F<http://github.com/Test-More/test-more/>.
|
| 80 |
+
|
| 81 |
+
=head1 MAINTAINERS
|
| 82 |
+
|
| 83 |
+
=over 4
|
| 84 |
+
|
| 85 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 86 |
+
|
| 87 |
+
=back
|
| 88 |
+
|
| 89 |
+
=head1 AUTHORS
|
| 90 |
+
|
| 91 |
+
=over 4
|
| 92 |
+
|
| 93 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 94 |
+
|
| 95 |
+
=back
|
| 96 |
+
|
| 97 |
+
=head1 COPYRIGHT
|
| 98 |
+
|
| 99 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 100 |
+
|
| 101 |
+
This program is free software; you can redistribute it and/or
|
| 102 |
+
modify it under the same terms as Perl itself.
|
| 103 |
+
|
| 104 |
+
See F<http://dev.perl.org/licenses/>
|
| 105 |
+
|
| 106 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/EventFacet/Trace.pm
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::EventFacet::Trace;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
BEGIN { require Test2::EventFacet; our @ISA = qw(Test2::EventFacet) }
|
| 8 |
+
|
| 9 |
+
use Test2::Util qw/get_tid pkg_to_file gen_uid/;
|
| 10 |
+
use Carp qw/confess/;
|
| 11 |
+
|
| 12 |
+
use Test2::Util::HashBase qw{^frame ^pid ^tid ^cid -hid -nested details -buffered -uuid -huuid};
|
| 13 |
+
|
| 14 |
+
{
|
| 15 |
+
no warnings 'once';
|
| 16 |
+
*DETAIL = \&DETAILS;
|
| 17 |
+
*detail = \&details;
|
| 18 |
+
*set_detail = \&set_details;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
sub init {
|
| 22 |
+
confess "The 'frame' attribute is required"
|
| 23 |
+
unless $_[0]->{+FRAME};
|
| 24 |
+
|
| 25 |
+
$_[0]->{+DETAILS} = delete $_[0]->{detail} if $_[0]->{detail};
|
| 26 |
+
|
| 27 |
+
unless (defined($_[0]->{+PID}) || defined($_[0]->{+TID}) || defined($_[0]->{+CID})) {
|
| 28 |
+
$_[0]->{+PID} = $$ unless defined $_[0]->{+PID};
|
| 29 |
+
$_[0]->{+TID} = get_tid() unless defined $_[0]->{+TID};
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
sub snapshot {
|
| 34 |
+
my ($orig, @override) = @_;
|
| 35 |
+
bless {%$orig, @override}, __PACKAGE__;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
sub signature {
|
| 39 |
+
my $self = shift;
|
| 40 |
+
|
| 41 |
+
# Signature is only valid if all of these fields are defined, there is no
|
| 42 |
+
# signature if any is missing. '0' is ok, but '' is not.
|
| 43 |
+
return join ':' => map { (defined($_) && length($_)) ? $_ : return undef } (
|
| 44 |
+
$self->{+CID},
|
| 45 |
+
$self->{+PID},
|
| 46 |
+
$self->{+TID},
|
| 47 |
+
$self->{+FRAME}->[1],
|
| 48 |
+
$self->{+FRAME}->[2],
|
| 49 |
+
);
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
sub debug {
|
| 53 |
+
my $self = shift;
|
| 54 |
+
return $self->{+DETAILS} if $self->{+DETAILS};
|
| 55 |
+
my ($pkg, $file, $line) = $self->call;
|
| 56 |
+
return "at $file line $line";
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
sub alert {
|
| 60 |
+
my $self = shift;
|
| 61 |
+
my ($msg) = @_;
|
| 62 |
+
warn $msg . ' ' . $self->debug . ".\n";
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
sub throw {
|
| 66 |
+
my $self = shift;
|
| 67 |
+
my ($msg) = @_;
|
| 68 |
+
die $msg . ' ' . $self->debug . ".\n";
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
sub call { @{$_[0]->{+FRAME}} }
|
| 72 |
+
|
| 73 |
+
sub package { $_[0]->{+FRAME}->[0] }
|
| 74 |
+
sub file { $_[0]->{+FRAME}->[1] }
|
| 75 |
+
sub line { $_[0]->{+FRAME}->[2] }
|
| 76 |
+
sub subname { $_[0]->{+FRAME}->[3] }
|
| 77 |
+
|
| 78 |
+
1;
|
| 79 |
+
|
| 80 |
+
__END__
|
| 81 |
+
|
| 82 |
+
=pod
|
| 83 |
+
|
| 84 |
+
=encoding UTF-8
|
| 85 |
+
|
| 86 |
+
=head1 NAME
|
| 87 |
+
|
| 88 |
+
Test2::EventFacet::Trace - Debug information for events
|
| 89 |
+
|
| 90 |
+
=head1 DESCRIPTION
|
| 91 |
+
|
| 92 |
+
The L<Test2::API::Context> object, as well as all L<Test2::Event> types need to
|
| 93 |
+
have access to information about where they were created. This object
|
| 94 |
+
represents that information.
|
| 95 |
+
|
| 96 |
+
=head1 SYNOPSIS
|
| 97 |
+
|
| 98 |
+
use Test2::EventFacet::Trace;
|
| 99 |
+
|
| 100 |
+
my $trace = Test2::EventFacet::Trace->new(
|
| 101 |
+
frame => [$package, $file, $line, $subname],
|
| 102 |
+
);
|
| 103 |
+
|
| 104 |
+
=head1 FACET FIELDS
|
| 105 |
+
|
| 106 |
+
=over 4
|
| 107 |
+
|
| 108 |
+
=item $string = $trace->{details}
|
| 109 |
+
|
| 110 |
+
=item $string = $trace->details()
|
| 111 |
+
|
| 112 |
+
Used as a custom trace message that will be used INSTEAD of
|
| 113 |
+
C<< at <FILE> line <LINE> >> when calling C<< $trace->debug >>.
|
| 114 |
+
|
| 115 |
+
=item $frame = $trace->{frame}
|
| 116 |
+
|
| 117 |
+
=item $frame = $trace->frame()
|
| 118 |
+
|
| 119 |
+
Get the call frame arrayref.
|
| 120 |
+
|
| 121 |
+
=item $int = $trace->{pid}
|
| 122 |
+
|
| 123 |
+
=item $int = $trace->pid()
|
| 124 |
+
|
| 125 |
+
The process ID in which the event was generated.
|
| 126 |
+
|
| 127 |
+
=item $int = $trace->{tid}
|
| 128 |
+
|
| 129 |
+
=item $int = $trace->tid()
|
| 130 |
+
|
| 131 |
+
The thread ID in which the event was generated.
|
| 132 |
+
|
| 133 |
+
=item $id = $trace->{cid}
|
| 134 |
+
|
| 135 |
+
=item $id = $trace->cid()
|
| 136 |
+
|
| 137 |
+
The ID of the context that was used to create the event.
|
| 138 |
+
|
| 139 |
+
=item $uuid = $trace->{uuid}
|
| 140 |
+
|
| 141 |
+
=item $uuid = $trace->uuid()
|
| 142 |
+
|
| 143 |
+
The UUID of the context that was used to create the event. (If uuid tagging was
|
| 144 |
+
enabled)
|
| 145 |
+
|
| 146 |
+
=back
|
| 147 |
+
|
| 148 |
+
=head2 DISCOURAGED HUB RELATED FIELDS
|
| 149 |
+
|
| 150 |
+
These fields were not always set properly by tools. These are B<MOSTLY>
|
| 151 |
+
deprecated by the L<Test2::EventFacet::Hub> facets. These fields are not
|
| 152 |
+
required, and may only reflect the hub that was current when the event was
|
| 153 |
+
created, which is not necessarily the same as the hub the event was sent
|
| 154 |
+
through.
|
| 155 |
+
|
| 156 |
+
Some tools did do a good job setting these to the correct hub, but you cannot
|
| 157 |
+
always rely on that. Use the 'hubs' facet list instead.
|
| 158 |
+
|
| 159 |
+
=over 4
|
| 160 |
+
|
| 161 |
+
=item $hid = $trace->{hid}
|
| 162 |
+
|
| 163 |
+
=item $hid = $trace->hid()
|
| 164 |
+
|
| 165 |
+
The ID of the hub that was current when the event was created.
|
| 166 |
+
|
| 167 |
+
=item $huuid = $trace->{huuid}
|
| 168 |
+
|
| 169 |
+
=item $huuid = $trace->huuid()
|
| 170 |
+
|
| 171 |
+
The UUID of the hub that was current when the event was created. (If uuid
|
| 172 |
+
tagging was enabled).
|
| 173 |
+
|
| 174 |
+
=item $int = $trace->{nested}
|
| 175 |
+
|
| 176 |
+
=item $int = $trace->nested()
|
| 177 |
+
|
| 178 |
+
How deeply nested the event is.
|
| 179 |
+
|
| 180 |
+
=item $bool = $trace->{buffered}
|
| 181 |
+
|
| 182 |
+
=item $bool = $trace->buffered()
|
| 183 |
+
|
| 184 |
+
True if the event was buffered and not sent to the formatter independent of a
|
| 185 |
+
parent (This should never be set when nested is C<0> or C<undef>).
|
| 186 |
+
|
| 187 |
+
=back
|
| 188 |
+
|
| 189 |
+
=head1 METHODS
|
| 190 |
+
|
| 191 |
+
B<Note:> All facet frames are also methods.
|
| 192 |
+
|
| 193 |
+
=over 4
|
| 194 |
+
|
| 195 |
+
=item $trace->set_detail($msg)
|
| 196 |
+
|
| 197 |
+
=item $msg = $trace->detail
|
| 198 |
+
|
| 199 |
+
Used to get/set a custom trace message that will be used INSTEAD of
|
| 200 |
+
C<< at <FILE> line <LINE> >> when calling C<< $trace->debug >>.
|
| 201 |
+
|
| 202 |
+
C<detail()> is an alias to the C<details> facet field for backwards
|
| 203 |
+
compatibility.
|
| 204 |
+
|
| 205 |
+
=item $str = $trace->debug
|
| 206 |
+
|
| 207 |
+
Typically returns the string C<< at <FILE> line <LINE> >>. If C<detail> is set
|
| 208 |
+
then its value will be returned instead.
|
| 209 |
+
|
| 210 |
+
=item $trace->alert($MESSAGE)
|
| 211 |
+
|
| 212 |
+
This issues a warning at the frame (filename and line number where
|
| 213 |
+
errors should be reported).
|
| 214 |
+
|
| 215 |
+
=item $trace->throw($MESSAGE)
|
| 216 |
+
|
| 217 |
+
This throws an exception at the frame (filename and line number where
|
| 218 |
+
errors should be reported).
|
| 219 |
+
|
| 220 |
+
=item ($package, $file, $line, $subname) = $trace->call()
|
| 221 |
+
|
| 222 |
+
Get the caller details for the debug-info. This is where errors should be
|
| 223 |
+
reported.
|
| 224 |
+
|
| 225 |
+
=item $pkg = $trace->package
|
| 226 |
+
|
| 227 |
+
Get the debug-info package.
|
| 228 |
+
|
| 229 |
+
=item $file = $trace->file
|
| 230 |
+
|
| 231 |
+
Get the debug-info filename.
|
| 232 |
+
|
| 233 |
+
=item $line = $trace->line
|
| 234 |
+
|
| 235 |
+
Get the debug-info line number.
|
| 236 |
+
|
| 237 |
+
=item $subname = $trace->subname
|
| 238 |
+
|
| 239 |
+
Get the debug-info subroutine name.
|
| 240 |
+
|
| 241 |
+
=item $sig = trace->signature
|
| 242 |
+
|
| 243 |
+
Get a signature string that identifies this trace. This is used to check if
|
| 244 |
+
multiple events are related. The signature includes pid, tid, file, line
|
| 245 |
+
number, and the cid.
|
| 246 |
+
|
| 247 |
+
=back
|
| 248 |
+
|
| 249 |
+
=head1 SOURCE
|
| 250 |
+
|
| 251 |
+
The source code repository for Test2 can be found at
|
| 252 |
+
F<http://github.com/Test-More/test-more/>.
|
| 253 |
+
|
| 254 |
+
=head1 MAINTAINERS
|
| 255 |
+
|
| 256 |
+
=over 4
|
| 257 |
+
|
| 258 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 259 |
+
|
| 260 |
+
=back
|
| 261 |
+
|
| 262 |
+
=head1 AUTHORS
|
| 263 |
+
|
| 264 |
+
=over 4
|
| 265 |
+
|
| 266 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 267 |
+
|
| 268 |
+
=back
|
| 269 |
+
|
| 270 |
+
=head1 COPYRIGHT
|
| 271 |
+
|
| 272 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 273 |
+
|
| 274 |
+
This program is free software; you can redistribute it and/or
|
| 275 |
+
modify it under the same terms as Perl itself.
|
| 276 |
+
|
| 277 |
+
See F<http://dev.perl.org/licenses/>
|
| 278 |
+
|
| 279 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Formatter/TAP.pm
ADDED
|
@@ -0,0 +1,524 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Formatter::TAP;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
use Test2::Util qw/clone_io/;
|
| 8 |
+
|
| 9 |
+
use Test2::Util::HashBase qw{
|
| 10 |
+
no_numbers handles _encoding _last_fh
|
| 11 |
+
-made_assertion
|
| 12 |
+
};
|
| 13 |
+
|
| 14 |
+
sub OUT_STD() { 0 }
|
| 15 |
+
sub OUT_ERR() { 1 }
|
| 16 |
+
|
| 17 |
+
BEGIN { require Test2::Formatter; our @ISA = qw(Test2::Formatter) }
|
| 18 |
+
|
| 19 |
+
# Not constants because this is a method, and can be overriden
|
| 20 |
+
BEGIN {
|
| 21 |
+
local $SIG{__DIE__} = 'DEFAULT';
|
| 22 |
+
local $@;
|
| 23 |
+
if (($INC{'Term/Table.pm'} && $INC{'Term/Table/Util.pm'}) || eval { require Term::Table; require Term::Table::Util; 1 }) {
|
| 24 |
+
*supports_tables = sub { 1 };
|
| 25 |
+
}
|
| 26 |
+
else {
|
| 27 |
+
*supports_tables = sub { 0 };
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
sub _autoflush {
|
| 32 |
+
my($fh) = pop;
|
| 33 |
+
my $old_fh = select $fh;
|
| 34 |
+
$| = 1;
|
| 35 |
+
select $old_fh;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
_autoflush(\*STDOUT);
|
| 39 |
+
_autoflush(\*STDERR);
|
| 40 |
+
|
| 41 |
+
sub hide_buffered { 1 }
|
| 42 |
+
|
| 43 |
+
sub init {
|
| 44 |
+
my $self = shift;
|
| 45 |
+
|
| 46 |
+
$self->{+HANDLES} ||= $self->_open_handles;
|
| 47 |
+
if(my $enc = delete $self->{encoding}) {
|
| 48 |
+
$self->encoding($enc);
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
sub _open_handles {
|
| 53 |
+
my $self = shift;
|
| 54 |
+
|
| 55 |
+
require Test2::API;
|
| 56 |
+
my $out = clone_io(Test2::API::test2_stdout());
|
| 57 |
+
my $err = clone_io(Test2::API::test2_stderr());
|
| 58 |
+
|
| 59 |
+
_autoflush($out);
|
| 60 |
+
_autoflush($err);
|
| 61 |
+
|
| 62 |
+
return [$out, $err];
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
sub encoding {
|
| 66 |
+
my $self = shift;
|
| 67 |
+
|
| 68 |
+
if ($] ge "5.007003" and @_) {
|
| 69 |
+
my ($enc) = @_;
|
| 70 |
+
my $handles = $self->{+HANDLES};
|
| 71 |
+
|
| 72 |
+
# https://rt.perl.org/Public/Bug/Display.html?id=31923
|
| 73 |
+
# If utf8 is requested we use ':utf8' instead of ':encoding(utf8)' in
|
| 74 |
+
# order to avoid the thread segfault.
|
| 75 |
+
if ($enc =~ m/^utf-?8$/i) {
|
| 76 |
+
binmode($_, ":utf8") for @$handles;
|
| 77 |
+
}
|
| 78 |
+
else {
|
| 79 |
+
binmode($_, ":encoding($enc)") for @$handles;
|
| 80 |
+
}
|
| 81 |
+
$self->{+_ENCODING} = $enc;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
return $self->{+_ENCODING};
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
if ($^C) {
|
| 88 |
+
no warnings 'redefine';
|
| 89 |
+
*write = sub {};
|
| 90 |
+
}
|
| 91 |
+
sub write {
|
| 92 |
+
my ($self, $e, $num, $f) = @_;
|
| 93 |
+
|
| 94 |
+
# The most common case, a pass event with no amnesty and a normal name.
|
| 95 |
+
return if $self->print_optimal_pass($e, $num);
|
| 96 |
+
|
| 97 |
+
$f ||= $e->facet_data;
|
| 98 |
+
|
| 99 |
+
$self->encoding($f->{control}->{encoding}) if $f->{control}->{encoding};
|
| 100 |
+
|
| 101 |
+
my @tap = $self->event_tap($f, $num) or return;
|
| 102 |
+
|
| 103 |
+
$self->{+MADE_ASSERTION} = 1 if $f->{assert};
|
| 104 |
+
|
| 105 |
+
my $nesting = $f->{trace}->{nested} || 0;
|
| 106 |
+
my $handles = $self->{+HANDLES};
|
| 107 |
+
my $indent = ' ' x $nesting;
|
| 108 |
+
|
| 109 |
+
# Local is expensive! Only do it if we really need to.
|
| 110 |
+
local($\, $,) = (undef, '') if $\ || $,;
|
| 111 |
+
for my $set (@tap) {
|
| 112 |
+
no warnings 'uninitialized';
|
| 113 |
+
my ($hid, $msg) = @$set;
|
| 114 |
+
next unless $msg;
|
| 115 |
+
my $io = $handles->[$hid] or next;
|
| 116 |
+
|
| 117 |
+
print $io "\n"
|
| 118 |
+
if $ENV{HARNESS_ACTIVE}
|
| 119 |
+
&& $hid == OUT_ERR
|
| 120 |
+
&& $self->{+_LAST_FH} != $io
|
| 121 |
+
&& $msg =~ m/^#\s*Failed( \(TODO\))? test /;
|
| 122 |
+
|
| 123 |
+
$msg =~ s/^/$indent/mg if $nesting;
|
| 124 |
+
print $io $msg;
|
| 125 |
+
$self->{+_LAST_FH} = $io;
|
| 126 |
+
}
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
sub print_optimal_pass {
|
| 130 |
+
my ($self, $e, $num) = @_;
|
| 131 |
+
|
| 132 |
+
my $type = ref($e);
|
| 133 |
+
|
| 134 |
+
# Only optimal if this is a Pass or a passing Ok
|
| 135 |
+
return unless $type eq 'Test2::Event::Pass' || ($type eq 'Test2::Event::Ok' && $e->{pass});
|
| 136 |
+
|
| 137 |
+
# Amnesty requires further processing (todo is a form of amnesty)
|
| 138 |
+
return if ($e->{amnesty} && @{$e->{amnesty}}) || defined($e->{todo});
|
| 139 |
+
|
| 140 |
+
# A name with a newline or hash symbol needs extra processing
|
| 141 |
+
return if defined($e->{name}) && (-1 != index($e->{name}, "\n") || -1 != index($e->{name}, '#'));
|
| 142 |
+
|
| 143 |
+
my $ok = 'ok';
|
| 144 |
+
$ok .= " $num" if $num && !$self->{+NO_NUMBERS};
|
| 145 |
+
$ok .= defined($e->{name}) ? " - $e->{name}\n" : "\n";
|
| 146 |
+
|
| 147 |
+
if (my $nesting = $e->{trace}->{nested}) {
|
| 148 |
+
my $indent = ' ' x $nesting;
|
| 149 |
+
$ok = "$indent$ok";
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
my $io = $self->{+HANDLES}->[OUT_STD];
|
| 153 |
+
|
| 154 |
+
local($\, $,) = (undef, '') if $\ || $,;
|
| 155 |
+
print $io $ok;
|
| 156 |
+
$self->{+_LAST_FH} = $io;
|
| 157 |
+
|
| 158 |
+
return 1;
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
sub event_tap {
|
| 162 |
+
my ($self, $f, $num) = @_;
|
| 163 |
+
|
| 164 |
+
my @tap;
|
| 165 |
+
|
| 166 |
+
# If this IS the first event the plan should come first
|
| 167 |
+
# (plan must be before or after assertions, not in the middle)
|
| 168 |
+
push @tap => $self->plan_tap($f) if $f->{plan} && !$self->{+MADE_ASSERTION};
|
| 169 |
+
|
| 170 |
+
# The assertion is most important, if present.
|
| 171 |
+
if ($f->{assert}) {
|
| 172 |
+
push @tap => $self->assert_tap($f, $num);
|
| 173 |
+
push @tap => $self->debug_tap($f, $num) unless $f->{assert}->{no_debug} || $f->{assert}->{pass};
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
# Almost as important as an assertion
|
| 177 |
+
push @tap => $self->error_tap($f) if $f->{errors};
|
| 178 |
+
|
| 179 |
+
# Now lets see the diagnostics messages
|
| 180 |
+
push @tap => $self->info_tap($f) if $f->{info};
|
| 181 |
+
|
| 182 |
+
# If this IS NOT the first event the plan should come last
|
| 183 |
+
# (plan must be before or after assertions, not in the middle)
|
| 184 |
+
push @tap => $self->plan_tap($f) if $self->{+MADE_ASSERTION} && $f->{plan};
|
| 185 |
+
|
| 186 |
+
# Bail out
|
| 187 |
+
push @tap => $self->halt_tap($f) if $f->{control}->{halt};
|
| 188 |
+
|
| 189 |
+
return @tap if @tap;
|
| 190 |
+
return @tap if $f->{control}->{halt};
|
| 191 |
+
return @tap if grep { $f->{$_} } qw/assert plan info errors/;
|
| 192 |
+
|
| 193 |
+
# Use the summary as a fallback if nothing else is usable.
|
| 194 |
+
return $self->summary_tap($f, $num);
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
sub error_tap {
|
| 198 |
+
my $self = shift;
|
| 199 |
+
my ($f) = @_;
|
| 200 |
+
|
| 201 |
+
my $IO = ($f->{amnesty} && @{$f->{amnesty}}) ? OUT_STD : OUT_ERR;
|
| 202 |
+
|
| 203 |
+
return map {
|
| 204 |
+
my $details = $_->{details};
|
| 205 |
+
|
| 206 |
+
my $msg;
|
| 207 |
+
if (ref($details)) {
|
| 208 |
+
require Data::Dumper;
|
| 209 |
+
my $dumper = Data::Dumper->new([$details])->Indent(2)->Terse(1)->Pad('# ')->Useqq(1)->Sortkeys(1);
|
| 210 |
+
chomp($msg = $dumper->Dump);
|
| 211 |
+
}
|
| 212 |
+
else {
|
| 213 |
+
chomp($msg = $details);
|
| 214 |
+
$msg =~ s/^/# /;
|
| 215 |
+
$msg =~ s/\n/\n# /g;
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
[$IO, "$msg\n"];
|
| 219 |
+
} @{$f->{errors}};
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
sub plan_tap {
|
| 223 |
+
my $self = shift;
|
| 224 |
+
my ($f) = @_;
|
| 225 |
+
my $plan = $f->{plan} or return;
|
| 226 |
+
|
| 227 |
+
return if $plan->{none};
|
| 228 |
+
|
| 229 |
+
if ($plan->{skip}) {
|
| 230 |
+
my $reason = $plan->{details} or return [OUT_STD, "1..0 # SKIP\n"];
|
| 231 |
+
chomp($reason);
|
| 232 |
+
return [OUT_STD, '1..0 # SKIP ' . $reason . "\n"];
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
return [OUT_STD, "1.." . $plan->{count} . "\n"];
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
sub no_subtest_space { 0 }
|
| 239 |
+
sub assert_tap {
|
| 240 |
+
my $self = shift;
|
| 241 |
+
my ($f, $num) = @_;
|
| 242 |
+
|
| 243 |
+
my $assert = $f->{assert} or return;
|
| 244 |
+
my $pass = $assert->{pass};
|
| 245 |
+
my $name = $assert->{details};
|
| 246 |
+
|
| 247 |
+
my $ok = $pass ? 'ok' : 'not ok';
|
| 248 |
+
$ok .= " $num" if $num && !$self->{+NO_NUMBERS};
|
| 249 |
+
|
| 250 |
+
# The regex form is ~250ms, the index form is ~50ms
|
| 251 |
+
my @extra;
|
| 252 |
+
defined($name) && (
|
| 253 |
+
(index($name, "\n") != -1 && (($name, @extra) = split(/\n\r?/, $name, -1))),
|
| 254 |
+
((index($name, "#" ) != -1 || substr($name, -1) eq '\\') && (($name =~ s|\\|\\\\|g), ($name =~ s|#|\\#|g)))
|
| 255 |
+
);
|
| 256 |
+
|
| 257 |
+
my $extra_space = @extra ? ' ' x (length($ok) + 2) : '';
|
| 258 |
+
my $extra_indent = '';
|
| 259 |
+
|
| 260 |
+
my ($directives, $reason, $is_skip);
|
| 261 |
+
if ($f->{amnesty}) {
|
| 262 |
+
my %directives;
|
| 263 |
+
|
| 264 |
+
for my $am (@{$f->{amnesty}}) {
|
| 265 |
+
next if $am->{inherited};
|
| 266 |
+
my $tag = $am->{tag} or next;
|
| 267 |
+
$is_skip = 1 if $tag eq 'skip';
|
| 268 |
+
|
| 269 |
+
$directives{$tag} ||= $am->{details};
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
my %seen;
|
| 273 |
+
my @order = grep { !$seen{$_}++ } sort keys %directives;
|
| 274 |
+
|
| 275 |
+
$directives = ' # ' . join ' & ' => @order;
|
| 276 |
+
|
| 277 |
+
for my $tag ('skip', @order) {
|
| 278 |
+
next unless defined($directives{$tag}) && length($directives{$tag});
|
| 279 |
+
$reason = $directives{$tag};
|
| 280 |
+
last;
|
| 281 |
+
}
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
$ok .= " - $name" if defined $name && !($is_skip && !$name);
|
| 285 |
+
|
| 286 |
+
my @subtap;
|
| 287 |
+
if ($f->{parent} && $f->{parent}->{buffered}) {
|
| 288 |
+
$ok .= ' {';
|
| 289 |
+
|
| 290 |
+
# In a verbose harness we indent the extra since they will appear
|
| 291 |
+
# inside the subtest braces. This helps readability. In a non-verbose
|
| 292 |
+
# harness we do not do this because it is less readable.
|
| 293 |
+
if ($ENV{HARNESS_IS_VERBOSE} || !$ENV{HARNESS_ACTIVE}) {
|
| 294 |
+
$extra_indent = " ";
|
| 295 |
+
$extra_space = ' ';
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
# Render the sub-events, we use our own counter for these.
|
| 299 |
+
my $count = 0;
|
| 300 |
+
@subtap = map {
|
| 301 |
+
my $f2 = $_;
|
| 302 |
+
|
| 303 |
+
# Bump the count for any event that should bump it.
|
| 304 |
+
$count++ if $f2->{assert};
|
| 305 |
+
|
| 306 |
+
# This indents all output lines generated for the sub-events.
|
| 307 |
+
# index 0 is the filehandle, index 1 is the message we want to indent.
|
| 308 |
+
map { $_->[1] =~ s/^(.*\S.*)$/ $1/mg; $_ } $self->event_tap($f2, $count);
|
| 309 |
+
} @{$f->{parent}->{children}};
|
| 310 |
+
|
| 311 |
+
push @subtap => [OUT_STD, "}\n"];
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
if ($directives) {
|
| 315 |
+
$directives = ' # TODO & SKIP' if $directives eq ' # TODO & skip';
|
| 316 |
+
$ok .= $directives;
|
| 317 |
+
$ok .= " $reason" if defined($reason);
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
$extra_space = ' ' if $self->no_subtest_space;
|
| 321 |
+
|
| 322 |
+
my @out = ([OUT_STD, "$ok\n"]);
|
| 323 |
+
push @out => map {[OUT_STD, "${extra_indent}#${extra_space}$_\n"]} @extra if @extra;
|
| 324 |
+
push @out => @subtap;
|
| 325 |
+
|
| 326 |
+
return @out;
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
sub debug_tap {
|
| 330 |
+
my ($self, $f, $num) = @_;
|
| 331 |
+
|
| 332 |
+
# Figure out the debug info, this is typically the file name and line
|
| 333 |
+
# number, but can also be a custom message. If no trace object is provided
|
| 334 |
+
# then we have nothing useful to display.
|
| 335 |
+
my $name = $f->{assert}->{details};
|
| 336 |
+
my $trace = $f->{trace};
|
| 337 |
+
|
| 338 |
+
my $debug = "[No trace info available]";
|
| 339 |
+
if ($trace->{details}) {
|
| 340 |
+
$debug = $trace->{details};
|
| 341 |
+
}
|
| 342 |
+
elsif ($trace->{frame}) {
|
| 343 |
+
my ($pkg, $file, $line) = @{$trace->{frame}};
|
| 344 |
+
$debug = "at $file line $line." if $file && $line;
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
my $amnesty = $f->{amnesty} && @{$f->{amnesty}}
|
| 348 |
+
? ' (with amnesty)'
|
| 349 |
+
: '';
|
| 350 |
+
|
| 351 |
+
# Create the initial diagnostics. If the test has a name we put the debug
|
| 352 |
+
# info on a second line, this behavior is inherited from Test::Builder.
|
| 353 |
+
my $msg = defined($name)
|
| 354 |
+
? qq[# Failed test${amnesty} '$name'\n# $debug\n]
|
| 355 |
+
: qq[# Failed test${amnesty} $debug\n];
|
| 356 |
+
|
| 357 |
+
my $IO = $f->{amnesty} && @{$f->{amnesty}} ? OUT_STD : OUT_ERR;
|
| 358 |
+
|
| 359 |
+
return [$IO, $msg];
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
sub halt_tap {
|
| 363 |
+
my ($self, $f) = @_;
|
| 364 |
+
|
| 365 |
+
return if $f->{trace}->{nested} && !$f->{trace}->{buffered};
|
| 366 |
+
my $details = $f->{control}->{details};
|
| 367 |
+
|
| 368 |
+
return [OUT_STD, "Bail out!\n"] unless defined($details) && length($details);
|
| 369 |
+
return [OUT_STD, "Bail out! $details\n"];
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
sub info_tap {
|
| 373 |
+
my ($self, $f) = @_;
|
| 374 |
+
|
| 375 |
+
return map {
|
| 376 |
+
my $details = $_->{details};
|
| 377 |
+
my $table = $_->{table};
|
| 378 |
+
|
| 379 |
+
my $IO = $_->{debug} && !($f->{amnesty} && @{$f->{amnesty}}) ? OUT_ERR : OUT_STD;
|
| 380 |
+
|
| 381 |
+
my $msg;
|
| 382 |
+
if ($table && $self->supports_tables) {
|
| 383 |
+
$msg = join "\n" => map { "# $_" } Term::Table->new(
|
| 384 |
+
header => $table->{header},
|
| 385 |
+
rows => $table->{rows},
|
| 386 |
+
collapse => $table->{collapse},
|
| 387 |
+
no_collapse => $table->{no_collapse},
|
| 388 |
+
sanitize => 1,
|
| 389 |
+
mark_tail => 1,
|
| 390 |
+
max_width => $self->calc_table_size($f),
|
| 391 |
+
)->render();
|
| 392 |
+
}
|
| 393 |
+
elsif (ref($details)) {
|
| 394 |
+
require Data::Dumper;
|
| 395 |
+
my $dumper = Data::Dumper->new([$details])->Indent(2)->Terse(1)->Pad('# ')->Useqq(1)->Sortkeys(1);
|
| 396 |
+
chomp($msg = $dumper->Dump);
|
| 397 |
+
}
|
| 398 |
+
else {
|
| 399 |
+
chomp($msg = $details);
|
| 400 |
+
$msg =~ s/^/# /;
|
| 401 |
+
$msg =~ s/\n/\n# /g;
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
[$IO, "$msg\n"];
|
| 405 |
+
} @{$f->{info}};
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
sub summary_tap {
|
| 409 |
+
my ($self, $f, $num) = @_;
|
| 410 |
+
|
| 411 |
+
return if $f->{about}->{no_display};
|
| 412 |
+
|
| 413 |
+
my $summary = $f->{about}->{details} or return;
|
| 414 |
+
chomp($summary);
|
| 415 |
+
$summary =~ s/^/# /smg;
|
| 416 |
+
|
| 417 |
+
return [OUT_STD, "$summary\n"];
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
sub calc_table_size {
|
| 421 |
+
my $self = shift;
|
| 422 |
+
my ($f) = @_;
|
| 423 |
+
|
| 424 |
+
my $term = Term::Table::Util::term_size();
|
| 425 |
+
my $nesting = 2 + (($f->{trace}->{nested} || 0) * 4); # 4 spaces per level, also '# ' prefix
|
| 426 |
+
my $total = $term - $nesting;
|
| 427 |
+
|
| 428 |
+
# Sane minimum width, any smaller and we are asking for pain
|
| 429 |
+
return 50 if $total < 50;
|
| 430 |
+
|
| 431 |
+
return $total;
|
| 432 |
+
}
|
| 433 |
+
|
| 434 |
+
1;
|
| 435 |
+
|
| 436 |
+
__END__
|
| 437 |
+
|
| 438 |
+
=pod
|
| 439 |
+
|
| 440 |
+
=encoding UTF-8
|
| 441 |
+
|
| 442 |
+
=head1 NAME
|
| 443 |
+
|
| 444 |
+
Test2::Formatter::TAP - Standard TAP formatter
|
| 445 |
+
|
| 446 |
+
=head1 DESCRIPTION
|
| 447 |
+
|
| 448 |
+
This is what takes events and turns them into TAP.
|
| 449 |
+
|
| 450 |
+
=head1 SYNOPSIS
|
| 451 |
+
|
| 452 |
+
use Test2::Formatter::TAP;
|
| 453 |
+
my $tap = Test2::Formatter::TAP->new();
|
| 454 |
+
|
| 455 |
+
# Switch to utf8
|
| 456 |
+
$tap->encoding('utf8');
|
| 457 |
+
|
| 458 |
+
$tap->write($event, $number); # Output an event
|
| 459 |
+
|
| 460 |
+
=head1 METHODS
|
| 461 |
+
|
| 462 |
+
=over 4
|
| 463 |
+
|
| 464 |
+
=item $bool = $tap->no_numbers
|
| 465 |
+
|
| 466 |
+
=item $tap->set_no_numbers($bool)
|
| 467 |
+
|
| 468 |
+
Use to turn numbers on and off.
|
| 469 |
+
|
| 470 |
+
=item $arrayref = $tap->handles
|
| 471 |
+
|
| 472 |
+
=item $tap->set_handles(\@handles);
|
| 473 |
+
|
| 474 |
+
Can be used to get/set the filehandles. Indexes are identified by the
|
| 475 |
+
C<OUT_STD> and C<OUT_ERR> constants.
|
| 476 |
+
|
| 477 |
+
=item $encoding = $tap->encoding
|
| 478 |
+
|
| 479 |
+
=item $tap->encoding($encoding)
|
| 480 |
+
|
| 481 |
+
Get or set the encoding. By default no encoding is set, the original settings
|
| 482 |
+
of STDOUT and STDERR are used.
|
| 483 |
+
|
| 484 |
+
This directly modifies the stored filehandles, it does not create new ones.
|
| 485 |
+
|
| 486 |
+
=item $tap->write($e, $num)
|
| 487 |
+
|
| 488 |
+
Write an event to the console.
|
| 489 |
+
|
| 490 |
+
=back
|
| 491 |
+
|
| 492 |
+
=head1 SOURCE
|
| 493 |
+
|
| 494 |
+
The source code repository for Test2 can be found at
|
| 495 |
+
F<http://github.com/Test-More/test-more/>.
|
| 496 |
+
|
| 497 |
+
=head1 MAINTAINERS
|
| 498 |
+
|
| 499 |
+
=over 4
|
| 500 |
+
|
| 501 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 502 |
+
|
| 503 |
+
=back
|
| 504 |
+
|
| 505 |
+
=head1 AUTHORS
|
| 506 |
+
|
| 507 |
+
=over 4
|
| 508 |
+
|
| 509 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 510 |
+
|
| 511 |
+
=item Kent Fredric E<lt>[email protected]<gt>
|
| 512 |
+
|
| 513 |
+
=back
|
| 514 |
+
|
| 515 |
+
=head1 COPYRIGHT
|
| 516 |
+
|
| 517 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 518 |
+
|
| 519 |
+
This program is free software; you can redistribute it and/or
|
| 520 |
+
modify it under the same terms as Perl itself.
|
| 521 |
+
|
| 522 |
+
See F<http://dev.perl.org/licenses/>
|
| 523 |
+
|
| 524 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Tools/Tiny.pm
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Tools::Tiny;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
BEGIN {
|
| 6 |
+
if ($] lt "5.008") {
|
| 7 |
+
require Test::Builder::IO::Scalar;
|
| 8 |
+
}
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
use Scalar::Util qw/blessed/;
|
| 12 |
+
|
| 13 |
+
use Test2::Util qw/try/;
|
| 14 |
+
use Test2::API qw/context run_subtest test2_stack/;
|
| 15 |
+
|
| 16 |
+
use Test2::Hub::Interceptor();
|
| 17 |
+
use Test2::Hub::Interceptor::Terminator();
|
| 18 |
+
|
| 19 |
+
our $VERSION = '1.302162';
|
| 20 |
+
|
| 21 |
+
BEGIN { require Exporter; our @ISA = qw(Exporter) }
|
| 22 |
+
our @EXPORT = qw{
|
| 23 |
+
ok is isnt like unlike is_deeply diag note skip_all todo plan done_testing
|
| 24 |
+
warnings exception tests capture
|
| 25 |
+
};
|
| 26 |
+
|
| 27 |
+
sub ok($;$@) {
|
| 28 |
+
my ($bool, $name, @diag) = @_;
|
| 29 |
+
my $ctx = context();
|
| 30 |
+
|
| 31 |
+
return $ctx->pass_and_release($name) if $bool;
|
| 32 |
+
return $ctx->fail_and_release($name, @diag);
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
sub is($$;$@) {
|
| 36 |
+
my ($got, $want, $name, @diag) = @_;
|
| 37 |
+
my $ctx = context();
|
| 38 |
+
|
| 39 |
+
my $bool;
|
| 40 |
+
if (defined($got) && defined($want)) {
|
| 41 |
+
$bool = "$got" eq "$want";
|
| 42 |
+
}
|
| 43 |
+
elsif (defined($got) xor defined($want)) {
|
| 44 |
+
$bool = 0;
|
| 45 |
+
}
|
| 46 |
+
else { # Both are undef
|
| 47 |
+
$bool = 1;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
return $ctx->pass_and_release($name) if $bool;
|
| 51 |
+
|
| 52 |
+
$got = '*NOT DEFINED*' unless defined $got;
|
| 53 |
+
$want = '*NOT DEFINED*' unless defined $want;
|
| 54 |
+
unshift @diag => (
|
| 55 |
+
"GOT: $got",
|
| 56 |
+
"EXPECTED: $want",
|
| 57 |
+
);
|
| 58 |
+
|
| 59 |
+
return $ctx->fail_and_release($name, @diag);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
sub isnt($$;$@) {
|
| 63 |
+
my ($got, $want, $name, @diag) = @_;
|
| 64 |
+
my $ctx = context();
|
| 65 |
+
|
| 66 |
+
my $bool;
|
| 67 |
+
if (defined($got) && defined($want)) {
|
| 68 |
+
$bool = "$got" ne "$want";
|
| 69 |
+
}
|
| 70 |
+
elsif (defined($got) xor defined($want)) {
|
| 71 |
+
$bool = 1;
|
| 72 |
+
}
|
| 73 |
+
else { # Both are undef
|
| 74 |
+
$bool = 0;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
return $ctx->pass_and_release($name) if $bool;
|
| 78 |
+
|
| 79 |
+
unshift @diag => "Strings are the same (they should not be)"
|
| 80 |
+
unless $bool;
|
| 81 |
+
|
| 82 |
+
return $ctx->fail_and_release($name, @diag);
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
sub like($$;$@) {
|
| 86 |
+
my ($thing, $pattern, $name, @diag) = @_;
|
| 87 |
+
my $ctx = context();
|
| 88 |
+
|
| 89 |
+
my $bool;
|
| 90 |
+
if (defined($thing)) {
|
| 91 |
+
$bool = "$thing" =~ $pattern;
|
| 92 |
+
unshift @diag => (
|
| 93 |
+
"Value: $thing",
|
| 94 |
+
"Does not match: $pattern"
|
| 95 |
+
) unless $bool;
|
| 96 |
+
}
|
| 97 |
+
else {
|
| 98 |
+
$bool = 0;
|
| 99 |
+
unshift @diag => "Got an undefined value.";
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
return $ctx->pass_and_release($name) if $bool;
|
| 103 |
+
return $ctx->fail_and_release($name, @diag);
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
sub unlike($$;$@) {
|
| 107 |
+
my ($thing, $pattern, $name, @diag) = @_;
|
| 108 |
+
my $ctx = context();
|
| 109 |
+
|
| 110 |
+
my $bool;
|
| 111 |
+
if (defined($thing)) {
|
| 112 |
+
$bool = "$thing" !~ $pattern;
|
| 113 |
+
unshift @diag => (
|
| 114 |
+
"Unexpected pattern match (it should not match)",
|
| 115 |
+
"Value: $thing",
|
| 116 |
+
"Matches: $pattern"
|
| 117 |
+
) unless $bool;
|
| 118 |
+
}
|
| 119 |
+
else {
|
| 120 |
+
$bool = 0;
|
| 121 |
+
unshift @diag => "Got an undefined value.";
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
return $ctx->pass_and_release($name) if $bool;
|
| 125 |
+
return $ctx->fail_and_release($name, @diag);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
sub is_deeply($$;$@) {
|
| 129 |
+
my ($got, $want, $name, @diag) = @_;
|
| 130 |
+
my $ctx = context();
|
| 131 |
+
|
| 132 |
+
no warnings 'once';
|
| 133 |
+
require Data::Dumper;
|
| 134 |
+
|
| 135 |
+
# Otherwise numbers might be unquoted
|
| 136 |
+
local $Data::Dumper::Useperl = 1;
|
| 137 |
+
|
| 138 |
+
local $Data::Dumper::Sortkeys = 1;
|
| 139 |
+
local $Data::Dumper::Deparse = 1;
|
| 140 |
+
local $Data::Dumper::Freezer = 'XXX';
|
| 141 |
+
local *UNIVERSAL::XXX = sub {
|
| 142 |
+
my ($thing) = @_;
|
| 143 |
+
if (ref($thing)) {
|
| 144 |
+
$thing = {%$thing} if "$thing" =~ m/=HASH/;
|
| 145 |
+
$thing = [@$thing] if "$thing" =~ m/=ARRAY/;
|
| 146 |
+
$thing = \"$$thing" if "$thing" =~ m/=SCALAR/;
|
| 147 |
+
}
|
| 148 |
+
$_[0] = $thing;
|
| 149 |
+
};
|
| 150 |
+
|
| 151 |
+
my $g = Data::Dumper::Dumper($got);
|
| 152 |
+
my $w = Data::Dumper::Dumper($want);
|
| 153 |
+
|
| 154 |
+
my $bool = $g eq $w;
|
| 155 |
+
|
| 156 |
+
return $ctx->pass_and_release($name) if $bool;
|
| 157 |
+
return $ctx->fail_and_release($name, $g, $w, @diag);
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
sub diag {
|
| 161 |
+
my $ctx = context();
|
| 162 |
+
$ctx->diag(join '', @_);
|
| 163 |
+
$ctx->release;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
sub note {
|
| 167 |
+
my $ctx = context();
|
| 168 |
+
$ctx->note(join '', @_);
|
| 169 |
+
$ctx->release;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
sub skip_all {
|
| 173 |
+
my ($reason) = @_;
|
| 174 |
+
my $ctx = context();
|
| 175 |
+
$ctx->plan(0, SKIP => $reason);
|
| 176 |
+
$ctx->release if $ctx;
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
sub todo {
|
| 180 |
+
my ($reason, $sub) = @_;
|
| 181 |
+
my $ctx = context();
|
| 182 |
+
|
| 183 |
+
# This code is mostly copied from Test2::Todo in the Test2-Suite
|
| 184 |
+
# distribution.
|
| 185 |
+
my $hub = test2_stack->top;
|
| 186 |
+
my $filter = $hub->pre_filter(
|
| 187 |
+
sub {
|
| 188 |
+
my ($active_hub, $event) = @_;
|
| 189 |
+
if ($active_hub == $hub) {
|
| 190 |
+
$event->set_todo($reason) if $event->can('set_todo');
|
| 191 |
+
$event->add_amnesty({tag => 'TODO', details => $reason});
|
| 192 |
+
}
|
| 193 |
+
else {
|
| 194 |
+
$event->add_amnesty({tag => 'TODO', details => $reason, inherited => 1});
|
| 195 |
+
}
|
| 196 |
+
return $event;
|
| 197 |
+
},
|
| 198 |
+
inherit => 1,
|
| 199 |
+
todo => $reason,
|
| 200 |
+
);
|
| 201 |
+
$sub->();
|
| 202 |
+
$hub->pre_unfilter($filter);
|
| 203 |
+
|
| 204 |
+
$ctx->release if $ctx;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
sub plan {
|
| 208 |
+
my ($max) = @_;
|
| 209 |
+
my $ctx = context();
|
| 210 |
+
$ctx->plan($max);
|
| 211 |
+
$ctx->release;
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
sub done_testing {
|
| 215 |
+
my $ctx = context();
|
| 216 |
+
$ctx->done_testing;
|
| 217 |
+
$ctx->release;
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
sub warnings(&) {
|
| 221 |
+
my $code = shift;
|
| 222 |
+
my @warnings;
|
| 223 |
+
local $SIG{__WARN__} = sub { push @warnings => @_ };
|
| 224 |
+
$code->();
|
| 225 |
+
return \@warnings;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
sub exception(&) {
|
| 229 |
+
my $code = shift;
|
| 230 |
+
local ($@, $!, $SIG{__DIE__});
|
| 231 |
+
my $ok = eval { $code->(); 1 };
|
| 232 |
+
my $error = $@ || 'SQUASHED ERROR';
|
| 233 |
+
return $ok ? undef : $error;
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
sub tests {
|
| 237 |
+
my ($name, $code) = @_;
|
| 238 |
+
my $ctx = context();
|
| 239 |
+
|
| 240 |
+
my $be = caller->can('before_each');
|
| 241 |
+
|
| 242 |
+
$be->($name) if $be;
|
| 243 |
+
|
| 244 |
+
my $bool = run_subtest($name, $code, 1);
|
| 245 |
+
|
| 246 |
+
$ctx->release;
|
| 247 |
+
|
| 248 |
+
return $bool;
|
| 249 |
+
}
|
| 250 |
+
|
| 251 |
+
sub capture(&) {
|
| 252 |
+
my $code = shift;
|
| 253 |
+
|
| 254 |
+
my ($err, $out) = ("", "");
|
| 255 |
+
|
| 256 |
+
my $handles = test2_stack->top->format->handles;
|
| 257 |
+
my ($ok, $e);
|
| 258 |
+
{
|
| 259 |
+
my ($out_fh, $err_fh);
|
| 260 |
+
|
| 261 |
+
($ok, $e) = try {
|
| 262 |
+
# Scalar refs as filehandles were added in 5.8.
|
| 263 |
+
if ($] ge "5.008") {
|
| 264 |
+
open($out_fh, '>', \$out) or die "Failed to open a temporary STDOUT: $!";
|
| 265 |
+
open($err_fh, '>', \$err) or die "Failed to open a temporary STDERR: $!";
|
| 266 |
+
}
|
| 267 |
+
# Emulate scalar ref filehandles with a tie.
|
| 268 |
+
else {
|
| 269 |
+
$out_fh = Test::Builder::IO::Scalar->new(\$out) or die "Failed to open a temporary STDOUT";
|
| 270 |
+
$err_fh = Test::Builder::IO::Scalar->new(\$err) or die "Failed to open a temporary STDERR";
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
test2_stack->top->format->set_handles([$out_fh, $err_fh, $out_fh]);
|
| 274 |
+
|
| 275 |
+
$code->();
|
| 276 |
+
};
|
| 277 |
+
}
|
| 278 |
+
test2_stack->top->format->set_handles($handles);
|
| 279 |
+
|
| 280 |
+
die $e unless $ok;
|
| 281 |
+
|
| 282 |
+
$err =~ s/ $/_/mg;
|
| 283 |
+
$out =~ s/ $/_/mg;
|
| 284 |
+
|
| 285 |
+
return {
|
| 286 |
+
STDOUT => $out,
|
| 287 |
+
STDERR => $err,
|
| 288 |
+
};
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
1;
|
| 292 |
+
|
| 293 |
+
__END__
|
| 294 |
+
|
| 295 |
+
=pod
|
| 296 |
+
|
| 297 |
+
=encoding UTF-8
|
| 298 |
+
|
| 299 |
+
=head1 NAME
|
| 300 |
+
|
| 301 |
+
Test2::Tools::Tiny - Tiny set of tools for unfortunate souls who cannot use
|
| 302 |
+
L<Test2::Suite>.
|
| 303 |
+
|
| 304 |
+
=head1 DESCRIPTION
|
| 305 |
+
|
| 306 |
+
You should really look at L<Test2::Suite>. This package is some very basic
|
| 307 |
+
essential tools implemented using L<Test2>. This exists only so that L<Test2>
|
| 308 |
+
and other tools required by L<Test2::Suite> can be tested. This is the package
|
| 309 |
+
L<Test2> uses to test itself.
|
| 310 |
+
|
| 311 |
+
=head1 USE Test2::Suite INSTEAD
|
| 312 |
+
|
| 313 |
+
Use L<Test2::Suite> if at all possible.
|
| 314 |
+
|
| 315 |
+
=head1 EXPORTS
|
| 316 |
+
|
| 317 |
+
=over 4
|
| 318 |
+
|
| 319 |
+
=item ok($bool, $name)
|
| 320 |
+
|
| 321 |
+
=item ok($bool, $name, @diag)
|
| 322 |
+
|
| 323 |
+
Run a simple assertion.
|
| 324 |
+
|
| 325 |
+
=item is($got, $want, $name)
|
| 326 |
+
|
| 327 |
+
=item is($got, $want, $name, @diag)
|
| 328 |
+
|
| 329 |
+
Assert that 2 strings are the same.
|
| 330 |
+
|
| 331 |
+
=item isnt($got, $do_not_want, $name)
|
| 332 |
+
|
| 333 |
+
=item isnt($got, $do_not_want, $name, @diag)
|
| 334 |
+
|
| 335 |
+
Assert that 2 strings are not the same.
|
| 336 |
+
|
| 337 |
+
=item like($got, $regex, $name)
|
| 338 |
+
|
| 339 |
+
=item like($got, $regex, $name, @diag)
|
| 340 |
+
|
| 341 |
+
Check that the input string matches the regex.
|
| 342 |
+
|
| 343 |
+
=item unlike($got, $regex, $name)
|
| 344 |
+
|
| 345 |
+
=item unlike($got, $regex, $name, @diag)
|
| 346 |
+
|
| 347 |
+
Check that the input string does not match the regex.
|
| 348 |
+
|
| 349 |
+
=item is_deeply($got, $want, $name)
|
| 350 |
+
|
| 351 |
+
=item is_deeply($got, $want, $name, @diag)
|
| 352 |
+
|
| 353 |
+
Check 2 data structures. Please note that this is a I<DUMB> implementation that
|
| 354 |
+
compares the output of L<Data::Dumper> against both structures.
|
| 355 |
+
|
| 356 |
+
=item diag($msg)
|
| 357 |
+
|
| 358 |
+
Issue a diagnostics message to STDERR.
|
| 359 |
+
|
| 360 |
+
=item note($msg)
|
| 361 |
+
|
| 362 |
+
Issue a diagnostics message to STDOUT.
|
| 363 |
+
|
| 364 |
+
=item skip_all($reason)
|
| 365 |
+
|
| 366 |
+
Skip all tests.
|
| 367 |
+
|
| 368 |
+
=item todo $reason => sub { ... }
|
| 369 |
+
|
| 370 |
+
Run a block in TODO mode.
|
| 371 |
+
|
| 372 |
+
=item plan($count)
|
| 373 |
+
|
| 374 |
+
Set the plan.
|
| 375 |
+
|
| 376 |
+
=item done_testing()
|
| 377 |
+
|
| 378 |
+
Set the plan to the current test count.
|
| 379 |
+
|
| 380 |
+
=item $warnings = warnings { ... }
|
| 381 |
+
|
| 382 |
+
Capture an arrayref of warnings from the block.
|
| 383 |
+
|
| 384 |
+
=item $exception = exception { ... }
|
| 385 |
+
|
| 386 |
+
Capture an exception.
|
| 387 |
+
|
| 388 |
+
=item tests $name => sub { ... }
|
| 389 |
+
|
| 390 |
+
Run a subtest.
|
| 391 |
+
|
| 392 |
+
=item $output = capture { ... }
|
| 393 |
+
|
| 394 |
+
Capture STDOUT and STDERR output.
|
| 395 |
+
|
| 396 |
+
Result looks like this:
|
| 397 |
+
|
| 398 |
+
{
|
| 399 |
+
STDOUT => "...",
|
| 400 |
+
STDERR => "...",
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
=back
|
| 404 |
+
|
| 405 |
+
=head1 SOURCE
|
| 406 |
+
|
| 407 |
+
The source code repository for Test2 can be found at
|
| 408 |
+
F<http://github.com/Test-More/test-more/>.
|
| 409 |
+
|
| 410 |
+
=head1 MAINTAINERS
|
| 411 |
+
|
| 412 |
+
=over 4
|
| 413 |
+
|
| 414 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 415 |
+
|
| 416 |
+
=back
|
| 417 |
+
|
| 418 |
+
=head1 AUTHORS
|
| 419 |
+
|
| 420 |
+
=over 4
|
| 421 |
+
|
| 422 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 423 |
+
|
| 424 |
+
=back
|
| 425 |
+
|
| 426 |
+
=head1 COPYRIGHT
|
| 427 |
+
|
| 428 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 429 |
+
|
| 430 |
+
This program is free software; you can redistribute it and/or
|
| 431 |
+
modify it under the same terms as Perl itself.
|
| 432 |
+
|
| 433 |
+
See F<http://dev.perl.org/licenses/>
|
| 434 |
+
|
| 435 |
+
=cut
|
my_container_sandbox/usr/share/perl/5.30.0/Test2/Util/HashBase.pm
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package Test2::Util::HashBase;
|
| 2 |
+
use strict;
|
| 3 |
+
use warnings;
|
| 4 |
+
|
| 5 |
+
our $VERSION = '1.302162';
|
| 6 |
+
|
| 7 |
+
#################################################################
|
| 8 |
+
# #
|
| 9 |
+
# This is a generated file! Do not modify this file directly! #
|
| 10 |
+
# Use hashbase_inc.pl script to regenerate this file. #
|
| 11 |
+
# The script is part of the Object::HashBase distribution. #
|
| 12 |
+
# Note: You can modify the version number above this comment #
|
| 13 |
+
# if needed, that is fine. #
|
| 14 |
+
# #
|
| 15 |
+
#################################################################
|
| 16 |
+
|
| 17 |
+
{
|
| 18 |
+
no warnings 'once';
|
| 19 |
+
$Test2::Util::HashBase::HB_VERSION = '0.006';
|
| 20 |
+
*Test2::Util::HashBase::ATTR_SUBS = \%Object::HashBase::ATTR_SUBS;
|
| 21 |
+
*Test2::Util::HashBase::ATTR_LIST = \%Object::HashBase::ATTR_LIST;
|
| 22 |
+
*Test2::Util::HashBase::VERSION = \%Object::HashBase::VERSION;
|
| 23 |
+
*Test2::Util::HashBase::CAN_CACHE = \%Object::HashBase::CAN_CACHE;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
require Carp;
|
| 28 |
+
{
|
| 29 |
+
no warnings 'once';
|
| 30 |
+
$Carp::Internal{+__PACKAGE__} = 1;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
BEGIN {
|
| 34 |
+
# these are not strictly equivalent, but for out use we don't care
|
| 35 |
+
# about order
|
| 36 |
+
*_isa = ($] >= 5.010 && require mro) ? \&mro::get_linear_isa : sub {
|
| 37 |
+
no strict 'refs';
|
| 38 |
+
my @packages = ($_[0]);
|
| 39 |
+
my %seen;
|
| 40 |
+
for my $package (@packages) {
|
| 41 |
+
push @packages, grep !$seen{$_}++, @{"$package\::ISA"};
|
| 42 |
+
}
|
| 43 |
+
return \@packages;
|
| 44 |
+
}
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
my %STRIP = (
|
| 48 |
+
'^' => 1,
|
| 49 |
+
'-' => 1,
|
| 50 |
+
);
|
| 51 |
+
|
| 52 |
+
sub import {
|
| 53 |
+
my $class = shift;
|
| 54 |
+
my $into = caller;
|
| 55 |
+
|
| 56 |
+
# Make sure we list the OLDEST version used to create this class.
|
| 57 |
+
my $ver = $Test2::Util::HashBase::HB_VERSION || $Test2::Util::HashBase::VERSION;
|
| 58 |
+
$Test2::Util::HashBase::VERSION{$into} = $ver if !$Test2::Util::HashBase::VERSION{$into} || $Test2::Util::HashBase::VERSION{$into} > $ver;
|
| 59 |
+
|
| 60 |
+
my $isa = _isa($into);
|
| 61 |
+
my $attr_list = $Test2::Util::HashBase::ATTR_LIST{$into} ||= [];
|
| 62 |
+
my $attr_subs = $Test2::Util::HashBase::ATTR_SUBS{$into} ||= {};
|
| 63 |
+
|
| 64 |
+
my %subs = (
|
| 65 |
+
($into->can('new') ? () : (new => \&_new)),
|
| 66 |
+
(map %{$Test2::Util::HashBase::ATTR_SUBS{$_} || {}}, @{$isa}[1 .. $#$isa]),
|
| 67 |
+
(
|
| 68 |
+
map {
|
| 69 |
+
my $p = substr($_, 0, 1);
|
| 70 |
+
my $x = $_;
|
| 71 |
+
substr($x, 0, 1) = '' if $STRIP{$p};
|
| 72 |
+
push @$attr_list => $x;
|
| 73 |
+
my ($sub, $attr) = (uc $x, $x);
|
| 74 |
+
$sub => ($attr_subs->{$sub} = sub() { $attr }),
|
| 75 |
+
$attr => sub { $_[0]->{$attr} },
|
| 76 |
+
$p eq '-' ? ("set_$attr" => sub { Carp::croak("'$attr' is read-only") })
|
| 77 |
+
: $p eq '^' ? ("set_$attr" => sub { Carp::carp("set_$attr() is deprecated"); $_[0]->{$attr} = $_[1] })
|
| 78 |
+
: ("set_$attr" => sub { $_[0]->{$attr} = $_[1] }),
|
| 79 |
+
} @_
|
| 80 |
+
),
|
| 81 |
+
);
|
| 82 |
+
|
| 83 |
+
no strict 'refs';
|
| 84 |
+
*{"$into\::$_"} = $subs{$_} for keys %subs;
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
sub attr_list {
|
| 88 |
+
my $class = shift;
|
| 89 |
+
|
| 90 |
+
my $isa = _isa($class);
|
| 91 |
+
|
| 92 |
+
my %seen;
|
| 93 |
+
my @list = grep { !$seen{$_}++ } map {
|
| 94 |
+
my @out;
|
| 95 |
+
|
| 96 |
+
if (0.004 > ($Test2::Util::HashBase::VERSION{$_} || 0)) {
|
| 97 |
+
Carp::carp("$_ uses an inlined version of Test2::Util::HashBase too old to support attr_list()");
|
| 98 |
+
}
|
| 99 |
+
else {
|
| 100 |
+
my $list = $Test2::Util::HashBase::ATTR_LIST{$_};
|
| 101 |
+
@out = $list ? @$list : ()
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
@out;
|
| 105 |
+
} reverse @$isa;
|
| 106 |
+
|
| 107 |
+
return @list;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
sub _new {
|
| 111 |
+
my $class = shift;
|
| 112 |
+
|
| 113 |
+
my $self;
|
| 114 |
+
|
| 115 |
+
if (@_ == 1) {
|
| 116 |
+
my $arg = shift;
|
| 117 |
+
my $type = ref($arg);
|
| 118 |
+
|
| 119 |
+
if ($type eq 'HASH') {
|
| 120 |
+
$self = bless({%$arg}, $class)
|
| 121 |
+
}
|
| 122 |
+
else {
|
| 123 |
+
Carp::croak("Not sure what to do with '$type' in $class constructor")
|
| 124 |
+
unless $type eq 'ARRAY';
|
| 125 |
+
|
| 126 |
+
my %proto;
|
| 127 |
+
my @attributes = attr_list($class);
|
| 128 |
+
while (@$arg) {
|
| 129 |
+
my $val = shift @$arg;
|
| 130 |
+
my $key = shift @attributes or Carp::croak("Too many arguments for $class constructor");
|
| 131 |
+
$proto{$key} = $val;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
$self = bless(\%proto, $class);
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
else {
|
| 138 |
+
$self = bless({@_}, $class);
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
$Test2::Util::HashBase::CAN_CACHE{$class} = $self->can('init')
|
| 142 |
+
unless exists $Test2::Util::HashBase::CAN_CACHE{$class};
|
| 143 |
+
|
| 144 |
+
$self->init if $Test2::Util::HashBase::CAN_CACHE{$class};
|
| 145 |
+
|
| 146 |
+
$self;
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
1;
|
| 150 |
+
|
| 151 |
+
__END__
|
| 152 |
+
|
| 153 |
+
=pod
|
| 154 |
+
|
| 155 |
+
=encoding UTF-8
|
| 156 |
+
|
| 157 |
+
=head1 NAME
|
| 158 |
+
|
| 159 |
+
Test2::Util::HashBase - Build hash based classes.
|
| 160 |
+
|
| 161 |
+
=head1 SYNOPSIS
|
| 162 |
+
|
| 163 |
+
A class:
|
| 164 |
+
|
| 165 |
+
package My::Class;
|
| 166 |
+
use strict;
|
| 167 |
+
use warnings;
|
| 168 |
+
|
| 169 |
+
# Generate 3 accessors
|
| 170 |
+
use Test2::Util::HashBase qw/foo -bar ^baz/;
|
| 171 |
+
|
| 172 |
+
# Chance to initialize defaults
|
| 173 |
+
sub init {
|
| 174 |
+
my $self = shift; # No other args
|
| 175 |
+
$self->{+FOO} ||= "foo";
|
| 176 |
+
$self->{+BAR} ||= "bar";
|
| 177 |
+
$self->{+BAZ} ||= "baz";
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
sub print {
|
| 181 |
+
print join ", " => map { $self->{$_} } FOO, BAR, BAZ;
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
Subclass it
|
| 185 |
+
|
| 186 |
+
package My::Subclass;
|
| 187 |
+
use strict;
|
| 188 |
+
use warnings;
|
| 189 |
+
|
| 190 |
+
# Note, you should subclass before loading HashBase.
|
| 191 |
+
use base 'My::Class';
|
| 192 |
+
use Test2::Util::HashBase qw/bat/;
|
| 193 |
+
|
| 194 |
+
sub init {
|
| 195 |
+
my $self = shift;
|
| 196 |
+
|
| 197 |
+
# We get the constants from the base class for free.
|
| 198 |
+
$self->{+FOO} ||= 'SubFoo';
|
| 199 |
+
$self->{+BAT} ||= 'bat';
|
| 200 |
+
|
| 201 |
+
$self->SUPER::init();
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
use it:
|
| 205 |
+
|
| 206 |
+
package main;
|
| 207 |
+
use strict;
|
| 208 |
+
use warnings;
|
| 209 |
+
use My::Class;
|
| 210 |
+
|
| 211 |
+
# These are all functionally identical
|
| 212 |
+
my $one = My::Class->new(foo => 'MyFoo', bar => 'MyBar');
|
| 213 |
+
my $two = My::Class->new({foo => 'MyFoo', bar => 'MyBar'});
|
| 214 |
+
my $three = My::Class->new(['MyFoo', 'MyBar']);
|
| 215 |
+
|
| 216 |
+
# Accessors!
|
| 217 |
+
my $foo = $one->foo; # 'MyFoo'
|
| 218 |
+
my $bar = $one->bar; # 'MyBar'
|
| 219 |
+
my $baz = $one->baz; # Defaulted to: 'baz'
|
| 220 |
+
|
| 221 |
+
# Setters!
|
| 222 |
+
$one->set_foo('A Foo');
|
| 223 |
+
|
| 224 |
+
#'-bar' means read-only, so the setter will throw an exception (but is defined).
|
| 225 |
+
$one->set_bar('A bar');
|
| 226 |
+
|
| 227 |
+
# '^baz' means deprecated setter, this will warn about the setter being
|
| 228 |
+
# deprecated.
|
| 229 |
+
$one->set_baz('A Baz');
|
| 230 |
+
|
| 231 |
+
$one->{+FOO} = 'xxx';
|
| 232 |
+
|
| 233 |
+
=head1 DESCRIPTION
|
| 234 |
+
|
| 235 |
+
This package is used to generate classes based on hashrefs. Using this class
|
| 236 |
+
will give you a C<new()> method, as well as generating accessors you request.
|
| 237 |
+
Generated accessors will be getters, C<set_ACCESSOR> setters will also be
|
| 238 |
+
generated for you. You also get constants for each accessor (all caps) which
|
| 239 |
+
return the key into the hash for that accessor. Single inheritance is also
|
| 240 |
+
supported.
|
| 241 |
+
|
| 242 |
+
=head1 THIS IS A BUNDLED COPY OF HASHBASE
|
| 243 |
+
|
| 244 |
+
This is a bundled copy of L<Object::HashBase>. This file was generated using
|
| 245 |
+
the
|
| 246 |
+
C</home/exodist/perl5/perlbrew/perls/main/bin/hashbase_inc.pl>
|
| 247 |
+
script.
|
| 248 |
+
|
| 249 |
+
=head1 METHODS
|
| 250 |
+
|
| 251 |
+
=head2 PROVIDED BY HASH BASE
|
| 252 |
+
|
| 253 |
+
=over 4
|
| 254 |
+
|
| 255 |
+
=item $it = $class->new(%PAIRS)
|
| 256 |
+
|
| 257 |
+
=item $it = $class->new(\%PAIRS)
|
| 258 |
+
|
| 259 |
+
=item $it = $class->new(\@ORDERED_VALUES)
|
| 260 |
+
|
| 261 |
+
Create a new instance.
|
| 262 |
+
|
| 263 |
+
HashBase will not export C<new()> if there is already a C<new()> method in your
|
| 264 |
+
packages inheritance chain.
|
| 265 |
+
|
| 266 |
+
B<If you do not want this method you can define your own> you just have to
|
| 267 |
+
declare it before loading L<Test2::Util::HashBase>.
|
| 268 |
+
|
| 269 |
+
package My::Package;
|
| 270 |
+
|
| 271 |
+
# predeclare new() so that HashBase does not give us one.
|
| 272 |
+
sub new;
|
| 273 |
+
|
| 274 |
+
use Test2::Util::HashBase qw/foo bar baz/;
|
| 275 |
+
|
| 276 |
+
# Now we define our own new method.
|
| 277 |
+
sub new { ... }
|
| 278 |
+
|
| 279 |
+
This makes it so that HashBase sees that you have your own C<new()> method.
|
| 280 |
+
Alternatively you can define the method before loading HashBase instead of just
|
| 281 |
+
declaring it, but that scatters your use statements.
|
| 282 |
+
|
| 283 |
+
The most common way to create an object is to pass in key/value pairs where
|
| 284 |
+
each key is an attribute and each value is what you want assigned to that
|
| 285 |
+
attribute. No checking is done to verify the attributes or values are valid,
|
| 286 |
+
you may do that in C<init()> if desired.
|
| 287 |
+
|
| 288 |
+
If you would like, you can pass in a hashref instead of pairs. When you do so
|
| 289 |
+
the hashref will be copied, and the copy will be returned blessed as an object.
|
| 290 |
+
There is no way to ask HashBase to bless a specific hashref.
|
| 291 |
+
|
| 292 |
+
In some cases an object may only have 1 or 2 attributes, in which case a
|
| 293 |
+
hashref may be too verbose for your liking. In these cases you can pass in an
|
| 294 |
+
arrayref with only values. The values will be assigned to attributes in the
|
| 295 |
+
order the attributes were listed. When there is inheritance involved the
|
| 296 |
+
attributes from parent classes will come before subclasses.
|
| 297 |
+
|
| 298 |
+
=back
|
| 299 |
+
|
| 300 |
+
=head2 HOOKS
|
| 301 |
+
|
| 302 |
+
=over 4
|
| 303 |
+
|
| 304 |
+
=item $self->init()
|
| 305 |
+
|
| 306 |
+
This gives you the chance to set some default values to your fields. The only
|
| 307 |
+
argument is C<$self> with its indexes already set from the constructor.
|
| 308 |
+
|
| 309 |
+
B<Note:> Test2::Util::HashBase checks for an init using C<< $class->can('init') >>
|
| 310 |
+
during construction. It DOES NOT call C<can()> on the created object. Also note
|
| 311 |
+
that the result of the check is cached, it is only ever checked once, the first
|
| 312 |
+
time an instance of your class is created. This means that adding an C<init()>
|
| 313 |
+
method AFTER the first construction will result in it being ignored.
|
| 314 |
+
|
| 315 |
+
=back
|
| 316 |
+
|
| 317 |
+
=head1 ACCESSORS
|
| 318 |
+
|
| 319 |
+
=head2 READ/WRITE
|
| 320 |
+
|
| 321 |
+
To generate accessors you list them when using the module:
|
| 322 |
+
|
| 323 |
+
use Test2::Util::HashBase qw/foo/;
|
| 324 |
+
|
| 325 |
+
This will generate the following subs in your namespace:
|
| 326 |
+
|
| 327 |
+
=over 4
|
| 328 |
+
|
| 329 |
+
=item foo()
|
| 330 |
+
|
| 331 |
+
Getter, used to get the value of the C<foo> field.
|
| 332 |
+
|
| 333 |
+
=item set_foo()
|
| 334 |
+
|
| 335 |
+
Setter, used to set the value of the C<foo> field.
|
| 336 |
+
|
| 337 |
+
=item FOO()
|
| 338 |
+
|
| 339 |
+
Constant, returns the field C<foo>'s key into the class hashref. Subclasses will
|
| 340 |
+
also get this function as a constant, not simply a method, that means it is
|
| 341 |
+
copied into the subclass namespace.
|
| 342 |
+
|
| 343 |
+
The main reason for using these constants is to help avoid spelling mistakes
|
| 344 |
+
and similar typos. It will not help you if you forget to prefix the '+' though.
|
| 345 |
+
|
| 346 |
+
=back
|
| 347 |
+
|
| 348 |
+
=head2 READ ONLY
|
| 349 |
+
|
| 350 |
+
use Test2::Util::HashBase qw/-foo/;
|
| 351 |
+
|
| 352 |
+
=over 4
|
| 353 |
+
|
| 354 |
+
=item set_foo()
|
| 355 |
+
|
| 356 |
+
Throws an exception telling you the attribute is read-only. This is exported to
|
| 357 |
+
override any active setters for the attribute in a parent class.
|
| 358 |
+
|
| 359 |
+
=back
|
| 360 |
+
|
| 361 |
+
=head2 DEPRECATED SETTER
|
| 362 |
+
|
| 363 |
+
use Test2::Util::HashBase qw/^foo/;
|
| 364 |
+
|
| 365 |
+
=over 4
|
| 366 |
+
|
| 367 |
+
=item set_foo()
|
| 368 |
+
|
| 369 |
+
This will set the value, but it will also warn you that the method is
|
| 370 |
+
deprecated.
|
| 371 |
+
|
| 372 |
+
=back
|
| 373 |
+
|
| 374 |
+
=head1 SUBCLASSING
|
| 375 |
+
|
| 376 |
+
You can subclass an existing HashBase class.
|
| 377 |
+
|
| 378 |
+
use base 'Another::HashBase::Class';
|
| 379 |
+
use Test2::Util::HashBase qw/foo bar baz/;
|
| 380 |
+
|
| 381 |
+
The base class is added to C<@ISA> for you, and all constants from base classes
|
| 382 |
+
are added to subclasses automatically.
|
| 383 |
+
|
| 384 |
+
=head1 GETTING A LIST OF ATTRIBUTES FOR A CLASS
|
| 385 |
+
|
| 386 |
+
Test2::Util::HashBase provides a function for retrieving a list of attributes for an
|
| 387 |
+
Test2::Util::HashBase class.
|
| 388 |
+
|
| 389 |
+
=over 4
|
| 390 |
+
|
| 391 |
+
=item @list = Test2::Util::HashBase::attr_list($class)
|
| 392 |
+
|
| 393 |
+
=item @list = $class->Test2::Util::HashBase::attr_list()
|
| 394 |
+
|
| 395 |
+
Either form above will work. This will return a list of attributes defined on
|
| 396 |
+
the object. This list is returned in the attribute definition order, parent
|
| 397 |
+
class attributes are listed before subclass attributes. Duplicate attributes
|
| 398 |
+
will be removed before the list is returned.
|
| 399 |
+
|
| 400 |
+
B<Note:> This list is used in the C<< $class->new(\@ARRAY) >> constructor to
|
| 401 |
+
determine the attribute to which each value will be paired.
|
| 402 |
+
|
| 403 |
+
=back
|
| 404 |
+
|
| 405 |
+
=head1 SOURCE
|
| 406 |
+
|
| 407 |
+
The source code repository for HashBase can be found at
|
| 408 |
+
F<http://github.com/Test-More/HashBase/>.
|
| 409 |
+
|
| 410 |
+
=head1 MAINTAINERS
|
| 411 |
+
|
| 412 |
+
=over 4
|
| 413 |
+
|
| 414 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 415 |
+
|
| 416 |
+
=back
|
| 417 |
+
|
| 418 |
+
=head1 AUTHORS
|
| 419 |
+
|
| 420 |
+
=over 4
|
| 421 |
+
|
| 422 |
+
=item Chad Granum E<lt>[email protected]<gt>
|
| 423 |
+
|
| 424 |
+
=back
|
| 425 |
+
|
| 426 |
+
=head1 COPYRIGHT
|
| 427 |
+
|
| 428 |
+
Copyright 2019 Chad Granum E<lt>[email protected]<gt>.
|
| 429 |
+
|
| 430 |
+
This program is free software; you can redistribute it and/or
|
| 431 |
+
modify it under the same terms as Perl itself.
|
| 432 |
+
|
| 433 |
+
See F<http://dev.perl.org/licenses/>
|
| 434 |
+
|
| 435 |
+
=cut
|