grading
Version:
Grading of student submissions, in particular programming tests.
104 lines (86 loc) • 4.93 kB
text/typescript
import { OptionValues } from 'commander';
import * as fs from 'fs';
import path from 'path';
import { hrtime } from 'process';
import { absPath, createDir, ensureFileExists, ensureFolderExists, execShell, fileExists, findDirContainingFile, folderExists, isEmptyDir, readDir, rmDir, rmFile, timestamp, unzip } from '../fsUtil';
import { getPatchFileName, gitAddAndCommit, gitApplyPatch, gitCreateAndCheckoutBranch, hasLocalGitRepository } from '../gitCommands';
import { error, generateFileName, isSubmissionSelected, log, parseSubmitter, retrieveSelectedFilter, retrieveZipFile, substituteVariables, timeDiff, verb, verbosity, warn } from './cliUtil';
import { Submitter } from './submitter';
import { parsePrepareSubmissionCmd } from './cmdCheck';
export async function cmdPrepareAsPrevious(zipFile: string, options: OptionValues) {
verbosity(options);
log("Prepare submissions to be used as previous submissions in plagiary tool");
try {
zipFile = await retrieveZipFile(zipFile, options);
await ensureFileExists(zipFile, "Check zip file.");
const dry = options.dry;
const prevProjectsDir = options.prevProjectsDir;
if (!prevProjectsDir) {
program.error(`prevProjectsDir must be provided.`);
}
const prepareSubmissionCmd = parsePrepareSubmissionCmd(options.prepareSubmissionCmd);
if (!prepareSubmissionCmd) {
program.error(`prepareSubmissionCmd must be provided.`);
}
const projectFile = options.projectFile;
const ignoredDirs = options.ignoredDirs;
const submissionsDir = substituteVariables(prevProjectsDir, { zip: zipFile });
verb(`Extract submissions to ${submissionsDir}`);
if (await folderExists(submissionsDir, 'submissionsDir')) {
verb(`Remove submissions folder ${submissionsDir} (clean).`);
await rmDir(submissionsDir);
}
await unzip(zipFile, submissionsDir); // we always unzip the big file
const submissionDirs = await readDir(submissionsDir, 'dir', false, 'Check submissions folder.');
if (submissionDirs.length == 0) {
program.error(`No submissions found in ${submissionsDir}`)
}
let name = "", subId = ""; // define here for catch block
for (let counter = 0; counter < submissionDirs.length; counter++) {
try {
const subDir = submissionDirs[counter];
({ name, submissionId: subId } = parseSubmitter(subDir));
const absSubDir = path.join(submissionsDir, subDir);
log(SEP);
log(`\nProcessing submission ${counter + 1} of ${submissionDirs.length}: ${subId} ${name}\n`, options.colorSection);
// find the submitted zip file:
let submittedFiles = await readDir(absSubDir, 'file');
if (submittedFiles.length != 1) {
log(`Warning: ${name} submitted ${submittedFiles.length} files`);
if (submittedFiles.length > 1) {
submittedFiles = submittedFiles.filter(f => f.endsWith('.zip'));
if (submittedFiles.length != 1) {
log(`Warning: ${name} submitted ${submittedFiles.length} zip-files, take first one.`);
}
submittedFiles = [submittedFiles[0]]
}
if (submittedFiles.length != 1) {
log(`Warning: Skipping submission of ${name}.`);
continue;
}
}
// unzip the submitted zip file
const wsDir = path.join(submissionsDir, subDir, 'ws' + (name ? "_" + name.replace(/ /g, '_') : ""));
if (await folderExists(wsDir)) {
log(`Remove workspace folder ${wsDir}.`)
await rmDir(wsDir);
}
await createDir(wsDir);
const subZip = path.join(absSubDir, submittedFiles[0])
await unzip(subZip, wsDir);
// find project folder, usually the one folder contained in the submission
const projectDir = await findDirContainingFile(wsDir, projectFile, ignoredDirs);
// usually git reset --hard
await execShell(prepareSubmissionCmd.cmd, prepareSubmissionCmd.args,
{ ...options, colored: options.colored || false, colorStandard: options.colorPre }, { indent: false, prefix: 'pre: ', cwd: projectDir });
} catch (err) {
const msg = `${name}: ${err instanceof Error ? err.message : err}`
error(`${msg}`)
error(`Continue with next submission.`)
}
}
} catch (err) {
error(`${SEP}`);
program.error(String(err));
}
}