Skip to content
This repository has been archived by the owner on Oct 1, 2024. It is now read-only.

Commit

Permalink
Pre-/post-build command improvements
Browse files Browse the repository at this point in the history
* Full bash syntax support for pre-/post-build commands on UNIX systems
* Environment variables for pre-/post-build commands which give the user access to several build process parameters like the sketch, the output directory, serial port, build mode (verify, upload, analyze, ...), board type and workspace path
Addresses #786
  • Loading branch information
elektronikworkshop authored and adiazulay committed Jan 19, 2021
1 parent d3bcf6e commit 2af8f11
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 19 deletions.
57 changes: 42 additions & 15 deletions src/arduino/arduino.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,7 @@ export class ArduinoApp {
public async setPref(key, value) {
try {
await util.spawn(this._settings.commandPath,
null,
["--pref", `${key}=${value}`, "--save-prefs"]);
["--pref", `${key}=${value}`, "--save-prefs"]);
} catch (ex) {
}
}
Expand Down Expand Up @@ -331,30 +330,45 @@ export class ArduinoApp {
arduinoChannel.start(`${buildMode} sketch '${dc.sketch}'`);

if ((buildDir || dc.output) && compile) {
const outputPath = path.resolve(ArduinoWorkspace.rootPath, buildDir || dc.output);
const dirPath = path.dirname(outputPath);
buildDir = path.resolve(ArduinoWorkspace.rootPath, buildDir || dc.output);
const dirPath = path.dirname(buildDir);
if (!util.directoryExistsSync(dirPath)) {
logger.notifyUserError("InvalidOutPutPath", new Error(constants.messages.INVALID_OUTPUT_PATH + outputPath));
logger.notifyUserError("InvalidOutPutPath", new Error(constants.messages.INVALID_OUTPUT_PATH + buildDir));
return false;
}

if (this.useArduinoCli()) {
args.push("--build-path", outputPath);
args.push("--build-path", buildDir);

} else {
args.push("--pref", `build.path=${outputPath}`);
args.push("--pref", `build.path=${buildDir}`);
}

arduinoChannel.info(`Please see the build logs in output path: ${outputPath}`);
arduinoChannel.info(`Please see the build logs in output path: ${buildDir}`);
} else {
const msg = "Output path is not specified. Unable to reuse previously compiled files. Build will be slower. See README.";
arduinoChannel.warning(msg);
}

// Environment variables passed to pre- and post-build commands
const env = {
VSCA_BUILD_MODE: buildMode,
VSCA_SKETCH: dc.sketch,
VSCA_BOARD: boardDescriptor,
VSCA_WORKSPACE_DIR: ArduinoWorkspace.rootPath,
VSCA_LOG_LEVEL: verbose ? constants.LogLevel.Verbose : constants.LogLevel.Info,
};
if (dc.port) {
env["VSCA_SERIAL"] = dc.port;
}
if (buildDir) {
env["VSCA_BUILD_DIR"] = buildDir;
}

// TODO EW: What should we do with pre-/post build commands when running
// analysis? Some could use it to generate/manipulate code which could
// be a prerequisite for a successful build
if (!await this.runPrePostBuildCommand(dc, "pre")) {
if (!await this.runPrePostBuildCommand(dc, env, "pre")) {
return false;
}

Expand All @@ -370,7 +384,7 @@ export class ArduinoApp {
const cleanup = async (result: "ok" | "error") => {
let ret = true;
if (result === "ok") {
ret = await this.runPrePostBuildCommand(dc, "post");
ret = await this.runPrePostBuildCommand(dc, env, "post");
}
await cocopa.conclude();
if (buildMode === BuildMode.Upload || buildMode === BuildMode.UploadProgrammer) {
Expand Down Expand Up @@ -689,21 +703,34 @@ export class ArduinoApp {
* @returns True if successful, false on error.
*/
protected async runPrePostBuildCommand(dc: DeviceContext,
environment: any,
what: "pre" | "post"): Promise<boolean> {
const cmdline = what === "pre"
? dc.prebuild
: dc.postbuild;

if (cmdline) {
arduinoChannel.info(`Running ${what}-build command: "${cmdline}"`);
// TODO 2020-02-27, EW: We could call bash -c "cmd" here at least for
// UNIX systems. Windows users must live with their poor system :)
const args = cmdline.split(/\s+/);
const cmd = args.shift();
let cmd: string;
let args: string[];
// pre-/post-build commands feature full bash support on UNIX systems.
// Windows users must live with their poor system unless someone is
// willing to fight with the annoying Windows cmd escaping -- good luck!
if (os.platform() === "win32") {
args = cmdline.split(/\s+/);
cmd = args.shift();
} else {
args = ["-c", cmdline];
cmd = "bash";
}
try {
await util.spawn(cmd,
args,
{ shell: true, cwd: ArduinoWorkspace.rootPath },
{
shell: os.platform() === "win32",
cwd: ArduinoWorkspace.rootPath,
env: {...environment},
},
{ channel: arduinoChannel.channel });
} catch (ex) {
const msg = ex.error
Expand Down
8 changes: 4 additions & 4 deletions src/common/util.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import * as childProcess from "child_process";
import * as child_process from "child_process";
import * as fs from "fs";
import * as iconv from "iconv-lite";
import * as os from "os";
Expand Down Expand Up @@ -196,19 +196,19 @@ export function isArduinoFile(filePath): boolean {
export function spawn(
command: string,
args: string[] = [],
options: any = {},
options: child_process.SpawnOptions = {},
output?: {channel?: vscode.OutputChannel,
stdout?: (s: string) => void,
stderr?: (s: string) => void},
): Thenable<object> {
return new Promise((resolve, reject) => {
options.cwd = options.cwd || path.resolve(path.join(__dirname, ".."));
const child = childProcess.spawn(command, args, options);
const child = child_process.spawn(command, args, options);

let codepage = "65001";
if (os.platform() === "win32") {
try {
const chcp = childProcess.execSync("chcp.com");
const chcp = child_process.execSync("chcp.com");
codepage = chcp.toString().split(":").pop().trim();
} catch (error) {
arduinoChannel.warning(`Defaulting to code page 850 because chcp.com failed.\
Expand Down

0 comments on commit 2af8f11

Please sign in to comment.