#!/usr/bin/perl -w use strict; # sets mtime and atime of files to the latest commit time in git # # This is useful for serving static content (managed by git) # from a cluster of identically configured HTTP servers. HTTP # clients and content delivery networks can get consistent # Last-Modified headers no matter which HTTP server in the # cluster they hit. This should improve caching behavior. # # This does not take into account merges, but if you're updating # every machine in the cluster from the same commit (A) to the # same commit (B), the mtimes will be _consistent_ across all # machines if not necesarily accurate. # # THIS IS NOT INTENDED TO OPTIMIZE BUILD SYSTEMS SUCH AS 'make' # YOU HAVE BEEN WARNED! my %ls = (); my $commit_time; my $prefix = @ARGV && $ARGV[0] =~ s/^--prefix=// ? shift : ''; $/ = "\0"; open FH, 'git ls-files -z|' or die $!; while () { chomp; $ls{$_} = $_; } close FH; $/ = "\n"; my $pid = open FH, '-|'; defined $pid or die "fork failed $!\n"; if (!$pid) { # child exec qw/git log -c -r --name-only --no-color --pretty=raw -z/, @ARGV; die "exec failed: $!\n"; } # parent while () { chomp; if (/^committer .*? (\d+) (?:[\-\+]\d+)$/) { $commit_time = $1; } elsif (s/\0\0commit [a-f0-9]{40}$// or s/\0$//) { my @files = delete @ls{split(/\0/, $_)}; @files = grep { defined $_ } @files; next unless @files; map { s/^/$prefix/o } @files; utime $commit_time, $commit_time, @files; } last unless %ls; } close FH;