mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 17:34:31 +00:00
- Moved prole-tools-app to prole-app at the project root to make it self-contained for transition to its own repository. - Created prole-tools-app/dist/ directory to host build artifacts. - Generated distribution artifacts (Prole Tools.app and Prole Tools.zip) using prole-app/build.sh package. - Checked in the generated artifacts to prole-tools-app/dist/ (bypassing .gitignore for temporary release process). Changes Summary • Renamed directory prole-tools-app/ to prole-app/. • Populated prole-tools-app/dist/ with the latest build output from prole-app/build.sh. • Staged all changes, including the forced addition of ignored artifacts in prole-tools-app/dist/.
91 lines
4.0 KiB
Swift
91 lines
4.0 KiB
Swift
import Foundation
|
|
|
|
// Lightweight helper to manage the user LaunchAgent that runs kubectl port-forwards.
|
|
// This replaces the in-app PortForwardManager supervision.
|
|
final class LaunchAgentManager {
|
|
// Filenames/paths
|
|
private let label = "org.prole.prole-db.kpf-dev"
|
|
private var plistURL: URL {
|
|
let home = FileManager.default.homeDirectoryForCurrentUser
|
|
return home.appendingPathComponent("Library/LaunchAgents/\(label).plist")
|
|
}
|
|
// Deprecated: helper script is no longer bundled. All shell commands must go via $PROLE_HOME/env.sh.
|
|
// Leaving the placeholder to avoid breaking callers; it is unused now.
|
|
private var helperScriptURL: URL {
|
|
let home = FileManager.default.homeDirectoryForCurrentUser
|
|
return home.appendingPathComponent("Library/Application Support/Prole/bin/prole-kpf.sh")
|
|
}
|
|
|
|
// Key that stores the list of commands inside the plist (array of strings)
|
|
private let commandsKey = "ProleCommands"
|
|
|
|
// Read commands from the LaunchAgent plist. Returns empty if missing.
|
|
func readCommands() -> [String] {
|
|
guard let data = try? Data(contentsOf: plistURL) else { return [] }
|
|
var format = PropertyListSerialization.PropertyListFormat.xml
|
|
guard let obj = try? PropertyListSerialization.propertyList(from: data, options: [], format: &format),
|
|
let dict = obj as? [String: Any],
|
|
let cmds = dict[commandsKey] as? [String] else {
|
|
return []
|
|
}
|
|
return cmds
|
|
}
|
|
|
|
// Write commands back to the plist, preserving other keys if present.
|
|
func writeCommands(_ commands: [String]) {
|
|
var dict: [String: Any] = [:]
|
|
if let data = try? Data(contentsOf: plistURL),
|
|
let obj = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil),
|
|
let existing = obj as? [String: Any] {
|
|
dict = existing
|
|
}
|
|
dict[commandsKey] = commands
|
|
if let out = try? PropertyListSerialization.data(fromPropertyList: dict, format: .xml, options: 0) {
|
|
// Ensure parent directory exists
|
|
try? FileManager.default.createDirectory(at: plistURL.deletingLastPathComponent(), withIntermediateDirectories: true)
|
|
try? out.write(to: plistURL)
|
|
}
|
|
}
|
|
|
|
// Reload the LaunchAgent: try kickstart; if not present, bootstrap then kickstart.
|
|
func resetAgent() {
|
|
let uid = getuid()
|
|
let domainTarget = "gui/\(uid)/\(label)"
|
|
|
|
// Try kickstart first (reload)
|
|
let ks = run("/bin/launchctl", ["kickstart", "-k", domainTarget])
|
|
if ks.exitCode == 0 { return }
|
|
|
|
// If kickstart failed, try bootout then bootstrap, then kickstart again
|
|
_ = run("/bin/launchctl", ["bootout", "gui/\(uid)", domainTarget])
|
|
// bootstrap requires path to plist
|
|
_ = run("/bin/launchctl", ["bootstrap", "gui/\(uid)", plistURL.path])
|
|
_ = run("/bin/launchctl", ["kickstart", "-k", domainTarget])
|
|
}
|
|
|
|
// Deprecated: No-op. We no longer bundle or copy any init_port_forwards.sh; app uses $PROLE_HOME/env.sh.
|
|
func ensureHelperScript() { /* no-op */ }
|
|
|
|
static let defaultHelperScript = ""
|
|
|
|
// MARK: - Helpers
|
|
@discardableResult
|
|
private func run(_ path: String, _ args: [String]) -> (exitCode: Int32, out: String, err: String) {
|
|
let p = Process()
|
|
p.executableURL = URL(fileURLWithPath: path)
|
|
p.arguments = args
|
|
let outPipe = Pipe(); let errPipe = Pipe()
|
|
p.standardOutput = outPipe
|
|
p.standardError = errPipe
|
|
do { try p.run() } catch {
|
|
return (exitCode: -1, out: "", err: String(describing: error))
|
|
}
|
|
p.waitUntilExit()
|
|
let outData = outPipe.fileHandleForReading.readDataToEndOfFile()
|
|
let errData = errPipe.fileHandleForReading.readDataToEndOfFile()
|
|
let outStr = String(data: outData, encoding: .utf8) ?? ""
|
|
let errStr = String(data: errData, encoding: .utf8) ?? ""
|
|
return (p.terminationStatus, outStr, errStr)
|
|
}
|
|
}
|