From 59fc8666ae26f672ab6232cd637021aa61cd0e76 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Mon, 3 Jan 2022 03:07:50 +0100 Subject: feat: Rewrite the config if new details are added MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- packages/main/package.json | 2 + .../src/controllers/__tests__/initConfig.spec.ts | 41 ++++- packages/main/src/controllers/initConfig.ts | 23 +-- yarn.lock | 173 ++++++++++++++++++++- 4 files changed, 220 insertions(+), 19 deletions(-) diff --git a/packages/main/package.json b/packages/main/package.json index 80a93b9..c03e81e 100644 --- a/packages/main/package.json +++ b/packages/main/package.json @@ -11,6 +11,7 @@ "@sophie/service-shared": "workspace:*", "@sophie/shared": "workspace:*", "chalk": "^5.0.0", + "deep-equal": "^2.0.5", "electron": "17.0.0", "fs-extra": "^10.0.0", "json5": "^2.2.0", @@ -26,6 +27,7 @@ }, "devDependencies": { "@jest/globals": "^27.4.6", + "@types/deep-equal": "^1.0.1", "@types/electron-devtools-installer": "^2.2.1", "@types/lodash-es": "^4.17.5", "@types/ms": "^0.7.31", 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 @@ import { jest } from '@jest/globals'; import { mocked } from 'jest-mock'; +import { getSnapshot } from 'mobx-state-tree'; import ms from 'ms'; import type ConfigPersistenceService from '../../services/ConfigPersistenceService'; @@ -74,6 +75,8 @@ describe('when initializing', () => { mocked(persistenceService.readConfig).mockResolvedValueOnce({ found: true, data: { + // Use a default empty config file to not trigger config rewrite. + ...getSnapshot(config), themeSource: 'dark', }, }); @@ -95,7 +98,21 @@ describe('when initializing', () => { }); }); - it('should not apply an invalid config file', async () => { + it('should update the config file if new details are added during read', async () => { + mocked(persistenceService.readConfig).mockResolvedValueOnce({ + found: true, + data: { + themeSource: 'light', + profile: { + name: 'Test profile', + }, + }, + }); + await initConfig(config, persistenceService); + expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1); + }); + + it('should not apply an invalid config file but should not overwrite it', async () => { mocked(persistenceService.readConfig).mockResolvedValueOnce({ found: true, data: { @@ -104,6 +121,7 @@ describe('when initializing', () => { }); await initConfig(config, persistenceService); expect(config.themeSource).not.toBe(-1); + expect(persistenceService.writeConfig).not.toHaveBeenCalled(); }); 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', () => { beforeEach(async () => { mocked(persistenceService.readConfig).mockResolvedValueOnce({ found: true, - data: {}, + data: getSnapshot(config), }); mocked(persistenceService.watchConfig).mockReturnValueOnce(watcherDisposer); sutDisposer = await initConfig(config, persistenceService, throttleMs); @@ -152,6 +170,8 @@ describe('when it has loaded the config', () => { mocked(persistenceService.readConfig).mockResolvedValueOnce({ found: true, data: { + // Use a default empty config file to not trigger config rewrite. + ...getSnapshot(config), themeSource: 'dark', }, }); @@ -161,7 +181,21 @@ describe('when it has loaded the config', () => { expect(config.themeSource).toBe('dark'); }); - it('should not apply an invalid config file when it has changed', async () => { + it('should update the config file if new details are added', async () => { + mocked(persistenceService.readConfig).mockResolvedValueOnce({ + found: true, + data: { + themeSource: 'light', + profile: { + name: 'Test profile', + }, + }, + }); + await configChangedCallback(); + expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1); + }); + + it('should not apply an invalid config file when it has changed but should not overwrite it', async () => { mocked(persistenceService.readConfig).mockResolvedValueOnce({ found: true, data: { @@ -170,6 +204,7 @@ describe('when it has loaded the config', () => { }); await configChangedCallback(); expect(config.themeSource).not.toBe(-1); + expect(persistenceService.writeConfig).not.toHaveBeenCalled(); }); 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 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import deepEqual from 'deep-equal'; import { debounce } from 'lodash-es'; import { getSnapshot, onSnapshot } from 'mobx-state-tree'; import ms from 'ms'; -import type ConfigPersistenceService from '../services/ConfigPersistenceService.js'; -import { Config, ConfigFileIn, ConfigSnapshotOut } from '../stores/Config.js'; +import type ConfigPersistenceService from '../services/ConfigPersistenceService'; +import { Config, ConfigFileIn, ConfigSnapshotOut } from '../stores/Config'; import type Disposer from '../utils/Disposer'; import { getLogger } from '../utils/log'; @@ -40,6 +41,12 @@ export default async function initConfig( let lastSnapshotOnDisk: ConfigSnapshotOut | undefined; + async function writeConfig(): Promise { + const snapshot = getSnapshot(config); + await persistenceService.writeConfig(snapshot); + lastSnapshotOnDisk = snapshot; + } + async function readConfig(): Promise { const result = await persistenceService.readConfig(); if (result.found) { @@ -49,18 +56,16 @@ export default async function initConfig( config.loadFromConfigFile(result.data as ConfigFileIn); } catch (error) { log.error('Failed to apply config snapshot', result.data, error); + return true; + } + lastSnapshotOnDisk = getSnapshot(config); + if (!deepEqual(result.data, lastSnapshotOnDisk, { strict: true })) { + await writeConfig(); } } - lastSnapshotOnDisk = getSnapshot(config); return result.found; } - async function writeConfig(): Promise { - const snapshot = getSnapshot(config); - await persistenceService.writeConfig(snapshot); - lastSnapshotOnDisk = snapshot; - } - if (!(await readConfig())) { log.info('Config file was not found'); await writeConfig(); diff --git a/yarn.lock b/yarn.lock index eba34a3..f7dd338 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1237,12 +1237,14 @@ __metadata: "@jest/globals": ^27.4.6 "@sophie/service-shared": "workspace:*" "@sophie/shared": "workspace:*" + "@types/deep-equal": ^1.0.1 "@types/electron-devtools-installer": ^2.2.1 "@types/lodash-es": ^4.17.5 "@types/ms": ^0.7.31 "@types/node": ^17.0.12 "@types/slug": ^5 chalk: ^5.0.0 + deep-equal: ^2.0.5 electron: 17.0.0 electron-devtools-installer: ^3.2.0 esbuild: ^0.14.14 @@ -1418,6 +1420,13 @@ __metadata: languageName: node linkType: hard +"@types/deep-equal@npm:^1.0.1": + version: 1.0.1 + resolution: "@types/deep-equal@npm:1.0.1" + checksum: 689b5737dd0a37d173d9e1231c07f70a1a9a989087b757422e1d167ec3640fd7eb8a538bd6008b3df400c4c11ed07a6c2a92d9aafc1f98ffaa04731a9442c781 + languageName: node + linkType: hard + "@types/electron-devtools-installer@npm:^2.2.1": version: 2.2.1 resolution: "@types/electron-devtools-installer@npm:2.2.1" @@ -2203,6 +2212,13 @@ __metadata: languageName: node linkType: hard +"available-typed-arrays@npm:^1.0.5": + version: 1.0.5 + resolution: "available-typed-arrays@npm:1.0.5" + checksum: 20eb47b3cefd7db027b9bbb993c658abd36d4edd3fe1060e83699a03ee275b0c9b216cc076ff3f2db29073225fb70e7613987af14269ac1fe2a19803ccc97f1a + languageName: node + linkType: hard + "axe-core@npm:^4.3.5": version: 4.3.5 resolution: "axe-core@npm:4.3.5" @@ -3113,6 +3129,29 @@ __metadata: languageName: node linkType: hard +"deep-equal@npm:^2.0.5": + version: 2.0.5 + resolution: "deep-equal@npm:2.0.5" + dependencies: + call-bind: ^1.0.0 + es-get-iterator: ^1.1.1 + get-intrinsic: ^1.0.1 + is-arguments: ^1.0.4 + is-date-object: ^1.0.2 + is-regex: ^1.1.1 + isarray: ^2.0.5 + object-is: ^1.1.4 + object-keys: ^1.1.1 + object.assign: ^4.1.2 + regexp.prototype.flags: ^1.3.0 + side-channel: ^1.0.3 + which-boxed-primitive: ^1.0.1 + which-collection: ^1.0.1 + which-typed-array: ^1.1.2 + checksum: 2bb7332badf589b540184d25098acac750e30fe11c8dce4523d03fc5db15f46881a0105e6bf0b64bb0c57213a95ed964029ff0259026ad6f7f9e0019f8200de5 + languageName: node + linkType: hard + "deep-equal@npm:~0.0.0": version: 0.0.0 resolution: "deep-equal@npm:0.0.0" @@ -3508,7 +3547,7 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.19.0, es-abstract@npm:^1.19.1": +"es-abstract@npm:^1.18.5, es-abstract@npm:^1.19.0, es-abstract@npm:^1.19.1": version: 1.19.1 resolution: "es-abstract@npm:1.19.1" dependencies: @@ -3536,6 +3575,22 @@ __metadata: languageName: node linkType: hard +"es-get-iterator@npm:^1.1.1": + version: 1.1.2 + resolution: "es-get-iterator@npm:1.1.2" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.1.0 + has-symbols: ^1.0.1 + is-arguments: ^1.1.0 + is-map: ^2.0.2 + is-set: ^2.0.2 + is-string: ^1.0.5 + isarray: ^2.0.5 + checksum: f75e66acb6a45686fa08b3ade9c9421a70d36a0c43ed4363e67f4d7aab2226cb73dd977cb48abbaf75721b946d3cd810682fcf310c7ad0867802fbf929b17dcf + languageName: node + linkType: hard + "es-to-primitive@npm:^1.2.1": version: 1.2.1 resolution: "es-to-primitive@npm:1.2.1" @@ -4587,6 +4642,13 @@ __metadata: languageName: node linkType: hard +"foreach@npm:^2.0.5": + version: 2.0.5 + resolution: "foreach@npm:2.0.5" + checksum: dab4fbfef0b40b69ee5eab81bcb9626b8fa8b3469c8cfa26480f3e5e1ee08c40eae07048c9a967c65aeda26e774511ccc70b3f10a604c01753c6ef24361f0fc8 + languageName: node + linkType: hard + "form-data@npm:^3.0.0": version: 3.0.1 resolution: "form-data@npm:3.0.1" @@ -4723,7 +4785,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.0, get-intrinsic@npm:^1.1.1": +"get-intrinsic@npm:^1.0.1, get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.0, get-intrinsic@npm:^1.1.1": version: 1.1.1 resolution: "get-intrinsic@npm:1.1.1" dependencies: @@ -5259,6 +5321,16 @@ __metadata: languageName: node linkType: hard +"is-arguments@npm:^1.0.4, is-arguments@npm:^1.1.0": + version: 1.1.1 + resolution: "is-arguments@npm:1.1.1" + dependencies: + call-bind: ^1.0.2 + has-tostringtag: ^1.0.0 + checksum: 7f02700ec2171b691ef3e4d0e3e6c0ba408e8434368504bb593d0d7c891c0dbfda6d19d30808b904a6cb1929bca648c061ba438c39f296c2a8ca083229c49f27 + languageName: node + linkType: hard + "is-arrayish@npm:^0.2.1": version: 0.2.1 resolution: "is-arrayish@npm:0.2.1" @@ -5341,7 +5413,7 @@ __metadata: languageName: node linkType: hard -"is-date-object@npm:^1.0.1": +"is-date-object@npm:^1.0.1, is-date-object@npm:^1.0.2": version: 1.0.5 resolution: "is-date-object@npm:1.0.5" dependencies: @@ -5397,6 +5469,13 @@ __metadata: languageName: node linkType: hard +"is-map@npm:^2.0.1, is-map@npm:^2.0.2": + version: 2.0.2 + resolution: "is-map@npm:2.0.2" + checksum: ace3d0ecd667bbdefdb1852de601268f67f2db725624b1958f279316e13fecb8fa7df91fd60f690d7417b4ec180712f5a7ee967008e27c65cfd475cc84337728 + languageName: node + linkType: hard + "is-negative-zero@npm:^2.0.1": version: 2.0.2 resolution: "is-negative-zero@npm:2.0.2" @@ -5448,7 +5527,7 @@ __metadata: languageName: node linkType: hard -"is-regex@npm:^1.1.4": +"is-regex@npm:^1.1.1, is-regex@npm:^1.1.4": version: 1.1.4 resolution: "is-regex@npm:1.1.4" dependencies: @@ -5458,6 +5537,13 @@ __metadata: languageName: node linkType: hard +"is-set@npm:^2.0.1, is-set@npm:^2.0.2": + version: 2.0.2 + resolution: "is-set@npm:2.0.2" + checksum: b64343faf45e9387b97a6fd32be632ee7b269bd8183701f3b3f5b71a7cf00d04450ed8669d0bd08753e08b968beda96fca73a10fd0ff56a32603f64deba55a57 + languageName: node + linkType: hard + "is-shared-array-buffer@npm:^1.0.1": version: 1.0.1 resolution: "is-shared-array-buffer@npm:1.0.1" @@ -5490,6 +5576,19 @@ __metadata: languageName: node linkType: hard +"is-typed-array@npm:^1.1.7": + version: 1.1.8 + resolution: "is-typed-array@npm:1.1.8" + dependencies: + available-typed-arrays: ^1.0.5 + call-bind: ^1.0.2 + es-abstract: ^1.18.5 + foreach: ^2.0.5 + has-tostringtag: ^1.0.0 + checksum: aa0f9f0716e19e2fb8aef69e69e4205479d25ace778e2339fc910948115cde4b0d9aff9d5d1e8b80f09a5664998278e05e54ad3dc9cb12cefcf86db71084ed00 + languageName: node + linkType: hard + "is-typedarray@npm:^1.0.0": version: 1.0.0 resolution: "is-typedarray@npm:1.0.0" @@ -5497,6 +5596,13 @@ __metadata: languageName: node linkType: hard +"is-weakmap@npm:^2.0.1": + version: 2.0.1 + resolution: "is-weakmap@npm:2.0.1" + checksum: 1222bb7e90c32bdb949226e66d26cb7bce12e1e28e3e1b40bfa6b390ba3e08192a8664a703dff2a00a84825f4e022f9cd58c4599ff9981ab72b1d69479f4f7f6 + languageName: node + linkType: hard + "is-weakref@npm:^1.0.1": version: 1.0.2 resolution: "is-weakref@npm:1.0.2" @@ -5506,6 +5612,16 @@ __metadata: languageName: node linkType: hard +"is-weakset@npm:^2.0.1": + version: 2.0.2 + resolution: "is-weakset@npm:2.0.2" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.1.1 + checksum: 5d8698d1fa599a0635d7ca85be9c26d547b317ed8fd83fc75f03efbe75d50001b5eececb1e9971de85fcde84f69ae6f8346bc92d20d55d46201d328e4c74a367 + languageName: node + linkType: hard + "is-yarn-global@npm:^0.3.0": version: 0.3.0 resolution: "is-yarn-global@npm:0.3.0" @@ -5513,6 +5629,13 @@ __metadata: languageName: node linkType: hard +"isarray@npm:^2.0.5": + version: 2.0.5 + resolution: "isarray@npm:2.0.5" + checksum: bd5bbe4104438c4196ba58a54650116007fa0262eccef13a4c55b2e09a5b36b59f1e75b9fcc49883dd9d4953892e6fc007eef9e9155648ceea036e184b0f930a + languageName: node + linkType: hard + "isarray@npm:~1.0.0": version: 1.0.0 resolution: "isarray@npm:1.0.0" @@ -7002,6 +7125,16 @@ __metadata: languageName: node linkType: hard +"object-is@npm:^1.1.4": + version: 1.1.5 + resolution: "object-is@npm:1.1.5" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.3 + checksum: 989b18c4cba258a6b74dc1d74a41805c1a1425bce29f6cabb50dcb1a6a651ea9104a1b07046739a49a5bb1bc49727bcb00efd5c55f932f6ea04ec8927a7901fe + languageName: node + linkType: hard + "object-keys@npm:^1.0.12, object-keys@npm:^1.1.1": version: 1.1.1 resolution: "object-keys@npm:1.1.1" @@ -7703,7 +7836,7 @@ __metadata: languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.3.1": +"regexp.prototype.flags@npm:^1.3.0, regexp.prototype.flags@npm:^1.3.1": version: 1.3.1 resolution: "regexp.prototype.flags@npm:1.3.1" dependencies: @@ -8099,7 +8232,7 @@ __metadata: languageName: node linkType: hard -"side-channel@npm:^1.0.4": +"side-channel@npm:^1.0.3, side-channel@npm:^1.0.4": version: 1.0.4 resolution: "side-channel@npm:1.0.4" dependencies: @@ -9176,7 +9309,7 @@ __metadata: languageName: node linkType: hard -"which-boxed-primitive@npm:^1.0.2": +"which-boxed-primitive@npm:^1.0.1, which-boxed-primitive@npm:^1.0.2": version: 1.0.2 resolution: "which-boxed-primitive@npm:1.0.2" dependencies: @@ -9189,6 +9322,32 @@ __metadata: languageName: node linkType: hard +"which-collection@npm:^1.0.1": + version: 1.0.1 + resolution: "which-collection@npm:1.0.1" + dependencies: + is-map: ^2.0.1 + is-set: ^2.0.1 + is-weakmap: ^2.0.1 + is-weakset: ^2.0.1 + checksum: c815bbd163107ef9cb84f135e6f34453eaf4cca994e7ba85ddb0d27cea724c623fae2a473ceccfd5549c53cc65a5d82692de418166df3f858e1e5dc60818581c + languageName: node + linkType: hard + +"which-typed-array@npm:^1.1.2": + version: 1.1.7 + resolution: "which-typed-array@npm:1.1.7" + dependencies: + available-typed-arrays: ^1.0.5 + call-bind: ^1.0.2 + es-abstract: ^1.18.5 + foreach: ^2.0.5 + has-tostringtag: ^1.0.0 + is-typed-array: ^1.1.7 + checksum: 147837cf5866e36b6b2e427731709e02f79f1578477cbde68ed773a5307520a6cb6836c73c79c30690a473266ee59010b83b6d9b25d8d677a40ff77fb37a8a84 + languageName: node + linkType: hard + "which@npm:^2.0.1, which@npm:^2.0.2": version: 2.0.2 resolution: "which@npm:2.0.2" -- cgit v1.2.3-54-g00ecf