package Greenstone::Package; use strict; use warnings; use utf8; use File::Path 'make_path'; use File::Copy 'cp'; use Greenstone::Helpers; use base 'Exporter'; use parent 'Greenstone::Config'; our $VERSION = 1.00; our @EXPORT = qw(makepkg); =head1 NAME Greenstone::Package =head1 SYNOPSIS use Greenstone::Package; makepkg ( package => 'package', distro => 'distro' ); =head1 DESCRIPTION This module will generate scripts for building Greenstone packages under various Linux distributions =head2 FUNCTIONS Only the makepkg function is exported. All other functions are internal and should not be used externally. =cut sub makepkg { my %args = @_; # sanity checks die "A package must have a name" unless (exists $args{package}); die "A package must have a distro" unless (exists $args{distro}); my $package_conf = "packages/$args{package}"; -f $package_conf or die "Package '$args{package}' does not exist"; my $distro_conf = "distros/$args{distro}"; -f $distro_conf or die "Distro '$args{distro}' does not exist"; # Classify ourselves as config and load the config my $self = bless({}, 'Greenstone::Config'); $self->readconf ("global.conf"); $self->readconf ($distro_conf); die "Distro '$args{distro}' is invalid (does not specify a manager)" unless (exists $self->{config}->{MANAGER}); my $class = __PACKAGE__ . '::_' . lc $self->{config}->{MANAGER}; eval "require $class; 1" or die "Package manager '$self->{config}->{MANAGER}' does not exist or did not compile"; # Reclassify as our implementation bless $self, $class; $self->readconf ($package_conf); $self->{package} = $args{package}; $self->{distro} = $args{distro}; $self->{output} = "build/$args{distro}/$args{package}"; make_path $self->{output}; $self->add_sources; $self->add_makefile; $self->add_install; $self->add_package; } # Copys the source files required for this package, # from the files/ folder # Performs variable substitution on file names, # and file content for plain-text files sub add_sources { my $self = shift; for my $source (@{$self->{config}->{SOURCES}}) { $self->add ("files/$source", "$self->{output}/$source", $self->{config}); } } # Generates the Makefile for this package, # by concatenating the files in the segments/ folder sub add_makefile { my $self = shift; push @{$self->{config}->{SOURCES}}, 'Makefile'; my $makefile = "$self->{output}/Makefile"; print " - $makefile\n"; open MAKEFILE, '>', $makefile or die "Failed to open '$makefile' for writing: $!"; for my $segment (@{$self->{config}->{MAKEFILE}}) { open IN, '<', "segments/$segment" or die "Failed to open 'segments/$segment' for reading: $!"; while (my $line = ) { $self->subst ($line); print MAKEFILE $line; } close IN; print MAKEFILE "\n"; } # add a target for packaging my $manager_segment = "segments/$self->{config}->{MANAGER}"; open IN, '<', $manager_segment or die "Failed to open '$manager_segment' for reading: $!"; while (my $line = ) { $self->subst ($line); print MAKEFILE $line; } close IN; close MAKEFILE; } # Generates the package-manager specific package generation scripts sub add_package { my $self = shift; $self->add ("managers/$self->{config}->{MANAGER}", $self->{output}); } # Adds a file or a folder to the package's folder sub add { my ($self, $src, $dst) = @_; $self->subst ($dst); if (-d $src) { mkdir $dst; opendir my $DIRFH, $src or die "Could not open '$src': $!"; while (readdir $DIRFH) { next if ($_ eq '.' or $_ eq '..'); $self->add ("$src/$_", "$dst/$_"); } closedir $DIRFH; } else { print ' - ', $dst, "\n"; if (-B $src or $src =~ /\.patch$/i) { # copy binary file cp $src, $dst or die "Failed to copy '$src': $!"; } else { # copy normal file open IN, '<', $src or die "Failed to open '$src' for reading: $!"; open OUT, '>', $dst or die "Failed to open '$dst' for writing: $!"; while (my $line = ) { $self->subst ($line); print OUT $line; } my $perms = (stat IN)[2] & 07777; close IN; close OUT; chmod ($perms | 0600, $dst); } } } 1;