File Coverage

blib/lib/Lang/Go/Mod.pm
Criterion Covered Total %
statement 69 69 100.0
branch 49 54 90.7
condition 3 9 33.3
subroutine 8 8 100.0
pod 2 2 100.0
total 131 142 92.2


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Brad Clawsie, 2021 -- brad.clawsie@gmail.com
5              
6             package Lang::Go::Mod;
7 2     2   485757 use warnings;
  2         13  
  2         76  
8 2     2   11 use strict;
  2         3  
  2         48  
9 2     2   11 use Carp qw(croak);
  2         5  
  2         112  
10 2     2   1256 use English qw(-no_match_vars);
  2         8210  
  2         17  
11 2     2   819 use Exporter qw(import);
  2         7  
  2         63  
12 2     2   1893 use Path::Tiny qw(path);
  2         24769  
  2         2153  
13              
14             # ABSTRACT: parse and model go.mod files
15              
16             our $VERSION = '0.005';
17             our $AUTHORITY = 'cpan:bclawsie';
18              
19             our @EXPORT_OK = qw(read_go_mod parse_go_mod);
20              
21             sub read_go_mod {
22 1     1 1 158 my $use_msg = 'use: read_go_mod(go_mod_path)';
23 1   33     7 my $go_mod_path = shift || croak $use_msg;
24              
25 1   33     7 my $go_mod_content = path($go_mod_path)->slurp_utf8 || croak "$ERRNO";
26              
27 1         1358 return parse_go_mod($go_mod_content);
28             }
29              
30             sub parse_go_mod {
31 13   33 13 1 10174 my $go_mod_content = shift || croak 'use: parse_go_mod(go_mod_content)';
32              
33 13         28 my $m = {};
34 13         32 $m->{exclude} = {};
35 13         25 $m->{replace} = {};
36 13         26 $m->{'require'} = {};
37 13         31 my ( $excludes, $replaces, $requires ) = ( 0, 0, 0 );
38              
39 13         116 LINE: for my $line ( split /\n/msx, $go_mod_content ) {
40 69 100       230 next LINE if ( $line =~ /^\s*$/msx );
41 54 100       95 if ($excludes) {
42 3 100       45 if ( $line =~ /^\s*[)]\s*$/msx ) {
    100          
43 1         16 $excludes = 0;
44             }
45             elsif ( $line =~ /\s*(\S+)\s+(\S+)/msx ) {
46 1 50       21 $m->{exclude}->{$1} = [] unless ( defined $m->{exclude}->{$1} );
47 1         3 push @{ $m->{exclude}->{$1} }, $2;
  1         15  
48             }
49             else {
50 1         99 croak "malformed exclude line $line";
51             }
52 2         6 next LINE;
53             }
54 51 100       88 if ($replaces) {
55 4 100       25 if ( $line =~ /^\s*[)]\s*$/msx ) {
    100          
56 1         2 $replaces = 0;
57             }
58             elsif ( $line =~ /^\s*(\S+)\s+=>\s+(\S+)\s*$/msx ) {
59             croak "duplicate replace for $1"
60 2 50       10 if ( defined $m->{replace}->{$1} );
61 2         9 $m->{replace}->{$1} = $2;
62             }
63             else {
64 1         116 croak "malformed replace line $line";
65             }
66 3         7 next LINE;
67             }
68 47 100       80 if ($requires) {
69 5 100       40 if ( $line =~ /^\s*[)]\s*$/msx ) {
    100          
70 1         2 $requires = 0;
71             }
72             elsif ( $line =~ /^\s*(\S+)\s+(\S+).*$/msx ) {
73             croak "duplicate require for $1"
74 3 50       13 if ( defined $m->{'require'}->{$1} );
75 3         11 $m->{'require'}->{$1} = $2;
76             }
77             else {
78 1         96 croak "malformed require line $line";
79             }
80 4         7 next LINE;
81             }
82              
83 42 100       276 if ( $line =~ /^module\s+(\S+)$/msx ) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
84 12         46 $m->{module} = $1;
85             }
86             elsif ( $line =~ /^go\s+(\S+)$/msx ) {
87 12         33 $m->{go} = $1;
88             }
89             elsif ( $line =~ /^exclude\s+[(]\s*$/msx ) {
90              
91             # beginning of exclude block
92 2         5 $excludes = 1;
93             }
94             elsif ( $line =~ /^replace\s+[(]\s*$/msx ) {
95              
96             # beginning of replace block
97 2         5 $replaces = 1;
98             }
99             elsif ( $line =~ /^require\s+[(]\s*$/msx ) {
100              
101             # beginning of require block
102 2         5 $requires = 1;
103             }
104             elsif ( $line =~ /^exclude\s+(\S+)\s+(\S+)\s*$/msx ) {
105              
106             # single exclude
107 3 100       15 $m->{$1} = [] unless ( defined $m->{exclude}->{$1} );
108 3         5 push @{ $m->{exclude}->{$1} }, $2;
  3         11  
109             }
110             elsif ( $line =~ /^replace\s+(\S+)\s+=>\s+(\S+)\s*$/msx ) {
111              
112             # single replace
113             croak "duplicate replace for $1"
114 1 50       5 if ( defined $m->{replace}->{$1} );
115 1         4 $m->{replace}->{$1} = $2;
116             }
117             elsif ( $line =~ /^require\s+(\S+)+\s+(\S+).*$/msx ) {
118              
119             # single require
120             croak "duplicate require for $1"
121 1 50       5 if ( defined $m->{'require'}->{$1} );
122 1         14 $m->{'require'}->{$1} = $2;
123             }
124             elsif ( $line =~ m{^\s*//.*$}mx ) {
125              
126             # comment
127              
128             }
129             else {
130 6         967 croak "unknown line content: $line";
131             }
132             }
133              
134 4 100       285 croak 'missing module line' unless ( defined $m->{module} );
135 3 100       248 croak 'missing go line' unless ( defined $m->{go} );
136              
137 2         9 return $m;
138             }
139              
140             1;
141              
142             __END__