mirror of
https://github.com/munki/munki.git
synced 2026-02-04 22:30:10 -06:00
More efficient methods to get installed package information for processing removals. Speeds up generating the receipt database.
This commit is contained in:
@@ -201,33 +201,24 @@ func insertFileInfoIntoPkgDB(
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets info about pkg from pkgutil
|
||||
func getPkgMetaData(_ pkg: String) async throws -> PkgData {
|
||||
let result = await runCliAsync(
|
||||
"/usr/sbin/pkgutil", arguments: ["--pkg-info-plist", pkg]
|
||||
)
|
||||
if result.exitcode != 0 {
|
||||
throw MunkiError("Error calling pkgutil: \(result.error)")
|
||||
}
|
||||
let (pliststr, _) = parseFirstPlist(fromString: result.output)
|
||||
guard let plist = try readPlist(fromString: pliststr) as? PlistDict else {
|
||||
throw MunkiError("Could not parse expected data from pkgutil")
|
||||
}
|
||||
/// Given a plist generated by `pkgutil --pkg-info-plist`,
|
||||
/// returns a PkgData structure
|
||||
func getPkgMetaData(_ pkg: PlistDict) throws -> PkgData {
|
||||
var timestamp = 0
|
||||
var version = "0"
|
||||
var ppath = ""
|
||||
|
||||
guard let pkgid = plist["pkgid"] as? String else {
|
||||
guard let pkgid = pkg["pkgid"] as? String else {
|
||||
// something terribly wrong
|
||||
throw MunkiError("Could not parse expected data from pkgutil")
|
||||
throw MunkiError("Could not parse expected info data from pkgutil")
|
||||
}
|
||||
if let pkgVersion = plist["pkg-version"] as? String {
|
||||
if let pkgVersion = pkg["pkg-version"] as? String {
|
||||
version = pkgVersion
|
||||
}
|
||||
if let installTime = plist["install-time"] as? Int {
|
||||
if let installTime = pkg["install-time"] as? Int {
|
||||
timestamp = installTime
|
||||
}
|
||||
if let installLocation = plist["install-location"] as? String {
|
||||
if let installLocation = pkg["install-location"] as? String {
|
||||
ppath = installLocation
|
||||
if ppath.hasPrefix("./") {
|
||||
ppath.removeFirst(2)
|
||||
@@ -241,31 +232,82 @@ func getPkgMetaData(_ pkg: String) async throws -> PkgData {
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a list of files installed by pkg
|
||||
func getFilesForPkg(_ pkg: String) async throws -> [String] {
|
||||
let result = await runCliAsync("/usr/sbin/pkgutil", arguments: ["--files", pkg])
|
||||
/// Uses lsbom to get a list of files for pkgid
|
||||
func getBomFilesForPkg(_ pkgid: String) -> [String]? {
|
||||
let bomPath = "/private/var/db/receipts/\(pkgid).bom"
|
||||
if !pathExists(bomPath) {
|
||||
return nil
|
||||
}
|
||||
let result = runCLI(
|
||||
"/usr/bin/lsbom", arguments: ["-s", bomPath]
|
||||
)
|
||||
if result.exitcode != 0 {
|
||||
throw MunkiError("Error calling pkgutil: \(result.error)")
|
||||
return nil
|
||||
}
|
||||
var filelist = result.output.components(separatedBy: "\n").filter { !$0.isEmpty && $0 != "." }
|
||||
for i in 0 ..< filelist.count {
|
||||
if filelist[i].hasPrefix("./") {
|
||||
filelist[i].removeFirst(2)
|
||||
}
|
||||
}
|
||||
return filelist
|
||||
}
|
||||
|
||||
/// Returns a list of files installed by pkg
|
||||
func getFilesForPkg(_ pkgid: String) async throws -> [String] {
|
||||
if !pkgid.hasPrefix("com.apple.") {
|
||||
// try to use lsbom to get the list of files
|
||||
// (this is faster than using pkgutil)
|
||||
if let bomFileList = getBomFilesForPkg(pkgid) {
|
||||
return bomFileList
|
||||
}
|
||||
}
|
||||
// use pkgutil to get the list of files
|
||||
let result = try await runCliAsync("/usr/sbin/pkgutil", arguments: ["--files", pkgid], timeout: 10)
|
||||
if result.exitcode != 0 {
|
||||
throw MunkiError(
|
||||
"Error calling pkgutil to get list of files for \(pkgid): \(result.error)"
|
||||
)
|
||||
}
|
||||
return result.output.components(separatedBy: "\n").filter { !$0.isEmpty }
|
||||
}
|
||||
|
||||
/// Adds metadata for pkgid to our database
|
||||
func getPkgDataAndAddtoDB(pkgid: String) async throws {
|
||||
async let tempPkgdata = try getPkgMetaData(pkgid)
|
||||
async let fileList = try getFilesForPkg(pkgid)
|
||||
var pkgdata = try await tempPkgdata
|
||||
pkgdata.files = try await fileList
|
||||
func getPkgDataAndAddtoDB(pkg: PlistDict) async throws {
|
||||
var pkgdata = try getPkgMetaData(pkg)
|
||||
let fileList = try await getFilesForPkg(pkgdata.pkgid)
|
||||
pkgdata.files = fileList
|
||||
try insertPkgDataIntoPkgDB(pkgdata: pkgdata)
|
||||
}
|
||||
|
||||
/// Imports package data from pkgutil into our internal package database.
|
||||
func importFromPkgutil() async throws {
|
||||
let result = await runCliAsync("/usr/sbin/pkgutil", arguments: ["--pkgs"])
|
||||
if result.exitcode != 0 {
|
||||
throw MunkiError("Error calling pkgutil: \(result.error)")
|
||||
var pkglist = [PlistDict]()
|
||||
// get info plists about all installed pkgs
|
||||
let results = await runCliAsync(
|
||||
"/usr/sbin/pkgutil", arguments: ["--regexp", "--pkg-info-plist", ".*"]
|
||||
)
|
||||
if results.exitcode != 0 {
|
||||
throw MunkiError("Error calling pkgutil to get info plists for all packages: \(results.error)")
|
||||
}
|
||||
let pkglist = result.output.components(separatedBy: "\n").filter { !$0.isEmpty }
|
||||
// output is multiple XML-formatted plists, concatenated
|
||||
// iterate through the output, processing each plist
|
||||
var out = results.output
|
||||
while !out.isEmpty {
|
||||
let (pliststr, tempOut) = parseFirstPlist(fromString: out)
|
||||
out = tempOut
|
||||
if pliststr.isEmpty {
|
||||
break
|
||||
}
|
||||
if let plist = try? readPlist(fromString: pliststr) as? PlistDict {
|
||||
if plist["pkgid"] as? String != nil,
|
||||
plist["pkg-version"] as? String != nil
|
||||
{
|
||||
pkglist.append(plist)
|
||||
}
|
||||
}
|
||||
}
|
||||
// import each package into the receipt database
|
||||
let pkgCount = pkglist.count
|
||||
var current = 0
|
||||
displayPercentDone(current: current, maximum: pkgCount)
|
||||
@@ -274,8 +316,9 @@ func importFromPkgutil() async throws {
|
||||
throw UserCancelled()
|
||||
}
|
||||
current += 1
|
||||
display.detail("Importing \(pkg)...")
|
||||
try await getPkgDataAndAddtoDB(pkgid: pkg)
|
||||
let pkgid = pkg["pkgid"] as? String ?? "<unknown>"
|
||||
display.detail("Importing \(pkgid)...")
|
||||
try await getPkgDataAndAddtoDB(pkg: pkg)
|
||||
displayPercentDone(current: current, maximum: pkgCount)
|
||||
}
|
||||
}
|
||||
@@ -372,7 +415,7 @@ func forgetPkgFromAppleDB(_ pkgid: String) {
|
||||
display.detail(result.output)
|
||||
}
|
||||
} else {
|
||||
// maybe a warning?
|
||||
display.warning("pkgutil --forget for \(pkgid) returned an error: \(result.error)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,7 +533,7 @@ func removeFilesystemItems(pathsToRemove: [String], forceDeleteBundles: Bool) {
|
||||
itemIndex += 1
|
||||
let pathToRemove = "/" + item
|
||||
if pathIsRegularFile(pathToRemove) || pathIsSymlink(pathToRemove) {
|
||||
display.detail("Removing : \(pathToRemove)")
|
||||
display.detail("Removing: \(pathToRemove)")
|
||||
removeItemOrRecordError(pathToRemove)
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user