getDependentPackagesToUninstall <- function()

in R/R/sqlPackage.R [2426:2602]


getDependentPackagesToUninstall <- function(pkgs, installedPackages, dependencies = TRUE, checkReferences = TRUE, verbose = getOption("verbose"))
{
    excludeTopMostPackagesDependencies <- function(pkgsToRemove, dependencies, db, basePackages, verbose)
    {
        # This function remove, from the given packages dependency lists, all the packages which are top most (and their dependencies) which are not explicitly
        # stated to be removed
        #
        prunedDependencies <- dependencies

        # If we have the topmost package information, remove, from the dependencies, packages which are marked as topmost
        #
        if ('Attributes' %in% colnames(db))
        {
            # Find all the packegs , in the installed packages database, which are explicitly marked as top most
            #
            topMostInstalledPackages <- db[!is.na(db[,'Attributes']) &
                                               bitwAnd(as.integer(db[,'Attributes']), getPackageTopMostAttributeFlag()) ==  1
                                           ,, drop = FALSE]

            topMostDependencies <- unique(unlist(dependencies, recursive = TRUE, use.names = FALSE))
            topMostDependencies <- topMostDependencies[topMostDependencies %in% topMostInstalledPackages[,"Package"]]

            if (length(topMostDependencies) != 0)
            {
                # Exclude, from the top most dependencies the packages which we specifically asked to remove
                #
                topMostDependencies <- topMostDependencies[!(topMostDependencies %in% pkgsToRemove)]
            }

            if (length(topMostDependencies) != 0)
            {
                # Get the top most packages dependencies to ensure they can still work
                #
                topMostDependencies <- unique(c(unlist(tools::package_dependencies(packages = topMostDependencies,
                                                                                   db = db, recursive = TRUE,
                                                                                   verbose = FALSE), recursive = TRUE, use.names = FALSE),
                                                topMostDependencies))

                # Remove the dependencies which are base classes to allow the correct code to use these
                #
                topMostDependencies <- topMostDependencies[!topMostDependencies %in% basePackages]
            }

            if (length(topMostDependencies) != 0)
            {
                skippedDependencies <- character(0)
                prunedDependencies <- lapply(X = dependencies,
                                             FUN = function(dependency)
                                                {
                                                 skippedDependencies <<- c(skippedDependencies, dependency[dependency %in% topMostDependencies])
                                                 dependency[!dependency %in% topMostDependencies]
                                                }
                                             )

                if (verbose && length(skippedDependencies) > 0)
                {
                    write(sprintf("%s  skipping following top level dependent packages (%s)...", pkgTime(), paste(unique(skippedDependencies), collapse = ', ')), stdout())
                }
            }
        }

        prunedDependencies
    }

    # prune requested packages to exclude base packages
    #
    basePackages <- installedPackages[installedPackages[,"Priority"] %in% c("base", "recommended"), c("Package", "Priority"), drop = FALSE]$Package

    droppedPackages <- pkgs[pkgs %in% basePackages]

    if (length(droppedPackages) > 0)
    {
        warning(sprintf("Skipping base packages (%s)", paste(droppedPackages, collapse = ', ')), call. = FALSE)
    }

    pkgs <- pkgs[!(pkgs %in% droppedPackages)]

    if (length(pkgs) < 1)
    {
        return (NULL)
    }

    if (dependencies == FALSE)
    {
        dependencies = pkgs
    }
    else
    {
        # get dependency closure for all given packages
        #
        if (verbose)
        {
            write(sprintf("%s  Resolving package dependencies for (%s)...", pkgTime(), paste(pkgs, collapse = ', ')), stdout())
        }

        dependencies <- tools::package_dependencies(packages = pkgs, db = installedPackages, recursive = TRUE, verbose = FALSE)

        # Exclude, from the package dependencies, all the packages which are marked as top most and their dependencies
        #
        dependencies <- excludeTopMostPackagesDependencies(pkgsToRemove = pkgs,
                                                           dependencies = dependencies,
                                                           db = installedPackages,
                                                           basePackages = basePackages,
                                                           verbose = verbose)

        dependencies <- c(dependencies, pkgs)

        # get combined dependency closure w/o base packages
        #
        dependencies <- unique(unlist(c(dependencies, names(dependencies)), recursive = TRUE, use.names = FALSE))
        dependencies <- dependencies[dependencies != "NA" & dependencies != ""]
        dependencies <- dependencies[!(dependencies %in% basePackages)]

        if (length(dependencies) < 1)
        {
            return (NULL)
        }
    }

    if (checkReferences == TRUE)
    {
        # get reverse dependency closure for all given packages
        #
        if (verbose)
        {
            write(sprintf("%s  Resolving package reverse dependencies for (%s)...", pkgTime(), paste(pkgs, collapse = ', ')), stdout())
        }

        pkgsToSkip <- list()

        for (dependency in dependencies)
        {
            rdependencies <- tools::package_dependencies(packages = dependency, db = installedPackages, reverse = TRUE, recursive = TRUE, verbose = FALSE)
            rdependencies <- unique(unlist(c(rdependencies, names(rdependencies)), recursive = TRUE, use.names = FALSE))
            rdependencies <- rdependencies[rdependencies != "NA"]
            rdependencies <- rdependencies[rdependencies != ""]
            rdependencies <- rdependencies[!(rdependencies %in% dependencies)]

            if (length(rdependencies) > 0)
            {
                if (dependency %in% pkgs)
                {
                    skipMessage <- sprintf("skipping package (%s) being used by packages (%s)...",
                                           dependency, paste(rdependencies, collapse = ', '))
                    warning(skipMessage, call. = FALSE)
                }
                else
                {
                    skipMessage <- sprintf("skipping dependent package (%s) being used by packages (%s)...",
                                           dependency, paste(rdependencies, collapse = ', '))
                    write(skipMessage, stdout())
                }

                pkgsToSkip <- c(pkgsToSkip, dependency)
            }
        }

        pkgsToSkip <- unique(unlist(pkgsToSkip, recursive = TRUE, use.names = FALSE))

        # remove packages which are being referenced by other packages
        #
        dependencies <- dependencies[!(dependencies %in% pkgsToSkip)]

        if (length(dependencies) < 1)
        {
            return (NULL)
        }
    }

    # get the packages in order of dependency closure
    #
    dependencies <- unique(dependencies)
    pkgsToRemove <- installedPackages[match(dependencies, installedPackages$Package),, drop = FALSE]
    pkgsToRemove <- pkgsToRemove[!is.na(pkgsToRemove$Package),]

    return (pkgsToRemove)
}