UNPKG

balena-cli

Version:

The official balena Command Line Interface

111 lines 5.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getStream = exports.getImageWritableStream = exports.getImage = exports.resolveVersion = exports.isImageCached = exports.getImagePath = exports.getFileCreatedDate = void 0; const lazy_1 = require("./lazy"); const BALENAOS_VERSION_REGEX = /v?\d+\.\d+\.\d+(\.rev\d+)?((\-|\+).+)?/; const validateVersion = (version) => { if (!BALENAOS_VERSION_REGEX.test(version)) { throw new Error('Invalid version number'); } }; const getFileCreatedDate = async (filePath) => { const { promises: fs } = await Promise.resolve().then(() => require('fs')); const { ctime } = await fs.stat(filePath); return ctime; }; exports.getFileCreatedDate = getFileCreatedDate; const getImagePath = async (deviceType, version, type) => { if (typeof version === 'string') { validateVersion(version); } const balena = (0, lazy_1.getBalenaSdk)(); const [cacheDirectory, deviceTypeInfo] = await Promise.all([ balena.settings.get('cacheDirectory'), balena.models.config.getDeviceTypeManifestBySlug(deviceType), ]); const extension = deviceTypeInfo.yocto.fstype === 'zip' ? 'zip' : 'img'; const path = await Promise.resolve().then(() => require('path')); return path.join(cacheDirectory, `${deviceType}-v${version}${type != null ? `-${type}` : ''}.${extension}`); }; exports.getImagePath = getImagePath; const isImageCached = async (deviceType, version, type) => { const imagePath = await (0, exports.getImagePath)(deviceType, version, type); try { const createdDate = await (0, exports.getFileCreatedDate)(imagePath); return createdDate != null; } catch (_a) { return false; } }; exports.isImageCached = isImageCached; const resolveVersion = async (deviceType, versionOrRange) => { const balena = (0, lazy_1.getBalenaSdk)(); const { getOsType } = await Promise.resolve().then(() => require('./os')); const version = await balena.models.os.getMaxSatisfyingVersion(deviceType, versionOrRange, getOsType(versionOrRange)); if (!version) { const { OSVersionNotFoundError } = await Promise.resolve().then(() => require('../errors')); throw new OSVersionNotFoundError(`Version ${versionOrRange} is not available for the device type ${deviceType}`); } return version; }; exports.resolveVersion = resolveVersion; const getImage = async (deviceType, version, type) => { var _a; const imagePath = await (0, exports.getImagePath)(deviceType, version, type); const fs = await Promise.resolve().then(() => require('fs')); const stream = fs.createReadStream(imagePath); const { getType } = await Promise.resolve().then(() => require('mime')); stream.mime = (_a = getType(imagePath)) !== null && _a !== void 0 ? _a : 'application/octet-stream'; return stream; }; exports.getImage = getImage; const getImageWritableStream = async (deviceType, version, type) => { const imagePath = await (0, exports.getImagePath)(deviceType, version, type); const path = await Promise.resolve().then(() => require('path')); const { promises: fs, createWriteStream } = await Promise.resolve().then(() => require('node:fs')); await fs.mkdir(path.dirname(imagePath), { recursive: true }); const inProgressPath = imagePath + '.inprogress'; const stream = createWriteStream(inProgressPath); stream.persistCache = () => fs.rename(inProgressPath, imagePath); stream.removeCache = () => fs.unlink(inProgressPath); return stream; }; exports.getImageWritableStream = getImageWritableStream; const imageTypeToSdkParam = { 'installation-media': 'flasher', 'disk-image': 'raw', }; const doDownload = async ({ type, ...restOptions }) => { const balena = (0, lazy_1.getBalenaSdk)(); const imageStream = await balena.models.os.download({ ...restOptions, imageType: type ? imageTypeToSdkParam[type] : undefined, }); const { PassThrough } = await Promise.resolve().then(() => require('stream')); const pass = new PassThrough(); imageStream.pipe(pass); const cacheStream = await (0, exports.getImageWritableStream)(restOptions.deviceType, restOptions.version, type); pass.pipe(cacheStream, { end: false }); pass.on('end', cacheStream.persistCache); const pass2 = new PassThrough(); pass2.mime = imageStream.mime; imageStream.on('progress', (state) => pass2.emit('progress', state)); imageStream.on('error', async (err) => { await cacheStream.removeCache(); pass2.emit('error', err); }); return pass.pipe(pass2); }; const getStream = async (deviceType, versionOrRange, options = {}) => { versionOrRange !== null && versionOrRange !== void 0 ? versionOrRange : (versionOrRange = 'latest'); const version = await (0, exports.resolveVersion)(deviceType, versionOrRange); const existsInCache = await (0, exports.isImageCached)(deviceType, version, options.type); const $stream = existsInCache ? await (0, exports.getImage)(deviceType, version, options.type) : await doDownload({ ...options, deviceType, version }); setImmediate(() => $stream.emit('balena-image-manager:resolved-version', version)); return $stream; }; exports.getStream = getStream; //# sourceMappingURL=image-manager.js.map