#!/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 { shift =~ /^\s*$/ and return 1; } sub comment { shift =~ /^\s*#/ and return 1; } sub trim { for (@_) { s/^\s+|\s+$//g; } return @_; } sub add { my ($src, $dst, $subst) = @_; $dst =~ s/@([\w]+)@/$subst->{$1}/g; if (-d $src) { mkdir $dst; opendir my $DIRFH, $src or die "Could not open '$src': $!"; while (readdir $DIRFH) { next if ($_ eq '.' or $_ eq '..'); add ("$src/$_", "$dst/$_", $subst); } 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 () { s/@([\w]+)@/$subst->{$1}/g; print OUT; } my $perms = (stat IN)[2] & 07777; close IN; close OUT; chmod ($perms | 0600, $dst); } } } 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/@([\w]+)@/$vars->{$1}/g; $val =~ s/\\([ \\n]|$)/$escape{$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 (my $var = ) { chomp $var; (comment $var or empty $var) and next; readvar \%distro_vars, $var; } 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 (my $var = ) { chomp $var; empty $var and last; comment $var and next; readvar \%package_vars, $var; } for (keys %package_vars) { defined $package_vars{$_} or $package_vars{$_} = ' '; # print "$_ = $package_vars{$_}\n"; } while (my $file = ) { chomp $file; empty $file and last; comment $file and next; add ("files/$file", "$package_path/$file", \%package_vars); addsource (\%package_vars, "$package_path/$file"); } # write the makefile my $outfile = "$package_path/Makefile"; print " - $outfile\n"; open MAKEFILE, '>', $outfile or die "Failed to open '$outfile' for writing: $!"; while (my $segment = ) { chomp $segment; empty $segment and last; comment $segment and next; open IN, '<', "segments/$segment" or die "Failed to open 'segments/$segment' 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 add ("managers/$distro_vars{'MANAGER'}", $package_path, \%package_vars); } }