manifestutil: implement more subcommands

This commit is contained in:
Greg Neagle
2025-04-14 11:06:01 -07:00
parent e2d137ef5d
commit 2dbc418f7d
4 changed files with 202 additions and 8 deletions

View File

@@ -124,7 +124,7 @@ extension ManifestUtil {
}
}
/// Prints contents of a given manifest, expanding inlcuded maniifests
/// Prints contents of a given manifest, expanding included maniifests
extension ManifestUtil {
struct ExpandIncludedManifests: ParsableCommand {
static var configuration = CommandConfiguration(

View File

@@ -21,13 +21,13 @@
import ArgumentParser
import Foundation
func getManifestNames(repo: Repo) throws -> [String] {
func getManifestNames(repo: Repo) -> [String]? {
do {
let manifestNames = try repo.list("manifests")
return manifestNames.sorted()
} catch {
printStderr("Could not retrieve manifests: \(error.localizedDescription)")
throw ExitCode(-1)
return nil
}
}
@@ -44,7 +44,9 @@ extension ManifestUtil {
func run() throws {
let repo = try connectToRepo()
let manifestNames = try getManifestNames(repo: repo)
guard let manifestNames = getManifestNames(repo: repo) else {
return
}
if globString.isEmpty {
print(manifestNames.joined(separator: "\n"))
} else {

View File

@@ -0,0 +1,192 @@
//
// MUmanifestFileOperations.swift
// manifestutil
//
// Created by Greg Neagle on 4/14/25.
//
// Copyright 2024-2025 Greg Neagle.
//
// 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 ArgumentParser
import Foundation
/// Saves a manifest
func saveManifest(repo: Repo,
manifest: PlistDict,
name: String,
overwrite: Bool = false) -> Bool
{
if !overwrite {
let existingManifestNames = getManifestNames(repo: repo) ?? []
if existingManifestNames.contains(name) {
printStderr("Manifest '\(name)' already exists")
return false
}
}
do {
let data = try plistToData(manifest)
try repo.put("manifests/\(name)", content: data)
return true
} catch {
printStderr("Saving \(name) failed: \(error.localizedDescription)")
return false
}
}
/// Copies or renames a manifest.
/// (To rename we make a copy under the new name, then delete the original)
func copyOrRenameManifest(repo: Repo, sourceName: String, destinationName: String, overwrite: Bool = false, deleteSource: Bool = false) -> Bool {
if !overwrite {
let existingManifestNames = getManifestNames(repo: repo) ?? []
if existingManifestNames.contains(destinationName) {
printStderr("Manifest '\(destinationName)' already exists")
return false
}
}
do {
let data = try repo.get("manifests/\(sourceName)")
try repo.put("manifests/\(destinationName)", content: data)
if deleteSource {
try repo.delete("manifests/\(sourceName)")
}
return true
} catch {
printStderr("Renaming \(sourceName) to \(destinationName) failed: \(error.localizedDescription)")
return false
}
}
/// Creates a new, empty manifest
func newManifest(repo: Repo, name: String) -> Bool {
let manifest = [
"catalogs": [String](),
"included_manifests": [String](),
"managed_installs": [String](),
"managed_uninstalls": [String](),
]
return saveManifest(repo: repo, manifest: manifest, name: name)
}
/// Deletes a manifest
func deleteManifest(repo: Repo, name: String) -> Bool {
let existingManifestNames = getManifestNames(repo: repo) ?? []
if !existingManifestNames.contains(name) {
printStderr("No such manifest: \(name)")
return false
}
do {
try repo.delete("manifests/\(name)")
return true
} catch {
printStderr("Deleting \(name) failed: \(error.localizedDescription)")
return false
}
}
/// Create a new empty manifest
extension ManifestUtil {
struct NewManifest: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Creates a new empty manifest")
@Argument(help: ArgumentHelp(
"Name for the newly-created manifest",
valueName: "manifest-name"
))
var manifestName: String
func run() throws {
let repo = try connectToRepo()
_ = newManifest(repo: repo, name: manifestName)
}
}
}
/// Copy a manifest
extension ManifestUtil {
struct CopyManifest: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Copies a manifest")
@Argument(help: ArgumentHelp(
"Name of the source manifest",
valueName: "source-name"
))
var sourceName: String
@Argument(help: ArgumentHelp(
"Name of the destination manifest",
valueName: "destination-name"
))
var destinationName: String
func run() throws {
let repo = try connectToRepo()
_ = copyOrRenameManifest(
repo: repo,
sourceName: sourceName,
destinationName: destinationName
)
}
}
}
/// Rename a manifest
extension ManifestUtil {
struct RenameManifest: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Renames a manifest")
@Argument(help: ArgumentHelp(
"Name of the source manifest",
valueName: "source-name"
))
var sourceName: String
@Argument(help: ArgumentHelp(
"Name of the destination manifest",
valueName: "destination-name"
))
var destinationName: String
func run() throws {
let repo = try connectToRepo()
_ = copyOrRenameManifest(
repo: repo,
sourceName: sourceName,
destinationName: destinationName,
deleteSource: true
)
}
}
}
/// Delete a manifest
extension ManifestUtil {
struct DeleteManifest: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Deletes a manifest")
@Argument(help: ArgumentHelp(
"Name of the manifest to be deleted",
valueName: "manifest-name"
))
var manifestName: String
func run() throws {
let repo = try connectToRepo()
_ = deleteManifest(repo: repo, name: manifestName)
}
}
}

View File

@@ -60,10 +60,10 @@ struct ManifestUtil: AsyncParsableCommand {
DisplayManifest.self,
ExpandIncludedManifests.self,
// Find.self,
// NewManifest.self,
// CopyManifest.self,
// RenameManifest.self,
// DeleteManifest.self,
NewManifest.self,
CopyManifest.self,
RenameManifest.self,
DeleteManifest.self,
// RefreshCache.self,
Exit.self,
Help.self,