mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-02-21 09:51:58 +00:00
Merge qemu-ts.ts and qemu.ts files
This commit is contained in:
parent
52bece7f17
commit
cbcd7694a9
@ -232,7 +232,7 @@ export function buildProject(
|
|||||||
checkBuildSecretsRequirements,
|
checkBuildSecretsRequirements,
|
||||||
makeBuildTasks,
|
makeBuildTasks,
|
||||||
} = require('./compose_ts');
|
} = require('./compose_ts');
|
||||||
const qemu = require('./qemu-ts');
|
const qemu = require('./qemu');
|
||||||
const { toPosixPath } = builder.PathUtils;
|
const { toPosixPath } = builder.PathUtils;
|
||||||
|
|
||||||
logger.logInfo(`Building for ${arch}/${deviceType}`);
|
logger.logInfo(`Building for ${arch}/${deviceType}`);
|
||||||
|
@ -1,84 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { stripIndent } from 'common-tags';
|
|
||||||
import Dockerode = require('dockerode');
|
|
||||||
|
|
||||||
import Logger = require('./logger');
|
|
||||||
import { getQemuPath, installQemu } from './qemu';
|
|
||||||
|
|
||||||
export { QEMU_BIN_NAME } from './qemu';
|
|
||||||
export * from './qemu';
|
|
||||||
|
|
||||||
export async function installQemuIfNeeded(
|
|
||||||
emulated: boolean,
|
|
||||||
logger: Logger,
|
|
||||||
arch: string,
|
|
||||||
docker: Dockerode,
|
|
||||||
): Promise<boolean> {
|
|
||||||
// call platformNeedsQemu() regardless of whether emulation is required,
|
|
||||||
// because it logs useful information
|
|
||||||
const needsQemu = await platformNeedsQemu(docker, logger);
|
|
||||||
if (!emulated || !needsQemu) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const fs = await import('mz/fs');
|
|
||||||
if (!(await fs.exists(await getQemuPath(arch)))) {
|
|
||||||
logger.logInfo(`Installing qemu for ${arch} emulation...`);
|
|
||||||
await installQemu(arch);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the Docker daemon (including balenaEngine) requires explicit
|
|
||||||
* QEMU emulation setup. Note that Docker Desktop (Windows and Mac), and also
|
|
||||||
* the older Docker for Mac, have built-in support for binfmt_misc, so they
|
|
||||||
* do not require explicit QEMU setup. References:
|
|
||||||
* - https://en.wikipedia.org/wiki/Binfmt_misc
|
|
||||||
* - https://docs.docker.com/docker-for-mac/multi-arch/
|
|
||||||
* - https://www.ecliptik.com/Cross-Building-and-Running-Multi-Arch-Docker-Images/
|
|
||||||
* - https://stackoverflow.com/questions/55388725/run-linux-arm-container-via-qemu-binfmt-misc-on-docker-lcow
|
|
||||||
*
|
|
||||||
* @param docker Dockerode instance
|
|
||||||
*/
|
|
||||||
async function platformNeedsQemu(
|
|
||||||
docker: Dockerode,
|
|
||||||
logger: Logger,
|
|
||||||
): Promise<boolean> {
|
|
||||||
const dockerInfo = await docker.info();
|
|
||||||
// Docker Desktop (Windows and Mac) with Docker Engine 19.03 reports:
|
|
||||||
// OperatingSystem: Docker Desktop
|
|
||||||
// OSType: linux
|
|
||||||
// Docker for Mac with Docker Engine 18.06 reports:
|
|
||||||
// OperatingSystem: Docker for Mac
|
|
||||||
// OSType: linux
|
|
||||||
// On Ubuntu (standard Docker installation):
|
|
||||||
// OperatingSystem: Ubuntu 18.04.2 LTS (containerized)
|
|
||||||
// OSType: linux
|
|
||||||
// https://stackoverflow.com/questions/38223965/how-can-i-detect-if-docker-for-mac-is-installed
|
|
||||||
const isDockerDesktop = /(?:Docker Desktop)|(?:Docker for Mac)/i.test(
|
|
||||||
dockerInfo.OperatingSystem,
|
|
||||||
);
|
|
||||||
if (isDockerDesktop) {
|
|
||||||
logger.logInfo(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;
|
|
||||||
}
|
|
@ -15,8 +15,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as Promise from 'bluebird';
|
import * as Bluebird from 'bluebird';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Dockerode = require('dockerode');
|
||||||
import { getBalenaSdk } from './lazy';
|
import { getBalenaSdk } from './lazy';
|
||||||
|
import Logger = require('./logger');
|
||||||
|
|
||||||
export const QEMU_VERSION = 'v4.0.0+balena2';
|
export const QEMU_VERSION = 'v4.0.0+balena2';
|
||||||
export const QEMU_BIN_NAME = 'qemu-execve';
|
export const QEMU_BIN_NAME = 'qemu-execve';
|
||||||
|
|
||||||
@ -34,14 +38,14 @@ export function copyQemu(context: string, arch: string) {
|
|||||||
const binDir = path.join(context, '.balena');
|
const binDir = path.join(context, '.balena');
|
||||||
const binPath = path.join(binDir, QEMU_BIN_NAME);
|
const binPath = path.join(binDir, QEMU_BIN_NAME);
|
||||||
|
|
||||||
return Promise.resolve(fs.mkdir(binDir))
|
return Bluebird.resolve(fs.mkdir(binDir))
|
||||||
.catch({ code: 'EEXIST' }, function() {
|
.catch({ code: 'EEXIST' }, function() {
|
||||||
// noop
|
// noop
|
||||||
})
|
})
|
||||||
.then(() => getQemuPath(arch))
|
.then(() => getQemuPath(arch))
|
||||||
.then(
|
.then(
|
||||||
qemu =>
|
qemu =>
|
||||||
new Promise(function(resolve, reject) {
|
new Bluebird(function(resolve, reject) {
|
||||||
const read = fs.createReadStream(qemu);
|
const read = fs.createReadStream(qemu);
|
||||||
const write = fs.createWriteStream(binPath);
|
const write = fs.createWriteStream(binPath);
|
||||||
|
|
||||||
@ -62,7 +66,7 @@ export const getQemuPath = function(arch: string) {
|
|||||||
const fs = require('mz/fs') as typeof import('mz/fs');
|
const fs = require('mz/fs') as typeof import('mz/fs');
|
||||||
|
|
||||||
return balena.settings.get('binDirectory').then(binDir =>
|
return balena.settings.get('binDirectory').then(binDir =>
|
||||||
Promise.resolve(fs.mkdir(binDir))
|
Bluebird.resolve(fs.mkdir(binDir))
|
||||||
.catch({ code: 'EEXIST' }, function() {
|
.catch({ code: 'EEXIST' }, function() {
|
||||||
// noop
|
// noop
|
||||||
})
|
})
|
||||||
@ -80,7 +84,7 @@ export function installQemu(arch: string) {
|
|||||||
|
|
||||||
return getQemuPath(arch).then(
|
return getQemuPath(arch).then(
|
||||||
qemuPath =>
|
qemuPath =>
|
||||||
new Promise(function(resolve, reject) {
|
new Bluebird(function(resolve, reject) {
|
||||||
const installStream = fs.createWriteStream(qemuPath);
|
const installStream = fs.createWriteStream(qemuPath);
|
||||||
|
|
||||||
const qemuArch = balenaArchToQemuArch(arch);
|
const qemuArch = balenaArchToQemuArch(arch);
|
||||||
@ -127,3 +131,62 @@ const balenaArchToQemuArch = function(arch: string) {
|
|||||||
throw new Error(`Cannot install emulator for architecture ${arch}`);
|
throw new Error(`Cannot install emulator for architecture ${arch}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export async function installQemuIfNeeded(
|
||||||
|
emulated: boolean,
|
||||||
|
logger: Logger,
|
||||||
|
arch: string,
|
||||||
|
docker: Dockerode,
|
||||||
|
): Promise<boolean> {
|
||||||
|
// call platformNeedsQemu() regardless of whether emulation is required,
|
||||||
|
// because it logs useful information
|
||||||
|
const needsQemu = await platformNeedsQemu(docker, logger);
|
||||||
|
if (!emulated || !needsQemu) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const fs = await import('mz/fs');
|
||||||
|
if (!(await fs.exists(await getQemuPath(arch)))) {
|
||||||
|
logger.logInfo(`Installing qemu for ${arch} emulation...`);
|
||||||
|
await installQemu(arch);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the Docker daemon (including balenaEngine) requires explicit
|
||||||
|
* QEMU emulation setup. Note that Docker Desktop (Windows and Mac), and also
|
||||||
|
* the older Docker for Mac, have built-in support for binfmt_misc, so they
|
||||||
|
* do not require explicit QEMU setup. References:
|
||||||
|
* - https://en.wikipedia.org/wiki/Binfmt_misc
|
||||||
|
* - https://docs.docker.com/docker-for-mac/multi-arch/
|
||||||
|
* - https://www.ecliptik.com/Cross-Building-and-Running-Multi-Arch-Docker-Images/
|
||||||
|
* - https://stackoverflow.com/questions/55388725/run-linux-arm-container-via-qemu-binfmt-misc-on-docker-lcow
|
||||||
|
*
|
||||||
|
* @param docker Dockerode instance
|
||||||
|
*/
|
||||||
|
async function platformNeedsQemu(
|
||||||
|
docker: Dockerode,
|
||||||
|
logger: Logger,
|
||||||
|
): Promise<boolean> {
|
||||||
|
const dockerInfo = await docker.info();
|
||||||
|
// Docker Desktop (Windows and Mac) with Docker Engine 19.03 reports:
|
||||||
|
// OperatingSystem: Docker Desktop
|
||||||
|
// OSType: linux
|
||||||
|
// Docker for Mac with Docker Engine 18.06 reports:
|
||||||
|
// OperatingSystem: Docker for Mac
|
||||||
|
// OSType: linux
|
||||||
|
// On Ubuntu (standard Docker installation):
|
||||||
|
// OperatingSystem: Ubuntu 18.04.2 LTS (containerized)
|
||||||
|
// OSType: linux
|
||||||
|
// https://stackoverflow.com/questions/38223965/how-can-i-detect-if-docker-for-mac-is-installed
|
||||||
|
const isDockerDesktop = /(?:Docker Desktop)|(?:Docker for Mac)/i.test(
|
||||||
|
dockerInfo.OperatingSystem,
|
||||||
|
);
|
||||||
|
if (isDockerDesktop) {
|
||||||
|
logger.logInfo(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;
|
||||||
|
}
|
||||||
|
@ -176,7 +176,6 @@ describe('balena build', function() {
|
|||||||
copyQemu: async () => '',
|
copyQemu: async () => '',
|
||||||
});
|
});
|
||||||
mock.reRequire('../../build/utils/qemu');
|
mock.reRequire('../../build/utils/qemu');
|
||||||
mock.reRequire('../../build/utils/qemu-ts');
|
|
||||||
docker.expectGetInfo({ OperatingSystem: 'balenaOS 2.44.0+rev1' });
|
docker.expectGetInfo({ OperatingSystem: 'balenaOS 2.44.0+rev1' });
|
||||||
await testDockerBuildStream({
|
await testDockerBuildStream({
|
||||||
commandLine: `build ${projectPath} --emulated --deviceType ${deviceType} --arch ${arch}`,
|
commandLine: `build ${projectPath} --emulated --deviceType ${deviceType} --arch ${arch}`,
|
||||||
|
@ -20,7 +20,7 @@ import { expect } from 'chai';
|
|||||||
describe('resin-multibuild consistency', function() {
|
describe('resin-multibuild consistency', function() {
|
||||||
it('should use the same values for selected constants', async () => {
|
it('should use the same values for selected constants', async () => {
|
||||||
const { QEMU_BIN_NAME: MQEMU_BIN_NAME } = await import('resin-multibuild');
|
const { QEMU_BIN_NAME: MQEMU_BIN_NAME } = await import('resin-multibuild');
|
||||||
const { QEMU_BIN_NAME } = await import('../../build/utils/qemu-ts');
|
const { QEMU_BIN_NAME } = await import('../../build/utils/qemu');
|
||||||
expect(QEMU_BIN_NAME).to.equal(MQEMU_BIN_NAME);
|
expect(QEMU_BIN_NAME).to.equal(MQEMU_BIN_NAME);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user