Last active
July 7, 2023 18:47
-
-
Save BrianDiggs/63bc48cf2955e0fd38f0df24fa4e1802 to your computer and use it in GitHub Desktop.
A script which should find packages which you have loaded which are not used in a script. It needs to be run in a clean session because there is no way to verify that the state of your current session is the same as what the script would create. It assumes that packages are only loaded with either library or require, which is good practice anywa…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Define the file to test in the line below. That is the only per-run configuration needed. | |
fileToTest <- "Plot.R" | |
# Get the parse data for the file | |
parseData <- getParseData(parse(fileToTest), includeText = TRUE) | |
# Extract all the function calls and keep a unique list of them. | |
functionCalls <- unique(parseData[parseData$token == "SYMBOL_FUNCTION_CALL", "text"]) | |
# Look for any calls to `library` or `require` and go two steps up the | |
# call tree to find the complete call (with arguments). | |
libraryCalls <- parseData[parseData$token == "SYMBOL_FUNCTION_CALL" & parseData$text %in% c("library", "require"),] | |
libraryCalls <- parseData[parseData$id %in% libraryCalls$parent,] | |
libraryCalls <- parseData[parseData$id %in% libraryCalls$parent,] | |
libraryCalls <- libraryCalls$text | |
# Execute all the library/require calls to attach them to this session | |
eval(parse(text = libraryCalls)) | |
# For each function called, | |
# * Use `getAnywhere` to find out where it is found. That information is in a character | |
# vector which is the `where` component of the returned list. | |
# * From that vector of locations, keep only the ones starting with "package:", | |
# getting rid of those starting with "namespace:". | |
# * Take the first one of these which should be the first package that the | |
# function is found in and thus would be the one used. | |
names(functionCalls) <- functionCalls | |
matchPkg <- vapply(functionCalls, | |
FUN = (\(f) grep("^package:", getAnywhere(f)$where, value = TRUE)[1]), | |
FUN.VALUE = character(1)) | |
# get a list of all packages from the search path, keep only those that are | |
# actually packages (not .GlobalEnv, Autoloads, etc.), ignore those that are | |
# automatically attached (base, methods, datasets, utils, grDevices, graphics, stats), | |
# and then see of those which ones did not show up in the list of packages used | |
# by the functions. | |
packages <- search() | |
packages <- grep("^package:", packages, value = TRUE) | |
packages <- setdiff(packages, c("package:base", "package:methods", "package:datasets", "package:utils", "package:grDevices", "package:graphics", "package:stats")) | |
packages <- setdiff(packages, unique(matchPkg)) | |
# Report results | |
if(length(packages) > 0) { | |
cat("Unused packages: \n"); | |
print(packages) | |
} else { | |
cat("No unused packages found.\n") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Originally published at https://stackoverflow.com/a/75597088/892313