boB Rudis
6 years ago
8 changed files with 154 additions and 8 deletions
@ -1,4 +1,9 @@ |
|||
# Generated by roxygen2: do not edit by hand |
|||
|
|||
export(read_dsstore) |
|||
export(software_update_history) |
|||
import(reticulate) |
|||
import(sys) |
|||
import(xml2) |
|||
importFrom(anytime,anytime) |
|||
importFrom(purrr,map_df) |
|||
|
@ -0,0 +1,61 @@ |
|||
#' 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(setNames(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 |
|||
} |
|||
setNames(dat, keynms) |
|||
}) -> xdf |
|||
|
|||
xdf[,c("displayName", "displayVersion", "date", "packageIdentifiers", "processName", "contentType")] |
|||
|
|||
} |
@ -1,3 +1,12 @@ |
|||
is_url <- function(path) { |
|||
grepl("^(http|ftp)s?://", path) |
|||
} |
|||
} |
|||
|
|||
mlga <- function(x) { |
|||
x <- tolower(x) |
|||
x <- gsub("[[:punct:][:space:]]+", "_", x) |
|||
x <- gsub("_+", "_", x) |
|||
x <- gsub("(^_|_$)", "", x) |
|||
x <- make.unique(x, sep = "_") |
|||
x |
|||
} |
|||
|
@ -0,0 +1,21 @@ |
|||
% Generated by roxygen2: do not edit by hand |
|||
% Please edit documentation in R/su-hist-file.R |
|||
\name{software_update_history} |
|||
\alias{software_update_history} |
|||
\title{Retrieve Software Update history} |
|||
\usage{ |
|||
|
|||
software_update_history(su_hist_file = "/Library/Receipts/InstallHistory.plist") |
|||
} |
|||
\arguments{ |
|||
\item{su_hist_file}{path to "Software Update" history file} |
|||
} |
|||
\description{ |
|||
Modern macOS "Software Update" history is preserved in the |
|||
\code{/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). |
|||
} |
Loading…
Reference in new issue