UNPKG

balena-cli

Version:

The official balena Command Line Interface

155 lines • 5.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getQemuPath = exports.QEMU_BIN_NAME = exports.QEMU_VERSION = void 0; exports.qemuPathInContext = qemuPathInContext; exports.copyQemu = copyQemu; exports.installQemuIfNeeded = installQemuIfNeeded; const errors_1 = require("../errors"); const lazy_1 = require("./lazy"); exports.QEMU_VERSION = 'v7.0.0+balena1'; exports.QEMU_BIN_NAME = 'qemu-execve'; function qemuPathInContext(context) { const path = require('path'); const binDir = path.join(context, '.balena'); const binPath = path.join(binDir, exports.QEMU_BIN_NAME); return path.relative(context, binPath); } function copyQemu(context, arch) { const path = require('path'); const fs = require('fs'); const binDir = path.join(context, '.balena'); const binPath = path.join(binDir, exports.QEMU_BIN_NAME); return fs.promises .mkdir(binDir) .catch(function (err) { if (err.code === 'EEXIST') { return; } throw err; }) .then(() => (0, exports.getQemuPath)(arch)) .then((qemu) => new Promise(function (resolve, reject) { const read = fs.createReadStream(qemu); const write = fs.createWriteStream(binPath); read .on('error', reject) .pipe(write) .on('error', reject) .on('finish', resolve); })) .then(() => fs.promises.chmod(binPath, '755')) .then(() => path.relative(context, binPath)); } const getQemuPath = function (balenaArch) { const qemuArch = balenaArchToQemuArch(balenaArch); const balena = (0, lazy_1.getBalenaSdk)(); const path = require('path'); const { promises: fs } = require('fs'); return balena.settings.get('binDirectory').then((binDir) => fs .mkdir(binDir) .catch(function (err) { if (err.code === 'EEXIST') { return; } throw err; }) .then(() => path.join(binDir, `${exports.QEMU_BIN_NAME}-${qemuArch}-${exports.QEMU_VERSION}`))); }; exports.getQemuPath = getQemuPath; async function installQemu(arch, qemuPath) { const qemuArch = balenaArchToQemuArch(arch); const fileVersion = exports.QEMU_VERSION.replace('v', '').replace('+', '.'); const urlFile = encodeURIComponent(`qemu-${fileVersion}-${qemuArch}.tar.gz`); const urlVersion = encodeURIComponent(exports.QEMU_VERSION); const qemuUrl = `https://github.com/balena-io/qemu/releases/download/${urlVersion}/${urlFile}`; const request = await Promise.resolve().then(() => require('request')); const fs = await Promise.resolve().then(() => require('fs')); const zlib = await Promise.resolve().then(() => require('zlib')); const tar = await Promise.resolve().then(() => require('tar-stream')); const installStream = fs.createWriteStream(qemuPath); try { await new Promise((resolve, reject) => { const extract = tar.extract(); extract.on('entry', function (header, stream, next) { try { stream.on('end', next); if (header.name.includes(`qemu-${qemuArch}-static`)) { stream.pipe(installStream); } else { stream.resume(); } } catch (err) { reject(err); } }); request(qemuUrl) .on('error', reject) .pipe(zlib.createGunzip()) .on('error', reject) .pipe(extract) .on('error', reject) .on('finish', function () { fs.chmodSync(qemuPath, '755'); resolve(); }); }); } catch (err) { try { await fs.promises.unlink(qemuPath); } catch (_a) { } throw err; } } const balenaArchToQemuArch = function (arch) { switch (arch) { case 'rpi': case 'arm': case 'armhf': case 'armv7hf': return 'arm'; case 'arm64': case 'aarch64': return 'aarch64'; default: throw new errors_1.ExpectedError((0, lazy_1.stripIndent) ` Unknown ARM architecture identifier "${arch}". Known ARM identifiers: rpi arm armhf armv7hf arm64 aarch64`); } }; async function installQemuIfNeeded(emulated, logger, arch, docker) { const needsQemu = await platformNeedsQemu(docker, logger); if (!emulated || !needsQemu) { return false; } const { promises: fs } = await Promise.resolve().then(() => require('fs')); const qemuPath = await (0, exports.getQemuPath)(arch); try { const stats = await fs.stat(qemuPath); if (stats.size === 0) { await fs.unlink(qemuPath); } await fs.access(qemuPath); } catch (_a) { logger.logInfo(`Installing qemu for ${arch} emulation...`); await installQemu(arch, qemuPath); } return true; } async function platformNeedsQemu(docker, logger) { const dockerInfo = await docker.info(); const isDockerDesktop = /(?:Docker Desktop)|(?:Docker for Mac)/i.test(dockerInfo.OperatingSystem); if (isDockerDesktop) { logger.logInfo((0, lazy_1.stripIndent) ` Docker Desktop detected (daemon architecture: "${dockerInfo.Architecture}") Docker itself will determine and enable architecture emulation if required, without balena-cli intervention and regardless of the --emulated option.`); } return !isDockerDesktop; } //# sourceMappingURL=qemu.js.map