mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 19:24:32 +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/.
127 lines
5.9 KiB
Swift
127 lines
5.9 KiB
Swift
import Foundation
|
|
|
|
// Bridge to invoke Prole Tools environment wrapper for status/restart.
|
|
// Use the environment defined in env.sh and execute scripts via $PROLE_SERVICE
|
|
// e.g. "$PROLE_SERVICE/init_port_forwards.sh <cmd>" so we don't rely on PATH.
|
|
enum PFScriptBridge {
|
|
// Keep the last command description actually used, for display in the UI.
|
|
private static var lastInvocation: String = "$PROLE_SERVICE/init_port_forwards.sh"
|
|
|
|
/// Public accessor for display purposes. Shows the last invocation we used.
|
|
static func invocationDescription() -> String { lastInvocation }
|
|
|
|
@discardableResult
|
|
static func restart() -> (code: Int32, out: String, err: String) { runScript(arg: "restart") }
|
|
|
|
static func status() -> (code: Int32, out: String, err: String) { runScript(arg: "status") }
|
|
|
|
static func dbStatus() -> (code: Int32, out: String, err: String) {
|
|
runRawCommand(command: "kubectl cnpg status prole-db", description: "kubectl cnpg status prole-db")
|
|
}
|
|
|
|
static func cnpgStatus() -> (code: Int32, out: String, err: String) {
|
|
runRawCommand(command: "kubectl cnpg status prole-db | head -10", description: "kubectl cnpg status prole-db | head -10")
|
|
}
|
|
|
|
static func openbaoStatus() -> (code: Int32, out: String, err: String) {
|
|
// Check if the openbao pod is Ready in the default namespace (or wherever it's deployed)
|
|
// We look for any pod with label app=openbao and check its ready status
|
|
let cmd = "kubectl get pods -l app=openbao -o jsonpath='{.items[*].status.containerStatuses[*].ready}'"
|
|
return runRawCommand(command: cmd, description: "kubectl check openbao ready")
|
|
}
|
|
|
|
private static func runRawCommand(command: String, description: String) -> (code: Int32, out: String, err: String) {
|
|
lastInvocation = description
|
|
let p = Process()
|
|
p.executableURL = URL(fileURLWithPath: "/bin/bash")
|
|
p.arguments = ["-lc", command]
|
|
// Use home as default CWD
|
|
let env = ProcessInfo.processInfo.environment
|
|
let home = env["HOME"] ?? NSHomeDirectory()
|
|
let proleHomeEnv = env["PROLE_HOME"]
|
|
p.currentDirectoryURL = URL(fileURLWithPath: proleHomeEnv ?? home)
|
|
|
|
Logger.shared.info("invoking raw: \(description)")
|
|
|
|
let outPipe = Pipe(); let errPipe = Pipe()
|
|
p.standardOutput = outPipe
|
|
p.standardError = errPipe
|
|
do { try p.run() } catch {
|
|
let errStr = String(describing: error)
|
|
Logger.shared.error("spawn error: \(errStr)")
|
|
return (-1, "", errStr)
|
|
}
|
|
p.waitUntilExit()
|
|
let out = String(data: outPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
|
|
let err = String(data: errPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
|
|
let code = p.terminationStatus
|
|
|
|
return (code, out, err)
|
|
}
|
|
|
|
private static func runScript(arg: String) -> (code: Int32, out: String, err: String) {
|
|
let fm = FileManager.default
|
|
let env = ProcessInfo.processInfo.environment
|
|
let home = env["HOME"] ?? NSHomeDirectory()
|
|
let proleHomeEnv = env["PROLE_HOME"]
|
|
// Candidate locations for env.sh
|
|
let envCandidates: [String] = [
|
|
(proleHomeEnv != nil ? (proleHomeEnv! + "/env.sh") : nil),
|
|
home + "/dev/prole/env.sh",
|
|
].compactMap { $0 }
|
|
|
|
// Candidate locations for the script if we can't use env.sh
|
|
let scriptCandidates: [String] = [
|
|
(proleHomeEnv != nil ? (proleHomeEnv! + "/etc/init_port_forwards.sh") : nil),
|
|
home + "/dev/prole/etc/init_port_forwards.sh",
|
|
].compactMap { $0 }
|
|
|
|
// Build the command using the best available method.
|
|
var command: String
|
|
var cwd: String = proleHomeEnv ?? home
|
|
if let envPath = envCandidates.first(where: { fm.fileExists(atPath: $0) }) {
|
|
// Use env.sh to populate PROLE_* and invoke via $PROLE_SERVICE
|
|
command = "export PROLE_HOME=\"${PROLE_HOME:-$HOME}\"; . \"\(envPath)\"; \"${PROLE_SERVICE}/init_port_forwards.sh\" \(arg)"
|
|
lastInvocation = ". \(envPath) && $PROLE_SERVICE/init_port_forwards.sh \(arg)"
|
|
} else if let scriptPath = scriptCandidates.first(where: { fm.fileExists(atPath: $0) }) {
|
|
// Fallback: directly execute the repo script
|
|
command = "\"\(scriptPath)\" \(arg)"
|
|
lastInvocation = scriptPath + " \(arg)"
|
|
} else {
|
|
// Nothing found; construct a failing but explicit command for diagnostics
|
|
command = "echo '[prole-tools] env.sh and init_port_forwards.sh not found' 1>&2; exit 127"
|
|
lastInvocation = "<not found> init_port_forwards.sh \(arg)"
|
|
}
|
|
|
|
let p = Process()
|
|
p.executableURL = URL(fileURLWithPath: "/bin/bash")
|
|
p.arguments = ["-lc", command]
|
|
p.currentDirectoryURL = URL(fileURLWithPath: cwd)
|
|
Logger.shared.info("invoking: \(lastInvocation)")
|
|
|
|
let outPipe = Pipe(); let errPipe = Pipe()
|
|
p.standardOutput = outPipe
|
|
p.standardError = errPipe
|
|
do { try p.run() } catch {
|
|
let errStr = String(describing: error)
|
|
Logger.shared.error("spawn error: \(errStr)")
|
|
return (-1, "", errStr)
|
|
}
|
|
p.waitUntilExit()
|
|
let out = String(data: outPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
|
|
let err = String(data: errPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
|
|
let code = p.terminationStatus
|
|
|
|
// Combine to match UI exactly
|
|
var combined = out
|
|
if !err.isEmpty { combined += (combined.isEmpty ? "" : "\n") + err }
|
|
let trimmedCombined = combined.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
if trimmedCombined.isEmpty {
|
|
Logger.shared.info("exit code: \(code); (no output)")
|
|
} else {
|
|
Logger.shared.info("output (exit=\(code)):\n\(combined)")
|
|
}
|
|
return (code, out, err)
|
|
}
|
|
}
|