From e7a8deed0568fc6600c1e49a634aebbd358dbbfa Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 3 May 2018 14:48:01 +0200 Subject: [PATCH 1/4] Inline the entire resin-cli-errors module It's awkward that error handling requires you to go to a different package, it makes things more complicated, and there's nowhere else that really should be reusing this logic. Let's inline it, so we can deprecate the module entirely. Change-Type: patch --- lib/errors.ts | 66 ++++++++++++++++++++++++++++++++--- package.json | 1 - typings/resin-cli-errors.d.ts | 1 - 3 files changed, 62 insertions(+), 6 deletions(-) delete mode 100644 typings/resin-cli-errors.d.ts diff --git a/lib/errors.ts b/lib/errors.ts index 6e9bf9ec..24ac5adc 100644 --- a/lib/errors.ts +++ b/lib/errors.ts @@ -14,18 +14,76 @@ See the License for the specific language governing permissions and limitations under the License. */ -import errors = require('resin-cli-errors'); -import patterns = require('./utils/patterns'); +import _ = require('lodash'); +import os = require('os'); import Raven = require('raven'); import Promise = require('bluebird'); +import { stripIndent } from 'common-tags'; + +import patterns = require('./utils/patterns'); const captureException = Promise.promisify( Raven.captureException, { context: Raven }, ); +function hasCode(error: any): error is Error & { code: string } { + return error.code != null; +} + +function interpret(error: any): string | undefined { + if (!(error instanceof Error)) { + return; + } else if (hasCode(error)) { + const errorCodeHandler = messages[error.code]; + const message = errorCodeHandler && errorCodeHandler(error); + + if (message) { + return message; + } + + if (!_.isEmpty(error.message)) { + return `${error.code}: ${error.message}`; + } + + return; + } else { + return error.message; + } +} + +const messages: { + [key: string]: (error: Error & { path?: string }) => string +} = { + EISDIR: (error) => `File is a directory: ${error.path}`, + + ENOENT: (error) => `No such file or directory: ${error.path}`, + + ENOGIT: () => stripIndent` + Git is not installed on this system. + Head over to http://git-scm.com to install it and run this command again.`, + + EPERM: () => stripIndent` + You don't have enough privileges to run this operation. + ${os.platform() === 'win32' ? + 'Run a new Command Prompt as administrator and try running this command again.' : + 'Try running this command again prefixing it with `sudo`.' + } + + If this is not the case, and you're trying to burn an SDCard, check that the write lock is not set.`, + + EACCES: (e) => messages.EPERM(e), + + ETIMEDOUT: () => 'Oops something went wrong, please check your connection and try again.', + + ResinExpiredToken: () => stripIndent` + Looks like your session token is expired. + Please try logging in again with: + $ resin login` +} + exports.handle = function(error: any) { - let message = errors.interpret(error); + let message = interpret(error); if (message == null) { return; } @@ -34,7 +92,7 @@ exports.handle = function(error: any) { message = error.stack; } - patterns.printErrorMessage(message); + patterns.printErrorMessage(message!); return captureException(error) .timeout(1000) diff --git a/package.json b/package.json index bc1f8a96..d8bad806 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,6 @@ "reconfix": "^0.0.3", "request": "^2.81.0", "resin-bundle-resolve": "^0.5.3", - "resin-cli-errors": "^1.2.0", "resin-cli-form": "^1.4.1", "resin-cli-visuals": "^1.4.0", "resin-compose-parse": "^1.8.1", diff --git a/typings/resin-cli-errors.d.ts b/typings/resin-cli-errors.d.ts deleted file mode 100644 index b62af69f..00000000 --- a/typings/resin-cli-errors.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'resin-cli-errors'; From c2518448a30bcbd1131f7ba8eba7d5fd8335d98e Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 3 May 2018 15:15:22 +0200 Subject: [PATCH 2/4] Catch require errors and provide helpful instructions Change-Type: patch --- lib/errors.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/errors.ts b/lib/errors.ts index 24ac5adc..d6a203ba 100644 --- a/lib/errors.ts +++ b/lib/errors.ts @@ -31,10 +31,20 @@ function hasCode(error: any): error is Error & { code: string } { return error.code != null; } +function treatFailedBindingAsMissingModule(error: any): void { + if (error.message.startsWith('Could not locate the bindings file.')) { + error.code = 'MODULE_NOT_FOUND'; + } +} + function interpret(error: any): string | undefined { if (!(error instanceof Error)) { return; - } else if (hasCode(error)) { + } + + treatFailedBindingAsMissingModule(error); + + if (hasCode(error)) { const errorCodeHandler = messages[error.code]; const message = errorCodeHandler && errorCodeHandler(error); @@ -76,6 +86,18 @@ const messages: { ETIMEDOUT: () => 'Oops something went wrong, please check your connection and try again.', + MODULE_NOT_FOUND: () => stripIndent` + Part of the CLI could not be loaded. This typically means your CLI install is in a broken state. + ${os.arch() === 'x64' ? + 'You can normally fix this by uninstalling and reinstalling the CLI.' + : + stripIndent` + You're using an unsupported architecture (${os.arch()}), so this is typically caused by missing native modules. + Reinstalling may help, but pay attention to errors in native module build steps en route. + ` + } + `, + ResinExpiredToken: () => stripIndent` Looks like your session token is expired. Please try logging in again with: From 4b818ad51c15cbcf6b543bcfd86f57af9b6da5be Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 3 May 2018 18:59:12 +0200 Subject: [PATCH 3/4] Style improvements after review --- lib/errors.ts | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/errors.ts b/lib/errors.ts index d6a203ba..a8ec40e8 100644 --- a/lib/errors.ts +++ b/lib/errors.ts @@ -14,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import _ = require('lodash'); -import os = require('os'); -import Raven = require('raven'); -import Promise = require('bluebird'); +import * as _ from 'lodash'; +import * as os from 'os'; +import * as Raven from 'raven'; +import * as Promise from 'bluebird'; import { stripIndent } from 'common-tags'; -import patterns = require('./utils/patterns'); +import * as patterns from './utils/patterns'; const captureException = Promise.promisify( Raven.captureException, @@ -55,19 +55,17 @@ function interpret(error: any): string | undefined { if (!_.isEmpty(error.message)) { return `${error.code}: ${error.message}`; } - - return; } else { return error.message; } } const messages: { - [key: string]: (error: Error & { path?: string }) => string + [key: string]: (error: Error & { path?: string }) => string; } = { - EISDIR: (error) => `File is a directory: ${error.path}`, + EISDIR: error => `File is a directory: ${error.path}`, - ENOENT: (error) => `No such file or directory: ${error.path}`, + ENOENT: error => `No such file or directory: ${error.path}`, ENOGIT: () => stripIndent` Git is not installed on this system. @@ -75,23 +73,25 @@ const messages: { EPERM: () => stripIndent` You don't have enough privileges to run this operation. - ${os.platform() === 'win32' ? - 'Run a new Command Prompt as administrator and try running this command again.' : - 'Try running this command again prefixing it with `sudo`.' + ${ + os.platform() === 'win32' + ? 'Run a new Command Prompt as administrator and try running this command again.' + : 'Try running this command again prefixing it with `sudo`.' } If this is not the case, and you're trying to burn an SDCard, check that the write lock is not set.`, - EACCES: (e) => messages.EPERM(e), + EACCES: e => messages.EPERM(e), - ETIMEDOUT: () => 'Oops something went wrong, please check your connection and try again.', + ETIMEDOUT: () => + 'Oops something went wrong, please check your connection and try again.', MODULE_NOT_FOUND: () => stripIndent` Part of the CLI could not be loaded. This typically means your CLI install is in a broken state. - ${os.arch() === 'x64' ? - 'You can normally fix this by uninstalling and reinstalling the CLI.' - : - stripIndent` + ${ + os.arch() === 'x64' + ? 'You can normally fix this by uninstalling and reinstalling the CLI.' + : stripIndent` You're using an unsupported architecture (${os.arch()}), so this is typically caused by missing native modules. Reinstalling may help, but pay attention to errors in native module build steps en route. ` @@ -101,8 +101,8 @@ const messages: { ResinExpiredToken: () => stripIndent` Looks like your session token is expired. Please try logging in again with: - $ resin login` -} + $ resin login`, +}; exports.handle = function(error: any) { let message = interpret(error); From e85f252f2996afdcef56fceb5d2a660c362a0af0 Mon Sep 17 00:00:00 2001 From: "resin-io-versionbot[bot]" Date: Thu, 3 May 2018 17:49:06 +0000 Subject: [PATCH 4/4] v7.3.8 --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97a2603a..601c5315 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY! This project adheres to [Semantic Versioning](http://semver.org/). +## v7.3.8 - 2018-05-03 + +* Catch require errors and provide helpful instructions #874 [Tim Perry] +* Inline the entire resin-cli-errors module #874 [Tim Perry] + ## v7.3.7 - 2018-04-30 * Pin node types to v9.0.0 to avoid build errors with transient dependencies #871 [Cameron Diver] diff --git a/package.json b/package.json index d8bad806..a24567fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "resin-cli", - "version": "7.3.7", + "version": "7.3.8", "description": "The official resin.io CLI tool", "main": "./build/actions/index.js", "homepage": "https://github.com/resin-io/resin-cli",