#!/usr/bin/perl -w =head1 NAME dh_bash-completion - install bash completions for package =cut use strict; use File::Find; use Debian::Debhelper::Dh_Lib; =head1 SYNOPSIS B [S>] =head1 DESCRIPTION dh_bash-completion is a debhelper program that is responsible for installing completions for bash, usable installing the "bash-completion" package. In order to use it, you need to pass "--with bash-completion" to debhelper and Build-depend on bash-completion. If a file named debian/package.bash-completion exists, then different actions are performed, depending on its format. It can be a proper completion snippet, and in that case it would be installed in the completion directory, and no other actions would be performed. It can also be a list of files, with an optionally specified name to call the completion snippet after. The file format is as follows: my/path/to/foo-completion # this would be installed as "foo-completion" my/path/to/bar-completion baz # this would be installed as "baz" =cut # This helper function tries to determine (using some poor man's # heuristics) whether $file (its first and only argument) is a # filelist containing a list of files to be installed by us, or a # bash-completion script, which should itself be installed. # # If we're dealing with a filelist, return 1. Otherwise, return 0. sub is_filelist { # The file to be checked. my ($file) = @_; open (DH_FILE, '<', $file) || error("cannot read $file: $!"); while () { # Get rid of lines containing just spaces or comments. chomp; s/^\s++//; next if /^#/; s/\s++$//; # We always ignore/permit empty lines next if $_ eq ''; # This is the heart of the script. Here, we check for some # well-known idioms on bash scripts, and try to determine if # they're present in the file we're examining. We assume that # if they are, then this means the file is a bash-completion # script. # # The regexes check: # # - If we're calling the bash function "complete", which is a # pretty common thing to do in bash-completion scripts, or # # - If we're using the $(program) way of executing a program. # We don't take into account multi-line statements. Or # # - If we're calling the bash function "compgen", which is # also a pretty common thing that bash-completion scripts # do. Or # # - If we see an "if...then" construction in the file. We # take into account multi-line statements. if (/(^|[|&;])\s*complete.*-[A-Za-z].*/ || /\$\(.*\)/ || /\s*compgen.*-[A-Za-z].*/ || /\s*if.*;.*then/s) { return 0; } } # If we reached the end, this is not a bash-completion script. return 1; } init(); my $srcdir = '.'; $srcdir = $dh{SOURCEDIR}."/" if defined $dh{SOURCEDIR}; # PROMISE: DH NOOP WITHOUT bash-completion cli-options() PKG: foreach my $package (@{$dh{DOPACKAGES}}) { next if is_udeb($package); my $tmp = tmpdir($package); my $bc_dir = "$tmp/usr/share/bash-completion/completions"; my $completions = pkgfile($package,"bash-completion"); my @install; my $name; if ($completions) { install_dir($bc_dir); # Invoke our heuristic function to try and determine # if we're dealing with a filelist or with a # bash-completion script. if (!is_filelist($completions)) { verbose_print "detected $completions as a bash-completion script"; install_file($completions, "$bc_dir/$package"); next PKG } # try parsing a list of files @install = filedoublearray($completions); foreach my $set (@install) { my @filelist; my @tmp = @$set; if (@$set > 1) { $name = pop @$set; } else { $name = basename($tmp[0]); } verbose_print "installing $tmp[0] as $name"; my @found; foreach my $glob (@$set) { @found = glob "$srcdir/$glob"; if (!compat(6)) { # Fall back to looking into debian/tmp if (!@found || !-e $found[0]) { @found = glob "debian/tmp/$glob"; } } if (!@found || !-e $found[0]) { warning "file-list parsing failed, installing as proper snippet"; install_file($completions, "$bc_dir/$package"); next PKG } push @filelist, @found; } if (!@filelist) { error("$package missing files (@$set), aborting"); } foreach my $src (@filelist) { install_file($src, "$bc_dir/$name"); } } } } =head1 SEE ALSO L This program is a part of bash-completion. L =head1 AUTHOR David Paleino =cut