From 9aacb7ec56aafa498fc1e599917b71d9b1f88312 Mon Sep 17 00:00:00 2001 From: Pagan Gazzard Date: Wed, 29 Jul 2020 18:27:20 +0100 Subject: [PATCH] Remove some bluebird usage Change-type: patch --- lib/actions-oclif/local/configure.ts | 8 +- lib/actions/preload.js | 10 +- lib/auth/utils.ts | 9 +- lib/utils/compose_ts.ts | 43 +++++---- lib/utils/config.ts | 88 +++++++++--------- lib/utils/device/deploy.ts | 5 +- lib/utils/docker-js.js | 132 +++++++++++++-------------- typings/denymount/index.d.ts | 2 +- typings/umount/index.d.ts | 2 +- 9 files changed, 149 insertions(+), 150 deletions(-) diff --git a/lib/actions-oclif/local/configure.ts b/lib/actions-oclif/local/configure.ts index b5849515..c949a68e 100644 --- a/lib/actions-oclif/local/configure.ts +++ b/lib/actions-oclif/local/configure.ts @@ -59,13 +59,13 @@ export default class LocalConfigureCmd extends Command { public async run() { const { args: params } = this.parse(LocalConfigureCmd); - const Bluebird = await import('bluebird'); + const { promisify } = await import('util'); const path = await import('path'); const umount = await import('umount'); - const umountAsync = Bluebird.promisify(umount.umount); - const isMountedAsync = Bluebird.promisify(umount.isMounted); + const umountAsync = promisify(umount.umount); + const isMountedAsync = promisify(umount.isMounted); const reconfix = await import('reconfix'); - const denymount = Bluebird.promisify(await import('denymount')); + const denymount = promisify(await import('denymount')); const Logger = await import('../../utils/logger'); const logger = Logger.getLogger(); diff --git a/lib/actions/preload.js b/lib/actions/preload.js index cf7e804b..a68c39e1 100644 --- a/lib/actions/preload.js +++ b/lib/actions/preload.js @@ -42,10 +42,9 @@ const applicationExpandOptions = { }; let allDeviceTypes; -const getDeviceTypes = function () { - const Bluebird = require('bluebird'); +const getDeviceTypes = async function () { if (allDeviceTypes !== undefined) { - return Bluebird.resolve(allDeviceTypes); + return allDeviceTypes; } const balena = getBalenaSdk(); return balena.models.config @@ -154,12 +153,11 @@ const selectApplicationCommit = function (releases) { }); }; -const offerToDisableAutomaticUpdates = function ( +const offerToDisableAutomaticUpdates = async function ( application, commit, pinDevice, ) { - const Bluebird = require('bluebird'); const balena = getBalenaSdk(); if ( @@ -167,7 +165,7 @@ const offerToDisableAutomaticUpdates = function ( !application.should_track_latest_release || pinDevice ) { - return Bluebird.resolve(); + return; } const message = `\ diff --git a/lib/auth/utils.ts b/lib/auth/utils.ts index 7fc862c1..d4c9d591 100644 --- a/lib/auth/utils.ts +++ b/lib/auth/utils.ts @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import * as Bluebird from 'bluebird'; import * as _ from 'lodash'; import * as url from 'url'; import { getBalenaSdk } from '../utils/lazy'; @@ -26,7 +25,7 @@ import { getBalenaSdk } from '../utils/lazy'; * * @param {String} callbackUrl - callback url * @fulfil {String} - dashboard login url - * @returns {Bluebird} + * @returns {Promise} * * @example * utils.getDashboardLoginURL('http://127.0.0.1:3000').then (url) -> @@ -58,15 +57,15 @@ export const getDashboardLoginURL = (callbackUrl: string) => { * * @param {String} token - session token or api key * @fulfil {Boolean} - whether the login was successful or not - * @returns {Bluebird} + * @returns {Promise} * * utils.loginIfTokenValid('...').then (loggedIn) -> * if loggedIn * console.log('Token is valid!') */ -export const loginIfTokenValid = (token: string) => { +export const loginIfTokenValid = async (token: string) => { if (_.isEmpty(token?.trim())) { - return Bluebird.resolve(false); + return false; } const balena = getBalenaSdk(); diff --git a/lib/utils/compose_ts.ts b/lib/utils/compose_ts.ts index 712f0c57..6550284e 100644 --- a/lib/utils/compose_ts.ts +++ b/lib/utils/compose_ts.ts @@ -15,7 +15,6 @@ * limitations under the License. */ import { BalenaSDK } from 'balena-sdk'; -import * as Bluebird from 'bluebird'; import type * as Dockerode from 'dockerode'; import * as _ from 'lodash'; import { promises as fs } from 'fs'; @@ -249,7 +248,7 @@ export async function tarDirectory( preFinalizeCallback, }: TarDirectoryOptions, ): Promise { - (await import('assert')).strict.strictEqual(nogitignore, true); + (await import('assert')).strict.equal(nogitignore, true); const { filterFilesWithDockerignore } = await import('./ignore'); const { toPosixPath } = (await import('resin-multibuild')).PathUtils; @@ -558,30 +557,34 @@ async function performResolution( }, preprocessHook, ); - // Do one task at a time (Bluebird.each instead of Bluebird.all) - // in order to reduce peak memory usage. Resolves to buildTasks. - Bluebird.each(buildTasks, (buildTask) => { - // buildStream is falsy for "external" tasks (image pull) - if (!buildTask.buildStream) { - return buildTask; - } - // Consume each task.buildStream in order to trigger the - // resolution events that define fields like: - // task.dockerfile, task.dockerfilePath, - // task.projectType, task.resolved - // This mimics what is currently done in `resin-builder`. - return cloneTarStream(buildTask.buildStream).then( - (clonedStream: tar.Pack) => { + (async () => { + try { + // Do one task at a time in order to reduce peak memory usage. Resolves to buildTasks. + for (const buildTask of buildTasks) { + // buildStream is falsy for "external" tasks (image pull) + if (!buildTask.buildStream) { + continue; + } + // Consume each task.buildStream in order to trigger the + // resolution events that define fields like: + // task.dockerfile, task.dockerfilePath, + // task.projectType, task.resolved + // This mimics what is currently done in `resin-builder`. + const clonedStream: tar.Pack = await cloneTarStream( + buildTask.buildStream, + ); buildTask.buildStream = clonedStream; if (!buildTask.external && !buildTask.resolved) { throw new ExpectedError( `Project type for service "${buildTask.serviceName}" could not be determined. Missing a Dockerfile?`, ); } - return buildTask; - }, - ); - }).then(resolve, reject); + } + resolve(buildTasks); + } catch (e) { + reject(e); + } + })(); }); } diff --git a/lib/utils/config.ts b/lib/utils/config.ts index 17ac473f..3ed82565 100644 --- a/lib/utils/config.ts +++ b/lib/utils/config.ts @@ -15,7 +15,6 @@ limitations under the License. */ import type * as BalenaSdk from 'balena-sdk'; import * as semver from 'balena-semver'; -import Bluebird = require('bluebird'); import { getBalenaSdk } from './lazy'; export interface ImgConfig { @@ -52,7 +51,7 @@ export interface ImgConfig { }; } -export function generateBaseConfig( +export async function generateBaseConfig( application: BalenaSdk.Application, options: { version: string; @@ -62,41 +61,44 @@ export function generateBaseConfig( sshKeys?: string[]; }; }, -): Bluebird { +): Promise { options = { ...options, appUpdatePollInterval: options.appUpdatePollInterval || 10, }; - const promise = getBalenaSdk().models.os.getConfig( + const config = (await getBalenaSdk().models.os.getConfig( application.app_name, options, - ) as Bluebird; - return promise.tap((config) => { - // os.getConfig always returns a config for an app - delete config.apiKey; + )) as ImgConfig & { apiKey?: string }; + // os.getConfig always returns a config for an app + delete config.apiKey; - // merge sshKeys to config, when they have been specified - if (options.os && options.os.sshKeys) { - // Create config.os object if it does not exist - config.os = config.os ? config.os : {}; - config.os.sshKeys = config.os.sshKeys - ? [...config.os.sshKeys, ...options.os.sshKeys] - : options.os.sshKeys; - } - }); + // merge sshKeys to config, when they have been specified + if (options.os && options.os.sshKeys) { + // Create config.os object if it does not exist + config.os = config.os ? config.os : {}; + config.os.sshKeys = config.os.sshKeys + ? [...config.os.sshKeys, ...options.os.sshKeys] + : options.os.sshKeys; + } + + return config; } -export function generateApplicationConfig( +export async function generateApplicationConfig( application: BalenaSdk.Application, options: { version: string; deviceType?: string }, ) { - return generateBaseConfig(application, options).tap((config) => { - if (semver.satisfies(options.version, '<2.7.8')) { - return addApplicationKey(config, application.id); - } - return addProvisioningKey(config, application.id); - }); + const config = await generateBaseConfig(application, options); + + if (semver.satisfies(options.version, '<2.7.8')) { + await addApplicationKey(config, application.id); + } else { + await addProvisioningKey(config, application.id); + } + + return config; } export function generateDeviceConfig( @@ -108,20 +110,20 @@ export function generateDeviceConfig( ) { return getBalenaSdk() .models.application.get(device.belongs_to__application.__id) - .then((application) => { + .then(async (application) => { const baseConfigOpts = { ...options, deviceType: device.device_type, }; - return generateBaseConfig(application, baseConfigOpts).tap((config) => { - if ( - deviceApiKey == null && - semver.satisfies(options.version, '<2.0.3') - ) { - return addApplicationKey(config, application.id); - } - return addDeviceKey(config, device.uuid, deviceApiKey || true); - }); + const config = await generateBaseConfig(application, baseConfigOpts); + + if (deviceApiKey == null && semver.satisfies(options.version, '<2.0.3')) { + await addApplicationKey(config, application.id); + } else { + await addDeviceKey(config, device.uuid, deviceApiKey || true); + } + + return config; }) .then((config) => { // Associate a device, to prevent the supervisor @@ -150,18 +152,16 @@ function addProvisioningKey(config: any, applicationNameOrId: string | number) { }); } -function addDeviceKey( +async function addDeviceKey( config: any, uuid: string, customDeviceApiKey: string | true, ) { - return Bluebird.try(() => { - if (customDeviceApiKey === true) { - return getBalenaSdk().models.device.generateDeviceKey(uuid); - } else { - return customDeviceApiKey; - } - }).tap((deviceApiKey) => { - config.deviceApiKey = deviceApiKey; - }); + if (customDeviceApiKey === true) { + config.deviceApiKey = await getBalenaSdk().models.device.generateDeviceKey( + uuid, + ); + } else { + config.deviceApiKey = customDeviceApiKey; + } } diff --git a/lib/utils/device/deploy.ts b/lib/utils/device/deploy.ts index bb47fe3b..222ee5ea 100644 --- a/lib/utils/device/deploy.ts +++ b/lib/utils/device/deploy.ts @@ -16,7 +16,6 @@ */ import * as semver from 'balena-semver'; -import * as Bluebird from 'bluebird'; import * as Docker from 'dockerode'; import * as _ from 'lodash'; import { Composition } from 'resin-compose-parse'; @@ -258,7 +257,7 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise { deployOpts: opts, }); - const promises: Array | Promise> = [livepush.init()]; + const promises: Array> = [livepush.init()]; // Only show logs if we're not detaching if (!opts.detached) { const logStream = await api.getLogStream(); @@ -298,7 +297,7 @@ function connectToDocker(host: string, port: number): Docker { return new Docker({ host, port, - Promise: Bluebird as any, + Promise: require('bluebird'), }); } diff --git a/lib/utils/docker-js.js b/lib/utils/docker-js.js index 737be3ff..69c257a6 100644 --- a/lib/utils/docker-js.js +++ b/lib/utils/docker-js.js @@ -106,76 +106,75 @@ Implements the same feature as the "docker build --cache-from" option.`, ]); } -const generateConnectOpts = function (opts) { - const { promises: fs } = require('fs'); - const Bluebird = require('bluebird'); +const generateConnectOpts = async function (opts) { + const { promises: fs } = await import('fs'); - return Bluebird.try(function () { - const connectOpts = {}; + const connectOpts = {}; - // Start with docker-modem defaults which take several env vars into account, - // including DOCKER_HOST, DOCKER_TLS_VERIFY, DOCKER_CERT_PATH, SSH_AUTH_SOCK - // https://github.com/apocas/docker-modem/blob/v2.1.3/lib/modem.js#L15-L65 - const Modem = require('docker-modem'); - const defaultOpts = new Modem(); - const optsOfInterest = [ - 'ca', - 'cert', - 'key', - 'host', - 'port', - 'socketPath', - 'protocol', - 'username', - 'sshAuthAgent', - 'timeout', - ]; - for (const opt of optsOfInterest) { - connectOpts[opt] = defaultOpts[opt]; - } + // Start with docker-modem defaults which take several env vars into account, + // including DOCKER_HOST, DOCKER_TLS_VERIFY, DOCKER_CERT_PATH, SSH_AUTH_SOCK + // https://github.com/apocas/docker-modem/blob/v2.1.3/lib/modem.js#L15-L65 + const Modem = await import('docker-modem'); + const defaultOpts = new Modem(); + const optsOfInterest = [ + 'ca', + 'cert', + 'key', + 'host', + 'port', + 'socketPath', + 'protocol', + 'username', + 'sshAuthAgent', + 'timeout', + ]; + for (const opt of optsOfInterest) { + connectOpts[opt] = defaultOpts[opt]; + } - // Now override the default options with any explicit command line options - if (opts.docker != null && opts.dockerHost == null) { - // good, local docker socket - connectOpts.socketPath = opts.docker; - delete connectOpts.host; - delete connectOpts.port; - } else if (opts.dockerHost != null && opts.docker == null) { - // Good a host is provided, and local socket isn't - connectOpts.host = opts.dockerHost; - connectOpts.port = opts.dockerPort || 2376; - delete connectOpts.socketPath; - } else if (opts.docker != null && opts.dockerHost != null) { - // Both provided, no obvious way to continue + // Now override the default options with any explicit command line options + if (opts.docker != null && opts.dockerHost == null) { + // good, local docker socket + connectOpts.socketPath = opts.docker; + delete connectOpts.host; + delete connectOpts.port; + } else if (opts.dockerHost != null && opts.docker == null) { + // Good a host is provided, and local socket isn't + connectOpts.host = opts.dockerHost; + connectOpts.port = opts.dockerPort || 2376; + delete connectOpts.socketPath; + } else if (opts.docker != null && opts.dockerHost != null) { + // Both provided, no obvious way to continue + throw new ExpectedError( + "Both a local docker socket and docker host have been provided. Don't know how to continue.", + ); + } + + // Now need to check if the user wants to connect over TLS + // to the host + + // If any are set... + if (opts.ca != null || opts.cert != null || opts.key != null) { + // but not all + if (!(opts.ca != null && opts.cert != null && opts.key != null)) { throw new ExpectedError( - "Both a local docker socket and docker host have been provided. Don't know how to continue.", + 'You must provide a CA, certificate and key in order to use TLS', ); } - // Now need to check if the user wants to connect over TLS - // to the host + const [ca, cert, key] = await Promise.all([ + fs.readFile(opts.ca, 'utf-8'), + fs.readFile(opts.cert, 'utf-8'), + fs.readFile(opts.key, 'utf-8'), + ]); + return _.merge(connectOpts, { + ca, + cert, + key, + }); + } - // If any are set... - if (opts.ca != null || opts.cert != null || opts.key != null) { - // but not all - if (!(opts.ca != null && opts.cert != null && opts.key != null)) { - throw new ExpectedError( - 'You must provide a CA, certificate and key in order to use TLS', - ); - } - - const certBodies = { - ca: fs.readFile(opts.ca, 'utf-8'), - cert: fs.readFile(opts.cert, 'utf-8'), - key: fs.readFile(opts.key, 'utf-8'), - }; - return Bluebird.props(certBodies).then((toMerge) => - _.merge(connectOpts, toMerge), - ); - } - - return connectOpts; - }); + return connectOpts; }; const parseBuildArgs = function (args) { @@ -231,10 +230,11 @@ export function generateBuildOpts(options) { * }} options * @returns {Promise} */ -export function getDocker(options) { - return generateConnectOpts(options) - .then(createClient) - .tap(ensureDockerSeemsAccessible); +export async function getDocker(options) { + const connectOpts = await generateConnectOpts(options); + const client = createClient(connectOpts); + await ensureDockerSeemsAccessible(client); + return client; } const getDockerToolbelt = _.once(function () { diff --git a/typings/denymount/index.d.ts b/typings/denymount/index.d.ts index bf8ed59a..1c8f08f9 100644 --- a/typings/denymount/index.d.ts +++ b/typings/denymount/index.d.ts @@ -20,7 +20,7 @@ declare module 'denymount' { target: string, handler: (cb: typeof callback) => void, opts?: { autoMountOnSuccess?: boolean; executablePath?: string }, - callback: (err?: any) => void, + callback: (err?: Error) => void, ) => void; export = denymount; } diff --git a/typings/umount/index.d.ts b/typings/umount/index.d.ts index 58f74d47..245efc27 100644 --- a/typings/umount/index.d.ts +++ b/typings/umount/index.d.ts @@ -22,6 +22,6 @@ declare module 'umount' { ) => void; export const isMounted: ( device: string, - callback: (err?: Error, isMounted?: boolean) => void, + callback: (err: Error | null, isMounted?: boolean) => void, ) => void; }