diff options
-rwxr-xr-x | build | 103 |
1 files changed, 103 insertions, 0 deletions
@@ -0,0 +1,103 @@ +#!/usr/bin/perl + +# build -- process and act on embedded build instructions + +use strict; +use warnings; + +# parse arguments + +my ($debug, $fork) = (0, 0); +my $usage = "usage: $0 [-dddf] file [...]\n"; + +while (@ARGV and ($_ = $ARGV[0]) =~ /^-/) { + shift @ARGV; + last if $_ eq '--'; + $debug++ for /(d)/g; + $fork++ if /f/; + die $usage if /[^-df]/; +} + +die $usage if not @ARGV; + +# find build line(s) in each file + +my $i; +for my $file (@ARGV) { + my ($cmd, $target, @deps); + open my $f, '<', $file or die "could not open $file: $!\n"; + $i = 1; + while (<$f>) { + if (not $cmd and m{ + ^ .* + (?: (?:build|generate) \s+ (?:it \s+)? with + | (?:built|generated) \s+ with + | the \s+ command + | run(?:ning)? + | issu(?:e|ing) + ) \s+ + (.+?) \s* (?: > \s* (.+?))? \.? \s* + (?:\*/)? \s* $ + }x) { + warn "$file build line: $_" if $debug > 2; + $cmd = $1; + $target = $2; + } + elsif (not @deps and m{ + ^ .* + (?: depends \s+ on + | dependent \s+ on + ) \s+ + (?: the \s+ files? \s+ )? + (.+?) \.? \s* + (?:\*/)? \s* $ + }x) { + warn "$file dependency line: $_" if $debug > 2; + push @deps, $_ for split /,?\s+/, $1; + if ($deps[-2] eq 'and') { + $deps[-2] = $deps[-1]; + pop @deps; + } + } + last if ++$i > 20; + } + warn "$file dependencies: @deps\n" if $debug > 1; + build($file, $cmd, $target, @deps) if $cmd; + warn "$file: no build line found\n" if not $cmd; +} + +# build target according to build line + +sub build { + my ($source, $cmd, $target, @deps) = @_; + my $m = (stat$target)[9]; + + if (! -e $target) { + warn "$source: building because $target does not exist\n" + if $debug; + goto update; + } + + for ($source, @deps) { + if (! -e $_) { + warn "$source: non-existent dependency '$_'\n"; + next; + } + if ($m < (stat$_)[9]) { + warn "$source: building because $_ is modified\n" + if $debug; + goto update; + } + } + warn "$source: $target already up-to-date\n"; + return; + +update: + warn "$source: $cmd > $target\n"; + if ($fork) { + exec('/bin/sh', '-c', "$cmd > $target") if fork() == 0; + } else { + system("$cmd > $target"); + } + return; +} |