Add CLI written in Node

This commit is contained in:
Vrganj 2021-01-16 13:14:17 +01:00
parent d666e5c19d
commit d8b6379b9a
9 changed files with 321 additions and 192 deletions

View File

@ -1,48 +0,0 @@
const { writeFile } = require('fs/promises');
const { spawn } = require('child_process');
async function execute(res, language, body) {
const stamp = new Date().getTime();
const sourceFile = `/tmp/${stamp}.code`;
await writeFile(sourceFile, body.source);
const process = spawn(__dirname + '/../../lxc/execute', [
language.name,
sourceFile,
body.args?.join('\n') ?? '',
]);
const result = {
ran: true,
language: language.name,
stderr: '',
stdout: '',
output: '',
};
if (language.version)
result.version = language.version;
process.stderr.on('data', chunk => {
result.stderr += chunk;
result.output += chunk;
});
process.stdout.on('data', chunk => {
result.stdout += chunk;
result.output += chunk;
});
process.on('exit', () => {
result.stderr = result.stderr.trim().substring(0, 65535);
result.stdout = result.stdout.trim().substring(0, 65535);
result.output = result.output.trim().substring(0, 65535);
res.json(result);
});
}
module.exports = {
execute,
};

View File

@ -1,5 +1,5 @@
const express = require('express'); const express = require('express');
const { execute } = require('./execute'); const { execute } = require('../../shared/execute');
const { languages } = require('./languages'); const { languages } = require('./languages');
const { checkSchema, validationResult } = require('express-validator'); const { checkSchema, validationResult } = require('express-validator');
@ -41,7 +41,7 @@ app.post(
}, },
} }
}), }),
(req, res) => { async (req, res) => {
const errors = validationResult(req).array(); const errors = validationResult(req).array();
if (errors.length === 0) { if (errors.length === 0) {
@ -49,7 +49,16 @@ app.post(
language.aliases.includes(req.body.language.toLowerCase()) language.aliases.includes(req.body.language.toLowerCase())
); );
execute(res, language, req.body); const { stdout, stderr, output } = await execute(language, req.body.source, req.body.args);
res.status(200).json({
ran: true,
language: language.name,
version: language.version,
stdout,
stderr,
output,
});
} else { } else {
res.status(400).json({ res.status(400).json({
message: errors[0].msg, message: errors[0].msg,

View File

@ -1,119 +1,5 @@
const { spawn } = require('child_process'); const { spawn } = require('child_process');
const languages = require('../../shared/languages.json');
const languages = [
{
name: 'nasm',
aliases: ['asm', 'nasm'],
},
{
name: 'nasm64',
aliases: ['asm64', 'nasm64'],
},
{
name: 'awk',
aliases: ['awk'],
},
{
name: 'bash',
aliases: ['bash'],
},
{
name: 'brainfuck',
aliases: ['bf', 'brainfuck'],
},
{
name: 'c',
aliases: ['c'],
},
{
name: 'csharp',
aliases: ['c#', 'cs', 'csharp'],
},
{
name: 'cpp',
aliases: ['c++', 'cpp'],
},
{
name: 'deno',
aliases: ['deno', 'denojs', 'denots'],
},
{
name: 'ruby',
aliases: ['duby', 'rb', 'ruby'],
},
{
name: 'emacs',
aliases: ['el', 'elisp', 'emacs'],
},
{
name: 'elixir',
aliases: ['elixir'],
},
{
name: 'haskell',
aliases: ['haskell', 'hs'],
},
{
name: 'go',
aliases: ['go'],
},
{
name: 'java',
aliases: ['java'],
},
{
name: 'node',
aliases: ['javascript', 'js', 'node'],
},
{
name: 'jelly',
aliases: ['jelly'],
},
{
name: 'julia',
aliases: ['jl', 'julia'],
},
{
name: 'kotlin',
aliases: ['kotlin'],
},
{
name: 'lua',
aliases: ['lua'],
},
{
name: 'paradoc',
aliases: ['paradoc'],
},
{
name: 'perl',
aliases: ['perl'],
},
{
name: 'php',
aliases: ['php', 'php3', 'php4', 'php5'],
},
{
name: 'python3',
aliases: ['py', 'py3', 'python', 'python3'],
},
{
name: 'python2',
aliases: ['python2'],
},
{
name: 'rust',
aliases: ['rs', 'rust'],
},
{
name: 'swift',
aliases: ['swift'],
},
{
name: 'typescript',
aliases: ['ts', 'typescript'],
},
];
{ {
const process = spawn(__dirname + '/../../lxc/versions'); const process = spawn(__dirname + '/../../lxc/versions');

3
cli/execute Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
node src $*

12
cli/package.json Normal file
View File

@ -0,0 +1,12 @@
{
"name": "cli",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

30
cli/src/index.js Normal file
View File

@ -0,0 +1,30 @@
const { execute } = require('../../shared/execute');
const { readFileSync } = require('fs');
const languages = require('../../shared/languages.json');
const [languageName, sourceFile, ...args] = process.argv.slice(2);
(async () => {
if (!languageName) {
console.error('Provide a language name');
return;
}
if (!sourceFile) {
console.error('Provide a source file');
return;
}
const source = readFileSync(sourceFile);
const language = languages.find(language => language.name === languageName);
if (!language) {
console.error(`${languageName} is not supported by Piston`);
return;
}
const { output } = await execute(language, source, args);
console.log(output);
})();

View File

@ -2,54 +2,54 @@
cd tests cd tests
echo 'testing awk' echo 'testing awk'
../execute awk test.awk ../../cli/execute awk test.awk
echo 'testing c' echo 'testing c'
../execute c test.c ../../cli/execute c test.c
echo 'testing cpp' echo 'testing cpp'
../execute cpp test.cpp ../../cli/execute cpp test.cpp
echo 'testing cs' echo 'testing cs'
../execute cs test.cs ../../cli/execute cs test.cs
echo 'testing deno' echo 'testing deno'
../execute deno testdeno.ts ../../cli/execute deno testdeno.ts
echo 'testing elisp' echo 'testing elisp'
../execute elisp test.el ../../cli/execute elisp test.el
echo 'testing elixir' echo 'testing elixir'
../execute exs test.exs ../../cli/execute exs test.exs
echo 'testing go' echo 'testing go'
../execute go test.go ../../cli/execute go test.go
echo 'testing haskell' echo 'testing haskell'
../execute haskell test.hs ../../cli/execute haskell test.hs
echo 'testing java' echo 'testing java'
../execute java test.java ../../cli/execute java test.java
echo 'testing jelly' echo 'testing jelly'
../execute jelly test.jelly ../../cli/execute jelly test.jelly
echo 'testing jl' echo 'testing jl'
../execute jl test.jl ../../cli/execute jl test.jl
echo 'testing js' echo 'testing js'
../execute js test.js ../../cli/execute js test.js
echo 'testing kotlin' echo 'testing kotlin'
../execute kotlin test.kt ../../cli/execute kotlin test.kt
echo 'testing asm 32 bit' echo 'testing asm 32 bit'
../execute asm test.nasm ../../cli/execute asm test.nasm
echo 'testing asm 64 bit' echo 'testing asm 64 bit'
../execute asm64 test64.nasm ../../cli/execute asm64 test64.nasm
echo 'testing php' echo 'testing php'
../execute php test.php ../../cli/execute php test.php
echo 'testing perl' echo 'testing perl'
../execute perl test.pl ../../cli/execute perl test.pl
echo 'testing ruby' echo 'testing ruby'
../execute ruby test.rb ../../cli/execute ruby test.rb
echo 'testing rust' echo 'testing rust'
../execute rust test.rs ../../cli/execute rust test.rs
echo 'testing bash' echo 'testing bash'
../execute bash test.sh ../../cli/execute bash test.sh
echo 'testing swift' echo 'testing swift'
../execute swift test.swift ../../cli/execute swift test.swift
echo 'testing typescript' echo 'testing typescript'
../execute typescript test.ts ../../cli/execute typescript test.ts
echo 'testing python2' echo 'testing python2'
../execute python2 test2.py ../../cli/execute python2 test2.py
echo 'testing python3' echo 'testing python3'
../execute python3 test3.py ../../cli/execute python3 test3.py
echo 'testing paradoc' echo 'testing paradoc'
../execute python3 test_paradoc.py ../../cli/execute python3 test_paradoc.py

43
shared/execute.js Normal file
View File

@ -0,0 +1,43 @@
const { writeFile } = require('fs/promises');
const { spawn } = require('child_process');
function execute(language, source, args) {
return new Promise(async resolve => {
const stamp = new Date().getTime();
const sourceFile = `/tmp/${stamp}.code`;
await writeFile(sourceFile, source);
const process = spawn(__dirname + '/../lxc/execute', [
language.name,
sourceFile,
args?.join('\n') ?? '',
]);
let stdout = '';
let stderr = '';
let output = '';
process.stderr.on('data', chunk => {
stderr += chunk;
output += chunk;
});
process.stdout.on('data', chunk => {
stdout += chunk;
output += chunk;
});
process.on('exit', () => {
stderr = stderr.trim().substring(0, 65535);
stdout = stdout.trim().substring(0, 65535);
output = output.trim().substring(0, 65535);
resolve({ stdout, stderr, output });
});
});
}
module.exports = {
execute,
};

194
shared/languages.json Normal file
View File

@ -0,0 +1,194 @@
[
{
"name": "nasm",
"aliases": [
"asm",
"nasm"
]
},
{
"name": "nasm64",
"aliases": [
"asm64",
"nasm64"
]
},
{
"name": "awk",
"aliases": [
"awk"
]
},
{
"name": "bash",
"aliases": [
"bash"
]
},
{
"name": "brainfuck",
"aliases": [
"bf",
"brainfuck"
]
},
{
"name": "c",
"aliases": [
"c"
]
},
{
"name": "csharp",
"aliases": [
"c#",
"cs",
"csharp"
]
},
{
"name": "cpp",
"aliases": [
"c++",
"cpp"
]
},
{
"name": "deno",
"aliases": [
"deno",
"denojs",
"denots"
]
},
{
"name": "ruby",
"aliases": [
"duby",
"rb",
"ruby"
]
},
{
"name": "emacs",
"aliases": [
"el",
"elisp",
"emacs"
]
},
{
"name": "elixir",
"aliases": [
"elixir"
]
},
{
"name": "haskell",
"aliases": [
"haskell",
"hs"
]
},
{
"name": "go",
"aliases": [
"go"
]
},
{
"name": "java",
"aliases": [
"java"
]
},
{
"name": "node",
"aliases": [
"javascript",
"js",
"node"
]
},
{
"name": "jelly",
"aliases": [
"jelly"
]
},
{
"name": "julia",
"aliases": [
"jl",
"julia"
]
},
{
"name": "kotlin",
"aliases": [
"kotlin"
]
},
{
"name": "lua",
"aliases": [
"lua"
]
},
{
"name": "paradoc",
"aliases": [
"paradoc"
]
},
{
"name": "perl",
"aliases": [
"perl"
]
},
{
"name": "php",
"aliases": [
"php",
"php3",
"php4",
"php5"
]
},
{
"name": "python3",
"aliases": [
"py",
"py3",
"python",
"python3"
]
},
{
"name": "python2",
"aliases": [
"python2"
]
},
{
"name": "rust",
"aliases": [
"rs",
"rust"
]
},
{
"name": "swift",
"aliases": [
"swift"
]
},
{
"name": "typescript",
"aliases": [
"ts",
"typescript"
]
}
]