File: yath

package info (click to toggle)
libtest2-harness-perl 1.000158-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,900 kB
  • sloc: perl: 17,017; makefile: 10; ansic: 6; sh: 4
file content (316 lines) | stat: -rwxr-xr-x 8,949 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
#!/usr/bin/perl
# Do not use warnings/strict, we want to avoid contamination of the

# '-D' and '--dev-lib' MUST be handled well in advance of loading ANYTHING.
# These will get re-processed later, but they MUST come even before App::Yath
# is loaded.
BEGIN {
    local $.;
    return if $^C;

    package App::Yath::Script;
    our $VERSION = '1.000156';

    my $ORIG_TMP;
    my $ORIG_TMP_PERMS;
    my %ORIG_SIG = map { defined($SIG{$_}) ? ($_ => "$SIG{$_}") : ()} keys %SIG;
    my @ORIG_ARGV = @ARGV;
    my @ORIG_INC = @INC;
    my @DEVLIBS;
    my %CONFIG;
    my $NO_PLUGINS;

    our $SCRIPT;

    # ==START TESTABLE CODE FIND_CONFIG_FILES==

    my ($config_file, $user_config_file);

    # Would be nice if we could use File::Spec, but we cannot load ANYTHING yet.
    my %no_stat = (mswin32 => 1, vms => 1, riscos => 1, os2 => 1, cygwin => 1);
    my %seen;
    my $dir = './';
    for (1 .. 100) {    # If we are more than 100 deep we have other problems
        if ($no_stat{lc($^O)}) {
            opendir(my $dh, $dir) or die "$!";
            my $key = join ':' => sort readdir($dh);
            last if $seen{$key}++;
        }
        else {
            my ($dev, $ino) = stat $dir;
            last if $seen{$dev}{$ino}++;
        }

        $config_file      //= "${dir}.yath.rc"      if -f "${dir}.yath.rc";
        $user_config_file //= "${dir}.yath.user.rc" if -f "${dir}.yath.user.rc";

        last if $config_file && $user_config_file;

        $dir .= "../";
    }

    # ==END TESTABLE CODE FIND_CONFIG_FILES==
    # ==START TESTABLE CODE PARSE_CONFIG_FILES==

    my (@CONFIG_ARGS, @TO_CLEAN);
    for my $file ($config_file, $user_config_file) {
        next unless $file && -f $file;

        my $cmd;
        open(my $fh, '<', $file) or die "Could not open config file '$file' for reading: $!";
        while (my $line = <$fh>) {
            chomp($line);
            $cmd = $1 and next if $line =~ m/^\[(.*)\]$/;
            $line =~ s/;.*$//g;
            $line =~ s/^\s*//g;
            $line =~ s/\s*$//g;
            next unless length($line);

            my ($key, $eq, $val);
            if ($line =~ m/^(-\S)((?:rel|glob|relglob)\(.*\))$/) {   # Handle things like -Irel(...)
                $key = $1;
                $eq  = '';
                $val = $2;
            }
            else {
                ($key, $eq, $val) = split /(=|\s+)/, $line, 2;  # Covers most cases
            }

            my $is_pre;
            if ($key =~ m/^-D/ || $key eq '--dev-lib') {
                $eq = '=' if $val;
                $is_pre = 1;
            }

            if ($key eq '--no-scan-plugins') {
                $is_pre = 1;
            }

            my $need_to_clean;
            if ($val && $val =~ s/(^|=)\s*rel\(\s*//) {
                die "Syntax error in $file line $.: Expected ')'\n" unless $val =~ s/\s*\)$//;
                my $path = $file;
                $path =~ s{[^/]*$}{}g;
                $val           = "${path}${val}";
                $need_to_clean = 1;
            }

            my @all;

            if ($val && $val =~ s/(^|=)\s*(rel)?glob\(\s*//) {
                my $rel = $2;

                die "Syntax error in $file line $.: Expected ')'\n" unless $val =~ s/\s*\)$//;

                my $path = '';
                if ($rel) {
                    $path = $file;
                    $path =~ s{[^/]*$}{}g;
                }

                # Avoid loading File::Glob in this process...
                my $out = `$^X -e 'print join "\\n" => glob("${path}${val}")'`;
                my @vals = split /\n/, $out;
                @all = map {[$key, $eq, $_, 1]} @vals;
            }
            else {
                @all = ([$key, $eq, $val, $need_to_clean]);
            }

            for my $set (@all) {
                my ($key, $eq, $val, $need_to_clean) = @$set;
                $eq //= '';

                my @parts = $eq eq '=' ? ("${key}${eq}${val}") : (grep { defined $_ } $key, $val);

                if ($is_pre) {
                    push @CONFIG_ARGS => @parts;
                }
                else {
                    $cmd //= '~';
                    push @{$CONFIG{$cmd}} => @parts;
                    push @TO_CLEAN => [$cmd, $#{$CONFIG{$cmd}}, $key, $eq, $val] if $need_to_clean;
                }
            }
        }
        close($fh);
    }

    unshift @ARGV => @CONFIG_ARGS;

    # ==END TESTABLE CODE PARSE_CONFIG_FILES==
    # ==START TESTABLE CODE PRE_PARSE_D_ARGS==

    my (@libs, %done, @args, $maybe_exec);
    while (@ARGV) {
        my $arg = shift @ARGV;

        if ($arg eq '--' || $arg eq '::') {
            push @args => $arg;
            last;
        }

        if ($arg eq '--no-dev-lib') {
            @libs = ();
            %done = ();
            next;
        }

        if ($arg =~ m{^(?:(?:-D=?|--dev-lib=)(.*)|--dev-lib)$}) {
            my @add = $1 ? ($1) : ();
            unless (@add) {
                @add        = ('lib', 'blib/lib', 'blib/arch');
                $maybe_exec = $arg;
            }

            push @libs => grep { !$done{$_}++ } @add;
            next;
        }

        if ($arg eq '--no-scan-plugins') {
            $NO_PLUGINS = 1;
            next;
        }

        push @args => $arg;
    }
    @ARGV = (@args, @ARGV);

    unshift @INC => @libs;
    unshift @DEVLIBS => @libs;

    # ==END TESTABLE CODE PRE_PARSE_D_ARGS==
    # ==START TESTABLE CODE EXEC==

    # Now it is safe/ok to load things.
    require Cwd;
    require File::Spec;

    $ORIG_TMP = File::Spec->tmpdir();
    $ORIG_TMP_PERMS = ((stat($ORIG_TMP))[2] & 07777);
    $SCRIPT = Cwd::realpath(__FILE__) // File::Spec->rel2abs(__FILE__);

    if ($maybe_exec && -e 'scripts/yath') {
        my $script = Cwd::realpath('scripts/yath') // File::Spec->rel2abs('scripts/yath');

        if ($SCRIPT ne $script) {
            warn "\n** $maybe_exec was used, and scripts/yath is present, using exec to switch to it. **\n\n";
            exec($script, @ORIG_ARGV);
            die("Should not see this, exec failed!");
        }
    }

    # ==END TESTABLE CODE EXEC==
    # ==START TESTABLE CODE CLEANUP_PATHS==

    if (@libs || @TO_CLEAN) {
        for (my $i = 0; $i < @libs; $i++) {
            $DEVLIBS[$i] = $INC[$i] = Cwd::realpath($INC[$i]) // File::Spec->rel2abs($INC[$i]);
        }

        for my $clean (@TO_CLEAN) {
            my ($cmd, $idx, $key, $eq, $val) = @$clean;
            $val = Cwd::realpath($val) // File::Spec->rel2abs($val);

            if ($eq eq '=') {
                $CONFIG{$cmd}->[$idx] = "${key}${eq}${val}";
            }
            else {
                $CONFIG{$cmd}->[$idx] = $val;
            }
        }
    }

    # ==END TESTABLE CODE CLEANUP_PATHS==
    # ==START TESTABLE CODE CREATE_APP==

    require App::Yath;
    require Time::HiRes;
    require Test2::Harness::Settings;

    my %mixin = (config_file => '', user_config_file => '');
    $mixin{config_file}      = Cwd::realpath($config_file)      // File::Spec->rel2abs($config_file)      if $config_file;
    $mixin{user_config_file} = Cwd::realpath($user_config_file) // File::Spec->rel2abs($user_config_file) if $user_config_file;

    my $settings = Test2::Harness::Settings->new(
        harness => {
            orig_tmp         => $ORIG_TMP,
            orig_tmp_perms   => $ORIG_TMP_PERMS,
            orig_sig         => \%ORIG_SIG,
            orig_argv        => \@ORIG_ARGV,
            orig_inc         => \@ORIG_INC,
            script           => $SCRIPT,
            no_scan_plugins  => $NO_PLUGINS,
            dev_libs         => \@DEVLIBS,
            start            => Time::HiRes::time(),
            version          => $App::Yath::VERSION,
            cwd              => Cwd::getcwd(),
            %mixin,
        },
    );

    my $app = App::Yath->new(
        argv    => \@ARGV,
        config  => \%CONFIG,
        settings => $settings,
    );

    $app->generate_run_sub('App::Yath::Script::run');

    # ==END TESTABLE CODE CREATE_APP==
}

# Reset these if we got this far.
$? = 0;
$@ = '';

exit(App::Yath::Script::run());

__END__

=pod

=encoding UTF-8

=head1 NAME

yath - Primary Command Line Interface (CLI) for Test2::Harness

=head1 DESCRIPTION

This is the primary command line interface for App::Yath/Test2::Harness. Yath
is essentially a shell around the components of L<Test2::Harness>.
For usage instructions and examples,
see L<App::Yath>.

=head1 SOURCE

The source code repository for Test2-Harness can be found at
F<http://github.com/Test-More/Test2-Harness/>.

=head1 MAINTAINERS

=over 4

=item Chad Granum E<lt>exodist@cpan.orgE<gt>

=back

=head1 AUTHORS

=over 4

=item Chad Granum E<lt>exodist@cpan.orgE<gt>

=back

=head1 COPYRIGHT

Copyright 2020 Chad Granum E<lt>exodist7@gmail.comE<gt>.

This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

See F<http://dev.perl.org/licenses/>

=cut