From 279f702c4a02a082eedba569082442b4f60139f5 Mon Sep 17 00:00:00 2001 From: Derk-Jan Karrenbeld Date: Thu, 4 Jul 2019 19:31:38 +0200 Subject: [PATCH 1/2] Add script for analyzing remote content --- bin/remote.bat | 4 ++ bin/remote.sh | 6 +++ src/remote-analyze.ts | 116 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 bin/remote.bat create mode 100644 bin/remote.sh create mode 100644 src/remote-analyze.ts diff --git a/bin/remote.bat b/bin/remote.bat new file mode 100644 index 00000000..cdf3983a --- /dev/null +++ b/bin/remote.bat @@ -0,0 +1,4 @@ +@REM Usage: +@REM ./bin/remote.bat https://exercism.io/solutions/8710d0d5953247848afd8bd6ae9dae04 + +node -r esm -r module-alias/register ./dist/remote-analyze.js __remote__ %* diff --git a/bin/remote.sh b/bin/remote.sh new file mode 100644 index 00000000..0590d90f --- /dev/null +++ b/bin/remote.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +# Usage: +# ./bin/remote.sh https://exercism.io/solutions/8710d0d5953247848afd8bd6ae9dae04 + +node -r esm -r module-alias/register ./dist/remote-analyze.js __remote__ "$@" diff --git a/src/remote-analyze.ts b/src/remote-analyze.ts new file mode 100644 index 00000000..bd9ae47e --- /dev/null +++ b/src/remote-analyze.ts @@ -0,0 +1,116 @@ +import { ExecutionOptionsImpl } from "./utils/execution_options"; +import { registerExceptionHandler } from "./errors/handler"; +import { Logger, setProcessLogger } from "./utils/logger"; +import { spawnSync, spawn } from 'child_process'; +import fs from 'fs'; +import path from 'path'; + +// The calls below uses the arguments passed to the process to figure out +// which exercise to target, where the input lives (url/solution id) and what +// execution options to set. +// +// remote https://exercism.io/mentor/solutions/11537f05a5ea4bbf8892291c6e75ec66 -dc +// +// For example, if arguments are passed directly, the above will attempt to +// use the exercism cli to download the above solution and then analyze it, +// based on where it downloads the exercise to and turning on debug and console +// logging. +// + +// [Bootstrap] start +registerExceptionHandler() +const options = ExecutionOptionsImpl.create() +const logger = new Logger(options) +setProcessLogger(logger) +// [Bootstrap] end + +logger.log('=> DEBUG mode is on') +logger.log(`=> input: ${options.inputDir}`) + +const input = options.inputDir.trim() + +let uuid = undefined +if (input.startsWith('https://exercism.io/')) { + uuid = input.split('/').reverse()[0] + if (uuid.length != 32) { + process.stderr.write(`Expected a UUID (length 32), got '${uuid}' (len: ${uuid.length})`) + process.exit(-2) + } +} else if (input.length == 32) { + uuid = input +} else if (fs.existsSync(input)) { + logger.error("=> input seems to be local") + logger.error(`=> run bin/analyse.sh ${input}`) + process.exit(-3) +} else { + process.stderr.write(`Expected a UUID (length 32) or solution URL, got '${input}'`) + process.exit(-4) +} + +logger.log(`~> exercism uuid: ${uuid}`) + +const downloadResult = spawnSync( + 'exercism', + [ + 'download', + `--uuid=${uuid}` + ], + { + env: process.env, + cwd: process.cwd(), + stdio: 'pipe' + } +) + +// Capture CLI tool errors +if (downloadResult.error) { + logger.error(downloadResult.error.name) + logger.error(downloadResult.error.message) + process.exit(-5) +} + +const [, downloadOut] = downloadResult.output; +const localPath = downloadOut.toString().trim() + +// Capture CLI tool issues (reported but not true) +if (!fs.existsSync(localPath)) { + logger.error(`=> cli tool reported output on ${localPath}`) + logger.error(`=> ${localPath} does not exist / is not accessible`) + process.exit(-6) +} + +// Capture incorrect track +const [exerciseSlug, track] = localPath.split(path.sep).reverse() +if (track !== 'javascript') { + logger.error(`=> expected a 'javascript' exercise, got '${track}'`) + process.exit(-7) +} + +const spawnable = path.join(__dirname, '..', 'dist', `analyze.js`) +logger.log(`-> executing node -r esm -r module-alias/register "${spawnable}" ${exerciseSlug} "${localPath}" ${process.argv.slice(4).join(' ')}`) + +// Keep in sync with bin/analyze.sh +// +const analyzeProcess = spawn('node', + [ + '-r', 'esm', + '-r', 'module-alias/register', + spawnable, + exerciseSlug, + localPath, + ...process.argv.slice(4) + ], + { cwd: process.cwd(), env: process.env } +) + +analyzeProcess.stderr.on('data', (data) => { + logger.error(data.toString()) +}) + +analyzeProcess.stdout.on('data', (data) => { + logger.log(data.toString()) +}) + +analyzeProcess.on('close', (code) => { + process.exit(code) +}) From 5e1e8b83112df4f1d235446c2ac577c4dc81cce4 Mon Sep 17 00:00:00 2001 From: Derk-Jan Karrenbeld Date: Thu, 4 Jul 2019 19:39:38 +0200 Subject: [PATCH 2/2] Trim line-endings --- src/remote-analyze.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/remote-analyze.ts b/src/remote-analyze.ts index bd9ae47e..49d6ce7c 100644 --- a/src/remote-analyze.ts +++ b/src/remote-analyze.ts @@ -104,11 +104,11 @@ const analyzeProcess = spawn('node', ) analyzeProcess.stderr.on('data', (data) => { - logger.error(data.toString()) + logger.error(data.toString().trim()) }) analyzeProcess.stdout.on('data', (data) => { - logger.log(data.toString()) + logger.log(data.toString().trim()) }) analyzeProcess.on('close', (code) => {