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

Commit ae0ebd4

Browse files
giuliofgiuliofMarcLVadiazulaymaddogjt
authored
Option to use arduino-cli instead of Arduino IDE (#1017)
* Hardcoded Arduino-CLI commands for build and upload * Added menu checkbox for Arduino CLI - Upload with programmer is still not supported - Must be created an arduino symlink pointing to arduino-cli * If Arduino-CLI, check for arduino-cli instead of arduino. Not yet supported on Windows or MacOS * Typo * Fixed CI requests * Fixed CI requests * Update src/common/sys/darwin.ts MacOS patch for arduino-cli Co-authored-by: Marc Lage-Vianna <[email protected]> * Update src/common/sys/win32.ts Windows patch for arduino-cli Co-authored-by: Marc Lage-Vianna <[email protected]> * Trigger * add cli option in commandPath for win32 * add cli support to board and lib managers * rename isArduinoCli to useArduinoCli * adds support for uploading using programmer * simplify getProgrammer * add CLI upload * Update src/arduino/arduino.ts Co-authored-by: Jason Tranchida <[email protected]> * refactor uploadUsingProgrammer * fix output path for CLI upload * Update package.json * update cli option text, thanks @maddogjt * update tests Co-authored-by: giuliof <[email protected]> Co-authored-by: Marc Lage-Vianna <[email protected]> Co-authored-by: Adi Azulay <[email protected]> Co-authored-by: Adi Azulay <[email protected]> Co-authored-by: Jason Tranchida <[email protected]>
1 parent 4efe14d commit ae0ebd4

13 files changed

+184
-106
lines changed

package.json

+13
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,18 @@
9393
"light": "images/ArduinoUpload_16.svg"
9494
}
9595
},
96+
{
97+
"command": "arduino.cliUpload",
98+
"title": "Arduino CLI: Upload"
99+
},
96100
{
97101
"command": "arduino.uploadUsingProgrammer",
98102
"title": "Arduino: Upload Using Programmer"
99103
},
104+
{
105+
"command": "arduino.cliUploadUsingProgrammer",
106+
"title": "Arduino CLI: Upload Using Programmer"
107+
},
100108
{
101109
"command": "arduino.selectProgrammer",
102110
"title": "Arduino: Select Programmer"
@@ -442,6 +450,11 @@
442450
"type": "object",
443451
"title": "Arduino configuration",
444452
"properties": {
453+
"arduino.useArduinoCli": {
454+
"type": "boolean",
455+
"default": false,
456+
"markdownDescription": "Use Arduino CLI installed instead of Arduino IDE. `#arduino.path#` must be set, as there is no default path for 'arduino-cli'. (Requires a restart after change)"
457+
},
445458
"arduino.path": {
446459
"type": "string",
447460
"default": "",

src/arduino/arduino.ts

+80-81
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,23 @@ export class ArduinoApp {
9393
}
9494
}
9595

96-
public async upload() {
96+
/**
97+
* Upload code to selected board
98+
* @param {bool} [compile=true] - Indicates whether to compile the code when using the CLI to upload
99+
* @param {bool} [useProgrammer=false] - Indicate whether a specific programmer should be used
100+
*/
101+
public async upload(compile: boolean = true, useProgrammer: boolean = false) {
97102
const dc = DeviceContext.getInstance();
98103
const boardDescriptor = this.getBoardBuildString();
99104
if (!boardDescriptor) {
100105
return;
101106
}
102107

108+
const selectProgrammer = useProgrammer ? this.getProgrammerString() : null;
109+
if (useProgrammer && !selectProgrammer) {
110+
return;
111+
}
112+
103113
if (!ArduinoWorkspace.rootPath) {
104114
vscode.window.showWarningMessage("Cannot find the sketch file.");
105115
return;
@@ -140,94 +150,47 @@ export class ArduinoApp {
140150
}
141151
}
142152

153+
if (!compile && !this.useArduinoCli()) {
154+
arduinoChannel.error("This command is only availble when using the Arduino CLI");
155+
return;
156+
}
157+
143158
const appPath = path.join(ArduinoWorkspace.rootPath, dc.sketch);
144-
const args = ["--upload", "--board", boardDescriptor];
159+
// TODO: add the --clean argument to the cli args when v 0.14 is released (this will clean up the build folder after uploading)
160+
const args = (!compile && this.useArduinoCli()) ? ["upload", "-b", boardDescriptor] :
161+
this.useArduinoCli() ? ["compile", "--upload", "-b", boardDescriptor] :
162+
["--upload", "--board", boardDescriptor];
163+
164+
if (useProgrammer) {
165+
if (this.useArduinoCli()) {
166+
args.push("--programmer", selectProgrammer)
167+
} else {
168+
args.push("--useprogrammer", "--pref", "programmer=" + selectProgrammer)
169+
}
170+
}
171+
145172
if (dc.port) {
146173
args.push("--port", dc.port);
147174
}
148175
args.push(appPath);
149176
if (VscodeSettings.getInstance().logLevel === "verbose") {
150177
args.push("--verbose");
151178
}
152-
if (dc.output) {
179+
if (dc.output && compile) {
153180
const outputPath = path.resolve(ArduinoWorkspace.rootPath, dc.output);
154181
const dirPath = path.dirname(outputPath);
155182
if (!util.directoryExistsSync(dirPath)) {
156183
Logger.notifyUserError("InvalidOutPutPath", new Error(constants.messages.INVALID_OUTPUT_PATH + outputPath));
157184
return;
158185
}
159186

160-
args.push("--pref", `build.path=${outputPath}`);
161-
arduinoChannel.info(`Please see the build logs in Output path: ${outputPath}`);
162-
} else {
163-
const msg = "Output path is not specified. Unable to reuse previously compiled files. Upload could be slow. See README.";
164-
arduinoChannel.warning(msg);
165-
}
166-
await util.spawn(this._settings.commandPath, arduinoChannel.channel, args).then(async () => {
167-
UsbDetector.getInstance().resumeListening();
168-
if (needRestore) {
169-
await serialMonitor.openSerialMonitor();
170-
}
171-
arduinoChannel.end(`Uploaded the sketch: ${dc.sketch}${os.EOL}`);
172-
}, (reason) => {
173-
arduinoChannel.error(`Exit with code=${reason.code}${os.EOL}`);
174-
});
175-
}
176-
177-
public async uploadUsingProgrammer() {
178-
const dc = DeviceContext.getInstance();
179-
const boardDescriptor = this.getBoardBuildString();
180-
if (!boardDescriptor) {
181-
return;
182-
}
183-
184-
const selectProgrammer = this.getProgrammerString();
185-
if (!selectProgrammer) {
186-
return;
187-
}
187+
if (this.useArduinoCli()) {
188+
args.push("--build-path", outputPath);
188189

189-
if (!ArduinoWorkspace.rootPath) {
190-
vscode.window.showWarningMessage("Cannot find the sketch file.");
191-
return;
192-
}
193-
194-
if (!dc.sketch || !util.fileExistsSync(path.join(ArduinoWorkspace.rootPath, dc.sketch))) {
195-
await this.getMainSketch(dc);
196-
}
197-
if (!dc.port) {
198-
const choice = await vscode.window.showInformationMessage(
199-
"Serial port is not specified. Do you want to select a serial port for uploading?",
200-
"Yes", "No");
201-
if (choice === "Yes") {
202-
vscode.commands.executeCommand("arduino.selectSerialPort");
203-
}
204-
return;
205-
}
206-
207-
arduinoChannel.show();
208-
arduinoChannel.start(`Upload sketch - ${dc.sketch}`);
209-
210-
const serialMonitor = SerialMonitor.getInstance();
211-
212-
const needRestore = await serialMonitor.closeSerialMonitor(dc.port);
213-
UsbDetector.getInstance().pauseListening();
214-
await vscode.workspace.saveAll(false);
215-
216-
const appPath = path.join(ArduinoWorkspace.rootPath, dc.sketch);
217-
const args = ["--upload", "--board", boardDescriptor, "--port", dc.port, "--useprogrammer",
218-
"--pref", "programmer=" + selectProgrammer, appPath];
219-
if (VscodeSettings.getInstance().logLevel === "verbose") {
220-
args.push("--verbose");
221-
}
222-
if (dc.output) {
223-
const outputPath = path.resolve(ArduinoWorkspace.rootPath, dc.output);
224-
const dirPath = path.dirname(outputPath);
225-
if (!util.directoryExistsSync(dirPath)) {
226-
Logger.notifyUserError("InvalidOutPutPath", new Error(constants.messages.INVALID_OUTPUT_PATH + outputPath));
227-
return;
190+
} else {
191+
args.push("--pref", `build.path=${outputPath}`);
228192
}
229193

230-
args.push("--pref", `build.path=${outputPath}`);
231194
arduinoChannel.info(`Please see the build logs in Output path: ${outputPath}`);
232195
} else {
233196
const msg = "Output path is not specified. Unable to reuse previously compiled files. Upload could be slow. See README.";
@@ -277,7 +240,7 @@ export class ArduinoApp {
277240
}
278241

279242
const appPath = path.join(ArduinoWorkspace.rootPath, dc.sketch);
280-
const args = ["--verify", "--board", boardDescriptor, appPath];
243+
const args = this.useArduinoCli() ? ["compile", "-b", boardDescriptor, appPath] : ["--verify", "--board", boardDescriptor, appPath];
281244
if (VscodeSettings.getInstance().logLevel === "verbose") {
282245
args.push("--verbose");
283246
}
@@ -289,7 +252,13 @@ export class ArduinoApp {
289252
return;
290253
}
291254

292-
args.push("--pref", `build.path=${outputPath}`);
255+
if (this.useArduinoCli()) {
256+
args.push("--build-path", outputPath);
257+
258+
} else {
259+
args.push("--pref", `build.path=${outputPath}`);
260+
}
261+
293262
arduinoChannel.info(`Please see the build logs in Output path: ${outputPath}`);
294263
} else {
295264
const msg = "Output path is not specified. Unable to reuse previously compiled files. Verify could be slow. See README.";
@@ -495,33 +464,43 @@ export class ArduinoApp {
495464
}
496465
}
497466

498-
/**
499-
* Install arduino board package based on package name and platform hardware architecture.
500-
*/
467+
/**
468+
* Installs arduino board package.
469+
* (If using the aduino CLI this installs the corrosponding core.)
470+
* @param {string} packageName - board vendor
471+
* @param {string} arch - board architecture
472+
* @param {string} version - version of board package or core to download
473+
* @param {boolean} [showOutput=true] - show raw output from command
474+
*/
501475
public async installBoard(packageName: string, arch: string = "", version: string = "", showOutput: boolean = true) {
502476
arduinoChannel.show();
503477
const updatingIndex = packageName === "dummy" && !arch && !version;
504478
if (updatingIndex) {
505479
arduinoChannel.start(`Update package index files...`);
506480
} else {
507481
try {
508-
const packagePath = path.join(this._settings.packagePath, "packages", packageName);
482+
const packagePath = path.join(this._settings.packagePath, "packages", packageName, arch);
509483
if (util.directoryExistsSync(packagePath)) {
510484
util.rmdirRecursivelySync(packagePath);
511485
}
512486
arduinoChannel.start(`Install package - ${packageName}...`);
513487
} catch (error) {
514488
arduinoChannel.start(`Install package - ${packageName} failed under directory : ${error.path}${os.EOL}
515-
Please make sure the folder is not occupied by other procedures .`);
489+
Please make sure the folder is not occupied by other procedures .`);
516490
arduinoChannel.error(`Error message - ${error.message}${os.EOL}`);
517491
arduinoChannel.error(`Exit with code=${error.code}${os.EOL}`);
518492
return;
519493
}
520494
}
495+
arduinoChannel.info(`${packageName}${arch && ":" + arch}${version && ":" + version}`);
521496
try {
522-
await util.spawn(this._settings.commandPath,
523-
showOutput ? arduinoChannel.channel : null,
524-
["--install-boards", `${packageName}${arch && ":" + arch}${version && ":" + version}`]);
497+
this.useArduinoCli() ?
498+
await util.spawn(this._settings.commandPath,
499+
showOutput ? arduinoChannel.channel : null,
500+
["core", "install", `${packageName}${arch && ":" + arch}${version && "@" + version}`]) :
501+
await util.spawn(this._settings.commandPath,
502+
showOutput ? arduinoChannel.channel : null,
503+
["--install-boards", `${packageName}${arch && ":" + arch}${version && ":" + version}`]);
525504

526505
if (updatingIndex) {
527506
arduinoChannel.end("Updated package index files.");
@@ -548,6 +527,13 @@ Please make sure the folder is not occupied by other procedures .`);
548527
arduinoChannel.end(`Uninstalled board package - ${boardName}${os.EOL}`);
549528
}
550529

530+
/**
531+
* Downloads or updates a library
532+
* @param {string} libName - name of the library to download
533+
* @param {string} version - version of library to download
534+
* @param {boolean} [showOutput=true] - show raw output from command
535+
*/
536+
551537
public async installLibrary(libName: string, version: string = "", showOutput: boolean = true) {
552538
arduinoChannel.show();
553539
const updatingIndex = (libName === "dummy" && !version);
@@ -557,6 +543,10 @@ Please make sure the folder is not occupied by other procedures .`);
557543
arduinoChannel.start(`Install library - ${libName}`);
558544
}
559545
try {
546+
this.useArduinoCli() ?
547+
await util.spawn(this._settings.commandPath,
548+
showOutput ? arduinoChannel.channel : null,
549+
["lib", "install", `${libName}${version && "@" + version}`]) :
560550
await util.spawn(this._settings.commandPath,
561551
showOutput ? arduinoChannel.channel : null,
562552
["--install-library", `${libName}${version && ":" + version}`]);
@@ -769,6 +759,15 @@ Please make sure the folder is not occupied by other procedures .`);
769759
this._programmerManager = value;
770760
}
771761

762+
/**
763+
* Checks if the arduino cli is being used
764+
* @returns {bool} - true if arduino cli is being use
765+
*/
766+
private useArduinoCli() {
767+
return this._settings.useArduinoCli;
768+
// return VscodeSettings.getInstance().useArduinoCli;
769+
}
770+
772771
private getProgrammerString(): string {
773772
const selectProgrammer = this.programmerManager.currentProgrammer;
774773
if (!selectProgrammer) {

src/arduino/arduinoSettings.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export interface IArduinoSettings {
2222
preferencePath: string;
2323
defaultBaudRate: number;
2424
preferences: Map<string, string>;
25+
useArduinoCli: boolean;
2526
reloadPreferences(): void;
2627
}
2728

@@ -38,18 +39,21 @@ export class ArduinoSettings implements IArduinoSettings {
3839

3940
private _preferences: Map<string, string>;
4041

42+
private _useArduinoCli: boolean;
43+
4144
public constructor() {
4245
}
4346

4447
public async initialize() {
4548
const platform = os.platform();
4649
this._commandPath = VscodeSettings.getInstance().commandPath;
50+
this._useArduinoCli = VscodeSettings.getInstance().useArduinoCli;
4751
await this.tryResolveArduinoPath();
4852
await this.tryGetDefaultBaudRate();
4953
if (platform === "win32") {
5054
await this.updateWindowsPath();
5155
if (this._commandPath === "") {
52-
this._commandPath = "arduino_debug.exe";
56+
this._useArduinoCli ? this._commandPath = "arduino-cli.exe" : this._commandPath = "arduino_debug.exe";
5357
}
5458
} else if (platform === "linux") {
5559
if (util.directoryExistsSync(path.join(this._arduinoPath, "portable"))) {
@@ -150,6 +154,10 @@ export class ArduinoSettings implements IArduinoSettings {
150154
return this._preferences;
151155
}
152156

157+
public get useArduinoCli() {
158+
return this._useArduinoCli;
159+
}
160+
153161
public get defaultBaudRate() {
154162
return this._defaultBaudRate;
155163
}

0 commit comments

Comments
 (0)