File Coverage

blib/lib/OTRS/OPM/Parser.pm
Criterion Covered Total %
statement 129 130 99.2
branch 32 34 94.1
condition 10 10 100.0
subroutine 16 17 94.1
pod 4 4 100.0
total 191 195 97.9


line stmt bran cond sub pod time code
1             package OTRS::OPM::Parser;
2             $OTRS::OPM::Parser::VERSION = '1.05';
3             # ABSTRACT: Parser for the .opm file
4              
5 9     9   955927 use Moo;
  9         109058  
  9         57  
6 9     9   18842 use MooX::HandlesVia;
  9         90397  
  9         59  
7 9     9   5331 use OTRS::OPM::Parser::Types qw(:all);
  9         35  
  9         110  
8              
9 9     9   515337 use MIME::Base64 ();
  9         7285  
  9         294  
10 9     9   5054 use OTRS::OPM::Validate;
  9         35210  
  9         345  
11 9     9   4221 use Path::Class;
  9         359428  
  9         633  
12 9     9   5086 use Try::Tiny;
  9         12062  
  9         548  
13 9     9   6562 use XML::LibXML;
  9         514523  
  9         63  
14              
15             # declare attributes
16             has product => ( is => 'rw', isa => Str, );
17             has name => ( is => 'rw', isa => Str, );
18             has version => ( is => 'rw', isa => VersionString, );
19             has vendor => ( is => 'rw', isa => Str, );
20             has url => ( is => 'rw', isa => Str, );
21             has license => ( is => 'rw', isa => Str, );
22             has description => ( is => 'rw', isa => Str, );
23             has error_string => ( is => 'rw', isa => Str, );
24             has tree => ( is => 'rw', isa => XMLTree, );
25              
26             has opm_file => (
27             is => 'ro',
28             isa => Str,
29             required => 1,
30             );
31              
32             has files => (
33             is => 'rw',
34             isa => ArrayRef[HashRef],
35             default => sub{ [] },
36             handles_via => 'Array',
37             handles => {
38             add_file => 'push',
39             },
40             );
41              
42             has framework => (
43             handles_via => 'Array',
44             is => 'rw',
45             isa => ArrayRef[FrameworkVersionString],
46             default => sub { [] },
47             handles => {
48             add_framework => 'push',
49             },
50             );
51              
52             has framework_details => (
53             handles_via => 'Array',
54             is => 'rw',
55             isa => ArrayRef[HashRef],
56             default => sub { [] },
57             handles => {
58             add_framework_detail => 'push',
59             },
60             );
61              
62             has dependencies => (
63             handles_via => 'Array',
64             is => 'rw',
65             isa => ArrayRef[HashRef[Str]],
66             default => sub { [] },
67             handles => {
68             add_dependency => 'push',
69             },
70             );
71              
72              
73             sub documentation {
74 9     9 1 11036 my ($self,%params) = @_;
75            
76 9         21 my $doc_file;
77             my $found_file;
78            
79 9   100     49 my $lang = $params{lang} || 'en';
80 9   100     29 my $type = $params{type} || '';
81              
82 9         15 for my $file ( @{ $self->files } ) {
  9         205  
83              
84 35         105 my $filename = $file->{filename};
85 35 100       103 next if $filename !~ m{ \A doc/ }x;
86            
87 19 100       38 if ( !$doc_file ) {
88 8         16 $doc_file = $file;
89 8         14 $found_file = $filename;
90             }
91            
92 19 100       155 next if $filename !~ m{ \A doc/$lang/ }x;
93            
94 9 100       58 if ( $found_file !~ m{ \A doc/$lang/ }x ) {
95 3         6 $doc_file = $file;
96 3         3 $found_file = $filename;
97             }
98            
99 9 100 100     163 next if $type && $filename !~ m{ \A doc/[^/]+/.*\.$type \z }x;
100            
101 7 100 100     57 if ( $type && $found_file !~ m{ \A doc/[^/]+/.*\.$type \z }x ) {
102 1         3 $doc_file = $file;
103 1         2 $found_file = $filename;
104             }
105              
106 7 100       113 last if $found_file =~ m{ \A doc/$lang/.*\.$type \z }x;
107             }
108            
109 9         41 return $doc_file;
110             }
111              
112             sub validate {
113 15     15 1 3815 my ($self) = @_;
114              
115 15         354 $self->error_string( '' );
116            
117 15 100       832 if ( !-e $self->opm_file ) {
118 1         27 $self->error_string( 'File does not exist' );
119 1         29 return;
120             }
121              
122             try {
123 14     14   834 my $fh = IO::File->new( $self->opm_file, 'r' );
124 14         2251 my $content = join '', $fh->getlines;
125 14         3533 OTRS::OPM::Validate->validate( $content );
126             }
127             catch {
128 3     3   669 $self->error_string( 'opm file is invalid: ' . $_ );
129 14         172 };
130              
131 14 100       17539 return if $self->error_string;
132 11         125 return 1;
133             }
134              
135             sub parse {
136 10     10 1 6609 my ($self) = @_;
137              
138 10         271 $self->error_string( '' );
139            
140 10 100       626 if ( !-e $self->opm_file ) {
141 1         26 $self->error_string( 'File does not exist' );
142 1         29 return;
143             }
144            
145 9         34 my $tree;
146             try {
147 9     9   645 my $parser = XML::LibXML->new;
148 9         258 $tree = $parser->parse_file( $self->opm_file );
149              
150 8         4060 $self->tree( $tree );
151             }
152             catch {
153 1     1   815 $self->error_string( 'Could not parse .opm: ' . $_ );
154 1         130 return;
155 9         114 };
156              
157 9 100       795 return if $self->error_string;
158            
159 8         116 my $is_valid = $self->validate;
160 8 50       43 return if !$is_valid;
161            
162 8         88 my $root = $tree->getDocumentElement;
163            
164             # collect basic data
165 8         72 $self->vendor( $root->findvalue( 'Vendor' ) );
166 8         2319 $self->name( $root->findvalue( 'Name' ) );
167 8         1157 $self->license( $root->findvalue( 'License' ) );
168 8         1061 $self->version( $root->findvalue( 'Version' ) );
169 8         257 $self->url( $root->findvalue( 'URL' ) );
170              
171 8         1080 my $root_name = $root->nodeName;
172 8         52 $root_name =~ s{_package}{};
173              
174 8         164 $self->product( $root_name );
175            
176             # retrieve framework information
177 8         308 my @frameworks = $root->findnodes( 'Framework' );
178            
179             FILE:
180 8         299 for my $framework ( @frameworks ) {
181 34         1511 my $framework_version = $framework->textContent;
182            
183 34         108 my %details = ( Content => $framework_version );
184 34         96 my $maximum = $framework->findvalue( '@Maximum' );
185 34         1861 my $minimum = $framework->findvalue( '@Minimum' );
186              
187 34 100       1654 $details{Maximum} = $maximum if $maximum;
188 34 100       86 $details{Minimum} = $minimum if $minimum;
189            
190             # push framework info to attribute
191 34         736 $self->add_framework( $framework_version );
192 34         2240 $self->add_framework_detail( \%details );
193             }
194              
195             # retrieve file information
196 8         378 my @files = $root->findnodes( 'Filelist/File' );
197            
198             FILE:
199 8         294 for my $file ( @files ) {
200 30         1199 my $name = $file->findvalue( '@Location' );
201            
202             #next FILE if $name !~ m{ \. (?:pl|pm|pod|t) \z }xms;
203 30         1866 my $encode = $file->findvalue( '@Encode' );
204 30 100       1583 next FILE if $encode ne 'Base64';
205            
206 28         272 my $content_base64 = $file->textContent;
207 28         263 my $content = MIME::Base64::decode( $content_base64 );
208            
209             # push file info to attribute
210 28         651 $self->add_file({
211             filename => $name,
212             content => $content,
213             });
214             }
215            
216             # get description - english if available, any other language otherwise
217 8         320 my @descriptions = $root->findnodes( 'Description' );
218 8         247 my $description_string;
219            
220             DESCRIPTION:
221 8         25 for my $description ( @descriptions ) {
222 10         52 $description_string = $description->textContent;
223 10         39 my $language = $description->findvalue( '@Lang' );
224            
225 10 100       572 last DESCRIPTION if $language eq 'en';
226             }
227            
228 8         200 $self->description( $description_string );
229            
230             # get OTRS and CPAN dependencies
231 8         332 my @otrs_deps = $root->findnodes( 'PackageRequired' );
232 8         272 my @cpan_deps = $root->findnodes( 'ModuleRequired' );
233            
234 8         217 my %types = (
235             PackageRequired => 'OTRS',
236             ModuleRequired => 'CPAN',
237             );
238            
239 8         38 for my $dep ( @otrs_deps, @cpan_deps ) {
240 24         933 my $node_type = $dep->nodeName;
241 24         77 my $version = $dep->findvalue( '@Version' );
242 24         1416 my $dep_name = $dep->textContent;
243 24         70 my $dep_type = $types{$node_type};
244            
245 24         561 $self->add_dependency({
246             type => $dep_type,
247             version => $version,
248             name => $dep_name,
249             });
250             }
251            
252 8         422 return 1;
253             }
254              
255             sub as_sopm {
256 2     2 1 3152 my ($self) = @_;
257              
258 2         53 my $tree = $self->tree->cloneNode(1);
259 2         121 my $root = $tree->getDocumentElement;
260            
261 2         10 my @build_host = $root->findnodes( 'BuildHost' );
262 2         110 my @build_date = $root->findnodes( 'BuildDate' );
263            
264 2         77 $root->removeChild( $_ ) for @build_host;
265 2         46 $root->removeChild( $_ ) for @build_date;
266              
267             #$build_host->unbindNode() if $build_host;
268             #$build_date->unbindNode() if $build_date;
269            
270 2         27 my @files = $root->findnodes( 'Filelist/File' );
271 2         86 for my $file ( @files ) {
272 9         25 my ($encode) = $file->findnodes( '@Encode' );
273 9 50       307 $encode->unbindNode() if $encode;
274            
275 9         114 $file->removeChildNodes();
276             }
277            
278 2         17 return $tree->toString;
279             }
280              
281              
282             sub _get_xsd {
283              
284 0     0     return q~
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            
317            
318            
319            
320            
321            
322            
323            
324            
325            
326            
327            
328            
329            
330            
331            
332            
333            
334            
335            
336            
337            
338            
339            
340            
341            
342            
343            
344            
345            
346            
347            
348            
349            
350            
351              
352            
353            
354            
355            
356            
357            
358            
359            
360            
361            
362            
363            
364            
365            
366            
367            
368            
369            
370            
371            
372            
373            
374            
375            
376            
377            
378            
379            
380            
381            
382            
383            
384            
385            
386            
387            
388            
389            
390            
391            
392            
393            
394            
395            
396            
397            
398            
399            
400            
401            
402            
403            
404            
405            
406            
407            
408            
409            
410            
411            
412            
413            
414            
415            
416            
417            
418            
419            
420            
421            
422            
423            
424            
425            
426            
427            
428            
429            
430            
431            
432            
433            
434            
435            
436            
437            
438            
439            
440            
441            
442            
443            
444            
445            
446            
447            
448            
449            
450            
451            
452            
453            
454            
455            
456            
457            
458            
459            
460            
461            
462            
463            
464            
465            
466            
467            
468            
469            
470            
471            
472            
473            
474            
475            
476            
477            
478            
479            
480            
481            
482            
483            
484            
485            
486            
487            
488            
489            
490            
491            
492            
493            
494            
495            
496            
497            
498            
499            
500            
501            
502            
503            
504            
505            
506            
507              
508            
509            
510            
511            
512            
513            
514            
515            
516            
517            
518            
519            
520            
521            
522            
523            
524            
525            
526            
527            
528            
529            
530            
531            
532            
533            
534            
535            
536            
537            
538            
539            
540            
541            
542            
543            
544            
545            
546            
547            
548            
549            
550            
551            
552            
553            
554            
555            
556            
557            
558            
559            
560            
561            
562            
563            
564            
565            
566            
567            
568            
569            
570            
571            
572            
573            
574            
575            
576            
577            
578            
579            
580            
581            
582            
583            
584            
585            
586            
587            
588              
589            
590            
591            
592            
593            
594            
595              
596            
597            
598            
599            
600            
601            
602              
603            
604            
605            
606            
607            
608            
609            
610            
611            
612            
613            
614            
615            
616            
617            
618            
619            
620              
621            
622            
623            
624            
625            
626            
627            
628              
629            
630            
631            
632            
633            
634            
635            
636              
637            
638            
639            
640            
641            
642            
643            
644            
645            
646            
647            
648            
649            
650            
651            
652            
653              
654            
655            
656            
657            
658            
659            
660            
661              
662            
663            
664            
665            
666            
667            
668            
669              
670            
671            
672            
673            
674            
675            
676            
677            
678            
679            
680            
681            
682            
683            
684            
685            
686            
687            
688              
689            
690            
691            
692            
693            
694            
695            
696            
697            
698             ~;
699             }
700              
701             1;
702              
703             __END__