### -*-shell-script-*-
#
# Native package manager integration
#
# Long term, we should abstract this out into a plugin system so
# distribution developers can teach autopackage how to use their
# package managers without patching. For now, let's do it the simplest
# way possible.
#
# ########################################################################
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Copyright 2005 Mike Hearn (mike@plan99.net)
#
###

##
# _fileToNativeName FILENAME
#
# Try a series of package managers in turn, returning either when
# an owning package has been found, or when there are no more to
# try. Note that this does NOT check the autopackage database!
#
# This function will set the $result_package_manager variable
# to the name of whatever package manager (rpm, dpkg, etc) the result
# came from. It will set the $result_name variable to whatever
# the native name is. This function does NOT output to stdout.
#
# A "native name" is a package name that is specific to the systems
# distribution or package manager. Generally, you should treat native
# names as opaque local identifiers: do not attempt to parse them or
# switch codepaths based on them.
#
# Example:
# _fileToNativeName /usr/bin/gedit
# echo $name_result                     -> gedit-2.10.2-4
# echo $package_manager_result          -> rpm
function _fileToNativeName() {
    if [ ! -e "$1" ]; then
	warn "$1 does not exist"
	return 1
    fi

    if locateCommand rpm; then
	trace "checking rpm"
	if result_package_name=$( LC_ALL=C $lc_command -qf $1 --queryformat %{NAME} 2>&1 ); then
	    trace "file $1 is owned by $result_package_name"
	    result_package_manager=rpm
	    return 0
	else
	    warn "rpm query failed: $result_package_name"
	    unset result_package_name
	fi
    fi

    if locateCommand dpkg; then
	fixme "dpkg file query support not implemented yet"
    fi

    warn "file $1 was not claimed by any package manager"
    return 1
}

##
# removeOwningPackage FILENAME
# FILENAME: File to query the native package manager about.
# Since: 1.2
#
# If FILENAME exists, this function will query the systems native
# package manager to find out what package owns it, and it will
# then attempt to uninstall the given package. This is useful
# in prepare scripts to ensure the autopackage does not conflict
# with a pre-existing installation (which will cause file backups).
#
# For some programs, you may need to call removeOwningPackage more than once.
# This is because some distributions (eg, Debian) love to split up
# programs into multiple packages. The dividing line can sometimes
# seem arbitrary: plugins, documentation, even extra artwork or game
# levels can be split out.
#
# You should only remove files that would directly conflict: in other
# words, that exist in the prefix you are installing to. As an
# alternative consider making your package parallel installable with
# the systems copy.
#
# If a frontend is connected, this function will show the uninstalling
# part of the user interface.
#
# Symlinks not owned by a package will be followed recursively.
#
# Example:
# removeOwningPackage "$PREFIX/bin/foobar"
# removeOwningPackage "$PREFIX/lib/libwidgets.so.0"
function removeOwningPackage() {
    pushOptE; set +e;
    
    if [ ! -e "$1" ]; then
        trace "$1 does not exist"
        popOptE
        return 0
    fi

    trace "called with $1"
    
    if ! _fileToNativeName "$1"; then
        if [ -h "$1" ]; then
            # if this is a symlink (e.g., libwidgets.so.0 created by ldconfig),
            # follow it so people can use removeOwningPackage on libraries
            removeOwningPackage "`readlink $1`"
            return $?
        else
            warn _fileToNativeName failed
            return 0
        fi
        # if the file is not claimed by any pkg manager, then
        # _fileToNativeName will return 1. This is a problem
        # on systems where support for the package manager is
        # not yet implemented (e.g., pkgtool on slackware).
        
    fi
    
    if [[ "$result_package_manager" == "rpm" ]]; then
        
        if [[ $( id -u ) != "0" ]]; then
            # this is unlikely: if we're installing to a prefix that conflicts
            # with an RPM it's probably because the user entered the root password
            # so we should have access rights here.
            warn "file $1 is owned by RPM but we are not root, bailing out"
            local msg=$( out "$intl_OWNED_BY_PM_BUT_NOT_ROOT" "$1" )
            outputFail "$msg"

            clearResults
            popOptE
            return 1
        fi

        trace "running: rpm -q --whatrequires $result_package_name"
        local whatrequires
        if whatrequires=$( rpm -q --whatrequires $result_package_name --queryformat %{NAME} 2>&1 ); then
            warn "we cannot remove $result_package_name, something else requires it"
            local msg=$( out "$intl_CANNOT_REMOVE_SYSTEM_PACKAGE" "$1" "$whatrequires" )
            outputFail "$msg"

            clearResults
            popOptE
            return 1
        fi
        
        trace "running: rpm -e $result_package_name"
        _outputUninstalling "$result_package_name" "$result_package_name" "rpm"

        local result
        if ! result=$( rpm -e --nodeps "$result_package_name" ); then
            err "rpm failed to remove $result_package_name: $result"
            outputFail "$intl_RPM_DID_NOT_REMOVE_PACKAGE"

            clearResults
            popOptE
            return 1
        fi

        sleep 5

        _outputUninstallDone

        trace "uninstall complete"
        clearResults
        popOptE
        return 0
    else
        fixme "$result_package_manager support not implemented yet"
        outputFail "$result_package_manager support not implemented yet"

        clearResults
        popOptE
        return 1
    fi

    assertNotReached
}
