Convert more comments to documentation

This commit is contained in:
Greg Neagle
2024-09-11 17:26:04 -07:00
parent b59988e11d
commit 65d0d6724f
3 changed files with 84 additions and 98 deletions
+21 -27
View File
@@ -20,13 +20,13 @@
import Foundation
/// Do spotlight search for type applications within the
/// list of directories provided. Returns a list of paths to applications.
/// dirList is actually a list of NSMetadataQuery search scopes, which
/// can be paths, or certain constants
/// Typically we'll use NSMetadataQueryLocalComputerScope to search the
/// local computer (skipping mounted network volumes)
func findAppsInDirs(_ dirList: [String]) -> [[String: String]] {
// Do spotlight search for type applications within the
// list of directories provided. Returns a list of paths to applications
// dirList is actually a list of NSMetadataQuery search scopes, which
// can be paths, or certain constants
// Typically we'll use NSMetadataQueryLocalComputerScope to search the
// local computer (skipping mounted network volumes)
var appList = [[String: String]]()
let query = NSMetadataQuery()
query.predicate = NSPredicate(format: "(kMDItemKind = \"Application\")")
@@ -79,14 +79,14 @@ func findAppsInDirs(_ dirList: [String]) -> [[String: String]] {
return appList
}
/// Get paths of currently installed applications per Spotlight.
/// Return value is list of paths.
/// Currently searches only the local computer, but not network volumes
func spotlightInstalledApps() -> [[String: String]] {
// Get paths of currently installed applications per Spotlight.
// Return value is list of paths.
// Currently searches only the local computer, but not network volumes
return findAppsInDirs([NSMetadataQueryLocalComputerScope])
}
// private, undocumented LaunchServices function
/// private, undocumented LaunchServices function
@_silgen_name("_LSCopyAllApplicationURLs") func LSCopyAllApplicationURLs(_: UnsafeMutablePointer<NSMutableArray?>) -> OSStatus
func launchServicesInstalledApps() -> [String] {
var apps: NSMutableArray?
@@ -99,9 +99,9 @@ func launchServicesInstalledApps() -> [String] {
return [String]()
}
/// Uses system profiler to get application info for this machine
/// Returns a dictionary with app paths as keys
func spApplicationData() async -> PlistDict {
// Uses system profiler to get application info for this machine
// Returns a dictionary with app paths as keys
var applicationData = PlistDict()
let tool = "/usr/sbin/system_profiler"
let arguments = ["SPApplicationsDataType", "-xml"]
@@ -141,21 +141,15 @@ func spApplicationData() async -> PlistDict {
return applicationData
}
/// Gets info on currently installed apps.
/// Returns a list of dicts containing path, name, version and bundleid
func getAppData() -> [[String: String]] {
// Gets info on currently installed apps.
// Returns a list of dicts containing path, name, version and bundleid
// one thing I'm not at all sure about is what iOS/iPadOS apps
// installed on Apple silicon Macs look like and how/if
// Launch Services, Spotlight, and system_profiler report them
displayDebug1("Getting info on currently installed applications...")
// async let spAppData = spApplicationData()
let lsApps = launchServicesInstalledApps()
// print("LaunchServices found \(lsApps.count) apps")
let spotlightApps = spotlightInstalledApps()
// print("Spotlight found \(spotlightApps.count) apps")
// print("system_profiler found \(await spAppData.count) apps")
// find apps that are unique to the LaunchServices list
let spotlightAppPaths = spotlightApps.map { $0["path"] ?? "" }.filter { !$0.isEmpty }
@@ -192,9 +186,8 @@ func getAppData() -> [[String: String]] {
return applicationData
}
/// A Singleton class for application inventory info, since it's expensive to generate
class ApplicationInventory {
// a Singleton class for application inventory info, since it's expensive
// to generate
static let shared = ApplicationInventory()
var inventory: [[String: String]]
@@ -213,22 +206,23 @@ class ApplicationInventory {
}
}
/// Return (possibly cached) installed application data
func appData() -> [[String: String]] {
return ApplicationInventory.shared.get()
}
/// Returns a filtered version of app_data, filtering out apps in user
/// home directories for use by compare_application_version()
func filteredAppData() -> [[String: String]] {
// Returns a filtered version of app_data, filtering out apps in user
// home directories for use by compare_application_version()
return appData().filter {
!(($0["path"] ?? "").hasPrefix("/Users") && !($0["path"] ?? "").hasPrefix("/Users/Shared"))
}
}
/// Save installed application data
/// data from appData() is meant for use by updatecheck
/// we need to massage it a bit for more general usage
func saveAppData() {
// Save installed application data
// data from appData() is meant for use by updatecheck
// we need to massage it a bit for more general usage
munkiLog("Saving application inventory...")
var appInventory = [[String: String]]()
for item in appData() {
+32 -38
View File
@@ -20,10 +20,9 @@
import Foundation
/// Gets some facts about this machine we use to determine if a given
/// installer is applicable to this OS or hardware
func generateMachineFacts() async -> PlistDict {
// Gets some facts about this machine we use to determine if a given
// installer is applicable to this OS or hardware
// these all call system_profiler so see if we can do
// them concurrently
async let ip4addresses = await getIPAddresses("IPv4")
@@ -66,9 +65,8 @@ func generateMachineFacts() async -> PlistDict {
return machine
}
/// A Singleton class for machine facts, since they are expensive to generate
class MachineFacts {
// a Singleton class for machine facts, since they are expensive
// to generate
static let shared = MachineFacts()
var facts: PlistDict
@@ -85,21 +83,20 @@ class MachineFacts {
}
}
/// Return 'facts' about this machine
func getMachineFacts() async -> PlistDict {
// return 'facts' about this machine
return await MachineFacts.shared.get()
}
/// Returns the path to the conditional scripts dir
private func conditionalScriptsDir() -> String {
// returns the path to the conditional scripts dir
// TODO: make this relative to the managedsoftwareupdate binary
return "/usr/local/munki/conditions"
}
/// Fetches key/value pairs from condition scripts
/// which can be placed into /usr/local/munki/conditions
func getConditions() async -> PlistDict {
// Fetches key/value pairs from condition scripts
// which can be placed into /usr/local/munki/conditions
let conditionalScriptDir = conditionalScriptsDir()
let conditionalItemsPath = managedInstallsDir(subpath: "ConditionalItems.plist")
let filemanager = FileManager.default
@@ -151,17 +148,16 @@ func getConditions() async -> PlistDict {
return PlistDict() // empty results
}
/// Input: NSDate object
/// Output: NSDate object with same date and time as the UTC.
/// In Los Angeles (PDT), '2011-06-20T12:00:00Z' becomes
/// '2011-06-20 12:00:00 -0700'.
/// In New York (EDT), it becomes '2011-06-20 12:00:00 -0400'.
/// This allows a pkginfo item to reference a time in UTC that
/// gets translated to the same relative local time.
/// A force_install_after_date for '2011-06-20T12:00:00Z' will happen
/// after 2011-06-20 12:00:00 local time.
func subtractTZOffsetFromDate(_ date: Date) -> Date {
// Input: NSDate object
// Output: NSDate object with same date and time as the UTC.
// In Los Angeles (PDT), '2011-06-20T12:00:00Z' becomes
// '2011-06-20 12:00:00 -0700'.
// In New York (EDT), it becomes '2011-06-20 12:00:00 -0400'.
// This allows a pkginfo item to reference a time in UTC that
// gets translated to the same relative local time.
// A force_install_after_date for '2011-06-20T12:00:00Z' will happen
// after 2011-06-20 12:00:00 local time.
// find our time zone offset in seconds
let timezone = NSTimeZone.default
let secondsOffset = Double(timezone.secondsFromGMT(for: date))
@@ -169,17 +165,16 @@ func subtractTZOffsetFromDate(_ date: Date) -> Date {
return Date(timeInterval: -secondsOffset, since: date)
}
/// Input: NSDate object
/// Output: NSDate object with timezone difference added
/// to the date. This allows conditional_item conditions to
/// be written like so:
///
/// <key>condition</key>
/// <string>date > CAST("2012-12-17T16:00:00Z", "NSDate")</string>
///
/// with the intent being that the comparison is against local time.
func addTZOffsetToDate(_ date: Date) -> Date {
// Input: NSDate object
// Output: NSDate object with timezone difference added
// to the date. This allows conditional_item conditions to
// be written like so:
//
// <key>condition</key>
// <string>date > CAST("2012-12-17T16:00:00Z", "NSDate")</string>
//
// with the intent being that the comparison is against local time.
// find our time zone offset in seconds
let timezone = NSTimeZone.default
let secondsOffset = Double(timezone.secondsFromGMT(for: date))
@@ -187,9 +182,9 @@ func addTZOffsetToDate(_ date: Date) -> Date {
return Date(timeInterval: secondsOffset, since: date)
}
/// Returns our info object used for predicate comparisons
func generatePredicateInfo() async -> PlistDict {
// Returns our info object used for predicate comparisons
// let's do some stuff concurrently
async let machine = getMachineFacts()
async let conditions = getConditions()
var infoObject = await machine
@@ -223,9 +218,8 @@ func generatePredicateInfo() async -> PlistDict {
return infoObject
}
/// A Singleton class for predicate info, since it's expensive to generate
class PredicateInfo {
// a Singleton class for predicate info, since it's expensive
// to generate
static let shared = PredicateInfo()
var info: PlistDict
@@ -242,19 +236,19 @@ class PredicateInfo {
}
}
/// Return our (possibly cached) info object
func predicateInfoObject() async -> PlistDict {
return await PredicateInfo.shared.get()
}
/// Evaluates predicate against the info object; returns a boolean
/// Calls out to an Objective-C function because NSPrediacte methods can
/// raise NSExecption, whcih Swift cannot catch
func predicateEvaluatesAsTrue(
_ predicateString: String,
infoObject: PlistDict,
additionalInfo: PlistDict? = nil
) -> Bool {
// Evaluates predicate against the info object; returns a boolean
// Calls out to an Objective-C function because NSPrediacte methods can
// raise NSExecption, whcih Swift cannot catch
var ourObject = infoObject
if let additionalInfo {
ourObject.merge(additionalInfo) { _, new in new }
+31 -33
View File
@@ -23,8 +23,8 @@ import Darwin
import Foundation
import IOKit
/// Uses system profiler to get info of dataType for this machine
func getSystemProfilerData(_ dataType: String) async -> PlistDict {
// Uses system profiler to get info of data_type for this machine
let tool = "/usr/sbin/system_profiler"
let arguments = [dataType, "-xml"]
let result = await runCliAsync(tool, arguments: arguments)
@@ -46,20 +46,20 @@ func getSystemProfilerData(_ dataType: String) async -> PlistDict {
return PlistDict()
}
/// Uses system profiler to get hardware info for this machine
func getHardwareInfo() async -> PlistDict {
// Uses system profiler to get hardware info for this machine
return await getSystemProfilerData("SPHardwareDataType")
}
/// Uses system profiler to get iBridge info for this machine
func getIBridgeInfo() async -> PlistDict {
// Uses system profiler to get iBridge info for this machine
return await getSystemProfilerData("SPiBridgeDataType")
}
/// Uses system profiler to get active IP addresses for this machine
/// kind must be one of 'IPv4' or 'IPv6'
/// NOTE this does not return any utun addresses.
func getIPAddresses(_ kind: String) async -> [String] {
// Uses system profiler to get active IP addresses for this machine
// kind must be one of 'IPv4' or 'IPv6'
// NOTE this does not return any utun addresses.
var ipAddresses = [String]()
let tool = "/usr/sbin/system_profiler"
let arguments = ["SPNetworkDataType", "-xml"]
@@ -86,25 +86,25 @@ func getIPAddresses(_ kind: String) async -> [String] {
return ipAddresses
}
// IOKit helpers
// MARK: IOKit helpers
/// Returns a reference to an IOKit service matching on IOService class name,
/// typically something like "IOPlatformExpertDevice"
private func serviceMatching(_ className: String) -> io_registry_entry_t {
// returns a reference to an IOKit service matching on IOService class name,
// typically something like "IOPlatformExpertDevice"
return IOServiceGetMatchingService(
kIOMasterPortDefault, IOServiceMatching(className)
)
}
/// Returns a reference to an IOKit service matching on IOService name
private func serviceNameMatching(_ name: String) -> io_registry_entry_t {
// returns a reference to an IOKit service matching on IOService name
return IOServiceGetMatchingService(
kIOMasterPortDefault, IOServiceNameMatching(name)
)
}
/// Attempts to return a string value for the given property key
private func stringValueForIOServiceProperty(service: io_registry_entry_t, key: String) -> String? {
// attempts to return a string value for the given property key
let rawData = IORegistryEntryCreateCFProperty(
service, key as CFString, kCFAllocatorDefault, 0
)
@@ -116,11 +116,11 @@ private func stringValueForIOServiceProperty(service: io_registry_entry_t, key:
encoding: .utf8)?.trimmingCharacters(in: ["\0"])
}
// info functions that call IOKit
// MARK: info functions that call IOKit
/// Returns mouse/keyboard idel time in nanoseconds
/// (1/1000000000) of a second
func hidIdleTime() -> Int {
// returns mouse/keyboard idel time in nanoseconds
// (1/1000000000) of a second
let idleTime = IORegistryEntryCreateCFProperty(
serviceMatching("IOHIDSystem"),
"HIDIdleTime" as CFString,
@@ -134,8 +134,8 @@ func hidIdleTime() -> Int {
return nanoSeconds as! Int
}
/// Returns the serial number of this Mac
func serialNumber() -> String {
// Returns the serial number of this Mac
let serial = IORegistryEntryCreateCFProperty(
serviceMatching("IOPlatformExpertDevice"),
kIOPlatformSerialNumberKey as CFString,
@@ -148,34 +148,34 @@ func serialNumber() -> String {
return "UNKNOWN"
}
/// Returns the product name from IORegistry
func productName() -> String {
// Returns the product name from IORegistry
return stringValueForIOServiceProperty(
service: serviceNameMatching("product"),
key: "product-name"
) ?? "Intel Mac"
}
/// Returns board-id from IORegistry
func boardID() -> String {
// Returns board-id from IORegistry
return stringValueForIOServiceProperty(
service: serviceMatching("IOPlatformExpertDevice"),
key: "board-id"
) ?? "<none>"
}
/// Returns device id from IORegistry
func deviceID() -> String {
// Returns board-id from IORegistry
return stringValueForIOServiceProperty(
service: serviceMatching("IOPlatformExpertDevice"),
key: "target-sub-type"
) ?? "<none>"
}
// info functions that use sysctlbyname
// MARK: info functions that use sysctlbyname
/// Returns model (like 'Mac1,2')
func hardwareModel() -> String {
// returns model (Mac1,2)
var size = 0
// call sysctlbyname to get the size of the returned string
let err1 = sysctlbyname("hw.model", nil, &size, nil, 0)
@@ -196,8 +196,8 @@ func hardwareModel() -> String {
return str
}
/// Returns true if this Mac has an Intel processor that supports 64bit code
func hasIntel64Support() -> Bool {
// returns true if this Mac has an Intel processor that supports 64bit code
var size = 0
// call sysctlbyname to get the size of the returned value
let err1 = sysctlbyname("hw.optional.x86_64", nil, &size, nil, 0)
@@ -215,10 +215,10 @@ func hasIntel64Support() -> Bool {
return buffer[0] == 1
}
/// Returns available diskspace in KBytes.
/// Value should be very close to `df -k` output
/// Returns negative values of there is an error
func availableDiskSpace(volumePath _: String = "/") -> Int {
// Returns available diskspace in KBytes.
// Value should be very close to `df -k` output
// Returns negative values of there is an error
let buffer = UnsafeMutablePointer<statvfs>.allocate(capacity: 1024)
defer { buffer.deallocate() }
let err = statvfs("/", buffer)
@@ -230,8 +230,8 @@ func availableDiskSpace(volumePath _: String = "/") -> Int {
return Int(f_frsize * f_bavail / 1024)
}
/// Returns uname's version of hostname
func hostname() -> String {
// returns uname's version of hostname
var systemInfo = utsname()
uname(&systemInfo)
let size = Int(_SYS_NAMELEN) // is 256 on Darwin
@@ -244,8 +244,8 @@ func hostname() -> String {
return str
}
/// Returns platform (arch) ("x86_64", "arm64")
func platform() -> String {
// returns platform (arch) ("x86_64", "arm64")
var systemInfo = utsname()
uname(&systemInfo)
let size = Int(_SYS_NAMELEN) // is 256 on Darwin
@@ -258,8 +258,8 @@ func platform() -> String {
return str
}
/// Returns uname's version string
func uname_version() -> String {
// returns uname's version string
var systemInfo = utsname()
uname(&systemInfo)
let size = Int(_SYS_NAMELEN) // is 256 on Darwin
@@ -272,9 +272,8 @@ func uname_version() -> String {
return str
}
/// Returns uname's system string. (Pretty much always returns "Darwin")
func uname_sysname() -> String {
// returns uname's system string
// Pretty much always returns "Darwin"
var systemInfo = utsname()
uname(&systemInfo)
let size = Int(_SYS_NAMELEN) // is 256 on Darwin
@@ -287,9 +286,8 @@ func uname_sysname() -> String {
return str
}
/// Returns uname's release string (Darwin version)
func uname_release() -> String {
// returns uname's system string
// Pretty much always returns "Darwin"
var systemInfo = utsname()
uname(&systemInfo)
let size = Int(_SYS_NAMELEN) // is 256 on Darwin
@@ -302,13 +300,13 @@ func uname_release() -> String {
return str
}
/// Returns true if we're running on Apple silicon
func isAppleSilicon() -> Bool {
// Returns true if we're running on Apple silicon"
return platform() == "arm64"
}
/// Returns the OS Build "number" (example 16G1212).
func getOSBuild() -> String {
// Returns the OS Build "number" (example 16G1212).
do {
if let systemVersion = try readPlist(
fromFile: "/System/Library/CoreServices/SystemVersion.plist"