#!/usr/bin/perl # Uses symlinks to merge the files contained in a set of subversion # checkouts to into a single directory. Keeps track of when files are # removed from the merged directories and removes the symlinks. # # Only merges files that match the specified pattern. # # Note that the directories given to merge should be paths that will work # for symlink targets from the destination directory (so either full paths, # or they should be right inside the destination directory). # # Note that other files in the destination directory will be left as-is. # # Copyright 2006 by Joey Hess, licensed under the GPL. if (! @ARGV) { die "usage: svnmerge include-pattern dest dir1 [dir2 ...]\n"; } my $pattern=shift; my $dest=shift; foreach my $dir (@ARGV) { my %known; # Link in each thing from the dir. opendir(DIR, $dir) || die "opendir: $!"; while ($_=readdir(DIR)) { next if $_ eq '.' || $_ eq '..' || $_ eq 'known' || $_ eq '.svn'; next unless /$pattern/; $known{$_}=1; if (! -l "$dest/$_" && -e "$dest/$_") { print STDERR "$_ in $dir is also in $dest\n"; } elsif (! -l "$dest/$_") { system("ln", "-svf", "$dir/$_", $dest); } } closedir(DIR); # Remove anything that was previously linked in but is not in the # dir anymore. if (-e "$dir/known") { open(KNOWN, "$dir/known") || die "open $dir/known: $!"; while () { chomp; if (! $known{$_}) { system("rm", "-vf", "$dest/$_"); } } close KNOWN; } # Save state for next time. open(KNOWN, ">$dir/known") || die "write $dir/known: $!"; foreach my $file (sort keys %known) { print KNOWN "$file\n"; } close KNOWN; }