From fec28db2e470005aeffe7989973c8ba42d44c5e7 Mon Sep 17 00:00:00 2001 From: Muffin Date: Wed, 3 Jan 2024 21:53:55 -0600 Subject: [PATCH 1/4] Attempt to autodetect what "python" is called on this system --- package-lock.json | 99 ++++++++++++++++++++++++++++++++++++++++----- package.json | 5 ++- universal-python.js | 61 ++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 12 deletions(-) create mode 100644 universal-python.js diff --git a/package-lock.json b/package-lock.json index f845aeeb6b..5fe1dc6333 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,8 @@ "transifex": "1.6.6", "uglifyjs-webpack-plugin": "1.3.0", "webpack": "4.47.0", - "webpack-cli": "3.3.12" + "webpack-cli": "3.3.12", + "which": "^4.0.0" } }, "node_modules/@ampproject/remapping": { @@ -2325,6 +2326,24 @@ "which": "^1.2.9" } }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -3871,6 +3890,24 @@ "node": ">=6" } }, + "node_modules/global-prefix/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -4886,10 +4923,13 @@ "dev": true }, "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } }, "node_modules/isobject": { "version": "3.0.1", @@ -6693,6 +6733,24 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-dir/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/resolve-dir/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/resolve-from": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", @@ -8954,6 +9012,12 @@ "node": ">=4.8" } }, + "node_modules/webpack-cli/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, "node_modules/webpack-cli/node_modules/supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -8966,6 +9030,18 @@ "node": ">=6" } }, + "node_modules/webpack-cli/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/webpack-sources": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", @@ -9062,15 +9138,18 @@ } }, "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, "dependencies": { - "isexe": "^2.0.0" + "isexe": "^3.1.1" }, "bin": { - "which": "bin/which" + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" } }, "node_modules/which-module": { diff --git a/package.json b/package.json index 102165132e..f5d5e5e1f7 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "browser": "./shim/vertical.js", "scripts": { "deploy": "rimraf gh-pages/closure-library/scripts/ci/CloseAdobeDialog.exe && gh-pages -t -d gh-pages -m \"Build for $(git log --pretty=format:%H -n1) [skip ci]\"", - "prepublish": "python3 build.py && webpack", + "prepublish": "node universal-python.js build.py && webpack", "test:unit": "node tests/jsunit/test_runner.js", "test:lint": "eslint .", "test:messages": "npm run translate && node i18n/test_scratch_msgs.js", @@ -46,6 +46,7 @@ "transifex": "1.6.6", "uglifyjs-webpack-plugin": "1.3.0", "webpack": "4.47.0", - "webpack-cli": "3.3.12" + "webpack-cli": "3.3.12", + "which": "^4.0.0" } } diff --git a/universal-python.js b/universal-python.js new file mode 100644 index 0000000000..fe66c18560 --- /dev/null +++ b/universal-python.js @@ -0,0 +1,61 @@ +/* eslint-env node */ + +// There are a lot of different ways that people can install python, and there is no +// universal name that they use for the actual executable. We can already assume +// that there is a working Node.js environment, so this script can figure it out. + +var child_process = require('child_process'); +var _which = require('which'); + +function which(command) { + return _which.sync(command, { + nothrow: true + }); +} + +function run(command, args) { + console.log('universal-python: running ' + command + ' with arguments ' + args.join(', ')); + var subprocess = child_process.spawn(command, args, { + windowsHide: true, + shell: false, + stdio: 'inherit' + }); + subprocess.on('exit', function(code) { + console.log('universal-python: exited with code ' + code); + process.exit(code); + }); + process.on('SIGINT', function() { + subprocess.kill('SIGINT'); + }); +} + +var argv = process.argv.slice(2); + +// Linux distributions, macOS, and Microsoft Store install python 3 as python3 +// This is the happy path +var python3 = which('python3'); +if (python3) { + run(python3, argv); +} else { + // Windows installers from python.org install the py launcher + var py = which('py'); + if (py) { + run(py, ['-3'].concat(argv)); + } else { + // Sometimes it only gets installed as "python" + // Don't know what version it will be, but 2 and 3 both work so it doesn't matter + var python = which('python'); + if (python) { + run(python, argv); + } else { + // Some weird systems might only have python 2 installed as python2 + var python2 = which('python2'); + if (python2) { + run(python2, argv); + } else { + console.log("Could not find any python executables on your PATH environment variable"); + process.exit(1); + } + } + } +} From fc6bb84510d8bba693c1fcf8c0c8bcdd8a0bdc0d Mon Sep 17 00:00:00 2001 From: Muffin Date: Wed, 3 Jan 2024 22:54:38 -0600 Subject: [PATCH 2/4] Make it work on windows --- universal-python.js | 48 ++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/universal-python.js b/universal-python.js index fe66c18560..899cc2ddb7 100644 --- a/universal-python.js +++ b/universal-python.js @@ -14,16 +14,27 @@ function which(command) { } function run(command, args) { - console.log('universal-python: running ' + command + ' with arguments ' + args.join(', ')); + console.log('universal-python: Running ' + command + ' with arguments ' + args.join(', ')); var subprocess = child_process.spawn(command, args, { windowsHide: true, shell: false, stdio: 'inherit' }); subprocess.on('exit', function(code) { - console.log('universal-python: exited with code ' + code); + // Microsoft Store install shim exits with code 9009 + if (process.platform === 'win32' && code === 9009) { + console.log('universal-python: Attempted to start python, but got the Microsoft Store installation shim. Install python from the Microsoft Store or python.org. (code 9009)') + } else if (code === 0) { + console.log('universal-python: Success'); + } else { + console.log('universal-python: Failed with code ' + code); + } process.exit(code); }); + subprocess.on('error', function(error) { + console.log('universal-python: Error starting python; please ensure you have python installed: ' + error); + process.exit(1); + }); process.on('SIGINT', function() { subprocess.kill('SIGINT'); }); @@ -31,29 +42,38 @@ function run(command, args) { var argv = process.argv.slice(2); -// Linux distributions, macOS, and Microsoft Store install python 3 as python3 -// This is the happy path -var python3 = which('python3'); -if (python3) { - run(python3, argv); -} else { - // Windows installers from python.org install the py launcher - var py = which('py'); +if (process.platform === 'win32') { + // Python in Windows is weird. Most commonly it will be installed using the python.org installers or + // from the Microsoft Store. Interestingly the Microsoft Store shims always exist on PATH and are + // also weird fake files so Node.js' fs does not work very well with them. + // Python.org installers will usually install the py launcher, so we'll try that first so that we + // don't open up the Microsoft Store for people who installed Python from there. + var py = which('py.exe'); if (py) { run(py, ['-3'].concat(argv)); } else { - // Sometimes it only gets installed as "python" - // Don't know what version it will be, but 2 and 3 both work so it doesn't matter + // This will either run the python installation from PATH or the Microsoft Store install shim. + // Don't know what version we'll get, but 2 and 3 both work so it doesn't matter. + run('python.exe', argv); + } +} else { + // Python 3 is usually installed as python3 + var python3 = which('python3'); + if (python3) { + run(python3, argv); + } else { + // Sometimes it might only be installed as python + // Don't know what version we'll get, but 2 and 3 both work so it doesn't matter var python = which('python'); if (python) { run(python, argv); } else { - // Some weird systems might only have python 2 installed as python2 + // Some old systems might only have python 2 var python2 = which('python2'); if (python2) { run(python2, argv); } else { - console.log("Could not find any python executables on your PATH environment variable"); + console.log("universal-python: Could not find python on your PATH; please ensure you have python installed."); process.exit(1); } } From 1a6d7bbe39bf925f752385ec87993eb3585bb72d Mon Sep 17 00:00:00 2001 From: Muffin Date: Wed, 3 Jan 2024 22:55:31 -0600 Subject: [PATCH 3/4] Fix eslint warning --- universal-python.js | 1 + 1 file changed, 1 insertion(+) diff --git a/universal-python.js b/universal-python.js index 899cc2ddb7..00cd7ad52f 100644 --- a/universal-python.js +++ b/universal-python.js @@ -23,6 +23,7 @@ function run(command, args) { subprocess.on('exit', function(code) { // Microsoft Store install shim exits with code 9009 if (process.platform === 'win32' && code === 9009) { + // eslint-disable-next-line max-len console.log('universal-python: Attempted to start python, but got the Microsoft Store installation shim. Install python from the Microsoft Store or python.org. (code 9009)') } else if (code === 0) { console.log('universal-python: Success'); From a57c4da1aee365b4cae2f7b0de1477cd4aebc5c2 Mon Sep 17 00:00:00 2001 From: Muffin Date: Wed, 3 Jan 2024 22:58:34 -0600 Subject: [PATCH 4/4] Fix another eslint error --- universal-python.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/universal-python.js b/universal-python.js index 00cd7ad52f..6ea5cd99e8 100644 --- a/universal-python.js +++ b/universal-python.js @@ -24,7 +24,7 @@ function run(command, args) { // Microsoft Store install shim exits with code 9009 if (process.platform === 'win32' && code === 9009) { // eslint-disable-next-line max-len - console.log('universal-python: Attempted to start python, but got the Microsoft Store installation shim. Install python from the Microsoft Store or python.org. (code 9009)') + console.log('universal-python: Attempted to start python, but got the Microsoft Store installation shim. Install python from the Microsoft Store or python.org. (code 9009)'); } else if (code === 0) { console.log('universal-python: Success'); } else {