#!/bin/env perl -w
#
# $Id: depmaker 6679 2009-10-03 08:47:27Z dmichelsen $
#
# Copyright 2006 Cory Omand <comand@blastwave.org>
# All rights reserved.  Use is subject to license terms.
#
# Redistribution and/or use, with or without modification, is
# permitted.  This software is without warranty of any kind.  The
# author(s) shall not be liable in the event that use of the
# software causes damage.
#
# depmaker - find package dependencies for a list of files
#

use strict;

use File::Basename;
use Getopt::Long qw/:config no_ignore_case gnu_getopt/;
use File::Spec::Functions qw/canonpath catfile/;
use File::Temp qw/tempfile/;

my $self = basename $0;
my $VERSION = "1.0";

# Get command line options
my $do_script = 1;
my $be_quiet  = 0;
my (@nodep, $rootdir);
my $text_files = 0;
GetOptions(
    'script!'   => \$do_script,
    'quiet|q'   => \$be_quiet,
    'root=s'    => \$rootdir,
    'nodep=s'   => \@nodep,
    'help|h'    => \&usage,
    'text|t'    => \$text_files,
    'version|V' => sub {
        print STDERR "$self v$VERSION\n";
        exit 2;
    },
) or usage();

# Join package patterns
my $nodep = join "|", @nodep;

sub usage {
    print STDERR "Usage: $self [--text] [--no/script] [--nodep <pkg>] [--root <path>] < path_list > depend\n";
    exit 1;
}

sub msg {
    return if $be_quiet;
    print STDERR @_;
}

sub exclude {
    my $path = shift;
    foreach my $pat (@nodep) { return 1 if $path =~ $pat }
    return 0;
}

msg "root directory      : $rootdir\n" if $rootdir;
msg "skip depends for    : " . join(", ", sort @nodep) . "\n";
msg "script dependencies : " . ($do_script ? "enabled" : "disabled") . "\n";
msg "\n";

msg "processing path list...\n";

# Analyze the incoming path list...
my %depfiles;
foreach (<>) {
    chomp;

    # Prepend the root directory, if supplied
    my ($filedst,$filesrc) = split /=/, $_;
    $filesrc = $filedst unless $filesrc;
    if ($rootdir) {
        if ($filesrc =~ /^\$basedir/) {
            $filesrc =~ s/^\$basedir/$rootdir/;
        }
        else {
            $filesrc = catfile($rootdir, $filesrc);
        }
        $filesrc = canonpath($filesrc);
    }

    local $_ = $filesrc;
    next unless -f;

    my ($ftype) = `/bin/file -h '$_'`;

    my @depfiles;
    if ($do_script and $ftype =~ /script/) {
        # Extract an interpreter dependency...
        my ($bangpath) = `head -1 $_`; chomp $bangpath;
        $bangpath =~ s/^#!\s*(\S+)(\s.+)?/$1/;

        msg "$_ ... $bangpath script";

        # Compensate for /bin -> /usr/bin
        $bangpath = "/usr$bangpath" if $bangpath =~ '^/bin';
        $depfiles{$bangpath}++;

    }
    elsif ($ftype =~ /dynamically linked/) {
        msg "$_\n";

        foreach my $line (`dump -Lv $_`) {
            next unless $line =~ /NEEDED/; chomp $line;
            my (undef, undef, $lib) = split /\s+/, $line;
            #msg "    $lib\n";    
            $depfiles{$lib}++ if $lib;
        }
    }
    elsif ($text_files and $ftype =~ /text/) {
        $depfiles{$filesrc}++;
    }
}
exit 0 unless scalar keys %depfiles;

# Write dependency paths out to a temp file
my ($deptmp_fh, $deptmp) = tempfile;
print $deptmp_fh $_, "\n" foreach (sort keys %depfiles);

msg "searching package database for dependencies...\n";

# Look for all files that had dependencies in the system install
# install database, and store the package names...
$nodep = "-v '$nodep'" if $nodep;
my $query;
   $query .= $nodep ? "egrep $nodep " : "cat ";
   $query .= "/var/sadm/install/contents ";
   $query .= "| fgrep -f $deptmp ";
   $query .= "| gawk '{print \$NF}' ";
   $query .= "| sort | uniq";

close $deptmp_fh;

chomp(my @deppkg = `$query`);

foreach (sort @deppkg) {
    my ($desc) = `pkginfo $_` or next;
    chomp $desc;
    my ($class, $pkginst, $pdesc) = split /\s+/, $desc, 3;
    print "P $pkginst $pdesc\n";
}

exit 0;
