From 6ff83aa7383f2a0ac8f3206613d2df2dd69a72ef Mon Sep 17 00:00:00 2001 From: paulober <44974737+paulober@users.noreply.github.com> Date: Mon, 18 Nov 2024 00:07:12 +0100 Subject: [PATCH] Detect if firmware is in subdirectory by locating .micropico file as default root Signed-off-by: paulober <44974737+paulober@users.noreply.github.com> --- package.json | 2 +- src/activator.mts | 1 + src/osHelper.mts | 24 +++++++++++++++++++++++- src/settings.mts | 48 +++++++++++++++++++++++++++++++++++++++-------- src/stubs.mts | 1 - 5 files changed, 65 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 0d03188..b0b4e89 100644 --- a/package.json +++ b/package.json @@ -347,7 +347,7 @@ "micropico.syncFolder": { "type": "string", "scope": "machine-overridable", - "default": "", + "default": null, "title": "Sync Folder", "description": "This folder will be uploaded to the pyboard when using the sync button. Leave empty to sync the complete project. (only allows folders within the project). Use a path relative to the project you opened in vscode, without leading or trailing slash", "order": 4 diff --git a/src/activator.mts b/src/activator.mts index 04b6e97..aafc938 100644 --- a/src/activator.mts +++ b/src/activator.mts @@ -972,6 +972,7 @@ export default class Activator { return; } + this.settings.reload(); const syncDir = await this.settings.requestSyncFolder("Download"); diff --git a/src/osHelper.mts b/src/osHelper.mts index 9871072..86fc93d 100644 --- a/src/osHelper.mts +++ b/src/osHelper.mts @@ -1,5 +1,6 @@ -import { lstat } from "fs"; +import { lstat, readdirSync } from "fs"; import { readFile, stat, writeFile } from "fs/promises"; +import { basename, join } from "path"; import { rimrafSync } from "rimraf"; export async function pathExists(path: string): Promise { @@ -61,3 +62,24 @@ export function removeJunction(junctionPath: string): Promise { }); }); } + +/** + * Searches for a file in a directory and its subdirectories. + * + * @param directory The directory to search in. + * @param fileName The name of the file to search for. + * @returns The path to the file if found, otherwise undefined. + */ +export function searchFile( + directory: string, + fileName: string +): string | undefined { + const contents = readdirSync(directory, { + encoding: "utf8", + recursive: true, + }); + + const file = contents.find(c => basename(c) === fileName); + + return file ? join(directory, file) : undefined; +} diff --git a/src/settings.mts b/src/settings.mts index c7552ef..6776568 100644 --- a/src/settings.mts +++ b/src/settings.mts @@ -1,8 +1,9 @@ import type { Memento, Uri, WorkspaceConfiguration } from "vscode"; import { window, workspace as vsWorkspace } from "vscode"; import { extName, getProjectPath, settingsStubsBasePath } from "./api.mjs"; -import { join, relative } from "path"; +import { dirname, join, relative } from "path"; import { PicoMpyCom } from "@paulober/pico-mpy-com"; +import { searchFile } from "./osHelper.mjs"; export enum SettingsKey { autoConnect = "autoConnect", @@ -75,6 +76,10 @@ export default class Settings { return this.config.update(key, value, true); } + public updateWorkspaceFolder(key: string, value: T): Thenable { + return this.config.update(key, value, null); + } + public updatePython(key: string, value: T): Thenable { return this.pythonConfig.update(key, value, null); } @@ -126,22 +131,22 @@ export default class Settings { * Returns the absolute path to the sync folder. If the sync folder is undefined, * the project path is returned. * - * @returns the absolute path to the sync folder + * @returns The absolute path to the sync folder and if the setting is undefined */ - public getSyncFolderAbsPath(): string | undefined { + public getSyncFolderAbsPath(): [string | undefined, boolean] { const syncDir = this.getString(SettingsKey.syncFolder); const projectDir = getProjectPath(); - if (syncDir === undefined) { - return projectDir; + if (syncDir === undefined || syncDir.length === 0) { + return [projectDir, true]; } if (projectDir === undefined) { // How can this ever happen??! - return undefined; + return [undefined, false]; } - return join(projectDir, syncDir); + return [join(projectDir, syncDir), false]; } /** @@ -158,7 +163,7 @@ export default class Settings { public async requestSyncFolder( actionTitle: string ): Promise<[string, string] | undefined> { - const syncFolder = this.getSyncFolderAbsPath(); + let [syncFolder, syncSettingNotSet] = this.getSyncFolderAbsPath(); const projectDir = getProjectPath(); if (projectDir === undefined) { @@ -166,6 +171,33 @@ export default class Settings { return; } + // sync folder setting not set + if (syncSettingNotSet) { + const activationFile = searchFile(projectDir, ".micropico"); + const actParent = activationFile ? dirname(activationFile) : undefined; + + // check if activation file is not in project root + if (activationFile && actParent && actParent !== projectDir) { + syncFolder = actParent; + + // update transparent to the user + await this.updateWorkspaceFolder( + SettingsKey.syncFolder, + relative(projectDir, actParent) + ); + + void window.showWarningMessage( + `Sync folder has been set to \`${relative( + projectDir, + actParent + )}\` ` + + "because the `.micropico` file was found in a subdirectory " + + "and no sync folder was set. To disable this behavior, " + + "set a sync folder in the settings to `.` for the project root." + ); + } + } + let additionalSyncFolders = this.getArray( SettingsKey.additionalSyncFolders )?.map(sf => join(projectDir, sf)); diff --git a/src/stubs.mts b/src/stubs.mts index 007de17..939351a 100644 --- a/src/stubs.mts +++ b/src/stubs.mts @@ -191,7 +191,6 @@ export default class Stubs { }; if (!justUpdate) { - defaultSettings["micropico.syncFolder"] = ""; defaultSettings["micropico.openOnStart"] = true; }