Files
mixly3-server/scripts/arduino-install.js
2025-10-04 10:33:41 +08:00

167 lines
5.9 KiB
JavaScript
Executable File

import os from 'node:os';
import fs from 'node:fs';
import path from 'node:path';
import fsExtra from 'fs-extra';
import fsPlus from 'fs-plus';
import fetch from 'node-fetch';
import decompress from 'decompress';
import decompressUnzip from 'decompress-unzip';
import * as tar from 'tar';
import shell from 'shelljs';
const CLI_VERSION = '1.3.1';
const ARDUINO_AVR_VERSION = '1.8.6';
const ARDUINO_ESP8266_VERSION = '3.1.1';
const ARDUINO_ESP32_VERSION = '2.0.15-cn';
const CLI_DIR_PATH = path.resolve(process.cwd(), 'arduino-cli');
class ArduinoCLI {
static getDonwloadUrl(version) {
const platform = os.platform();
const arch = os.arch();
let filename = '';
if (platform === 'win32') {
if (arch === 'x64') {
filename = `arduino-cli_${version}_Windows_64bit.zip`;
} else if (arch === 'ia32') {
filename = `arduino-cli_${version}_Windows_32bit.zip`;
}
} else if (platform === 'darwin') {
if (arch === 'x64') {
filename = `arduino-cli_${version}_macOS_64bit.tar.gz`;
} else if (arch === 'arm64') {
filename = `arduino-cli_${version}_macOS_ARM64.tar.gz`;
}
} else if (platform === 'linux') {
if (arch === 'x64') {
filename = `arduino-cli_${version}_Linux_64bit.tar.gz`;
} else if (arch === 'ia32') {
filename = `arduino-cli_${version}_Linux_32bit.tar.gz`;
} else if (arch === 'arm64') {
filename = `arduino-cli_${version}_Linux_ARM64.tar.gz`;
} else if (arch === 'arm') {
const { stdout } = shell.exec('uname -m', { silent: true });
if (stdout === 'armv6l') {
filename = `arduino-cli_${version}_Linux_ARMv6.tar.gz`;
} else if (stdout === 'armv7l') {
filename = `arduino-cli_${version}_Linux_ARMv7.tar.gz`;
}
}
}
if (!filename) {
throw new Error('The current system or architecture is not supported');
}
return `https://downloads.arduino.cc/arduino-cli/${filename}`;
}
#version_ = '';
#dirPath_ = '';
#cliPath_ = '';
#configPath_ = '';
#tempPath_ = '';
#boards_ = {};
constructor(version, dirPath) {
this.#version_ = version;
this.#dirPath_ = dirPath;
this.#tempPath_ = path.resolve(dirPath, 'temp');
fsExtra.ensureDirSync(dirPath);
fsExtra.ensureDirSync(this.#tempPath_);
if (os.platform() === 'win32') {
this.#cliPath_ = path.resolve(dirPath, 'arduino-cli.exe');
} else {
this.#cliPath_ = path.resolve(dirPath, 'arduino-cli');
}
this.#configPath_ = path.resolve(dirPath, 'arduino-cli.json');
}
async init() {
const config = await fsExtra.readJson(path.resolve(process.cwd(), 'arduino-cli.json'));
config.directories = {
data: path.resolve(this.#dirPath_, 'Arduino15'),
downloads: path.resolve(this.#dirPath_, 'staging'),
user: path.resolve(this.#dirPath_, 'Arduino')
};
await fsExtra.writeJson(this.#configPath_, config, {
spaces: ' '
});
if (!this.available()) {
await this.install();
}
shell.exec(`"${this.#cliPath_}" core update-index --config-file "${this.#configPath_}"`);
this.updateBoardsStatus();
}
updateBoardsStatus() {
const { stdout } = shell.exec(`"${this.#cliPath_}" core list --json --config-file "${this.#configPath_}"`, {
silent: true
});
const info = JSON.parse(stdout);
const { platforms } = info;
this.#boards_ = {};
for (let board of platforms) {
this.#boards_[board.id] = board.installed_version;
}
}
available() {
let available = false;
if (fsPlus.isFileSync(this.#cliPath_)) {
const { stdout } = shell.exec(`"${this.#cliPath_}" version --json --config-file "${this.#configPath_}"`, {
silent: true
});
const info = JSON.parse(stdout);
if (info.VersionString === this.#version_) {
available = true;
}
}
return available;
}
async coreInstall(boardKey, version) {
if (this.#boards_[boardKey] === version) {
console.log(`Platform ${boardKey}@${version} already installed`);
return;
}
shell.exec(`"${this.#cliPath_}" core install ${boardKey}@${version} --config-file "${this.#configPath_}"`);
}
async install() {
const url = ArduinoCLI.getDonwloadUrl(this.#version_);
console.log(`Start Download: ${url}`);
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Download failed: ${res.statusText}`);
}
const cliTempPath = path.resolve(this.#tempPath_, path.basename(url));
const fileStream = fs.createWriteStream(cliTempPath);
await new Promise((resolve, reject) => {
res.body.pipe(fileStream);
res.body.on('error', reject);
fileStream.on('finish', resolve);
});
console.log('Download complete, start to unzip...');
if (url.endsWith('.zip')) {
await decompress(cliTempPath, this.#dirPath_, {
plugins: [decompressUnzip()]
});
} else {
await tar.x({
file: cliTempPath,
cwd: this.#dirPath_,
strict: true
});
}
fs.unlinkSync(cliTempPath);
console.log('Unzip successfully, the arduino-cli is ready');
}
}
const arduino = new ArduinoCLI(CLI_VERSION, CLI_DIR_PATH);
await arduino.init();
arduino.coreInstall('arduino:avr', ARDUINO_AVR_VERSION);
arduino.coreInstall('esp8266:esp8266', ARDUINO_ESP8266_VERSION);
arduino.coreInstall('esp32:esp32', ARDUINO_ESP32_VERSION);