From 9a8616f05ed74da5d4b1e91a4202ee58e2625f6c Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 4 Aug 2021 08:02:21 -0400 Subject: [PATCH] Create c&p folder before starting kube sync (#3428) Signed-off-by: Sebastian Malton --- src/main/catalog-sources/kubeconfig-sync.ts | 114 +++++++++++--------- src/main/index.ts | 4 +- 2 files changed, 64 insertions(+), 54 deletions(-) diff --git a/src/main/catalog-sources/kubeconfig-sync.ts b/src/main/catalog-sources/kubeconfig-sync.ts index 8a628e97e6..668dad2884 100644 --- a/src/main/catalog-sources/kubeconfig-sync.ts +++ b/src/main/catalog-sources/kubeconfig-sync.ts @@ -22,10 +22,9 @@ import { action, observable, IComputedValue, computed, ObservableMap, runInAction, makeObservable, observe } from "mobx"; import type { CatalogEntity } from "../../common/catalog"; import { catalogEntityRegistry } from "../../main/catalog"; -import { watch } from "chokidar"; +import { FSWatcher, watch } from "chokidar"; import fs from "fs"; import path from "path"; -import fse from "fs-extra"; import type stream from "stream"; import { Disposer, ExtendedObservableMap, iter, Singleton, storedKubeConfigFolder } from "../../common/utils"; import logger from "../logger"; @@ -117,20 +116,15 @@ export class KubeconfigSyncManager extends Singleton { } @action - protected async startNewSync(filePath: string): Promise { + protected startNewSync(filePath: string): void { if (this.sources.has(filePath)) { // don't start a new sync if we already have one return void logger.debug(`${logPrefix} already syncing file/folder`, { filePath }); } - try { - this.sources.set(filePath, await watchFileChanges(filePath)); - - logger.info(`${logPrefix} starting sync of file/folder`, { filePath }); - logger.debug(`${logPrefix} ${this.sources.size} files/folders watched`, { files: Array.from(this.sources.keys()) }); - } catch (error) { - logger.warn(`${logPrefix} failed to start watching changes: ${error}`); - } + this.sources.set(filePath, watchFileChanges(filePath)); + logger.info(`${logPrefix} starting sync of file/folder`, { filePath }); + logger.debug(`${logPrefix} ${this.sources.size} files/folders watched`, { files: Array.from(this.sources.keys()) }); } @action @@ -274,55 +268,69 @@ function diffChangedConfig(filePath: string, source: RootSource): Disposer { return cleanup; } -async function watchFileChanges(filePath: string): Promise<[IComputedValue, Disposer]> { - const stat = await fse.stat(filePath); // traverses symlinks, is a race condition - const isFolderSync = stat.isDirectory(); - const watcher = watch(filePath, { - followSymlinks: true, - depth: isFolderSync ? 0 : 1, // DIRs works with 0 but files need 1 (bug: https://github.com/paulmillr/chokidar/issues/1095) - disableGlobbing: true, - ignorePermissionErrors: true, - usePolling: false, - awaitWriteFinish: { - pollInterval: 100, - stabilityThreshold: 1000, - }, - }); +function watchFileChanges(filePath: string): [IComputedValue, Disposer] { const rootSource = new ExtendedObservableMap>(); const derivedSource = computed(() => Array.from(iter.flatMap(rootSource.values(), from => iter.map(from.values(), child => child[1])))); - const cleanupFns = new Map(); - watcher - .on("change", (childFilePath) => { - const cleanup = cleanupFns.get(childFilePath); + let watcher: FSWatcher; - if (!cleanup) { - // file was previously ignored, do nothing - return void logger.debug(`${logPrefix} ${inspect(childFilePath)} that should have been previously ignored has changed. Doing nothing`); - } + (async () => { + try { + const stat = await fs.promises.stat(filePath); + const isFolderSync = stat.isDirectory(); + const cleanupFns = new Map(); - cleanup(); - cleanupFns.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrInsert(childFilePath, observable.map))); - }) - .on("add", (childFilePath) => { - if (isFolderSync) { - const fileName = path.basename(childFilePath); + watcher = watch(filePath, { + followSymlinks: true, + depth: isFolderSync ? 0 : 1, // DIRs works with 0 but files need 1 (bug: https://github.com/paulmillr/chokidar/issues/1095) + disableGlobbing: true, + ignorePermissionErrors: true, + usePolling: false, + awaitWriteFinish: { + pollInterval: 100, + stabilityThreshold: 1000, + }, + atomic: 150, // for "atomic writes" + }); - for (const ignoreGlob of ignoreGlobs) { - if (ignoreGlob.matcher.test(fileName)) { - return void logger.info(`${logPrefix} ignoring ${inspect(childFilePath)} due to ignore glob: ${ignoreGlob.rawGlob}`); + watcher + .on("change", (childFilePath) => { + const cleanup = cleanupFns.get(childFilePath); + + if (!cleanup) { + // file was previously ignored, do nothing + return void logger.debug(`${logPrefix} ${inspect(childFilePath)} that should have been previously ignored has changed. Doing nothing`); } - } - } - cleanupFns.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrInsert(childFilePath, observable.map))); - }) - .on("unlink", (childFilePath) => { - cleanupFns.get(childFilePath)?.(); - cleanupFns.delete(childFilePath); - rootSource.delete(childFilePath); - }) - .on("error", error => logger.error(`${logPrefix} watching file/folder failed: ${error}`, { filePath })); + cleanup(); + cleanupFns.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrInsert(childFilePath, observable.map))); + }) + .on("add", (childFilePath) => { + if (isFolderSync) { + const fileName = path.basename(childFilePath); - return [derivedSource, () => watcher.close()]; + for (const ignoreGlob of ignoreGlobs) { + if (ignoreGlob.matcher.test(fileName)) { + return void logger.info(`${logPrefix} ignoring ${inspect(childFilePath)} due to ignore glob: ${ignoreGlob.rawGlob}`); + } + } + } + + cleanupFns.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrInsert(childFilePath, observable.map))); + }) + .on("unlink", (childFilePath) => { + cleanupFns.get(childFilePath)?.(); + cleanupFns.delete(childFilePath); + rootSource.delete(childFilePath); + }) + .on("error", error => logger.error(`${logPrefix} watching file/folder failed: ${error}`, { filePath })); + } catch (error) { + console.log(error.stack); + logger.warn(`${logPrefix} failed to start watching changes: ${error}`); + } + })(); + + return [derivedSource, () => { + watcher?.close(); + }]; } diff --git a/src/main/index.ts b/src/main/index.ts index a5116cfdb0..66e336dedc 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -60,6 +60,7 @@ import { WeblinkStore } from "../common/weblink-store"; import { ExtensionsStore } from "../extensions/extensions-store"; import { FilesystemProvisionerStore } from "./extension-filesystem"; import { SentryInit } from "../common/sentry"; +import { ensureDir } from "fs-extra"; // This has to be called before start using winton-based logger // For example, before any logger.log @@ -210,8 +211,9 @@ app.on("ready", async () => { windowManager.ensureMainWindow(); } - ipcMainOn(IpcRendererNavigationEvents.LOADED, () => { + ipcMainOn(IpcRendererNavigationEvents.LOADED, async () => { cleanup.push(pushCatalogToRenderer(catalogEntityRegistry)); + await ensureDir(ClusterStore.storedKubeConfigFolder); KubeconfigSyncManager.getInstance().startSync(); startUpdateChecking(); LensProtocolRouterMain.getInstance().rendererLoaded = true;