manifestutil: swiftformat fixes; do recursion when expanding included manifests

This commit is contained in:
Greg Neagle
2025-04-14 09:26:26 -07:00
parent 63e6442a77
commit e2d137ef5d
4 changed files with 99 additions and 41 deletions
+8 -8
View File
@@ -26,7 +26,7 @@ func getCatalogNames(repo: Repo) throws -> [String] {
do {
let catalogNames = try repo.list("catalogs")
return catalogNames.sorted()
} catch let error {
} catch {
printStderr("Could not retrieve catalogs: \(error.localizedDescription)")
throw ExitCode(-1)
}
@@ -37,7 +37,7 @@ extension ManifestUtil {
struct ListCatalogs: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Lists available catalogs in Munki repo.")
func run() throws {
let repo = try connectToRepo()
let catalogNames = try getCatalogNames(repo: repo)
@@ -57,7 +57,7 @@ func getInstallerItemNames(repo: Repo, catalogs: [String]) throws -> [String] {
if let catalog = try readPlist(fromData: data) as? [PlistDict] {
let itemNames = catalog.filter {
($0["update_for"] as? String ?? "").isEmpty &&
!(($0["name"] as? String ?? "").isEmpty)
!(($0["name"] as? String ?? "").isEmpty)
}.map {
$0["name"] as? String ?? ""
}
@@ -65,7 +65,7 @@ func getInstallerItemNames(repo: Repo, catalogs: [String]) throws -> [String] {
} else {
printStderr("Catalog \(catalogName) is malformed")
}
} catch let error {
} catch {
printStderr("Could not retrieve catalog: \(catalogName): \(error.localizedDescription)")
}
}
@@ -78,23 +78,23 @@ extension ManifestUtil {
struct ListCatalogItems: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Lists items in the given catalogs.")
@Argument(help: ArgumentHelp(
"Catalog name",
valueName: "catalog-name"
))
var catalogNames: [String] = []
func validate() throws {
if catalogNames.isEmpty {
throw ValidationError("At least one catalog name must be provided.")
}
}
func run() throws {
let repo = try connectToRepo()
let avaliableCatalogs = try getCatalogNames(repo: repo)
for catalogName in catalogNames {
if !avaliableCatalogs.contains(catalogName) {
printStderr("Catalog '\(catalogName)' does not exist.")
@@ -46,7 +46,7 @@ func printPlistItem(_ label: String, _ value: Any?, indent: Int = 0) {
if !label.isEmpty {
print("\(INDENTSPACE)\(label):")
}
for subkey in dict.keys.sorted() {
for subkey in dict.keys.sorted() {
printPlistItem(subkey, dict[subkey], indent: indent + 1)
}
} else {
@@ -66,25 +66,84 @@ func printPlist(_ plist: PlistDict) {
}
}
/// Recursive expansion of included manifests.
/// Input: a "normal" manifest
/// Output: a manifest with the included\_manifest names replaced with dictionaries containing
/// the actual content of the included manifestd
func expandIncludedManifests(repo: Repo, manifest: PlistDict) -> PlistDict {
// No infinite loop checking! Be wary!
var expandedManifest = manifest
if let includedManifests = manifest["included_manifests"] as? [String] {
var expandedIncludedManifests = [PlistDict]()
for name in includedManifests {
if var includedManifest = getManifest(repo: repo, name: name) {
includedManifest = expandIncludedManifests(repo: repo, manifest: includedManifest)
expandedIncludedManifests.append([name: includedManifest])
}
}
expandedManifest["included_manifests"] = expandedIncludedManifests
}
return expandedManifest
}
/// Prints contents of a given manifest
extension ManifestUtil {
struct DisplayManifest: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Displays a manifest.")
@Flag(name: [.long, .customShort("X")],
@Flag(name: .shortAndLong,
help: "Expand included manifests.")
var expand: Bool = false
@Flag(name: .shortAndLong,
help: "Display manifest in XML format.")
var xml: Bool = false
@Argument(help: ArgumentHelp(
"Prints the contents of the specified manifest",
valueName: "manifest-name"
))
var manifestName: String
func run() throws {
let repo = try connectToRepo()
if let manifest = getManifest(repo: repo, name: manifestName) {
if var manifest = getManifest(repo: repo, name: manifestName) {
if expand {
manifest = expandIncludedManifests(repo: repo, manifest: manifest)
}
if xml {
print((try? plistToString(manifest)) ?? "")
} else {
printPlist(manifest)
}
} else {
printStderr("Manifest data was malformed or not found.")
}
}
}
}
/// Prints contents of a given manifest, expanding inlcuded maniifests
extension ManifestUtil {
struct ExpandIncludedManifests: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Displays a manifest, expanding included manifests.")
@Flag(name: .shortAndLong,
help: "Display manifest in XML format.")
var xml: Bool = false
@Argument(help: ArgumentHelp(
"Prints the contents of the specified manifest",
valueName: "manifest-name"
))
var manifestName: String
func run() throws {
let repo = try connectToRepo()
if var manifest = getManifest(repo: repo, name: manifestName) {
manifest = expandIncludedManifests(repo: repo, manifest: manifest)
if xml {
print((try? plistToString(manifest)) ?? "")
} else {
@@ -25,7 +25,7 @@ func getManifestNames(repo: Repo) throws -> [String] {
do {
let manifestNames = try repo.list("manifests")
return manifestNames.sorted()
} catch let error {
} catch {
printStderr("Could not retrieve manifests: \(error.localizedDescription)")
throw ExitCode(-1)
}
@@ -35,13 +35,13 @@ extension ManifestUtil {
struct ListManifests: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Lists available manifest in Munki repo.")
@Argument(help: ArgumentHelp(
"String to match manifest names similar to file name globbing. To avoid the shell expanding wildcards, wrap the string in quotes.",
valueName: "match-string"
))
var globString: String = ""
func run() throws {
let repo = try connectToRepo()
let manifestNames = try getManifestNames(repo: repo)
+23 -24
View File
@@ -47,28 +47,29 @@ struct ManifestUtil: AsyncParsableCommand {
commandName: "manifestutil",
abstract: "A utility for working with Munki manifests.",
subcommands: [
//AddPkg.self,
//AddCatalog.self,
//AddIncludedManifest.self,
//RemovePkg.self,
//MoveInstallToUninstall.self,
//RemoveCatalog.self,
//RemoveIncludedManifest.self,
// AddPkg.self,
// AddCatalog.self,
// AddIncludedManifest.self,
// RemovePkg.self,
// MoveInstallToUninstall.self,
// RemoveCatalog.self,
// RemoveIncludedManifest.self,
ListCatalogs.self,
ListCatalogItems.self,
ListManifests.self,
DisplayManifest.self,
//ExpandIncludedManifests.self,
//Find.self,
//NewManifest.self,
//CopyManifest.self,
//RenameManifest.self,
//DeleteManifest.self,
//RefreshCache.self,
ExpandIncludedManifests.self,
// Find.self,
// NewManifest.self,
// CopyManifest.self,
// RenameManifest.self,
// DeleteManifest.self,
// RefreshCache.self,
Exit.self,
Help.self,
Configure.self,
Version.self],
Version.self,
],
defaultSubcommand: RunInteractive.self
)
}
@@ -77,7 +78,7 @@ extension ManifestUtil {
struct Exit: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Exits this utility when in interactive mode.")
func run() throws {
throw ExitCode(0)
}
@@ -87,7 +88,7 @@ extension ManifestUtil {
extension ManifestUtil {
struct Help: ParsableCommand {
static var configuration = CommandConfiguration(abstract: "Show help information.")
func run() throws {
print(ManifestUtil.helpMessage())
}
@@ -98,11 +99,11 @@ extension ManifestUtil {
struct Configure: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Show and edit configuration for this tool.")
func run() throws {
let promptList = [
("repo_url", "Repo URL (example: afp://munki.example.com/repo)"),
("plugin", "Munki repo plugin (defaults to FileRepo)")
("plugin", "Munki repo plugin (defaults to FileRepo)"),
]
configure(promptList: promptList)
}
@@ -112,7 +113,7 @@ extension ManifestUtil {
extension ManifestUtil {
struct Version: ParsableCommand {
static var configuration = CommandConfiguration(abstract: "Print version information.")
func run() throws {
print(CLI_TOOLS_VERSION)
}
@@ -123,9 +124,7 @@ extension ManifestUtil {
struct RunInteractive: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Runs this utility in interactive mode.")
func run() throws {
}
func run() throws {}
}
}