[Shared][Web][Sandbox] Build shared in docker

This commit is contained in:
orosmatthew 2024-03-12 12:37:19 -04:00
parent 24b1b2b4ad
commit 4c02999c0a
11 changed files with 28 additions and 6763 deletions

2
sandbox/.dockerignore Normal file
View File

@ -0,0 +1,2 @@
/node_modules
/build

View File

@ -2,9 +2,6 @@ FROM ubuntu:22.04
# Setup # Setup
RUN mkdir sandbox
WORKDIR /app/sandbox
RUN apt-get update RUN apt-get update
RUN apt-get install curl -y RUN apt-get install curl -y
@ -23,21 +20,24 @@ ENV DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true
RUN git config --global user.name "Admin" RUN git config --global user.name "Admin"
RUN git config --global user.email noemail@example.com RUN git config --global user.email noemail@example.com
# Prep Sandbox
WORKDIR /app/sandbox
COPY ./sandbox/package*.json ./
RUN npm install
COPY ./sandbox/ .
# Prep Shared # Prep Shared
WORKDIR /app WORKDIR /app
RUN mkdir shared RUN mkdir shared
WORKDIR /app/shared WORKDIR /app/shared
COPY ./shared/package*.json ./
RUN npm ci
COPY ./shared . COPY ./shared .
# Prep Sandbox
RUN mkdir sandbox
WORKDIR /app/sandbox
COPY ./sandbox/package*.json ./
RUN npm ci
COPY ./sandbox/ .
# Build/Run # Build/Run
WORKDIR /app/sandbox WORKDIR /app/sandbox

View File

@ -1 +1,2 @@
/node_modules /node_modules
/build

2
shared/.gitignore vendored
View File

@ -1,2 +1,2 @@
node_modules node_modules
dist/tsconfig/tsbuildinfo /build

2462
shared/dist/cpp.js vendored

File diff suppressed because it is too large Load Diff

227
shared/dist/csharp.js vendored
View File

@ -1,227 +0,0 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// node_modules/tree-kill/index.js
var require_tree_kill = __commonJS({
"node_modules/tree-kill/index.js"(exports2, module2) {
"use strict";
var childProcess = require("child_process");
var spawn2 = childProcess.spawn;
var exec = childProcess.exec;
module2.exports = function(pid, signal, callback) {
if (typeof signal === "function" && callback === void 0) {
callback = signal;
signal = void 0;
}
pid = parseInt(pid);
if (Number.isNaN(pid)) {
if (callback) {
return callback(new Error("pid must be a number"));
} else {
throw new Error("pid must be a number");
}
}
var tree = {};
var pidsToProcess = {};
tree[pid] = [];
pidsToProcess[pid] = 1;
switch (process.platform) {
case "win32":
exec("taskkill /pid " + pid + " /T /F", callback);
break;
case "darwin":
buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
return spawn2("pgrep", ["-P", parentPid]);
}, function() {
killAll(tree, signal, callback);
});
break;
default:
buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
return spawn2("ps", ["-o", "pid", "--no-headers", "--ppid", parentPid]);
}, function() {
killAll(tree, signal, callback);
});
break;
}
};
function killAll(tree, signal, callback) {
var killed = {};
try {
Object.keys(tree).forEach(function(pid) {
tree[pid].forEach(function(pidpid) {
if (!killed[pidpid]) {
killPid(pidpid, signal);
killed[pidpid] = 1;
}
});
if (!killed[pid]) {
killPid(pid, signal);
killed[pid] = 1;
}
});
} catch (err) {
if (callback) {
return callback(err);
} else {
throw err;
}
}
if (callback) {
return callback();
}
}
function killPid(pid, signal) {
try {
process.kill(parseInt(pid, 10), signal);
} catch (err) {
if (err.code !== "ESRCH")
throw err;
}
}
function buildProcessTree(parentPid, tree, pidsToProcess, spawnChildProcessesList, cb) {
var ps = spawnChildProcessesList(parentPid);
var allData = "";
ps.stdout.on("data", function(data) {
var data = data.toString("ascii");
allData += data;
});
var onClose = function(code) {
delete pidsToProcess[parentPid];
if (code != 0) {
if (Object.keys(pidsToProcess).length == 0) {
cb();
}
return;
}
allData.match(/\d+/g).forEach(function(pid) {
pid = parseInt(pid, 10);
tree[parentPid].push(pid);
tree[pid] = [];
pidsToProcess[pid] = 1;
buildProcessTree(pid, tree, pidsToProcess, spawnChildProcessesList, cb);
});
};
ps.on("close", onClose);
}
}
});
// submission-runner/csharp.cts
var csharp_exports = {};
__export(csharp_exports, {
runCSharp: () => runCSharp
});
module.exports = __toCommonJS(csharp_exports);
var import_child_process = require("child_process");
var import_tree_kill = __toESM(require_tree_kill());
// submission-runner/settings.cts
var timeoutSeconds = 30;
// submission-runner/csharp.cts
var runCSharp = async function(params) {
console.log(`- RUN: ${params.srcDir}`);
const child = (0, import_child_process.spawn)("dotnet run", { shell: true, cwd: params.srcDir });
try {
let outputBuffer = "";
child.stdout.setEncoding("utf8");
child.stdout.on("data", (data) => {
outputBuffer += data.toString();
params.outputCallback?.(data.toString());
});
child.stderr.setEncoding("utf8");
child.stderr.on("data", (data) => {
outputBuffer += data.toString();
params.outputCallback?.(data.toString());
});
const runStartTime = performance.now();
child.stdin.write(params.input);
child.stdin.end();
let timeLimitExceeded = false;
let completedNormally = false;
return {
success: true,
runResult: new Promise((resolve) => {
child.on("close", () => {
completedNormally = !timeLimitExceeded;
const runEndTime = performance.now();
const runtimeMilliseconds = Math.floor(runEndTime - runStartTime);
if (completedNormally) {
clearTimeout(timeoutHandle);
resolve({
kind: "Completed",
output: outputBuffer,
exitCode: child.exitCode,
runtimeMilliseconds
});
} else {
console.log(`Process terminated, total sandbox time: ${runtimeMilliseconds}ms`);
resolve({
kind: "TimeLimitExceeded",
output: outputBuffer,
resultKindReason: `Timeout after ${timeoutSeconds} seconds`
});
}
});
const timeoutHandle = setTimeout(() => {
if (completedNormally) {
return;
}
console.log(`Run timed out after ${timeoutSeconds} seconds, killing process...`);
timeLimitExceeded = true;
child.stdin.end();
child.stdin.destroy();
child.stdout.destroy();
child.stderr.destroy();
if (child.pid !== void 0) {
(0, import_tree_kill.default)(child.pid);
}
}, timeoutSeconds * 1e3);
}),
killFunc() {
if (child.pid !== void 0) {
if (!completedNormally && !timeLimitExceeded) {
(0, import_tree_kill.default)(child.pid);
params.outputCallback?.("\n[Manually stopped]");
}
}
}
};
} catch (error) {
return { success: false, runResult: { kind: "RunError" } };
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
runCSharp
});

241
shared/dist/java.js vendored
View File

@ -1,241 +0,0 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// node_modules/tree-kill/index.js
var require_tree_kill = __commonJS({
"node_modules/tree-kill/index.js"(exports2, module2) {
"use strict";
var childProcess = require("child_process");
var spawn2 = childProcess.spawn;
var exec2 = childProcess.exec;
module2.exports = function(pid, signal, callback) {
if (typeof signal === "function" && callback === void 0) {
callback = signal;
signal = void 0;
}
pid = parseInt(pid);
if (Number.isNaN(pid)) {
if (callback) {
return callback(new Error("pid must be a number"));
} else {
throw new Error("pid must be a number");
}
}
var tree = {};
var pidsToProcess = {};
tree[pid] = [];
pidsToProcess[pid] = 1;
switch (process.platform) {
case "win32":
exec2("taskkill /pid " + pid + " /T /F", callback);
break;
case "darwin":
buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
return spawn2("pgrep", ["-P", parentPid]);
}, function() {
killAll(tree, signal, callback);
});
break;
default:
buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
return spawn2("ps", ["-o", "pid", "--no-headers", "--ppid", parentPid]);
}, function() {
killAll(tree, signal, callback);
});
break;
}
};
function killAll(tree, signal, callback) {
var killed = {};
try {
Object.keys(tree).forEach(function(pid) {
tree[pid].forEach(function(pidpid) {
if (!killed[pidpid]) {
killPid(pidpid, signal);
killed[pidpid] = 1;
}
});
if (!killed[pid]) {
killPid(pid, signal);
killed[pid] = 1;
}
});
} catch (err) {
if (callback) {
return callback(err);
} else {
throw err;
}
}
if (callback) {
return callback();
}
}
function killPid(pid, signal) {
try {
process.kill(parseInt(pid, 10), signal);
} catch (err) {
if (err.code !== "ESRCH")
throw err;
}
}
function buildProcessTree(parentPid, tree, pidsToProcess, spawnChildProcessesList, cb) {
var ps = spawnChildProcessesList(parentPid);
var allData = "";
ps.stdout.on("data", function(data) {
var data = data.toString("ascii");
allData += data;
});
var onClose = function(code) {
delete pidsToProcess[parentPid];
if (code != 0) {
if (Object.keys(pidsToProcess).length == 0) {
cb();
}
return;
}
allData.match(/\d+/g).forEach(function(pid) {
pid = parseInt(pid, 10);
tree[parentPid].push(pid);
tree[pid] = [];
pidsToProcess[pid] = 1;
buildProcessTree(pid, tree, pidsToProcess, spawnChildProcessesList, cb);
});
};
ps.on("close", onClose);
}
}
});
// submission-runner/java.cts
var java_exports = {};
__export(java_exports, {
runJava: () => runJava
});
module.exports = __toCommonJS(java_exports);
var import_path = require("path");
var import_child_process = require("child_process");
var util = __toESM(require("util"));
// submission-runner/settings.cts
var timeoutSeconds = 30;
// submission-runner/java.cts
var kill = require_tree_kill();
var execPromise = util.promisify(import_child_process.exec);
var runJava = async function(params) {
console.log(`- BUILD: ${params.mainFile}`);
const compileCommand = `javac -cp ${(0, import_path.join)(params.srcDir, "src")} ${params.mainFile} -d ${(0, import_path.join)(params.srcDir, "build")}`;
try {
await execPromise(compileCommand);
} catch (e) {
const buildErrorText = e?.toString() ?? "Unknown build errors.";
console.log("Build errors: " + buildErrorText);
return {
success: false,
runResult: { kind: "CompileFailed", resultKindReason: buildErrorText }
};
}
console.log(`- RUN: ${params.mainClass}`);
const runCommand = `java -cp "${(0, import_path.join)(params.srcDir, "build")}" ${params.mainClass}`;
try {
let outputBuffer = "";
const child = (0, import_child_process.spawn)(runCommand, { shell: true });
child.stdout.setEncoding("utf8");
child.stdout.on("data", (data) => {
outputBuffer += data.toString();
params.outputCallback?.(data.toString());
});
child.stderr.setEncoding("utf8");
child.stderr.on("data", (data) => {
outputBuffer += data.toString();
params.outputCallback?.(data.toString());
});
const runStartTime = performance.now();
child.stdin.write(params.input);
child.stdin.end();
let timeLimitExceeded = false;
let completedNormally = false;
return {
success: true,
runResult: new Promise((resolve) => {
child.on("close", () => {
completedNormally = !timeLimitExceeded;
const runEndTime = performance.now();
const runtimeMilliseconds = Math.floor(runEndTime - runStartTime);
if (completedNormally) {
clearTimeout(timeoutHandle);
resolve({
kind: "Completed",
output: outputBuffer,
exitCode: child.exitCode,
runtimeMilliseconds
});
} else {
console.log(`Process terminated, total sandbox time: ${runtimeMilliseconds}ms`);
resolve({
kind: "TimeLimitExceeded",
output: outputBuffer,
resultKindReason: `Timeout after ${timeoutSeconds} seconds`
});
}
});
const timeoutHandle = setTimeout(() => {
if (completedNormally) {
return;
}
console.log(`Run timed out after ${timeoutSeconds} seconds, killing process...`);
timeLimitExceeded = true;
child.stdin.end();
child.stdin.destroy();
child.stdout.destroy();
child.stderr.destroy();
child.kill("SIGKILL");
}, timeoutSeconds * 1e3);
}),
killFunc() {
if (child.pid !== void 0) {
if (!completedNormally && !timeLimitExceeded) {
kill(child.pid);
params.outputCallback?.("\n[Manually stopped]");
}
}
}
};
} catch (error) {
return { success: false, runResult: { kind: "RunError" } };
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
runJava
});

View File

@ -1,30 +0,0 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// submission-runner/settings.cts
var settings_exports = {};
__export(settings_exports, {
timeoutSeconds: () => timeoutSeconds
});
module.exports = __toCommonJS(settings_exports);
var timeoutSeconds = 30;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
timeoutSeconds
});

3778
shared/dist/types.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "bwcontest-shared", "name": "bwcontest-shared",
"scripts": { "scripts": {
"build": "esbuild submission-runner/*.cts --bundle --outdir=dist --format=cjs --platform=node", "build": "esbuild submission-runner/*.cts --bundle --outdir=build --format=cjs --platform=node --sourcemap",
"format": "prettier --write .", "format": "prettier --write .",
"lint": "prettier --check . && eslint .", "lint": "prettier --check . && eslint .",
"check": "tsc -noEmit" "check": "tsc -noEmit"

View File

@ -2,9 +2,6 @@ FROM ubuntu:22.04
# Setup # Setup
RUN mkdir web
WORKDIR /app/web
RUN apt-get update RUN apt-get update
RUN apt-get install curl -y RUN apt-get install curl -y
@ -14,23 +11,26 @@ RUN apt-get install nodejs git -y
RUN git config --global user.name "Admin" RUN git config --global user.name "Admin"
RUN git config --global user.email noemail@example.com RUN git config --global user.email noemail@example.com
# Prep Web
COPY ./web/package*.json ./
RUN npm install
COPY ./web/ .
# Prep Shared # Prep Shared
WORKDIR /app WORKDIR /app
RUN mkdir shared RUN mkdir shared
WORKDIR /app/shared WORKDIR /app/shared
COPY ./shared/package*.json ./
RUN npm ci
COPY ./shared/ . COPY ./shared/ .
RUN npm run build
# Prep Web
RUN mkdir web
WORKDIR /app/web
COPY ./web/package*.json ./
RUN npm ci
COPY ./web/ .
# Env/Build/Run # Env/Build/Run
WORKDIR /app/web
ENV PORT=3000 ENV PORT=3000
EXPOSE 3000 EXPOSE 3000
EXPOSE 7006 EXPOSE 7006