#!/usr/bin/env perl # Generates Makefiles for different systems and packages # Uses a hashmap to do config variables (see readvar for how variables are # read in and an example of how they are resolved / used) use strict; use warnings; use utf8; use File::Basename; use File::Path 'make_path'; use File::Copy 'cp'; use Storable 'dclone'; use Digest::MD5; my $USAGE = "Usage: " . basename($0) . " distros: A comma separated list of the distros defined in distros/ Or 'all' (for all distros) packages: A comma separated list of the packages defined in packages/ Or 'all' (for all packages) "; $#ARGV == 1 or die $USAGE; sub globbify { my ($dir, $files) = @_; $files =~ /^all$/i and return glob "$dir/*"; my @list = glob "$dir/{$files}"; for (@list) { -f or die "Could not find '", $_, "'"; } return @list; } sub empty { /^\s*$/ and return 1; } sub comment { /^\s*#/ and return 1; } sub trim { for (@_) { s/^\s+|\s+$//g; } return @_; } sub copydir { my ($src, $dst, $subst) = @_; mkdir $dst; opendir my $DIRFH, $src or die "Could not open '$src': $!"; while (readdir $DIRFH) { next if ($_ eq '.' or $_ eq '..'); print " - $dst/$_\n"; if (-d "$src/$_") { # copy folder copydir ("$src/$_", "$dst/$_", $subst); } elsif (-B "$src/$_") { # copy binary file cp "$src/$_", "$dst/$_" or die "Failed to copy '$_': $!"; } else { # copy normal file my $newFile = "$dst/$_"; open OUT, '>', $newFile or die "Failed to open '$_' for writing: $!"; open IN, '<', "$src/$_" or die "Failed to open '$_' for reading: $!"; while () { s/@([\w]+)@/$subst->{$1}/g; print OUT; } my $perms = (stat IN)[2] & 07777; close IN; close OUT; chmod ($perms | 0600, $newFile); } } closedir $DIRFH; } my %escape = ( "n" => "\n", "\\" => "\\", " " => " " ); sub readvar { my ($vars, $line) = @_; my ($var, $val) = trim (split ":", $line, 2); defined $var and defined $val or die "Invalid variable assignment: '$line'"; local $/ = ''; $val =~ s/\\([ \\n]|$)/$escape{$1}/g; $val =~ s/@([\w]+)@/$vars->{$1}/g; $vars->{$var} = $val; } sub addsource { my ($vars, $source) = @_; my $md5 = Digest::MD5->new; open my $MD5FH, '<', $source; binmode $MD5FH; $md5->addfile ($MD5FH); my $field_separator = $vars->{'FIELD_SEPARATOR'}; $vars->{'SOURCES'} .= $field_separator . basename($source); $vars->{'SOURCE_SUMS'} .= $field_separator . $md5->hexdigest; close $MD5FH; } my @distros = globbify "distros", shift; my @packages = globbify "packages", shift; for my $dconf (@distros) { my $distro = basename $dconf; print "$distro\n"; open DISTRO, '<', $dconf; my %distro_vars; while () { chomp; (comment or empty) and next; readvar \%distro_vars, $_; } close DISTRO; for my $pconf (@packages) { my $package = basename $pconf; print " - $package\n"; my $package_path = "build/$distro/$package"; make_path $package_path; open PACKAGE, '<', $pconf; my %package_vars = %{dclone \%distro_vars}; while () { chomp; empty and last; comment and next; readvar \%package_vars, $_; } for (keys %package_vars) { defined $package_vars{$_} or $package_vars{$_} = ' '; # print "$_ = $package_vars{$_}\n"; } while () { chomp; empty and last; comment and next; cp "files/$_", "$package_path/$_" or die "Failed to copy '$_': $!"; addsource \%package_vars, "$package_path/$_"; } # write the makefile my $outfile = "$package_path/Makefile"; print " - $outfile\n"; open MAKEFILE, '>', $outfile or die "Failed to open '$outfile' for writing: $!"; while () { chomp; empty and last; comment and next; open IN, '<', "segments/$_" or die "Failed to open '$_' for reading: $!"; while () { s/@([\w]+)@/$package_vars{$1}/g; print MAKEFILE; } close IN; print MAKEFILE "\n"; } close PACKAGE; # add a target for packaging if (open IN, '<', "segments/$distro_vars{'MANAGER'}") { while () { s/@([\w]+)@/$package_vars{$1}/g; print MAKEFILE; } close IN; } close MAKEFILE; addsource \%package_vars, $outfile; # write the package manager files copydir ("managers/$distro_vars{'MANAGER'}", $package_path, \%package_vars); } }