[extension] Submit problems

This commit is contained in:
orosmatthew 2023-05-08 14:37:52 -04:00
parent 8ace5a0061
commit 4bb261a8a5
5 changed files with 108 additions and 31 deletions

View File

@ -27,7 +27,7 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
switch (data.type) { switch (data.type) {
case 'onTestAndSubmit': { case 'onTestAndSubmit': {
if (this._context) { if (this._context) {
BWPanel.createOrShow(this._context?.extensionUri, this._context); BWPanel.createOrShow(this._context);
} }
break; break;
} }

View File

@ -98,7 +98,7 @@ export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand('bwcontest.helloWorld', () => { vscode.commands.registerCommand('bwcontest.helloWorld', () => {
BWPanel.createOrShow(context.extensionUri, context); BWPanel.createOrShow(context);
}) })
); );

View File

@ -3,6 +3,7 @@ import { getNonce } from './getNonce';
import { runJava } from './run/java'; import { runJava } from './run/java';
import { extensionSettings } from './extension'; import { extensionSettings } from './extension';
import { join } from 'path'; import { join } from 'path';
import { submitProblem } from './submit';
export class BWPanel { export class BWPanel {
/** /**
@ -17,7 +18,7 @@ export class BWPanel {
private _disposables: vscode.Disposable[] = []; private _disposables: vscode.Disposable[] = [];
private static _context?: vscode.ExtensionContext; private static _context?: vscode.ExtensionContext;
public static createOrShow(extensionUri: vscode.Uri, context: vscode.ExtensionContext) { public static createOrShow(context: vscode.ExtensionContext) {
this._context = context; this._context = context;
const column = vscode.window.activeTextEditor const column = vscode.window.activeTextEditor
? vscode.window.activeTextEditor.viewColumn ? vscode.window.activeTextEditor.viewColumn
@ -26,7 +27,6 @@ export class BWPanel {
// If we already have a panel, show it. // If we already have a panel, show it.
if (BWPanel.currentPanel) { if (BWPanel.currentPanel) {
BWPanel.currentPanel._panel.reveal(column); BWPanel.currentPanel._panel.reveal(column);
BWPanel.currentPanel._update();
return; return;
} }
@ -43,13 +43,13 @@ export class BWPanel {
// And restrict the webview to only loading content from our extension's `media` directory. // And restrict the webview to only loading content from our extension's `media` directory.
localResourceRoots: [ localResourceRoots: [
vscode.Uri.joinPath(extensionUri, 'media'), vscode.Uri.joinPath(context.extensionUri, 'media'),
vscode.Uri.joinPath(extensionUri, 'out/compiled') vscode.Uri.joinPath(context.extensionUri, 'out/compiled')
] ]
} }
); );
BWPanel.currentPanel = new BWPanel(panel, extensionUri); BWPanel.currentPanel = new BWPanel(panel, context.extensionUri);
} }
public static kill() { public static kill() {
@ -64,34 +64,13 @@ export class BWPanel {
private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) { private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
this._panel = panel; this._panel = panel;
this._extensionUri = extensionUri; this._extensionUri = extensionUri;
// Set the webview's initial html content
this._update(); this._update();
// Listen for when the panel is disposed
// This happens when the user closes the panel or when the panel is closed programatically
this._panel.onDidDispose(() => this.dispose(), null, this._disposables); this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
// // Handle messages from the webview
// this._panel.webview.onDidReceiveMessage(
// (message) => {
// switch (message.command) {
// case "alert":
// vscode.window.showErrorMessage(message.text);
// return;
// }
// },
// null,
// this._disposables
// );
} }
public dispose() { public dispose() {
BWPanel.currentPanel = undefined; BWPanel.currentPanel = undefined;
// Clean up our resources
this._panel.dispose(); this._panel.dispose();
while (this._disposables.length) { while (this._disposables.length) {
const x = this._disposables.pop(); const x = this._disposables.pop();
if (x) { if (x) {
@ -106,12 +85,39 @@ export class BWPanel {
this._panel.webview.html = this._getHtmlForWebview(webview); this._panel.webview.html = this._getHtmlForWebview(webview);
webview.onDidReceiveMessage(async (data) => { webview.onDidReceiveMessage(async (data) => {
switch (data.type) { switch (data.type) {
case 'onSubmit': {
if (!data.value) {
return;
}
const ans = await vscode.window.showInformationMessage(
`Are you sure you want to submit ${data.value.problemName}?`,
'Yes',
'No'
);
if (ans !== 'Yes') {
break;
}
try {
await submitProblem(
data.value.sessionToken,
data.value.contestId,
data.value.teamId,
data.value.problemId
);
} catch (reason) {
vscode.window.showErrorMessage('Unable to submit');
console.error(reason);
break;
}
vscode.window.showInformationMessage('Submitted!');
break;
}
case 'onRun': { case 'onRun': {
if (!data.value) { if (!data.value) {
return; return;
} }
const repoDir = extensionSettings().repoClonePath; const repoDir = extensionSettings().repoClonePath;
const output = await runJava( runJava(
join( join(
repoDir, repoDir,
'BWContest', 'BWContest',
@ -129,8 +135,9 @@ export class BWPanel {
), ),
data.value.problemPascalName, data.value.problemPascalName,
data.value.input data.value.input
); ).then((output) => {
this._panel.webview.postMessage({ type: 'onOutput', value: output }); this._panel.webview.postMessage({ type: 'onOutput', value: output });
});
break; break;
} }
case 'onStartup': { case 'onStartup': {

View File

@ -0,0 +1,63 @@
import { extensionSettings } from './extension';
import { exec } from 'child_process';
import util = require('node:util');
import axios from 'axios';
const execPromise = util.promisify(exec);
export async function submitProblem(
sessionToken: string,
contestId: number,
teamId: number,
problemId: number
) {
const repoClonePath = extensionSettings().repoClonePath;
console.log(repoClonePath);
const clonedRepoPath = `${repoClonePath}/BWContest/${contestId.toString()}/${teamId.toString()}`;
let output: { stdout: string; stderr: string };
output = await execPromise(`git add .`, {
cwd: clonedRepoPath
});
if (output.stderr) {
console.error(output.stderr);
}
output = await execPromise(`git commit -m "Submit problem ${problemId}"`, {
cwd: clonedRepoPath
});
if (output.stderr) {
console.error(output.stderr);
}
output = await execPromise(`git push`, {
cwd: clonedRepoPath
});
if (output.stderr) {
console.error(output.stderr);
}
output = await execPromise(`git rev-parse HEAD`, {
cwd: clonedRepoPath
});
if (output.stderr) {
console.error(output.stderr);
}
const commitHash = output.stdout.toString().replace('\n', '');
const res = await axios.post(`http://localhost:5173/api/team/${sessionToken}/submit`, {
commitHash: commitHash,
problemId: problemId
});
if (res.status !== 200) {
throw Error('Failed to post submission');
}
if (!res.data.success) {
throw Error('Submission post unsuccessful');
}
}

View File

@ -55,6 +55,12 @@
} }
} }
function onSubmit() {
if (teamId && contestId && sessionToken) {
postMessage({type: 'onSubmit', value: {sessionToken: sessionToken, contestId: contestId, teamId: teamId, problemId: activeProblem.id, problemName: activeProblem.pascalName}})
}
}
async function fetchProblemData() { async function fetchProblemData() {
if (sessionToken) { if (sessionToken) {
const res = await fetch(`http://localhost:5173/api/contest/${sessionToken}`); const res = await fetch(`http://localhost:5173/api/contest/${sessionToken}`);
@ -122,6 +128,7 @@
<button style="margin-top:5px" on:click={onRun} type="button">Run</button> <button style="margin-top:5px" on:click={onRun} type="button">Run</button>
</div> </div>
</div> </div>
<button on:click={onSubmit} type="button">Submit</button>
{/if} {/if}
<style> <style>