From 240368fb09efaf67b31f10f0cf7f3fdba46fa65f Mon Sep 17 00:00:00 2001 From: Glavin Wiechert Date: Thu, 30 Apr 2015 15:06:54 -0300 Subject: [PATCH] Closes #164. Auto-detect Shell environment variables --- src/beautifiers/beautifier.coffee | 124 ++++++++++++++++++++-------- src/beautifiers/cli-beautify.coffee | 111 ------------------------- src/beautifiers/index.coffee | 9 +- 3 files changed, 90 insertions(+), 154 deletions(-) delete mode 100644 src/beautifiers/cli-beautify.coffee diff --git a/src/beautifiers/beautifier.coffee b/src/beautifiers/beautifier.coffee index 24a2236..7d66e23 100644 --- a/src/beautifiers/beautifier.coffee +++ b/src/beautifiers/beautifier.coffee @@ -52,16 +52,18 @@ module.exports = class Beautifier ### Create temporary file ### - tempFile: (name = "atom-beautify-temp", contents) -> + tempFile: (name = "atom-beautify-temp", contents = "") -> return new Promise((resolve, reject) -> # create temp file temp.open(name, (err, info) -> - # console.log(name, info) + console.log(name, err, info) return reject(err) if err - fs.write(info.fd, contents) if contents? - fs.close(info.fd, (err) -> + fs.write(info.fd, contents, (err) -> return reject(err) if err - resolve(info.path) + fs.close(info.fd, (err) -> + return reject(err) if err + resolve(info.path) + ) ) ) ) @@ -75,49 +77,101 @@ module.exports = class Beautifier return readFile(filePath, "utf8") ) + ### + Get Shell Environment variables + + Special thank you to @ioquatix + See https://github.com/ioquatix/script-runner/blob/v1.5.0/lib/script-runner.coffee#L45-L63 + ### + _envCache: null + _envCacheDate: null + _envCacheExpiry: 10000 # 10 seconds + getShellEnvironment: -> + return new @Promise((resolve, reject) => + # Check Cache + if @_envCache? and @_envCacheDate? + # Check if Cache is old + if (new Date() - @_envCacheDate) < @_envCacheExpiry + # Still fresh + return resolve(@_envCache) + + # Check if Windows + isWin = /^win/.test(process.platform) + if isWin + # Windows + # Use default + resolve(process.env) + else + # Mac & Linux + # I tried using ChildProcess.execFile but there is no way to set detached and + # this causes the child shell to lock up. + # This command runs an interactive login shell and + # executes the export command to get a list of environment variables. + # We then use these to run the script: + child = spawn process.env.SHELL, ['-ilc', 'env'], + # This is essential for interactive shells, otherwise it never finishes: + detached: true, + # We don't care about stdin, stderr can go out the usual way: + stdio: ['ignore', 'pipe', process.stderr] + # We buffer stdout: + buffer = '' + child.stdout.on 'data', (data) -> buffer += data + # When the process finishes, extract the environment variables and pass them to the callback: + child.on 'close', (code, signal) => + if code isnt 0 + return reject(new Error("Could not get Shell Environment. Exit code: "+code+", Signal: "+signal)) + environment = {} + for definition in buffer.split('\n') + [key, value] = definition.split('=', 2) + environment[key] = value if key != '' + # Cache Environment + @_envCache = environment + @_envCacheDate = new Date() + resolve(environment) + ) + ### Run command-line interface command ### run: (executable, args) -> - console.log('run', arguments) - # TODO: Get $PATH # Resolve executable Promise.resolve(executable) - .then((exe) -> - console.log('exe', exe) + .then((exe) => # Flatten args first args = _.flatten(args) - console.log('flat args', args) # Resolve all args Promise.all(args) - .then((args) -> - return new Promise((resolve, reject) -> - console.log('resolved args', args) - # Remove null values + .then((args) => + return new Promise((resolve, reject) => + # Remove undefined/null values args = _.without(args, undefined) args = _.without(args, null) - console.log('args without undefined/null', args) - # Spawn command - stdout = "" - stderr = "" - options = { - env: { - PATH: "/Users/glavin/.rvm/gems/ruby-1.9.3-p551/bin:/Users/glavin/.rvm/gems/ruby-1.9.3-p551@global/bin:/Users/glavin/.rvm/rubies/ruby-1.9.3-p551/bin:/Users/glavin/.nvm/v0.10.32/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/texbin:/Developer/android-sdk-macosx/tools:/Developer/android-sdk-macosx/platform-tools:/Users/glavin/pear/bin:/Users/glavin/gocode/bin:/Users/glavin/.rvm/bin" + # Get PATH and other environment variables + @getShellEnvironment() + .then((env) -> + # Spawn command + stdout = "" + stderr = "" + options = { + env: env } - } - console.log('spawn', exe, args) - cmd = spawn(exe, args, options) - # add a 'data' event listener for the spawn instance - cmd.stdout.on('data', (data) -> stdout += data ) - cmd.stderr.on('data', (data) -> stderr += data ) - # when the spawn child process exits, check if there were any errors and close the writeable stream - cmd.on('exit', (code) -> - console.log('spawn done', code, stderr, stdout) - # If return code is not 0 then error occured - if code isnt 0 - reject(stderr) - else - resolve(stdout) + # console.log('spawn', exe, args) + cmd = spawn(exe, args, options) + # add a 'data' event listener for the spawn instance + cmd.stdout.on('data', (data) -> stdout += data ) + cmd.stderr.on('data', (data) -> stderr += data ) + # when the spawn child process exits, check if there were any errors and close the writeable stream + cmd.on('exit', (code) -> + # console.log('spawn done', code, stderr, stdout) + # If return code is not 0 then error occured + if code isnt 0 + reject(stderr) + else + resolve(stdout) + ) + cmd.on('error', (err) -> + reject(err) + ) ) ) ) diff --git a/src/beautifiers/cli-beautify.coffee b/src/beautifiers/cli-beautify.coffee deleted file mode 100644 index 3cefb2d..0000000 --- a/src/beautifiers/cli-beautify.coffee +++ /dev/null @@ -1,111 +0,0 @@ -### -Requires http://pear.php.net/package/PHP_Beautifier -### -"use strict" -fs = require("fs") -temp = require("temp").track() -exec = require("child_process").exec -module.exports = (getCmd, isStdout) -> - (text, options, callback) -> - - # Create temp input file - temp.open "input", (err, info) -> - unless err - - # Save current text to input file - fs.write info.fd, text or "", -> - fs.close info.fd, (err) -> - unless err - - # Create temp output file - outputPath = temp.path() - deleteOutputFile = -> - temp.cleanup() - # Delete the output path - fs.unlink outputPath, (err) -> - # console.log "Deleting output file", err if err - return - return - - # Process the command - processCmd = (cmd, optCallback) -> - if optCallback? and typeof optCallback is "function" - # console.log('Optional Callback found') - cb = callback # Save callback for later - callback = (output) -> # Wrap callback (cb) with optCallback - # console.log('Callback called!', output) - optCallback(output, cb) - - if typeof cmd is "string" - - config = env: process.env - isWin = /^win/.test(process.platform) - unless isWin - - # We need the $PATH to be correct when executing the command. - # This should normalize the $PATH - # by calling the external files that would usually - # change the $PATH variable on user login. - $path = "[ -f ~/.bash_profile ] && source ~/.bash_profile > /dev/null 2>&1;" - $path += "[ -f ~/.bashrc ] && source ~/.bashrc > /dev/null 2>&1;" - - # See http://stackoverflow.com/a/638980/2578205 - # for checking if file exists in Bash - cmd = $path + cmd - - # Execute and beautify! - exec cmd, config, (err, stdout, stderr) -> - - # console.log(stderr); - unless err - - # Beautification has completed - if isStdout - - # Execute callback with resulting output text - callback stdout - deleteOutputFile() - else - - # Read contents of output file - fs.readFile outputPath, "utf8", (err, newText) -> - - # Execute callback with resulting output text - callback newText - deleteOutputFile() - return - - else - console.error "Beautifcation Error: ", err - callback err - deleteOutputFile() - return - - # Check if there's an error - else if cmd instanceof Error - return callback(cmd) - else - console.error "CLI Beautifier command not valid." - return callback(new Error("CLI Beautifier command not valid."+ - " Invalid command '#{cmd}'.")) - - - # Get the command - try - cmd = getCmd(info.path, outputPath, options, processCmd) # jshint ignore: line - catch e - return callback(e) - - if typeof cmd is "string" - processCmd cmd - # Check if there's an error - else if cmd instanceof Error - return callback(cmd) - - return - - return - - return - - return diff --git a/src/beautifiers/index.coffee b/src/beautifiers/index.coffee index 1e6e43c..4510f44 100644 --- a/src/beautifiers/index.coffee +++ b/src/beautifiers/index.coffee @@ -95,8 +95,6 @@ module.exports = class Beautifiers # getBeautifiersForExtension: (extension) -> beautify: (text, allOptions, grammar, filePath) -> - # console.log(@) - return new Promise((resolve, reject) => # Get language @@ -112,15 +110,12 @@ module.exports = class Beautifiers return resolve(null) # Options for Language - console.log('allOptions', allOptions) options = @getOptions(language.namespace, allOptions) || {} # Support fallback for options if language.fallback? for fallback in language.fallback # Merge current options on top of fallback options - console.log(fallback) options = _.merge(@getOptions(fallback, allOptions) || {}, options) - console.log('options', options) # Get Beautifiers # console.log(grammar, language) @@ -136,7 +131,6 @@ module.exports = class Beautifiers # Transform options, if applicable beautifierOptions = beautifier.options[language.name] - console.log('beautifierOptions', beautifierOptions) if typeof beautifierOptions is "boolean" if beautifierOptions isnt true # Disable options @@ -158,8 +152,7 @@ module.exports = class Beautifiers # Replace old options with new transformed options options = transformedOptions else - console.warn("Unsupported Language options: ",beautifierOptions) - console.log('beautify!', beautifier, language, options) + console.warn("Unsupported Language options: ", beautifierOptions) beautifier.beautify(text, language.name, options) .then(resolve) .catch(reject)