Skip to content

Commit 44263d2

Browse files
committed
cli: switch to external environment management
Currently can only be able to be run by nix, but the plan is to create a docker container for non-nix users. Can run the cli using: nix run . -- pawtograder /path/to/submission -s /path/to/solution
1 parent b1603c6 commit 44263d2

File tree

13 files changed

+111
-274
lines changed

13 files changed

+111
-274
lines changed

flake.nix

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,23 @@
2323

2424
formatter = eachSystem (pkgs: treefmtEval.${pkgs.system}.config.build.wrapper);
2525

26+
apps = eachSystem (
27+
pkgs:
28+
let
29+
packages = self.packages.${pkgs.system};
30+
in
31+
{
32+
default = {
33+
type = "app";
34+
program = "${packages.cli}/bin/cli";
35+
};
36+
pawtograder-pyret = {
37+
type = "app";
38+
program = "${packages.pawtograder-exec}/bin/pyret-pawtograder";
39+
};
40+
}
41+
);
42+
2643
checks = eachSystem (pkgs: {
2744

2845
});

nix/packages/cli/default.nix

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
stdenv,
3+
lib,
4+
nodejs-slim-stripped,
5+
makeWrapper,
6+
pyret-autograder-prepared,
7+
nodejs,
8+
pnpm,
9+
pawtograder-exec,
10+
...
11+
}:
12+
stdenv.mkDerivation (finalAttrs: {
13+
name = "pyret-autograder-cli";
14+
15+
src = pyret-autograder-prepared;
16+
17+
nativeBuildInputs = [
18+
nodejs
19+
pnpm
20+
makeWrapper
21+
];
22+
23+
buildPhase = ''
24+
set -eu
25+
pushd pkgs/cli
26+
pnpm run build
27+
popd
28+
'';
29+
30+
installPhase = ''
31+
runHook preInstall
32+
33+
set -eu
34+
mkdir -p $out/bin
35+
36+
cp -r pkgs/cli/dist $out/
37+
cp pkgs/cli/package.json $out/
38+
cp -rL pkgs/cli/node_modules $out/
39+
cp ${pawtograder-exec}/bin/pyret-pawtograder $out/bin
40+
41+
makeWrapper ${lib.getExe nodejs-slim-stripped} $out/bin/cli \
42+
--add-flags "--enable-source-maps" \
43+
--add-flags "$out/dist/index.js" \
44+
--set PAWTOGRADER_PYRET_PATH "$out/bin/pyret-pawtograder"
45+
46+
runHook postInstall
47+
'';
48+
})

nix/packages/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let
1717
pyret-autograder-prepared = callPackage ./pyret-autograder-prepared/default.nix { };
1818
pawtograder-exec = callPackage ./pawtograder-exec/default.nix { };
1919
scc = callPackage ./scc/default.nix { };
20+
cli = callPackage ./cli/default.nix { };
2021
};
2122
in
2223
packages

nix/packages/pawtograder-exec/default.nix

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
compiled-builtins,
77
makeWrapper,
88
callPackage,
9-
nodejs,
10-
pnpm,
119
...
1210
}:
1311
let

nix/packages/pyret-autograder-prepared/default.nix

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
nodejs,
44
pnpm,
55
pyret-autograder-src,
6+
lib,
67
...
78
}:
89
stdenv.mkDerivation (finalAttrs: {
@@ -21,7 +22,7 @@ stdenv.mkDerivation (finalAttrs: {
2122
inherit (finalAttrs) src;
2223
fetcherVersion = 2;
2324
# hash = lib.fakeHash;
24-
hash = "sha256-MkD1/VpdvcIhIv9XxG05IA6DLwUVqAkFzGpGzyT8YDE=";
25+
hash = "sha256-0imd3gMgbWmaqW1DHa5Ne/x0eQhQMi+qo4pL9Jx+xpQ=";
2526
}).overrideAttrs
2627
(old: {
2728
# HACK: we really shouldn't be doing this! but its tricky to update the lockfile for the overrides

pkgs/cli/.swcrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
{
22
"$schema": "https://swc.rs/schema.json",
33
"jsc": {
44
"parser": {

pkgs/cli/bin/pawtograder.ts

Lines changed: 23 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,48 +17,15 @@
1717
with pyret-autograder-cli. If not, see <http://www.gnu.org/licenses/>.
1818
*/
1919

20-
import yaml from "yaml";
21-
import { readFile, mkdtemp } from "node:fs/promises";
20+
import chalk from "chalk";
2221
import { spawn } from "node:child_process";
22+
import { mkdtemp } from "node:fs/promises";
2323
import path from "node:path";
24-
import { Config, Spec, z } from "pyret-autograder-pawtograder";
25-
import chalk from "chalk";
2624
import os from "os";
2725

28-
const PKG_ROOT = path.resolve(import.meta.dirname, "..");
29-
const DEFAULT_COMPILED_PATH =
30-
path.join(PKG_ROOT, "build/pyret/lib-compiled") +
31-
":" +
32-
path.join(PKG_ROOT, "build/pyret/cpo-compiled");
33-
34-
async function resolveSpec(submissionPath: string, solutionPath: string) {
35-
const rawConfig = await readFile(
36-
path.join(solutionPath, "pawtograder.yml"),
37-
"utf8",
38-
);
39-
40-
const config: Config = yaml.parse(rawConfig, { merge: true });
41-
42-
console.dir(config, { depth: 3 });
43-
44-
const parseRes = Spec.safeParse({
45-
solution_dir: solutionPath,
46-
submission_dir: submissionPath,
47-
config,
48-
});
49-
50-
if (parseRes.success) {
51-
return parseRes.data;
52-
} else {
53-
const pretty = z.prettifyError(parseRes.error);
54-
const err =
55-
chalk.redBright.bold`Invalid specification provided` +
56-
`:\n${chalk.yellow(pretty)}\n\n` +
57-
chalk.bold`See the ` +
58-
chalk.blackBright.bold`cause` +
59-
chalk.bold` field for the full error.`;
60-
61-
throw new Error(err, { cause: parseRes.error });
26+
class InnerError extends Error {
27+
constructor(message: string) {
28+
super(message);
6229
}
6330
}
6431

@@ -68,7 +35,6 @@ export async function pawtograderAction(
6835
) {
6936
const submissionPath = path.resolve(submission);
7037
const solutionPath = path.resolve(solution);
71-
const spec = await resolveSpec(submissionPath, solutionPath);
7238

7339
console.log(
7440
`Grading submission at ${submissionPath} with the specification located in ${solutionPath}`,
@@ -81,29 +47,26 @@ export async function pawtograderAction(
8147
})();
8248
const result = await new Promise((resolve, reject) => {
8349
const env = {
84-
PA_PYRET_LANG_COMPILED_PATH: DEFAULT_COMPILED_PATH,
8550
PA_CURRENT_LOAD_PATH: submissionPath,
8651
PA_ARTIFACT_DIR: artifactDir,
8752
...process.env,
8853
PWD: submissionPath,
8954
};
9055

9156
const child = spawn(
92-
process.execPath,
93-
[path.join(import.meta.dirname, "../src/pawtograder.cjs")],
57+
process.env.PAWTOGRADER_PYRET_PATH ?? "pyret-pawtograder",
58+
[solutionPath, submissionPath],
9459
{
9560
env,
9661
cwd: submissionPath,
9762
// [ stdin, stdout, stderr, custom]
98-
stdio: ["pipe", "pipe", "pipe", "pipe"],
63+
stdio: ["ignore", "pipe", "pipe", "pipe"],
9964
},
10065
);
10166

102-
console.log("grader started");
103-
10467
for (const [stream, target, name] of [
105-
[child.stdout, process.stdout, chalk.blue`stdout`],
106-
[child.stderr, process.stderr, chalk.red`stderr`],
68+
[child.stdout!, process.stdout, chalk.blue`stdout`],
69+
[child.stderr!, process.stderr, chalk.red`stderr`],
10770
] as const) {
10871
const prefix = `${name} » `;
10972
let leftover = "";
@@ -125,18 +88,22 @@ export async function pawtograderAction(
12588

12689
child.on("close", (code) => {
12790
console.log("grader ended");
128-
if (code !== 0) {
91+
if (code === 0) {
92+
try {
93+
resolve(JSON.parse(output));
94+
} catch (e) {
95+
reject(new Error(`Invalid JSON from grader: ${output}\n${e}`));
96+
}
97+
} else if (code === 1) {
98+
try {
99+
reject(new InnerError(JSON.parse(output)));
100+
} catch (e) {
101+
reject(new Error(`Invalid JSON from grader: ${output}\n${e}`));
102+
}
103+
} else {
129104
return reject(new Error(`Grader failed with code ${code}.`));
130105
}
131-
try {
132-
resolve(JSON.parse(output));
133-
} catch (e) {
134-
reject(new Error(`Invalid JSON from grader: ${output}\n${e}`));
135-
}
136106
});
137-
138-
child.stdin.write(JSON.stringify(spec));
139-
child.stdin.end();
140107
});
141108

142109
console.dir(result);

pkgs/cli/package.json

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,17 @@
1414
"pyret-autograder-cli": "dist/index.js"
1515
},
1616
"scripts": {
17-
"build": "pnpm run build_typescript && npm run build_pawtograder",
17+
"build": "swc bin -d dist --strip-leading-paths",
1818
"build_typescript": "swc bin -d dist --strip-leading-paths",
19-
"build_pawtograder": "pnpm run build_pawtograder:prepare && pnpm run build_pawtograder:pyret",
20-
"build_pawtograder:prepare": "./scripts/prepare.sh",
21-
"build_pawtograder:pyret": "./scripts/compile-pawtograder.sh",
2219
"prepack": "pnpm run build"
2320
},
2421
"dependencies": {
2522
"chalk": "^5.4.1",
26-
"commander": "^14.0.0",
27-
"pyret-autograder": "workspace:^",
28-
"pyret-autograder-pawtograder": "workspace:^",
29-
"yaml": "catalog:",
30-
"canvas": "catalog:pyret-runtime",
31-
"cross-fetch": "catalog:pyret-runtime",
32-
"fast-csv": "catalog:pyret-runtime",
33-
"js-md5": "catalog:pyret-runtime",
34-
"js-sha256": "catalog:pyret-runtime",
35-
"q": "catalog:pyret-runtime",
36-
"resolve": "catalog:pyret-runtime",
37-
"s-expression": "catalog:pyret-runtime",
38-
"seedrandom": "catalog:pyret-runtime",
39-
"source-map": "catalog:pyret-runtime",
40-
"vega": "catalog:pyret-runtime"
23+
"commander": "^14.0.2"
4124
},
4225
"devDependencies": {
43-
"@types/node": "catalog:",
4426
"@swc/cli": "catalog:",
45-
"@swc/core": "catalog:"
27+
"@swc/core": "catalog:",
28+
"@types/node": "catalog:"
4629
}
4730
}

pkgs/cli/scripts/compile-pawtograder.sh

Lines changed: 0 additions & 16 deletions
This file was deleted.

pkgs/cli/scripts/dcic2024-charts.patch

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)