feat: migrate Mac mini services into Reyna CLI
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import Foundation
|
||||
|
||||
public struct PythonRuntime: Equatable {
|
||||
public let workingDirectory: URL
|
||||
public let python: URL
|
||||
}
|
||||
|
||||
public func parsePythonRuntimeConfig(_ content: String) -> [String: String] {
|
||||
var values: [String: String] = [:]
|
||||
for rawLine in content.components(separatedBy: .newlines) {
|
||||
let line = rawLine.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard !line.isEmpty, !line.hasPrefix("#") else { continue }
|
||||
let parts = line.split(separator: "=", maxSplits: 1).map(String.init)
|
||||
guard parts.count == 2 else { continue }
|
||||
let key = parts[0].trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
var value = parts[1].trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if value.count >= 2,
|
||||
((value.hasPrefix("\"") && value.hasSuffix("\"")) || (value.hasPrefix("'") && value.hasSuffix("'"))) {
|
||||
value.removeFirst()
|
||||
value.removeLast()
|
||||
}
|
||||
guard key == "REYNA_CLI_DIR" || key == "REYNA_CLI_PYTHON" else { continue }
|
||||
values[key] = value
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
public func pythonRuntimeConfig(homeDirectory: URL = FileManager.default.homeDirectoryForCurrentUser) -> [String: String] {
|
||||
let paths = [
|
||||
homeDirectory.appendingPathComponent(".reyna-cli.env"),
|
||||
homeDirectory.appendingPathComponent(".config/reyna-cli/env"),
|
||||
]
|
||||
var result: [String: String] = [:]
|
||||
for path in paths {
|
||||
guard let content = try? String(contentsOf: path, encoding: .utf8) else { continue }
|
||||
result.merge(parsePythonRuntimeConfig(content)) { _, newest in newest }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func resolvePythonRuntime(
|
||||
homeDirectory: URL = FileManager.default.homeDirectoryForCurrentUser,
|
||||
environment: [String: String] = ProcessInfo.processInfo.environment,
|
||||
config: [String: String]? = nil,
|
||||
isExecutable: (String) -> Bool = { FileManager.default.isExecutableFile(atPath: $0) }
|
||||
) -> PythonRuntime {
|
||||
let loadedConfig = config ?? pythonRuntimeConfig(homeDirectory: homeDirectory)
|
||||
let defaultWorkDirectory = homeDirectory.appendingPathComponent("Projects/reyna-cli").path
|
||||
let workDirectoryPath = environment["REYNA_CLI_DIR"] ?? loadedConfig["REYNA_CLI_DIR"] ?? defaultWorkDirectory
|
||||
let selectedPython = environment["REYNA_CLI_PYTHON"]
|
||||
?? loadedConfig["REYNA_CLI_PYTHON"]
|
||||
?? URL(fileURLWithPath: workDirectoryPath).appendingPathComponent(".venv/bin/python").path
|
||||
let pythonPath = isExecutable(selectedPython) ? selectedPython : "/usr/bin/python3"
|
||||
return PythonRuntime(
|
||||
workingDirectory: URL(fileURLWithPath: workDirectoryPath),
|
||||
python: URL(fileURLWithPath: pythonPath)
|
||||
)
|
||||
}
|
||||
|
||||
public func pythonCommand(runtime: PythonRuntime, forwardedArguments: [String]) -> [String] {
|
||||
[runtime.python.path, "-m", "reyna_cli.cli"] + forwardedArguments
|
||||
}
|
||||
|
||||
public func pythonLaunchEnvironment(from environment: [String: String] = ProcessInfo.processInfo.environment) -> [String: String] {
|
||||
var sanitized = environment
|
||||
for key in ["PYTHONHOME", "PYTHONPATH", "VIRTUAL_ENV"] {
|
||||
sanitized.removeValue(forKey: key)
|
||||
}
|
||||
sanitized["PYTHONNOUSERSITE"] = "1"
|
||||
return sanitized
|
||||
}
|
||||
|
||||
public func runPythonCLI(forwardedArguments: [String]) -> Int32 {
|
||||
let runtime = resolvePythonRuntime()
|
||||
let command = pythonCommand(runtime: runtime, forwardedArguments: forwardedArguments)
|
||||
let process = Process()
|
||||
process.executableURL = runtime.python
|
||||
process.arguments = Array(command.dropFirst())
|
||||
process.currentDirectoryURL = runtime.workingDirectory
|
||||
process.environment = pythonLaunchEnvironment()
|
||||
|
||||
do {
|
||||
try process.run()
|
||||
process.waitUntilExit()
|
||||
return process.terminationStatus
|
||||
} catch {
|
||||
fputs("error: failed to run Reyna CLI Python: \(error)\n", stderr)
|
||||
return 127
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user