From 202a2dc2808c22a779dc50aecfbde61275c09710 Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Tue, 10 May 2022 18:18:06 +0200 Subject: [PATCH 01/19] Add a flag to use master version of elm-explorations/test --- lib/Install.js | 39 +++++++++++++++++++++++++++++++++++++++ lib/RunTests.js | 11 ++++++++++- lib/elm-test.js | 12 ++++++++---- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/lib/Install.js b/lib/Install.js index 99c753da..aec26310 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -1,5 +1,6 @@ // @flow +const {exec} = require('child_process'); const spawn = require('cross-spawn'); const fs = require('fs'); const path = require('path'); @@ -117,6 +118,44 @@ function install( return 'SuccessfullyInstalled'; } +async function installUnstableTestMaster() { + const tempDir = 'elm-stuff/elm-build-cache'; + const pkg = 'elm-explorations/test'; + const version = '1.2.2'; + const pkgWithDash = pkg.replace('/','-'); + + const zipballUrl = `https://github.com/${pkg}/archive/refs/heads/master.zip`; + const zipballPath = `${tempDir}/${pkgWithDash}.zip`; + + // based on info in https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/ + const elmHome = process.env.ELM_HOME ?? process.platform === 'win32' ? `${process.env.APPDATA}/elm` : `~/.elm`; + const packagePath = `${elmHome}/0.19.1/packages/${pkg}/${version}`; + + const ourExec = async (cmd) => + new Promise((resolve, reject) => { + exec(cmd, (error,stdout,stderr) => { + if (error) { + reject(error); + } + resolve([stdout,stderr]); + }); + }); + + await ourExec(`rm -rf ${tempDir}`); + await ourExec(`mkdir -p ${tempDir}`); + await ourExec(`rm -rf ${packagePath}`); + await ourExec(`rm -rf elm-stuff/generated-code`); + await ourExec(`mkdir -p ${packagePath}`); + await ourExec(`curl -L ${zipballUrl} -o ${zipballPath}`); + await ourExec(`unzip -o ${zipballPath} -d ${tempDir}`); + await ourExec(`mv ${tempDir}/test-master/src ${packagePath}`); + await ourExec(`mv ${tempDir}/test-master/elm.json ${packagePath}`); + await ourExec(`mv ${tempDir}/test-master/LICENSE ${packagePath}`); + await ourExec(`mv ${tempDir}/test-master/README.md ${packagePath}`); + await ourExec(`rm -rf '${zipballPath}'`); +} + module.exports = { install, + installUnstableTestMaster, }; diff --git a/lib/RunTests.js b/lib/RunTests.js index 066f4bc9..d44b09e1 100644 --- a/lib/RunTests.js +++ b/lib/RunTests.js @@ -10,6 +10,7 @@ const DependencyProvider = require('./DependencyProvider.js'); const ElmJson = require('./ElmJson'); const FindTests = require('./FindTests'); const Generate = require('./Generate'); +const Install = require('./Install'); const Project = require('./Project'); const Report = require('./Report'); const Supervisor = require('./Supervisor'); @@ -117,7 +118,7 @@ function watcherEventMessage(queue /*: typeof Queue */) /*: string */ { return `${filePaths.length} files ${events.join('/')}`; } -function runTests( +async function runTests( dependencyProvider /*: DependencyProvider */, projectRootDir /*: string */, pathToElmBinary /*: string */, @@ -128,11 +129,13 @@ function runTests( report, seed, fuzz, + unstableUseTestMaster, } /*: { watch: boolean, report: typeof Report.Report, seed: number, fuzz: number, + unstableUseTestMaster: boolean, } */ ) /*: Promise */ { let watcher = undefined; @@ -249,6 +252,12 @@ function runTests( } } + if (unstableUseTestMaster) { + console.log('Using the master version of elm-explorations/test'); + console.log('Note you might need to rm -rf ~/.elm and/or ./elm-stuff afterwards.'); + await Install.installUnstableTestMaster(); + } + if (watch) { progressLogger.clearConsole(); diff --git a/lib/elm-test.js b/lib/elm-test.js index 3ff462c9..c3a337d3 100644 --- a/lib/elm-test.js +++ b/lib/elm-test.js @@ -142,6 +142,10 @@ function main() { '--color', 'Force colored console output (setting FORCE_COLOR to anything but 0 also works)' ) + .option( + '--unstable-use-test-master', + 'Use the bleeding-edge version of the elm-explorations/test library' + ) .option( '--compiler ', 'Use a custom path to an Elm executable (default: elm)', @@ -165,12 +169,12 @@ function main() { program .command('init') .description('Install elm-explorations/test and create tests/Example.elm') - .action(() => { + .action(async () => { const options = program.opts(); const pathToElmBinary = getPathToElmBinary(options.compiler); const project = getProject('init'); try { - Install.install(project, pathToElmBinary, 'elm-explorations/test'); + await Install.install(project, pathToElmBinary, 'elm-explorations/test'); fs.mkdirSync(project.testsDir, { recursive: true }); fs.copyFileSync( path.join(__dirname, '..', 'templates', 'tests', 'Example.elm'), @@ -241,12 +245,12 @@ function main() { // commander would interpret the `tests` in `elm-test tests src` as a // command and only run tests in `src/`, ignoring all files in `tests/`. .command('__elmTestCommand__ [globs...]', { hidden: true, isDefault: true }) - .action((testFileGlobs) => { + .action(async (testFileGlobs) => { const options = program.opts(); const pathToElmBinary = getPathToElmBinary(options.compiler); const projectRootDir = getProjectRootDir('tests'); const processes = Math.max(1, os.cpus().length); - RunTests.runTests( + await RunTests.runTests( dependencyProvider, projectRootDir, pathToElmBinary, From f8429a308985fab5c542dc720fd2ac432aad5437 Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Wed, 11 May 2022 17:50:51 +0200 Subject: [PATCH 02/19] Small fixes (we'll rip these out anyways) --- lib/Install.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Install.js b/lib/Install.js index aec26310..3b0023ea 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -128,7 +128,7 @@ async function installUnstableTestMaster() { const zipballPath = `${tempDir}/${pkgWithDash}.zip`; // based on info in https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/ - const elmHome = process.env.ELM_HOME ?? process.platform === 'win32' ? `${process.env.APPDATA}/elm` : `~/.elm`; + const elmHome = process.env.ELM_HOME ?? (process.platform === 'win32' ? `${process.env.APPDATA}/elm` : `~/.elm`); const packagePath = `${elmHome}/0.19.1/packages/${pkg}/${version}`; const ourExec = async (cmd) => @@ -144,7 +144,7 @@ async function installUnstableTestMaster() { await ourExec(`rm -rf ${tempDir}`); await ourExec(`mkdir -p ${tempDir}`); await ourExec(`rm -rf ${packagePath}`); - await ourExec(`rm -rf elm-stuff/generated-code`); + await ourExec(`rm -rf elm-stuff/generated-code/elm-community/elm-test`); await ourExec(`mkdir -p ${packagePath}`); await ourExec(`curl -L ${zipballUrl} -o ${zipballPath}`); await ourExec(`unzip -o ${zipballPath} -d ${tempDir}`); From 14dd7fa1e74afbf3906122fae81eb26f7f497e75 Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Wed, 11 May 2022 18:54:22 +0200 Subject: [PATCH 03/19] Use Node versions of commands --- lib/Install.js | 152 +++++++++++++++++++++++++++++++++++------------- lib/RunTests.js | 4 +- 2 files changed, 113 insertions(+), 43 deletions(-) diff --git a/lib/Install.js b/lib/Install.js index 3b0023ea..46b48046 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -2,8 +2,12 @@ const {exec} = require('child_process'); const spawn = require('cross-spawn'); +const {unzip} = require('zlib'); const fs = require('fs'); +const os = require('os'); +const https = require('https'); const path = require('path'); +const chalk = require('chalk'); const ElmJson = require('./ElmJson'); const Project = require('./Project'); @@ -20,18 +24,8 @@ function install( // Recreate the directory to remove any artifacts from the last time // someone ran `elm-test install`. We do not delete this directory after // the installation finishes in case the user needs to debug the test run. - // We can replace this with just `fs.rmSync(installationScratchDir, { recursive: true, force: true })` - // when Node.js 12 is EOL 2022-04-30 and support for Node.js 12 is dropped. - // `fs.rmSync` was added in Node.js 14.14.0, which is also when the - // `recursive` option of `fs.rmdirSync` was deprecated. The `if` avoids - // printing a deprecation message. // $FlowFixMe[prop-missing]: Flow does not know of `fs.rmSync` yet. - if (fs.rmSync !== undefined) { - fs.rmSync(installationScratchDir, { recursive: true, force: true }); - } else if (fs.existsSync(installationScratchDir)) { - // $FlowFixMe[extra-arg]: Flow does not know of the options argument yet. - fs.rmdirSync(installationScratchDir, { recursive: true }); - } + fs.rmSync(installationScratchDir, { recursive: true, force: true }); fs.mkdirSync(installationScratchDir, { recursive: true }); } catch (error) { throw new Error( @@ -118,41 +112,119 @@ function install( return 'SuccessfullyInstalled'; } -async function installUnstableTestMaster() { - const tempDir = 'elm-stuff/elm-build-cache'; +async function downloadFileNative(url, filePath) { + const usedCommand = `require("https").get(${JSON.stringify(url)})`; + const errorPrefix = `${usedCommand}\nThe above call errored: `; + + return new Promise((resolve, reject) => { + const file = fs.createWriteStream(filePath); + let fileInfo = null; + + const request = https.get(url, response => { + if (response.statusCode !== 200) { + fs.unlink(filePath, () => { + reject(new Error(`Failed to get '${url}' (${response.statusCode})`)); + }); + return; + } + + fileInfo = { + mime: response.headers['content-type'], + size: parseInt(response.headers['content-length'], 10), + }; + + response.pipe(file); + }); + + // The destination stream is ended by the time it's called + file.on('finish', () => resolve(fileInfo)); + + request.on('error', err => { + fs.unlink(filePath, () => reject(err)); + }); + + file.on('error', err => { + fs.unlink(filePath, () => reject(err)); + }); + + request.end(); + }); +} + +async function installUnstableTestMaster(projectRootDir) { + console.log(chalk.yellow('Using the master version of elm-explorations/test')); + console.log(chalk.yellow('Note you might need to rm -rf ~/.elm and/or ./elm-stuff afterwards.')); + const pkg = 'elm-explorations/test'; const version = '1.2.2'; const pkgWithDash = pkg.replace('/','-'); - const zipballUrl = `https://github.com/${pkg}/archive/refs/heads/master.zip`; - const zipballPath = `${tempDir}/${pkgWithDash}.zip`; + const tempPath = path.join( + projectRootDir, + 'elm-stuff', + 'generated-code', + 'elm-community', + 'elm-test' + ); + const zipballUrl = `https://codeload.github.com/${pkg}/zip/refs/heads/master`; + const zipballFilename = `${pkgWithDash}.zip`; + const zipballPath = path.join(tempPath, zipballFilename); + const homeDir = os.homedir(); // based on info in https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/ - const elmHome = process.env.ELM_HOME ?? (process.platform === 'win32' ? `${process.env.APPDATA}/elm` : `~/.elm`); - const packagePath = `${elmHome}/0.19.1/packages/${pkg}/${version}`; - - const ourExec = async (cmd) => - new Promise((resolve, reject) => { - exec(cmd, (error,stdout,stderr) => { - if (error) { - reject(error); - } - resolve([stdout,stderr]); - }); - }); - - await ourExec(`rm -rf ${tempDir}`); - await ourExec(`mkdir -p ${tempDir}`); - await ourExec(`rm -rf ${packagePath}`); - await ourExec(`rm -rf elm-stuff/generated-code/elm-community/elm-test`); - await ourExec(`mkdir -p ${packagePath}`); - await ourExec(`curl -L ${zipballUrl} -o ${zipballPath}`); - await ourExec(`unzip -o ${zipballPath} -d ${tempDir}`); - await ourExec(`mv ${tempDir}/test-master/src ${packagePath}`); - await ourExec(`mv ${tempDir}/test-master/elm.json ${packagePath}`); - await ourExec(`mv ${tempDir}/test-master/LICENSE ${packagePath}`); - await ourExec(`mv ${tempDir}/test-master/README.md ${packagePath}`); - await ourExec(`rm -rf '${zipballPath}'`); + const elmHome = process.env.ELM_HOME ?? ( + process.platform === 'win32' + ? path.join(process.env.APPDATA, 'elm') + : path.join(homeDir, '.elm') + ); + const packagePath = path.join( + elmHome, + '0.19.1', + 'packages', + pkg, + version + ); + + fs.rmSync(tempPath, { recursive: true, force: true }); + fs.rmSync(packagePath, { recursive: true, force: true }); + fs.mkdirSync(tempPath, { recursive: true }); + fs.mkdirSync(packagePath, { recursive: true }); + await downloadFileNative(zipballUrl, zipballPath); + const unzipResult = spawn.sync( + 'unzip', + [ + '-o', // overwrite + zipballFilename, // file to unzip + '-d', tempPath // directory where to extract files + ], + { + cwd: tempPath, + } + ); + if (unzipResult.status !== 0) { + const tarResult = spawn.sync( + 'tar', + [ + 'zxf', // eXtract Zipped File + zipballFilename, // file to unzip + '-C', tempPath // directory where to extract files + ], + { + cwd: tempPath, + } + ); + if (tarResult.status !== 0) { + throw new Error("Failed to unzip the elm-explorations/test repo zipfile"); + } + } + fs.renameSync( + path.join( + tempPath, + 'test-master' + ), + packagePath + ); + fs.rmSync(zipballPath, { recursive: true, force: true }); } module.exports = { diff --git a/lib/RunTests.js b/lib/RunTests.js index d44b09e1..fb1c0933 100644 --- a/lib/RunTests.js +++ b/lib/RunTests.js @@ -253,9 +253,7 @@ async function runTests( } if (unstableUseTestMaster) { - console.log('Using the master version of elm-explorations/test'); - console.log('Note you might need to rm -rf ~/.elm and/or ./elm-stuff afterwards.'); - await Install.installUnstableTestMaster(); + await Install.installUnstableTestMaster(projectRootDir); } if (watch) { From ae25add1fa8fa59a3775e025661ad4cb91efe7fb Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Mon, 16 May 2022 08:29:13 +0200 Subject: [PATCH 04/19] Revert await for Install.install --- lib/elm-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/elm-test.js b/lib/elm-test.js index c3a337d3..4c57f81f 100644 --- a/lib/elm-test.js +++ b/lib/elm-test.js @@ -169,12 +169,12 @@ function main() { program .command('init') .description('Install elm-explorations/test and create tests/Example.elm') - .action(async () => { + .action(() => { const options = program.opts(); const pathToElmBinary = getPathToElmBinary(options.compiler); const project = getProject('init'); try { - await Install.install(project, pathToElmBinary, 'elm-explorations/test'); + Install.install(project, pathToElmBinary, 'elm-explorations/test'); fs.mkdirSync(project.testsDir, { recursive: true }); fs.copyFileSync( path.join(__dirname, '..', 'templates', 'tests', 'Example.elm'), From 0d5d3c23d8c535c5113d0efe4fe5c9bd42f8da0a Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Mon, 16 May 2022 08:32:06 +0200 Subject: [PATCH 05/19] Revert Node 12->14 changes --- lib/Install.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/Install.js b/lib/Install.js index 46b48046..b644f73a 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -24,8 +24,18 @@ function install( // Recreate the directory to remove any artifacts from the last time // someone ran `elm-test install`. We do not delete this directory after // the installation finishes in case the user needs to debug the test run. + // We can replace this with just `fs.rmSync(installationScratchDir, { recursive: true, force: true })` + // when Node.js 12 is EOL 2022-04-30 and support for Node.js 12 is dropped. + // `fs.rmSync` was added in Node.js 14.14.0, which is also when the + // `recursive` option of `fs.rmdirSync` was deprecated. The `if` avoids + // printing a deprecation message. // $FlowFixMe[prop-missing]: Flow does not know of `fs.rmSync` yet. - fs.rmSync(installationScratchDir, { recursive: true, force: true }); + if (fs.rmSync !== undefined) { + fs.rmSync(installationScratchDir, { recursive: true, force: true }); + } else if (fs.existsSync(installationScratchDir)) { + // $FlowFixMe[extra-arg]: Flow does not know of the options argument yet. + fs.rmdirSync(installationScratchDir, { recursive: true }); + } fs.mkdirSync(installationScratchDir, { recursive: true }); } catch (error) { throw new Error( From f8e8670beda38e78525e3163c6ca0dde0d5fc538 Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Thu, 26 May 2022 21:54:19 +0200 Subject: [PATCH 06/19] Apply CR suggestions --- lib/Install.js | 69 +++++++++++++++++++++++++++++++++++-------------- lib/RunTests.js | 9 +------ lib/elm-test.js | 27 +++++++++++++++---- 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/lib/Install.js b/lib/Install.js index b644f73a..d1aeef7a 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -161,32 +161,20 @@ async function downloadFileNative(url, filePath) { }); } -async function installUnstableTestMaster(projectRootDir) { - console.log(chalk.yellow('Using the master version of elm-explorations/test')); - console.log(chalk.yellow('Note you might need to rm -rf ~/.elm and/or ./elm-stuff afterwards.')); - +async function installUnstableTestMaster(project) { const pkg = 'elm-explorations/test'; const version = '1.2.2'; + + console.log(chalk.yellow(`Using the master version of ${pkg} in place of ${version}.`)); + console.log(chalk.yellow(`Note you will need to rm -rf ~/.elm and ./elm-stuff (or use the \`elm-test uninstall-unstable-test-master\` command) afterwards to get back to the ${version} version.`)); + const pkgWithDash = pkg.replace('/','-'); - const tempPath = path.join( - projectRootDir, - 'elm-stuff', - 'generated-code', - 'elm-community', - 'elm-test' - ); + const tempPath = project.generatedCodeDir; const zipballUrl = `https://codeload.github.com/${pkg}/zip/refs/heads/master`; const zipballFilename = `${pkgWithDash}.zip`; const zipballPath = path.join(tempPath, zipballFilename); - const homeDir = os.homedir(); - // based on info in https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/ - const elmHome = process.env.ELM_HOME ?? ( - process.platform === 'win32' - ? path.join(process.env.APPDATA, 'elm') - : path.join(homeDir, '.elm') - ); const packagePath = path.join( elmHome, '0.19.1', @@ -195,11 +183,19 @@ async function installUnstableTestMaster(projectRootDir) { version ); - fs.rmSync(tempPath, { recursive: true, force: true }); + console.log(chalk.dim.yellow(`Removing ${tempPath}`)); + fs.rmSync(tempPath, { recursive: true, force: true }); + + console.log(chalk.dim.yellow(`Removing ${packagePath}`)); fs.rmSync(packagePath, { recursive: true, force: true }); + fs.mkdirSync(tempPath, { recursive: true }); fs.mkdirSync(packagePath, { recursive: true }); + + console.log(chalk.dim.yellow(`Downloading ${zipballUrl}`)); await downloadFileNative(zipballUrl, zipballPath); + + console.log(chalk.dim.yellow(`Unzipping ${zipballPath}`)); const unzipResult = spawn.sync( 'unzip', [ @@ -227,6 +223,8 @@ async function installUnstableTestMaster(projectRootDir) { throw new Error("Failed to unzip the elm-explorations/test repo zipfile"); } } + + console.log(chalk.dim.yellow(`Moving to ELM_HOME: ${packagePath}`)); fs.renameSync( path.join( tempPath, @@ -234,10 +232,41 @@ async function installUnstableTestMaster(projectRootDir) { ), packagePath ); - fs.rmSync(zipballPath, { recursive: true, force: true }); + + console.log(chalk.dim.yellow(`Removing ${zipballPath}`)); + fs.rmSync(zipballPath, { recursive: false, force: true }); +} + +function uninstallUnstableTestMaster(project) { + const pkg = 'elm-explorations/test'; + const version = '1.2.2'; + + const tempPath = project.generatedCodeDir; + const packagePath = path.join( + elmHome, + '0.19.1', + 'packages', + pkg, + version + ); + + console.log(chalk.dim.yellow(`Removing ${tempPath}`)); + fs.rmSync(tempPath, { recursive: true, force: true }); + + console.log(chalk.dim.yellow(`Removing ${packagePath}`)); + fs.rmSync(packagePath, { recursive: true, force: true }); } +// ELM_HOME: based on info in https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/ +const elmHome = + process.env.ELM_HOME ?? ( + process.platform === 'win32' + ? path.join(process.env.APPDATA, 'elm') + : path.join(os.homedir(), '.elm') + ); + module.exports = { install, installUnstableTestMaster, + uninstallUnstableTestMaster, }; diff --git a/lib/RunTests.js b/lib/RunTests.js index fb1c0933..066f4bc9 100644 --- a/lib/RunTests.js +++ b/lib/RunTests.js @@ -10,7 +10,6 @@ const DependencyProvider = require('./DependencyProvider.js'); const ElmJson = require('./ElmJson'); const FindTests = require('./FindTests'); const Generate = require('./Generate'); -const Install = require('./Install'); const Project = require('./Project'); const Report = require('./Report'); const Supervisor = require('./Supervisor'); @@ -118,7 +117,7 @@ function watcherEventMessage(queue /*: typeof Queue */) /*: string */ { return `${filePaths.length} files ${events.join('/')}`; } -async function runTests( +function runTests( dependencyProvider /*: DependencyProvider */, projectRootDir /*: string */, pathToElmBinary /*: string */, @@ -129,13 +128,11 @@ async function runTests( report, seed, fuzz, - unstableUseTestMaster, } /*: { watch: boolean, report: typeof Report.Report, seed: number, fuzz: number, - unstableUseTestMaster: boolean, } */ ) /*: Promise */ { let watcher = undefined; @@ -252,10 +249,6 @@ async function runTests( } } - if (unstableUseTestMaster) { - await Install.installUnstableTestMaster(projectRootDir); - } - if (watch) { progressLogger.clearConsole(); diff --git a/lib/elm-test.js b/lib/elm-test.js index 4c57f81f..0d7946e0 100644 --- a/lib/elm-test.js +++ b/lib/elm-test.js @@ -142,10 +142,6 @@ function main() { '--color', 'Force colored console output (setting FORCE_COLOR to anything but 0 also works)' ) - .option( - '--unstable-use-test-master', - 'Use the bleeding-edge version of the elm-explorations/test library' - ) .option( '--compiler ', 'Use a custom path to an Elm executable (default: elm)', @@ -250,7 +246,7 @@ function main() { const pathToElmBinary = getPathToElmBinary(options.compiler); const projectRootDir = getProjectRootDir('tests'); const processes = Math.max(1, os.cpus().length); - await RunTests.runTests( + RunTests.runTests( dependencyProvider, projectRootDir, pathToElmBinary, @@ -266,6 +262,27 @@ function main() { ); }); + program + .command('install-unstable-test-master') + .description('Use the `master` version of the elm-explorations/test library') + .action(() => { + const project = getProject('install-unstable-test-master'); + Install.installUnstableTestMaster(project) + .then( + () => process.exit(0), + () => process.exit(1) + ) + }); + + program + .command('uninstall-unstable-test-master') + .description('Stop using the `master` version of the elm-explorations/test library') + .action(() => { + const project = getProject('uninstall-unstable-test-master'); + Install.uninstallUnstableTestMaster(project); + process.exit(0); + }); + program.parse(process.argv); } From b9bc09a10ea221c1a9ceb6c1280448bdc5823904 Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Thu, 26 May 2022 21:55:18 +0200 Subject: [PATCH 07/19] Minimize diff --- lib/elm-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/elm-test.js b/lib/elm-test.js index 0d7946e0..daa8dce7 100644 --- a/lib/elm-test.js +++ b/lib/elm-test.js @@ -241,7 +241,7 @@ function main() { // commander would interpret the `tests` in `elm-test tests src` as a // command and only run tests in `src/`, ignoring all files in `tests/`. .command('__elmTestCommand__ [globs...]', { hidden: true, isDefault: true }) - .action(async (testFileGlobs) => { + .action((testFileGlobs) => { const options = program.opts(); const pathToElmBinary = getPathToElmBinary(options.compiler); const projectRootDir = getProjectRootDir('tests'); From 6a2c471e647b34475a445532a3d0ccc1d1193820 Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Thu, 26 May 2022 21:56:18 +0200 Subject: [PATCH 08/19] lint --- lib/Install.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/Install.js b/lib/Install.js index d1aeef7a..54aa467a 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -1,8 +1,6 @@ // @flow -const {exec} = require('child_process'); const spawn = require('cross-spawn'); -const {unzip} = require('zlib'); const fs = require('fs'); const os = require('os'); const https = require('https'); @@ -123,9 +121,6 @@ function install( } async function downloadFileNative(url, filePath) { - const usedCommand = `require("https").get(${JSON.stringify(url)})`; - const errorPrefix = `${usedCommand}\nThe above call errored: `; - return new Promise((resolve, reject) => { const file = fs.createWriteStream(filePath); let fileInfo = null; From 250a6b59833baa0baea61383f5f21c6ed68528de Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Thu, 26 May 2022 22:09:18 +0200 Subject: [PATCH 09/19] prettier + bugfix --- lib/Install.js | 122 ++++++++++++++++++++++++++---------------------- lib/elm-test.js | 23 +++++---- 2 files changed, 79 insertions(+), 66 deletions(-) diff --git a/lib/Install.js b/lib/Install.js index 54aa467a..52969008 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -11,6 +11,36 @@ const Project = require('./Project'); void Project; +function rmDirSync(dir) { + // We can replace this with just `fs.rmSync(installationScratchDir, { recursive: true, force: true })` + // when Node.js 12 is EOL 2022-04-30 and support for Node.js 12 is dropped. + // `fs.rmSync` was added in Node.js 14.14.0, which is also when the + // `recursive` option of `fs.rmdirSync` was deprecated. The `if` avoids + // printing a deprecation message. + // $FlowFixMe[prop-missing]: Flow does not know of `fs.rmSync` yet. + if (fs.rmSync !== undefined) { + fs.rmSync(dir, { recursive: true, force: true }); + } else if (fs.existsSync(dir)) { + // $FlowFixMe[extra-arg]: Flow does not know of the options argument yet. + fs.rmdirSync(dir, { recursive: true }); + } +} + +function rmFileSync(file) { + // We can replace this with just `fs.rmSync(installationScratchDir, { recursive: true, force: true })` + // when Node.js 12 is EOL 2022-04-30 and support for Node.js 12 is dropped. + // `fs.rmSync` was added in Node.js 14.14.0, which is also when the + // `recursive` option of `fs.rmdirSync` was deprecated. The `if` avoids + // printing a deprecation message. + // $FlowFixMe[prop-missing]: Flow does not know of `fs.rmSync` yet. + if (fs.rmSync !== undefined) { + fs.rmSync(file, { recursive: false, force: true }); + } else if (fs.existsSync(file)) { + // $FlowFixMe[extra-arg]: Flow does not know of the options argument yet. + fs.rmdirSync(file, { recursive: false }); + } +} + function install( project /*: typeof Project.Project */, pathToElmBinary /*: string */, @@ -22,18 +52,7 @@ function install( // Recreate the directory to remove any artifacts from the last time // someone ran `elm-test install`. We do not delete this directory after // the installation finishes in case the user needs to debug the test run. - // We can replace this with just `fs.rmSync(installationScratchDir, { recursive: true, force: true })` - // when Node.js 12 is EOL 2022-04-30 and support for Node.js 12 is dropped. - // `fs.rmSync` was added in Node.js 14.14.0, which is also when the - // `recursive` option of `fs.rmdirSync` was deprecated. The `if` avoids - // printing a deprecation message. - // $FlowFixMe[prop-missing]: Flow does not know of `fs.rmSync` yet. - if (fs.rmSync !== undefined) { - fs.rmSync(installationScratchDir, { recursive: true, force: true }); - } else if (fs.existsSync(installationScratchDir)) { - // $FlowFixMe[extra-arg]: Flow does not know of the options argument yet. - fs.rmdirSync(installationScratchDir, { recursive: true }); - } + rmDirSync(installationScratchDir); fs.mkdirSync(installationScratchDir, { recursive: true }); } catch (error) { throw new Error( @@ -125,7 +144,7 @@ async function downloadFileNative(url, filePath) { const file = fs.createWriteStream(filePath); let fileInfo = null; - const request = https.get(url, response => { + const request = https.get(url, (response) => { if (response.statusCode !== 200) { fs.unlink(filePath, () => { reject(new Error(`Failed to get '${url}' (${response.statusCode})`)); @@ -144,11 +163,11 @@ async function downloadFileNative(url, filePath) { // The destination stream is ended by the time it's called file.on('finish', () => resolve(fileInfo)); - request.on('error', err => { + request.on('error', (err) => { fs.unlink(filePath, () => reject(err)); }); - file.on('error', err => { + file.on('error', (err) => { fs.unlink(filePath, () => reject(err)); }); @@ -156,35 +175,37 @@ async function downloadFileNative(url, filePath) { }); } -async function installUnstableTestMaster(project) { +async function installUnstableTestMaster( + project /*: typeof Project.Project */ +) { const pkg = 'elm-explorations/test'; const version = '1.2.2'; - console.log(chalk.yellow(`Using the master version of ${pkg} in place of ${version}.`)); - console.log(chalk.yellow(`Note you will need to rm -rf ~/.elm and ./elm-stuff (or use the \`elm-test uninstall-unstable-test-master\` command) afterwards to get back to the ${version} version.`)); + console.log( + chalk.yellow(`Using the master version of ${pkg} in place of ${version}.`) + ); + console.log( + chalk.yellow( + `Note you will need to rm -rf ~/.elm and ./elm-stuff (or use the \`elm-test uninstall-unstable-test-master\` command) afterwards to get back to the ${version} version.` + ) + ); - const pkgWithDash = pkg.replace('/','-'); + const pkgWithDash = pkg.replace('/', '-'); const tempPath = project.generatedCodeDir; const zipballUrl = `https://codeload.github.com/${pkg}/zip/refs/heads/master`; const zipballFilename = `${pkgWithDash}.zip`; const zipballPath = path.join(tempPath, zipballFilename); - const packagePath = path.join( - elmHome, - '0.19.1', - 'packages', - pkg, - version - ); + const packagePath = path.join(elmHome, '0.19.1', 'packages', pkg, version); console.log(chalk.dim.yellow(`Removing ${tempPath}`)); - fs.rmSync(tempPath, { recursive: true, force: true }); + rmDirSync(tempPath); console.log(chalk.dim.yellow(`Removing ${packagePath}`)); - fs.rmSync(packagePath, { recursive: true, force: true }); + rmDirSync(packagePath); - fs.mkdirSync(tempPath, { recursive: true }); + fs.mkdirSync(tempPath, { recursive: true }); fs.mkdirSync(packagePath, { recursive: true }); console.log(chalk.dim.yellow(`Downloading ${zipballUrl}`)); @@ -196,7 +217,8 @@ async function installUnstableTestMaster(project) { [ '-o', // overwrite zipballFilename, // file to unzip - '-d', tempPath // directory where to extract files + '-d', + tempPath, // directory where to extract files ], { cwd: tempPath, @@ -208,57 +230,45 @@ async function installUnstableTestMaster(project) { [ 'zxf', // eXtract Zipped File zipballFilename, // file to unzip - '-C', tempPath // directory where to extract files + '-C', + tempPath, // directory where to extract files ], { cwd: tempPath, } ); if (tarResult.status !== 0) { - throw new Error("Failed to unzip the elm-explorations/test repo zipfile"); + throw new Error('Failed to unzip the elm-explorations/test repo zipfile'); } } console.log(chalk.dim.yellow(`Moving to ELM_HOME: ${packagePath}`)); - fs.renameSync( - path.join( - tempPath, - 'test-master' - ), - packagePath - ); + fs.renameSync(path.join(tempPath, 'test-master'), packagePath); console.log(chalk.dim.yellow(`Removing ${zipballPath}`)); - fs.rmSync(zipballPath, { recursive: false, force: true }); + rmFileSync(zipballPath); } -function uninstallUnstableTestMaster(project) { +function uninstallUnstableTestMaster(project /*: typeof Project.Project */) { const pkg = 'elm-explorations/test'; const version = '1.2.2'; const tempPath = project.generatedCodeDir; - const packagePath = path.join( - elmHome, - '0.19.1', - 'packages', - pkg, - version - ); + const packagePath = path.join(elmHome, '0.19.1', 'packages', pkg, version); console.log(chalk.dim.yellow(`Removing ${tempPath}`)); - fs.rmSync(tempPath, { recursive: true, force: true }); + rmDirSync(tempPath); console.log(chalk.dim.yellow(`Removing ${packagePath}`)); - fs.rmSync(packagePath, { recursive: true, force: true }); + rmDirSync(packagePath); } // ELM_HOME: based on info in https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/ -const elmHome = - process.env.ELM_HOME ?? ( - process.platform === 'win32' - ? path.join(process.env.APPDATA, 'elm') - : path.join(os.homedir(), '.elm') - ); +const elmHome = + process.env.ELM_HOME ?? + (process.platform === 'win32' + ? path.join(process.env.APPDATA ?? '', 'elm') + : path.join(os.homedir(), '.elm')); module.exports = { install, diff --git a/lib/elm-test.js b/lib/elm-test.js index daa8dce7..678426a2 100644 --- a/lib/elm-test.js +++ b/lib/elm-test.js @@ -264,22 +264,25 @@ function main() { program .command('install-unstable-test-master') - .description('Use the `master` version of the elm-explorations/test library') - .action(() => { + .description( + 'Use the `master` version of the elm-explorations/test library' + ) + .action(() => { const project = getProject('install-unstable-test-master'); - Install.installUnstableTestMaster(project) - .then( - () => process.exit(0), - () => process.exit(1) - ) + Install.installUnstableTestMaster(project).then( + () => process.exit(0), + () => process.exit(1) + ); }); program .command('uninstall-unstable-test-master') - .description('Stop using the `master` version of the elm-explorations/test library') - .action(() => { + .description( + 'Stop using the `master` version of the elm-explorations/test library' + ) + .action(() => { const project = getProject('uninstall-unstable-test-master'); - Install.uninstallUnstableTestMaster(project); + Install.uninstallUnstableTestMaster(project); process.exit(0); }); From bec15620ce3dc986c9a65ea373a27de76318831a Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Thu, 26 May 2022 22:10:19 +0200 Subject: [PATCH 10/19] Fix comments --- lib/Install.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Install.js b/lib/Install.js index 52969008..4ab84301 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -12,7 +12,7 @@ const Project = require('./Project'); void Project; function rmDirSync(dir) { - // We can replace this with just `fs.rmSync(installationScratchDir, { recursive: true, force: true })` + // We can replace this with just `fs.rmSync(dir, { recursive: true, force: true })` // when Node.js 12 is EOL 2022-04-30 and support for Node.js 12 is dropped. // `fs.rmSync` was added in Node.js 14.14.0, which is also when the // `recursive` option of `fs.rmdirSync` was deprecated. The `if` avoids @@ -27,7 +27,7 @@ function rmDirSync(dir) { } function rmFileSync(file) { - // We can replace this with just `fs.rmSync(installationScratchDir, { recursive: true, force: true })` + // We can replace this with just `fs.rmSync(dir, { recursive: false, force: true })` // when Node.js 12 is EOL 2022-04-30 and support for Node.js 12 is dropped. // `fs.rmSync` was added in Node.js 14.14.0, which is also when the // `recursive` option of `fs.rmdirSync` was deprecated. The `if` avoids From 59818ea0a855bc463c0252fee708986e60cb03ff Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Thu, 26 May 2022 22:10:48 +0200 Subject: [PATCH 11/19] Fix comment again --- lib/Install.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Install.js b/lib/Install.js index 4ab84301..e815109d 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -27,7 +27,7 @@ function rmDirSync(dir) { } function rmFileSync(file) { - // We can replace this with just `fs.rmSync(dir, { recursive: false, force: true })` + // We can replace this with just `fs.rmSync(file, { recursive: false, force: true })` // when Node.js 12 is EOL 2022-04-30 and support for Node.js 12 is dropped. // `fs.rmSync` was added in Node.js 14.14.0, which is also when the // `recursive` option of `fs.rmdirSync` was deprecated. The `if` avoids From 7247fa597961e322c519be357f058c29a564552b Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Sat, 28 May 2022 10:18:41 +0200 Subject: [PATCH 12/19] Fix `??` not available in Node.js 12, the ambitious way --- lib/DependencyProvider.js | 49 +++++---------------------------------- lib/ElmHome.js | 47 +++++++++++++++++++++++++++++++++++++ lib/Install.js | 30 ++++++++---------------- 3 files changed, 63 insertions(+), 63 deletions(-) create mode 100644 lib/ElmHome.js diff --git a/lib/DependencyProvider.js b/lib/DependencyProvider.js index 4f1ac4df..09f5bd32 100644 --- a/lib/DependencyProvider.js +++ b/lib/DependencyProvider.js @@ -1,9 +1,9 @@ // @flow const fs = require('fs'); -const os = require('os'); const path = require('path'); const wasm = require('elm-solve-deps-wasm'); +const ElmHome = require('./ElmHome.js'); const SyncGet = require('./SyncGet.js'); const collator = new Intl.Collator('en', { numeric: true }); // for sorting SemVer strings @@ -17,7 +17,7 @@ class OnlineVersionsCache { map /*: Map> */ = new Map(); update() { - const pubgrubHome = path.join(elmHome(), 'pubgrub'); + const pubgrubHome = path.join(ElmHome.elmHome(), 'pubgrub'); fs.mkdirSync(pubgrubHome, { recursive: true }); const cachePath = path.join(pubgrubHome, 'versions_cache.json'); const remotePackagesUrl = 'https://package.elm-lang.org/all-packages'; @@ -139,7 +139,7 @@ class OfflineAvailableVersionLister { } function readVersionsInElmHomeAndSort(pkg /*: string */) /*: Array */ { - const pkgPath = homePkgPath(pkg); + const pkgPath = ElmHome.packagePath(pkg); let offlineVersions; try { offlineVersions = fs.readdirSync(pkgPath); @@ -316,9 +316,9 @@ function cacheElmJsonPath( pkg /*: string */, version /*: string */ ) /*: string */ { - const parts = splitAuthorPkg(pkg); + const parts = ElmHome.splitAuthorPkg(pkg); return path.join( - elmHome(), + ElmHome.elmHome(), 'pubgrub', 'elm_json_cache', parts.author, @@ -332,20 +332,7 @@ function homeElmJsonPath( pkg /*: string */, version /*: string */ ) /*: string */ { - return path.join(homePkgPath(pkg), version, 'elm.json'); -} - -function homePkgPath(pkg /*: string */) /*: string */ { - const parts = splitAuthorPkg(pkg); - return path.join(elmHome(), '0.19.1', 'packages', parts.author, parts.pkg); -} - -function splitAuthorPkg(pkgIdentifier /*: string */) /*: { - author: string, - pkg: string, -} */ { - const parts = pkgIdentifier.split('/'); - return { author: parts[0], pkg: parts[1] }; + return path.join(ElmHome.packagePath(pkg), version, 'elm.json'); } function splitPkgVersion(str /*: string */) /*: { @@ -356,28 +343,4 @@ function splitPkgVersion(str /*: string */) /*: { return { pkg: parts[0], version: parts[1] }; } -function elmHome() /*: string */ { - const elmHomeEnv = process.env['ELM_HOME']; - return elmHomeEnv === undefined ? defaultElmHome() : elmHomeEnv; -} - -function defaultElmHome() /*: string */ { - return process.platform === 'win32' - ? defaultWindowsElmHome() - : defaultUnixElmHome(); -} - -function defaultUnixElmHome() /*: string */ { - return path.join(os.homedir(), '.elm'); -} - -function defaultWindowsElmHome() /*: string */ { - const appData = process.env.APPDATA; - const dir = - appData === undefined - ? path.join(os.homedir(), 'AppData', 'Roaming') - : appData; - return path.join(dir, 'elm'); -} - module.exports = DependencyProvider; diff --git a/lib/ElmHome.js b/lib/ElmHome.js new file mode 100644 index 00000000..787eaee4 --- /dev/null +++ b/lib/ElmHome.js @@ -0,0 +1,47 @@ +// @flow + +const path = require('path'); +const os = require('os'); + +function elmHome() /*: string */ { + const elmHomeEnv = process.env['ELM_HOME']; + return elmHomeEnv === undefined ? defaultElmHome() : elmHomeEnv; +} + +function defaultElmHome() /*: string */ { + return process.platform === 'win32' + ? defaultWindowsElmHome() + : defaultUnixElmHome(); +} + +function defaultUnixElmHome() /*: string */ { + return path.join(os.homedir(), '.elm'); +} + +function defaultWindowsElmHome() /*: string */ { + const appData = process.env.APPDATA; + const dir = + appData === undefined + ? path.join(os.homedir(), 'AppData', 'Roaming') + : appData; + return path.join(dir, 'elm'); +} + +function packagePath(pkg /*: string */) /*: string */ { + const parts = splitAuthorPkg(pkg); + return path.join(elmHome(), '0.19.1', 'packages', parts.author, parts.pkg); +} + +function splitAuthorPkg(pkgIdentifier /*: string */) /*: { + author: string, + pkg: string, +} */ { + const parts = pkgIdentifier.split('/'); + return { author: parts[0], pkg: parts[1] }; +} + +module.exports = { + elmHome, + packagePath, + splitAuthorPkg, +}; diff --git a/lib/Install.js b/lib/Install.js index e815109d..7db5de12 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -2,10 +2,10 @@ const spawn = require('cross-spawn'); const fs = require('fs'); -const os = require('os'); const https = require('https'); const path = require('path'); const chalk = require('chalk'); +const ElmHome = require('./ElmHome'); const ElmJson = require('./ElmJson'); const Project = require('./Project'); @@ -175,29 +175,29 @@ async function downloadFileNative(url, filePath) { }); } +const PKG = 'elm-explorations/test'; +const VERSION = '1.2.2'; + async function installUnstableTestMaster( project /*: typeof Project.Project */ ) { - const pkg = 'elm-explorations/test'; - const version = '1.2.2'; - console.log( - chalk.yellow(`Using the master version of ${pkg} in place of ${version}.`) + chalk.yellow(`Using the master version of ${PKG} in place of ${VERSION}.`) ); console.log( chalk.yellow( - `Note you will need to rm -rf ~/.elm and ./elm-stuff (or use the \`elm-test uninstall-unstable-test-master\` command) afterwards to get back to the ${version} version.` + `Note: You will need to rm -rf ~/.elm and ./elm-stuff (or use the \`elm-test uninstall-unstable-test-master\` command) afterwards to get back to the ${VERSION} version.` ) ); - const pkgWithDash = pkg.replace('/', '-'); + const pkgWithDash = PKG.replace('/', '-'); const tempPath = project.generatedCodeDir; - const zipballUrl = `https://codeload.github.com/${pkg}/zip/refs/heads/master`; + const zipballUrl = `https://codeload.github.com/${PKG}/zip/refs/heads/master`; const zipballFilename = `${pkgWithDash}.zip`; const zipballPath = path.join(tempPath, zipballFilename); - const packagePath = path.join(elmHome, '0.19.1', 'packages', pkg, version); + const packagePath = path.join(ElmHome.packagePath(PKG), VERSION); console.log(chalk.dim.yellow(`Removing ${tempPath}`)); rmDirSync(tempPath); @@ -250,11 +250,8 @@ async function installUnstableTestMaster( } function uninstallUnstableTestMaster(project /*: typeof Project.Project */) { - const pkg = 'elm-explorations/test'; - const version = '1.2.2'; - const tempPath = project.generatedCodeDir; - const packagePath = path.join(elmHome, '0.19.1', 'packages', pkg, version); + const packagePath = path.join(ElmHome.packagePath(PKG), VERSION); console.log(chalk.dim.yellow(`Removing ${tempPath}`)); rmDirSync(tempPath); @@ -263,13 +260,6 @@ function uninstallUnstableTestMaster(project /*: typeof Project.Project */) { rmDirSync(packagePath); } -// ELM_HOME: based on info in https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/ -const elmHome = - process.env.ELM_HOME ?? - (process.platform === 'win32' - ? path.join(process.env.APPDATA ?? '', 'elm') - : path.join(os.homedir(), '.elm')); - module.exports = { install, installUnstableTestMaster, From 557634f3d71b9cf2f453e71d367223f941b3e435 Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Sat, 28 May 2022 10:23:13 +0200 Subject: [PATCH 13/19] Handle errors like we do in other commands --- lib/elm-test.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/elm-test.js b/lib/elm-test.js index 678426a2..88515333 100644 --- a/lib/elm-test.js +++ b/lib/elm-test.js @@ -217,7 +217,7 @@ function main() { const pathToElmBinary = getPathToElmBinary(options.compiler); const project = getProject('make'); const make = async () => { - await Generate.generateElmJson(dependencyProvider, project); + Generate.generateElmJson(dependencyProvider, project); await Compile.compileSources( FindTests.resolveGlobs( testFileGlobs.length === 0 ? [project.testsDir] : testFileGlobs, @@ -271,7 +271,10 @@ function main() { const project = getProject('install-unstable-test-master'); Install.installUnstableTestMaster(project).then( () => process.exit(0), - () => process.exit(1) + (error) => { + console.error(error.message); + process.exit(1); + } ); }); @@ -282,8 +285,13 @@ function main() { ) .action(() => { const project = getProject('uninstall-unstable-test-master'); - Install.uninstallUnstableTestMaster(project); - process.exit(0); + try { + Install.uninstallUnstableTestMaster(project); + process.exit(0); + } catch (error) { + console.error(error.message); + process.exit(1); + } }); program.parse(process.argv); From bbf9fa85a2b2f3fe3c5856e314f863efbbbdf081 Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Sat, 28 May 2022 10:26:52 +0200 Subject: [PATCH 14/19] Replace rmFileSync with fs.unlinkSync --- lib/Install.js | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/Install.js b/lib/Install.js index 7db5de12..37e5ee96 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -26,21 +26,6 @@ function rmDirSync(dir) { } } -function rmFileSync(file) { - // We can replace this with just `fs.rmSync(file, { recursive: false, force: true })` - // when Node.js 12 is EOL 2022-04-30 and support for Node.js 12 is dropped. - // `fs.rmSync` was added in Node.js 14.14.0, which is also when the - // `recursive` option of `fs.rmdirSync` was deprecated. The `if` avoids - // printing a deprecation message. - // $FlowFixMe[prop-missing]: Flow does not know of `fs.rmSync` yet. - if (fs.rmSync !== undefined) { - fs.rmSync(file, { recursive: false, force: true }); - } else if (fs.existsSync(file)) { - // $FlowFixMe[extra-arg]: Flow does not know of the options argument yet. - fs.rmdirSync(file, { recursive: false }); - } -} - function install( project /*: typeof Project.Project */, pathToElmBinary /*: string */, @@ -246,7 +231,7 @@ async function installUnstableTestMaster( fs.renameSync(path.join(tempPath, 'test-master'), packagePath); console.log(chalk.dim.yellow(`Removing ${zipballPath}`)); - rmFileSync(zipballPath); + fs.unlinkSync(zipballPath); } function uninstallUnstableTestMaster(project /*: typeof Project.Project */) { From bf7150eb56dd99f85c8dd5ac19fe81c78c93edba Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Sat, 28 May 2022 16:45:37 +0200 Subject: [PATCH 15/19] Remove mention of rm -rf --- lib/Install.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Install.js b/lib/Install.js index 37e5ee96..b018a56d 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -171,7 +171,7 @@ async function installUnstableTestMaster( ); console.log( chalk.yellow( - `Note: You will need to rm -rf ~/.elm and ./elm-stuff (or use the \`elm-test uninstall-unstable-test-master\` command) afterwards to get back to the ${VERSION} version.` + `Note: You will need to use the \`elm-test uninstall-unstable-test-master\` command afterwards to get back to the ${VERSION} version.` ) ); From 94dedda11a909a706e9fd35dbfd4467d15691b5d Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Sat, 28 May 2022 18:41:32 +0200 Subject: [PATCH 16/19] Try to fix Windows --- lib/Install.js | 59 ++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/lib/Install.js b/lib/Install.js index 37e5ee96..ae57f77f 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -179,8 +179,7 @@ async function installUnstableTestMaster( const tempPath = project.generatedCodeDir; const zipballUrl = `https://codeload.github.com/${PKG}/zip/refs/heads/master`; - const zipballFilename = `${pkgWithDash}.zip`; - const zipballPath = path.join(tempPath, zipballFilename); + const zipballPath = path.join(tempPath, `${pkgWithDash}.zip`); const packagePath = path.join(ElmHome.packagePath(PKG), VERSION); @@ -197,49 +196,43 @@ async function installUnstableTestMaster( await downloadFileNative(zipballUrl, zipballPath); console.log(chalk.dim.yellow(`Unzipping ${zipballPath}`)); - const unzipResult = spawn.sync( - 'unzip', - [ - '-o', // overwrite - zipballFilename, // file to unzip - '-d', - tempPath, // directory where to extract files - ], - { - cwd: tempPath, - } - ); - if (unzipResult.status !== 0) { - const tarResult = spawn.sync( - 'tar', - [ - 'zxf', // eXtract Zipped File - zipballFilename, // file to unzip - '-C', - tempPath, // directory where to extract files - ], - { - cwd: tempPath, - } - ); + const unzipResult = spawn.sync('unzip', [ + '-o', // overwrite + zipballPath, // file to unzip + '-d', + tempPath, // directory where to extract files + ]); + + if (unzipResult.status === 0) { + console.log(chalk.dim.yellow(`Moving to ELM_HOME: ${packagePath}`)); + fs.renameSync(path.join(tempPath, 'test-master'), packagePath); + } else { + // Windows does not have `unzip`, but BSD `tar`. On Windows, we have to extract + // straight into `packagePath` (instead of `tempPath`), because `fs.renameSync` + // gives an EPERM error otherwise, which seems to be due to how antivirus works + // on Windows. + const tarResult = spawn.sync('tar', [ + 'zxf', // eXtract Zipped File + zipballPath, // file to unzip + '-C', + packagePath, // directory where to extract files + '--strip-components=1', // strip the inner 'test-master' folder + ]); if (tarResult.status !== 0) { throw new Error('Failed to unzip the elm-explorations/test repo zipfile'); } } - console.log(chalk.dim.yellow(`Moving to ELM_HOME: ${packagePath}`)); - fs.renameSync(path.join(tempPath, 'test-master'), packagePath); - console.log(chalk.dim.yellow(`Removing ${zipballPath}`)); fs.unlinkSync(zipballPath); } function uninstallUnstableTestMaster(project /*: typeof Project.Project */) { - const tempPath = project.generatedCodeDir; + const { generatedCodeDir } = project; const packagePath = path.join(ElmHome.packagePath(PKG), VERSION); - console.log(chalk.dim.yellow(`Removing ${tempPath}`)); - rmDirSync(tempPath); + console.log(chalk.dim.yellow(`Removing ${generatedCodeDir}`)); + rmDirSync(generatedCodeDir); console.log(chalk.dim.yellow(`Removing ${packagePath}`)); rmDirSync(packagePath); From 0b9a0f35a67b124a0f3cb9d41ebc6a01426d5890 Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Sun, 29 May 2022 10:37:41 +0200 Subject: [PATCH 17/19] Remove unused value and add type annotations --- lib/Install.js | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/Install.js b/lib/Install.js index b29bbb33..de18e693 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -11,7 +11,7 @@ const Project = require('./Project'); void Project; -function rmDirSync(dir) { +function rmDirSync(dir /*: string */) /*: void */ { // We can replace this with just `fs.rmSync(dir, { recursive: true, force: true })` // when Node.js 12 is EOL 2022-04-30 and support for Node.js 12 is dropped. // `fs.rmSync` was added in Node.js 14.14.0, which is also when the @@ -124,29 +124,25 @@ function install( return 'SuccessfullyInstalled'; } -async function downloadFileNative(url, filePath) { +async function downloadFileNative( + url /*: string */, + filePath /*: string */ +) /*: Promise */ { return new Promise((resolve, reject) => { const file = fs.createWriteStream(filePath); - let fileInfo = null; const request = https.get(url, (response) => { if (response.statusCode !== 200) { fs.unlink(filePath, () => { reject(new Error(`Failed to get '${url}' (${response.statusCode})`)); }); - return; + } else { + response.pipe(file); } - - fileInfo = { - mime: response.headers['content-type'], - size: parseInt(response.headers['content-length'], 10), - }; - - response.pipe(file); }); // The destination stream is ended by the time it's called - file.on('finish', () => resolve(fileInfo)); + file.on('finish', () => resolve()); request.on('error', (err) => { fs.unlink(filePath, () => reject(err)); @@ -165,7 +161,7 @@ const VERSION = '1.2.2'; async function installUnstableTestMaster( project /*: typeof Project.Project */ -) { +) /*: Promise */ { console.log( chalk.yellow(`Using the master version of ${PKG} in place of ${VERSION}.`) ); @@ -227,7 +223,9 @@ async function installUnstableTestMaster( fs.unlinkSync(zipballPath); } -function uninstallUnstableTestMaster(project /*: typeof Project.Project */) { +function uninstallUnstableTestMaster( + project /*: typeof Project.Project */ +) /*: void */ { const { generatedCodeDir } = project; const packagePath = path.join(ElmHome.packagePath(PKG), VERSION); From 54f7093d21d097277360893f82b2a017bb55a29f Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Sun, 29 May 2022 11:08:51 +0200 Subject: [PATCH 18/19] Validate that 1.2.2 is used --- lib/ElmJson.js | 1 + lib/Install.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/lib/ElmJson.js b/lib/ElmJson.js index c9784220..96e1608d 100644 --- a/lib/ElmJson.js +++ b/lib/ElmJson.js @@ -184,6 +184,7 @@ function stringify(json /*: mixed */) /*: string */ { } module.exports = { + Dependencies, DirectAndIndirectDependencies, ElmJson, getPath, diff --git a/lib/Install.js b/lib/Install.js index de18e693..f4187ee5 100644 --- a/lib/Install.js +++ b/lib/Install.js @@ -156,12 +156,46 @@ async function downloadFileNative( }); } +function getDirectTestDependencies( + project /*: typeof Project.Project */ +) /*: typeof ElmJson.Dependencies */ { + switch (project.elmJson.type) { + case 'application': + return project.elmJson['test-dependencies'].direct; + case 'package': + return project.elmJson['test-dependencies']; + } +} + const PKG = 'elm-explorations/test'; const VERSION = '1.2.2'; async function installUnstableTestMaster( project /*: typeof Project.Project */ ) /*: Promise */ { + const directTestDependencies = getDirectTestDependencies(project); + const actualVersion = directTestDependencies[PKG]; + if (actualVersion !== VERSION) { + throw new Error( + ` +Could not find ${JSON.stringify(PKG)}: ${JSON.stringify( + VERSION + )} in your elm.json file here: + +${ElmJson.getPath(project.rootDir)} + +This command only works if you have ${PKG} as a (direct) test-dependency, +and only if you use version ${VERSION}. + +${ + actualVersion === undefined + ? 'I could not find it at all.' + : `You seem to be using version ${actualVersion}.` +} + `.trim() + ); + } + console.log( chalk.yellow(`Using the master version of ${PKG} in place of ${VERSION}.`) ); From e79119f0aad4fde445876c1953cfb4f039ff2440 Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Mon, 6 Jun 2022 13:16:54 +0200 Subject: [PATCH 19/19] Install package elm-explorations/test after uninstalling master --- lib/elm-test.js | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/elm-test.js b/lib/elm-test.js index 88515333..a426ba2b 100644 --- a/lib/elm-test.js +++ b/lib/elm-test.js @@ -284,14 +284,32 @@ function main() { 'Stop using the `master` version of the elm-explorations/test library' ) .action(() => { + const options = program.opts(); + const pathToElmBinary = getPathToElmBinary(options.compiler); const project = getProject('uninstall-unstable-test-master'); - try { + const run = async () => { Install.uninstallUnstableTestMaster(project); - process.exit(0); - } catch (error) { - console.error(error.message); - process.exit(1); - } + // Install project elm-explorations/test again. This is based on the `make` command. + Generate.generateElmJson(dependencyProvider, project); + const dummyFile = path.join(project.generatedCodeDir, 'Dummy.elm'); + fs.writeFileSync( + dummyFile, + `module Dummy exposing (dummy)\ndummy = ()` + ); + await Compile.compileSources( + [dummyFile], + project.generatedCodeDir, + pathToElmBinary, + options.report + ); + }; + run().then( + () => process.exit(0), + (error) => { + console.error(error.message); + process.exit(1); + } + ); }); program.parse(process.argv);