[debhelper-devel] [debhelper] 01/02: Dh_Lib: Add restore_file_on_clean

Niels Thykier nthykier at moszumanska.debian.org
Sun Jan 10 10:54:22 UTC 2016


This is an automated email from the git hooks/post-receive script.

nthykier pushed a commit to branch master
in repository debhelper.

commit 1566865e67d2712c45462794cc29d89f75c011d1
Author: Niels Thykier <niels at thykier.net>
Date:   Sun Jan 10 10:19:29 2016 +0000

    Dh_Lib: Add restore_file_on_clean
    
    Signed-off-by: Niels Thykier <niels at thykier.net>
---
 Debian/Debhelper/Dh_Lib.pm | 78 ++++++++++++++++++++++++++++++++++++++++++++++
 dh_clean                   | 10 ++++--
 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 3d846b6..da20b76 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:
diff --git a/dh_clean b/dh_clean
index 666766d..f5fc8ad 100755
--- a/dh_clean
+++ b/dh_clean
@@ -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 e5b9a72..1f03bdf 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

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debhelper/debhelper.git




More information about the debhelper-devel mailing list