Skip to content

Commit b0f54fe

Browse files
Add script for analyzing remote content (#42)
* Add script for analyzing remote content * Trim line-endings
1 parent 39c6533 commit b0f54fe

3 files changed

Lines changed: 126 additions & 0 deletions

File tree

bin/remote.bat

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@REM Usage:
2+
@REM ./bin/remote.bat https://exercism.io/solutions/8710d0d5953247848afd8bd6ae9dae04
3+
4+
node -r esm -r module-alias/register ./dist/remote-analyze.js __remote__ %*

bin/remote.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env sh
2+
3+
# Usage:
4+
# ./bin/remote.sh https://exercism.io/solutions/8710d0d5953247848afd8bd6ae9dae04
5+
6+
node -r esm -r module-alias/register ./dist/remote-analyze.js __remote__ "$@"

src/remote-analyze.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { ExecutionOptionsImpl } from "./utils/execution_options";
2+
import { registerExceptionHandler } from "./errors/handler";
3+
import { Logger, setProcessLogger } from "./utils/logger";
4+
import { spawnSync, spawn } from 'child_process';
5+
import fs from 'fs';
6+
import path from 'path';
7+
8+
// The calls below uses the arguments passed to the process to figure out
9+
// which exercise to target, where the input lives (url/solution id) and what
10+
// execution options to set.
11+
//
12+
// remote https://exercism.io/mentor/solutions/11537f05a5ea4bbf8892291c6e75ec66 -dc
13+
//
14+
// For example, if arguments are passed directly, the above will attempt to
15+
// use the exercism cli to download the above solution and then analyze it,
16+
// based on where it downloads the exercise to and turning on debug and console
17+
// logging.
18+
//
19+
20+
// [Bootstrap] start
21+
registerExceptionHandler()
22+
const options = ExecutionOptionsImpl.create()
23+
const logger = new Logger(options)
24+
setProcessLogger(logger)
25+
// [Bootstrap] end
26+
27+
logger.log('=> DEBUG mode is on')
28+
logger.log(`=> input: ${options.inputDir}`)
29+
30+
const input = options.inputDir.trim()
31+
32+
let uuid = undefined
33+
if (input.startsWith('https://exercism.io/')) {
34+
uuid = input.split('/').reverse()[0]
35+
if (uuid.length != 32) {
36+
process.stderr.write(`Expected a UUID (length 32), got '${uuid}' (len: ${uuid.length})`)
37+
process.exit(-2)
38+
}
39+
} else if (input.length == 32) {
40+
uuid = input
41+
} else if (fs.existsSync(input)) {
42+
logger.error("=> input seems to be local")
43+
logger.error(`=> run bin/analyse.sh <exercise> ${input}`)
44+
process.exit(-3)
45+
} else {
46+
process.stderr.write(`Expected a UUID (length 32) or solution URL, got '${input}'`)
47+
process.exit(-4)
48+
}
49+
50+
logger.log(`~> exercism uuid: ${uuid}`)
51+
52+
const downloadResult = spawnSync(
53+
'exercism',
54+
[
55+
'download',
56+
`--uuid=${uuid}`
57+
],
58+
{
59+
env: process.env,
60+
cwd: process.cwd(),
61+
stdio: 'pipe'
62+
}
63+
)
64+
65+
// Capture CLI tool errors
66+
if (downloadResult.error) {
67+
logger.error(downloadResult.error.name)
68+
logger.error(downloadResult.error.message)
69+
process.exit(-5)
70+
}
71+
72+
const [, downloadOut] = downloadResult.output;
73+
const localPath = downloadOut.toString().trim()
74+
75+
// Capture CLI tool issues (reported but not true)
76+
if (!fs.existsSync(localPath)) {
77+
logger.error(`=> cli tool reported output on ${localPath}`)
78+
logger.error(`=> ${localPath} does not exist / is not accessible`)
79+
process.exit(-6)
80+
}
81+
82+
// Capture incorrect track
83+
const [exerciseSlug, track] = localPath.split(path.sep).reverse()
84+
if (track !== 'javascript') {
85+
logger.error(`=> expected a 'javascript' exercise, got '${track}'`)
86+
process.exit(-7)
87+
}
88+
89+
const spawnable = path.join(__dirname, '..', 'dist', `analyze.js`)
90+
logger.log(`-> executing node -r esm -r module-alias/register "${spawnable}" ${exerciseSlug} "${localPath}" ${process.argv.slice(4).join(' ')}`)
91+
92+
// Keep in sync with bin/analyze.sh
93+
//
94+
const analyzeProcess = spawn('node',
95+
[
96+
'-r', 'esm',
97+
'-r', 'module-alias/register',
98+
spawnable,
99+
exerciseSlug,
100+
localPath,
101+
...process.argv.slice(4)
102+
],
103+
{ cwd: process.cwd(), env: process.env }
104+
)
105+
106+
analyzeProcess.stderr.on('data', (data) => {
107+
logger.error(data.toString().trim())
108+
})
109+
110+
analyzeProcess.stdout.on('data', (data) => {
111+
logger.log(data.toString().trim())
112+
})
113+
114+
analyzeProcess.on('close', (code) => {
115+
process.exit(code)
116+
})

0 commit comments

Comments
 (0)