Skip to content

Commit 0f51b2d

Browse files
committed
feat: bundle RedisDriver plugin and show correct installed plugin versions
1 parent a2d2bee commit 0f51b2d

4 files changed

Lines changed: 76 additions & 4 deletions

File tree

TablePro.xcodeproj/project.pbxproj

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
5ACE00012F4F000000000006 /* CodeEditTextView in Frameworks */ = {isa = PBXBuildFile; productRef = 5ACE00012F4F000000000007 /* CodeEditTextView */; };
3636
5ACE00012F4F00000000000A /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 5ACE00012F4F000000000009 /* Sparkle */; };
3737
5ACE00012F4F00000000000D /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 5ACE00012F4F00000000000C /* MarkdownUI */; };
38+
5A867000D00000000 /* RedisDriver.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A867000100000000 /* RedisDriver.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
3839
5ADDB00000000000000000D0 /* DynamoDBDriverPlugin.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5ADDB00300000000000000A0 /* DynamoDBDriverPlugin.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
3940
5ADDB00100000000000000A1 /* DynamoDBConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ADDB00200000000000000A1 /* DynamoDBConnection.swift */; };
4041
5ADDB00100000000000000A2 /* DynamoDBItemFlattener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ADDB00200000000000000A2 /* DynamoDBItemFlattener.swift */; };
@@ -133,6 +134,13 @@
133134
remoteGlobalIDString = 5A1091C62EF17EDC0055EA7C;
134135
remoteInfo = TablePro;
135136
};
137+
5A867000B00000000 /* PBXContainerItemProxy */ = {
138+
isa = PBXContainerItemProxy;
139+
containerPortal = 5A1091BF2EF17EDC0055EA7C /* Project object */;
140+
proxyType = 1;
141+
remoteGlobalIDString = 5A867000000000000;
142+
remoteInfo = RedisDriver;
143+
};
136144
5ADDB00000000000000000C0 /* PBXContainerItemProxy */ = {
137145
isa = PBXContainerItemProxy;
138146
containerPortal = 5A1091BF2EF17EDC0055EA7C /* Project object */;
@@ -156,6 +164,7 @@
156164
5A86B000D00000000 /* JSONExport.tableplugin in Copy Plug-Ins */,
157165
5A86C000D00000000 /* SQLExport.tableplugin in Copy Plug-Ins */,
158166
5ADDB00000000000000000D0 /* DynamoDBDriverPlugin.tableplugin in Copy Plug-Ins */,
167+
5A867000D00000000 /* RedisDriver.tableplugin in Copy Plug-Ins */,
159168
);
160169
name = "Copy Plug-Ins";
161170
runOnlyForDeploymentPostprocessing = 0;
@@ -830,6 +839,7 @@
830839
5A86B000C00000000 /* PBXTargetDependency */,
831840
5A86C000C00000000 /* PBXTargetDependency */,
832841
5ADDB00000000000000000C1 /* PBXTargetDependency */,
842+
5A867000C00000000 /* PBXTargetDependency */,
833843
);
834844
fileSystemSynchronizedGroups = (
835845
5A1091C92EF17EDC0055EA7C /* TablePro */,
@@ -1766,6 +1776,11 @@
17661776
target = 5A86B000000000000 /* JSONExport */;
17671777
targetProxy = 5A86B000B00000000 /* PBXContainerItemProxy */;
17681778
};
1779+
5A867000C00000000 /* PBXTargetDependency */ = {
1780+
isa = PBXTargetDependency;
1781+
target = 5A867000000000000 /* RedisDriver */;
1782+
targetProxy = 5A867000B00000000 /* PBXContainerItemProxy */;
1783+
};
17691784
5A86C000C00000000 /* PBXTargetDependency */ = {
17701785
isa = PBXTargetDependency;
17711786
target = 5A86C000000000000 /* SQLExport */;

TablePro/Core/Plugins/PluginManager.swift

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,49 @@ final class PluginManager {
6161

6262
private init() {}
6363

64+
// MARK: - Registry Metadata
65+
66+
private struct RegistryMetadata: Codable {
67+
let version: String
68+
let pluginId: String
69+
}
70+
71+
nonisolated private static func metadataURL(for pluginURL: URL) -> URL {
72+
pluginURL.deletingLastPathComponent()
73+
.appendingPathComponent(pluginURL.lastPathComponent + ".metadata.json")
74+
}
75+
76+
nonisolated private static func readRegistryVersion(for pluginURL: URL) -> String? {
77+
let url = metadataURL(for: pluginURL)
78+
guard let data = try? Data(contentsOf: url),
79+
let metadata = try? JSONDecoder().decode(RegistryMetadata.self, from: data) else {
80+
return nil
81+
}
82+
return metadata.version
83+
}
84+
85+
func updatePluginVersion(id: String, version: String) {
86+
if let index = plugins.firstIndex(where: { $0.id == id }) {
87+
plugins[index].version = version
88+
}
89+
}
90+
91+
func saveRegistryMetadata(version: String, pluginId: String, pluginURL: URL) {
92+
let metadata = RegistryMetadata(version: version, pluginId: pluginId)
93+
let url = Self.metadataURL(for: pluginURL)
94+
do {
95+
let data = try JSONEncoder().encode(metadata)
96+
try data.write(to: url, options: .atomic)
97+
} catch {
98+
Self.logger.error("Failed to save registry metadata for \(pluginId): \(error.localizedDescription)")
99+
}
100+
}
101+
102+
private func removeRegistryMetadata(for pluginURL: URL) {
103+
let url = Self.metadataURL(for: pluginURL)
104+
try? FileManager.default.removeItem(at: url)
105+
}
106+
64107
private func migrateDisabledPluginsKey() {
65108
let defaults = UserDefaults.standard
66109
if let legacy = defaults.stringArray(forKey: Self.legacyDisabledPluginsKey) {
@@ -156,13 +199,14 @@ final class PluginManager {
156199
}
157200

158201
let driverType = principalClass as? any DriverPlugin.Type
202+
let version = readRegistryVersion(for: entry.url) ?? principalClass.pluginVersion
159203
let loaded = LoadedBundle(
160204
url: entry.url,
161205
source: entry.source,
162206
bundle: bundle,
163207
principalClassName: NSStringFromClass(principalClass),
164208
pluginName: principalClass.pluginName,
165-
pluginVersion: principalClass.pluginVersion,
209+
pluginVersion: version,
166210
pluginDescription: principalClass.pluginDescription,
167211
capabilities: principalClass.capabilities,
168212
databaseTypeId: driverType?.databaseTypeId,
@@ -359,13 +403,14 @@ final class PluginManager {
359403
let disabled = disabledPluginIds
360404

361405
let driverType = principalClass as? any DriverPlugin.Type
406+
let version = Self.readRegistryVersion(for: url) ?? principalClass.pluginVersion
362407
let entry = PluginEntry(
363408
id: bundleId,
364409
bundle: bundle,
365410
url: url,
366411
source: source,
367412
name: principalClass.pluginName,
368-
version: principalClass.pluginVersion,
413+
version: version,
369414
pluginDescription: principalClass.pluginDescription,
370415
capabilities: principalClass.capabilities,
371416
isEnabled: !disabled.contains(bundleId),
@@ -1009,6 +1054,8 @@ final class PluginManager {
10091054
entry.bundle.unload()
10101055
plugins.remove(at: index)
10111056

1057+
removeRegistryMetadata(for: entry.url)
1058+
10121059
let fm = FileManager.default
10131060
if fm.fileExists(atPath: entry.url.path) {
10141061
try fm.removeItem(at: entry.url)

TablePro/Core/Plugins/PluginModels.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ struct PluginEntry: Identifiable {
1212
let url: URL
1313
let source: PluginSource
1414
let name: String
15-
let version: String
15+
var version: String
1616
let pluginDescription: String
1717
let capabilities: [PluginCapability]
1818
var isEnabled: Bool

TablePro/Core/Plugins/Registry/PluginManager+Registry.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ extension PluginManager {
6868
// Move to our temp directory for installPlugin
6969
try FileManager.default.moveItem(at: tempDownloadURL, to: tempZipURL)
7070

71-
return try await installPlugin(from: tempZipURL)
71+
var entry = try await installPlugin(from: tempZipURL)
72+
73+
saveRegistryMetadata(
74+
version: registryPlugin.version,
75+
pluginId: registryPlugin.id,
76+
pluginURL: entry.url
77+
)
78+
entry.version = registryPlugin.version
79+
updatePluginVersion(id: entry.id, version: registryPlugin.version)
80+
81+
return entry
7282
}
7383
}

0 commit comments

Comments
 (0)