balena-cli
Version:
The official balena Command Line Interface
115 lines • 5.16 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.getStream = exports.getImageWritableStream = exports.getImage = exports.isESR = exports.isImageFresh = 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) => {
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}.${extension}`);
};
exports.getImagePath = getImagePath;
const isImageFresh = async (deviceType, version) => {
const imagePath = await (0, exports.getImagePath)(deviceType, version);
let createdDate;
try {
createdDate = await (0, exports.getFileCreatedDate)(imagePath);
}
catch (_a) {
}
if (createdDate == null) {
return false;
}
const balena = (0, lazy_1.getBalenaSdk)();
const lastModifiedDate = await balena.models.os.getLastModified(deviceType, version);
return lastModifiedDate < createdDate;
};
exports.isImageFresh = isImageFresh;
const isESR = (version) => {
const match = version.match(/^v?(\d+)\.\d+\.\d+/);
const major = parseInt((match && match[1]) || '', 10);
return major >= 2018;
};
exports.isESR = isESR;
const resolveVersion = async (deviceType, versionOrRange) => {
const balena = (0, lazy_1.getBalenaSdk)();
const version = await balena.models.os.getMaxSatisfyingVersion(deviceType, versionOrRange, (0, exports.isESR)(versionOrRange) ? 'esr' : 'default');
if (!version) {
throw new Error('No such version for the device type');
}
return version;
};
const getImage = async (deviceType, version) => {
var _a;
const imagePath = await (0, exports.getImagePath)(deviceType, version);
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) => {
const imagePath = await (0, exports.getImagePath)(deviceType, version);
const path = await Promise.resolve().then(() => require('path'));
const { mkdirp } = await Promise.resolve().then(() => require('mkdirp'));
await mkdirp(path.dirname(imagePath));
const inProgressPath = imagePath + '.inprogress';
const { promises, createWriteStream } = await Promise.resolve().then(() => require('fs'));
const stream = createWriteStream(inProgressPath);
stream.persistCache = () => promises.rename(inProgressPath, imagePath);
stream.removeCache = () => promises.unlink(inProgressPath);
return stream;
};
exports.getImageWritableStream = getImageWritableStream;
const doDownload = async (options) => {
const balena = (0, lazy_1.getBalenaSdk)();
const imageStream = await balena.models.os.download(options);
const { PassThrough } = await Promise.resolve().then(() => require('stream'));
const pass = new PassThrough();
imageStream.pipe(pass);
const cacheStream = await (0, exports.getImageWritableStream)(options.deviceType, options.version);
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 = {}) => {
if (versionOrRange == null) {
versionOrRange = 'latest';
}
const version = await resolveVersion(deviceType, versionOrRange);
const isFresh = await (0, exports.isImageFresh)(deviceType, version);
const $stream = isFresh
? await (0, exports.getImage)(deviceType, version)
: await doDownload({ ...options, deviceType, version });
setImmediate(() => $stream.emit('balena-image-manager:resolved-version', version));
return $stream;
};
exports.getStream = getStream;
//# sourceMappingURL=image-manager.js.map
;