summaryrefslogtreecommitdiffstats
path: root/dh_install
diff options
context:
space:
mode:
Diffstat (limited to 'dh_install')
-rwxr-xr-xdh_install393
1 files changed, 393 insertions, 0 deletions
diff --git a/dh_install b/dh_install
new file mode 100755
index 0000000..665f77c
--- /dev/null
+++ b/dh_install
@@ -0,0 +1,393 @@
+#!/usr/bin/perl
+
+=head1 NAME
+
+dh_install - install files into package build directories
+
+=cut
+
+use strict;
+use warnings;
+use Debian::Debhelper::Dh_Lib;
+
+our $VERSION = DH_BUILTIN_VERSION;
+
+=head1 SYNOPSIS
+
+B<dh_install> [B<-X>I<item>] [B<--autodest>] [B<--sourcedir=>I<dir>] [S<I<debhelper options>>] [S<I<file|dir> ... I<destdir>>]
+
+=head1 DESCRIPTION
+
+B<dh_install> is a debhelper program that handles installing files into package
+build directories. There are many B<dh_install>I<*> commands that handle installing
+specific types of files such as documentation, examples, man pages, and so on,
+and they should be used when possible as they often have extra intelligence for
+those particular tasks. B<dh_install>, then, is useful for installing everything
+else, for which no particular intelligence is needed. It is a replacement for
+the old B<dh_movefiles> command.
+
+This program may be used in one of two ways. If you just have a file or two
+that the upstream Makefile does not install for you, you can run B<dh_install>
+on them to move them into place. On the other hand, maybe you have a large
+package that builds multiple binary packages. You can use the upstream
+F<Makefile> to install it all into F<debian/tmp>, and then use B<dh_install> to copy
+directories and files from there into the proper package build directories.
+
+From debhelper compatibility level 7 on, B<dh_install> will fall back to
+looking in F<debian/tmp> for files, if it does not find them in the current
+directory (or wherever you've told it to look using B<--sourcedir>).
+
+=head1 FILES
+
+=over 4
+
+=item debian/I<package>.install
+
+List the files to install into each package and the directory they should be
+installed to. The format is a set of lines, where each line lists a file or
+files to install, and at the end of the line tells the directory it should be
+installed in. The name of the files (or directories) to install should be given
+relative to the current directory, while the installation directory is given
+relative to the package build directory. You may use wildcards in the names of
+the files to install.
+
+Note that if you list exactly one filename or wildcard-pattern on a line by
+itself, with no explicit destination, then B<dh_install>
+will automatically guess the destination to use, the same as if the
+--autodest option were used.
+
+Supports substitution variables in compat 13 and later as
+documented in L<debhelper(7)>.
+
+=item debian/not-installed
+
+Used with the deprecated B<--list-missing> and B<--fail-missing> options.
+Please refer to L<dh_missing(1)> for the documentation of this file.
+
+=back
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--list-missing>
+
+B<Deprecated>: Please use B<dh_missing --list-missing> instead. If you use
+this option, B<dh_install> will call B<dh_missing> with that option after it has
+processed all the files. Please see L<dh_missing(1)> for the documentation of
+this option.
+
+This option is removed in compat 12.
+
+=item B<--fail-missing>
+
+B<Deprecated>: Please use B<dh_missing --fail-missing> instead. If you use
+this option, B<dh_install> will call B<dh_missing> with that option after it has
+processed all the files. Please see L<dh_missing(1)> for the documentation of
+this option.
+
+This option is removed in compat 12.
+
+=item B<--sourcedir=>I<dir>
+
+Look in the specified directory for files to be installed.
+
+Note that this is not the same as the B<--sourcedirectory> option used
+by the B<dh_auto_>I<*> commands. You rarely need to use this option, since
+B<dh_install> automatically looks for files in F<debian/tmp> in debhelper
+compatibility level 7 and above.
+
+=item B<--autodest>
+
+Guess as the destination directory to install things to. If this is
+specified, you should not list destination directories in
+F<debian/package.install> files or on the command line. Instead, B<dh_install>
+will guess as follows:
+
+Strip off F<debian/tmp> (or the sourcedir if one is given) from the front of
+the filename, if it is present, and install into the dirname of the
+filename. So if the filename is F<debian/tmp/usr/bin>, then that directory
+will be copied to F<debian/package/usr/>. If the filename is
+F<debian/tmp/etc/passwd>, it will be copied to F<debian/package/etc/>.
+
+=item I<file|dir> ... I<destdir>
+
+Lists files (or directories) to install and where to install them to.
+The files will be installed into the first package F<dh_install> acts on.
+
+=back
+
+=cut
+
+init(options => {
+ "autodest" => \$dh{AUTODEST},
+ "list-missing" => \$dh{LIST_MISSING},
+ "fail-missing" => \$dh{FAIL_MISSING},
+ "sourcedir=s" => \$dh{SOURCEDIR},
+});
+
+my $srcdir = '.';
+if (defined($dh{SOURCEDIR})) {
+ $srcdir = $dh{SOURCEDIR};
+ $srcdir =~ s{/+$}{};
+ error("Invalid --sourcedir - must not be empty nor /") if not $srcdir;
+}
+
+my $missing_files = 0;
+
+if ($dh{LIST_MISSING} || $dh{FAIL_MISSING}) {
+ deprecated_functionality('Please use dh_missing --list-missing/--fail-missing instead', 12);
+}
+
+# Support for -X flag.
+my $exclude = '';
+if ($dh{EXCLUDE_FIND}) {
+ $exclude = '! \( '.$dh{EXCLUDE_FIND}.' \)';
+}
+
+# PROMISE: DH NOOP WITHOUT pkgfile-logged(install) cli-options()
+
+foreach my $package (getpackages()) {
+ my (@installed, %dest2sources);
+ my $default_source_dir = default_sourcedir($package);
+ my @search_dirs = ($srcdir);
+ push(@search_dirs, $default_source_dir) if not compat(6);
+
+ # Look at the install files for all packages to handle
+ # list-missing/fail-missing, but skip really installing for
+ # packages that are not being acted on.
+ my $skip_install = process_pkg($package) ? 0 : 1;
+
+ my $tmp=tmpdir($package);
+ my $file=pkgfile($package,"install");
+
+ my @install;
+ if ($file) {
+ @install=filedoublearray($file); # no globbing here; done below
+ }
+
+
+ # With autodest, we can just pretend every pattern was on its own line
+ @install = map { [$_] } map { @$_ } @install if $dh{AUTODEST};
+
+ if (($package eq $dh{FIRSTPACKAGE} || $dh{PARAMS_ALL}) && @ARGV) {
+ if ($dh{AUTODEST}) {
+ # Same as above, with autodest, we can just isolate each entry
+ # - the split is for bug-backwards compatibility (#867866).
+ push(@install, map { [$_] } map { split } @ARGV);
+ } else {
+ # Bug backwards compatibility (#867866). The new "glob_expand"
+ # interface is smart enough to not split on spaces, but dh_install
+ # used to do that... *except* for the "DEST" since it was never
+ # passed to the glob function.
+ my @a = @ARGV;
+ my $dest = pop(@a) if @a > 1;
+ my @srcs = map { split } @a;
+ push(@srcs, $dest) if defined($dest);
+ push(@install, \@srcs);
+ }
+ }
+
+
+ my $glob_error_handler = sub {
+ # Do not require a match for packages that not acted on
+ # (directly). After all, the files might not have been
+ # generated/compiled.
+ return if $skip_install;
+ ++$missing_files;
+ goto \&glob_expand_error_handler_warn_and_discard;
+ };
+
+ foreach my $set (@install) {
+ my ($dest, @filelist, @patterns);
+
+ if (@$set > 1) {
+ $dest=pop @$set;
+ }
+ # Skip excluded patterns. We will need two exclude checks per pattern;
+ # 1) exclude the entire pattern as people expect this to work (#814856)
+ # 2) exclude files matched by the pattern as people could have just
+ # excluded a single file of a "dir/*"-pattern.
+ # This line below filters entire patterns
+ @patterns = grep { not excludefile($_) } @{$set};
+ next if not @patterns;
+ foreach my $glob (@patterns) {
+ my @found = glob_expand(\@search_dirs, $glob_error_handler, $glob);
+ push(@filelist, map { tr{/}{/}s; $_ } @found);
+ }
+
+ if (! @filelist && ! $skip_install) {
+ warning("$package missing files: @$set");
+ ++$missing_files;
+ next;
+ }
+
+ # Do a quick bulk handling of excluded files and update @installed.
+ # - this is for filtering files matched by the pattern
+ @filelist = grep { not excludefile($_) } @filelist if $exclude;
+ push(@installed, @filelist);
+
+ # ... because then we can short-curcit here.
+ next if $skip_install or $missing_files;
+
+ if (not $exclude) {
+ my @unoptimized;
+ for my $src (@filelist) {
+ my $d = $dest // compute_dest($default_source_dir, $src);
+ my $basename = basename($src);
+ if (exists($dest2sources{$d}{$basename})) {
+ # If there is a clash, silently undo the optimizations.
+ # See #866405 and #868169.
+ my $replaced = delete($dest2sources{$d}{$basename});
+ # Associate the $replaced the destination
+ # directory. We cannot be sure that compute_dest will
+ # get it right nor can we blindly set $dest.
+ #
+ # It is technically unnecessary for $src, but we
+ # might as well do it to possibly save a
+ # compute_dest call.
+ push(@unoptimized, [$replaced, $d], [$src, $d]);
+ next;
+ }
+ $dest2sources{$d}{$basename} = $src;
+ }
+ next if not @unoptimized;
+ @filelist = @unoptimized;
+ }
+
+ foreach my $src (@filelist) {
+
+ my $target_dest;
+
+ if (ref($src)) {
+ # On a failed optimization, we will have the
+ # destination directory.
+ ($src, $target_dest) = @{$src};
+ } else {
+ $target_dest = $dest;
+ if (! defined $target_dest) {
+ # Guess at destination directory.
+ $target_dest = compute_dest($default_source_dir, $src);
+ }
+ }
+
+ # Make sure the destination directory exists.
+ install_dir("$tmp/$target_dest");
+
+ if (-d $src && $exclude) {
+ my $basename = basename($src);
+ my $dir = ($basename eq '.') ? $src : "$src/..";
+ my $pwd=`pwd`;
+ chomp $pwd;
+ complex_doit("cd '$dir' && " .
+ "find '$basename' $exclude \\( -type f -or -type l \\) -print0 | LC_ALL=C sort -z | " .
+ "xargs -0 -I {} cp --reflink=auto --parents -dp {} $pwd/$tmp/$target_dest/");
+ # cp is annoying so I need a separate pass
+ # just for empty directories
+ complex_doit("cd '$dir' && " .
+ "find '$basename' $exclude \\( -type d -and -empty \\) -print0 | LC_ALL=C sort -z | " .
+ "xargs -0 -I {} cp --reflink=auto --parents -a {} $pwd/$tmp/$target_dest/");
+ }
+ else {
+ doit("cp", '--reflink=auto', "-a", $src, "$tmp/$target_dest/");
+ }
+ }
+ }
+
+ for my $dest (sort(keys(%dest2sources))) {
+ my @srcs = sort(values(%{$dest2sources{$dest}}));
+ # Make sure the destination directory exists.
+ install_dir("$tmp/$dest");
+ xargs(\@srcs, "cp", '--reflink=auto', "-a", XARGS_INSERT_PARAMS_HERE, "$tmp/$dest/");
+ }
+ log_installed_files($package, @installed);
+}
+
+if ($missing_files) {
+ # There were files we could not install (e.g. patterns that matched nothing)
+ error("missing files, aborting");
+}
+
+if ($dh{LIST_MISSING} || $dh{FAIL_MISSING}) {
+ my @options;
+ foreach (@{$dh{EXCLUDE}}) {
+ push(@options, '--exclude', $_);
+ }
+ push(@options, '--sourcedir', $dh{SOURCEDIR}) if defined($dh{SOURCEDIR});
+ push @options, "--list-missing" if $dh{LIST_MISSING};
+ push @options, "--fail-missing" if $dh{FAIL_MISSING};
+ doit("dh_missing", @options);
+}
+
+sub compute_dest {
+ my ($source_dir, $dest) = @_;
+
+ $dest =~ s/^(.*\/)?\Q$srcdir\E\///;
+ $dest =~ s/^(.*\/)?\Q$source_dir\E\///;
+ $dest = dirname("/".$dest);
+
+ return $dest;
+}
+
+=head1 EXAMPLES
+
+Here are some small examples of configuration files for dh_install.
+
+ # Install my-prog into usr/bin (as "usr/bin/my-prog")
+ my-prog usr/bin
+
+ # Install a plugins directory into usr/share/my-prog
+ # (as "usr/share/my-prog/plugins/")
+ plugins usr/share/my-prog
+
+ # Install a file with spaces in into usr/share/my-prog/data
+ # (as "usr/share/my-prog/data/my datafile with spaces.txt")
+ # ASSUMES COMPAT 13, where substitution patterns are available
+ my${Space}datafile${Space}with${Space}spaces.txt usr/share/my-prog/data
+
+ # Install a library into the multi-arch lib directory
+ # ASSUMES COMPAT 13, where substitution patterns are available
+ build/output/libfrop*.so.* usr/lib/${DEB_HOST_MULTIARCH}
+
+=head1 LIMITATIONS
+
+B<dh_install> cannot rename files or directories, it can only install them
+with the names they already have into wherever you want in the package
+build tree.
+
+There is also no way to filter out results based on build profiles or
+architecture. For documentation content, consider using B<dh_installdocs> or
+B<dh_installexamples> as those helpers account for the B<nodoc> build
+profile.
+
+However, renaming and filtering can be achieved by using B<dh-exec>
+with compatibility level 9 or later. An example debian/I<package>.install
+file using B<dh-exec> could look like:
+
+ #!/usr/bin/dh-exec
+ debian/default.conf => /etc/my-package/start.conf
+ build/foo /usr/bin <!pkg.bar.nofoo>
+
+Please remember the following three things:
+
+=over 4
+
+=item * The package must be using compatibility level 9 or later (see L<debhelper(7)>)
+
+=item * The package will need a build-dependency on dh-exec.
+
+=item * The install file must be marked as executable.
+
+=back
+
+=head1 SEE ALSO
+
+L<debhelper(7)>
+
+This program is a part of debhelper.
+
+=head1 AUTHOR
+
+Joey Hess <joeyh@debian.org>
+
+=cut