diff --git a/lib/utils/qemu.coffee b/lib/utils/qemu.coffee deleted file mode 100644 index e91ffb2c..00000000 --- a/lib/utils/qemu.coffee +++ /dev/null @@ -1,105 +0,0 @@ -###* -# @license -# Copyright 2017-2019 Balena Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -### - -Promise = require('bluebird') -{ getBalenaSdk } = require('./lazy') - -exports.QEMU_VERSION = QEMU_VERSION = 'v4.0.0-balena' -exports.QEMU_BIN_NAME = QEMU_BIN_NAME = 'qemu-execve' - -exports.qemuPathInContext = (context) -> - path = require('path') - binDir = path.join(context, '.balena') - binPath = path.join(binDir, QEMU_BIN_NAME) - path.relative(context, binPath) - -exports.copyQemu = (context, arch) -> - path = require('path') - fs = require('mz/fs') - # Create a hidden directory in the build context, containing qemu - binDir = path.join(context, '.balena') - binPath = path.join(binDir, QEMU_BIN_NAME) - - Promise.resolve(fs.mkdir(binDir)) - .catch(code: 'EEXIST', ->) - .then -> - getQemuPath(arch) - .then (qemu) -> - new Promise (resolve, reject) -> - read = fs.createReadStream(qemu) - write = fs.createWriteStream(binPath) - - read - .on('error', reject) - .pipe(write) - .on('error', reject) - .on('finish', resolve) - .then -> - fs.chmod(binPath, '755') - .then -> - path.relative(context, binPath) - -exports.getQemuPath = getQemuPath = (arch) -> - balena = getBalenaSdk() - path = require('path') - fs = require('mz/fs') - - balena.settings.get('binDirectory') - .then (binDir) -> - Promise.resolve(fs.mkdir(binDir)) - .catch(code: 'EEXIST', ->) - .then -> - path.join(binDir, "#{QEMU_BIN_NAME}-#{arch}-#{QEMU_VERSION}") - -exports.installQemu = (arch) -> - request = require('request') - fs = require('fs') - zlib = require('zlib') - tar = require('tar-stream') - - getQemuPath(arch) - .then (qemuPath) -> - new Promise (resolve, reject) -> - installStream = fs.createWriteStream(qemuPath) - - qemuArch = balenaArchToQemuArch(arch) - downloadArchiveName = "qemu-#{QEMU_VERSION.replace(/^v/, '')}-#{qemuArch}.tar.gz" - qemuUrl = "https://github.com/balena-io/qemu/releases/download/#{QEMU_VERSION}/#{downloadArchiveName}" - - extract = tar.extract() - extract.on 'entry', (header, stream, next) -> - stream.on('end', next) - if header.name.includes("qemu-#{qemuArch}-static") - stream.pipe(installStream) - else - stream.resume() - - request(qemuUrl) - .on('error', reject) - .pipe(zlib.createGunzip()) - .on('error', reject) - .pipe(extract) - .on('error', reject) - .on 'finish', -> - fs.chmodSync(qemuPath, '755') - resolve() - -balenaArchToQemuArch = (arch) -> - switch arch - when 'armv7hf', 'rpi', 'armhf' then 'arm' - when 'aarch64' then 'aarch64' - else throw new Error("Cannot install emulator for architecture #{arch}") diff --git a/lib/utils/qemu.d.ts b/lib/utils/qemu.d.ts deleted file mode 100644 index 52d01fac..00000000 --- a/lib/utils/qemu.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @license - * Copyright 2019 Balena Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export const QEMU_VERSION: string; -export const QEMU_BIN_NAME: string; - -export async function getQemuPath(arch: string): Promise; -export async function installQemu(arch: string): Promise; diff --git a/lib/utils/qemu.js b/lib/utils/qemu.js new file mode 100644 index 00000000..642cd27a --- /dev/null +++ b/lib/utils/qemu.js @@ -0,0 +1,128 @@ +/** + * @license + * Copyright 2017-2020 Balena Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as Promise from 'bluebird'; +import { getBalenaSdk } from './lazy'; +export const QEMU_VERSION = 'v4.0.0-balena'; +export const QEMU_BIN_NAME = 'qemu-execve'; + +export function qemuPathInContext(context) { + const path = require('path'); + const binDir = path.join(context, '.balena'); + const binPath = path.join(binDir, QEMU_BIN_NAME); + return path.relative(context, binPath); +} + +export function copyQemu(context, arch) { + const path = require('path'); + const fs = require('mz/fs'); + // Create a hidden directory in the build context, containing qemu + const binDir = path.join(context, '.balena'); + const binPath = path.join(binDir, QEMU_BIN_NAME); + + return Promise.resolve(fs.mkdir(binDir)) + .catch({ code: 'EEXIST' }, function() { + // noop + }) + .then(() => 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.chmod(binPath, '755')) + .then(() => path.relative(context, binPath)); +} + +export const getQemuPath = function(arch) { + const balena = getBalenaSdk(); + const path = require('path'); + const fs = require('mz/fs'); + + return balena.settings.get('binDirectory').then(binDir => + Promise.resolve(fs.mkdir(binDir)) + .catch({ code: 'EEXIST' }, function() { + // noop + }) + .then(() => + path.join(binDir, `${QEMU_BIN_NAME}-${arch}-${QEMU_VERSION}`), + ), + ); +}; + +export function installQemu(arch) { + const request = require('request'); + const fs = require('fs'); + const zlib = require('zlib'); + const tar = require('tar-stream'); + + return getQemuPath(arch).then( + qemuPath => + new Promise(function(resolve, reject) { + const installStream = fs.createWriteStream(qemuPath); + + const qemuArch = balenaArchToQemuArch(arch); + const downloadArchiveName = `qemu-${QEMU_VERSION.replace( + /^v/, + '', + )}-${qemuArch}.tar.gz`; + const qemuUrl = `https://github.com/balena-io/qemu/releases/download/${QEMU_VERSION}/${downloadArchiveName}`; + + const extract = tar.extract(); + extract.on('entry', function(header, stream, next) { + stream.on('end', next); + if (header.name.includes(`qemu-${qemuArch}-static`)) { + stream.pipe(installStream); + } else { + stream.resume(); + } + }); + + return request(qemuUrl) + .on('error', reject) + .pipe(zlib.createGunzip()) + .on('error', reject) + .pipe(extract) + .on('error', reject) + .on('finish', function() { + fs.chmodSync(qemuPath, '755'); + resolve(); + }); + }), + ); +} + +var balenaArchToQemuArch = function(arch) { + switch (arch) { + case 'armv7hf': + case 'rpi': + case 'armhf': + return 'arm'; + case 'aarch64': + return 'aarch64'; + default: + throw new Error(`Cannot install emulator for architecture ${arch}`); + } +}; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index e6335a72..caeade38 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1135,6 +1135,15 @@ "@types/node": "*" } }, + "@types/moment-duration-format": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@types/moment-duration-format/-/moment-duration-format-2.2.2.tgz", + "integrity": "sha512-CuYswsMI3y5uR5sD9i/VUqIbZrsYN2eaCs7nH3qpDl2CZlNI48mjMf4ve2RpQ/65irprtnQVetfnea9my+jqcg==", + "dev": true, + "requires": { + "moment": ">=2.14.0" + } + }, "@types/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/@types/mz/-/mz-2.7.0.tgz", diff --git a/package.json b/package.json index 82cf566b..991f58c5 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "@types/mkdirp": "^0.5.2", "@types/mocha": "^5.2.7", "@types/mock-require": "^2.0.0", + "@types/moment-duration-format": "^2.2.2", "@types/mz": "^2.7.0", "@types/net-keepalive": "^0.4.0", "@types/nock": "^11.0.7",