builder
Advanced tools
Comparing version 3.0.0-beta.2 to 3.0.0-beta.3
@@ -11,5 +11,8 @@ "use strict"; | ||
var path = require("path"); | ||
var clone = require("./utils/clone"); | ||
// OS-agnostic path delimiter. | ||
var DELIM = process.platform.indexOf("win") === 0 ? ";" : ":"; | ||
// OS-specific helpers | ||
var IS_WIN = process.platform.indexOf("win") === 0; | ||
var DELIM = IS_WIN ? ";" : ":"; | ||
var ENV_PATH_NAME = IS_WIN ? "Path" : "PATH"; | ||
@@ -23,3 +26,3 @@ // Node directories. | ||
* | ||
* **NOTE - Side Effects**: Mutates wrapped environment object. | ||
* **NOTE**: Clones object if real `process.env` to avoid mutation | ||
* | ||
@@ -34,3 +37,8 @@ * @param {Object} opts Options object | ||
this.config = opts.config; | ||
// Clone if real process env to avoid direct mutation. | ||
this.env = opts.env || process.env; | ||
if (this.env === process.env) { | ||
this.env = clone(this.env); | ||
} | ||
@@ -46,3 +54,3 @@ // Chalk: Force colors. | ||
// Mutate environment paths. | ||
this.env.PATH = this.updatePath(this.config.archetypePaths); | ||
this.env[ENV_PATH_NAME] = this.updatePath(this.config.archetypePaths); | ||
this.env.NODE_PATH = this.updateNodePath(this.config.archetypeNodePaths); | ||
@@ -66,3 +74,3 @@ | ||
Environment.prototype.updatePath = function (archetypePaths) { | ||
var basePath = (this.env.PATH || "") | ||
var basePath = (this.env[ENV_PATH_NAME] || "") | ||
.split(DELIM) | ||
@@ -105,4 +113,2 @@ .filter(function (x) { return x; }); | ||
* | ||
* **Note**: We only go _one level deep_ for process.env mutations. | ||
* | ||
* Resolution order: | ||
@@ -109,0 +115,0 @@ * 1. Existing environment |
@@ -5,2 +5,3 @@ "use strict"; | ||
var args = require("./args"); | ||
var clone = require("./utils/clone"); | ||
@@ -27,3 +28,3 @@ // Wrap "type". | ||
* | ||
* **NOTE - Side Effects**: Mutates environment. | ||
* **NOTE**: Clones object if real `process.env` to avoid mutation | ||
* | ||
@@ -37,6 +38,11 @@ * @param {Object} opts Options object | ||
opts = opts || {}; | ||
var env = opts.env && opts.env.env || process.env; | ||
// Clone if real process env to avoid direct mutation. | ||
log._env = opts.env && opts.env.env || log._env || process.env; | ||
if (log._env === process.env) { | ||
log._env = clone(log._env); | ||
} | ||
// Try to determine log level from environment. | ||
var level = env._BUILDER_ARGS_LOG_LEVEL; | ||
var level = log._env._BUILDER_ARGS_LOG_LEVEL; | ||
@@ -50,3 +56,3 @@ // If not, determine log level from command line. | ||
// Statefully set level. | ||
env._BUILDER_ARGS_LOG_LEVEL = level; | ||
log._env._BUILDER_ARGS_LOG_LEVEL = level; | ||
log._level = LEVELS[level]; | ||
@@ -63,3 +69,3 @@ if (typeof log._level === "undefined") { | ||
_unsetLevel: function () { | ||
delete process.env._BUILDER_ARGS_LOG_LEVEL; | ||
delete log._env._BUILDER_ARGS_LOG_LEVEL; | ||
delete log._level; | ||
@@ -66,0 +72,0 @@ delete log._queue; |
"use strict"; | ||
/*eslint max-params: [2, 4], max-statements: [2, 20] */ | ||
var path = require("path"); | ||
var _ = require("lodash"); | ||
@@ -14,2 +13,3 @@ var async = require("async"); | ||
var Task = require("./task"); | ||
var clone = require("./utils/clone"); | ||
var runner; | ||
@@ -69,17 +69,24 @@ | ||
* @param {String} str String to parse | ||
* @param {String} token Token to replace | ||
* @param {String} tokens Tokens to replace (multiple for windows) | ||
* @param {String} sub Replacement | ||
* @returns {String} Mutated string. | ||
* @returns {String} Mutated string | ||
*/ | ||
var replaceToken = function (str, token, sub) { | ||
var tokenRe = new RegExp("(^|\\s|\\'|\\\")(" + _.escapeRegExp(token) + ")", "g"); | ||
var replaceToken = function (str, tokens, sub) { | ||
var tokenRes = tokens.map(function (token) { | ||
return { | ||
token: token, | ||
re: new RegExp("(^|\\s|\\'|\\\")(" + _.escapeRegExp(token) + ")", "g") | ||
}; | ||
}); | ||
return str.replace(tokenRe, function (match, prelimMatch, tokenMatch/* offset, origStr*/) { | ||
// Sanity check. | ||
if (tokenMatch !== token) { | ||
throw new Error("Bad match " + match + " for token " + token); | ||
} | ||
return tokenRes.reduce(function (memo, obj) { | ||
return memo.replace(obj.re, function (match, prelimMatch, tokenMatch/* offset, origStr*/) { | ||
// Sanity check. | ||
if (tokenMatch !== obj.token) { | ||
throw new Error("Bad match " + match + " for token " + obj.token); | ||
} | ||
return prelimMatch + sub; | ||
}); | ||
return prelimMatch + sub; | ||
}); | ||
}, str); | ||
}; | ||
@@ -133,5 +140,9 @@ | ||
// Create final token for replacing. | ||
var archetypeToken = path.join("node_modules", archetypeName); | ||
var archetypeTokens = [["node_modules", archetypeName].join("/")]; // unix | ||
if (process.platform.indexOf("win") === 0) { | ||
// Add windows delimiter too. | ||
archetypeTokens.push(["node_modules", archetypeName].join("\\")); | ||
} | ||
return replaceToken(cmd, archetypeToken, archetypePath); | ||
return replaceToken(cmd, archetypeTokens, archetypePath); | ||
}; | ||
@@ -161,7 +172,7 @@ | ||
stdio: buffer ? "pipe" : "inherit" | ||
}, shOpts); | ||
}, clone(shOpts)); // Clone deep to coerce env to plain object. | ||
// Copied from npm's lib/utils/lifecycle.js | ||
if (process.platform === "win32") { | ||
sh = process.env.comspec || "cmd"; | ||
sh = shOpts.env.comspec || "cmd"; | ||
shFlag = "/d /s /c"; | ||
@@ -427,3 +438,3 @@ shOpts.windowsVerbatimArguments = true; | ||
var queue = opts.queue; | ||
var taskEnvs = opts._envs; | ||
var taskEnvs = clone(opts._envs); | ||
var bail = opts.bail; | ||
@@ -436,3 +447,3 @@ | ||
// `process.env` is a special object which changes merge behavior. | ||
var taskShOpts = _.merge(_.cloneDeep(shOpts), { env: taskEnv }); | ||
var taskShOpts = _.merge(clone(shOpts), { env: taskEnv }); | ||
var taskOpts = _.extend({ tracker: tracker, taskEnv: taskEnv }, opts); | ||
@@ -439,0 +450,0 @@ |
{ | ||
"name": "builder", | ||
"version": "3.0.0-beta.2", | ||
"version": "3.0.0-beta.3", | ||
"description": "An NPM-based task runner", | ||
@@ -5,0 +5,0 @@ "repository": { |
[![Travis Status][trav_img]][trav_site] | ||
[![Appveyor Status][av_img]][av_site] | ||
[![Coverage Status][cov_img]][cov_site] | ||
@@ -89,2 +90,3 @@ | ||
- [PATH, NODE_PATH Resolution](#path-node_path-resolution) | ||
- [Environment Variables](#environment-variables) | ||
- [Alternative to `npm link`](#alternative-to-npm-link) | ||
@@ -94,4 +96,2 @@ - [Project Root](#project-root) | ||
- [Other Process Execution](#other-process-execution) | ||
- [Terminal Color](#terminal-color) | ||
- [Why Exec?](#why-exec) | ||
- [I Give Up. How Do I Abandon Builder?](#i-give-up-how-do-i-abandon-builder) | ||
@@ -1262,2 +1262,15 @@ - [Versions v1, v2, v3](#versions-v1-v2-v3) | ||
### Environment Variables | ||
Builder clones the entire environment object before mutating it for further | ||
execution of tasks. On Mac/Linux, this has no real change of behavior of how | ||
the execution environment works. However, on Windows, there are some subtle | ||
issues with the fact that Windows has a case-insensitive environment variable | ||
model wherein you can set `PATH` in a node process, but internally this is | ||
transformed to set `Path`. Builder specifically handles `PATH` correctly across | ||
platforms for it's own specific mutation. | ||
However, if your tasks rely on the Windows coercion of case-insensitivity of | ||
environment variables, you may run into some idiosyncratic problems with tasks. | ||
### Alternative to `npm link` | ||
@@ -1333,18 +1346,2 @@ | ||
### Terminal Color | ||
Builder uses `exec` under the hood with piped `stdout` and `stderr`. Programs | ||
typically interpret the piped environment as "doesn't support color" and | ||
disable color. Consequently, you typically need to set a "**force color**" | ||
option on your executables in `scripts` commands if they exist. | ||
### Why Exec? | ||
So, why `exec` and not `spawn` or something similar that has a lot more process | ||
control and flexibility? The answer lies in the fact that most of what Builder | ||
consumes is shell strings to execute, like `script --foo --bar "Hi there"`. | ||
_Parsing_ these arguments into something easily consumable by `spawn` and always | ||
correct is quite challenging. `exec` works easily with straight strings, and | ||
since that is the target of `scripts` commands, that is what we use for Builder. | ||
### I Give Up. How Do I Abandon Builder? | ||
@@ -1425,4 +1422,6 @@ | ||
[trav_site]: https://travis-ci.org/FormidableLabs/builder | ||
[av_img]: https://ci.appveyor.com/api/projects/status/oq3m2hay1tl82tsj?svg=true | ||
[av_site]: https://ci.appveyor.com/project/FormidableLabs/builder | ||
[cov]: https://coveralls.io | ||
[cov_img]: https://img.shields.io/coveralls/FormidableLabs/builder.svg | ||
[cov_site]: https://coveralls.io/r/FormidableLabs/builder |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
108668
18
1549
1423