File Coverage

blib/lib/LCFG/Build/PkgSpec.pm
Criterion Covered Total %
statement 170 185 91.8
branch 41 46 89.1
condition 17 20 85.0
subroutine 27 29 93.1
pod 16 17 94.1
total 271 297 91.2


line stmt bran cond sub pod time code
1             package LCFG::Build::PkgSpec; # -*-perl-*-
2 10     10   352854 use strict;
  10         20  
  10         483  
3 10     10   57 use warnings;
  10         18  
  10         814  
4              
5             # $Id: PkgSpec.pm.in 27862 2015-06-24 10:11:40Z squinney@INF.ED.AC.UK $
6             # $Source: /var/cvs/dice/LCFG-Build-PkgSpec/lib/LCFG/Build/PkgSpec.pm.in,v $
7             # $Revision: 27862 $
8             # $HeadURL: https://svn.lcfg.org/svn/source/tags/LCFG-Build-PkgSpec/LCFG_Build_PkgSpec_0_1_0/lib/LCFG/Build/PkgSpec.pm.in $
9             # $Date: 2015-06-24 11:11:40 +0100 (Wed, 24 Jun 2015) $
10              
11             our $VERSION = '0.1.0';
12              
13 10     10   7533 use Data::Structure::Util ();
  10         89719  
  10         371  
14 10     10   10644 use DateTime ();
  10         1653336  
  10         475  
15 10     10   7605 use Email::Address ();
  10         333384  
  10         946  
16 10     10   9240 use Email::Valid ();
  10         1045241  
  10         318  
17 10     10   86 use IO::File ();
  10         16  
  10         147  
18 10     10   45 use Scalar::Util ();
  10         16  
  10         159  
19              
20 10     10   6589 use Moose;
  10         4543216  
  10         85  
21 10     10   68344 use Moose::Util::TypeConstraints;
  10         24  
  10         116  
22              
23             # A type and coercion to allow the attribute to be set as either an
24             # ref to an array or a scalar string.
25              
26             subtype 'ArrayRefOrString' => as 'ArrayRef[Str]';
27             coerce 'ArrayRefOrString' => from 'Str' => via { [ split /\s*,\s*/, $_ ] };
28              
29             subtype 'EmailAddress'
30             => as 'Str'
31             => where { Email::Valid->address( -address => $_ ) }
32             => message { "Address ($_) for report must be a valid email address" };
33              
34             subtype 'EmailAddressList'
35             => as 'ArrayRef[EmailAddress]';
36              
37             coerce 'EmailAddressList'
38             => from 'Str'
39             => via { [ map { $_->format } Email::Address->parse($_)] };
40              
41             coerce 'EmailAddressList'
42             => from 'ArrayRef'
43             => via { [ map { $_->format } map { Email::Address->parse($_) } @{$_} ] };
44              
45             subtype 'VersionString'
46             => as 'Str'
47             => where { $_ =~ m/^\d+\.\d+\.\d+(_dev)?$/ }
48             => message { $_ = 'undef' if !defined $_; "Version string ($_) does not match the expected LCFG format." };
49              
50             subtype 'ReleaseString'
51             => as 'Str'
52             => where { $_ =~ m/^\d+/ }
53             => message { "Release string ($_) does not match the expected LCFG format." };
54              
55             has 'name' => ( is => 'rw', required => 1 );
56             has 'base' => ( is => 'rw', default => q{} );
57             has 'abstract' => ( is => 'rw' );
58              
59             has 'version' => (
60             is => 'rw',
61             required => 1,
62             isa => 'VersionString',
63             default => '0.0.0',
64             );
65              
66             has 'release' => (
67             is => 'rw',
68             isa => 'Maybe[ReleaseString]',
69             default => 1,
70             );
71              
72             has 'schema' => (
73             is => 'rw',
74             isa => 'Int',
75             default => 1,
76             );
77              
78             has 'group' => ( is => 'rw');
79             has 'vendor' => ( is => 'rw');
80             has 'license' => ( is => 'rw');
81              
82             has 'translate' => (
83             is => 'rw',
84             isa => 'ArrayRef[Str]',
85             auto_deref => 1,
86             );
87              
88             has 'date' => (
89             is => 'rw',
90             isa => 'Str',
91             default => sub { DateTime->now->strftime('%d/%m/%y %T') },
92             );
93              
94             has 'metafile' => (
95             is => 'rw',
96             isa => 'Maybe[Str]',
97             );
98              
99             # I would quite like to treat author and platforms as sets but that
100             # doesn't seem to be available at present.
101              
102             has 'author' => (
103             is => 'rw',
104             isa => 'EmailAddressList',
105             coerce => 1,
106             auto_deref => 1,
107             default => sub { [] },
108             );
109              
110             has 'platforms' => (
111             is => 'rw',
112             isa => 'ArrayRefOrString',
113             coerce => 1,
114             auto_deref => 1,
115             default => sub { [] },
116             );
117              
118             has 'build' => (
119             traits => ['Hash'],
120             is => 'rw',
121             isa => 'HashRef[Str]',
122             default => sub { {} },
123             lazy => 1,
124             handles => {
125             exists_in_buildinfo => 'exists',
126             ids_in_buildinfo => 'keys',
127             get_buildinfo => 'get',
128             set_buildinfo => 'set',
129             },
130             );
131              
132             has 'vcs' => (
133             traits => ['Hash'],
134             is => 'rw',
135             isa => 'HashRef[Str]',
136             default => sub { {} },
137             handles => {
138             exists_in_vcsinfo => 'exists',
139             ids_in_vcsinfo => 'keys',
140             get_vcsinfo => 'get',
141             set_vcsinfo => 'set',
142             },
143             );
144              
145             has 'orgident' => (
146             is => 'rw',
147             isa => 'Str',
148             default => 'org.lcfg'
149             );
150              
151 10     10   28404 no Moose;
  10         25  
  10         70  
152             __PACKAGE__->meta->make_immutable;
153              
154             sub perl_version {
155 0     0 1 0 my ($self) = @_;
156              
157 0         0 my $perl_version = $self->version;
158 0 0       0 if ( $perl_version =~ s/_dev$// ) {
159              
160             # Cannot use a non-numeric in a Perl version string. A "devel"
161             # version is signified with a suffix which is an underscore
162             # and a release number. See "perldoc version" for details.
163              
164 0         0 my $release = $self->release;
165 0         0 $perl_version .= q{_} . $release;
166             }
167              
168 0         0 return $perl_version;
169             }
170              
171             sub get_major {
172 6     6 1 25 my ($self) = @_;
173              
174 6         315 my $version = $self->version;
175 6         25 $version =~ s/_dev$//;
176              
177 6         36 my $major = (split /\./, $version)[0];
178              
179 6         47 return $major;
180             }
181              
182             sub get_minor {
183 6     6 1 26 my ($self) = @_;
184              
185 6         350 my $version = $self->version;
186 6         23 $version =~ s/_dev$//;
187              
188 6         36 my $minor = (split /\./, $version)[1];
189              
190 6         58 return $minor;
191             }
192              
193             sub get_micro {
194 6     6 1 28 my ($self) = @_;
195              
196 6         311 my $version = $self->version;
197 6         20 $version =~ s/_dev$//;
198              
199 6         36 my $micro = (split /\./, $version)[2];
200              
201 6         37 return $micro;
202             }
203              
204             sub pkgident {
205 0     0 1 0 my ($self) = @_;
206              
207 0         0 my $org = $self->orgident;
208 0         0 my $name = $self->fullname;
209 0         0 my $id = join q{.}, $org, $name;
210              
211 0         0 return $id;
212             }
213              
214             sub fullname {
215 5     5 1 10 my ($self) = @_;
216              
217 5         10 my $fullname;
218 5 100 66     186 if ( defined $self->base && length $self->base > 0 ) {
219 3         77 $fullname = join q{-}, $self->base, $self->name;
220             }
221             else {
222 2         44 $fullname = $self->name;
223             }
224              
225 5         43 return $fullname;
226             }
227              
228             sub tarname {
229 1     1 1 2 my ($self) = @_;
230              
231 1         3 my $packname = join q{-}, $self->fullname, $self->version;
232 1         3 my $tarname = $packname . '.tar.gz';
233              
234 1         3 return $tarname;
235             }
236              
237             sub clone {
238 1     1 0 506 my ($self) = @_;
239              
240 1         12 require Storable;
241 1         166 my $clone = Storable::dclone($self);
242              
243 1         5 return $clone;
244             }
245              
246             sub new_from_metafile {
247 6     6 1 1502 my ( $class, $file ) = @_;
248              
249 6 100 100     177 if ( !defined $file || !length $file ) {
    100          
250 2         11 die "Error: You need to specify the LCFG meta-data file name\n";
251             }
252             elsif ( !-f $file ) {
253 1         8 die "Error: Cannot find LCFG meta-data file '$file'\n";
254             }
255              
256 3         1908 require YAML::Syck;
257 3         5513 my $data;
258             {
259             # Allow true/false, yes/no for booleans
260 3         6 local $YAML::Syck::ImplicitTyping = 1;
  3         7  
261              
262 3         13 $data = YAML::Syck::LoadFile($file);
263              
264             # We unbless as previously saved metafiles are going to have a
265             # blessing. We want all input files treated with the same
266             # amount of contempt.
267              
268 3         701 Data::Structure::Util::unbless($data);
269             }
270              
271 3         209 my $self = $class->new($data);
272              
273 3         87 $self->metafile($file);
274              
275 3         22 return $self;
276             }
277              
278             sub new_from_cfgmk {
279 9     9 1 1185 my ( $proto, $file ) = @_;
280              
281 9 100 100     301 if ( !defined $file || !length $file ) {
    100          
282 2         17 die "Error: You need to specify the LCFG config file name\n";
283             }
284             elsif ( !-f $file ) {
285 1         9 die "Error: Cannot find LCFG config file '$file'\n";
286             }
287              
288 6         63 my %translator = (
289             COMP => 'name',
290             DESCR => 'abstract',
291             V => 'version',
292             R => 'release',
293             SCHEMA => 'schema',
294             GROUP => 'group',
295             AUTHOR => 'author',
296             ORGANIZATION => 'vendor',
297             DATE => 'date',
298             );
299              
300 6         9 my %spec;
301              
302 6 50       61 my $in = IO::File->new( $file, 'r' ) or die "Could not open $file: $!\n";
303              
304 6         951 while ( defined ( my $line = <$in> ) ) {
305 173         276 $line =~ s/^\s+//;
306 173         445 $line =~ s/\s+$//;
307              
308 173         358 while ( $line =~ m{^(.*?)\\$} ) {
309 0         0 my $extra = <$in>;
310 0         0 $line = $1 . $extra;
311             }
312              
313 173 100       518 if ( $line =~ m/^([^=]+)=(.+)$/ ) {
314 143         277 my ( $key, $value ) = ( $1, $2 );
315 143 100       1073 if ( exists $translator{$key} ) {
    100          
    100          
316 53         260 $spec{ $translator{$key} } = $value;
317             }
318             elsif ( $key eq 'PLATFORMS' ) {
319 6         43 my @platforms = split /,\s*/, $value;
320 6         42 $spec{platforms} = [@platforms];
321             }
322             elsif ( $key eq 'NAME' ) {
323 6         9 my $compname;
324 6 50       42 if ( $value =~ m/^(.+?)-(.+?)$/ ) {
325 6         25 ( $spec{base}, $compname ) = ( $1, $2 );
326             }
327             else {
328 0         0 $compname = $value;
329             }
330              
331 6 100       32 if ( $compname ne '$(COMP)' ) {
332 1         7 $spec{name} = $compname;
333             }
334             }
335             }
336              
337             }
338              
339 6         60 $in->close;
340              
341 6         179 my $pkgspec;
342 6 100 100     66 if ( !ref $proto ) {
    100          
343 3         11 $spec{license} = 'GPLv2';
344 3   100     17 $spec{vendor} ||= 'University of Edinburgh';
345 3         14 $spec{vcs} = { logname => 'ChangeLog' };
346 3         10 $spec{build} = { gencmake => 1 };
347 3         10 $spec{translate} = [ '*.cin' ];
348 3         147 $pkgspec = $proto->new(\%spec);
349             }
350             elsif ( defined Scalar::Util::blessed($proto) && $proto->isa(__PACKAGE__) ) {
351 1         2 $pkgspec = $proto;
352 1         8 for my $key ( keys %spec ) {
353 11         552 $pkgspec->$key($spec{$key});
354             }
355             }
356             else {
357 2         42 die "Error: new_from_cfgmk method called on wrong class or object\n";
358             }
359              
360 3         50 return $pkgspec;
361             }
362              
363             sub save_metafile {
364 3     3 1 5883 my ( $self, $file ) = @_;
365              
366 3   66     137 $file ||= $self->metafile;
367              
368 3 100 66     15 if ( !defined $file || !length $file ) {
369 2         21 die "Error: You need to specify the LCFG config file name\n";
370             }
371              
372 1         9 require YAML::Syck;
373             {
374 1         1 local $YAML::Syck::SortKeys = 1;
  1         3  
375 1         1 my $dump = \%{$self};
  1         2  
376 1         3 delete $dump->{metafile};
377 1         6 YAML::Syck::DumpFile( $file, $dump );
378             }
379              
380 1         39335 return;
381             }
382              
383             sub dev_version {
384 2     2 1 5 my ($self) = @_;
385              
386 2         77 my $version = $self->version;
387 2 100       12 if ( $version !~ m/_dev$/ ) {
388 1         3 $version .= '_dev';
389 1         38 $self->version($version);
390             }
391              
392 2         8 $self->update_release;
393              
394 2         78 return $self->version;
395             }
396              
397             sub update_release {
398 6     6 1 1845 my ($self) = @_;
399              
400 6         255 my $release = $self->release;
401              
402 6 100       22 if ( !defined $release ) {
403 1         4 $release = 1;
404             }
405             else {
406 5         13 $release++;
407             }
408              
409 6         294 $self->release($release);
410              
411 6         15 return;
412             }
413              
414             sub update_date {
415 12     12 1 1000211 my ($self) = @_;
416              
417 12         119 my $now = DateTime->now->strftime('%d/%m/%y %T');
418              
419 12         8463 $self->date($now);
420              
421 12         25 return;
422             }
423              
424             sub update_major {
425 3     3 1 1000217 my ($self) = @_;
426 3         21 return $self->_update_version('major');
427             }
428              
429             sub update_minor {
430 3     3 1 1000266 my ($self) = @_;
431 3         19 return $self->_update_version('minor');
432             }
433              
434             sub update_micro {
435 4     4 1 1000791 my ($self) = @_;
436 4         26 return $self->_update_version('micro');
437             }
438              
439             sub _update_version {
440 11     11   1000393 my ( $self, $uptype ) = @_;
441              
442 11         716 my $version = $self->version;
443 11         39 $version =~ s/_dev$//;
444              
445 11         81 my ( $major, $minor, $micro ) = split /\./, $version;
446              
447 11 100       88 if ( $uptype eq 'major' ) {
    100          
    100          
448 3         11 $major++;
449 3         11 $minor = 0;
450 3         6 $micro = 0;
451             }
452             elsif ( $uptype eq 'minor' ) {
453 3         10 $minor++;
454 3         10 $micro = 0;
455             }
456             elsif ( $uptype eq 'micro' ) {
457 4         13 $micro++;
458             }
459             else {
460 1         22 die "Unknown version update-type: $uptype\n";
461             }
462              
463 10         44 my $newver = join q{.}, $major, $minor, $micro;
464              
465 10         433 my $rel = $self->release;
466 10         19 my $newrel;
467 10 100       51 if ( defined $rel ) {
468 9 50       73 if ( $rel =~ m/^\d+(.*)$/ ) {
469 9         49 $newrel = q{1} . $1;
470             }
471             else {
472 0         0 die "Release string, '$rel', does not match expected format\n";
473             }
474             }
475             else {
476 1         5 $newrel = 1;
477             }
478              
479             # Only update the attributes if everything else has succeeded
480             # (i.e. we got this far in the code).
481              
482 10         415 $self->version($newver);
483 10         570 $self->release($newrel);
484 10         53 $self->update_date();
485              
486 10         50 return;
487             }
488              
489             1;
490             __END__
491              
492             =head1 NAME
493              
494             LCFG::Build::PkgSpec - Object-oriented interface to LCFG build metadata
495              
496             =head1 VERSION
497              
498             This documentation refers to LCFG::Build::PkgSpec version 0.1.0
499              
500             =head1 SYNOPSIS
501              
502             my $spec = LCFG::Build::PkgSpec->new( name => "foo",
503             version => "0.0.1" );
504              
505             $spec->schema(2);
506              
507             $spec->save_metafile("./lcfg.yml");
508              
509             my $spec2 =
510             LCFG::Build::PkgSpec->new_from_metafile("./lcfg.yml");
511              
512             print "Package name is: " . $spec2->name . "\n";
513              
514             $spec2->update_major();
515              
516             $spec->save_metafile("./lcfg.yml");
517              
518             =head1 DESCRIPTION
519              
520             This class provides an object-oriented interface to the LCFG build
521             tools metadata file. All simple fields are available through attribute
522             accessors. Specific methods are also provided for querying and
523             modifying the more complex data types (e.g. lists and hashes).
524              
525             This class has methods for carrying out specific procedures related to
526             tagging releases with the LCFG build tools. It also has methods for
527             handling the old format LCFG build configuration files.
528              
529             More information on the LCFG build tools is available from the website
530             http://www.lcfg.org/doc/buildtools/
531              
532             =head1 ATTRIBUTES
533              
534             =over 4
535              
536             =item name
537              
538             This is the name of the project or LCFG component. In the case of the
539             component think of it as the "foo" part of "lcfg-foo". When an object
540             is created this field MUST be specified, there is no default value.
541              
542             =item base
543              
544             This is only really meaningful in terms of LCFG components, in which
545             case it is the "lcfg" part of "lcfg-foo" or the "dice" part of
546             "dice-foo". This is optional and the default value is an empty string.
547              
548             =item abstract
549              
550             This is a short description of the project, it is optional and there
551             is no default.
552              
553             =item version
554              
555             This is the version of the project, it is required and if not
556             specified at object creation time it will default to '0.0.0'. Due to
557             backwards compatibility reasons this version must be in 3 integer
558             parts separated with the period character. Any attempt to set it
559             otherwise will result in an error being thrown.
560              
561             =item release
562              
563             This is the release number for a project and is directly related to
564             the release field used for RPMs and Debian packages. It is optional
565             and defaults to 1. If used, the first character of the release field
566             MUST be an integer, after that you can put in whatever you like.
567              
568             =item schema
569              
570             This is only really meaningful in terms of LCFG components. It is the
571             schema number of the defaults file which specifies the details for the
572             supported resources. It is optional and will default to 1.
573              
574             =item group
575              
576             This is the software group into which this project best fits, it is
577             mainly provided for RPM specfile generation support
578             (e.g. "Development/Libraries"). It is optional and has no default
579             value.
580              
581             =item vendor
582              
583             This matches the "Vendor" field used in RPMs, it is optional and has
584             no default value.
585              
586             =item orgident
587              
588             This is an identifier for your organisation which is based on the
589             reversed form of your domain name, C<com.example> or C<org.example>
590             for example. No validation is done to check if this is the reversal of
591             a real domain name, you can use whatever you want, the default value
592             is C<org.lcfg>. This is used by the C<pkgident> method as part of the
593             process of generating MacOSX packages.
594              
595             =item license
596              
597             This is the short string used in RPMs to specify the license for the
598             project. This field is optional and there is no default value.
599              
600             =item date
601              
602             This is used to show the date and time at which the project version
603             was last altered. If not specified it will default to the current date
604             and time in the format 'DD/MM/YY HH:MM:SS'.
605              
606             =item author
607              
608             This is the name (or list of names) of the project author(s). The
609             default value is an empty list. You should note that calling this
610             accessor with no arguments returns a list not a scalar value. See
611             below for convenience methods provided for accessing and managing the
612             information contained with the list.
613              
614             =item platforms
615              
616             This is the list of supported platforms for the project. The default
617             value is an empty list. You should note that calling this accessor
618             with no arguments returns a list not a scalar value. See below for
619             convenience methods provided for accessing and managing the
620             information contained with the list.
621              
622             =item vcs
623              
624             This is a reference to a hash containing details of the version
625             control system used for the project. This is optional and defaults to
626             an empty hash. See below for convenience methods provided for
627             accessing and managing the information contained with the hash.
628              
629             =back
630              
631             =head1 SUBROUTINES/METHODS
632              
633             =over 4
634              
635             =item fullname
636              
637             Returns the full name of the package, if the 'base' attribute is
638             specified then this will be a combination of base and package name
639             separated with a hyphen, e.g. 'lcfg-foo'. If no base is specified then
640             this is just the package name, e.g. 'foo'.
641              
642             =item pkgident
643              
644             This returns a string formed by the concatenation of the C<orgident>
645             and C<fullname> values, joined with a period character,
646             C<com.example.lcfg-client> for example. This is used as the identifier
647             name for MacOSX packages.
648              
649             =item tarname
650              
651             Returns the standard LCFG name of the tarfile which would be generated
652             for this version of the package. This combines the full name and the
653             version, for example, lcfg-foo-1.0.1.tar.gz
654              
655             =item new_from_metafile($file)
656              
657             Create a new object which represents the LCFG build metadata stored in
658             the YAML file.
659              
660             =item save_metafile($file)
661              
662             Save the object data into the LCFG metadata file.
663              
664             =item new_from_cfgmk($file)
665              
666             Create from the old-style LCFG config.mk a new object which represents
667             the LCFG build metadata.
668              
669             =item perl_version
670              
671             This returns the package version as a string in a style which is safe
672             for use in Perl modules. If this is a development release the C<dev>
673             suffix is replaced with the value of the release. This is done because
674             Perl versions are not permitted to contain non-numeric characters.
675              
676             =item get_major
677              
678             Get just the major (first) part of the package version.
679              
680             =item get_minor
681              
682             Get just the minor (middle) part of the package version.
683              
684             =item get_micro
685              
686             Get just the micro (last) part of the package version.
687              
688             =item update_major
689              
690             Increment by one the first (largest) part of the version. This will
691             also reset the second and third parts of the version to 0 (zero) and
692             the release field to 1. For example, version 1.2.3 would become 2.0.0
693             and the release field would go from 5 to 1.
694              
695             =item update_minor
696              
697             Increment by one the second (middle) part of the version. This will
698             also reset the third part of the version to 0 (zero) and the release
699             field to 1. For example, version 1.2.3 would become 1.3.0 and the
700             release field would go from 5 to 1.
701              
702             =item update_micro
703              
704             Increment by one the third (smallest) part of the version field. This
705             will also reset the release field to 1. For example, version 1.2.3
706             would become 1.2.4 and the release field would go from 5 to 1.
707              
708             =item update_date
709              
710             Update the date attribute to the current time, this is set to the
711             format 'DD/MM/YY HH:MM::SS'. You should not normally need to call this
712             method, it is called at the end of the update_micro, update_minor and
713             update_major methods to show when the version update occurred.
714              
715             =item update_release
716              
717             This method updates the release field by incrementing the value. If it
718             was not previously defined then it will be set to one.
719              
720             =item dev_version
721              
722             This method converts the version to the development format. If it is
723             not already present an '_dev' string is appended to the version
724             string. The release field is also incremented.
725              
726             =item add_author
727              
728             A convenience method for adding new authors to the list of project
729             authors. Note that this does not prevent an author being added
730             multiple times.
731              
732             =item add_platform
733              
734             A convenience method for adding new platforms to the list of
735             supported platforms for this project. Note that this does not prevent
736             a platform being added multiple times.
737              
738             =item exists_in_vcsinfo($key)
739              
740             A convenience method to see if a particular key exists in the
741             version-control information.
742              
743             =item ids_in_vcsinfo
744              
745             A convenience method to get a list of all the keys in the
746             version-control information.
747              
748             =item get_vcsinfo($key)
749              
750             A convenience method to get the data associated with a particular key
751             in the version-control information.
752              
753             =item set_vcsinfo($key, $value)
754              
755             A convenience method to set the data associated with a particular key
756             in the version-control information.
757              
758             =item exists_in_buildinfo($key)
759              
760             A convenience method to see if a particular key exists in the
761             build information.
762              
763             =item ids_in_buildinfo
764              
765             A convenience method to get a list of all the keys in the
766             build information.
767              
768             =item get_buildinfo($key)
769              
770             A convenience method to get the data associated with a particular key
771             in the build information.
772              
773             =item set_buildinfo($key, $value)
774              
775             A convenience method to set the data associated with a particular key
776             in the build information.
777              
778             =back
779              
780             =head1 DEPENDENCIES
781              
782             This module is L<Moose> powered. It also requires
783             L<Data::Structure::Util>, L<DateTime> and if you want to parse and
784             write LCFG metadata files you will need L<YAML::Syck>.
785              
786             =head1 SEE ALSO
787              
788             lcfg-cfg2meta(1), lcfg-pkgcfg(1), LCFG::Build::Tools(3)
789              
790             =head1 PLATFORMS
791              
792             This is the list of platforms on which we have tested this
793             software. We expect this software to work on any Unix-like platform
794             which is supported by Perl.
795              
796             ScientificLinux5, ScientificLinux6
797              
798             =head1 BUGS AND LIMITATIONS
799              
800             There are no known bugs in this application. Please report any
801             problems to bugs@lcfg.org, feedback and patches are also always very
802             welcome.
803              
804             =head1 AUTHOR
805              
806             Stephen Quinney <squinney@inf.ed.ac.uk>
807              
808             =head1 LICENSE AND COPYRIGHT
809              
810             Copyright (C) 2008-2015 University of Edinburgh. All rights reserved.
811              
812             This library is free software; you can redistribute it and/or modify
813             it under the terms of the GPL, version 2 or later.
814              
815             =cut