diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-01-03 03:07:50 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-02-08 21:42:22 +0100 |
commit | 59fc8666ae26f672ab6232cd637021aa61cd0e76 (patch) | |
tree | 10a4328e9ccb1a2fcdc6c1042876d4f1d5630946 /packages/main/src | |
parent | feat: Add Profile and Service stores (diff) | |
download | sophie-59fc8666ae26f672ab6232cd637021aa61cd0e76.tar.gz sophie-59fc8666ae26f672ab6232cd637021aa61cd0e76.tar.zst sophie-59fc8666ae26f672ab6232cd637021aa61cd0e76.zip |
feat: Rewrite the config if new details are added
If we generate a new ID or a new profile, it should be added to the
config file immediately.
Signed-off-by: Kristóf Marussy <kristof@marussy.com>
Diffstat (limited to 'packages/main/src')
-rw-r--r-- | packages/main/src/controllers/__tests__/initConfig.spec.ts | 41 | ||||
-rw-r--r-- | packages/main/src/controllers/initConfig.ts | 23 |
2 files changed, 52 insertions, 12 deletions
diff --git a/packages/main/src/controllers/__tests__/initConfig.spec.ts b/packages/main/src/controllers/__tests__/initConfig.spec.ts index 11e7690..241ab2d 100644 --- a/packages/main/src/controllers/__tests__/initConfig.spec.ts +++ b/packages/main/src/controllers/__tests__/initConfig.spec.ts | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | import { jest } from '@jest/globals'; | 21 | import { jest } from '@jest/globals'; |
22 | import { mocked } from 'jest-mock'; | 22 | import { mocked } from 'jest-mock'; |
23 | import { getSnapshot } from 'mobx-state-tree'; | ||
23 | import ms from 'ms'; | 24 | import ms from 'ms'; |
24 | 25 | ||
25 | import type ConfigPersistenceService from '../../services/ConfigPersistenceService'; | 26 | import type ConfigPersistenceService from '../../services/ConfigPersistenceService'; |
@@ -74,6 +75,8 @@ describe('when initializing', () => { | |||
74 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ | 75 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ |
75 | found: true, | 76 | found: true, |
76 | data: { | 77 | data: { |
78 | // Use a default empty config file to not trigger config rewrite. | ||
79 | ...getSnapshot(config), | ||
77 | themeSource: 'dark', | 80 | themeSource: 'dark', |
78 | }, | 81 | }, |
79 | }); | 82 | }); |
@@ -95,7 +98,21 @@ describe('when initializing', () => { | |||
95 | }); | 98 | }); |
96 | }); | 99 | }); |
97 | 100 | ||
98 | it('should not apply an invalid config file', async () => { | 101 | it('should update the config file if new details are added during read', async () => { |
102 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ | ||
103 | found: true, | ||
104 | data: { | ||
105 | themeSource: 'light', | ||
106 | profile: { | ||
107 | name: 'Test profile', | ||
108 | }, | ||
109 | }, | ||
110 | }); | ||
111 | await initConfig(config, persistenceService); | ||
112 | expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1); | ||
113 | }); | ||
114 | |||
115 | it('should not apply an invalid config file but should not overwrite it', async () => { | ||
99 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ | 116 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ |
100 | found: true, | 117 | found: true, |
101 | data: { | 118 | data: { |
@@ -104,6 +121,7 @@ describe('when initializing', () => { | |||
104 | }); | 121 | }); |
105 | await initConfig(config, persistenceService); | 122 | await initConfig(config, persistenceService); |
106 | expect(config.themeSource).not.toBe(-1); | 123 | expect(config.themeSource).not.toBe(-1); |
124 | expect(persistenceService.writeConfig).not.toHaveBeenCalled(); | ||
107 | }); | 125 | }); |
108 | 126 | ||
109 | it('should bail if it cannot determine whether there is a config file', async () => { | 127 | it('should bail if it cannot determine whether there is a config file', async () => { |
@@ -122,7 +140,7 @@ describe('when it has loaded the config', () => { | |||
122 | beforeEach(async () => { | 140 | beforeEach(async () => { |
123 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ | 141 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ |
124 | found: true, | 142 | found: true, |
125 | data: {}, | 143 | data: getSnapshot(config), |
126 | }); | 144 | }); |
127 | mocked(persistenceService.watchConfig).mockReturnValueOnce(watcherDisposer); | 145 | mocked(persistenceService.watchConfig).mockReturnValueOnce(watcherDisposer); |
128 | sutDisposer = await initConfig(config, persistenceService, throttleMs); | 146 | sutDisposer = await initConfig(config, persistenceService, throttleMs); |
@@ -152,6 +170,8 @@ describe('when it has loaded the config', () => { | |||
152 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ | 170 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ |
153 | found: true, | 171 | found: true, |
154 | data: { | 172 | data: { |
173 | // Use a default empty config file to not trigger config rewrite. | ||
174 | ...getSnapshot(config), | ||
155 | themeSource: 'dark', | 175 | themeSource: 'dark', |
156 | }, | 176 | }, |
157 | }); | 177 | }); |
@@ -161,7 +181,21 @@ describe('when it has loaded the config', () => { | |||
161 | expect(config.themeSource).toBe('dark'); | 181 | expect(config.themeSource).toBe('dark'); |
162 | }); | 182 | }); |
163 | 183 | ||
164 | it('should not apply an invalid config file when it has changed', async () => { | 184 | it('should update the config file if new details are added', async () => { |
185 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ | ||
186 | found: true, | ||
187 | data: { | ||
188 | themeSource: 'light', | ||
189 | profile: { | ||
190 | name: 'Test profile', | ||
191 | }, | ||
192 | }, | ||
193 | }); | ||
194 | await configChangedCallback(); | ||
195 | expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1); | ||
196 | }); | ||
197 | |||
198 | it('should not apply an invalid config file when it has changed but should not overwrite it', async () => { | ||
165 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ | 199 | mocked(persistenceService.readConfig).mockResolvedValueOnce({ |
166 | found: true, | 200 | found: true, |
167 | data: { | 201 | data: { |
@@ -170,6 +204,7 @@ describe('when it has loaded the config', () => { | |||
170 | }); | 204 | }); |
171 | await configChangedCallback(); | 205 | await configChangedCallback(); |
172 | expect(config.themeSource).not.toBe(-1); | 206 | expect(config.themeSource).not.toBe(-1); |
207 | expect(persistenceService.writeConfig).not.toHaveBeenCalled(); | ||
173 | }); | 208 | }); |
174 | 209 | ||
175 | it('should handle config reading errors gracefully', async () => { | 210 | it('should handle config reading errors gracefully', async () => { |
diff --git a/packages/main/src/controllers/initConfig.ts b/packages/main/src/controllers/initConfig.ts index 93be978..2dcabaf 100644 --- a/packages/main/src/controllers/initConfig.ts +++ b/packages/main/src/controllers/initConfig.ts | |||
@@ -18,12 +18,13 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import deepEqual from 'deep-equal'; | ||
21 | import { debounce } from 'lodash-es'; | 22 | import { debounce } from 'lodash-es'; |
22 | import { getSnapshot, onSnapshot } from 'mobx-state-tree'; | 23 | import { getSnapshot, onSnapshot } from 'mobx-state-tree'; |
23 | import ms from 'ms'; | 24 | import ms from 'ms'; |
24 | 25 | ||
25 | import type ConfigPersistenceService from '../services/ConfigPersistenceService.js'; | 26 | import type ConfigPersistenceService from '../services/ConfigPersistenceService'; |
26 | import { Config, ConfigFileIn, ConfigSnapshotOut } from '../stores/Config.js'; | 27 | import { Config, ConfigFileIn, ConfigSnapshotOut } from '../stores/Config'; |
27 | import type Disposer from '../utils/Disposer'; | 28 | import type Disposer from '../utils/Disposer'; |
28 | import { getLogger } from '../utils/log'; | 29 | import { getLogger } from '../utils/log'; |
29 | 30 | ||
@@ -40,6 +41,12 @@ export default async function initConfig( | |||
40 | 41 | ||
41 | let lastSnapshotOnDisk: ConfigSnapshotOut | undefined; | 42 | let lastSnapshotOnDisk: ConfigSnapshotOut | undefined; |
42 | 43 | ||
44 | async function writeConfig(): Promise<void> { | ||
45 | const snapshot = getSnapshot(config); | ||
46 | await persistenceService.writeConfig(snapshot); | ||
47 | lastSnapshotOnDisk = snapshot; | ||
48 | } | ||
49 | |||
43 | async function readConfig(): Promise<boolean> { | 50 | async function readConfig(): Promise<boolean> { |
44 | const result = await persistenceService.readConfig(); | 51 | const result = await persistenceService.readConfig(); |
45 | if (result.found) { | 52 | if (result.found) { |
@@ -49,18 +56,16 @@ export default async function initConfig( | |||
49 | config.loadFromConfigFile(result.data as ConfigFileIn); | 56 | config.loadFromConfigFile(result.data as ConfigFileIn); |
50 | } catch (error) { | 57 | } catch (error) { |
51 | log.error('Failed to apply config snapshot', result.data, error); | 58 | log.error('Failed to apply config snapshot', result.data, error); |
59 | return true; | ||
60 | } | ||
61 | lastSnapshotOnDisk = getSnapshot(config); | ||
62 | if (!deepEqual(result.data, lastSnapshotOnDisk, { strict: true })) { | ||
63 | await writeConfig(); | ||
52 | } | 64 | } |
53 | } | 65 | } |
54 | lastSnapshotOnDisk = getSnapshot(config); | ||
55 | return result.found; | 66 | return result.found; |
56 | } | 67 | } |
57 | 68 | ||
58 | async function writeConfig(): Promise<void> { | ||
59 | const snapshot = getSnapshot(config); | ||
60 | await persistenceService.writeConfig(snapshot); | ||
61 | lastSnapshotOnDisk = snapshot; | ||
62 | } | ||
63 | |||
64 | if (!(await readConfig())) { | 69 | if (!(await readConfig())) { |
65 | log.info('Config file was not found'); | 70 | log.info('Config file was not found'); |
66 | await writeConfig(); | 71 | await writeConfig(); |