File Coverage

File:blib/lib/App/FileSync/Platform.pm
Coverage:100.0%

linestmtbrancondsubtimecode
1package App::FileSync::Platform;
2
3# Deliberately dependency-free, and loaded first by every module that uses
4# Sub::Private: the end-of-scope hook implementation has to be chosen before
5# anything loads B::Hooks::EndOfScope, and Sub::Private loads it at compile time.
6
7
328
328
328
731
244
4255
use strict;
8
328
328
328
463
247
5930
use warnings;
9
10
328
328
328
49558
251682
792
use version; our $VERSION = version->declare('0.001.1');
11
12=encoding utf8
13
14 - 73
=head1 NAME

App::FileSync::Platform - choose platform workarounds before other modules load

=head1 SYNOPSIS

        use App::FileSync::Platform;    # first, before Sub::Private or Log::Abstraction

=head1 DESCRIPTION

B::Hooks::EndOfScope 0.28 releases its XS scope hook with an access violation
(0xC0000005) on Perl 5.42 for Windows, after a command has done its work but
before the interpreter exits, so a run that synced everything would still exit
nonzero.  Its plain-Perl hook does not fault.  The implementation is fixed when
B::Hooks::EndOfScope first loads, so this module makes the choice in a BEGIN
block and is the first thing every App::FileSync module loads.

=head1 FUNCTIONS

=head2 wants_plain_end_of_scope_hook

Purpose: decide whether an interpreter needs the plain-Perl end-of-scope hook.

Args: C<$os> (as C<$^O>), C<$version> (as C<$]>).

Returns: 1 for MSWin32 with a 5.42.x interpreter, otherwise 0.

Side Effects: none.

Usage:

        App::FileSync::Platform::wants_plain_end_of_scope_hook('MSWin32', 5.042003);    # 1

=head3 EXAMPLE

        print App::FileSync::Platform::wants_plain_end_of_scope_hook($^O, $]) ? "PP\n" : "XS\n";

=head3 API SPECIFICATION

=head4 INPUT

        [
                { name => 'os',      type => 'string', optional => 1 },
                { name => 'version', type => 'string', optional => 1 },
        ]

=head4 OUTPUT

        { type => 'integer', min => 0, max => 1 }

=head3 MESSAGES

None.

=head3 FORMAL SPECIFICATION

        wants : OS × VERSION → 𝔹
        wants(os, v) ⇔ os = MSWin32 ∧ v ∈ ℚ ∧ 5.042 ≤ v < 5.043

=cut
74
75sub wants_plain_end_of_scope_hook {
76
338
12807308
        my ($os, $version) = @_;
77
78        # 5.42.x only: later releases may not share the fault, and forcing an
79        # implementation a later B::Hooks::EndOfScope no longer ships would refuse
80        # to load.
81
338
1592
        return (defined $os && $os eq 'MSWin32'
82                && defined $version && $version =~ /\A[0-9.]+\z/
83                && $version >= 5.042 && $version < 5.043) ? 1 : 0;
84}
85
86 - 132
=head2 use_plain_end_of_scope_hook

Purpose: select the plain-Perl hook for an interpreter that needs it.

Args: C<$os>, C<$version>, as for L</wants_plain_end_of_scope_hook>.

Returns: 1 when the environment variable was set, 0 when it was left alone.

Side Effects: may set C<$ENV{B_HOOKS_ENDOFSCOPE_IMPLEMENTATION}> to C<PP>.  An
implementation already named in the environment always wins.

Usage:

        App::FileSync::Platform::use_plain_end_of_scope_hook($^O, $]);

=head3 EXAMPLE

        local $ENV{B_HOOKS_ENDOFSCOPE_IMPLEMENTATION};
        App::FileSync::Platform::use_plain_end_of_scope_hook('MSWin32', 5.042003);
        print "$ENV{B_HOOKS_ENDOFSCOPE_IMPLEMENTATION}\n";    # PP

=head3 API SPECIFICATION

=head4 INPUT

        [
                { name => 'os',      type => 'string', optional => 1 },
                { name => 'version', type => 'string', optional => 1 },
        ]

=head4 OUTPUT

        { type => 'integer', min => 0, max => 1 }

=head3 MESSAGES

None.

=head3 FORMAL SPECIFICATION

        Î”ENV
        os? : OS ; v? : VERSION ; r! : 𝔹
        r! ⇔ B_HOOKS ∉ dom ENV ∧ wants(os?, v?)
        r! ⇒ ENV' = ENV ⊕ {B_HOOKS ↦ PP}
        Â¬r! ⇒ ENV' = ENV

=cut
133
134sub use_plain_end_of_scope_hook {
135
330
146085
        my ($os, $version) = @_;
136
137        my $set = (!defined $ENV{B_HOOKS_ENDOFSCOPE_IMPLEMENTATION}
138
330
987
                && wants_plain_end_of_scope_hook($os, $version)) ? 1 : 0;
139
330
467
        $ENV{B_HOOKS_ENDOFSCOPE_IMPLEMENTATION} = 'PP' if $set;
140
141
330
3468
        return $set;
142}
143
144BEGIN {
145
328
41837
        use_plain_end_of_scope_hook($^O, $]);
146}
147
1481;
149