|
@@ -1,11 +1,11 @@
|
|
|
'use strict';
|
|
|
-import * as vscode from 'vscode';
|
|
|
-import { mkdirSync, existsSync, copyFileSync, openSync, readSync, readdirSync, writeSync, closeSync } from "fs";
|
|
|
-import { dirname, join, extname, basename } from "path";
|
|
|
import * as child_process from 'child_process';
|
|
|
+import { closeSync, copyFileSync, existsSync, mkdirSync, openSync, readdirSync, readSync, writeSync } from "fs";
|
|
|
+import { basename, dirname, extname, join } from "path";
|
|
|
+import * as vscode from 'vscode';
|
|
|
import * as gwen from './gwen';
|
|
|
-import { TestcaseResult, Verdict, SolutionResult, Problem, Contest, SiteDescription } from "./types";
|
|
|
import { ceTerminal, stderrTerminal } from './terminal';
|
|
|
+import { Contest, Problem, SiteDescription, SolutionResult, TestcaseResult, Verdict } from "./types";
|
|
|
const md5File = require('md5-file');
|
|
|
|
|
|
export const TESTCASES = 'testcases';
|
|
@@ -15,13 +15,13 @@ export const SRC = dirname(__filename);
|
|
|
/**
|
|
|
* Name of program file. Take extension dynamically from configuration
|
|
|
*/
|
|
|
-export function solFile(){
|
|
|
- let extension: string|undefined = vscode.workspace.getConfiguration('acmx.configuration', null).get('extension');
|
|
|
+export function solFile() {
|
|
|
+ let extension: string | undefined = vscode.workspace.getConfiguration('acmx.configuration', null).get('extension');
|
|
|
return 'sol.' + extension;
|
|
|
}
|
|
|
|
|
|
-export function getTimeout(){
|
|
|
- let timeout: number|undefined = vscode.workspace.getConfiguration('acmx.run', null).get('timeLimit');
|
|
|
+export function getTimeout() {
|
|
|
+ let timeout: number | undefined = vscode.workspace.getConfiguration('acmx.run', null).get('timeLimit');
|
|
|
timeout = timeout! * 1000;
|
|
|
return timeout;
|
|
|
}
|
|
@@ -29,16 +29,16 @@ export function getTimeout(){
|
|
|
/**
|
|
|
* Can only handle testcases of at most 512MB
|
|
|
*/
|
|
|
-function getMaxSizeInput(){
|
|
|
+function getMaxSizeInput() {
|
|
|
return 512 * 1024;
|
|
|
}
|
|
|
|
|
|
function isProblemFolder(path: string) {
|
|
|
- return existsSync(join(path, solFile())) &&
|
|
|
- existsSync(join(path, 'attic'));
|
|
|
+ return existsSync(join(path, solFile())) &&
|
|
|
+ existsSync(join(path, 'attic'));
|
|
|
}
|
|
|
|
|
|
-function isTestcase(path: string){
|
|
|
+function isTestcase(path: string) {
|
|
|
let ext = extname(path);
|
|
|
return ext === '.in' || ext === '.out' || ext === '.real';
|
|
|
}
|
|
@@ -47,18 +47,18 @@ export function currentTestcase() {
|
|
|
let answer: string | undefined = undefined;
|
|
|
|
|
|
// Try to find an open testcase
|
|
|
- if (vscode.window.activeTextEditor){
|
|
|
+ if (vscode.window.activeTextEditor) {
|
|
|
let path = vscode.window.activeTextEditor.document.uri.fsPath;
|
|
|
|
|
|
- if (isTestcase(path)){
|
|
|
+ if (isTestcase(path)) {
|
|
|
answer = removeExtension(basename(path));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Try to find the test case watching the current open workspace folder
|
|
|
- if (vscode.workspace.workspaceFolders !== undefined){
|
|
|
- vscode.workspace.workspaceFolders.forEach(function(fd){
|
|
|
- if (answer === undefined && isTestcase(fd.uri.fsPath)){
|
|
|
+ if (vscode.workspace.workspaceFolders !== undefined) {
|
|
|
+ vscode.workspace.workspaceFolders.forEach(function (fd) {
|
|
|
+ if (answer === undefined && isTestcase(fd.uri.fsPath)) {
|
|
|
answer = removeExtension(basename(fd.uri.fsPath));
|
|
|
}
|
|
|
});
|
|
@@ -70,7 +70,7 @@ export function currentTestcase() {
|
|
|
|
|
|
export function currentProblem() {
|
|
|
// Try to find the problem using current open file
|
|
|
- if (vscode.window.activeTextEditor){
|
|
|
+ if (vscode.window.activeTextEditor) {
|
|
|
let path = vscode.window.activeTextEditor.document.uri.fsPath;
|
|
|
|
|
|
const MAX_DEPTH = 3;
|
|
@@ -79,13 +79,13 @@ export function currentProblem() {
|
|
|
path = dirname(path);
|
|
|
}
|
|
|
|
|
|
- if (isProblemFolder(path)){
|
|
|
+ if (isProblemFolder(path)) {
|
|
|
return path;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Try to find the problem using the current open workspace folder
|
|
|
- if (vscode.workspace.workspaceFolders !== undefined){
|
|
|
+ if (vscode.workspace.workspaceFolders !== undefined) {
|
|
|
let path = vscode.workspace.workspaceFolders[0].uri.fsPath;
|
|
|
|
|
|
const MAX_DEPTH = 1;
|
|
@@ -94,7 +94,7 @@ export function currentProblem() {
|
|
|
path = dirname(path);
|
|
|
}
|
|
|
|
|
|
- if (isProblemFolder(path)){
|
|
|
+ if (isProblemFolder(path)) {
|
|
|
return path;
|
|
|
}
|
|
|
}
|
|
@@ -103,8 +103,8 @@ export function currentProblem() {
|
|
|
return undefined;
|
|
|
}
|
|
|
|
|
|
-function createFolder(path: string){
|
|
|
- if (!existsSync(path)){
|
|
|
+function createFolder(path: string) {
|
|
|
+ if (!existsSync(path)) {
|
|
|
createFolder(dirname(path));
|
|
|
mkdirSync(path);
|
|
|
}
|
|
@@ -115,7 +115,7 @@ function createFolder(path: string){
|
|
|
*
|
|
|
* @param testingPath Use for unit tests
|
|
|
*/
|
|
|
-function globalAtticPath(testingPath: string | undefined = undefined){
|
|
|
+function globalAtticPath(testingPath: string | undefined = undefined) {
|
|
|
let path: string | undefined = vscode.workspace.getConfiguration('acmx.configuration', null).get('solutionPath');
|
|
|
return join(path!, ATTIC);
|
|
|
}
|
|
@@ -123,7 +123,7 @@ function globalAtticPath(testingPath: string | undefined = undefined){
|
|
|
/**
|
|
|
* Create default environment that let acmX run properly
|
|
|
*/
|
|
|
-export function initAcmX(){
|
|
|
+export function initAcmX() {
|
|
|
// Create global attic.
|
|
|
let globalAttic = globalAtticPath();
|
|
|
createFolder(globalAttic);
|
|
@@ -134,21 +134,21 @@ export function initAcmX(){
|
|
|
|
|
|
// Copy testlib
|
|
|
let testlib = 'testlib.h';
|
|
|
- if (!existsSync(join(checkerFolder, testlib))){
|
|
|
+ if (!existsSync(join(checkerFolder, testlib))) {
|
|
|
copyFileSync(join(SRC, 'static', 'checkers', testlib),
|
|
|
- join(checkerFolder, testlib));
|
|
|
+ join(checkerFolder, testlib));
|
|
|
}
|
|
|
|
|
|
// Create wcmp checker
|
|
|
let checkerName = 'wcmp.cpp';
|
|
|
- if (!existsSync(join(checkerFolder, checkerName))){
|
|
|
+ if (!existsSync(join(checkerFolder, checkerName))) {
|
|
|
copyFileSync(join(SRC, 'static', 'checkers', checkerName),
|
|
|
- join(checkerFolder, checkerName));
|
|
|
+ join(checkerFolder, checkerName));
|
|
|
}
|
|
|
|
|
|
// Compile checker
|
|
|
let compiledName = 'wcmp.exe';
|
|
|
- if (!existsSync(join(checkerFolder, compiledName))){
|
|
|
+ if (!existsSync(join(checkerFolder, compiledName))) {
|
|
|
let checkerPath = join(checkerFolder, checkerName);
|
|
|
let compiledPath = join(checkerFolder, compiledName);
|
|
|
|
|
@@ -156,7 +156,7 @@ export function initAcmX(){
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-export function newArena(path: string){
|
|
|
+export function newArena(path: string) {
|
|
|
createFolder(path);
|
|
|
|
|
|
let testcases = join(path, TESTCASES);
|
|
@@ -167,41 +167,41 @@ export function newArena(path: string){
|
|
|
|
|
|
let templatePath: string | undefined = vscode.workspace.getConfiguration('acmx.configuration', null).get('templatePath');
|
|
|
|
|
|
- if (templatePath! === ""){
|
|
|
+ if (templatePath! === "") {
|
|
|
templatePath = join(SRC, 'static', 'template.cpp');
|
|
|
}
|
|
|
|
|
|
let solution = join(path, solFile());
|
|
|
|
|
|
- if (!existsSync(solution)){
|
|
|
+ if (!existsSync(solution)) {
|
|
|
copyFileSync(templatePath!, join(path, solFile()));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-export function removeExtension(name: string){
|
|
|
+export function removeExtension(name: string) {
|
|
|
let split = name.split('.');
|
|
|
- if (split.length === 0){
|
|
|
+ if (split.length === 0) {
|
|
|
return name;
|
|
|
}
|
|
|
- else{
|
|
|
+ else {
|
|
|
split.pop(); // drop extension
|
|
|
return split.join('.');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-export function testcasesName(path: string){
|
|
|
+export function testcasesName(path: string) {
|
|
|
return readdirSync(join(path, TESTCASES)).
|
|
|
- filter( function (tcpath) {
|
|
|
- return extname(tcpath) === '.in';
|
|
|
- }).
|
|
|
- map( function(tcpath) { return removeExtension(tcpath); });
|
|
|
+ filter(function (tcpath) {
|
|
|
+ return extname(tcpath) === '.in';
|
|
|
+ }).
|
|
|
+ map(function (tcpath) { return removeExtension(tcpath); });
|
|
|
}
|
|
|
|
|
|
export function upgradeArena(path: string) {
|
|
|
// Create brute force solution
|
|
|
let brute = join(path, 'brute.cpp');
|
|
|
|
|
|
- if (!existsSync(brute)){
|
|
|
+ if (!existsSync(brute)) {
|
|
|
// Create brute.cpp file
|
|
|
copyFileSync(join(SRC, 'static', 'template.cpp'), brute);
|
|
|
}
|
|
@@ -209,7 +209,7 @@ export function upgradeArena(path: string) {
|
|
|
// Create test case generator
|
|
|
let generator = join(path, 'gen.py');
|
|
|
|
|
|
- if (!existsSync(generator)){
|
|
|
+ if (!existsSync(generator)) {
|
|
|
// TODO: If generator already exist ask whether to overwrite or not.
|
|
|
gwen.create(path, generator);
|
|
|
}
|
|
@@ -217,14 +217,14 @@ export function upgradeArena(path: string) {
|
|
|
// Create checker for multiple answers.
|
|
|
let checker = join(path, ATTIC, 'checker.cpp');
|
|
|
|
|
|
- if (!existsSync(checker)){
|
|
|
+ if (!existsSync(checker)) {
|
|
|
let testlib_path = join(path, ATTIC, 'testlib.h');
|
|
|
copyFileSync(join(SRC, 'static', 'checkers', 'wcmp.cpp'), checker);
|
|
|
copyFileSync(join(SRC, 'static', 'checkers', 'testlib.h'), testlib_path);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function newProblem(path: string, problem: Problem){
|
|
|
+function newProblem(path: string, problem: Problem) {
|
|
|
newArena(path);
|
|
|
|
|
|
problem.inputs!.forEach((value, index) => {
|
|
@@ -238,7 +238,7 @@ function newProblem(path: string, problem: Problem){
|
|
|
});
|
|
|
}
|
|
|
|
|
|
-export async function newProblemFromId(path: string, site: SiteDescription, problemId: string){
|
|
|
+export async function newProblemFromId(path: string, site: SiteDescription, problemId: string) {
|
|
|
let problem = await site.problemParser(problemId);
|
|
|
|
|
|
path = join(path, problem.identifier!);
|
|
@@ -248,13 +248,13 @@ export async function newProblemFromId(path: string, site: SiteDescription, prob
|
|
|
return path;
|
|
|
}
|
|
|
|
|
|
-function newContest(path: string, contest: Contest){
|
|
|
+function newContest(path: string, contest: Contest) {
|
|
|
contest.problems!.forEach(problem => {
|
|
|
newProblem(join(path, problem.identifier!), problem);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
-export function newProblemFromCompanion(config: any){
|
|
|
+export function newProblemFromCompanion(config: any) {
|
|
|
console.log(config);
|
|
|
|
|
|
let _path: string | undefined = vscode.workspace.getConfiguration('acmx.configuration', null).get('solutionPath');
|
|
@@ -267,7 +267,7 @@ export function newProblemFromCompanion(config: any){
|
|
|
let inputs: string[] = [];
|
|
|
let outputs: string[] = [];
|
|
|
|
|
|
- config.tests.forEach(function(testcase: any){
|
|
|
+ config.tests.forEach(function (testcase: any) {
|
|
|
inputs.push(testcase.input);
|
|
|
outputs.push(testcase.output);
|
|
|
});
|
|
@@ -282,7 +282,7 @@ export function newProblemFromCompanion(config: any){
|
|
|
*
|
|
|
* @param contestId Id of the contest that user want to retrieve.
|
|
|
*/
|
|
|
-export async function newContestFromId(path: string, site: SiteDescription, contestId: string){
|
|
|
+export async function newContestFromId(path: string, site: SiteDescription, contestId: string) {
|
|
|
let contest = await site.contestParser(contestId);
|
|
|
let contestPath = join(path, site.name, contest.name);
|
|
|
|
|
@@ -317,7 +317,7 @@ function get_checker_path() {
|
|
|
* @param tcName
|
|
|
* @param timeout in miliseconds
|
|
|
*/
|
|
|
-export function timedRun(path: string, tcName: string, timeout: number){
|
|
|
+export function timedRun(path: string, tcName: string, timeout: number) {
|
|
|
let tcInput = join(path, TESTCASES, `${tcName}.in`);
|
|
|
let tcOutput = join(path, TESTCASES, `${tcName}.out`);
|
|
|
let tcCurrent = join(path, TESTCASES, `${tcName}.real`);
|
|
@@ -350,11 +350,11 @@ export function timedRun(path: string, tcName: string, timeout: number){
|
|
|
}
|
|
|
|
|
|
// Check if an error happened
|
|
|
- if (xresult.status !== 0){
|
|
|
- if (spanTime < timeout){
|
|
|
+ if (xresult.status !== 0) {
|
|
|
+ if (spanTime < timeout) {
|
|
|
return new TestcaseResult(Verdict.RTE);
|
|
|
}
|
|
|
- else{
|
|
|
+ else {
|
|
|
return new TestcaseResult(Verdict.TLE);
|
|
|
}
|
|
|
}
|
|
@@ -367,10 +367,10 @@ export function timedRun(path: string, tcName: string, timeout: number){
|
|
|
let checker_path = get_checker_path();
|
|
|
let checker_result = child_process.spawnSync(checker_path, [tcInput, tcCurrent, tcOutput]);
|
|
|
|
|
|
- if (checker_result.status !== 0){
|
|
|
+ if (checker_result.status !== 0) {
|
|
|
return new TestcaseResult(Verdict.WA);
|
|
|
}
|
|
|
- else{
|
|
|
+ else {
|
|
|
return new TestcaseResult(Verdict.OK, spanTime);
|
|
|
}
|
|
|
}
|
|
@@ -382,7 +382,7 @@ function escape_double_ticks(text: string) {
|
|
|
return text;
|
|
|
}
|
|
|
|
|
|
-export function compileCode(pathCode: string, pathOutput: string){
|
|
|
+export function compileCode(pathCode: string, pathOutput: string) {
|
|
|
let pathCodeMD5 = pathCode + '.md5';
|
|
|
let md5data = "";
|
|
|
|
|
@@ -398,7 +398,7 @@ export function compileCode(pathCode: string, pathOutput: string){
|
|
|
|
|
|
if (codeMD5 === md5data) {
|
|
|
return {
|
|
|
- 'status' : 0
|
|
|
+ 'status': 0
|
|
|
};
|
|
|
}
|
|
|
|
|
@@ -409,14 +409,14 @@ export function compileCode(pathCode: string, pathOutput: string){
|
|
|
let instruction: string | undefined = vscode.workspace.getConfiguration('acmx.execution', null).get('compile');
|
|
|
let splitedInstruction = instruction!.split(' ');
|
|
|
|
|
|
- for (let i = 0; i < splitedInstruction.length; ++i){
|
|
|
+ for (let i = 0; i < splitedInstruction.length; ++i) {
|
|
|
splitedInstruction[i] = splitedInstruction[i].replace('$PROGRAM', pathCode).replace('$OUTPUT', pathOutput);
|
|
|
}
|
|
|
|
|
|
let program = splitedInstruction[0];
|
|
|
let args = splitedInstruction.slice(1);
|
|
|
|
|
|
- let result = child_process.spawnSync(program, args);
|
|
|
+ let result = child_process.spawnSync(program, args);
|
|
|
|
|
|
if (result.status !== 0) {
|
|
|
// Write to the compile error terminal
|
|
@@ -429,24 +429,24 @@ export function compileCode(pathCode: string, pathOutput: string){
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-export function testSolution(path: string){
|
|
|
+export function testSolution(path: string) {
|
|
|
let sol = join(path, solFile());
|
|
|
let out = join(path, ATTIC, 'sol.exe');
|
|
|
|
|
|
- if (!existsSync(sol)){
|
|
|
+ if (!existsSync(sol)) {
|
|
|
throw new Error("Open a coding environment first.");
|
|
|
}
|
|
|
|
|
|
// Compile solution
|
|
|
let xresult = compileCode(sol, out);
|
|
|
|
|
|
- if (xresult.status !== 0){
|
|
|
+ if (xresult.status !== 0) {
|
|
|
throw new Error(`Compilation Error. ${sol}`);
|
|
|
}
|
|
|
|
|
|
let testcasesId = testcasesName(path);
|
|
|
|
|
|
- if (testcasesId.length === 0){
|
|
|
+ if (testcasesId.length === 0) {
|
|
|
return new SolutionResult(Verdict.NO_TESTCASES, undefined, undefined);
|
|
|
}
|
|
|
|
|
@@ -456,7 +456,7 @@ export function testSolution(path: string){
|
|
|
// Run current test case first (if it exists)
|
|
|
let startTc = currentTestcase();
|
|
|
|
|
|
- if (startTc !== undefined){
|
|
|
+ if (startTc !== undefined) {
|
|
|
testcasesId = testcasesId.reverse().filter(name => name !== startTc);
|
|
|
testcasesId.push(startTc);
|
|
|
testcasesId = testcasesId.reverse();
|
|
@@ -466,31 +466,31 @@ export function testSolution(path: string){
|
|
|
let fail: SolutionResult | undefined = undefined;
|
|
|
testcasesId.forEach(tcId => {
|
|
|
// Run while there none have failed already
|
|
|
- if (fail === undefined){
|
|
|
+ if (fail === undefined) {
|
|
|
let tcResult = timedRun(path, tcId, getTimeout());
|
|
|
- if (tcResult.status !== Verdict.OK){
|
|
|
+ if (tcResult.status !== Verdict.OK) {
|
|
|
fail = new SolutionResult(tcResult.status, tcId);
|
|
|
}
|
|
|
results.push(tcResult);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- if (fail === undefined){
|
|
|
+ if (fail === undefined) {
|
|
|
let maxTime = 0;
|
|
|
- for (let i = 0; i < results.length; i++){
|
|
|
- if (results[i].spanTime! > maxTime){
|
|
|
+ for (let i = 0; i < results.length; i++) {
|
|
|
+ if (results[i].spanTime! > maxTime) {
|
|
|
maxTime = results[i].spanTime!;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return new SolutionResult(Verdict.OK, undefined, maxTime);
|
|
|
}
|
|
|
- else{
|
|
|
+ else {
|
|
|
return fail;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function generateTestcase(path: string){
|
|
|
+function generateTestcase(path: string) {
|
|
|
let python: string | undefined = vscode.workspace.getConfiguration('acmx.execution', null).get('pythonPath');
|
|
|
let genResult = child_process.spawnSync(python!, [join(path, 'gen.py')]);
|
|
|
|
|
@@ -499,28 +499,28 @@ function generateTestcase(path: string){
|
|
|
closeSync(currentFd);
|
|
|
}
|
|
|
|
|
|
-export function stressSolution(path: string, times: number){
|
|
|
+export function stressSolution(path: string, times: number) {
|
|
|
let sol = join(path, solFile());
|
|
|
let out = join(path, ATTIC, 'sol');
|
|
|
let brute = join(path, 'brute.cpp');
|
|
|
|
|
|
- if (!existsSync(sol)){
|
|
|
+ if (!existsSync(sol)) {
|
|
|
throw new Error("Open a coding environment first.");
|
|
|
}
|
|
|
|
|
|
- if (!existsSync(brute)){
|
|
|
+ if (!existsSync(brute)) {
|
|
|
throw new Error("Upgrade environment first.");
|
|
|
}
|
|
|
|
|
|
let brout = join(path, ATTIC, 'brout.exe');
|
|
|
|
|
|
let solCompileResult = compileCode(sol, out);
|
|
|
- if (solCompileResult.status !== 0){
|
|
|
+ if (solCompileResult.status !== 0) {
|
|
|
throw new Error(`Compilation Error. ${sol}`);
|
|
|
}
|
|
|
|
|
|
let bruteCompileResult = compileCode(brute, brout);
|
|
|
- if (bruteCompileResult.status !== 0){
|
|
|
+ if (bruteCompileResult.status !== 0) {
|
|
|
throw new Error(`Compilation Error. ${brute}`);
|
|
|
}
|
|
|
|
|
@@ -551,7 +551,7 @@ export function stressSolution(path: string, times: number){
|
|
|
// Check sol report same result than brute
|
|
|
let result = timedRun(path, 'gen', getTimeout());
|
|
|
|
|
|
- if (result.status !== Verdict.OK){
|
|
|
+ if (result.status !== Verdict.OK) {
|
|
|
return new SolutionResult(result.status, 'gen');
|
|
|
}
|
|
|
|
|
@@ -559,8 +559,8 @@ export function stressSolution(path: string, times: number){
|
|
|
}
|
|
|
|
|
|
let maxTime = 0;
|
|
|
- for (let i = 0; i < results.length; i++){
|
|
|
- if (results[i].spanTime! > maxTime){
|
|
|
+ for (let i = 0; i < results.length; i++) {
|
|
|
+ if (results[i].spanTime! > maxTime) {
|
|
|
maxTime = results[i].spanTime!;
|
|
|
}
|
|
|
}
|
|
@@ -568,7 +568,7 @@ export function stressSolution(path: string, times: number){
|
|
|
return new SolutionResult(Verdict.OK, undefined, maxTime);
|
|
|
}
|
|
|
|
|
|
-export function verdictName(verdict: Verdict){
|
|
|
+export function verdictName(verdict: Verdict) {
|
|
|
switch (verdict) {
|
|
|
case Verdict.OK:
|
|
|
return "OK";
|