Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Sources/DevConfiguration/Core/ConfigVariableReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,9 @@ public final class ConfigVariableReader: Sendable {
var namedProviders = namedProviders

if isEditorEnabled {
let provider = EditorOverrideProvider()
provider.load(from: UserDefaults(suiteName: EditorOverrideProvider.suiteName)!)
let provider = EditorOverrideProvider(
userDefaults: UserDefaults(suiteName: "devkit.DevConfiguration") ?? .standard
)
editorOverrideProvider = provider
namedProviders.insert(.init(provider, displayName: localizedString("editorOverrideProvider.name")), at: 0)
}
Expand Down
1 change: 0 additions & 1 deletion Sources/DevConfiguration/Editor/ConfigVariableEditor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public struct ConfigVariableEditor: View {
workingCopyDisplayName: localizedString("editorOverrideProvider.name"),
namedProviders: namedProviders,
registeredVariables: Array(reader.registeredVariables.values),
userDefaults: .standard,
undoManager: UndoManager()
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ final class EditorDocument {
/// The editor override provider.
private let editorOverrideProvider: EditorOverrideProvider

/// The UserDefaults instance used for persisting overrides.
private let userDefaults: UserDefaults

/// The undo manager used for working copy changes.
let undoManager: UndoManager

Expand All @@ -75,19 +72,16 @@ final class EditorDocument {
/// - workingCopyDisplayName: The display name for the working copy in the UI.
/// - namedProviders: The reader's named providers, excluding the editor override provider.
/// - registeredVariables: The registered variables to display in the editor.
/// - userDefaults: The UserDefaults instance used for persisting overrides.
/// - undoManager: The undo manager for working copy changes.
init(
editorOverrideProvider: EditorOverrideProvider,
workingCopyDisplayName: String,
namedProviders: [NamedConfigProvider],
registeredVariables: [RegisteredConfigVariable],
userDefaults: UserDefaults,
undoManager: UndoManager
) {
self.editorOverrideProvider = editorOverrideProvider
self.workingCopyDisplayName = workingCopyDisplayName
self.userDefaults = userDefaults
self.undoManager = undoManager

// Build registered variables dictionary
Expand Down Expand Up @@ -416,7 +410,7 @@ extension EditorDocument {
}

// Persist
editorOverrideProvider.persist(to: userDefaults)
editorOverrideProvider.persist()

// Update baseline
baseline = workingCopy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,28 @@ final class EditorOverrideProvider: Sendable {
/// The name used to identify this provider.
static let providerName = "EditorOverrideProvider"

/// The UserDefaults suite name used for persistence.
static let suiteName = "devkit.DevConfiguration"

/// The UserDefaults key under which overrides are stored.
private static let persistenceKey = "editorOverrides"

/// The logger used for persistence diagnostics.
private static let logger = Logger(subsystem: "DevConfiguration", category: "EditorOverrideProvider")

/// The UserDefaults instance used for persistence.
nonisolated(unsafe) private let userDefaults: UserDefaults

/// The mutable state protected by a mutex.
private let mutableState: Mutex<MutableState> = .init(MutableState())


/// Creates a new editor override provider.
///
/// Loads any previously persisted overrides from the given UserDefaults instance.
///
/// - Parameter userDefaults: The UserDefaults instance used for persistence.
init(userDefaults: UserDefaults) {
self.userDefaults = userDefaults
load()
}
}


Expand Down Expand Up @@ -206,13 +217,10 @@ extension EditorOverrideProvider {
// MARK: - Persistence

extension EditorOverrideProvider {
/// Loads persisted overrides from the given UserDefaults into memory.
///
/// Any entries that fail to decode are silently skipped. This method is intended to be called once during setup,
/// before the provider is shared with other components.
/// Loads persisted overrides from UserDefaults into memory.
///
/// - Parameter userDefaults: The UserDefaults instance to load from.
func load(from userDefaults: UserDefaults) {
/// Any entries that fail to decode are silently skipped.
private func load() {
guard let stored = userDefaults.dictionary(forKey: Self.persistenceKey) as? [String: Data] else {
return
}
Expand All @@ -234,12 +242,10 @@ extension EditorOverrideProvider {
}


/// Persists the current overrides to the given UserDefaults.
/// Persists the current overrides to UserDefaults.
///
/// Each override is JSON-encoded individually. The resulting dictionary is stored under the persistence key.
///
/// - Parameter userDefaults: The UserDefaults instance to persist to.
func persist(to userDefaults: UserDefaults) {
func persist() {
let currentOverrides = overrides
let encoder = JSONEncoder()
encoder.outputFormatting = .sortedKeys
Expand All @@ -258,12 +264,10 @@ extension EditorOverrideProvider {
}


/// Removes all persisted overrides from the given UserDefaults.
/// Removes all persisted overrides from UserDefaults.
///
/// This does not affect the in-memory overrides.
///
/// - Parameter userDefaults: The UserDefaults instance to clear.
func clearPersistence(from userDefaults: UserDefaults) {
func clearPersistence() {
userDefaults.removeObject(forKey: Self.persistenceKey)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ import Testing
struct ConfigVariableDetailViewModelTests: RandomValueGenerating {
var randomNumberGenerator = makeRandomNumberGenerator()

let editorOverrideProvider = EditorOverrideProvider()
var userDefaults: UserDefaults!
let editorOverrideProvider: EditorOverrideProvider
var workingCopyDisplayName: String!
let undoManager = UndoManager()


init() {
let userDefaults = UserDefaults(suiteName: "devkit.DevConfiguration.test.\(UUID())")!
userDefaults.removeObject(forKey: "editorOverrides")
editorOverrideProvider = EditorOverrideProvider(userDefaults: userDefaults)
workingCopyDisplayName = randomAlphanumericString()
userDefaults = UserDefaults(suiteName: randomAlphanumericString())!
}


Expand All @@ -39,7 +40,6 @@ struct ConfigVariableDetailViewModelTests: RandomValueGenerating {
workingCopyDisplayName: workingCopyDisplayName,
namedProviders: namedProviders,
registeredVariables: registeredVariables,
userDefaults: userDefaults,
undoManager: undoManager
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@ import Testing
struct ConfigVariableListViewModelTests: RandomValueGenerating {
var randomNumberGenerator = makeRandomNumberGenerator()

let editorOverrideProvider = EditorOverrideProvider()
var userDefaults: UserDefaults!
let editorOverrideProvider: EditorOverrideProvider
var workingCopyDisplayName: String!
let undoManager = UndoManager()

nonisolated(unsafe) var onSaveStub: Stub<[RegisteredConfigVariable], Void>!


init() {
let userDefaults = UserDefaults(suiteName: "devkit.DevConfiguration.test.\(UUID())")!
userDefaults.removeObject(forKey: "editorOverrides")
editorOverrideProvider = EditorOverrideProvider(userDefaults: userDefaults)
workingCopyDisplayName = randomAlphanumericString()
userDefaults = UserDefaults(suiteName: randomAlphanumericString())!
onSaveStub = Stub()
}

Expand All @@ -42,7 +43,6 @@ struct ConfigVariableListViewModelTests: RandomValueGenerating {
workingCopyDisplayName: workingCopyDisplayName,
namedProviders: namedProviders,
registeredVariables: registeredVariables ?? [randomRegisteredVariable()],
userDefaults: userDefaults,
undoManager: undoManager
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ import Testing
struct EditorDocumentTests: RandomValueGenerating {
var randomNumberGenerator = makeRandomNumberGenerator()

let editorOverrideProvider = EditorOverrideProvider()
var userDefaults: UserDefaults!
let editorOverrideProvider: EditorOverrideProvider
var workingCopyDisplayName: String!
let undoManager = UndoManager()


init() {
let userDefaults = UserDefaults(suiteName: "devkit.DevConfiguration.test.\(UUID())")!
userDefaults.removeObject(forKey: "editorOverrides")
editorOverrideProvider = EditorOverrideProvider(userDefaults: userDefaults)
workingCopyDisplayName = randomAlphanumericString()
userDefaults = UserDefaults(suiteName: randomAlphanumericString())!
}


Expand All @@ -40,7 +41,6 @@ struct EditorDocumentTests: RandomValueGenerating {
workingCopyDisplayName: workingCopyDisplayName,
namedProviders: namedProviders,
registeredVariables: registeredVariables ?? [randomRegisteredVariable()],
userDefaults: userDefaults,
undoManager: undoManager
)
}
Expand Down
Loading