From 5726dab86366b6d7dcc2cc4c21e60010caa43f4c Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 29 Sep 2023 17:29:18 -0700 Subject: [PATCH] Minor refactor, print STDERR in red --- README.md | 2 +- arduino-littlefs-upload-1.0.0.vsix | Bin 96032 -> 96443 bytes src/extension.ts | 412 +++++++++++++++-------------- 3 files changed, 208 insertions(+), 206 deletions(-) diff --git a/README.md b/README.md index 714e4b3..aba7ca4 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ LittleFS uploader compatible with Arduino IDE 2.2.1 or higher. For use with the ## Usage -`[Ctrl]+[Shift]+[P]`, then "`Upload LittleFS to Pico/ESP8266`" +`[Ctrl]` + `[Shift]` + `[P]`, then "`Upload LittleFS to Pico/ESP8266`" ## Glitches diff --git a/arduino-littlefs-upload-1.0.0.vsix b/arduino-littlefs-upload-1.0.0.vsix index 049aaafa8ce1e4e41879d40e1f26c56b80ba8711..3309b043977fc0e3ccc675f19af429160fcf7465 100644 GIT binary patch delta 5234 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 diff --git a/src/extension.ts b/src/extension.ts index c1dc46e..9ef49e4 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -8,238 +8,240 @@ const writeEmitter = new vscode.EventEmitter(); let writerReady : boolean = false; function makeTerminal(title : string) { - // If it exists, move it to the front - let w = vscode.window.terminals.find( (w) => ((w.name === title) && (w.exitStatus === undefined))); - if (w !== undefined) { - w.show(false); - return; - } - // Not found, make a new terminal - const pty = { - onDidWrite: writeEmitter.event, - open: () => { writerReady = true; }, - close: () => { writerReady = false; }, - handleInput: () => {} - }; - let terminal = (vscode.window).createTerminal({name: title, pty}); - terminal.show(); + // If it exists, move it to the front + let w = vscode.window.terminals.find( (w) => ((w.name === title) && (w.exitStatus === undefined))); + if (w !== undefined) { + w.show(false); + return; + } + // Not found, make a new terminal + const pty = { + onDidWrite: writeEmitter.event, + open: () => { writerReady = true; }, + close: () => { writerReady = false; }, + handleInput: () => {} + }; + const terminal = (vscode.window).createTerminal({name: title, pty}); + terminal.show(); } function findTool(ctx: ArduinoContext, match : string) : string | undefined { - let found = false; - let ret = undefined; - if (ctx.boardDetails !== undefined) { - Object.keys(ctx.boardDetails.buildProperties).forEach( (elem) => { - if (elem.startsWith(match) && !found && (ctx.boardDetails?.buildProperties[elem] !== undefined)) { - ret = ctx.boardDetails.buildProperties[elem]; - found = true; - } - }); - } - return ret; + let found = false; + let ret = undefined; + if (ctx.boardDetails !== undefined) { + Object.keys(ctx.boardDetails.buildProperties).forEach( (elem) => { + if (elem.startsWith(match) && !found && (ctx.boardDetails?.buildProperties[elem] !== undefined)) { + ret = ctx.boardDetails.buildProperties[elem]; + found = true; + } + }); + } + return ret; +} + +// Execute a command and display it's output in the terminal +async function runCommand(exe : string, opts : any[]) { + const cmd = spawn(exe, opts); + for await (const chunk of cmd.stdout) { + writeEmitter.fire(String(chunk).replace(/\n/g, "\r\n")); + } + for await (const chunk of cmd.stderr) { + // Write stderr in red + writeEmitter.fire("\x1b[31m" + String(chunk).replace(/\n/g, "\r\n") + "\x1b[0m"); + } + // Wait until the executable finishes + let exitCode = await new Promise( (resolve, reject) => { + cmd.on('close', resolve); + }); + return exitCode; } export function activate(context: vscode.ExtensionContext) { - // Get the Arduino info extension loaded - const arduinoContext: ArduinoContext = vscode.extensions.getExtension('dankeboy36.vscode-arduino-api')?.exports; - if (!arduinoContext) { - // Failed to load the Arduino API. - vscode.window.showErrorMessage("Unable to load the Arduino IDE Context extension."); - return; - } + // Get the Arduino info extension loaded + const arduinoContext: ArduinoContext = vscode.extensions.getExtension('dankeboy36.vscode-arduino-api')?.exports; + if (!arduinoContext) { + // Failed to load the Arduino API. + vscode.window.showErrorMessage("Unable to load the Arduino IDE Context extension."); + return; + } - // Register the command - const disposable = vscode.commands.registerCommand('arduino-littlefs-upload.uploadLittleFS', async () => { + // Register the command + const disposable = vscode.commands.registerCommand('arduino-littlefs-upload.uploadLittleFS', async () => { - //let str = JSON.stringify(arduinoContext, null, 4); - //console.log(str); + //let str = JSON.stringify(arduinoContext, null, 4); + //console.log(str); - if ((arduinoContext.boardDetails === undefined) || (arduinoContext.fqbn === undefined)){ - vscode.window.showErrorMessage("Board details not available. Compile the sketch once."); - return; - } + if ((arduinoContext.boardDetails === undefined) || (arduinoContext.fqbn === undefined)){ + vscode.window.showErrorMessage("Board details not available. Compile the sketch once."); + return; + } - makeTerminal("LittleFS Upload"); - // Wait for the terminal to become active. - while (!writerReady) { - await new Promise( resolve => setTimeout(resolve, 100) ); - } + makeTerminal("LittleFS Upload"); - // Clear the terminal - writeEmitter.fire('\x1b[2J\x1b[3J\x1b[;H'); + // Wait for the terminal to become active. + let cnt = 0; + while (!writerReady) { + if (cnt++ >= 50) { // Give it 5 seconds and then give up + vscode.window.showErrorMessage("Unable to open upload terminal"); + return; + } + await new Promise( resolve => setTimeout(resolve, 100) ); + } - writeEmitter.fire("LittleFS Filesystem Uploader\r\n\r\n"); + // Clear the terminal + writeEmitter.fire('\x1b[2J\x1b[3J\x1b[;H'); - // Need to have a data folder present, or this isn't gonna work... - let dataFolder = arduinoContext.sketchPath + "/data"; - if (!fs.existsSync(dataFolder)) { - writeEmitter.fire("ERROR: No data folder found\r\n"); - return; - } + writeEmitter.fire("LittleFS Filesystem Uploader\r\n\r\n"); - // Figure out what we're running on - let pico = false; - let esp8266 = false; - switch (arduinoContext.fqbn.split(':')[1]) { - case "rp2040": { - pico = true; - break; - } - case "esp8266": { - esp8266 = true; - break; - } - default: { - writeEmitter.fire("ERROR: Only Arduino-Pico RP2040 and ESP8266 supported.\r\n"); - return; - } - } + // Need to have a data folder present, or this isn't gonna work... + let dataFolder = arduinoContext.sketchPath + "/data"; + if (!fs.existsSync(dataFolder)) { + writeEmitter.fire("ERROR: No data folder found\r\n"); + return; + } - // Need to find the selected menu item, then get the associated build values for the FS configuration - let fsStart = 0; - let fsEnd = 0; - let page = 0; - let blocksize = 0; - let uploadSpeed = 115200; // ESP8266-only - arduinoContext.boardDetails.configOptions.forEach( (opt) => { - let optSeek = pico ? "flash" : "eesz"; - let startMarker = pico ? "fs_start" : "spiffs_start"; - let endMarker = pico ? "fs_end" : "spiffs_end"; - if (String(opt.option) === String(optSeek)) { - opt.values.forEach( (itm) => { - if (itm.selected) { - let menustr = "menu." + optSeek + "." + itm.value + ".build."; - fsStart = Number(arduinoContext.boardDetails?.buildProperties[menustr + startMarker]); - fsEnd = Number(arduinoContext.boardDetails?.buildProperties[menustr + endMarker]); - if (pico) { // Fixed-size always - page = 256; - blocksize = 4096; - } else if (esp8266) { - page = Number(arduinoContext.boardDetails?.buildProperties[menustr + "spiffs_pagesize"]); - blocksize = Number(arduinoContext.boardDetails?.buildProperties[menustr + "spiffs_blocksize"]); - } - } - }); - } else if (String(opt.option) === "baud") { - opt.values.forEach( (itm) => { - if (itm.selected) { - uploadSpeed = Number(itm.value); - } - }); - } - }); - if (!fsStart || !fsEnd || !page || !blocksize || (fsEnd <= fsStart)) { - writeEmitter.fire("ERROR: No filesystem specified, check flash size menu\r\n"); - return; - } + // Figure out what we're running on + let pico = false; + let esp8266 = false; + switch (arduinoContext.fqbn.split(':')[1]) { + case "rp2040": { + pico = true; + break; + } + case "esp8266": { + esp8266 = true; + break; + } + default: { + writeEmitter.fire("ERROR: Only Arduino-Pico RP2040 and ESP8266 supported.\r\n"); + return; + } + } - // Windows exes need ".exe" suffix - let ext = (platform() === 'win32') ? ".exe" : ""; - let mklittlefs = "mklittlefs" + ext; + // Need to find the selected menu item, then get the associated build values for the FS configuration + let fsStart = 0; + let fsEnd = 0; + let page = 0; + let blocksize = 0; + let uploadSpeed = 115200; // ESP8266-only + arduinoContext.boardDetails.configOptions.forEach( (opt) => { + let optSeek = pico ? "flash" : "eesz"; + let startMarker = pico ? "fs_start" : "spiffs_start"; + let endMarker = pico ? "fs_end" : "spiffs_end"; + if (String(opt.option) === String(optSeek)) { + opt.values.forEach( (itm) => { + if (itm.selected) { + let menustr = "menu." + optSeek + "." + itm.value + ".build."; + fsStart = Number(arduinoContext.boardDetails?.buildProperties[menustr + startMarker]); + fsEnd = Number(arduinoContext.boardDetails?.buildProperties[menustr + endMarker]); + if (pico) { // Fixed-size always + page = 256; + blocksize = 4096; + } else if (esp8266) { + page = Number(arduinoContext.boardDetails?.buildProperties[menustr + "spiffs_pagesize"]); + blocksize = Number(arduinoContext.boardDetails?.buildProperties[menustr + "spiffs_blocksize"]); + } + } + }); + } else if (String(opt.option) === "baud") { + opt.values.forEach( (itm) => { + if (itm.selected) { + uploadSpeed = Number(itm.value); + } + }); + } + }); + if (!fsStart || !fsEnd || !page || !blocksize || (fsEnd <= fsStart)) { + writeEmitter.fire("ERROR: No filesystem specified, check flash size menu\r\n"); + return; + } - let tool = undefined; - if (pico) { - tool = findTool(arduinoContext, "runtime.tools.pqt-mklittlefs"); - } else { // ESP826 - tool = findTool(arduinoContext, "runtime.tools.mklittlefs"); - } - if (tool) { - mklittlefs = tool + "/" + mklittlefs; - } + // Windows exes need ".exe" suffix + let ext = (platform() === 'win32') ? ".exe" : ""; + let mklittlefs = "mklittlefs" + ext; - // TBD - add non-serial UF2 upload via OpenOCD - let serialPort = ""; - if (arduinoContext.port?.address === undefined) { - writeEmitter.fire("ERROR: No port specified, check IDE menus.\r\n"); - return; - } else { - serialPort = arduinoContext.port?.address; - } - if (arduinoContext.port?.protocol !== "serial") { - writeEmitter.fire("ERROR: Only serial port upload supported at this time.\r\n"); - return; - } + let tool = undefined; + if (pico) { + tool = findTool(arduinoContext, "runtime.tools.pqt-mklittlefs"); + } else { // ESP8266 + tool = findTool(arduinoContext, "runtime.tools.mklittlefs"); + } + if (tool) { + mklittlefs = tool + "/" + mklittlefs; + } - let python3 = "python3" + ext; - let python3Path = undefined; - if (pico) { - python3Path = findTool(arduinoContext, "runtime.tools.pqt-python3"); - } else if (esp8266) { - python3Path = findTool(arduinoContext, "runtime.tools.python3"); - } - if (python3Path) { - python3 = python3Path + "/" + python3; - } + // TBD - add non-serial UF2 upload via OpenOCD + let serialPort = ""; + if (arduinoContext.port?.address === undefined) { + writeEmitter.fire("ERROR: No port specified, check IDE menus.\r\n"); + return; + } else { + serialPort = arduinoContext.port?.address; + } + if (arduinoContext.port?.protocol !== "serial") { + writeEmitter.fire("ERROR: Only serial port upload supported at this time.\r\n"); + return; + } - // We can't always know where the compile path is, so just use a temp name - const tmp = require('tmp'); - tmp.setGracefulCleanup(); - let imageFile = tmp.tmpNameSync({postfix: ".littlefs.bin"}); + let python3 = "python3" + ext; + let python3Path = undefined; + if (pico) { + python3Path = findTool(arduinoContext, "runtime.tools.pqt-python3"); + } else if (esp8266) { + python3Path = findTool(arduinoContext, "runtime.tools.python3"); + } + if (python3Path) { + python3 = python3Path + "/" + python3; + } - let buildOpts = ["-c", dataFolder, "-p", String(page), "-b", String(blocksize), "-s", String(fsEnd - fsStart), imageFile]; + // We can't always know where the compile path is, so just use a temp name + const tmp = require('tmp'); + tmp.setGracefulCleanup(); + let imageFile = tmp.tmpNameSync({postfix: ".littlefs.bin"}); - // All mklittlefs take the same options, so run in common - writeEmitter.fire("Building LittleFS filesystem\r\n"); - writeEmitter.fire(mklittlefs + " " + buildOpts.join(" ") + "\r\n"); + let buildOpts = ["-c", dataFolder, "-p", String(page), "-b", String(blocksize), "-s", String(fsEnd - fsStart), imageFile]; - const mkfs = spawn(mklittlefs, buildOpts); - for await (const chunk of mkfs.stdout) { - writeEmitter.fire(String(chunk).replace(/\n/g, "\r\n")); - } - for await (const chunk of mkfs.stderr) { - writeEmitter.fire(String(chunk).replace(/\n/g, "\r\n")); - } - // Wait until the executable finishes - let exitCode = await new Promise( (resolve, reject) => { - mkfs.on('close', resolve); - }); + // All mklittlefs take the same options, so run in common + writeEmitter.fire("Building LittleFS filesystem\r\n"); + writeEmitter.fire(mklittlefs + " " + buildOpts.join(" ") + "\r\n"); - if (exitCode) { - writeEmitter.fire("ERROR: Mklittlefs failed, error code: " + String(exitCode) + "\r\n\r\n"); - return; - } + let exitCode = await runCommand(mklittlefs, buildOpts); + if (exitCode) { + writeEmitter.fire("ERROR: Mklittlefs failed, error code: " + String(exitCode) + "\r\n\r\n"); + return; + } - // Upload stage differs per core - let uploadOpts : any[] = []; - if (pico) { - let uf2conv = "tools/uf2conv.py"; - let uf2Path = findTool(arduinoContext, "runtime.platform.path"); - if (uf2Path) { - uf2conv = uf2Path + "/" + uf2conv; - } - uploadOpts = [uf2conv, "--base", String(fsStart), "--serial", serialPort, "--family", "RP2040", imageFile]; - } else { - let upload = "tools/upload.py"; - let uploadPath = findTool(arduinoContext, "runtime.platform.path"); - if (uploadPath) { - upload = uploadPath + "/" + upload; - } - uploadOpts = [upload, "--chip", "esp8266", "--port", serialPort, "--baud", String(uploadSpeed), "write_flash", String(fsStart), imageFile]; - } + // Upload stage differs per core + let uploadOpts : any[] = []; + if (pico) { + let uf2conv = "tools/uf2conv.py"; + let uf2Path = findTool(arduinoContext, "runtime.platform.path"); + if (uf2Path) { + uf2conv = uf2Path + "/" + uf2conv; + } + uploadOpts = [uf2conv, "--base", String(fsStart), "--serial", serialPort, "--family", "RP2040", imageFile]; + } else { + let upload = "tools/upload.py"; + let uploadPath = findTool(arduinoContext, "runtime.platform.path"); + if (uploadPath) { + upload = uploadPath + "/" + upload; + } + uploadOpts = [upload, "--chip", "esp8266", "--port", serialPort, "--baud", String(uploadSpeed), "write_flash", String(fsStart), imageFile]; + } - writeEmitter.fire("\r\n\r\nUploading LittleFS filesystem\r\n"); - writeEmitter.fire(python3 + " " + uploadOpts.join(" ") + "\r\n"); - const upld = spawn(python3, uploadOpts); - for await (const chunk of upld.stdout) { - writeEmitter.fire(String(chunk).replace(/\n/g, "\r\n")); - } - for await (const chunk of upld.stderr) { - writeEmitter.fire(String(chunk).replace(/\n/g, "\r\n")); - } - // Wait until the executable finishes - exitCode = await new Promise( (resolve, reject) => { - upld.on('close', resolve); - }); + writeEmitter.fire("\r\n\r\nUploading LittleFS filesystem\r\n"); + writeEmitter.fire(python3 + " " + uploadOpts.join(" ") + "\r\n"); - if (exitCode) { - writeEmitter.fire("ERROR: Upload failed, error code: " + String(exitCode) + "\r\n\r\n"); - return; - } + exitCode = await runCommand(python3, uploadOpts); + if (exitCode) { + writeEmitter.fire("ERROR: Upload failed, error code: " + String(exitCode) + "\r\n\r\n"); + return; + } - writeEmitter.fire("\r\n\Completed upload.\r\n\r\n"); - vscode.window.showInformationMessage("LittleFS upload completed!"); - }); - context.subscriptions.push(disposable); + writeEmitter.fire("\r\n\Completed upload.\r\n\r\n"); + vscode.window.showInformationMessage("LittleFS upload completed!"); + }); + context.subscriptions.push(disposable); } -export function deactivate() { } \ No newline at end of file +export function deactivate() { }