mirror of
https://github.com/munki/munki.git
synced 2026-01-26 08:59:17 -06:00
Convert more comments to documentation
This commit is contained in:
@@ -7,9 +7,9 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Sets owner, group and mode for path from info in itemInfo.
|
||||
/// Returns 0 on success, non-zero otherwise.
|
||||
func setPermissions(_ itemInfo: PlistDict, path: String) -> Int {
|
||||
// Sets owner, group and mode for path from info in itemInfo.
|
||||
// Returns 0 on success, non-zero otherwise.
|
||||
// Yes, we could call FileManager methods like setAttributes(_:ofItemAtPath:),
|
||||
// But the user and group might be names or numbers, and the mode is
|
||||
// supposed to be symbolic (but could also be in the format of "777",
|
||||
@@ -40,9 +40,9 @@ func setPermissions(_ itemInfo: PlistDict, path: String) -> Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
/// Creates any missing intermediate directories so we can copy item.
|
||||
/// Returns boolean to indicate success or failure
|
||||
func createMissingDirs(_ path: String) -> Bool {
|
||||
// Creates any missing intermediate directories so we can copy item.
|
||||
// Returns boolean to indicate success or failure
|
||||
let filemanager = FileManager.default
|
||||
if filemanager.fileExists(atPath: path) {
|
||||
// the path exists; don't need to create anything
|
||||
@@ -75,8 +75,8 @@ func createMissingDirs(_ path: String) -> Bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes com.apple.quarantine xattr from a path
|
||||
func removeQuarantineXattrFromItem(_ path: String) {
|
||||
// Removes com.apple.quarantine xattr from a path
|
||||
do {
|
||||
let xattrs = try listXattrs(atPath: path)
|
||||
if xattrs.contains("com.apple.quarantine") {
|
||||
@@ -89,8 +89,8 @@ func removeQuarantineXattrFromItem(_ path: String) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes com.apple.quarantine xattr from a path, recursively if needed
|
||||
func removeQuarantineXattrsRecursively(_ path: String) {
|
||||
// Removes com.apple.quarantine xattr from a path, recursively if needed
|
||||
removeQuarantineXattrFromItem(path)
|
||||
if pathIsDirectory(path) {
|
||||
let dirEnum = FileManager.default.enumerator(atPath: path)
|
||||
@@ -101,11 +101,9 @@ func removeQuarantineXattrsRecursively(_ path: String) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates source and destination for item to be copied from a mounted disk image.
|
||||
/// Returns a tuple of (success, source_path, destination_path)
|
||||
func validateSourceAndDestination(mountpoint: String, item: PlistDict) -> (Bool, String, String) {
|
||||
// Validates source and destination for item to be copied from a mounted
|
||||
// disk image.
|
||||
// Returns a tuple of (success, source_path, destination_path)
|
||||
|
||||
// Ensure source item is defined
|
||||
guard let sourceItemName = item["source_item"] as? String else {
|
||||
displayError("Missing name of item to copy!")
|
||||
@@ -147,8 +145,8 @@ func validateSourceAndDestination(mountpoint: String, item: PlistDict) -> (Bool,
|
||||
return (true, sourceItemPath, fullDestinationPath)
|
||||
}
|
||||
|
||||
/// Recursively gets size of pathname in bytes
|
||||
func getSize(_ path: String) -> Int {
|
||||
// Recursively gets size of pathname in bytes
|
||||
if pathIsDirectory(path) {
|
||||
return getSizeOfDirectory(path)
|
||||
}
|
||||
@@ -160,10 +158,8 @@ func getSize(_ path: String) -> Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
/// Subclass of AsyncProcessRunner that handles the progress output from /usr/bin/ditto
|
||||
class DittoRunner: AsyncProcessRunner {
|
||||
// subclass of AsyncProcessRunner that handles the progress output from
|
||||
// /usr/bin/ditto
|
||||
|
||||
var remainingErrorOutput = ""
|
||||
var totalBytesCopied = 0
|
||||
var sourceItemSize = 1
|
||||
@@ -202,16 +198,16 @@ class DittoRunner: AsyncProcessRunner {
|
||||
}
|
||||
}
|
||||
|
||||
/// Uses ditto to copy an item and provides progress output
|
||||
func dittoWithProgress(sourcePath: String, destinationPath: String) async -> Int {
|
||||
// Uses ditto to copy an item and provides progress output
|
||||
let proc = DittoRunner(sourcePath: sourcePath, destinationPath: destinationPath)
|
||||
await proc.run()
|
||||
return proc.results.exitcode
|
||||
}
|
||||
|
||||
/// Copies items from the mountpoint to the startup disk
|
||||
/// Returns 0 if no issues; some error code otherwise.
|
||||
func copyItemsFromMountpoint(_ mountpoint: String, itemList: [PlistDict]) async -> Int {
|
||||
// copies items from the mountpoint to the startup disk
|
||||
// Returns 0 if no issues; some error code otherwise.
|
||||
guard let tempDestinationDir = TempDir.shared.makeTempDir() else {
|
||||
displayError("Could not create a temporary directory!")
|
||||
return -1
|
||||
@@ -268,8 +264,8 @@ func copyItemsFromMountpoint(_ mountpoint: String, itemList: [PlistDict]) async
|
||||
return 0
|
||||
}
|
||||
|
||||
/// Copies items from disk image to local disk
|
||||
func copyFromDmg(dmgPath: String, itemList: [PlistDict]) async -> Int {
|
||||
// Copies items from disk image to local disk
|
||||
if itemList.isEmpty {
|
||||
displayError("No items to copy!")
|
||||
return -1
|
||||
|
||||
@@ -7,12 +7,11 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Removes filesystem items based on info in itemlist.
|
||||
/// These items were typically installed via copy_from_dmg
|
||||
/// This current aborts and returns false on the first error;
|
||||
/// might it make sense to try to continue and remove as much as we can?
|
||||
func removeCopiedItems(_ itemList: [PlistDict]) -> Bool {
|
||||
// Removes filesystem items based on info in itemlist.
|
||||
// These items were typically installed via copy_from_dmg
|
||||
// This current aborts and returns false on the first error;
|
||||
// might it make sense to try to continue and remove as much
|
||||
// as we can?
|
||||
if itemList.isEmpty {
|
||||
displayError("Nothing to remove!")
|
||||
return false
|
||||
@@ -61,9 +60,9 @@ func removeCopiedItems(_ itemList: [PlistDict]) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
/// Looks for item prerequisites (requires and update_for) in the list of skipped items.
|
||||
/// Returns a list of matches.
|
||||
func itemPrereqsInSkippedItems(currentItem: PlistDict, skippedItems: [PlistDict]) -> [String] {
|
||||
// Looks for item prerequisites (requires and update_for) in the list
|
||||
// of skipped items. Returns a list of matches.
|
||||
var matchedPrereqs = [String]()
|
||||
if skippedItems.isEmpty {
|
||||
return matchedPrereqs
|
||||
@@ -112,14 +111,14 @@ func itemPrereqsInSkippedItems(currentItem: PlistDict, skippedItems: [PlistDict]
|
||||
return matchedPrereqs
|
||||
}
|
||||
|
||||
/// Returns boolean to indicate if the item needs a restart
|
||||
func requiresRestart(_ item: PlistDict) -> Bool {
|
||||
// Returns boolean to indicate if the item needs a restart
|
||||
let restartAction = item["RestartAction"] as? String ?? ""
|
||||
return ["RequireRestart", "RecommendRestart"].contains(restartAction)
|
||||
}
|
||||
|
||||
/// Process an Apple package for install. Returns retcode, needs_restart
|
||||
func handleApplePackageInstall(pkginfo: PlistDict, itemPath: String) async -> (Int, Bool) {
|
||||
// Process an Apple package for install. Returns retcode, needs_restart
|
||||
if pkginfo["suppress_bundle_relocation"] as? Bool ?? false {
|
||||
displayWarning("Item has 'suppress_bundle_relocation' attribute. This feature is no longer supported.")
|
||||
}
|
||||
@@ -163,9 +162,9 @@ func handleApplePackageInstall(pkginfo: PlistDict, itemPath: String) async -> (I
|
||||
return (-99, false)
|
||||
}
|
||||
|
||||
/// Attempt to install a single item from the installList
|
||||
/// Returns an exitcode for the attempted install and a flag to indicate the need to restart
|
||||
func installItem(_ item: PlistDict) async -> (Int, Bool) {
|
||||
// Attempt to install a single item from the installList
|
||||
// returns an exitcode for the attempted install and a flag to indicate the need to restart
|
||||
var needToRestart = false
|
||||
let itemName = item["name"] as? String ?? "<unknown>"
|
||||
let installerType = item["installer_type"] as? String ?? "pkg_install"
|
||||
@@ -238,12 +237,10 @@ func installItem(_ item: PlistDict) async -> (Int, Bool) {
|
||||
return (retcode, needToRestart)
|
||||
}
|
||||
|
||||
/// Uses the installInfo installs list to install items in the correct order and with additional options
|
||||
func installWithInstallInfo(
|
||||
installList: [PlistDict], onlyUnattended: Bool = false
|
||||
) async -> (Bool, [PlistDict]) {
|
||||
// Uses the installInfo installs list to install items in the
|
||||
// correct order and with additional options
|
||||
|
||||
var restartFlag = false
|
||||
var itemIndex = 0
|
||||
var skippedInstalls = [PlistDict]()
|
||||
@@ -396,10 +393,9 @@ func installWithInstallInfo(
|
||||
return (restartFlag, skippedInstalls)
|
||||
}
|
||||
|
||||
/// Looks for items in the skipped_items that require or are update_for
|
||||
/// the current item. Returns a list of matches.
|
||||
func skippedItemsThatRequire(_ thisItem: PlistDict, skippedItems: [PlistDict]) -> [String] {
|
||||
// Looks for items in the skipped_items that require or are update_for
|
||||
// the current item. Returns a list of matches.
|
||||
|
||||
var matchedSkippedItems = [String]()
|
||||
if skippedItems.isEmpty {
|
||||
return matchedSkippedItems
|
||||
@@ -422,10 +418,9 @@ func skippedItemsThatRequire(_ thisItem: PlistDict, skippedItems: [PlistDict]) -
|
||||
return matchedSkippedItems
|
||||
}
|
||||
|
||||
/// Attempts to uninstall a single item from the removalList
|
||||
/// returns an exitcode for the attempted install and a flag to indicate the need to restart
|
||||
func uninstallItem(_ item: PlistDict) async -> (Int, Bool) {
|
||||
// Attempts to uninstall a single item from the removalList
|
||||
// returns an exitcode for the attempted install and a flag to indicate the need to restart
|
||||
|
||||
var needToRestart = false
|
||||
let itemName = item["display_name"] as? String ?? "<unknown>"
|
||||
let displayName = item["display_name"] as? String ?? itemName
|
||||
@@ -512,8 +507,8 @@ func uninstallItem(_ item: PlistDict) async -> (Int, Bool) {
|
||||
return (retcode, needToRestart)
|
||||
}
|
||||
|
||||
/// Processes removals from the removal list
|
||||
func processRemovals(_ removalList: [PlistDict], onlyUnattended: Bool = false) async -> (Bool, [PlistDict]) {
|
||||
// Processes removals from the removal list
|
||||
var restartFlag = false
|
||||
var index = 0
|
||||
var skippedRemovals = [PlistDict]()
|
||||
@@ -581,11 +576,11 @@ func processRemovals(_ removalList: [PlistDict], onlyUnattended: Bool = false) a
|
||||
return (restartFlag, skippedRemovals)
|
||||
}
|
||||
|
||||
/// Runs the install/removal session.
|
||||
///
|
||||
/// Args:
|
||||
/// only_unattended: Boolean. If True, only do unattended_(un)install pkgs.
|
||||
func doInstallsAndRemovals(onlyUnattended: Bool = false) async -> Int {
|
||||
// Runs the install/removal session.
|
||||
//
|
||||
// Args:
|
||||
// only_unattended: Boolean. If True, only do unattended_(un)install pkgs.
|
||||
var removalsNeedRestart = false
|
||||
var installsNeedRestart = false
|
||||
|
||||
|
||||
@@ -20,16 +20,13 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Stub function
|
||||
func removeBundleRelocationInfo() {
|
||||
// this function existed in the Python version of Munki
|
||||
// but could work only on bundle-style packages
|
||||
// May not be worth porting.
|
||||
displayWarning("'suppress_bundle_relocation' is no longer supported. Ignoring.")
|
||||
}
|
||||
|
||||
/// Query a package for its RestartAction. Returns true if a restart is needed, false otherwise
|
||||
func pkgNeedsRestart(_ pkgpath: String, options: PlistDict) -> Bool {
|
||||
// Query a package for its RestartAction. Returns true if a restart is
|
||||
// needed, false otherwise
|
||||
let tool = "/usr/sbin/installer"
|
||||
var arguments = ["-query", "RestartAction", "-pkg", pkgpath, "-plist"]
|
||||
if let choicesXML = options["installer_choices_xml"] as? PlistDict,
|
||||
@@ -84,10 +81,8 @@ func getInstallerEnvironment(_ customEnv: [String: String]?) -> [String: String]
|
||||
return env
|
||||
}
|
||||
|
||||
/// Parses a line of output from installer, displays it as progress output and logs it
|
||||
func displayInstallerOutput(_ text: String) {
|
||||
// Parses a line of output from installer, displays it as progress output
|
||||
// and logs it
|
||||
|
||||
if !text.hasPrefix("installer:") {
|
||||
// this should not have been sent to this function!
|
||||
return
|
||||
@@ -119,10 +114,8 @@ func displayInstallerOutput(_ text: String) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Subclass of AsyncProcessRunner that handles the progress output from /usr/sbin/installer
|
||||
class installerRunner: AsyncProcessRunner {
|
||||
// subclass of AsyncProcessRunner that handles the progress output from
|
||||
// /usr/sbin/installer
|
||||
|
||||
var remainingOutput = ""
|
||||
var lastProcessedOutputLine = ""
|
||||
|
||||
@@ -161,10 +154,8 @@ class installerRunner: AsyncProcessRunner {
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs /usr/sbin/installer, parses and displays the output, and returns the process exit code
|
||||
func runInstaller(arguments: [String], environment: [String: String], pkgName: String) async -> Int {
|
||||
// Runs /usr/sbin/installer, parses and displays the output, and returns
|
||||
// the process exit code
|
||||
|
||||
let proc = installerRunner(arguments: arguments, environment: environment)
|
||||
await proc.run()
|
||||
let results = proc.results
|
||||
@@ -182,11 +173,10 @@ func runInstaller(arguments: [String], environment: [String: String], pkgName: S
|
||||
return results.exitcode
|
||||
}
|
||||
|
||||
// Uses the Apple installer to install the package or metapackage at pkgpath.
|
||||
// Returns a tuple:
|
||||
// the installer return code and restart needed as a boolean.
|
||||
func install(_ pkgpath: String, options: PlistDict = [:]) async -> (Int, Bool) {
|
||||
// Uses the Apple installer to install the package or metapackage at pkgpath.
|
||||
// Returns a tuple:
|
||||
// the installer return code and restart needed as a boolean.
|
||||
|
||||
var restartNeeded = false
|
||||
let packageName = (pkgpath as NSString).lastPathComponent
|
||||
let displayName = options["display_name"] as? String ?? options["name"] as? String ?? packageName
|
||||
@@ -237,13 +227,13 @@ func install(_ pkgpath: String, options: PlistDict = [:]) async -> (Int, Bool) {
|
||||
return (retcode, restartNeeded)
|
||||
}
|
||||
|
||||
// The Python version of Munki would actually install _all_ the pkgs from a given
|
||||
// directory (which was usually the root of a mounted disk image). This was rarely
|
||||
// was was actaully wanted. This version just installs the first installable item in
|
||||
// the directory.
|
||||
// Returns a tuple containing the exit code of the installer process and a boolean
|
||||
// indicating if a restart is needed
|
||||
func installFromDirectory(_ directoryPath: String, options: PlistDict = [:]) async -> (Int, Bool) {
|
||||
// The Python version of Munki would actually install _all_ the pkgs from a given
|
||||
// directory (which was usually the root of a mounted disk image. This was rarely
|
||||
// was was actaully wanted. This version just installs the first installable item in
|
||||
// the directory.
|
||||
// Returns a tuple containing the exit code of the installer process and a boolean
|
||||
// indicating if a restart is needed
|
||||
if stopRequested() {
|
||||
return (0, false)
|
||||
}
|
||||
|
||||
@@ -52,15 +52,13 @@ import Foundation
|
||||
#################################################################
|
||||
*/
|
||||
|
||||
/// Returns path to our package DB
|
||||
func pkgDBPath() -> String {
|
||||
// returns path to our package DB
|
||||
// let dbDir = managedInstallsDir()
|
||||
let dbDir = "/tmp"
|
||||
return (dbDir as NSString).appendingPathComponent("b.receiptdb")
|
||||
return managedInstallsDir(subpath: "b.receiptdb")
|
||||
}
|
||||
|
||||
/// Checks to see if our internal package (receipt) DB should be rebuilt.
|
||||
func shouldRebuildReceiptDB() -> Bool {
|
||||
// Checks to see if our internal package (receipt) DB should be rebuilt.
|
||||
let dbPath = pkgDBPath()
|
||||
let filemanager = FileManager.default
|
||||
if !filemanager.fileExists(atPath: dbPath) {
|
||||
@@ -84,8 +82,8 @@ func shouldRebuildReceiptDB() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
/// Creates the tables needed for our internal package database.
|
||||
func createReceiptDBTables(_ conn: SQL3Connection) throws {
|
||||
// Creates the tables needed for our internal package database.
|
||||
try conn.execute("""
|
||||
CREATE TABLE paths
|
||||
(path_key INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -121,10 +119,10 @@ struct PkgData {
|
||||
var files: [String] = []
|
||||
}
|
||||
|
||||
/// Inserts a pkg row into the db, returns rowid
|
||||
/// (which should be an alias for the integer primary key "pkg_key")
|
||||
func insertPkgDataIntoPkgDB(pkgdata: PkgData
|
||||
) throws {
|
||||
// inserts a pkg row into the db, returns rowid (which should be an alias for
|
||||
// the integer primary key "pkg_key"
|
||||
let connection = try SQL3Connection(pkgDBPath())
|
||||
try connection.execute("PRAGMA journal_mode = WAL;")
|
||||
try connection.execute("PRAGMA synchronous = normal;")
|
||||
@@ -148,10 +146,10 @@ func insertPkgDataIntoPkgDB(pkgdata: PkgData
|
||||
try connection.close()
|
||||
}
|
||||
|
||||
/// Inserts info into paths and pkg_paths tables
|
||||
func insertFileInfoIntoPkgDB(
|
||||
connection: SQL3Connection, pkgKey: Int64, pkgdata: PkgData
|
||||
) throws {
|
||||
// inserts info into paths and pkg_paths tables
|
||||
let pathsQuery = try SQL3Statement(
|
||||
connection: connection,
|
||||
SQLString: "SELECT path_key FROM paths WHERE path = ?"
|
||||
@@ -202,6 +200,7 @@ 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]
|
||||
@@ -241,8 +240,8 @@ func getPkgMetaData(_ pkg: String) async throws -> PkgData {
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a list of files installed by pkg
|
||||
func getFilesForPkg(_ pkg: String) async throws -> [String] {
|
||||
// Returns a list of files installed by pkg
|
||||
let result = await runCliAsync("/usr/sbin/pkgutil", arguments: ["--files", pkg])
|
||||
if result.exitcode != 0 {
|
||||
throw MunkiError("Error calling pkgutil: \(result.error)")
|
||||
@@ -250,6 +249,7 @@ func getFilesForPkg(_ pkg: String) async throws -> [String] {
|
||||
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)
|
||||
@@ -258,8 +258,8 @@ func getPkgDataAndAddtoDB(pkgid: String) async throws {
|
||||
try insertPkgDataIntoPkgDB(pkgdata: pkgdata)
|
||||
}
|
||||
|
||||
/// Imports package data from pkgutil into our internal package database.
|
||||
func importFromPkgutil() async throws {
|
||||
// Imports package data from pkgutil into our internal package database.
|
||||
let result = await runCliAsync("/usr/sbin/pkgutil", arguments: ["--pkgs"])
|
||||
if result.exitcode != 0 {
|
||||
throw MunkiError("Error calling pkgutil: \(result.error)")
|
||||
@@ -279,9 +279,8 @@ func importFromPkgutil() async throws {
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds or rebuilds our internal package database.
|
||||
func initReceiptDB(forcerebuild: Bool = false) async throws {
|
||||
// Builds or rebuilds our internal package database.
|
||||
|
||||
if !shouldRebuildReceiptDB(), !forcerebuild {
|
||||
// we'll use existing db
|
||||
return
|
||||
@@ -307,15 +306,15 @@ func initReceiptDB(forcerebuild: Bool = false) async throws {
|
||||
try await importFromPkgutil()
|
||||
}
|
||||
|
||||
/// Prepares a list of values for use in a SQL query
|
||||
func quoteAndJoin(_ stringList: [String]) -> String {
|
||||
// prepares a list of values for use in a SQL query
|
||||
let quotedStrings = stringList.map { "\"\($0)\"" }
|
||||
return "(" + quotedStrings.joined(separator: ",") + ")"
|
||||
}
|
||||
|
||||
/// Given a list of package ids, returns
|
||||
/// a list of pkg_keys from the pkgs table in our database.
|
||||
func getPkgKeysFromPkgDB(pkgids: [String]) throws -> [String] {
|
||||
// Given a list of package ids, returns
|
||||
// a list of pkg_keys from the pkgs table in our database.
|
||||
var keys = [String]()
|
||||
let sqlString = "SELECT pkg_key FROM pkgs WHERE pkgid IN " + quoteAndJoin(pkgids)
|
||||
let connection = try SQL3Connection(pkgDBPath())
|
||||
@@ -326,8 +325,8 @@ func getPkgKeysFromPkgDB(pkgids: [String]) throws -> [String] {
|
||||
return keys
|
||||
}
|
||||
|
||||
/// Queries our database for paths to remove.
|
||||
func getPathsToRemove(pkgKeys: [String]) throws -> [String] {
|
||||
// Queries our database for paths to remove.
|
||||
var pathsToRemove = [String]()
|
||||
let keyList = quoteAndJoin(pkgKeys)
|
||||
let selectedPkgs = "SELECT DISTINCT path_key FROM pkgs_paths WHERE pkg_key IN " + keyList
|
||||
@@ -364,6 +363,7 @@ func deletePkgKeyFromDB(connection: SQL3Connection, pkgKey: Int) throws {
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes info about pkgid from Apple's pkgutil database
|
||||
func forgetPkgFromAppleDB(_ pkgid: String) {
|
||||
let result = runCLI("/usr/sbin/pkgutil", arguments: ["--forget", pkgid])
|
||||
if result.exitcode == 0 {
|
||||
@@ -375,9 +375,9 @@ func forgetPkgFromAppleDB(_ pkgid: String) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes receipt data from our internal package database,
|
||||
/// and optionally Apple's package database.
|
||||
func removePkgReceipts(pkgKeys: [String], updateApplePkgDB: Bool = true) throws {
|
||||
// Removes receipt data from our internal package database,
|
||||
// and optionally Apple's package database.
|
||||
let taskCount = pkgKeys.count
|
||||
|
||||
displayMinorStatus("Removing receipt info")
|
||||
@@ -418,8 +418,8 @@ func removePkgReceipts(pkgKeys: [String], updateApplePkgDB: Bool = true) throws
|
||||
displayPercentDone(current: taskCount, maximum: taskCount)
|
||||
}
|
||||
|
||||
/// Returns true if path is a bundle-style directory.
|
||||
func pathIsBundle(_ path: String) -> Bool {
|
||||
// Returns true if path is a bundle-style directory.
|
||||
let bundleExtensions = [".action",
|
||||
".app",
|
||||
".bundle",
|
||||
@@ -452,8 +452,8 @@ func pathIsBundle(_ path: String) -> Bool {
|
||||
bundleExtensions.contains((path as NSString).pathExtension)
|
||||
}
|
||||
|
||||
/// Check the path to see if it's inside a bundle.
|
||||
func pathIsInsideBundle(_ path: String) -> Bool {
|
||||
// Check the path to see if it's inside a bundle.
|
||||
var currentPath = path
|
||||
while currentPath.count > 1 {
|
||||
if pathIsBundle(currentPath) {
|
||||
@@ -466,9 +466,8 @@ func pathIsInsideBundle(_ path: String) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
/// Attempts to remove all the paths in the pathsToRemove list
|
||||
func removeFilesystemItems(pathsToRemove: [String], forceDeleteBundles: Bool) {
|
||||
// Attempts to remove all the paths in the pathsToRemove list
|
||||
|
||||
var removalErrors = [String]()
|
||||
let itemCount = pathsToRemove.count
|
||||
displayMajorStatus("Removing \(itemCount) filesystem items")
|
||||
@@ -545,6 +544,8 @@ func removeFilesystemItems(pathsToRemove: [String], forceDeleteBundles: Bool) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Our main function, called to remove items based on receipt info.
|
||||
/// if listFiles is true, this is a dry run
|
||||
func removePackages(
|
||||
_ pkgids: [String],
|
||||
forceDeleteBundles: Bool = false,
|
||||
@@ -553,8 +554,6 @@ func removePackages(
|
||||
noRemoveReceipts: Bool = false,
|
||||
noUpdateApplePkgDB: Bool = false
|
||||
) async -> Int {
|
||||
// Our main function, called to remove items based on receipt info.
|
||||
// if listFiles is true, this is a dry run
|
||||
if pkgids.isEmpty {
|
||||
displayError("You must specify at least one package to remove!")
|
||||
return -2
|
||||
|
||||
Reference in New Issue
Block a user