#!/usr/bin/perl
# Installs a package dependency. By and large the source package names are
# based on opensuse but the capacity exists to map the package names based
# on the distribution.
use strict;
use POSIX();
use POSIX qw(getuid);

if ($ENV{"ASSUME_PACKAGE_INSTALLED"} eq "yes") {
	exit 0;
}

# File::Which is not always available. Bodge it
sub which {
	my $binary = $_[0];

	open(BODGE, "which $binary 2>/dev/null |") || die("Failed to open pipe to which");
	chomp(my $line = <BODGE>);
	close(BODGE);
	return $line;
}

my %package_map = (
	"debian::acl-devel"	=> "libacl1-dev",
	"debian::attr-devel"	=> "libattr1-dev",
	"debian::binutils-devel" => "binutils-dev",
	"debian::blas-devel"	=> "libblas-dev",
	"debian::btrfsprogs"	=> "btrfs-tools",
	"debian::cpupower"	=> "linux-tools-common",
	"debian::diffutils"	=> "diff",
	"debian::expect-devel"	=> "expect-dev",
	"debian::gcc-32bit"	=> "gcc-multilib",
	"debian::gcc-c++"	=> "g++",
	"debian::gcc-fortran"	=> "gfortran",
	"debian::hwloc-devel"	=> "libhwloc-dev",
	"debian::hwloc-lstopo"	=> "hwloc-nox",
	"debian::libaio-devel"	=> "libaio-dev",
	"debian::libcurl-devel"	=> "libcurl4-gnutls-dev",
	"debian::libevent-devel" => "libevent-dev",
	"debian::libhugetlbfs"	=> "libhugetlbfs0",
	"debian::libnuma-devel"	=> "libnuma-dev",
	"debian::libopenssl-devel" => "libssl-dev",
	"debian::libpsm_infinipath1" => "libpsm-infinipath1",
	"debian::libuuid-devel"	=> "uuid-dev",
	"debian::libxml2-devel"	=> "libxml2-dev",
	"debian::mono"		=> "mono-complete",
	"debian::MPlayer"	=> "mplayer",
	"debian::perl-Math-Round" => "libmath-round-perl",
	"debian::perl-Time-HiRes" => "perl",
	"debian::popt-devel"	=> "libpopt-dev",
	"debian::python3-devel"	=> "python3-dev",
	"debian::xfsprogs-devel" => "xfslibs-dev",
	"debian::xorg-x11-server" => "xserver-xorg",
	"debian::xz"		=> "xz-utils",
	"debian::zeromq-devel"	=> "libzmq3-dev",
	"debian::zlib-devel"	=> "zlib1g-dev",

	"redhat::libnurses5"	 => "ncurses",
	"redhat::gcc-fortran"    => "gcc-gfortran",
	"redhat::libnuma-devel"  => "numactl-devel",
	"redhat::gcc-32bit"      => "libgcc.i686",
	"redhat::openmpi-32bit"  => "openmpi.i686",
	"redhat::openmpi-32bit"  => "openmpi.i686",
	"redhat::btrfsprogs"     => "btrfs-progs",
	"redhat::glibc-devel-static-32bit" => "glibc-static.i686",
	"redhat::libopenssl-devel"	   => "openssl-devel",

	"gentoo::acl-devel"	=> "sys-apps/acl",
	"gentoo::attr-devel"	=> "sys-apps/attr",
	"gentoo::binutils-devel" => "sys-devel/binutils",
	"gentoo::blas-devel-static" => "virtual/blas",
	"gentoo::blas-devel"	=> "virtual/blas",
	"gentoo::btrfsprogs"	=> "sys-fs/btrfs-progs",
	"gentoo::expect-devel"	=> "dev-tcltk/expect",
	"gentoo::gcc-32bit"	=> "sys-devel/gcc",
	"gentoo::gcc-c++"	=> "sys-devel/gcc",
	"gentoo::gcc-fortran"	=> "sys-devel/gcc",
	"gentoo::git-core"	=> "dev-vcs/git",
	"gentoo::glibc-devel-static-32bit" => "sys-libs/glibc",
	"gentoo::glibc-devel-static" => "sys-libs/glibc",
	"gentoo::glibc-devel"	=> "sys-libs/glibc",
	"gentoo::hwloc-devel"	=> "sys-apps/hwloc",
	"gentoo::hwloc-lstopo"	=> "sys-apps/hwloc",
	"gentoo::kpartx"	=> "sys-fs/multipath-tools",
	"gentoo::libaio-devel"	=> "dev-libs/libaio",
	"gentoo::libbtrfs-devel" => "sys-fs/btrfs-progs",
	"gentoo::libcurl-devel"	=> "net-misc/curl",
	"gentoo::libevent-devel" => "dev-libs/libevent",
	"gentoo::libexpat-devel" => "dev-libs/expat",
	"gentoo::libncurses5"	=> "sys-libs/ncurses",
	"gentoo::libnuma-devel"	=> "sys-process/numactl",
	"gentoo::libopenssl-devel" => "dev-libs/openssl",
	"gentoo::libreoffice-writer" => "app-office/libreoffice-bin",
	"gentoo::libstdc++-devel" => "sys-devel/gcc",
	"gentoo::libuuid-devel"	=> "sys-apps/util-linux",
	"gentoo::libxml2-devel"	=> "dev-libs/libxml2",
	"gentoo::MPlayer"	=> "media-video/mplayer",
	"gentoo::openmpi-32bit"	=> "sys-cluster/openmpi",
	"gentoo::openmpi-devel"	=> "sys-cluster/openmpi",
	"gentoo::openmpi-libs"	=> "sys-cluster/openmpi",
	"gentoo::perl-Math-Round" => "dev-perl/Math-Round",
	"gentoo::popt-devel"	=> "dev-libs/popt",
	"gentoo::python-numpy"	=> "dev-python/numpy",
	"gentoo::python-rpy2"	=> "dev-python/rpy",
	"gentoo::xfsprogs-devel" => "sys-fs/xfsprogs",
	"gentoo::xorg-x11-server" => "x11-base/xorg-server",
	"gentoo::xz"		=> "app-arch/xz-utils",
	"gentoo::zeromq-devel"	=> "net-libs/zeromq",
	"gentoo::zlib-devel"	=> "sys-libs/zlib",
);
	
my %package_bin = (
	"suse"		=> "zypper install",
	"debian"	=> "apt-get install",
	"redhat"	=> "yum install",
	"gentoo"	=> "emerge",
);

my %force_install = (
	"suse" => "",
	"debian" => "",
	"redhat" => "",
	"gentoo" => "",
);

my $distro;
foreach my $release_file ("debian_version", "debian_release",
			  "redhat-release", "redhat_version",
			  "SuSE-release", "gentoo-release") {
	if (-r "/etc/$release_file" ) {
		$distro = $release_file;
		$distro =~ tr/[A-Z]/[a-z]/;
		$distro =~ s/[_-].*//;
		last;
	}
}

if (!defined($distro)) {
	if (-r "/etc/os-release") {
		open(OSRELEASE, "</etc/os-release");
		foreach (<OSRELEASE>) {
			# https://www.freedesktop.org/software/systemd/man/os-release.html
			# multiple values possible
			if (/ID_LIKE="(.*)"/) {
				$distro = $1;
				last;
			}
			if (/CPE_NAME="cpe:\/o:([a-z]*):/) {
				$distro = $1;
				last;
			}
		}
	}
}

if (!defined($distro)) {
	if (-r "/etc/lsb-release") {
		open(LSBRELEASE, "/etc/lsb-release");
		foreach (<LSBRELEASE>) {
			if (/DISTRIB_ID=(.*)/) {
				$distro = $1;
				$distro =~ tr/"//d;
				$distro =~ tr/[A-Z]/[a-z]/;
				last;
			}
		}
	}
}

if (!defined($distro)) {
	die("Failed to identify distribution\n");
}

# If we're "suse"-like (no matter whether "suse", "suse opensuse" or
# "opensuse suse"), we want zypper
$distro =~ s/(.*)(\bsuse\b)(.*)/$2/;

if (!defined($package_bin{$distro})) {
	die("Do not know how to invoke package manager for distro $distro");
}

my $sudo = "";
if (getuid() != 0) {
	$sudo = which("sudo");
	if (!defined $sudo) {
		print "ERROR: user is not root and sudo not available\n";
		exit(-1);
	}
}

foreach my $package (@ARGV) {

	# Map the package onto the distro-equivalent name
	if (defined($package_map{"$distro\::$package"})) {
		$package = $package_map{"$distro\::$package"};
	}

	# Check if the package is already installed
	if ($distro eq "debian") {
		if (system("dpkg --list $package > /dev/null 2>&1") == 0) {
			next;
		}
	} elsif ($distro eq "gentoo") {
		my $pn=qx(qatom -F %{PN} $package);
		$pn =~ tr/\n//d;
		if (system("qlist -Iv | grep -q '/$pn-[0-9]' > /dev/null 2>&1") == 0) {
			next;
		}
	} else {
		# Assume RPM based distro
		if (!defined(which("rpm"))) {
			die("Assumed rpm-based distro but no rpm");
		}
		if (system("rpm -q $package >& /dev/null") == 0) {
			next;
		}
	}

	if ($ENV{"AUTO_PACKAGE_INSTALL"} ne "yes" && ! -e $ENV{"HOME"} . "/.mmtests-auto-package-install") {
		if (! -e $ENV{"HOME"} . "/.mmtests-never-auto-package-install") {
			print "MMTests needs to install $package, should all packages be automatically installed (yes/no/never)? ";
			my $input = <STDIN>;
			chomp($input);
			if ($input eq "yes" || $input eq "y") {
				open(TOUCH, '>', $ENV{"HOME"} . "/.mmtests-auto-package-install");
				close TOUCH;
			}
			if ($input eq "never") {
				open(TOUCH, '>', $ENV{"HOME"} . "/.mmtests-never-auto-package-install");
				close TOUCH;
			}
		}
	}

	if ($ENV{"AUTO_PACKAGE_INSTALL"} eq "yes" || -e $ENV{"HOME"} . "/.mmtests-auto-package-install") {
		$force_install{"suse"} = "-y";
		$force_install{"debian"} = "-y --force-yes";
		$force_install{"redhat"} = "-y";
	}

	if (system("$sudo $package_bin{$distro} $force_install{$distro} $package") != 0) {
		die("Failed to install package $package for distro $distro");
	}

	print "Installed $package\n";
}

exit(0);
