See #394. Improve error message when program cannot be found

This commit is contained in:
Glavin Wiechert 2015-06-11 17:37:23 -03:00
parent a0e07c232d
commit 2663b41505
4 changed files with 310 additions and 45 deletions

View File

@ -62,6 +62,118 @@ describe "Atom-Beautify", ->
expect(v).not.toBe(null)
expect(v instanceof Error).toBe(true)
expect(v.code).toBe("CommandNotFound")
expect(v.description).toBe(undefined, \
'Error should not have a description.')
return v
p.then(cb, cb)
return p
it "should error with help description \
when beautifier's program not found", ->
expect(beautifier).not.toBe(null)
expect(beautifier instanceof Beautifier).toBe(true)
waitsForPromise shouldReject: true, ->
help = {
link: "http://test.com"
program: "test-program"
pathOption: "Lang - Test Program Path"
}
p = beautifier.run("program", [], help: help)
expect(p).not.toBe(null)
expect(p instanceof beautifier.Promise).toBe(true)
cb = (v) ->
# console.log(v)
expect(v).not.toBe(null)
expect(v instanceof Error).toBe(true)
expect(v.code).toBe("CommandNotFound")
expect(v.description).not.toBe(null)
expect(v.description.indexOf(help.link)).not.toBe(-1)
expect(v.description.indexOf(help.program)).not.toBe(-1)
expect(v.description
.indexOf(help.pathOption)).not.toBe(-1, \
"Error should have a description.")
return v
p.then(cb, cb)
return p
it "should error with Windows-specific help description \
when beautifier's program not found", ->
expect(beautifier).not.toBe(null)
expect(beautifier instanceof Beautifier).toBe(true)
waitsForPromise shouldReject: true, ->
help = {
link: "http://test.com"
program: "test-program"
pathOption: "Lang - Test Program Path"
}
# Force to be Windows
beautifier.isWindows = true
terminal = 'CMD prompt'
whichCmd = "where.exe"
# Process
p = beautifier.run("program", [], help: help)
expect(p).not.toBe(null)
expect(p instanceof beautifier.Promise).toBe(true)
cb = (v) ->
# console.log(v)
expect(v).not.toBe(null)
expect(v instanceof Error).toBe(true)
expect(v.code).toBe("CommandNotFound")
expect(v.description).not.toBe(null)
expect(v.description.indexOf(help.link)).not.toBe(-1)
expect(v.description.indexOf(help.program)).not.toBe(-1)
expect(v.description
.indexOf(help.pathOption)).not.toBe(-1, \
"Error should have a description.")
expect(v.description
.indexOf(terminal)).not.toBe(-1, \
"Error should have a description including \
'#{terminal}' in message.")
expect(v.description
.indexOf(whichCmd)).not.toBe(-1, \
"Error should have a description including \
'#{whichCmd}' in message.")
return v
p.then(cb, cb)
return p
it "should error with Mac/Linux-specific help description \
when beautifier's program not found", ->
expect(beautifier).not.toBe(null)
expect(beautifier instanceof Beautifier).toBe(true)
waitsForPromise shouldReject: true, ->
help = {
link: "http://test.com"
program: "test-program"
pathOption: "Lang - Test Program Path"
}
# Force to be Mac/Linux (not Windows)
beautifier.isWindows = false
terminal = "Terminal"
whichCmd = "which"
# Process
p = beautifier.run("program", [], help: help)
expect(p).not.toBe(null)
expect(p instanceof beautifier.Promise).toBe(true)
cb = (v) ->
# console.log(v)
expect(v).not.toBe(null)
expect(v instanceof Error).toBe(true)
expect(v.code).toBe("CommandNotFound")
expect(v.description).not.toBe(null)
expect(v.description.indexOf(help.link)).not.toBe(-1)
expect(v.description.indexOf(help.program)).not.toBe(-1)
expect(v.description
.indexOf(terminal)).not.toBe(-1, \
"Error should have a description including \
'#{terminal}' in message.")
expect(v.description
.indexOf(whichCmd)).not.toBe(-1, \
"Error should have a description including \
'#{whichCmd}' in message.")
return v
p.then(cb, cb)
return p

View File

@ -0,0 +1,84 @@
PHPCSFixer = require "../src/beautifiers/php-cs-fixer"
Beautifier = require "../src/beautifiers/beautifier"
# Use the command `window:run-package-specs` (cmd-alt-ctrl-p) to run specs.
#
# To run a specific `it` or `describe` block add an `f` to the front (e.g. `fit`
# or `fdescribe`). Remove the `f` to unfocus the block.
describe "PHP-CS-Fixer Beautifier", ->
beforeEach ->
# Activate package
waitsForPromise ->
activationPromise = atom.packages.activatePackage('atom-beautify')
# Force activate package
pack = atom.packages.getLoadedPackage("atom-beautify")
pack.activateNow()
# Change logger level
# atom.config.set('atom-beautify._loggerLevel', 'verbose')
# Return promise
return activationPromise
describe "Beautifier::beautify", ->
beautifier = null
beforeEach ->
beautifier = new PHPCSFixer()
it "should error when beautifier's program not found", ->
expect(beautifier).not.toBe(null)
expect(beautifier instanceof Beautifier).toBe(true)
waitsForPromise shouldReject: true, ->
text = ""
language = "PHP"
options = {
fixers: ""
levels: ""
}
# Mock
beautifier.getShellEnvironment = -> Promise.resolve("")
#
p = beautifier.beautify(text, language, options)
expect(p).not.toBe(null)
expect(p instanceof beautifier.Promise).toBe(true)
cb = (v) ->
console.log(v)
expect(v).not.toBe(null)
expect(v instanceof Error).toBe(true)
expect(v.code).toBe("CommandNotFound")
return v
p.then(cb, cb)
return p
# it "should error with help description \
# when beautifier's program not found", ->
# expect(beautifier).not.toBe(null)
# expect(beautifier instanceof Beautifier).toBe(true)
#
# waitsForPromise shouldReject: true, ->
# help = {
# link: "http://test.com"
# program: "test-program"
# pathOption: "Lang - Test Program Path"
# }
# p = beautifier.run("program", [], help: help)
# expect(p).not.toBe(null)
# expect(p instanceof beautifier.Promise).toBe(true)
# cb = (v) ->
# # console.log(v)
# expect(v).not.toBe(null)
# expect(v instanceof Error).toBe(true)
# expect(v.code).toBe("CommandNotFound")
# expect(v.description).not.toBe(null)
# expect(v.description.indexOf(help.link)).not.toBe(-1)
# expect(v.description.indexOf(help.program)).not.toBe(-1)
# expect(v.description
# .indexOf(help.pathOption)).not.toBe(-1, \
# "Error should have a description.")
# return v
# p.then(cb, cb)
# return p

View File

@ -80,6 +80,12 @@ module.exports = class Beautifier
return readFile(filePath, "utf8")
)
###
If platform is Windows
###
isWindows: do ->
return /^win/.test(process.platform)
###
Get Shell Environment variables
@ -99,8 +105,7 @@ module.exports = class Beautifier
return resolve(@_envCache)
# Check if Windows
isWin = /^win/.test(process.platform)
if isWin
if @isWindows
# Windows
# Use default
resolve(process.env)
@ -154,6 +159,70 @@ module.exports = class Beautifier
)
)
###
Add help to error.description
Note: error.description is not officially used in JavaScript,
however it is used internally for Atom Beautify when displaying errors.
###
commandNotFoundError: (exe, help) ->
# Create new improved error
# notify user that it may not be
# installed or in path
message = "Could not find '#{exe}'. \
The program may not be installed."
er = new Error(message)
er.code = 'CommandNotFound'
er.errno = er.code
er.syscall = 'beautifier::run'
er.file = exe
if help?
if typeof help is "object"
# Basic notice
helpStr = "See #{help.link} for program \
installation instructions.\n"
# Help to configure Atom Beautify for program's path
helpStr += "You can configure Atom Beautify \
with the absolute path \
to '#{help.program or exe}' by setting \
'#{help.pathOption}' in \
the Atom Beautify package settings.\n" if help.pathOption
# Optional, additional help
helpStr += help.additional if help.additional
# Common Help
issueSearchLink =
"https://github.com/Glavin001/atom-beautify/\
search?q=#{exe}&type=Issues"
docsLink = "https://github.com/Glavin001/\
atom-beautify/tree/master/docs"
helpStr += "Your program is properly installed if running \
'#{if @isWindows then 'where.exe' \
else 'which'} #{exe}' \
in your #{if @isWindows then 'CMD prompt' \
else 'Terminal'} \
returns an absolute path to the executable. \
If this does not work then you have not \
installed the program correctly and so \
Atom Beautify will not find the program. \
Atom Beautify requires that the program be \
found in your PATH environment variable. \n\
Note that this is not an Atom Beautify issue \
if beautification does not work and the above \
command also does not work: this is expected \
behaviour, since you have not properly installed \
your program. Please properly setup the program \
and search through existing Atom Beautify issues \
before creating a new issue. \
See #{issueSearchLink} for related Issues and \
#{docsLink} for documentation. \
If you are still unable to resolve this issue on \
your own then please create a new issue and \
ask for help.\n"
er.description = helpStr
else #if typeof help is "string"
er.description = help
return er
###
Run command-line interface command
###
@ -200,27 +269,7 @@ module.exports = class Beautifier
# Check if error is ENOENT
# (command could not be found)
if err.code is 'ENOENT' or err.errno is 'ENOENT'
# Create new improved error
# notify user that it may not be
# installed or in path
message = "Could not find '#{exe}'. \
The program may not be installed."
er = new Error(message)
if help?
if typeof help is "object"
helpStr = "See #{help.link} for program installation instructions.\n"
helpStr += "You can configure Atom Beautify with the absolute path \
to '#{help.program or exe}' by setting '#{help.pathOption}' in \
the Atom Beautify package settings.\n" if help.pathOption
helpStr += help.additional if help.additional
er.description = helpStr
else #if typeof help is "string"
er.description = help
er.code = 'CommandNotFound'
er.errno = er.code
er.syscall = 'beautifier::run'
er.file = exe
reject(er)
reject(@commandNotFoundError(exeName, help))
else
# continue as normal error
reject(err)

View File

@ -15,26 +15,48 @@ module.exports = class PHPCSFixer extends Beautifier
beautify: (text, language, options) ->
@debug('php-cs-fixer', options)
isWin = /^win/.test(process.platform)
isWin = @isWindows
if isWin
@run("php", [
options.cs_fixer_path or "php-cs-fixer.phar"
"fix"
"--level=#{options.level}" if options.level
"--fixers=#{options.fixers}" if options.fixers
tempFile = @tempFile("temp", text)
], {
ignoreReturnCode: true
help: {
# Find php-cs-fixer.phar script
@Promise.all([
@which(options.cs_fixer_path)
@which('php-cs-fixer')
@which('php-cs-fixer.phar')
]).then((paths...)=>
@debug('php-cs-fixer paths', paths)
path = require('path')
# Get first valid path
phpCSFixerPath = _.find(paths, (p) -> path.isAbsolute(p) )
@debug('phpCSFixerPath', phpCSFixerPath)
# Check if PHP-CS-Fixer path was found
if phpCSFixerPath?
# Found PHP-CS-Fixer path
@run("php", [
phpCSFixerPath
"fix"
"--level=#{options.level}" if options.level
"--fixers=#{options.fixers}" if options.fixers
tempFile = @tempFile("temp", text)
], {
ignoreReturnCode: true
help: {
link: "http://php.net/manual/en/install.php"
}
})
.then(=>
@readFile(tempFile)
)
else
# could not find PHP-CS-Fixer path
@Promise.reject(@commandNotFoundError(
'php-cs-fixer'
{
link: "https://github.com/FriendsOfPHP/PHP-CS-Fixer"
program: "php-cs-fixer.phar"
pathOption: "PHP - CS Fixer Path"
}
})
.then(=>
@readFile(tempFile)
)
})
)
)
else
@run("php-cs-fixer", [
"fix"
@ -42,12 +64,10 @@ module.exports = class PHPCSFixer extends Beautifier
"--fixers=#{options.fixers}" if options.fixers
tempFile = @tempFile("temp", text)
], {
ignoreReturnCode: true
help: {
link: "https://github.com/FriendsOfPHP/PHP-CS-Fixer"
program: "php-cs-fixer.phar"
pathOption: "PHP - CS Fixer Path"
}
ignoreReturnCode: true
help: {
link: "https://github.com/FriendsOfPHP/PHP-CS-Fixer"
}
})
.then(=>
@readFile(tempFile)