From 0b74e03466153c9b0538d5604c02a09f84dd18ed Mon Sep 17 00:00:00 2001 From: Mosh Feu Date: Sat, 26 Oct 2024 01:49:12 +0200 Subject: [PATCH] fix: copy files & better logging and error handling (#167) This pull request includes several changes to improve error handling, logging, and code organization in the `src/providers/foldersCompareProvider.ts` and related files. The most important [change](diffhunk://#diff-4b422bda5a0007c1c97c9190d7300c608819eb4605d55a172cce02d3ac4ddb71L270-L274) is building the `from` and `to` paths - got rid of the string manipulations, which often lead to... cross platform issues _ fix #162 fix #164 --- src/providers/foldersCompareProvider.ts | 19 ++++++++----------- src/services/globalState.ts | 6 ++++++ src/services/logger.ts | 13 ++++++++++++- .../includeExcludeFilesGetter.testkit.ts | 14 +++++++++++++- src/utils/ui.ts | 16 ++++------------ 5 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/providers/foldersCompareProvider.ts b/src/providers/foldersCompareProvider.ts index 95c789b..2adc750 100644 --- a/src/providers/foldersCompareProvider.ts +++ b/src/providers/foldersCompareProvider.ts @@ -10,7 +10,6 @@ import { ProgressLocation, commands, Uri, - Command, } from 'vscode'; import * as path from 'path'; import { copySync, removeSync } from 'fs-extra'; @@ -30,8 +29,8 @@ import { ViewOnlyProvider } from './viewOnlyProvider'; import { getConfiguration } from '../services/configuration'; import { setContext } from '../context/global'; import { HAS_FOLDERS } from '../constants/contextKeys'; -import { log } from '../services/logger'; -import { showErrorMessageWithMoreInfo, showInfoMessageWithTimeout } from '../utils/ui'; +import * as logger from '../services/logger'; +import { showErrorMessage, showErrorMessageWithMoreInfo, showInfoMessageWithTimeout } from '../utils/ui'; import { showUnaccessibleWarning } from '../services/validators'; import { uiContext, type DiffViewMode } from '../context/ui'; @@ -208,7 +207,7 @@ export class CompareFoldersProvider implements TreeDataProvider { } this.updateUI(); } catch (error) { - log(error); + logger.error(error); } }; @@ -267,15 +266,13 @@ export class CompareFoldersProvider implements TreeDataProvider { const [folder1Path, folder2Path] = pathContext.getPaths(); const [from, to] = direction === 'to-compared' ? [folder1Path, folder2Path] : [folder2Path, folder1Path]; - const { root, dir, base } = path.parse(from); - const pathWithoutSchema = dir.replace(root, ''); - const fileCopiedRelativePath = uri.fsPath.replace(pathWithoutSchema, '').replace(base, ''); - const fromPath = path.join(from, fileCopiedRelativePath); - const toPath = path.join(to, fileCopiedRelativePath); + const fromPath = uri.fsPath; + const toPath = path.join(to, path.relative(from, fromPath)); copySync(fromPath, toPath); this.refresh(false); } catch (error) { - log(error); + showErrorMessage('Failed to copy file', error); + logger.error(error); } } @@ -310,7 +307,7 @@ export class CompareFoldersProvider implements TreeDataProvider { return children; } catch (error) { - log(error); + logger.error(error); return []; } } diff --git a/src/services/globalState.ts b/src/services/globalState.ts index 9a31ed2..9f8e82c 100644 --- a/src/services/globalState.ts +++ b/src/services/globalState.ts @@ -3,10 +3,16 @@ import { log } from './logger'; class GlobalState { private readonly KEY = 'compareFolders.paths'; + private readonly VERSION_KEY = 'compareFolders.version'; private globalState?: Memento; init(context: ExtensionContext) { this.globalState = context.globalState; + this.globalState.update(this.VERSION_KEY, context.extension.packageJSON.version); + } + + get extensionVersion() { + return this.globalState?.get(this.VERSION_KEY); } updatePaths(path1: string, path2: string) { diff --git a/src/services/logger.ts b/src/services/logger.ts index 170d453..57c622f 100644 --- a/src/services/logger.ts +++ b/src/services/logger.ts @@ -4,7 +4,7 @@ import { type CompareOptions } from '../types'; const logger = window.createOutputChannel('Compare Folders'); -export function log(...data: (object | string | undefined | unknown)[]) { +function printData(...data: (object | string | undefined | unknown)[]) { data.forEach(item => { if (typeof item === 'string') { logger.appendLine(item); @@ -12,6 +12,17 @@ export function log(...data: (object | string | undefined | unknown)[]) { logger.appendLine(JSON.stringify(item, null, 2)); } }); +} + +export function error(...data: (object | string | undefined | unknown)[]) { + logger.appendLine('====error===='); + printData(...data); + console.error(...data); + logger.appendLine('==============='); +} + +export function log(...data: (object | string | undefined | unknown)[]) { + printData(...data); console.log(...data); } diff --git a/src/test/suite/includeExcludeFilesGetter/includeExcludeFilesGetter.testkit.ts b/src/test/suite/includeExcludeFilesGetter/includeExcludeFilesGetter.testkit.ts index 28e870b..0a3b8ad 100644 --- a/src/test/suite/includeExcludeFilesGetter/includeExcludeFilesGetter.testkit.ts +++ b/src/test/suite/includeExcludeFilesGetter/includeExcludeFilesGetter.testkit.ts @@ -1,4 +1,4 @@ -import { ExtensionContext, workspace, WorkspaceConfiguration } from 'vscode'; +import { ExtensionContext, Uri, workspace, WorkspaceConfiguration } from 'vscode'; import { IConfigurations } from '../../../services/configuration'; import * as fs from '../../../services/fs'; @@ -28,6 +28,18 @@ const defaultSettings: Partial = { const contextFactory = (): Partial => { const state: Record = {}; return { + extension: { + id: 'test', + extensionPath: '/', + extensionKind: 1, + extensionUri: Uri.parse('/'), + isActive: true, + activate: () => Promise.resolve(), + exports: {}, + packageJSON: { + version: '1.0.0', + }, + }, globalState: { keys: () => Object.keys(state), setKeysForSync: () => {}, diff --git a/src/utils/ui.ts b/src/utils/ui.ts index d6e2bd7..0d96f54 100644 --- a/src/utils/ui.ts +++ b/src/utils/ui.ts @@ -1,8 +1,7 @@ import { window, ProgressLocation, env, Uri, version } from 'vscode'; -import { join } from 'path'; -import { readFileSync } from 'fs'; import os from 'os'; -import { log } from '../services/logger'; +import * as logger from '../services/logger'; +import { globalState } from '../services/globalState'; export function showInfoMessageWithTimeout(message: string, timeout: number = 3000) { const upTo = timeout / 10; @@ -44,7 +43,7 @@ export async function showErrorMessage(message: string, error: any) { **System Info** Editor version: ${version} -Extension version: ${getExtensionVersion()} +Extension version: ${globalState.extensionVersion} OS: ${os.platform()} ${os.release()} **Stack** @@ -57,7 +56,7 @@ ${error.stack || error.message || error} const uri = Uri.parse(url); env.openExternal(uri); } catch (error) { - log(error); + logger.log(error); } } } @@ -69,10 +68,3 @@ export async function showErrorMessageWithMoreInfo(message: string, link: string env.openExternal(Uri.parse(link)); } } - -function getExtensionVersion() { - const { version: extVersion } = JSON.parse( - readFileSync(join(__dirname, '..', 'package.json'), { encoding: 'utf8' }) - ); - return extVersion; -}