diff --git a/Package.swift b/Package.swift index 38abaa7e..95b448ea 100644 --- a/Package.swift +++ b/Package.swift @@ -274,6 +274,7 @@ let package = Package( dependencies: [ .product(name: "Logging", package: "swift-log"), .product(name: "Containerization", package: "containerization"), + "ContainerVersion", "CVersion", ] ), diff --git a/Sources/ContainerPersistence/DefaultsStore.swift b/Sources/ContainerPersistence/DefaultsStore.swift index 3754cdcd..abeb7c7a 100644 --- a/Sources/ContainerPersistence/DefaultsStore.swift +++ b/Sources/ContainerPersistence/DefaultsStore.swift @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// import CVersion +import ContainerVersion import ContainerizationError import Foundation @@ -41,8 +42,10 @@ public enum DefaultsStore { } public static func get(key: DefaultsStore.Keys) -> String { - udSuite.string(forKey: key.rawValue) - ?? Bundle.main.infoDictionary?["\(Self.userDefaultDomain).\(key.rawValue)"] as? String + let executableURL = URL(fileURLWithPath: CommandLine.arguments[0]).resolvingSymlinksInPath() + let appBundle = Bundle.appBundle(executableURL: executableURL) + return udSuite.string(forKey: key.rawValue) + ?? appBundle?.infoDictionary?["\(Self.userDefaultDomain).\(key.rawValue)"] as? String ?? key.defaultValue } @@ -58,7 +61,9 @@ public enum DefaultsStore { if udSuite.object(forKey: key.rawValue) != nil { return udSuite.bool(forKey: key.rawValue) } - return Bundle.main.infoDictionary?["\(Self.userDefaultDomain).\(key.rawValue)"] as? Bool + let executableURL = URL(fileURLWithPath: CommandLine.arguments[0]).resolvingSymlinksInPath() + let appBundle = Bundle.appBundle(executableURL: executableURL) + return appBundle?.infoDictionary?["\(Self.userDefaultDomain).\(key.rawValue)"] as? Bool ?? Bool(key.defaultValue) } diff --git a/Sources/ContainerVersion/Bundle+AppBundle.swift b/Sources/ContainerVersion/Bundle+AppBundle.swift new file mode 100644 index 00000000..5e7adc08 --- /dev/null +++ b/Sources/ContainerVersion/Bundle+AppBundle.swift @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// Copyright © 2025 Apple Inc. and the container project authors. +// +// 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 + +/// Retrieve the application bundle for a path that refers to a macOS executable. +extension Bundle { + public static func appBundle(executableURL: URL) -> Bundle? { + let macOSURL = executableURL.deletingLastPathComponent() + let contentsURL = macOSURL.deletingLastPathComponent() + let bundleURL = contentsURL.deletingLastPathComponent() + if bundleURL.pathExtension == "app" { + return Bundle(url: bundleURL) + } + return nil + } +} diff --git a/Sources/ContainerVersion/ReleaseVersion.swift b/Sources/ContainerVersion/ReleaseVersion.swift index a06bd185..21f1e363 100644 --- a/Sources/ContainerVersion/ReleaseVersion.swift +++ b/Sources/ContainerVersion/ReleaseVersion.swift @@ -30,7 +30,9 @@ public struct ReleaseVersion { } public static func version() -> String { - let bundleVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) + let executableURL = URL(fileURLWithPath: CommandLine.arguments[0]).resolvingSymlinksInPath() + let appBundle = Bundle.appBundle(executableURL: executableURL) + let bundleVersion = appBundle?.infoDictionary?["CFBundleShortVersionString"] as? String return bundleVersion ?? get_release_version().map { String(cString: $0) } ?? "0.0.0" }