diff options
author | Niels Thykier <niels@thykier.net> | 2016-01-10 10:19:29 +0000 |
---|---|---|
committer | Niels Thykier <niels@thykier.net> | 2016-01-10 10:47:26 +0000 |
commit | 1566865e67d2712c45462794cc29d89f75c011d1 (patch) | |
tree | 017ca3bd9b5e2ae6f7d467686c9d631829f958ce | |
parent | bca06f8d784fb0d6ac6f1358fc1ea2366fbb774e (diff) | |
download | debhelper-1566865e67d2712c45462794cc29d89f75c011d1.tar.gz |
Dh_Lib: Add restore_file_on_clean
Signed-off-by: Niels Thykier <niels@thykier.net>
-rw-r--r-- | Debian/Debhelper/Dh_Lib.pm | 78 | ||||
-rwxr-xr-x | dh_clean | 10 | ||||
-rw-r--r-- | doc/PROGRAMMING | 9 |
3 files changed, 95 insertions, 2 deletions
diff --git a/Debian/Debhelper/Dh_Lib.pm b/Debian/Debhelper/Dh_Lib.pm index 3d846b6e..da20b76b 100644 --- a/Debian/Debhelper/Dh_Lib.pm +++ b/Debian/Debhelper/Dh_Lib.pm @@ -35,6 +35,7 @@ use vars qw(@EXPORT %dh); &install_file &install_prog &install_lib &install_dir &get_source_date_epoch &is_cross_compiling &generated_file &autotrigger &package_section + &restore_file_on_clean &restore_all_files ); my $max_compat=10; @@ -1322,6 +1323,83 @@ sub install_dh_config_file { return 1; } +sub restore_file_on_clean { + my ($file) = @_; + my $bucket_index = 'debian/.debhelper/bucket/index'; + my $bucket_dir = 'debian/.debhelper/bucket/files'; + my $checksum; + if (not -d $bucket_dir) { + install_dir($bucket_dir); + } + if ($file =~ m{^/}) { + error("restore_file_on_clean requires a path relative to the package dir"); + } + $file =~ s{^\./}{}g; + $file =~ s{//++}{}g; + if ($file =~ m{^\.} or $file =~ m{/CVS/} or $file =~ m{/\.svn/}) { + # We do not want to smash a Vcs repository by accident. + warning("Attempt to store $file, which looks like a VCS file or"); + warning("a hidden package file (like quilt's \".pc\" directory"); + error("This tool probably contains a bug."); + } + if (-l $file or not -f _) { + error("Cannot store $file, which is a non-file (incl. a symlink)"); + } + require Digest::SHA; + + $checksum = Digest::SHA->new('256')->addfile($file, 'b')->hexdigest; + + if (not $dh{NO_ACT}) { + my ($in_index); + open(my $fd, '+>>', $bucket_index) + or error("open($bucket_index, a+) failed: $!"); + seek($fd, 0, 0); + while (my $line = <$fd>) { + my ($cs, $stored_file); + chomp($line); + ($cs, $stored_file) = split(m/ /, $line, 2); + next if ($stored_file ne $file); + $in_index = 1; + } + if (not $in_index) { + # Copy and then rename so we always have the full copy of + # the file in the correct place (if any at all). + doit('cp', '-an', '--reflink=auto', $file, "${bucket_dir}/${checksum}.tmp"); + doit('mv', '-f', "${bucket_dir}/${checksum}.tmp", "${bucket_dir}/${checksum}"); + print {$fd} "${checksum} ${file}\n"; + } + close($fd) or error("close($bucket_index) failed: $!"); + } + + return 1; +} + +sub restore_all_files { + my $bucket_index = 'debian/.debhelper/bucket/index'; + my $bucket_dir = 'debian/.debhelper/bucket/files'; + + return if not -f $bucket_index; + open(my $fd, '<', $bucket_index) + or error("open($bucket_index) failed: $!"); + + while (my $line = <$fd>) { + my ($cs, $stored_file, $bucket_file); + chomp($line); + ($cs, $stored_file) = split(m/ /, $line, 2); + $bucket_file = "${bucket_dir}/${cs}"; + # Restore by copy and then rename. This ensures that: + # 1) If dh_clean is interrupted, we can always do a full restore again + # (otherwise, we would be missing some of the files and have to handle + # that with scary warnings) + # 2) The file is always fully restored or in its "pre-restore" state. + doit('cp', '-an', '--reflink=auto', $bucket_file, "${bucket_file}.tmp"); + doit('mv', '-Tf', "${bucket_file}.tmp", $stored_file); + } + close($fd); + return; +} + + 1 # Local Variables: @@ -113,8 +113,14 @@ foreach my $package (@{$dh{DOPACKAGES}}) { unless excludefile($tmp); } -# Remove internal state data -doit('rm', '-rf', 'debian/.debhelper/') if not $dh{D_FLAG}; + +if (not $dh{D_FLAG}) { + # Restore all files in our bucket (before we delete said bucket) + restore_all_files(); + + # Remove internal state data + doit('rm', '-rf', 'debian/.debhelper/'); +} # Remove all debhelper logs. diff --git a/doc/PROGRAMMING b/doc/PROGRAMMING index e5b9a726..1f03bdfb 100644 --- a/doc/PROGRAMMING +++ b/doc/PROGRAMMING @@ -290,6 +290,15 @@ load_log($package, $hashref) write_log($cmd, $package ...) Writes the log files for the specified package(s), adding the cmd to the end. +restore_file_on_clean($file) + Store a copy of $file, which will be restored by dh_clean. + The $file *must* be a relative path to the package root and + *must* be a real regular file. Dirs, devices and symlinks + (and everything else) *cannot* be restored by this. + If $file is passed multiple times (e.g. from different programs) + only the first version is stored. + CAVEAT: This *cannot* undo arbitrary "rm -fr"'ing. The dir, + which is/was in $file, must be present when dh_clean is called. make_symlink($src, $dest, $tmp) Creates a Policy compliant sytem link called $dest pointing to $src. If $tmp is given, then $tmp will be prefixed to $dest when |