diff --git a/scripts/arduino-install.js b/scripts/arduino-install.js index b89c306..6e98900 100644 --- a/scripts/arduino-install.js +++ b/scripts/arduino-install.js @@ -10,90 +10,158 @@ import * as tar from 'tar'; import shell from 'shelljs'; -const version = '1.2.2'; +const CLI_VERSION = '1.0.0'; +const ARDUINO_AVR_VERSION = '1.8.6'; +const ARDUINO_ESP8266_VERSION = '3.1.1'; +const ARDUINO_ESP32_VERSION = '2.0.15'; +const CLI_DIR_PATH = path.resolve(process.cwd(), 'arduino-cli'); -function getPlatformTarget() { - const platform = os.platform(); - const arch = os.arch(); - if (platform === 'win32') { - return arch === 'x64' ? 'arduino-cli_' + version + '_Windows_64bit.zip' : null; - } - if (platform === 'darwin') { - return 'arduino-cli_' + version + '_macOS_64bit.tar.gz'; - } - if (platform === 'linux') { - if (arch === 'x64') return 'arduino-cli_' + version + '_Linux_64bit.tar.gz'; - if (arch === 'arm64') return 'arduino-cli_' + version + '_Linux_ARM64.tar.gz'; - if (arch.startsWith('arm')) return 'arduino-cli_' + version + '_Linux_ARMv7.tar.gz'; - } - return null; -} - -async function arduinoInstall() { - const filename = getPlatformTarget(); - if (!filename) { - console.error('当前系统或架构不受支持'); - return; +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}`; } - const url = `https://downloads.arduino.cc/arduino-cli/${filename}`; - - const temp = path.resolve(process.cwd(), 'temp'); - await fsExtra.ensureDir(temp); - const dest = path.resolve(temp, filename); - const cliDirPath = path.resolve(process.cwd(), 'arduino-cli'); - await fsExtra.ensureDir(cliDirPath); - let cliPath = ''; - if (os.platform() === 'win32') { - cliPath = path.resolve(cliDirPath, 'arduino-cli.exe'); - } else { - cliPath = path.resolve(cliDirPath, 'arduino-cli'); + #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'); } - const configPath = path.resolve(cliDirPath, 'arduino-cli.json'); - const config = await fsExtra.readJson(path.resolve(process.cwd(), 'arduino-cli.json')); - config.directories = { - data: path.resolve(cliDirPath, 'Arduino15'), - downloads: path.resolve(cliDirPath, 'staging'), - user: path.resolve(cliDirPath, 'Arduino') - }; - await fsExtra.writeJson(configPath, config, { - spaces: ' ' - }); - if (!fsPlus.isFileSync(cliPath)) { - console.log(`开始下载: ${url}`); + + 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(`下载失败: ${res.statusText}`); - const fileStream = fs.createWriteStream(dest); + 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('下载完成,开始解压...'); - if (filename.endsWith('.zip')) { - await decompress(dest, cliDirPath, { + console.log('Download complete, start to unzip...'); + if (url.endsWith('.zip')) { + await decompress(cliTempPath, this.#dirPath_, { plugins: [decompressUnzip()] }); } else { await tar.x({ - file: dest, - cwd: cliDirPath, + file: cliTempPath, + cwd: this.#dirPath_, strict: true }); } - fs.unlinkSync(dest); - console.log('解压完成,arduino-cli可执行文件已准备好'); + fs.unlinkSync(cliTempPath); + console.log('Unzip successfully, the arduino-cli is ready'); } - - shell.exec(`"${cliPath}" core update-index --config-file "${configPath}"`); - console.log('\n开始下载: Arduino AVR'); - shell.exec(`"${cliPath}" core install arduino:avr@1.8.6 --config-file "${configPath}"`); - console.log('\n开始下载: Arduino ESP8266'); - shell.exec(`"${cliPath}" core install esp8266:esp8266@3.1.1 --config-file "${configPath}"`); - console.log('\n开始下载: Arduino ESP32'); - shell.exec(`"${cliPath}" core install esp32:esp32@2.0.15 --config-file "${configPath}"`); } -await arduinoInstall(); \ No newline at end of file + +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); \ No newline at end of file