From a5cc26a022b35f0201ce0e3d1a75e214fe6d9e50 Mon Sep 17 00:00:00 2001 From: Rajpreet Singh <63117988+rajpreet-s@users.noreply.github.com> Date: Mon, 29 Jul 2024 18:40:15 +0530 Subject: [PATCH] 12 hover provider for manifest files (#26) * updated globalState and refactored * fixed undefined of repoData * added scan for manifest when user creates a new file --- src/commands/debrickedCommand.ts | 4 +- src/constants/organization.ts | 1 - src/extension.ts | 7 ++- src/helpers/AuthHelper.ts | 17 ++++-- src/helpers/commandHelper.ts | 4 +- src/helpers/commonHelper.ts | 3 +- src/helpers/gitHelper.ts | 20 +++---- src/helpers/globalState.ts | 19 ++---- src/helpers/loggerHelper.ts | 2 +- src/helpers/manifestWatcher.ts | 92 ++++++++++++++++++++++++++++++ src/helpers/terminalHelper.ts | 2 +- src/services/baseCommandService.ts | 15 +++-- src/services/fileService.ts | 30 ++++++---- src/services/scanService.ts | 60 +------------------ 14 files changed, 160 insertions(+), 116 deletions(-) create mode 100644 src/helpers/manifestWatcher.ts diff --git a/src/commands/debrickedCommand.ts b/src/commands/debrickedCommand.ts index 0fe44a9..d8336dd 100644 --- a/src/commands/debrickedCommand.ts +++ b/src/commands/debrickedCommand.ts @@ -2,6 +2,7 @@ import * as vscode from "vscode"; import { DebrickedCommands, Organization } from "../constants/index"; import { BaseCommandService, ScanService, FileService } from "../services"; import { Logger, GlobalState, Common, ErrorHandler } from "../helpers"; +import { ManifestWatcher } from "helpers/manifestWatcher"; export class DebrickedCommand { private static get globalState(): GlobalState { @@ -41,8 +42,7 @@ export class DebrickedCommand { } // Add file watcher for all files found from 'debricked files find' - const foundFiles = (await FileService.findFilesService()) || []; - await ScanService.addWatcherToManifestFiles(foundFiles, context); + await ManifestWatcher.getInstance().setupWatchers(context); } catch (error) { ErrorHandler.handleError(error); } finally { diff --git a/src/constants/organization.ts b/src/constants/organization.ts index 0ee5413..08630ed 100644 --- a/src/constants/organization.ts +++ b/src/constants/organization.ts @@ -52,7 +52,6 @@ export class Organization { static readonly seqIdKey = "sequenceID"; static readonly access = "access"; static readonly accessTokenKey = "accessToken"; - static readonly repoDataKey = "repoData"; static readonly bearer = "bearer"; static readonly bearerTokenKey = "bearerToken"; static readonly userId = "userId"; diff --git a/src/extension.ts b/src/extension.ts index 5d8a2ff..fb16c86 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -25,6 +25,8 @@ export async function activate(context: vscode.ExtensionContext) { GlobalState.initialize(context); const globalState = GlobalState.getInstance(); + // For dev - Clears the globalData - uncomment to clear the globalData + // await globalState.clearAllGlobalData(); globalState.setGlobalData(Organization.seqIdKey, Common.generateHashCode()); progress.report({ message: "Activating VS Code Extension", @@ -42,10 +44,9 @@ export async function activate(context: vscode.ExtensionContext) { vscode.window.registerTreeDataProvider(Organization.debrickedCommand, debCommandsProvider); const currentVersion = await BaseCommandService.getCurrentExtensionVersion(); - const storedVersion = globalState.getGlobalData(Organization.extensionVersionKey, Organization.baseVersion); - const isFirstActivation = globalState.getGlobalData(Organization.isFirstActivationKey, true); + const debrickedData: any = globalState.getGlobalData(Organization.debrickedDataKey, {}); - if (currentVersion !== storedVersion || isFirstActivation) { + if (currentVersion !== debrickedData.extensionVersion || debrickedData.isFirstActivation) { globalState.setGlobalData(Organization.seqIdKey, Common.generateHashCode()); progress.report({ message: "Installing Debricked cli", diff --git a/src/helpers/AuthHelper.ts b/src/helpers/AuthHelper.ts index 5a5fb06..42b9cc4 100644 --- a/src/helpers/AuthHelper.ts +++ b/src/helpers/AuthHelper.ts @@ -13,7 +13,8 @@ export class AuthHelper { static async getToken(useDefaultToken: boolean = true, tokenKey: "access" | "bearer"): Promise { try { let token: string | undefined; - const TOKEN_KEY = tokenKey === "access" ? Organization.accessTokenKey : Organization.bearerTokenKey; + const TOKEN_KEY = + tokenKey === Organization.access ? Organization.accessTokenKey : Organization.bearerTokenKey; const defaultAccessToken: any = await AuthHelper.globalState.getSecretData(TOKEN_KEY); if (useDefaultToken) { @@ -25,19 +26,23 @@ export class AuthHelper { Logger.logInfo("InputBox Opened for tokens"); token = await ShowInputBoxHelper.promptForInput({ - prompt: tokenKey === "access" ? Messages.ENTER_ACCESS_TOKEN : Messages.ENTER_BEARER_TOKEN, + prompt: + tokenKey === Organization.access ? Messages.ENTER_ACCESS_TOKEN : Messages.ENTER_BEARER_TOKEN, ignoreFocusOut: true, password: true, - title: tokenKey === "access" ? Messages.ACCESS_TOKEN : Messages.BEARER_TOKEN, - placeHolder: tokenKey === "access" ? Messages.ENTER_ACCESS_TOKEN : Messages.ENTER_BEARER_TOKEN, + title: tokenKey === Organization.access ? Messages.ACCESS_TOKEN : Messages.BEARER_TOKEN, + placeHolder: + tokenKey === Organization.access ? Messages.ENTER_ACCESS_TOKEN : Messages.ENTER_BEARER_TOKEN, }); if (token) { await AuthHelper.globalState.setSecretData(TOKEN_KEY, token); - const message = tokenKey === "access" ? Messages.ACCESS_TOKEN_SAVED : Messages.BEARER_TOKEN_SAVED; + const message = + tokenKey === Organization.access ? Messages.ACCESS_TOKEN_SAVED : Messages.BEARER_TOKEN_SAVED; StatusBarMessageHelper.showInformationMessage(message); } else { - const message = tokenKey === "access" ? Messages.ACCESS_TOKEN_RQD : Messages.BEARER_TOKEN_RQD; + const message = + tokenKey === Organization.access ? Messages.ACCESS_TOKEN_RQD : Messages.BEARER_TOKEN_RQD; throw new Error(message); } } diff --git a/src/helpers/commandHelper.ts b/src/helpers/commandHelper.ts index 4a5165d..ede6938 100644 --- a/src/helpers/commandHelper.ts +++ b/src/helpers/commandHelper.ts @@ -10,7 +10,7 @@ export class Command { ): Promise { if (accessTokenRequired) { const flags = DebrickedCommands.getCommandSpecificFlags("Debricked") || []; - const accessToken = await AuthHelper.getToken(true, "access"); + const accessToken = await AuthHelper.getToken(true, Organization.access); if (accessToken) { cmdParams.push(flags[0].flag); @@ -57,7 +57,7 @@ export class Command { if (accessTokenRequired) { const flags = DebrickedCommands.getCommandSpecificFlags("Debricked") || []; - const accessToken = await AuthHelper.getToken(true, "access"); + const accessToken = await AuthHelper.getToken(true, Organization.access); if (accessToken) { command = `${command} ${flags[0].flag} ${accessToken}`; diff --git a/src/helpers/commonHelper.ts b/src/helpers/commonHelper.ts index f3d6bdd..8170a85 100644 --- a/src/helpers/commonHelper.ts +++ b/src/helpers/commonHelper.ts @@ -35,8 +35,9 @@ export class Common { */ public static async checkUserId(): Promise { try { - const userId = await Common.globalState.getGlobalDataByKey( + const userId = await Common.globalState.getGlobalData( Organization.debrickedDataKey, + "", Organization.userId, ); if (!userId) { diff --git a/src/helpers/gitHelper.ts b/src/helpers/gitHelper.ts index 2c49776..f6bd0db 100644 --- a/src/helpers/gitHelper.ts +++ b/src/helpers/gitHelper.ts @@ -1,4 +1,4 @@ -import { MessageStatus, Organization } from "../constants/index"; +import { MessageStatus } from "../constants/index"; import { Command, GlobalState, Logger, ShowInputBoxHelper } from "../helpers"; export class GitHelper { @@ -60,21 +60,21 @@ export class GitHelper { public static async setupGit(): Promise { const currentRepo = await GitHelper.getUpstream(); Logger.logMessageByStatus(MessageStatus.INFO, `Current repository: ${currentRepo}`); - const repoData: any = await GitHelper.globalState.getGlobalData(Organization.repoDataKey, {}); const selectedRepoName: string = await GitHelper.getRepositoryName(); + let repoData: any = await GitHelper.globalState.getGlobalData(selectedRepoName, {}); if (selectedRepoName) { - if (!repoData[selectedRepoName]) { - repoData[selectedRepoName] = {}; + if (!repoData) { + repoData = {}; } - repoData[selectedRepoName].repositoryName = selectedRepoName; + repoData.repositoryName = selectedRepoName; } - repoData[selectedRepoName].userName = await GitHelper.getUsername(); - repoData[selectedRepoName].email = await GitHelper.getEmail(); - repoData[selectedRepoName].currentBranch = await GitHelper.getCurrentBranch(); - repoData[selectedRepoName].commitID = await GitHelper.getCommitHash(); + repoData.userName = await GitHelper.getUsername(); + repoData.email = await GitHelper.getEmail(); + repoData.currentBranch = await GitHelper.getCurrentBranch(); + repoData.commitID = await GitHelper.getCommitHash(); - await GitHelper.globalState.setGlobalData(Organization.repoDataKey, repoData); + await GitHelper.globalState.setGlobalData(selectedRepoName, repoData); } } diff --git a/src/helpers/globalState.ts b/src/helpers/globalState.ts index f2d0edd..faaa585 100644 --- a/src/helpers/globalState.ts +++ b/src/helpers/globalState.ts @@ -25,29 +25,18 @@ export class GlobalState { return this.context.globalState.update(key, JSON.stringify(data)); } - public getGlobalData(key: string, defaultValue?: T): T | undefined { + public getGlobalData(key: string, defaultValue?: any, attribute?: string) { const storedValue = this.context.globalState.get(key); if (storedValue !== undefined) { - try { - return JSON.parse(storedValue) as T; - } catch (error) { - Logger.logMessageByStatus(MessageStatus.ERROR, `Error parsing stored value for key ${key}: ${error}`); - } - } - return defaultValue; - } - - public getGlobalDataByKey(globalKey: string, key: string) { - const storedValue = this.context.globalState.get(globalKey); - if (storedValue) { try { const data = JSON.parse(storedValue); - return data[key]; + + return attribute ? data[attribute] : data; } catch (error) { Logger.logMessageByStatus(MessageStatus.ERROR, `Error parsing stored value for key ${key}: ${error}`); } } - return storedValue; + return defaultValue; } public clearGlobalData(...keys: string[]): Thenable[] { diff --git a/src/helpers/loggerHelper.ts b/src/helpers/loggerHelper.ts index 354a22d..7b04656 100644 --- a/src/helpers/loggerHelper.ts +++ b/src/helpers/loggerHelper.ts @@ -32,7 +32,7 @@ export class Logger { private static async writeLog(message: string) { const timestamp = new Date().toISOString(); - const userId = await Logger.globalState.getGlobalDataByKey(Organization.debrickedDataKey, Organization.userId); + const userId = await Logger.globalState.getGlobalData(Organization.debrickedDataKey, "", Organization.userId); const sequenceId = Logger.globalState.getGlobalData(Organization.seqIdKey) ? `[seq_id:${Logger.globalState.getGlobalData(Organization.seqIdKey)}]` : ""; diff --git a/src/helpers/manifestWatcher.ts b/src/helpers/manifestWatcher.ts new file mode 100644 index 0000000..7204a17 --- /dev/null +++ b/src/helpers/manifestWatcher.ts @@ -0,0 +1,92 @@ +import * as vscode from "vscode"; +import * as path from "path"; +import { MessageStatus, Organization, DebrickedCommands } from "../constants"; +import { ScanService, FileService } from "services"; +import { Common, ErrorHandler, Logger, StatusMessage, StatusBarMessageHelper, GlobalState } from "../helpers"; + +export class ManifestWatcher { + private static instance: ManifestWatcher; + private globalWatcher: vscode.FileSystemWatcher | null = null; + private manifestWatchers: vscode.FileSystemWatcher[] = []; + + private constructor() {} + private static get globalState(): GlobalState { + return GlobalState.getInstance(); + } + + public static getInstance(): ManifestWatcher { + if (!ManifestWatcher.instance) { + ManifestWatcher.instance = new ManifestWatcher(); + } + return ManifestWatcher.instance; + } + + public async setupWatchers(context: vscode.ExtensionContext): Promise { + try { + Logger.logMessageByStatus(MessageStatus.INFO, "Setting up Manifest File Watchers"); + ManifestWatcher.globalState.setGlobalData(Organization.seqIdKey, Common.generateHashCode()); + + // Setup global watcher if not already set + if (!this.globalWatcher) { + this.setupGlobalWatcher(context); + } + + const filesToScan = (await FileService.findFilesService()) || []; + await this.updateManifestWatchers(filesToScan, context); + + StatusBarMessageHelper.setStatusBarMessage( + StatusMessage.getStatusMessage(MessageStatus.COMPLETE, DebrickedCommands.SCAN.cli_command), + ); + } catch (error: any) { + ErrorHandler.handleError(error); + } finally { + StatusBarMessageHelper.setStatusBarMessage( + StatusMessage.getStatusMessage(MessageStatus.FINISHED, DebrickedCommands.SCAN.cli_command), + ); + Logger.logMessageByStatus(MessageStatus.INFO, "Watchers for Manifest files are now ready to scan."); + } + } + + private setupGlobalWatcher(context: vscode.ExtensionContext): void { + this.globalWatcher = vscode.workspace.createFileSystemWatcher("**/*"); + this.globalWatcher.onDidCreate(async () => { + await this.setupWatchers(context); + }); + context.subscriptions.push(this.globalWatcher); + } + + private async updateManifestWatchers(filesToScan: string[], context: vscode.ExtensionContext): Promise { + // Dispose old watchers + this.manifestWatchers.forEach((watcher) => watcher.dispose()); + this.manifestWatchers = []; + + if (filesToScan.length > 0) { + const filesPattern = new RegExp(filesToScan.map((file) => `^${file}$`).join("|")); + + vscode.window.onDidChangeActiveTextEditor((editor) => { + if (editor && filesPattern.test(path.basename(editor.document.fileName))) { + vscode.commands.executeCommand("setContext", "debrickedFilesToScan", true); + } else { + vscode.commands.executeCommand("setContext", "debrickedFilesToScan", false); + } + }); + + filesToScan.forEach((file: string) => { + const watcher = vscode.workspace.createFileSystemWatcher(`**/${file}`); + const runScan = async () => { + await ScanService.scanService(); + }; + + watcher.onDidChange(runScan); + watcher.onDidCreate(runScan); + watcher.onDidDelete(runScan); + Logger.logMessageByStatus(MessageStatus.INFO, `Register watcher on ${file}`); + context.subscriptions.push(watcher); + this.manifestWatchers.push(watcher); + }); + Logger.logInfo("Watchers added successfully"); + } else { + Logger.logInfo("No manifest files found"); + } + } +} diff --git a/src/helpers/terminalHelper.ts b/src/helpers/terminalHelper.ts index e5ccc1a..389553e 100644 --- a/src/helpers/terminalHelper.ts +++ b/src/helpers/terminalHelper.ts @@ -12,7 +12,7 @@ export class Terminal { let command: string = `${Organization.debrickedCli}`; if (accessTokenRequired) { const flags = DebrickedCommands.getCommandSpecificFlags("Debricked") || []; - const accessToken = await AuthHelper.getToken(useDefaultAccessToken, "access"); + const accessToken = await AuthHelper.getToken(useDefaultAccessToken, Organization.access); if (accessToken) { Logger.logMessageByStatus( diff --git a/src/services/baseCommandService.ts b/src/services/baseCommandService.ts index 04f9b4c..ffd374c 100644 --- a/src/services/baseCommandService.ts +++ b/src/services/baseCommandService.ts @@ -113,12 +113,17 @@ export class BaseCommandService { ); await installer.runInstallScript(); - BaseCommandService.globalState.setGlobalData(Organization.isFirstActivationKey, false); - BaseCommandService.globalState.setGlobalData(Organization.extensionVersionKey, currentVersion); + const debrickedData: any = await BaseCommandService.globalState.getGlobalData( + Organization.debrickedDataKey, + {}, + ); + debrickedData[Organization.isFirstActivationKey] = false; + debrickedData[Organization.extensionVersionKey] = currentVersion; + BaseCommandService.globalState.setGlobalData(Organization.debrickedDataKey, debrickedData); Logger.logMessageByStatus( MessageStatus.INFO, - `${Organization.extensionVersionKey}: ${BaseCommandService.globalState.getGlobalData(Organization.extensionVersionKey, "")}`, + `${Organization.extensionVersionKey}: ${debrickedData[Organization.extensionVersionKey]}`, ); } catch (error: any) { ErrorHandler.handleError(error); @@ -144,10 +149,10 @@ export class BaseCommandService { } switch (selectedSubCommand?.cli_command) { case "accessToken": - AuthHelper.getToken(false, "access"); + AuthHelper.getToken(false, Organization.access); break; case "bearerToken": - AuthHelper.getToken(false, "bearer"); + AuthHelper.getToken(false, Organization.bearer); break; } } catch (error: any) { diff --git a/src/services/fileService.ts b/src/services/fileService.ts index 45f4e7c..bcd4e61 100644 --- a/src/services/fileService.ts +++ b/src/services/fileService.ts @@ -69,7 +69,7 @@ export class FileService { if (command.sub_commands && command.sub_commands.length > 0) { selectedSubCommand = command.sub_commands[0]; if (selectedSubCommand && selectedSubCommand.cli_command) { - cmdParams.push(selectedSubCommand.cli_command); + cmdParams.push(selectedSubCommand.cli_command, "-j"); } } @@ -80,20 +80,28 @@ export class FileService { progress.report({ message: "🚀Finding Files..." }); - const foundFiles = await Command.executeAsyncCommand(`${Organization.debrickedCli} ${cmdParams.join(" ")}`); - const foundFilesArray: string[] = Common.stringToArray(foundFiles, "\n"); - await GitHelper.setupGit(); - const repoData: any = await FileService.globalState.getGlobalData(Organization.repoDataKey, {}); - const selectedRepoName = await GitHelper.getRepositoryName(); + const foundFiles = JSON.parse( + await Command.executeAsyncCommand(`${Organization.debrickedCli} ${cmdParams.join(" ")}`), + ); + const foundFilesArray: string[] = foundFiles + .map((item: any) => item.manifestFile) + .filter((file: any) => file !== ""); + + await GitHelper.setupGit(); + const selectedRepoName = await GitHelper.getRepositoryName(); + let repoData: any = await FileService.globalState.getGlobalData(selectedRepoName, {}); - if (selectedRepoName && !repoData[selectedRepoName]) { - repoData[selectedRepoName] = {}; + if (!repoData) { + repoData = {}; } - repoData[selectedRepoName].filesToScan = foundFilesArray; + repoData.filesToScan = foundFilesArray; progress.report({ message: "🏁 Found Files" }); - await FileService.globalState.setGlobalData(Organization.repoDataKey, repoData); - Logger.logMessageByStatus(MessageStatus.INFO, `Found ${foundFilesArray.length} Files: ${foundFilesArray}`); + await FileService.globalState.setGlobalData(selectedRepoName, repoData); + Logger.logMessageByStatus( + MessageStatus.INFO, + `Found ${foundFilesArray.length} Files: ${foundFilesArray}`, + ); return foundFilesArray; } catch (error: any) { ErrorHandler.handleError(error); diff --git a/src/services/scanService.ts b/src/services/scanService.ts index b161d28..ed105c7 100644 --- a/src/services/scanService.ts +++ b/src/services/scanService.ts @@ -12,9 +12,6 @@ import { } from "../helpers"; import { DebrickedCommands, MessageStatus, Organization } from "../constants/index"; import { DebrickedCommandNode, Flag, RepositoryInfo } from "../types"; -import * as vscode from "vscode"; -import path from "path"; - export class ScanService { private static get globalState(): GlobalState { return GlobalState.getInstance(); @@ -29,10 +26,8 @@ export class ScanService { const command: DebrickedCommandNode = DebrickedCommands.SCAN; cmdParams.push(command.cli_command); - const currentRepoData: RepositoryInfo = await ScanService.globalState.getGlobalDataByKey( - Organization.repoDataKey, - await GitHelper.getRepositoryName(), - ); + const selectedRepoName = await GitHelper.getRepositoryName(); + const currentRepoData: RepositoryInfo = await ScanService.globalState.getGlobalData(selectedRepoName, {}); Logger.logMessageByStatus(MessageStatus.INFO, `Current repository name: ${currentRepoData.repositoryName}`); if (currentRepoData?.repositoryName !== MessageStatus.UNKNOWN) { @@ -130,55 +125,4 @@ export class ScanService { break; } } - - static async addWatcherToManifestFiles(filesToScan: string[], context: vscode.ExtensionContext) { - try { - Logger.logMessageByStatus(MessageStatus.INFO, "Add Watchers To Manifest Files"); - ScanService.globalState.setGlobalData(Organization.seqIdKey, Common.generateHashCode()); - - if (filesToScan && filesToScan.length > 0) { - const filesPattern = new RegExp(filesToScan.map((file: any) => `^${file}$`).join("|")); - - vscode.window.onDidChangeActiveTextEditor((editor) => { - if (editor && filesPattern.test(path.basename(editor.document.fileName))) { - vscode.commands.executeCommand("setContext", "debrickedFilesToScan", true); - } else { - vscode.commands.executeCommand("setContext", "debrickedFilesToScan", false); - } - }); - - filesToScan.forEach((file: any) => { - const watcher = vscode.workspace.createFileSystemWatcher(`**/${file}`); - - const runScan = async () => { - await this.scanService(); - }; - - watcher.onDidChange(runScan); - watcher.onDidCreate(runScan); - watcher.onDidDelete(runScan); - Logger.logMessageByStatus(MessageStatus.INFO, `register watcher on ${file}`); - context.subscriptions.push(watcher); - }); - Logger.logInfo("watchers added successfully"); - } else { - Logger.logInfo("No manifest files found"); - } - - StatusBarMessageHelper.setStatusBarMessage( - StatusMessage.getStatusMessage(MessageStatus.START, DebrickedCommands.SCAN.cli_command), - ); - - StatusBarMessageHelper.setStatusBarMessage( - StatusMessage.getStatusMessage(MessageStatus.COMPLETE, DebrickedCommands.SCAN.cli_command), - ); - } catch (error: any) { - ErrorHandler.handleError(error); - } finally { - StatusBarMessageHelper.setStatusBarMessage( - StatusMessage.getStatusMessage(MessageStatus.FINISHED, DebrickedCommands.SCAN.cli_command), - ); - Logger.logMessageByStatus(MessageStatus.INFO, "Watchers for Manifest files are now ready to scan."); - } - } }