From b114697cab11ab27c8cdae74397e97598037db58 Mon Sep 17 00:00:00 2001 From: Pagan Gazzard Date: Tue, 23 Jun 2020 11:57:57 +0100 Subject: [PATCH] Use native fs promises rather than promisify or mz Change-type: patch --- automation/check-doc.js | 2 +- lib/actions-oclif/key/add.ts | 5 ++--- lib/actions-oclif/os/configure.ts | 2 +- lib/actions/config.js | 11 ++++++----- lib/actions/os.js | 9 ++++----- lib/actions/ssh.ts | 4 ++-- lib/utils/compose.js | 4 ++-- lib/utils/compose_ts.ts | 23 ++++++++++++++++------- lib/utils/deploy-legacy.js | 6 +++--- lib/utils/docker-js.js | 2 +- lib/utils/eol-conversion.ts | 2 +- lib/utils/ignore.ts | 4 ++-- lib/utils/qemu.ts | 16 ++++++++++------ npm-shrinkwrap.json | 9 --------- package.json | 2 -- tests/commands/build.spec.ts | 11 +++++++---- tests/commands/deploy.spec.ts | 2 +- tests/commands/os/configure.spec.ts | 2 +- tests/commands/push.spec.ts | 2 +- tests/docker-build.ts | 2 +- tests/helpers.ts | 6 ++++-- tests/utils/eol-conversion.spec.ts | 2 +- 22 files changed, 67 insertions(+), 61 deletions(-) diff --git a/automation/check-doc.js b/automation/check-doc.js index 26b0bc39..3dfda9e2 100644 --- a/automation/check-doc.js +++ b/automation/check-doc.js @@ -17,7 +17,7 @@ const { stripIndent } = require('common-tags'); const _ = require('lodash'); -const { fs } = require('mz'); +const { promises: fs } = require('fs'); const path = require('path'); const simplegit = require('simple-git/promise'); diff --git a/lib/actions-oclif/key/add.ts b/lib/actions-oclif/key/add.ts index 22d51b06..e31324f1 100644 --- a/lib/actions-oclif/key/add.ts +++ b/lib/actions-oclif/key/add.ts @@ -73,9 +73,8 @@ export default class KeyAddCmd extends Command { let key: string; if (params.path != null) { - const { promisify } = await import('util'); - const readFileAsync = promisify((await import('fs')).readFile); - key = await readFileAsync(params.path, 'utf8'); + const { readFile } = (await import('fs')).promises; + key = await readFile(params.path, 'utf8'); } else if (this.stdin.length > 0) { key = this.stdin; } else { diff --git a/lib/actions-oclif/os/configure.ts b/lib/actions-oclif/os/configure.ts index fa1561e2..e51482a8 100644 --- a/lib/actions-oclif/os/configure.ts +++ b/lib/actions-oclif/os/configure.ts @@ -184,7 +184,7 @@ export default class OsConfigureCmd extends Command { await validateOptions(options); const devInit = await import('balena-device-init'); - const fs = await import('mz/fs'); + const { promises: fs } = await import('fs'); const { generateDeviceConfig, generateApplicationConfig } = await import( '../../utils/config' ); diff --git a/lib/actions/config.js b/lib/actions/config.js index 3d2c96f1..257a4004 100644 --- a/lib/actions/config.js +++ b/lib/actions/config.js @@ -154,17 +154,16 @@ Examples: root: true, action(params, options) { const Bluebird = require('bluebird'); - const util = require('util'); const config = require('balena-config-json'); const umountAsync = Bluebird.promisify(require('umount').umount); - const readFileAsync = util.promisify(require('fs').readFile); return Bluebird.try( () => options.drive || getVisuals().drive('Select the device drive'), ) .tap(umountAsync) .then((drive) => - readFileAsync(params.file, 'utf8') + require('fs') + .promises.readFile(params.file, 'utf8') .then(JSON.parse) .then((configJSON) => config.write(drive, options.type, configJSON)), ) @@ -312,7 +311,6 @@ Examples: action(_params, options) { normalizeUuidProp(options, 'device'); const Bluebird = require('bluebird'); - const writeFileAsync = Bluebird.promisify(require('fs').writeFile); const balena = getBalenaSdk(); const form = require('resin-cli-form'); const prettyjson = require('prettyjson'); @@ -408,7 +406,10 @@ See the help page for examples: }) .then(function (config) { if (options.output != null) { - return writeFileAsync(options.output, JSON.stringify(config)); + return require('fs').promises.writeFile( + options.output, + JSON.stringify(config), + ); } console.log(prettyjson.render(config)); diff --git a/lib/actions/os.js b/lib/actions/os.js index 7fd790b3..e96f4973 100644 --- a/lib/actions/os.js +++ b/lib/actions/os.js @@ -238,16 +238,15 @@ Example: }, ], action(params, options) { - const fs = require('fs'); - const Bluebird = require('bluebird'); - const writeFileAsync = Bluebird.promisify(fs.writeFile); - return $buildConfig( params.image, params['device-type'], options.advanced, ).then((answers) => - writeFileAsync(options.output, JSON.stringify(answers, null, 4)), + require('fs').promises.writeFile( + options.output, + JSON.stringify(answers, null, 4), + ), ); }, }; diff --git a/lib/actions/ssh.ts b/lib/actions/ssh.ts index 9735ec46..3a5fea7b 100644 --- a/lib/actions/ssh.ts +++ b/lib/actions/ssh.ts @@ -77,7 +77,7 @@ async function getContainerId( // We need to execute a balena ps command on the device, // and parse the output, looking for a specific // container - const { child_process } = await import('mz'); + const childProcess = await import('child_process'); const escapeRegex = await import('lodash/escapeRegExp'); const { which } = await import('../utils/helpers'); const { deviceContainerEngineBinary } = await import('../utils/device/ssh'); @@ -96,7 +96,7 @@ async function getContainerId( if (process.env.DEBUG) { console.error(`[debug] [${sshBinary}, ${sshArgs.join(', ')}]`); } - const subprocess = child_process.spawn(sshBinary, sshArgs, { + const subprocess = childProcess.spawn(sshBinary, sshArgs, { stdio: [null, 'pipe', null], }); const containers = await new Promise((resolve, reject) => { diff --git a/lib/utils/compose.js b/lib/utils/compose.js index 53da8aa7..89890672 100644 --- a/lib/utils/compose.js +++ b/lib/utils/compose.js @@ -119,7 +119,7 @@ Source files are not modified.`, * @returns Promise<{import('./compose-types').ComposeOpts}> */ export function generateOpts(options) { - const fs = require('mz/fs'); + const { promises: fs } = require('fs'); const { isV12 } = require('./version'); return fs.realpath(options.source || '.').then((projectPath) => ({ projectName: options.projectName, @@ -213,7 +213,7 @@ function originalTarDirectory(dir, param) { const tar = require('tar-stream'); const klaw = require('klaw'); - const fs = require('mz/fs'); + const { promises: fs } = require('fs'); const streamToPromise = require('stream-to-promise'); const { printGitignoreWarn } = require('./compose_ts'); const { FileIgnorer, IgnoreFileType } = require('./ignore'); diff --git a/lib/utils/compose_ts.ts b/lib/utils/compose_ts.ts index 299739ba..e50b17b6 100644 --- a/lib/utils/compose_ts.ts +++ b/lib/utils/compose_ts.ts @@ -19,7 +19,7 @@ import * as Bluebird from 'bluebird'; import { stripIndent } from 'common-tags'; import type * as Dockerode from 'dockerode'; import * as _ from 'lodash'; -import { fs } from 'mz'; +import { promises as fs } from 'fs'; import * as path from 'path'; import { Composition } from 'resin-compose-parse'; import * as MultiBuild from 'resin-multibuild'; @@ -46,6 +46,15 @@ export interface RegistrySecrets { }; } +const exists = async (filename: string) => { + try { + await fs.access(filename); + return true; + } catch { + return false; + } +}; + const compositionFileNames = ['docker-compose.yml', 'docker-compose.yaml']; /** @@ -101,11 +110,11 @@ async function resolveProject( let composeFileContents = ''; for (const fname of compositionFileNames) { const fpath = path.join(projectRoot, fname); - if (await fs.exists(fpath)) { + if (await exists(fpath)) { logger.logDebug(`${fname} file found at "${projectRoot}"`); composeFileName = fname; try { - composeFileContents = await fs.readFile(fpath, 'utf-8'); + composeFileContents = await fs.readFile(fpath, 'utf8'); } catch (err) { logger.logError(`Error reading composition file "${fpath}":\n${err}`); throw err; @@ -330,7 +339,7 @@ export async function getRegistrySecrets( ]; for (const potentialPath of potentialPaths) { - if (await fs.exists(potentialPath)) { + if (await exists(potentialPath)) { return await parseRegistrySecrets(potentialPath); } } @@ -506,7 +515,7 @@ async function validateSpecifiedDockerfile( const fullDockerfilePath = path.join(nativeProjectPath, nativeDockerfilePath); - if (!(await fs.exists(fullDockerfilePath))) { + if (!(await exists(fullDockerfilePath))) { throw new ExpectedError(stripIndent` Error: specified Dockerfile not found: Specified dockerfile: "${fullDockerfilePath}" @@ -550,7 +559,7 @@ export async function validateProjectDirectory( }, ): Promise { if ( - !(await fs.exists(opts.projectPath)) || + !(await exists(opts.projectPath)) || !(await fs.stat(opts.projectPath)).isDirectory() ) { throw new ExpectedError( @@ -585,7 +594,7 @@ export async function validateProjectDirectory( return _.some( await Promise.all( compositionFileNames.map((filename) => - fs.exists(path.join(folder, filename)), + exists(path.join(folder, filename)), ), ), ); diff --git a/lib/utils/deploy-legacy.js b/lib/utils/deploy-legacy.js index f96e58f0..81580afe 100644 --- a/lib/utils/deploy-legacy.js +++ b/lib/utils/deploy-legacy.js @@ -187,9 +187,9 @@ export const deployLegacy = function ( // If the file was never written to (for instance because an error // has occured before any data was written) this call will throw an // ugly error, just suppress it - Bluebird.try(() => require('mz/fs').unlink(bufferFile)).catchReturn( - undefined, - ), + Bluebird.try(() => + require('fs').promises.unlink(bufferFile), + ).catchReturn(undefined), ); }) .tap(function ({ buildId }) { diff --git a/lib/utils/docker-js.js b/lib/utils/docker-js.js index 8ffbdd2b..9ab59272 100644 --- a/lib/utils/docker-js.js +++ b/lib/utils/docker-js.js @@ -107,7 +107,7 @@ Implements the same feature as the "docker build --cache-from" option.`, } const generateConnectOpts = function (opts) { - const fs = require('mz/fs'); + const { promises: fs } = require('fs'); return Bluebird.try(function () { const connectOpts = {}; diff --git a/lib/utils/eol-conversion.ts b/lib/utils/eol-conversion.ts index 10291e6e..81279adb 100644 --- a/lib/utils/eol-conversion.ts +++ b/lib/utils/eol-conversion.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { fs } from 'mz'; +import { promises as fs } from 'fs'; import Logger = require('./logger'); import { isV12 } from './version'; diff --git a/lib/utils/ignore.ts b/lib/utils/ignore.ts index c7db59b8..4903c8cb 100644 --- a/lib/utils/ignore.ts +++ b/lib/utils/ignore.ts @@ -15,7 +15,7 @@ * limitations under the License. */ import * as _ from 'lodash'; -import { fs } from 'mz'; +import { promises as fs, Stats } from 'fs'; import * as path from 'path'; import * as MultiBuild from 'resin-multibuild'; @@ -193,7 +193,7 @@ export class FileIgnorer { export interface FileStats { filePath: string; relPath: string; - stats: fs.Stats; + stats: Stats; } /** diff --git a/lib/utils/qemu.ts b/lib/utils/qemu.ts index 0fc5202e..b8d9475d 100644 --- a/lib/utils/qemu.ts +++ b/lib/utils/qemu.ts @@ -33,12 +33,12 @@ export function qemuPathInContext(context: string) { export function copyQemu(context: string, arch: string) { const path = require('path') as typeof import('path'); - const fs = require('mz/fs') as typeof import('mz/fs'); + const fs = require('fs') as typeof import('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 Bluebird.resolve(fs.mkdir(binDir)) + return Bluebird.resolve(fs.promises.mkdir(binDir)) .catch({ code: 'EEXIST' }, function () { // noop }) @@ -56,14 +56,14 @@ export function copyQemu(context: string, arch: string) { .on('finish', resolve); }), ) - .then(() => fs.chmod(binPath, '755')) + .then(() => fs.promises.chmod(binPath, '755')) .then(() => path.relative(context, binPath)); } export const getQemuPath = function (arch: string) { const balena = getBalenaSdk(); const path = require('path') as typeof import('path'); - const fs = require('mz/fs') as typeof import('mz/fs'); + const { promises: fs } = require('fs') as typeof import('fs'); return balena.settings.get('binDirectory').then((binDir) => Bluebird.resolve(fs.mkdir(binDir)) @@ -144,8 +144,12 @@ export async function installQemuIfNeeded( if (!emulated || !needsQemu) { return false; } - const fs = await import('mz/fs'); - if (!(await fs.exists(await getQemuPath(arch)))) { + const { promises: fs } = await import('fs'); + const qemuPath = await getQemuPath(arch); + try { + await fs.access(qemuPath); + } catch { + // Qemu doesn't exist so install it logger.logInfo(`Installing qemu for ${arch} emulation...`); await installQemu(arch); } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index d8fdd548..d54d5fee 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1340,15 +1340,6 @@ "moment": ">=2.14.0" } }, - "@types/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@types/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-Q5TZYMKnH0hdV5fNstmMWL2LLw5eRRtTd73KNtsZxoQ2gtCQyET5X79uERUEwGneuxPglg441I7OSY00+9CkSw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/net-keepalive": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@types/net-keepalive/-/net-keepalive-0.4.0.tgz", diff --git a/package.json b/package.json index ca8e5fba..192b5079 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,6 @@ "@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", "@types/node": "^10.17.20", @@ -232,7 +231,6 @@ "mkdirp": "^0.5.1", "moment": "^2.24.0", "moment-duration-format": "^2.3.2", - "mz": "^2.7.0", "node-cleanup": "^2.1.2", "node-unzip-2": "^0.2.8", "oclif": "^1.15.2", diff --git a/tests/commands/build.spec.ts b/tests/commands/build.spec.ts index ea466ba6..530a2d1e 100644 --- a/tests/commands/build.spec.ts +++ b/tests/commands/build.spec.ts @@ -21,7 +21,7 @@ require('../config-tests'); // required for side effects import { expect } from 'chai'; import { stripIndent } from 'common-tags'; import mock = require('mock-require'); -import { fs } from 'mz'; +import { promises as fs } from 'fs'; import * as path from 'path'; import { BalenaAPIMock } from '../balena-api-mock'; @@ -193,7 +193,7 @@ describe('balena build', function () { } const arch = 'rpi'; const deviceType = 'raspberry-pi'; - const fsModPath = 'mz/fs'; + const fsModPath = 'fs'; const fsMod = await import(fsModPath); const qemuModPath = '../../build/utils/qemu'; const qemuMod = require(qemuModPath); @@ -201,8 +201,11 @@ describe('balena build', function () { try { mock(fsModPath, { ...fsMod, - exists: async (p: string) => - p === qemuBinPath ? true : fsMod.exists(p), + promises: { + ...fsMod.promises, + access: async (p: string) => + p === qemuBinPath ? undefined : fsMod.promises.access(p), + }, }); mock(qemuModPath, { ...qemuMod, diff --git a/tests/commands/deploy.spec.ts b/tests/commands/deploy.spec.ts index dcd77d95..28ea3274 100644 --- a/tests/commands/deploy.spec.ts +++ b/tests/commands/deploy.spec.ts @@ -19,7 +19,7 @@ require('../config-tests'); // required for side effects import { expect } from 'chai'; -import { fs } from 'mz'; +import { promises as fs } from 'fs'; import * as path from 'path'; import * as sinon from 'sinon'; diff --git a/tests/commands/os/configure.spec.ts b/tests/commands/os/configure.spec.ts index 6770cad1..b2754688 100644 --- a/tests/commands/os/configure.spec.ts +++ b/tests/commands/os/configure.spec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import * as fs from 'mz/fs'; +import { promises as fs } from 'fs'; import * as process from 'process'; import { runCommand } from '../../helpers'; diff --git a/tests/commands/push.spec.ts b/tests/commands/push.spec.ts index 724ad39f..04611097 100644 --- a/tests/commands/push.spec.ts +++ b/tests/commands/push.spec.ts @@ -19,7 +19,7 @@ require('../config-tests'); // required for side effects import { expect } from 'chai'; -import { fs } from 'mz'; +import { promises as fs } from 'fs'; import * as path from 'path'; import { BalenaAPIMock } from '../balena-api-mock'; diff --git a/tests/docker-build.ts b/tests/docker-build.ts index adf875ec..26fc1622 100644 --- a/tests/docker-build.ts +++ b/tests/docker-build.ts @@ -18,7 +18,7 @@ import { expect } from 'chai'; import { stripIndent } from 'common-tags'; import * as _ from 'lodash'; -import { fs } from 'mz'; +import { promises as fs } from 'fs'; import * as path from 'path'; import { PathUtils } from 'resin-multibuild'; import * as sinon from 'sinon'; diff --git a/tests/helpers.ts b/tests/helpers.ts index 8a996fed..34c4888c 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -21,7 +21,7 @@ require('./config-tests'); // required for side effects import { execFile } from 'child_process'; import intercept = require('intercept-stdout'); import * as _ from 'lodash'; -import { fs } from 'mz'; +import { promises as fs } from 'fs'; import * as nock from 'nock'; import * as path from 'path'; @@ -191,7 +191,9 @@ export async function runCommand(cmd: string): Promise { `The standalone tests require Node.js >= v10.16.0 because of net/proxy features ('global-agent' npm package)`, ); } - if (!(await fs.exists(standalonePath))) { + try { + await fs.access(standalonePath); + } catch { throw new Error(`Standalone executable not found: "${standalonePath}"`); } const proxy = await import('./proxy-server'); diff --git a/tests/utils/eol-conversion.spec.ts b/tests/utils/eol-conversion.spec.ts index 55a31608..a93a6f5d 100644 --- a/tests/utils/eol-conversion.spec.ts +++ b/tests/utils/eol-conversion.spec.ts @@ -16,7 +16,7 @@ */ import { expect } from 'chai'; -import { fs } from 'mz'; +import { promises as fs } from 'fs'; import * as path from 'path'; import {