From ff7a74c702776c49f0a27e896bd3c7873af4e626 Mon Sep 17 00:00:00 2001 From: Greg Neagle Date: Mon, 15 Jul 2024 13:52:50 -0700 Subject: [PATCH] Simplfy and unify many of the common errors --- .../cli/munki/makecatalogs/makecatalogs.swift | 4 +- code/cli/munki/makepkginfo/makepkginfo.swift | 10 +- .../cli/munki/munki.xcodeproj/project.pbxproj | 12 ++ code/cli/munki/munkiimport/munkiimport.swift | 28 ++--- .../munki/shared/admin/makecatalogslib.swift | 12 +- .../munki/shared/admin/munkiimportlib.swift | 104 +++++++----------- code/cli/munki/shared/admin/pkginfolib.swift | 29 ++--- code/cli/munki/shared/dmgutils.swift | 10 +- code/cli/munki/shared/errors.swift | 33 ++++++ .../cli/munki/shared/munkirepo/FileRepo.swift | 14 +-- .../munki/shared/munkirepo/RepoFactory.swift | 2 +- code/cli/munki/shared/osinstaller.swift | 20 ++-- code/cli/munki/shared/pkgutils.swift | 13 +-- 13 files changed, 136 insertions(+), 155 deletions(-) create mode 100644 code/cli/munki/shared/errors.swift diff --git a/code/cli/munki/makecatalogs/makecatalogs.swift b/code/cli/munki/makecatalogs/makecatalogs.swift index c19190ba..8ca68845 100644 --- a/code/cli/munki/makecatalogs/makecatalogs.swift +++ b/code/cli/munki/makecatalogs/makecatalogs.swift @@ -104,8 +104,8 @@ struct MakeCatalogs: ParsableCommand { } throw ExitCode(-1) } - } catch let RepoError.error(description) { - printStderr("Repo error: \(description)") + } catch let error as RepoError { + printStderr("Repo error: \(error.description)") throw ExitCode(-1) } catch let error as MakeCatalogsError { switch error { diff --git a/code/cli/munki/makepkginfo/makepkginfo.swift b/code/cli/munki/makepkginfo/makepkginfo.swift index d7d7a38d..79ff170a 100644 --- a/code/cli/munki/makepkginfo/makepkginfo.swift +++ b/code/cli/munki/makepkginfo/makepkginfo.swift @@ -109,14 +109,8 @@ struct MakePkgInfo: ParsableCommand { } catch let PlistError.writeError(description) { printStderr("ERROR: \(description)") throw ExitCode(-1) - } catch let PkgInfoGenerationError.error(description) { - printStderr("ERROR: \(description)") - throw ExitCode(-1) - } catch let PackageParsingError.error(description) { - printStderr("ERROR: \(description)") - throw ExitCode(-1) - } catch let DiskImageError.error(description) { - printStderr("ERROR: \(description)") + } catch let error as MunkiError { + printStderr("ERROR: \(error.description)") throw ExitCode(-1) } catch { printStderr("Unexpected error: \(type(of: error))") diff --git a/code/cli/munki/munki.xcodeproj/project.pbxproj b/code/cli/munki/munki.xcodeproj/project.pbxproj index 9c022896..f1476370 100644 --- a/code/cli/munki/munki.xcodeproj/project.pbxproj +++ b/code/cli/munki/munki.xcodeproj/project.pbxproj @@ -127,6 +127,11 @@ C0D00FB22C458EAA0021DA9C /* version.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FAF2C458EAA0021DA9C /* version.swift */; }; C0D00FB32C458EAA0021DA9C /* version.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FAF2C458EAA0021DA9C /* version.swift */; }; C0D00FB42C458EAA0021DA9C /* version.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FAF2C458EAA0021DA9C /* version.swift */; }; + C0D00FB62C45BCB90021DA9C /* errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FB52C45BCB90021DA9C /* errors.swift */; }; + C0D00FB72C45BCB90021DA9C /* errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FB52C45BCB90021DA9C /* errors.swift */; }; + C0D00FB82C45BCB90021DA9C /* errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FB52C45BCB90021DA9C /* errors.swift */; }; + C0D00FB92C45BCB90021DA9C /* errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FB52C45BCB90021DA9C /* errors.swift */; }; + C0D00FBA2C45BCB90021DA9C /* errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FB52C45BCB90021DA9C /* errors.swift */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -219,6 +224,7 @@ C07A6FD92C2CF19600090743 /* cliutils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = cliutils.swift; sourceTree = ""; }; C0D00FA72C45814F0021DA9C /* repoutils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = repoutils.swift; sourceTree = ""; }; C0D00FAF2C458EAA0021DA9C /* version.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = version.swift; sourceTree = ""; }; + C0D00FB52C45BCB90021DA9C /* errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = errors.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -389,6 +395,7 @@ C030A9EE2C43505B007F0B34 /* munkitester-Bridging-Header.h */, C030A9EF2C43505B007F0B34 /* munkiimport-Bridging-Header.h */, C0D00FAF2C458EAA0021DA9C /* version.swift */, + C0D00FB52C45BCB90021DA9C /* errors.swift */, ); path = shared; sourceTree = ""; @@ -569,6 +576,7 @@ C030A9AF2C3B50B5007F0B34 /* constants.swift in Sources */, C030A9A12C3B4F5B007F0B34 /* pkginfoOptions.swift in Sources */, C030A9A92C3B4FF5007F0B34 /* display.swift in Sources */, + C0D00FB92C45BCB90021DA9C /* errors.swift in Sources */, C030A9AE2C3B50A5007F0B34 /* reports.swift in Sources */, C030A9A62C3B4FDF007F0B34 /* munkihash.swift in Sources */, C030A9AA2C3B4FFC007F0B34 /* munkilog.swift in Sources */, @@ -584,6 +592,7 @@ files = ( C030A9EB2C4241AC007F0B34 /* munkilog.swift in Sources */, C030A9D42C41F849007F0B34 /* munkiimportOptions.swift in Sources */, + C0D00FBA2C45BCB90021DA9C /* errors.swift in Sources */, C030A9E92C424179007F0B34 /* fileutils.swift in Sources */, C0D00FAA2C45814F0021DA9C /* repoutils.swift in Sources */, C030A9DE2C424083007F0B34 /* munkiimportlib.swift in Sources */, @@ -623,6 +632,7 @@ C07A6FDA2C2CF19600090743 /* cliutils.swift in Sources */, C01364432C2DD1BA008DB215 /* plistutils.swift in Sources */, C030A98F2C39C135007F0B34 /* munkihash.swift in Sources */, + C0D00FB62C45BCB90021DA9C /* errors.swift in Sources */, C07A6FB02C2B22A400090743 /* prefs.swift in Sources */, C07A6FA92C2A82B400090743 /* managedsoftwareupdate.swift in Sources */, C0D00FB02C458EAA0021DA9C /* version.swift in Sources */, @@ -645,6 +655,7 @@ files = ( C01364442C2DD1BA008DB215 /* plistutils.swift in Sources */, C01364462C2E051F008DB215 /* makecatalogslib.swift in Sources */, + C0D00FB72C45BCB90021DA9C /* errors.swift in Sources */, C030A9C82C41F32E007F0B34 /* munkiimportOptions.swift in Sources */, C030A9C02C409738007F0B34 /* iconutils.swift in Sources */, C030A9F62C435183007F0B34 /* readline.swift in Sources */, @@ -684,6 +695,7 @@ C01364452C2DD1BA008DB215 /* plistutils.swift in Sources */, C0D00FA12C457E2B0021DA9C /* munkihash.swift in Sources */, C07A6FCB2C2B5C3A00090743 /* prefs.swift in Sources */, + C0D00FB82C45BCB90021DA9C /* errors.swift in Sources */, C013644F2C30F5D8008DB215 /* RepoFactory.swift in Sources */, C07A6FC72C2B5C0700090743 /* makecatalogs.swift in Sources */, C0D00FB22C458EAA0021DA9C /* version.swift in Sources */, diff --git a/code/cli/munki/munkiimport/munkiimport.swift b/code/cli/munki/munkiimport/munkiimport.swift index 872177ed..44b811f2 100644 --- a/code/cli/munki/munkiimport/munkiimport.swift +++ b/code/cli/munki/munkiimport/munkiimport.swift @@ -150,14 +150,8 @@ struct MunkiImport: AsyncParsableCommand { var pkginfo: PlistDict do { pkginfo = try makepkginfo(installerItem, options: pkginfoOptions) - } catch let PkgInfoGenerationError.error(description) { - printStderr("ERROR: \(description)") - throw ExitCode(-1) - } catch let PackageParsingError.error(description) { - printStderr("ERROR: \(description)") - throw ExitCode(-1) - } catch let DiskImageError.error(description) { - printStderr("ERROR: \(description)") + } catch let error as MunkiError { + printStderr("ERROR: \(error.description)") throw ExitCode(-1) } catch { printStderr("Unexpected error: \(type(of: error))") @@ -169,8 +163,8 @@ struct MunkiImport: AsyncParsableCommand { var repo: Repo do { repo = try repoConnect(url: repoURL, plugin: plugin) - } catch let RepoError.error(description) { - printStderr("Repo connection error: \(description)") + } catch let error as RepoError { + printStderr("Repo connection error: \(error.description)") throw ExitCode(-1) } @@ -296,7 +290,7 @@ struct MunkiImport: AsyncParsableCommand { { return } - // adjusr subdir if needed + // adjust subdir if needed if munkiImportOptions.subdirectory == nil, let filerepo = repo as? FileRepo { @@ -325,8 +319,8 @@ struct MunkiImport: AsyncParsableCommand { { do { let _ = try convertAndInstallIcon(repo, name: name, iconPath: iconPath) - } catch let MunkiImportError.error(description) { - printStderr("Error importing \(iconPath): \(description)") + } catch let error as MunkiImportError { + printStderr("Error importing \(iconPath): \(error.description)") } } else if !munkiImportOptions.extractIcon, !iconIsInRepo(repo, pkginfo: pkginfo) @@ -348,8 +342,8 @@ struct MunkiImport: AsyncParsableCommand { } else { print("No icons found for import.") } - } catch let MunkiImportError.error(description) { - printStderr("Error importing icons: \(description)") + } catch let error as MunkiImportError { + printStderr("Error importing icons: \(error.description)") } catch { printStderr("Error importing icons: \(error)") } @@ -363,8 +357,8 @@ struct MunkiImport: AsyncParsableCommand { let version = pkginfo["version"] as? String ?? "UNKNOWN" uploadedPkgPath = try copyInstallerItemToRepo(repo, itempath: installerItem, version: version, subdirectory: subdir) print("Copied \(installerItemName) to \(uploadedPkgPath).") - } catch let MunkiImportError.error(description) { - printStderr("Error importing \(installerItem): \(description)") + } catch let error as MunkiImportError { + printStderr("Error importing \(installerItem): \(error.description)") throw ExitCode(-1) } catch { printStderr("Error importing \(installerItem): \(error)") diff --git a/code/cli/munki/shared/admin/makecatalogslib.swift b/code/cli/munki/shared/admin/makecatalogslib.swift index 54a0df84..2329b2f4 100644 --- a/code/cli/munki/shared/admin/makecatalogslib.swift +++ b/code/cli/munki/shared/admin/makecatalogslib.swift @@ -90,8 +90,8 @@ struct CatalogsMaker { do { let icondata = try repo.get("icons/" + icon) iconHashes[icon] = sha256hash(data: icondata) - } catch let RepoError.error(description) { - errors.append("RepoError reading icons/\(icon): \(description)") + } catch let error as RepoError { + errors.append("Error reading icons/\(icon): \(error.description)") } catch { errors.append("Unexpected error reading icons/\(icon): \(error)") } @@ -296,8 +296,8 @@ struct CatalogsMaker { } } catch let PlistError.writeError(description) { errors.append("Could not serialize catalog \(key): \(description)") - } catch let RepoError.error(description) { - errors.append("Failed to create catalog \(key): \(description)") + } catch let error as RepoError { + errors.append("Failed to create catalog \(key): \(error.description)") } catch { errors.append("Unexpected error creating catalog \(key): \(error)") } @@ -317,8 +317,8 @@ struct CatalogsMaker { } } catch let PlistError.writeError(description) { errors.append("Could not serialize icon hashes: \(description)") - } catch let RepoError.error(description) { - errors.append("Failed to create \(iconHashesIdentifier): \(description)") + } catch let error as RepoError { + errors.append("Failed to create \(iconHashesIdentifier): \(error.description)") } catch { errors.append("Unexpected error creating \(iconHashesIdentifier): \(error)") } diff --git a/code/cli/munki/shared/admin/munkiimportlib.swift b/code/cli/munki/shared/admin/munkiimportlib.swift index de1cac48..5d35eb62 100644 --- a/code/cli/munki/shared/admin/munkiimportlib.swift +++ b/code/cli/munki/shared/admin/munkiimportlib.swift @@ -21,9 +21,7 @@ import Darwin.C import Foundation -enum MunkiImportError: Error { - case error(description: String) -} +typealias MunkiImportError = MunkiError func getSingleArch(_ pkginfo: PlistDict) -> String { // If there is exactly one supported architecture, return a string with it @@ -75,22 +73,18 @@ func copyInstallerItemToRepo(_ repo: Repo, itempath: String, version: String, su itemName = "\(name)__\(index)\(ext)" destIdentifier = (destPath as NSString).appendingPathComponent(itemName) } - } catch let RepoError.error(description) { - throw MunkiImportError.error( - description: "Unable to get list of current pkgs: \(description)") + } catch let error as RepoError { + throw MunkiImportError("Unable to get list of current pkgs: \(error.description)") } catch { - throw MunkiImportError.error( - description: "Unexpected error: \(error)") + throw MunkiImportError("Unexpected error: \(error)") } do { try repo.put(destIdentifier, fromFile: itempath) return destIdentifier - } catch let RepoError.error(description) { - throw MunkiImportError.error( - description: "Unable to copy \(itempath) to pkgs/\(destIdentifier): \(description)") + } catch let error as RepoError { + throw MunkiImportError("Unable to copy \(itempath) to pkgs/\(destIdentifier): \(error.description)") } catch { - throw MunkiImportError.error( - description: "Unexpected error when copying \(itempath) to pkgs/\(destIdentifier): \(error)") + throw MunkiImportError("Unexpected error when copying \(itempath) to pkgs/\(destIdentifier): \(error)") } } @@ -108,10 +102,10 @@ func copyPkgInfoToRepo(_ repo: Repo, pkginfo: PlistDict, subdirectory: String = arch = "-" + arch } guard let name = pkginfo["name"] as? String else { - throw MunkiImportError.error(description: "pkginfo is missing value for 'name'") + throw MunkiImportError("pkginfo is missing value for 'name'") } guard let version = pkginfo["version"] as? String else { - throw MunkiImportError.error(description: "pkginfo is missing value for 'version'") + throw MunkiImportError("pkginfo is missing value for 'version'") } var pkginfoName = "\(name)-\(version)\(arch)\(pkginfoExt)" var pkginfoIdentifier = (destinationPath as NSString).appendingPathComponent(pkginfoName) @@ -124,12 +118,10 @@ func copyPkgInfoToRepo(_ repo: Repo, pkginfo: PlistDict, subdirectory: String = pkginfoName = "\(name)-\(version)\(arch)__\(index)\(pkginfoExt)" pkginfoIdentifier = (destinationPath as NSString).appendingPathComponent(pkginfoName) } - } catch let RepoError.error(description) { - throw MunkiImportError.error( - description: "Unable to get list of current pkgsinfo: \(description)") + } catch let error as RepoError { + throw MunkiImportError("Unable to get list of current pkgsinfo: \(error.description)") } catch { - throw MunkiImportError.error( - description: "Unexpected error: \(error)") + throw MunkiImportError("Unexpected error: \(error)") } do { try repo.put(pkginfoIdentifier, content: pkginfoData) @@ -159,9 +151,9 @@ func makeCatalogDB(_ repo: Repo) throws -> CatalogDatabase { let catalogItems: [PlistDict] do { allCatalog = try repo.get("catalogs/all") - } catch let RepoError.error(description) { + } catch let error as RepoError { throw CatalogError.readError( - description: "Could not read 'all' catalog: \(description)") + description: "Could not read 'all' catalog: \(error.description)") } catch { throw CatalogError.readError( description: "Unexpected error while attempting to read 'all' catalog: \(error)") @@ -373,8 +365,8 @@ func iconIsInRepo(_ repo: Repo, pkginfo: PlistDict) -> Bool { do { let iconList = try listItemsOfKind(repo, "icons") return iconList.contains(iconIdentifer) - } catch let RepoError.error(description) { - printStderr("Unable to get list of icons: \(description)") + } catch let error as RepoError { + printStderr("Unable to get list of icons: \(error.description)") return false } catch { printStderr("Unable to get list of icons: \(error)") @@ -386,7 +378,7 @@ func convertAndInstallIcon(_ repo: Repo, name: String, iconPath: String) throws // Convert icon file to png and save to repo icon path. // Returns resource path to icon in repo guard let tmpDir = TempDir.shared.makeTempDir() else { - throw MunkiImportError.error(description: "Could not create a temp directory") + throw MunkiImportError("Could not create a temp directory") } defer { try? FileManager.default.removeItem(atPath: tmpDir) @@ -398,16 +390,13 @@ func convertAndInstallIcon(_ repo: Repo, name: String, iconPath: String) throws do { try repo.put(iconIdentifier, fromFile: localPNGpath) return iconIdentifier - } catch let RepoError.error(description) { - throw MunkiImportError.error( - description: "Could not create icon \(pngName) in repo: \(description)") + } catch let error as RepoError { + throw MunkiImportError("Could not create icon \(pngName) in repo: \(error.description)") } catch { - throw MunkiImportError.error( - description: "Could not create icon \(pngName) in repo: \(error)") + throw MunkiImportError("Could not create icon \(pngName) in repo: \(error)") } } - throw MunkiImportError.error( - description: "Could not create icon \(pngName) in repo: failed to convert icon to png") + throw MunkiImportError("Could not create icon \(pngName) in repo: failed to convert icon to png") } func generatePNGFromStartOSInstallItem(_ repo: Repo, installerDMG: String, itemname: String) throws -> String { @@ -426,14 +415,11 @@ func generatePNGFromStartOSInstallItem(_ repo: Repo, installerDMG: String, itemn ) return repoIconIdentifier } - throw MunkiImportError.error( - description: "Unexpected error generating PNG from installer dmg") - } catch let DiskImageError.error(description) { - throw MunkiImportError.error( - description: "Could not mount installer dmg: \(description)") + throw MunkiImportError("Unexpected error generating PNG from installer dmg") + } catch let error as DiskImageError { + throw MunkiImportError("Could not mount installer dmg: \(error.description)") } catch { - throw MunkiImportError.error( - description: "Unexpected error generating PNG from app on disk image: \(error)") + throw MunkiImportError("Unexpected error generating PNG from app on disk image: \(error)") } } @@ -441,8 +427,7 @@ func generatePNGFromDMGitem(_ repo: Repo, dmgPath: String, pkginfo: PlistDict) t // Generates a product icon from a copy_from_dmg item // and uploads to the repo. Returns repo path to icon guard let itemname = pkginfo["name"] as? String else { - throw MunkiImportError.error( - description: "pkginfo is missing 'name'") + throw MunkiImportError("pkginfo is missing 'name'") } do { let mountpoint = try mountdmg(dmgPath) @@ -467,12 +452,10 @@ func generatePNGFromDMGitem(_ repo: Repo, dmgPath: String, pkginfo: PlistDict) t } // it's not an error if nothing we copy is an app return "" - } catch let DiskImageError.error(description) { - throw MunkiImportError.error( - description: "Could not mount installer dmg: \(description)") + } catch let error as DiskImageError { + throw MunkiImportError("Could not mount installer dmg: \(error.description)") } catch { - throw MunkiImportError.error( - description: "Unexpected error generating PNG from app on disk image: \(error)") + throw MunkiImportError("Unexpected error generating PNG from app on disk image: \(error)") } } @@ -482,7 +465,7 @@ func generatePNGsFromPkg(_ repo: Repo, itemPath: String, pkginfo: PlistDict, imp // itemPath can be a path to a disk image or to a package guard let itemname = pkginfo["name"] as? String else { // this should essentially never happen - throw MunkiImportError.error(description: "Pkginfo is missing 'name': \(pkginfo)") + throw MunkiImportError("Pkginfo is missing 'name': \(pkginfo)") } var iconPaths = [String]() var importedPaths = [String]() @@ -552,31 +535,25 @@ func copyIconToRepo(_ repo: Repo, iconPath: String) throws -> String { // need to first remove existing icon do { try repo.delete(repoIdentifier) - } catch let RepoError.error(description) { - throw MunkiImportError.error( - description: "Could not delete existing icon in repo: \(description)") + } catch let error as RepoError { + throw MunkiImportError("Could not delete existing icon in repo: \(error.description)") } catch { - throw MunkiImportError.error( - description: "Could not delete existing icon in repo: \(error)") + throw MunkiImportError("Could not delete existing icon in repo: \(error)") } } - } catch let RepoError.error(description) { - throw MunkiImportError.error( - description: "Could not get list of icons on repo: \(description)") + } catch let error as RepoError { + throw MunkiImportError("Could not get list of icons on repo: \(error.description)") } catch { - throw MunkiImportError.error( - description: "Could not get list of icons on repo: \(error)") + throw MunkiImportError("Could not get list of icons on repo: \(error)") } print("Copying \(iconName) to \(repoIdentifier)...") do { try repo.put(repoIdentifier, fromFile: iconPath) return repoIdentifier - } catch let RepoError.error(description) { - throw MunkiImportError.error( - description: "Could not copy icon to repo: \(description)") + } catch let error as RepoError { + throw MunkiImportError("Could not copy icon to repo: \(error.description)") } catch { - throw MunkiImportError.error( - description: "Could not copy icon to repo: \(error)") + throw MunkiImportError("Could not copy icon to repo: \(error)") } } @@ -600,8 +577,7 @@ func extractAndCopyIcon(_ repo: Repo, installerItem: String, pkginfo: PlistDict, let importedPaths = try generatePNGsFromPkg(repo, itemPath: installerItem, pkginfo: pkginfo, importMultiple: importMultiple) return importedPaths default: - throw MunkiImportError.error( - description: "Can't generate icons for installer_type \(installerType)") + throw MunkiImportError("Can't generate icons for installer_type \(installerType)") } return [String]() } diff --git a/code/cli/munki/shared/admin/pkginfolib.swift b/code/cli/munki/shared/admin/pkginfolib.swift index fa134114..9e2f3f8d 100644 --- a/code/cli/munki/shared/admin/pkginfolib.swift +++ b/code/cli/munki/shared/admin/pkginfolib.swift @@ -26,9 +26,7 @@ import Foundation -enum PkgInfoGenerationError: Error { - case error(description: String) -} +typealias PkgInfoGenerationError = MunkiError func pkginfoMetadata() -> PlistDict { // Helps us record information about the environment in which the pkginfo was @@ -162,8 +160,7 @@ func createPkgInfoForDragNDrop(_ mountpoint: String, options: PkginfoOptions) th } } guard !dragNDropItem.isEmpty else { - throw PkgInfoGenerationError.error( - description: "No application found on disk image.") + throw PkgInfoGenerationError("No application found on disk image.") } // check to see if item is a macOS installer and we can generate a startosinstall item let itempath = (mountpoint as NSString).appendingPathComponent(dragNDropItem) @@ -265,12 +262,11 @@ func createPkgInfoFromDmg(_ dmgpath: String, var mountpoint = "" do { mountpoint = try mountdmg(dmgpath, useExistingMounts: true) - } catch let DiskImageError.error(description) { - throw PkgInfoGenerationError.error( - description: "Could not mount \(dmgpath): \(description)") + } catch let error as DiskImageError { + throw PkgInfoGenerationError("Could not mount \(dmgpath): \(error.description)") } guard !mountpoint.isEmpty else { - throw PkgInfoGenerationError.error(description: "No mountpoint for \(dmgpath)") + throw PkgInfoGenerationError("No mountpoint for \(dmgpath)") } if let pkgname = options.pkg.pkgname { // a package was specified @@ -330,8 +326,7 @@ func makepkginfo(_ filepath: String?, if !installeritem.isEmpty { if !FileManager.default.fileExists(atPath: installeritem) { - throw PkgInfoGenerationError.error( - description: "File \(installeritem) does not exist") + throw PkgInfoGenerationError("File \(installeritem) does not exist") } // is this the mountpoint for a mounted disk image? @@ -347,8 +342,7 @@ func makepkginfo(_ filepath: String?, if hasValidDiskImageExt(installeritem) { pkginfo = try createPkgInfoFromDmg(installeritem, options: options) if pkginfo.isEmpty { - throw PkgInfoGenerationError.error( - description: "Could not find a supported installer item in \(installeritem)") + throw PkgInfoGenerationError("Could not find a supported installer item in \(installeritem)") } if dmgIsWritable(installeritem), options.hidden.printWarnings { printStderr("WARNING: \(installeritem) is a writable disk image. Checksum verification is not supported.") @@ -361,15 +355,13 @@ func makepkginfo(_ filepath: String?, } pkginfo = try createPkgInfoFromPkg(installeritem, options: options) if pkginfo.isEmpty { - throw PkgInfoGenerationError.error( - description: "\(installeritem) doesn't appear to be a valid installer item.") + throw PkgInfoGenerationError("\(installeritem) doesn't appear to be a valid installer item.") } if pathIsDirectory(installeritem), options.hidden.printWarnings { printStderr("WARNING: \(installeritem) is a bundle-style package!\nTo use it with Munki, you should encapsulate it in a disk image.") } } else { - throw PkgInfoGenerationError.error( - description: "\(installeritem) is not a supported installer item!") + throw PkgInfoGenerationError("\(installeritem) is not a supported installer item!") } // try to generate the correct item location if item was imported from @@ -387,8 +379,7 @@ func makepkginfo(_ filepath: String?, pkginfo["minimum_munki_version"] = "6.2" } if !FileManager.default.fileExists(atPath: uninstalleritem) { - throw PkgInfoGenerationError.error( - description: "No uninstaller item at \(uninstalleritem)") + throw PkgInfoGenerationError("No uninstaller item at \(uninstalleritem)") } // TODO: remove start of path if it refers to the Munki repo pkgs dir // for now, just the filename diff --git a/code/cli/munki/shared/dmgutils.swift b/code/cli/munki/shared/dmgutils.swift index 8d464d08..95249a40 100644 --- a/code/cli/munki/shared/dmgutils.swift +++ b/code/cli/munki/shared/dmgutils.swift @@ -20,9 +20,7 @@ import Foundation -enum DiskImageError: Error { - case error(description: String) -} +typealias DiskImageError = MunkiError func hdiutilData(arguments: [String], stdIn: String = "") throws -> PlistDict { // runs an hdiutil on a dmg and attempts to return a plist data structure @@ -32,8 +30,7 @@ func hdiutilData(arguments: [String], stdIn: String = "") throws -> PlistDict { } let results = runCLI("/usr/bin/hdiutil", arguments: hdiUtilArgs, stdIn: stdIn) if results.exitcode != 0 { - throw DiskImageError.error( - description: "hdiutil error \(results.error) with arguments \(arguments)") + throw DiskImageError("hdiutil error \(results.error) with arguments \(arguments)") } let (plistStr, _) = parseFirstPlist(fromString: results.output) if !plistStr.isEmpty { @@ -203,8 +200,7 @@ func mountdmg(_ dmgPath: String, } } } - throw DiskImageError.error( - description: "Could not get mountpoint info from results of hdiutil attach \(dmgName)") + throw DiskImageError("Could not get mountpoint info from results of hdiutil attach \(dmgName)") } func unmountdmg(_ mountpoint: String) { diff --git a/code/cli/munki/shared/errors.swift b/code/cli/munki/shared/errors.swift new file mode 100644 index 00000000..de4518ba --- /dev/null +++ b/code/cli/munki/shared/errors.swift @@ -0,0 +1,33 @@ +// +// errors.swift +// munki +// +// Created by Greg Neagle on 7/15/24. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +struct MunkiError: Error, CustomStringConvertible { + // General error class for errors + public internal(set) var message: String + + // Creates a new error with the given message. + public init(_ message: String) { + self.message = message + } + + public var description: String { + return message + } +} diff --git a/code/cli/munki/shared/munkirepo/FileRepo.swift b/code/cli/munki/shared/munkirepo/FileRepo.swift index 250f725e..2b3a5711 100644 --- a/code/cli/munki/shared/munkirepo/FileRepo.swift +++ b/code/cli/munki/shared/munkirepo/FileRepo.swift @@ -21,11 +21,7 @@ import Foundation import NetFS -// Base classes -enum RepoError: Error { - /// General error class for repo errors - case error(description: String) -} +typealias RepoError = MunkiError protocol Repo { // Defines methods all repo classes must implement @@ -178,12 +174,12 @@ class FileRepo: Repo { root = try mountShareURL(baseurl) weMountedTheRepo = true } catch is ShareMountError { - throw RepoError.error(description: "Error mounting repo file share") + throw RepoError("Error mounting repo file share") } } // does root dir exist now? if !pathIsDirectory(root) { - throw RepoError.error(description: "Repo path does not exist") + throw RepoError("Repo path does not exist") } } @@ -225,7 +221,7 @@ class FileRepo: Repo { if let data = FileManager.default.contents(atPath: repoFilePath) { return data } - throw RepoError.error(description: "Error getting contents from \(repoFilePath)") + throw RepoError("Error getting contents from \(repoFilePath)") } func get(_ identifier: String, toFile local_file_path: String) throws { @@ -258,7 +254,7 @@ class FileRepo: Repo { ) } if !((content as NSData).write(toFile: fullPath(identifier), atomically: true)) { - throw RepoError.error(description: "Write to \(identifier) failed") + throw RepoError("Write to \(identifier) failed") } } diff --git a/code/cli/munki/shared/munkirepo/RepoFactory.swift b/code/cli/munki/shared/munkirepo/RepoFactory.swift index fc0fdab1..d1d15635 100644 --- a/code/cli/munki/shared/munkirepo/RepoFactory.swift +++ b/code/cli/munki/shared/munkirepo/RepoFactory.swift @@ -28,6 +28,6 @@ func repoConnect(url: String, plugin: String = "FileRepo") throws -> Repo { case "GitFileRepo": return try GitFileRepo(url) default: - throw RepoError.error(description: "No repo plugin named \"\(plugin)\"") + throw RepoError("No repo plugin named \"\(plugin)\"") } } diff --git a/code/cli/munki/shared/osinstaller.swift b/code/cli/munki/shared/osinstaller.swift index 7c2e6bd6..182f54b4 100644 --- a/code/cli/munki/shared/osinstaller.swift +++ b/code/cli/munki/shared/osinstaller.swift @@ -69,14 +69,12 @@ func getInfoFromInstallMacOSApp(_ appPath: String) throws -> PlistDict { } catch { // nothing } - throw PkgInfoGenerationError.error( - description: "Could not get info from Contents/SharedSupport/InstallInfo.plist") + throw PkgInfoGenerationError("Could not get info from Contents/SharedSupport/InstallInfo.plist") } let sharedSupportDmg = (appPath as NSString).appendingPathComponent("Contents/SharedSupport/SharedSupport.dmg") if pathIsRegularFile(sharedSupportDmg) { guard let mountpoint = try? mountdmg(sharedSupportDmg) else { - throw PkgInfoGenerationError.error( - description: "Could not mount Contents/SharedSupport/SharedSupport.dmg") + throw PkgInfoGenerationError("Could not mount Contents/SharedSupport/SharedSupport.dmg") } let plistPath = (mountpoint as NSString).appendingPathComponent("com_apple_MobileAsset_MacSoftwareUpdate/com_apple_MobileAsset_MacSoftwareUpdate.xml") do { @@ -99,11 +97,10 @@ func getInfoFromInstallMacOSApp(_ appPath: String) throws -> PlistDict { unmountdmg(mountpoint) } catch { unmountdmg(mountpoint) - throw PkgInfoGenerationError.error(description: "Could not parse com_apple_MobileAsset_MacSoftwareUpdate.xml") + throw PkgInfoGenerationError("Could not parse com_apple_MobileAsset_MacSoftwareUpdate.xml") } } - throw PkgInfoGenerationError.error( - description: "Could not parse info from \((appPath as NSString).lastPathComponent)") + throw PkgInfoGenerationError("Could not parse info from \((appPath as NSString).lastPathComponent)") } func generateInstallableCondition(_ models: [String]) -> String { @@ -128,14 +125,12 @@ func makeStartOSInstallPkgInfo(mountpoint: String, item: String) throws -> Plist // image, using the startosinstall installation method let appPath = (mountpoint as NSString).appendingPathComponent(item) guard pathIsInstallMacOSApp(appPath) else { - throw PkgInfoGenerationError.error( - description: "Disk image item \(item) doesn't appear to be a macOS installer app") + throw PkgInfoGenerationError("Disk image item \(item) doesn't appear to be a macOS installer app") } let appName = (item as NSString).lastPathComponent let appInfo = try getInfoFromInstallMacOSApp(appPath) guard let version = appInfo["version"] as? String else { - throw PkgInfoGenerationError.error( - description: "Could not parse version from \(item)") + throw PkgInfoGenerationError("Could not parse version from \(item)") } let displayName = (appName as NSString).deletingPathExtension let munkiItemName = displayName.replacingOccurrences(of: " ", with: "_") @@ -191,8 +186,7 @@ func makeStageOSInstallerPkgInfo(_ appPath: String) throws -> PlistDict { let appName = (appPath as NSString).lastPathComponent let appInfo = try getInfoFromInstallMacOSApp(appPath) guard let version = appInfo["version"] as? String else { - throw PkgInfoGenerationError.error( - description: "Could not parse version from \(appName)") + throw PkgInfoGenerationError("Could not parse version from \(appName)") } let displayNameStaged = (appName as NSString).deletingPathExtension diff --git a/code/cli/munki/shared/pkgutils.swift b/code/cli/munki/shared/pkgutils.swift index 4d782cfa..1e37be4a 100644 --- a/code/cli/munki/shared/pkgutils.swift +++ b/code/cli/munki/shared/pkgutils.swift @@ -20,9 +20,7 @@ import Foundation -enum PackageParsingError: Error { - case error(description: String) -} +typealias PackageParsingError = MunkiError func getPkgRestartInfo(_ pkgpath: String) throws -> PlistDict { var installerinfo = PlistDict() @@ -33,8 +31,7 @@ func getPkgRestartInfo(_ pkgpath: String) throws -> PlistDict { "-plist"] ) if results.exitcode != 0 { - throw PackageParsingError.error( - description: "installer -query for \(pkgpath) failed: \(results.error)") + throw PackageParsingError("installer -query for \(pkgpath) failed: \(results.error)") } let (pliststr, _) = parseFirstPlist(fromString: results.output) if !pliststr.isEmpty { @@ -291,8 +288,7 @@ func getBundlePackageInfo(_ pkgpath: String) throws -> PlistDict { if !receiptarray.isEmpty { return ["receipts": receiptarray] } - throw PackageParsingError.error( - description: "Could not get receipt info from \(pkgpath)") + throw PackageParsingError("Could not get receipt info from \(pkgpath)") } // MARK: XML file functions (mostly for flat packages) @@ -519,8 +515,7 @@ func getFlatPackageInfo(_ pkgpath: String) throws -> PlistDict { if !info.isEmpty { return info } - throw PackageParsingError.error( - description: "Could not parse info from \(pkgpath):\n\(errors.joined(separator: "\n"))") + throw PackageParsingError("Could not parse info from \(pkgpath):\n\(errors.joined(separator: "\n"))") } // MARK: higher-level functions for getting pkg metadata