diff --git a/InContext/Helper/Model/SiteModel.swift b/InContext/Helper/Model/SiteModel.swift index 71b1a52..50540d4 100644 --- a/InContext/Helper/Model/SiteModel.swift +++ b/InContext/Helper/Model/SiteModel.swift @@ -49,10 +49,6 @@ class SiteModel: ObservableObject, Identifiable { return site.favorites } - var actions: [Site.Action] { - return site.actions - } - init(rootURL: URL) { self.rootURL = rootURL // TODO: Guard the configuration loading. @@ -61,13 +57,6 @@ class SiteModel: ObservableObject, Identifiable { self.server = Server(site: site, tracker: tracker) } - func run(_ action: Site.Action) { - Task { - let runner = ActionRunner(site: site, action: action, tracker: self.tracker) - runner.run() - } - } - func start() { dispatchPrecondition(condition: .onQueue(.main)) self.task = Task(priority: .medium) { diff --git a/InContext/Helper/Views/ActionsMenu.swift b/InContext/Helper/Views/ActionsMenu.swift deleted file mode 100644 index 9600a35..0000000 --- a/InContext/Helper/Views/ActionsMenu.swift +++ /dev/null @@ -1,47 +0,0 @@ -// MIT License -// -// Copyright (c) 2016-2024 Jason Morley -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import SwiftUI - -struct ActionsMenu: View { - - @ObservedObject var siteModel: SiteModel - - var body: some View { - Menu { - if siteModel.actions.isEmpty { - Text("None") - } else { - ForEach(siteModel.actions) { action in - Button { - siteModel.run(action) - } label: { - Text(action.name) - } - } - } - } label: { - Text("Actions") - } - } - -} diff --git a/InContext/Helper/Views/LogView.swift b/InContext/Helper/Views/LogView.swift index 5f22bc3..2ff65e5 100644 --- a/InContext/Helper/Views/LogView.swift +++ b/InContext/Helper/Views/LogView.swift @@ -106,19 +106,6 @@ struct LogView: View { } } - ToolbarItem { - Menu { - ForEach(siteModel.actions) { action in - Button(action.name) { - siteModel.run(action) - } - } - } label: { - Label("Actions", systemImage: "play") - } - .disabled(siteModel.actions.isEmpty) - } - } } diff --git a/InContext/Helper/Views/SiteMenu.swift b/InContext/Helper/Views/SiteMenu.swift index 6d1fb0a..afbab09 100644 --- a/InContext/Helper/Views/SiteMenu.swift +++ b/InContext/Helper/Views/SiteMenu.swift @@ -39,7 +39,6 @@ struct SiteMenu: View { } } Divider() - ActionsMenu(siteModel: siteModel) FavoritesMenu(siteModel: siteModel) Divider() Button("Logs...") { diff --git a/InContext/InContext.xcodeproj/project.pbxproj b/InContext/InContext.xcodeproj/project.pbxproj index bdb1865..9baf571 100644 --- a/InContext/InContext.xcodeproj/project.pbxproj +++ b/InContext/InContext.xcodeproj/project.pbxproj @@ -41,7 +41,6 @@ D8A739BA2AA6627500946EED /* SettingsMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A739B92AA6627500946EED /* SettingsMenu.swift */; }; D8AD37AF2AA69FDF0006555F /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8AD37AE2AA69FDF0006555F /* Event.swift */; }; D8E4C1212BC9F81000B09A78 /* Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E4C1202BC9F77300B09A78 /* Main.swift */; }; - D8E592242AB3A840000EE676 /* ActionsMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E592232AB3A840000EE676 /* ActionsMenu.swift */; }; D8E592262AB3A8C3000EE676 /* FavoritesMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E592252AB3A8C3000EE676 /* FavoritesMenu.swift */; }; D8F672782AC8988D0073900D /* TaskRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F672772AC8988D0073900D /* TaskRow.swift */; }; D8F6727A2AC898B00073900D /* SessionFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F672792AC898B00073900D /* SessionFooter.swift */; }; @@ -113,7 +112,6 @@ D8A739B92AA6627500946EED /* SettingsMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsMenu.swift; sourceTree = ""; }; D8AD37AE2AA69FDF0006555F /* Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = ""; }; D8E4C1202BC9F77300B09A78 /* Main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Main.swift; sourceTree = ""; }; - D8E592232AB3A840000EE676 /* ActionsMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionsMenu.swift; sourceTree = ""; }; D8E592252AB3A8C3000EE676 /* FavoritesMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesMenu.swift; sourceTree = ""; }; D8F672772AC8988D0073900D /* TaskRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskRow.swift; sourceTree = ""; }; D8F672792AC898B00073900D /* SessionFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionFooter.swift; sourceTree = ""; }; @@ -173,7 +171,6 @@ D8121A762AA05DB300EEDF5B /* Views */ = { isa = PBXGroup; children = ( - D8E592232AB3A840000EE676 /* ActionsMenu.swift */, D8E592252AB3A8C3000EE676 /* FavoritesMenu.swift */, D8A739B32AA660F400946EED /* LogView.swift */, D8A739B52AA6611E00946EED /* LogWindow.swift */, @@ -465,7 +462,6 @@ buildActionMask = 2147483647; files = ( D8A739B62AA6611E00946EED /* LogWindow.swift in Sources */, - D8E592242AB3A840000EE676 /* ActionsMenu.swift in Sources */, D80E4FD12AA7AD5300FD4BB5 /* HelperTracker.swift in Sources */, D8A739BA2AA6627500946EED /* SettingsMenu.swift in Sources */, D80E4FCF2AA7AD3300FD4BB5 /* HelperSession.swift in Sources */, diff --git a/Sources/InContextCommand/Commands/Command.swift b/Sources/InContextCommand/Commands/Command.swift index b88364a..ae2cf3d 100644 --- a/Sources/InContextCommand/Commands/Command.swift +++ b/Sources/InContextCommand/Commands/Command.swift @@ -49,7 +49,6 @@ public struct Command: AsyncParsableCommand { Build.self, Clean.self, Serve.self, - Run.self, ]) public init() { diff --git a/Sources/InContextCommand/Commands/Run.swift b/Sources/InContextCommand/Commands/Run.swift deleted file mode 100644 index 0297dd9..0000000 --- a/Sources/InContextCommand/Commands/Run.swift +++ /dev/null @@ -1,47 +0,0 @@ -// MIT License -// -// Copyright (c) 2016-2024 Jason Morley -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import Foundation - -import ArgumentParser -import InContextCore - -struct Run: AsyncParsableCommand { - - static var configuration = CommandConfiguration(commandName: "run", - abstract: "Run a task.") - - @OptionGroup var options: Options - - @Argument(help: "Task to run.") - var task: String - - mutating func run() async throws { - let site = try options.resolveSite() - guard let action = site.actions.first(where: { $0.id == task }) else { - throw InContextError.internalInconsistency("Unknown task '\(task)'.") - } - let runner = ActionRunner(site: site, action: action, tracker: LoggingTracker()) - runner.run() - } - -} diff --git a/Sources/InContextCore/ActionRunner.swift b/Sources/InContextCore/ActionRunner.swift deleted file mode 100644 index efa7060..0000000 --- a/Sources/InContextCore/ActionRunner.swift +++ /dev/null @@ -1,92 +0,0 @@ -// MIT License -// -// Copyright (c) 2016-2024 Jason Morley -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import Foundation - -public class ActionRunner { - - let site: Site - let action: Site.Action - let tracker: Tracker - - public init(site: Site, action: Site.Action, tracker: Tracker) { - self.site = site - self.action = action - self.tracker = tracker - } - - static func run(site: Site, action: Site.Action, logger: Logger) throws { - logger.debug(action.run.trimmingCharacters(in: .whitespacesAndNewlines)) - - let process = Process() - let input = Pipe() - let output = Pipe() - process.currentDirectoryURL = site.rootURL - process.launchPath = "/bin/bash" - process.arguments = [] - process.standardInput = input - process.standardOutput = output - process.launch() - - let outputReader = Task { - guard let data = try output.fileHandleForReading.readToEnd(), - let result = String(data: data, encoding: .utf8) - else { - throw InContextError.internalInconsistency("Failed to read data!") - } - for line in result.split(separator: /\n+/) { - guard !line.isEmpty else { - continue - } - logger.info(String(line)) - } - } - - guard let command = action.run.data(using: .utf8) else { - throw InContextError.internalInconsistency("Failed to encode action script as input.") - } - - try input.fileHandleForWriting.write(contentsOf: command) - try input.fileHandleForWriting.close() - - process.waitUntilExit() - try outputReader.awaitResult() - - guard process.terminationStatus == 0 else { - throw InContextError.internalInconsistency("Failed with exit code \(process.terminationStatus).") - } - } - - public func run() { - do { - try tracker.withSession(type: .action, name: action.name) { session in - try session.withTask("Running action '\(action.name)'...") { task in - try Self.run(site: site, action: action, logger: task) - } - - } - } catch { - print("Task failed with error \(error).") - } - } - -} diff --git a/Sources/InContextCore/Site.swift b/Sources/InContextCore/Site.swift index e7cdb55..2c31e79 100644 --- a/Sources/InContextCore/Site.swift +++ b/Sources/InContextCore/Site.swift @@ -40,20 +40,6 @@ public struct Site { public let title: String } - public struct Action: Identifiable { - - public let id: String - public let name: String - public let run: String - - init(id: String, name: String? = nil, run: String) { - self.id = id - self.name = name ?? id - self.run = run - } - - } - private static let importers: [any Importer] = [ CopyImporter(), IgnoreImporter(), @@ -98,12 +84,6 @@ public struct Site { } } - public var actions: [Action] { - return settings.actions.map { name, action in - return Action(id: name, name: action.name, run: action.run) - } - } - public init(rootURL: URL) throws { self.rootURL = rootURL self.settingsURL = rootURL.appendingPathComponent("site.yaml")