Finally getting the hang of how documentation comments work

This commit is contained in:
Greg Neagle
2024-09-10 20:34:19 -07:00
parent 605ac2eedf
commit 544138152b
5 changed files with 55 additions and 64 deletions

View File

@@ -40,6 +40,7 @@ extension FetchError: LocalizedError {
}
}
/// Stores a sha256 hash of the file in an extended attribute, generating the hash if needed.
func storeCachedChecksum(toPath path: String, hash: String? = nil) -> String? {
let fhash: String = if let hash {
hash

View File

@@ -21,6 +21,7 @@
import Foundation
import Security
/// A simple logging function to use if none is given to Gurl
func defaultLogger(_ message: String) {
print(message)
}
@@ -42,8 +43,7 @@ struct GurlOptions {
var log: (String) -> Void = defaultLogger // logging function
}
/// A class for getting content from a URL
/// using NSURLSession and friends
/// A class for getting content from a URL using NSURLSession and friends
class Gurl: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate {
let GURL_XATTR = "com.googlecode.munki.downloadData"
@@ -199,9 +199,8 @@ class Gurl: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionData
}
}
/// Since HTTP header names are not case-sensitive, we normalize a
/// dictionary of HTTP headers by converting all the key names to
/// lower case
/// Normalize a dictionary of HTTP headers by converting all the key names to
/// lower case, since HTTP header names are not case-sensitive
func normalizeHeaderDict(_ headers: [String: String]) -> [String: String] {
var normalizedHeaders = [String: String]()
for (key, value) in headers {

View File

@@ -7,19 +7,24 @@
import Foundation
/// Uses URL to compose a URL from basURL and additional relative path
func composedURLWithBase(_ baseURLString: String, adding path: String) -> String {
let baseURL = URL(string: baseURLString)
let composedURL = URL(string: path, relativeTo: baseURL)
return composedURL?.absoluteString ?? ""
}
/// Returns a URL to something in a Munki repo.
/// If type is empty, returns the base URL for the Munki repo.
/// If type is one of the supported types, returns the type-specific URL.
/// If type is specifiied and resource is also specifiied, a full URL to the resource is
/// constructed and returned
func munkiRepoURL(_ type: String = "", resource: String = "") -> String? {
/// we could use composedURLWithBase, but that doesn't handle
/// URLs in the format of CGI invocations correctly, and would not
/// be consistent with the behavior of the Python version of Munki
/// So instead we'll do simple string concatenation
/// (with percent-encoding of the resource path)
// we could use composedURLWithBase, but that doesn't handle
// URLs in the format of CGI invocations correctly, and would not
// be consistent with the behavior of the Python version of Munki
// So instead we'll do simple string concatenation
// (with percent-encoding of the resource path)
let munkiBaseURL = pref("SoftwareRepoURL") as? String ?? ""
if type.isEmpty {
return munkiBaseURL

View File

@@ -7,13 +7,12 @@
import Foundation
/// For a URL, return the path that the download should cache to.
func getDownloadCachePath(_ urlString: String) -> String {
/// For a URL, return the path that the download should cache to.
///
/// Returns a string.
return managedInstallsDir(subpath: "Cache/" + baseName(urlString))
}
/// Determine if there is enough disk space to download and install the installer item.
func enoughDiskSpaceFor(
_ item: PlistDict,
installList: [PlistDict] = [],
@@ -21,9 +20,6 @@ func enoughDiskSpaceFor(
warn: Bool = true,
precaching: Bool = false
) -> Bool {
/// Determine if there is enough disk space to download and install
/// the installer item.
// fudgefactor is 100MB
let fudgefactor = 102_400 // KBytes
var alreadyDownloadedSize = 0
@@ -78,17 +74,15 @@ func enoughDiskSpaceFor(
return false
}
/// Downloads an (un)installer item.
/// Returns true if the item was downloaded, false if it was already cached.
/// Thows an error if there are issues
func downloadInstallerItem(
_ item: PlistDict,
installInfo: PlistDict,
uninstalling: Bool = false,
precaching: Bool = false
) throws -> Bool {
/// Downloads an (un)installer item.
/// Returns true if the item was downloaded,
/// false if it was already cached.
/// Thows an error if there are issues
let downloadItemKey = if uninstalling, item.keys.contains("uninstaller_item_location") {
"uninstaller_item_location"
} else {
@@ -171,9 +165,8 @@ func downloadInstallerItem(
let ICON_HASHES_PLIST_NAME = "_icon_hashes.plist"
/// Remove any cached/downloaded icons that aren't in the list of ones to keep
func cleanUpIconsDir(keepList: [String] = []) {
/// Remove any cached/downloaded icons that aren't in the list of ones
/// to keep
let itemsToKeep = keepList + [ICON_HASHES_PLIST_NAME]
let iconsDir = managedInstallsDir(subpath: "icons")
cleanUpDir(iconsDir, keeping: itemsToKeep)
@@ -196,9 +189,8 @@ func getIconHashes() -> [String: String] {
}
}
/// Attempts to download icons (actually image files) for items in itemList
func downloadIcons(_ itemList: [PlistDict]) {
/// Attempts to download icons (actually image files) for items in
/// itemList
var iconsToKeep = [String]()
let iconsDir = managedInstallsDir(subpath: "icons")
let iconHashes = getIconHashes()
@@ -258,14 +250,12 @@ func downloadIcons(_ itemList: [PlistDict]) {
cleanUpIconsDir(keepList: iconsToKeep)
}
/// Download client customization resources (if any).
/// Munki's preferences can specify an explicit name under ClientResourcesFilename
/// if that doesn't exist, use the primary manifest name as the filename.
/// If that fails, try site_default.zip
func downloadClientResources() {
/// Download client customization resources (if any).
/// Munki's preferences can specify an explicit name
/// under ClientResourcesFilename
/// if that doesn't exist, use the primary manifest name as the
/// filename. If that fails, try site_default.zip
// build a list of resource names to request from the server
var filenames = [String]()
if let resourcesName = pref("ClientResourcesFilename") as? String {
@@ -320,9 +310,8 @@ func downloadClientResources() {
}
}
/// Attempt to download a catalog from the Munki server. Returns the path to the downloaded catalog file.
func downloadCatalog(_ catalogName: String) -> String? {
/// Attempt to download a catalog from the Munki server, Returns the path to
/// the downloaded catalog file
let catalogPath = managedInstallsDir(subpath: "catalogs/\(catalogName)")
displayDetail("Getting catalog \(catalogName)...")
let message = "Retrieving catalog \(catalogName)..."
@@ -342,9 +331,9 @@ func downloadCatalog(_ catalogName: String) -> String? {
// TODO: precaching support (in progress)
/// Returns a list of items from InstallInfo.plist's optional_installs
/// that have precache=true and (installed=false or needs_update=true)
private func itemsToPrecache(_ installInfo: PlistDict) -> [PlistDict] {
/// Returns a list of items from InstallInfo.plist's optional_installs
/// that have precache=true and (installed=false or needs_update=true)
func boolValueFor(_ item: PlistDict, key: String) -> Bool {
return item[key] as? Bool ?? false
}
@@ -358,8 +347,8 @@ private func itemsToPrecache(_ installInfo: PlistDict) -> [PlistDict] {
return [PlistDict]()
}
/// Download any applicable precache items into our Cache folder
func precache() {
/// Download any applicable precache items into our Cache folder
guard let installInfo = getInstallInfo() else {
// nothing to do
return
@@ -378,8 +367,8 @@ func precache() {
displayInfo("### Ending precaching session ###")
}
/// Discard precached items to free up space for managed installs
func uncache(_: Int) {
/// Discard precached items to free up space for managed installs
guard let installInfo = getInstallInfo() else {
return
}

View File

@@ -31,8 +31,8 @@ extension ManifestError: LocalizedError {
}
}
/// a Singleton class to track manifest name -> local path
class Manifests {
/// a Singleton class to track manifest_name -> local path
static let shared = Manifests()
var db: [String: String]
@@ -62,14 +62,13 @@ class Manifests {
}
}
/// Gets a manifest from the server.
///
/// Returns:
/// string local path to the downloaded manifest
/// Throws:
/// ManifestError
func getManifest(_ name: String, suppressErrors: Bool = false) throws -> String {
/// Gets a manifest from the server.
///
/// Returns:
/// string local path to the downloaded manifest
/// Throws:
/// ManifestError
// have we already retrieved it this session?
if let manifestLocalPath = Manifests.shared.get(name) {
return manifestLocalPath
@@ -123,9 +122,9 @@ func getManifest(_ name: String, suppressErrors: Bool = false) throws -> String
return manifestLocalPath
}
/// Gets the primary client manifest from the server.
/// Can throw all the same errors as getManifest
func getPrimaryManifest(alternateIdentifier: String? = nil) throws -> String {
/// Gets the primary client manifest from the server.
/// Can throw all the same errors as getManifest
var clientIdentifier = ""
if let alternateIdentifier, !alternateIdentifier.isEmpty {
clientIdentifier = alternateIdentifier
@@ -187,16 +186,16 @@ func getPrimaryManifest(alternateIdentifier: String? = nil) throws -> String {
return manifest
}
/// Removes any manifest files that are no longer in use by this client
func cleanUpManifests() {
/// Removes any manifest files that are no longer in use by this client
let manifestDir = managedInstallsDir(subpath: "manifests")
let exceptions = ["SelfServeManifest"]
let keepList = Manifests.shared.list() + exceptions
cleanUpDir(manifestDir, keeping: keepList)
}
/// Reads a manifest file, returns a dictionary.
func manifestData(_ path: String) -> PlistDict? {
/// Reads a manifest file, returns a dictionary.
if pathExists(path) {
do {
if let plist = try readPlist(fromFile: path) as? PlistDict {
@@ -218,6 +217,7 @@ func manifestData(_ path: String) -> PlistDict? {
return nil
}
/// Returns the value for key for a manifest
func getManifestValue(_ path: String, forKey key: String) -> Any? {
if let manifest = manifestData(path) {
if let value = manifest[key] {
@@ -229,9 +229,8 @@ func getManifestValue(_ path: String, forKey key: String) -> Any? {
return nil
}
/// Remove the given itemname from the self-serve manifest's managed_uninstalls list
func removeItemFromSelfServeSection(itemname: String, section: String) {
/// Remove the given itemname from the self-serve manifest's
/// managed_uninstalls list
displayDebug1("Removing \(itemname) from SelfServeManifest's \(section)...")
let manifestPath = managedInstallsDir(subpath: "manifests/SelfServeManifest")
if !pathExists(manifestPath) {
@@ -258,9 +257,8 @@ func removeItemFromSelfServeSection(itemname: String, section: String) {
}
}
/// Remove the given itemname from the self-serve manifest's managed_installs list
func removeFromSelfServeInstalls(_ itemName: String) {
/// Remove the given itemname from the self-serve manifest's
/// managed_installs list
removeItemFromSelfServeSection(itemname: itemName, section: "managed_installs")
}
@@ -270,6 +268,13 @@ func removeFromSelfServeUninstalls(_ itemName: String) {
removeItemFromSelfServeSection(itemname: itemName, section: "managed_uninstalls")
}
/// Processes keys in manifests to build the lists of items to install and
/// remove.
///
/// Can be recursive if manifests include other manifests.
/// Probably doesn't handle circular manifest references well.
///
/// manifest can be a path to a manifest file or a dictionary object.
func processManifest(
_ manifestdata: PlistDict,
forKey key: String,
@@ -277,14 +282,6 @@ func processManifest(
parentCatalogs: [String] = [],
manifestName: String = "embedded manifest"
) async throws {
/// Processes keys in manifests to build the lists of items to install and
/// remove.
///
/// Can be recursive if manifests include other manifests.
/// Probably doesn't handle circular manifest references well.
///
/// manifest can be a path to a manifest file or a dictionary object.
let manifestCatalogs = manifestdata["catalogs"] as? [String] ?? []
var catalogList = [String]()
if !manifestCatalogs.isEmpty {
@@ -391,13 +388,13 @@ func processManifest(
}
}
/// Process a manifest _file_
func processManifest(
atPath manifestPath: String,
forKey key: String,
installInfo: inout PlistDict,
parentCatalogs: [String] = []
) async throws {
/// processe a manifest _file_
displayDebug1("** Processing manifest \(baseName(manifestPath)) for \(key)")
if let manifestdata = manifestData(manifestPath) {
try await processManifest(