| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#!/usr/bin/env perl |
|
2
|
|
|
|
|
|
|
# |
|
3
|
|
|
|
|
|
|
# ClarID-Tools CLI |
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
# Last Modified: Aug/08/2025 |
|
6
|
|
|
|
|
|
|
# |
|
7
|
|
|
|
|
|
|
# $VERSION taken from ClarID::Tools |
|
8
|
|
|
|
|
|
|
# |
|
9
|
|
|
|
|
|
|
# Copyright (C) 2025 Manuel Rueda - CNAG |
|
10
|
|
|
|
|
|
|
# |
|
11
|
|
|
|
|
|
|
# License: Artistic License 2.0 |
|
12
|
|
|
|
|
|
|
# |
|
13
|
|
|
|
|
|
|
# If this program helps you in your research, please cite. |
|
14
|
|
|
|
|
|
|
|
|
15
|
41
|
|
|
41
|
|
220870
|
use strict; |
|
|
41
|
|
|
|
|
110
|
|
|
|
41
|
|
|
|
|
1931
|
|
|
16
|
41
|
|
|
41
|
|
327
|
use warnings; |
|
|
41
|
|
|
|
|
159
|
|
|
|
41
|
|
|
|
|
2402
|
|
|
17
|
41
|
|
|
41
|
|
21066
|
use FindBin qw($Bin); |
|
|
41
|
|
|
|
|
61663
|
|
|
|
41
|
|
|
|
|
6745
|
|
|
18
|
41
|
|
|
41
|
|
27330
|
use lib "$Bin/../lib"; |
|
|
41
|
|
|
|
|
35103
|
|
|
|
41
|
|
|
|
|
299
|
|
|
19
|
41
|
|
|
41
|
|
26090
|
use ClarID::Tools; |
|
|
41
|
|
|
|
|
197
|
|
|
|
41
|
|
|
|
|
777
|
|
|
20
|
41
|
|
|
41
|
|
44207
|
use JSON::XS qw(encode_json); |
|
|
41
|
|
|
|
|
254594
|
|
|
|
41
|
|
|
|
|
3590
|
|
|
21
|
41
|
|
|
41
|
|
19542
|
use POSIX qw(strftime); |
|
|
41
|
|
|
|
|
310497
|
|
|
|
41
|
|
|
|
|
328
|
|
|
22
|
41
|
|
|
41
|
|
72134
|
use Cwd qw(getcwd); |
|
|
41
|
|
|
|
|
78
|
|
|
|
41
|
|
|
|
|
2792
|
|
|
23
|
|
|
|
|
|
|
|
|
24
|
41
|
|
|
41
|
|
292
|
use Path::Tiny; |
|
|
41
|
|
|
|
|
257
|
|
|
|
41
|
|
|
|
|
105276
|
|
|
25
|
|
|
|
|
|
|
|
|
26
|
41
|
|
|
|
|
8798133
|
my ( $LOG_PATH, $ARGV_ORIG ) = _extract_log_path(); |
|
27
|
41
|
|
|
|
|
306
|
_log_invocation( $LOG_PATH, $ARGV_ORIG ); |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# Shared usage text |
|
30
|
41
|
|
|
|
|
118
|
my $USAGE = <<'END_USAGE'; |
|
31
|
|
|
|
|
|
|
Error: no command given. |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Usage: |
|
34
|
|
|
|
|
|
|
clarid-tools [options] |
|
35
|
|
|
|
|
|
|
clarid-tools help [all|code|validate|qrcode] |
|
36
|
|
|
|
|
|
|
clarid-tools --version |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
Commands: |
|
39
|
|
|
|
|
|
|
code Encode or decode IDs using your codebook |
|
40
|
|
|
|
|
|
|
validate Validate a codebook against its JSON schema |
|
41
|
|
|
|
|
|
|
qrcode Encode or decode ClarIDs to/from QR codes |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
Run `clarid-tools help all` to see every option at once. |
|
44
|
|
|
|
|
|
|
END_USAGE |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# Dispatch |
|
47
|
|
|
|
|
|
|
# NOTE: we read @ARGV *after* stripping -log so users can put -log anywhere |
|
48
|
41
|
|
50
|
|
|
253
|
my $cmd = shift @ARGV // ''; |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# version flag |
|
51
|
41
|
50
|
33
|
|
|
407
|
if ( $cmd eq '-v' || $cmd eq '--v' || $cmd eq '--version' ) { |
|
|
|
|
33
|
|
|
|
|
|
52
|
0
|
|
|
|
|
0
|
printf "clarid-tools version %s\n", ClarID::Tools->VERSION; |
|
53
|
0
|
|
|
|
|
0
|
exit; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
41
|
50
|
|
|
|
256
|
if ( $cmd =~ /^-?-?help$/ ) { |
|
57
|
0
|
|
0
|
|
|
0
|
my $sub = shift @ARGV // 'all'; |
|
58
|
0
|
0
|
|
|
|
0
|
if ( $sub eq 'all' ) { |
|
59
|
0
|
|
|
|
|
0
|
for my $c (qw(code validate qrcode)) { |
|
60
|
0
|
|
|
|
|
0
|
print "\n=== clarid-tools $c options ===\n\n"; |
|
61
|
0
|
|
|
|
|
0
|
system( $^X, $0, $c, '--help' ); |
|
62
|
|
|
|
|
|
|
} |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
else { |
|
65
|
0
|
|
|
|
|
0
|
exec $^X, $0, $sub, '--help'; |
|
66
|
|
|
|
|
|
|
} |
|
67
|
0
|
|
|
|
|
0
|
exit; |
|
68
|
|
|
|
|
|
|
} |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# No command or unknown |
|
71
|
41
|
50
|
33
|
|
|
448
|
if ( !$cmd || $cmd !~ /^(?:code|validate|qrcode)$/ ) { |
|
72
|
0
|
|
|
|
|
0
|
die $USAGE; |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# Delegate to subcommands |
|
76
|
41
|
100
|
|
|
|
192
|
if ( $cmd eq 'code' ) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
77
|
36
|
|
|
|
|
31796
|
require ClarID::Tools::Command::code; |
|
78
|
36
|
|
|
|
|
786
|
ClarID::Tools::Command::code->new_with_options->execute; |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
elsif ( $cmd eq 'validate' ) { |
|
81
|
5
|
|
|
|
|
3415
|
require ClarID::Tools::Command::validate; |
|
82
|
5
|
|
|
|
|
83
|
ClarID::Tools::Command::validate->new_with_options->execute; |
|
83
|
|
|
|
|
|
|
} |
|
84
|
|
|
|
|
|
|
elsif ( $cmd eq 'qrcode' ) { |
|
85
|
0
|
|
|
|
|
0
|
require ClarID::Tools::Command::qrcode; |
|
86
|
0
|
|
|
|
|
0
|
ClarID::Tools::Command::qrcode->new_with_options->execute; |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# --- logging glue ---------------------------------------------------- |
|
90
|
|
|
|
|
|
|
sub _extract_log_path { |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# Returns (log_path_or_undef, \@argv_original) |
|
93
|
41
|
|
|
41
|
|
621
|
my @orig = @ARGV; |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# We must handle -log, --log, and --log=FILE, anywhere in ARGV |
|
96
|
41
|
|
|
|
|
387
|
for ( my $i = 0 ; $i < @ARGV ; $i++ ) { |
|
97
|
712
|
|
|
|
|
1137
|
my $arg = $ARGV[$i]; |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# --log=/path/file |
|
100
|
712
|
50
|
|
|
|
1755
|
if ( $arg =~ /^--log=(.*)$/ ) { |
|
101
|
0
|
0
|
|
|
|
0
|
my $path = $1 ne '' ? $1 : './clarid-cli.log'; |
|
102
|
0
|
|
|
|
|
0
|
splice @ARGV, $i, 1; |
|
103
|
0
|
|
|
|
|
0
|
return ( $path, \@orig ); |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# -log or --log [optional path] |
|
107
|
712
|
100
|
66
|
|
|
2630
|
if ( $arg eq '-log' || $arg eq '--log' ) { |
|
108
|
1
|
|
|
|
|
1
|
my $path = './clarid-cli.log'; |
|
109
|
1
|
50
|
33
|
|
|
6
|
if ( defined $ARGV[ $i + 1 ] && $ARGV[ $i + 1 ] !~ /^-/ ) { |
|
110
|
1
|
|
|
|
|
1
|
$path = $ARGV[ $i + 1 ]; |
|
111
|
1
|
|
|
|
|
3
|
splice @ARGV, $i, 2; # remove flag and path |
|
112
|
|
|
|
|
|
|
} |
|
113
|
|
|
|
|
|
|
else { |
|
114
|
0
|
|
|
|
|
0
|
splice @ARGV, $i, 1; # remove flag only |
|
115
|
|
|
|
|
|
|
} |
|
116
|
1
|
|
|
|
|
3
|
return ( $path, \@orig ); |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
} |
|
119
|
40
|
|
|
|
|
273
|
return ( undef, \@orig ); |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub _log_invocation { |
|
123
|
41
|
|
|
41
|
|
150
|
my ( $log_file, $argv_snapshot ) = @_; |
|
124
|
41
|
100
|
|
|
|
163
|
return unless $log_file; |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# Never crash CLI on logging errors |
|
127
|
1
|
|
|
|
|
2
|
eval { |
|
128
|
1
|
|
|
|
|
154
|
my $rec = { |
|
129
|
|
|
|
|
|
|
ts => strftime( '%Y-%m-%dT%H:%M:%SZ', gmtime ), |
|
130
|
|
|
|
|
|
|
cmd => $0, |
|
131
|
|
|
|
|
|
|
argv => $argv_snapshot, # original ARGV (including -log) |
|
132
|
|
|
|
|
|
|
cwd => getcwd(), |
|
133
|
|
|
|
|
|
|
pid => $$, |
|
134
|
|
|
|
|
|
|
version => ClarID::Tools->VERSION, |
|
135
|
|
|
|
|
|
|
}; |
|
136
|
1
|
|
|
|
|
37
|
my $json = JSON::XS->new->utf8->canonical->encode($rec); # utf-8 |
|
137
|
1
|
|
|
|
|
10
|
path($log_file)->spew($json); |
|
138
|
|
|
|
|
|
|
}; |
|
139
|
1
|
|
|
|
|
5924
|
return; |
|
140
|
|
|
|
|
|
|
} |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
1; |