Support for Repo plugins

This commit is contained in:
Greg Neagle
2025-05-09 16:52:46 -07:00
parent edf5b96986
commit 21114c19ff
3 changed files with 74 additions and 0 deletions

View File

@@ -20,6 +20,51 @@
import Foundation
/// Loads a Repo plugin from a dylib
/// implementation lifted from
/// https://theswiftdev.com/building-and-loading-dynamic-libraries-at-runtime-in-swift/
func loadRepoPlugin(at path: String) throws -> RepoPluginBuilder {
typealias InitFunction = @convention(c) () -> UnsafeMutableRawPointer
let openRes = dlopen(path, RTLD_NOW | RTLD_LOCAL)
if openRes != nil {
defer {
dlclose(openRes)
}
let symbolName = "createPlugin"
let sym = dlsym(openRes, symbolName)
if sym != nil {
let f: InitFunction = unsafeBitCast(sym, to: InitFunction.self)
let pluginPointer = f()
let builder = Unmanaged<RepoPluginBuilder>.fromOpaque(pluginPointer).takeRetainedValue()
return builder
} else {
throw MunkiError("Could not find symbol \(symbolName) in lib: \(path)")
}
} else {
if let err = dlerror() {
throw MunkiError("Error opening lib: \(String(format: "%s", err)), path: \(path)")
} else {
throw MunkiError("Error opening lib: unknown error, path: \(path)")
}
}
}
/// Try to load a Repo plugin from our RepoPlugins directory
func findRepoInPlugins(_ name: String, url: String) throws -> Repo? {
let pluginName = name + ".plugin"
let repoPluginsDir = (Bundle.main.bundlePath as NSString).appendingPathComponent("RepoPlugins")
let repoPluginNames = (try? FileManager.default.contentsOfDirectory(atPath: repoPluginsDir)) ?? []
if repoPluginNames.contains(pluginName) {
let pluginPath = (repoPluginsDir as NSString).appendingPathComponent(pluginName)
let repoPlugin = try loadRepoPlugin(at: pluginPath)
return repoPlugin.connect(url)
}
return nil
}
/// Factory function that returns an instance of a specific Repo class
func repoConnect(url: String, plugin: String = "FileRepo") throws -> Repo {
switch plugin {
@@ -28,6 +73,9 @@ func repoConnect(url: String, plugin: String = "FileRepo") throws -> Repo {
case "GitFileRepo":
return try GitFileRepo(url)
default:
if let repo = try findRepoInPlugins(plugin, url: url) {
return repo
}
throw MunkiError("No repo plugin named \"\(plugin)\"")
}
}

View File

@@ -4,6 +4,19 @@
//
// Created by Greg Neagle on 5/8/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 Foundation

View File

@@ -4,6 +4,19 @@
//
// Created by Greg Neagle on 7/15/24.
//
// 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 Foundation