You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
61 lines
2.2 KiB
61 lines
2.2 KiB
#' Retrieve Software Update history
|
|
#'
|
|
#' Modern macOS "Software Update" history is preserved in the
|
|
#' `/Library/Receipts/InstallHistory.plist` proeprty list file. The default
|
|
#' behaviour is to use this file as a source and parse the property list into
|
|
#' a data frame (tibble). The caller can also provide a path to a valid
|
|
#' property list "Software Update" history file (i.e. a systems administrator
|
|
#' may want to analyze a collected inventory of "Software Update" history files
|
|
#' from all the macOS systems on her network).
|
|
#'
|
|
#' @md
|
|
#' @param su_hist_file path to "Software Update" history file
|
|
#' @export
|
|
software_update_history <- function(su_hist_file = "/Library/Receipts/InstallHistory.plist") {
|
|
|
|
su_hist_file <- path.expand(su_hist_file)
|
|
su_hist_file <- normalizePath(su_hist_file)
|
|
|
|
if (!file.exists(su_hist_file)) stop("'hist_file' not found.", call.=FALSE)
|
|
|
|
doc <- xml2::read_xml(su_hist_file)
|
|
kids <- xml2::as_list(xml2::xml_children(doc))
|
|
|
|
shld_be_dict <- unique(names(kids[[1]]))
|
|
if (!((length(shld_be_dict) == 1) & (shld_be_dict[1] == "dict"))) {
|
|
stop("Not a valid plist file.", call.=FALSE)
|
|
}
|
|
|
|
purrr::map_df(1:length(kids[[1]]), function(.j) {
|
|
grandkids <- kids[[1]][[.j]]
|
|
nm <- names(grandkids)
|
|
keys <- which(nm == "key")
|
|
dat <- vector("list", length(keys))
|
|
keynms <- vector("character", length(keys))
|
|
j <- 1
|
|
for (i in keys) {
|
|
key_name <- grandkids[[i]][[1]]
|
|
keynms[j] <- key_name
|
|
val_type <- names(grandkids[i+1])
|
|
val <- switch(
|
|
val_type,
|
|
"string" = unlist(grandkids[[i+1]]),
|
|
"date" = anytime::anytime(unlist(grandkids[[i+1]])),
|
|
"integer" = as.integer(unlist(grandkids[[i+1]])),
|
|
"real" = as.numeric(unlist(grandkids[[i+1]])),
|
|
"true" = TRUE,
|
|
"false" = FALSE,
|
|
"array" = list(purrr::set_names(list(unlist(grandkids[[i+1]], use.names=FALSE)), key_name)),
|
|
"data" = "TODO",
|
|
"UNKNOWN - TODO"
|
|
)
|
|
if (length(val) == 0) val <- NA
|
|
dat[j] <- as.list(val)
|
|
j <- j + 1
|
|
}
|
|
purrr::set_names(dat, keynms)
|
|
}) -> xdf
|
|
|
|
xdf[,c("displayName", "displayVersion", "date", "packageIdentifiers", "processName", "contentType")]
|
|
|
|
}
|
|
|