jharding / grunt-exec

Grunt plugin for executing shell commands.
https://npmjs.org/package/grunt-exec
Other
248 stars 47 forks source link

WINDOWS REGRESSION: command with double-quotes cannot be executed #81

Closed warappa closed 7 years ago

warappa commented 7 years ago

In grunt-exec 1.0.1 it was possible to pass multiple quoted arguments like

exec: {
    {
        command: '"C:\\full-path\\chutzpah.console.exe" /path "C:\\full-path\\chutzpah.json"'
    }
}

With version 2.0.0 I get the following error: >> Failed with: Error: spawn "C:\full-path\chutzpah.console.exe" ENOENT

Going back to 1.0.1 fixes the problem for now.

gwicksted commented 7 years ago

Hi @warappa on my Windows 10 machine, I tested the following with both cmd.exe and powershell:

exec: {
    command: '"C:\\windows\\notepad.exe" "C:\\test.json"'
}

Which caused notepad to ask if I wanted to create the file C:\test.json (it does not exist on my disk). This is the expected behavior.

Can you perhaps provide some additional information? eg. Windows version, shell (and version), grunt version, node version? The full path would also be helpful. Perhaps yours has spaces? (my test did not)

To do this, run npm list, npm -v, node -v,

If you are running in powershell, please execute the following:

$PSVersionTable.PSVersion
[System.Environment]::OSVersion.Version
[System.Environment]::Is64BitProcess
[Environment]::Is64BitOperatingSystem
(Get-WmiObject win32_processor | Where-Object{$_.deviceID -eq "CPU0"}).AddressWidth
(Get-WmiObject -Class Win32_ComputerSystem).SystemType
npm -v
node -v
npm list
$pwd
Get-Content gruntfile.js | Where { $_.Contains('command: ') } | Out-String
warappa commented 7 years ago
Windows PowerShell
Copyright (C) 2016 Microsoft Corporation. Alle Rechte vorbehalten.

PS C:\full-path> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      14393  1066

PS C:\full-path> [System.Environment]::OSVersion.Version

Major  Minor  Build  Revision
-----  -----  -----  --------
10     0      14393  0

PS C:\full-path> [System.Environment]::Is64BitProcess
False
PS C:\full-path> [Environment]::Is64BitOperatingSystem
True
PS C:\full-path> (Get-WmiObject win32_processor | Where-Object{$_.deviceID -eq "CPU0"}).AddressWidth
64
PS C:\full-path> (Get-WmiObject -Class Win32_ComputerSystem).SystemType
x64-based PC
PS C:\full-path> npm -v
3.10.3
PS C:\full-path> node -v
v6.3.0
PS C:\full-path> npm list
webapp.test@1.0.0 C:\full-path
+-- grunt@0.4.5
| +-- async@0.1.22
| +-- coffee-script@1.3.3
| +-- colors@0.6.2
| +-- dateformat@1.0.2-1.2.3
| +-- eventemitter2@0.4.14
| +-- exit@0.1.2
| +-- findup-sync@0.1.3
| | +-- glob@3.2.11
| | | `-- minimatch@0.3.0
| | `-- lodash@2.4.2
| +-- getobject@0.1.0
| +-- glob@3.1.21
| | +-- graceful-fs@1.2.3
| | `-- inherits@1.0.2
| +-- grunt-legacy-log@0.1.3
| | +-- grunt-legacy-log-utils@0.1.1
| | | +-- lodash@2.4.2
| | | `-- underscore.string@2.3.3
| | +-- lodash@2.4.2
| | `-- underscore.string@2.3.3
| +-- grunt-legacy-util@0.2.0
| +-- hooker@0.2.3
| +-- iconv-lite@0.2.11
| +-- js-yaml@2.0.5
| | +-- argparse@0.1.16
| | | +-- underscore@1.7.0
| | | `-- underscore.string@2.4.0
| | `-- esprima@1.0.4
| +-- lodash@0.9.2
| +-- minimatch@0.2.14
| | +-- lru-cache@2.7.3
| | `-- sigmund@1.0.1
| +-- nopt@1.0.10
| | `-- abbrev@1.1.0
| +-- rimraf@2.2.8
| +-- underscore.string@2.2.1
| `-- which@1.0.9
+-- grunt-angular-templates@1.1.0
| `-- html-minifier@2.1.7
|   +-- change-case@3.0.1
|   | +-- camel-case@3.0.0
|   | +-- constant-case@2.0.0
|   | +-- dot-case@2.1.1
|   | +-- header-case@1.0.1
|   | +-- is-lower-case@1.1.3
|   | +-- is-upper-case@1.1.2
|   | +-- lower-case@1.1.4
|   | +-- lower-case-first@1.0.2
|   | +-- no-case@2.3.1
|   | +-- param-case@2.1.1
|   | +-- pascal-case@2.0.1
|   | +-- path-case@2.1.1
|   | +-- sentence-case@2.1.1
|   | +-- snake-case@2.1.0
|   | +-- swap-case@1.1.2
|   | +-- title-case@2.1.1
|   | +-- upper-case@1.1.3
|   | `-- upper-case-first@1.1.2
|   +-- clean-css@3.4.25
|   | +-- commander@2.8.1
|   | `-- source-map@0.4.4
|   +-- commander@2.9.0
|   | `-- graceful-readlink@1.0.1
|   +-- he@1.1.1
|   +-- ncname@1.0.0
|   | `-- xml-char-classes@1.0.0
|   `-- relateurl@0.2.7
+-- grunt-concat-css@0.3.2
+-- grunt-contrib-concat@0.5.1
| +-- chalk@0.5.1
| | +-- ansi-styles@1.1.0
| | +-- escape-string-regexp@1.0.5
| | +-- has-ansi@0.1.0
| | | `-- ansi-regex@0.2.1
| | +-- strip-ansi@0.3.0
| | `-- supports-color@0.2.0
| `-- source-map@0.3.0
|   `-- amdefine@1.0.1
+-- grunt-contrib-uglify@0.9.2
| +-- chalk@1.1.3
| | +-- ansi-styles@2.2.1
| | +-- has-ansi@2.0.0
| | | `-- ansi-regex@2.1.1
| | +-- strip-ansi@3.0.1
| | `-- supports-color@2.0.0
| +-- lodash@3.10.1
| +-- maxmin@1.1.0
| | +-- chalk@1.1.3
| | | +-- ansi-styles@2.2.1
| | | +-- has-ansi@2.0.0
| | | | `-- ansi-regex@2.1.1
| | | +-- strip-ansi@3.0.1
| | | `-- supports-color@2.0.0
| | +-- figures@1.7.0
| | +-- gzip-size@1.0.0
| | | +-- browserify-zlib@0.1.4
| | | | `-- pako@0.2.9
| | | `-- concat-stream@1.6.0
| | |   `-- typedarray@0.0.6
| | `-- pretty-bytes@1.0.4
| +-- uglify-js@2.6.4
| | +-- async@0.2.10
| | +-- source-map@0.5.6
| | +-- uglify-to-browserify@1.0.2
| | `-- yargs@3.10.0
| |   +-- camelcase@1.2.1
| |   +-- cliui@2.1.0
| |   | +-- center-align@0.1.3
| |   | | +-- align-text@0.1.4
| |   | | | +-- longest@1.0.1
| |   | | | `-- repeat-string@1.6.1
| |   | | `-- lazy-cache@1.0.4
| |   | +-- right-align@0.1.3
| |   | `-- wordwrap@0.0.2
| |   +-- decamelize@1.2.0
| |   `-- window-size@0.1.0
| `-- uri-path@0.0.2
+-- grunt-contrib-watch@0.6.1
| +-- async@0.2.10
| +-- gaze@0.5.2
| | `-- globule@0.1.0
| |   `-- lodash@1.0.2
| +-- lodash@2.4.2
| `-- tiny-lr-fork@0.0.5
|   +-- debug@0.7.4
|   +-- faye-websocket@0.4.4
|   +-- noptify@0.0.3
|   | `-- nopt@2.0.0
|   `-- qs@0.5.6
+-- grunt-dom-munger@3.4.0
| `-- cheerio@0.12.4
|   +-- cheerio-select@0.0.3
|   | `-- CSSselect@0.7.0
|   |   +-- boolbase@1.0.0
|   |   +-- CSSwhat@0.4.7
|   |   +-- domutils@1.4.3
|   |   `-- nth-check@1.0.1
|   +-- entities@0.5.0
|   +-- htmlparser2@3.1.4
|   | +-- domelementtype@1.3.0
|   | +-- domhandler@2.0.3
|   | +-- domutils@1.1.6
|   | `-- readable-stream@1.0.34
|   |   +-- core-util-is@1.0.2
|   |   +-- isarray@0.0.1
|   |   `-- string_decoder@0.10.31
|   `-- underscore@1.4.4
+-- grunt-exec@2.0.0
+-- grunt-ng-constant@2.0.1
| +-- jju@1.3.0
| +-- lodash@4.17.4
| +-- merge@1.2.0
| `-- tosource@1.0.0
+-- grunt-sass@2.0.0
| +-- each-async@1.1.1
| | +-- onetime@1.1.0
| | `-- set-immediate-shim@1.0.1
| +-- node-sass@4.5.2
| | +-- async-foreach@0.1.3
| | +-- chalk@1.1.3
| | | +-- ansi-styles@2.2.1
| | | +-- has-ansi@2.0.0
| | | | `-- ansi-regex@2.1.1
| | | +-- strip-ansi@3.0.1
| | | `-- supports-color@2.0.0
| | +-- cross-spawn@3.0.1
| | | +-- lru-cache@4.0.2
| | | | +-- pseudomap@1.0.2
| | | | `-- yallist@2.1.2
| | | `-- which@1.2.14
| | |   `-- isexe@2.0.0
| | +-- gaze@1.1.2
| | | `-- globule@1.1.0
| | |   `-- lodash@4.16.6
| | +-- get-stdin@4.0.1
| | +-- glob@7.1.1
| | | +-- fs.realpath@1.0.0
| | | +-- inflight@1.0.6
| | | | `-- wrappy@1.0.2
| | | +-- minimatch@3.0.4
| | | `-- once@1.4.0
| | +-- in-publish@2.0.0
| | +-- lodash.assign@4.2.0
| | +-- lodash.clonedeep@4.5.0
| | +-- lodash.mergewith@4.6.0
| | +-- meow@3.7.0
| | | +-- camelcase-keys@2.1.0
| | | | `-- camelcase@2.1.1
| | | +-- loud-rejection@1.6.0
| | | | +-- currently-unhandled@0.4.1
| | | | | `-- array-find-index@1.0.2
| | | | `-- signal-exit@3.0.2
| | | +-- map-obj@1.0.1
| | | +-- minimist@1.2.0
| | | +-- normalize-package-data@2.3.8
| | | | +-- hosted-git-info@2.4.2
| | | | +-- is-builtin-module@1.0.0
| | | | | `-- builtin-modules@1.1.1
| | | | `-- validate-npm-package-license@3.0.1
| | | |   +-- spdx-correct@1.0.2
| | | |   | `-- spdx-license-ids@1.2.2
| | | |   `-- spdx-expression-parse@1.0.4
| | | +-- read-pkg-up@1.0.1
| | | | +-- find-up@1.1.2
| | | | | +-- path-exists@2.1.0
| | | | | `-- pinkie-promise@2.0.1
| | | | |   `-- pinkie@2.0.4
| | | | `-- read-pkg@1.1.0
| | | |   +-- load-json-file@1.1.0
| | | |   | +-- graceful-fs@4.1.11
| | | |   | +-- parse-json@2.2.0
| | | |   | | `-- error-ex@1.3.1
| | | |   | |   `-- is-arrayish@0.2.1
| | | |   | +-- pify@2.3.0
| | | |   | `-- strip-bom@2.0.0
| | | |   |   `-- is-utf8@0.2.1
| | | |   `-- path-type@1.1.0
| | | |     `-- graceful-fs@4.1.11
| | | +-- redent@1.0.0
| | | | +-- indent-string@2.1.0
| | | | | `-- repeating@2.0.1
| | | | |   `-- is-finite@1.0.2
| | | | `-- strip-indent@1.0.1
| | | `-- trim-newlines@1.0.0
| | +-- mkdirp@0.5.1
| | | `-- minimist@0.0.8
| | +-- nan@2.6.2
| | +-- node-gyp@3.6.1
| | | +-- fstream@1.0.11
| | | | `-- graceful-fs@4.1.11
| | | +-- glob@7.1.1
| | | +-- graceful-fs@4.1.11
| | | +-- minimatch@3.0.4
| | | | `-- brace-expansion@1.1.7
| | | |   +-- balanced-match@0.4.2
| | | |   `-- concat-map@0.0.1
| | | +-- nopt@3.0.6
| | | +-- osenv@0.1.4
| | | | +-- os-homedir@1.0.2
| | | | `-- os-tmpdir@1.0.2
| | | +-- semver@5.3.0
| | | `-- tar@2.2.1
| | |   `-- block-stream@0.0.9
| | +-- npmlog@4.1.0
| | | +-- are-we-there-yet@1.1.4
| | | | `-- delegates@1.0.0
| | | +-- console-control-strings@1.1.0
| | | +-- gauge@2.7.4
| | | | +-- aproba@1.1.1
| | | | +-- has-unicode@2.0.1
| | | | +-- string-width@1.0.2
| | | | | +-- code-point-at@1.1.0
| | | | | +-- is-fullwidth-code-point@1.0.0
| | | | | | `-- number-is-nan@1.0.1
| | | | | `-- strip-ansi@3.0.1
| | | | |   `-- ansi-regex@2.1.1
| | | | +-- strip-ansi@3.0.1
| | | | | `-- ansi-regex@2.1.1
| | | | `-- wide-align@1.1.0
| | | `-- set-blocking@2.0.0
| | +-- request@2.81.0
| | | +-- aws-sign2@0.6.0
| | | +-- aws4@1.6.0
| | | +-- caseless@0.12.0
| | | +-- combined-stream@1.0.5
| | | | `-- delayed-stream@1.0.0
| | | +-- extend@3.0.1
| | | +-- forever-agent@0.6.1
| | | +-- form-data@2.1.4
| | | | `-- asynckit@0.4.0
| | | +-- har-validator@4.2.1
| | | | +-- ajv@4.11.8
| | | | | +-- co@4.6.0
| | | | | `-- json-stable-stringify@1.0.1
| | | | |   `-- jsonify@0.0.0
| | | | `-- har-schema@1.0.5
| | | +-- hawk@3.1.3
| | | | +-- boom@2.10.1
| | | | +-- cryptiles@2.0.5
| | | | +-- hoek@2.16.3
| | | | `-- sntp@1.0.9
| | | +-- http-signature@1.1.1
| | | | +-- assert-plus@0.2.0
| | | | +-- jsprim@1.4.0
| | | | | +-- assert-plus@1.0.0
| | | | | +-- extsprintf@1.0.2
| | | | | +-- json-schema@0.2.3
| | | | | `-- verror@1.3.6
| | | | `-- sshpk@1.13.0
| | | |   +-- asn1@0.2.3
| | | |   +-- assert-plus@1.0.0
| | | |   +-- bcrypt-pbkdf@1.0.1
| | | |   +-- dashdash@1.14.1
| | | |   | `-- assert-plus@1.0.0
| | | |   +-- ecc-jsbn@0.1.1
| | | |   +-- getpass@0.1.7
| | | |   | `-- assert-plus@1.0.0
| | | |   +-- jodid25519@1.0.2
| | | |   +-- jsbn@0.1.1
| | | |   `-- tweetnacl@0.14.5
| | | +-- is-typedarray@1.0.0
| | | +-- isstream@0.1.2
| | | +-- json-stringify-safe@5.0.1
| | | +-- mime-types@2.1.15
| | | | `-- mime-db@1.27.0
| | | +-- oauth-sign@0.8.2
| | | +-- performance-now@0.2.0
| | | +-- qs@6.4.0
| | | +-- safe-buffer@5.0.1
| | | +-- stringstream@0.0.5
| | | +-- tough-cookie@2.3.2
| | | | `-- punycode@1.4.1
| | | +-- tunnel-agent@0.6.0
| | | `-- uuid@3.0.1
| | +-- sass-graph@2.2.2
| | | +-- glob@7.1.1
| | | | `-- minimatch@3.0.4
| | | +-- lodash@4.17.4
| | | +-- scss-tokenizer@0.2.1
| | | | `-- js-base64@2.1.9
| | | `-- yargs@6.6.0
| | |   +-- camelcase@3.0.0
| | |   +-- cliui@3.2.0
| | |   | +-- strip-ansi@3.0.1
| | |   | | `-- ansi-regex@2.1.1
| | |   | `-- wrap-ansi@2.1.0
| | |   |   `-- strip-ansi@3.0.1
| | |   |     `-- ansi-regex@2.1.1
| | |   +-- get-caller-file@1.0.2
| | |   +-- os-locale@1.4.0
| | |   | `-- lcid@1.0.0
| | |   |   `-- invert-kv@1.0.0
| | |   +-- require-directory@2.1.1
| | |   +-- require-main-filename@1.0.1
| | |   +-- which-module@1.0.0
| | |   +-- y18n@3.2.1
| | |   `-- yargs-parser@4.2.1
| | |     `-- camelcase@3.0.0
| | `-- stdout-stream@1.4.0
| |   `-- readable-stream@2.2.9
| |     +-- buffer-shims@1.0.0
| |     +-- isarray@1.0.0
| |     +-- process-nextick-args@1.0.7
| |     +-- string_decoder@1.0.0
| |     `-- util-deprecate@1.0.2
| `-- object-assign@4.1.1
+-- grunt-tslint@2.5.0
+-- grunt-typescript@0.8.0
| +-- bluebird@2.9.34
| +-- chokidar@1.7.0
| | +-- anymatch@1.3.0
| | | +-- arrify@1.0.1
| | | `-- micromatch@2.3.11
| | |   +-- arr-diff@2.0.0
| | |   | `-- arr-flatten@1.0.3
| | |   +-- array-unique@0.2.1
| | |   +-- braces@1.8.5
| | |   | +-- expand-range@1.8.2
| | |   | | `-- fill-range@2.2.3
| | |   | |   +-- is-number@2.1.0
| | |   | |   +-- isobject@2.1.0
| | |   | |   `-- randomatic@1.1.6
| | |   | +-- preserve@0.2.0
| | |   | `-- repeat-element@1.1.2
| | |   +-- expand-brackets@0.1.5
| | |   | `-- is-posix-bracket@0.1.1
| | |   +-- extglob@0.3.2
| | |   +-- filename-regex@2.0.1
| | |   +-- kind-of@3.2.0
| | |   | `-- is-buffer@1.1.5
| | |   +-- normalize-path@2.1.1
| | |   | `-- remove-trailing-separator@1.0.1
| | |   +-- object.omit@2.0.1
| | |   | +-- for-own@0.1.5
| | |   | | `-- for-in@1.0.2
| | |   | `-- is-extendable@0.1.1
| | |   +-- parse-glob@3.0.4
| | |   | +-- glob-base@0.3.0
| | |   | `-- is-dotfile@1.0.2
| | |   `-- regex-cache@0.4.3
| | |     +-- is-equal-shallow@0.1.3
| | |     `-- is-primitive@2.0.0
| | +-- async-each@1.0.1
| | +-- UNMET OPTIONAL DEPENDENCY fsevents@^1.0.0
| | +-- glob-parent@2.0.0
| | +-- inherits@2.0.3
| | +-- is-binary-path@1.0.1
| | | `-- binary-extensions@1.8.0
| | +-- is-glob@2.0.1
| | | `-- is-extglob@1.0.0
| | +-- path-is-absolute@1.0.1
| | `-- readdirp@2.1.0
| |   +-- graceful-fs@4.1.11
| |   `-- minimatch@3.0.4
| `-- typescript@1.6.2
`-- UNMET PEER DEPENDENCY tslint@>=2.5.0-beta

npm ERR! peer dep missing: tslint@>=2.5.0-beta, required by grunt-tslint@2.5.0
PS C:\full-path> $pwd

Path
----
C:\full-path

PS C:\full-path> Get-Content gruntfile.js | Where { $_.Contains('command: ')
} | Out-String
                    //command: '"' + sourceDirectory + '\\packages\\tool\\tools\\chutzpah.console.exe" /path ":C\\full-path\\Tests\\chutzpah.json"'
                    command: '"C:\\windows\\notepad.exe" "C:\\test.json"'
warappa commented 7 years ago

BTW: I'm running the grunt-file with Task Runner Explorer in Visual Studio 2015 Update 3 (14.0.25431.01)

gwicksted commented 7 years ago

Does the notepad example work for you?

I see a potential typo in the commented out command here (colon before C): ":C\\full-path\\Tests\\chutzpah.json"

Other than that, I'm running PS 64 bit (vs 32) with npm 4.5.0, node 7.3.0, grunt-cli 1.2.0 and grunt 1.0.1

The biggest difference is probably that older grunt version. I don't think anything changed in node 6 vs 7 related to spawn. I'll have to do some testing with different versions.

P.S. You may want to update grunt beyond 1.0.0 (if possible). I know it can be a big hassle upgrading packages with npm -- lately I've been using yarn which has been great (on par or better than npm-check-updates for upgrading and way better for build vs dev server consistency). Just run:

npm install yarn -g
yarn
yarn clean
yarn upgrade

The yarn clean step is optional but it should save space/time and yarn upgrade will bump versions of your packages where possible.

From then on instead of npm install (which will still work) on your build server, just run yarn. Unlike npm, yarn is deterministic and always deploys the same node_modules structure/version where npm deploys different structure/versions depending on the order packages were installed.

gwicksted commented 7 years ago

Confirmed notepad test works with grunt@0.4.5 and grunt-exec@2.0.0 (still using node 7)

warappa commented 7 years ago

The typo was only introduced while blacking the data ;)

No spaces in the path.


I just found the difference: Task Runner Explorer uses node in $(VSINSTALLDIR)\Web\External which is v5.4.1. With node v6.3.0, which is on my PATH, it works.

@gwicksted, thank you for your help!