diff --git a/api/.eslintrc.json b/api/.eslintrc.json deleted file mode 100644 index 579bcfc..0000000 --- a/api/.eslintrc.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "env": { - "commonjs": true, - "es2021": true, - "node": true - }, - "plugins": [ - "snakecasejs" - ], - "extends": "eslint:recommended", - "parser": "babel-eslint", - "parserOptions": { - "ecmaVersion": 12 - }, - "settings": - { - "snakecasejs/filter": ["ClassDeclaration", "NewExpression"], - "snakecasejs/whitelist": [] - }, - "rules": { - "indent": [ - "error", - 4 - ], - "linebreak-style": [ - "error", - "unix" - ], - "quotes": [ - "error", - "single" - ], - "semi": [ - "error", - "always" - ], - "no-unused-vars": ["error", { "argsIgnorePattern": "^_"}], - "snakecasejs/snakecasejs": "warn" - } -} diff --git a/api/Dockerfile b/api/Dockerfile index b3eb8a8..fd261bd 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -1,12 +1,12 @@ FROM node:15.8.0-buster-slim RUN dpkg-reconfigure -p critical dash -RUN apt-get update && apt-get install -y libxml2 gnupg tar coreutils util-linux \ - && rm -rf /var/lib/apt/lists/* - RUN for i in $(seq 1001 1500); do \ groupadd -g $i runner$i && \ useradd -M runner$i -g $i -u $i ; \ done +RUN apt-get update && \ + apt-get install -y libxml2 gnupg tar coreutils util-linux libc6-dev binutils && \ + rm -rf /var/lib/apt/lists/* ENV NODE_ENV=production WORKDIR /piston_api @@ -15,4 +15,4 @@ RUN yarn COPY ./src ./src CMD [ "node", "src", "-m", "-c", "/piston/config.yaml"] -EXPOSE 6969/tcp \ No newline at end of file +EXPOSE 6969/tcp diff --git a/api/package.json b/api/package.json index ba86daa..75cb08c 100644 --- a/api/package.json +++ b/api/package.json @@ -1,25 +1,20 @@ { - "name": "piston-api", - "version": "3.0.0", - "description": "API for piston - a high performance code execution engine", - "main": "src/index.js", - "dependencies": { - "body-parser": "^1.19.0", - "express": "^4.17.1", - "express-validator": "^6.10.0", - "is-docker": "^2.1.1", - "js-yaml": "^4.0.0", - "logplease": "^1.2.15", - "nocamel": "HexF/nocamel#patch-1", - "node-fetch": "^2.6.1", - "semver": "^7.3.4", - "uuid": "^8.3.2", - "yargs": "^16.2.0" - }, - "devDependencies": { - "babel-eslint": "^10.1.0", - "eslint": "^7.20.0", - "eslint-plugin-snakecasejs": "^2.2.0" - }, - "license": "MIT" + "name": "piston-api", + "version": "3.0.0", + "description": "API for piston - a high performance code execution engine", + "main": "src/index.js", + "dependencies": { + "body-parser": "^1.19.0", + "express": "^4.17.1", + "express-validator": "^6.10.0", + "is-docker": "^2.1.1", + "js-yaml": "^4.0.0", + "logplease": "^1.2.15", + "nocamel": "HexF/nocamel#patch-1", + "node-fetch": "^2.6.1", + "semver": "^7.3.4", + "uuid": "^8.3.2", + "yargs": "^16.2.0" + }, + "license": "MIT" } diff --git a/api/src/config.js b/api/src/config.js index 2d841b0..2ad3ffc 100644 --- a/api/src/config.js +++ b/api/src/config.js @@ -1,25 +1,25 @@ const fss = require('fs'); const yargs = require('yargs'); -const hide_bin = require('yargs/helpers').hideBin; //eslint-disable-line snakecasejs/snakecasejs +const hide_bin = require('yargs/helpers').hideBin; const Logger = require('logplease'); const logger = Logger.create('config'); const yaml = require('js-yaml'); const header = `# -# ____ _ _ -# | _ \\(_)___| |_ ___ _ __ -# | |_) | / __| __/ _ \\| '_ \\ +# ____ _ _ +# | _ \\(_)___| |_ ___ _ __ +# | |_) | / __| __/ _ \\| '_ \\ # | __/| \\__ \\ || (_) | | | | # |_| |_|___/\\__\\___/|_| |_| # -# A High performance code execution engine +# A High performance code execution engine # github.com/engineer-man/piston # `; const argv = yargs(hide_bin(process.argv)) .usage('Usage: $0 -c [config]') - .demandOption('c') //eslint-disable-line snakecasejs/snakecasejs + .demandOption('c') .option('config', { alias: 'c', describe: 'config file to load from', @@ -29,18 +29,18 @@ const argv = yargs(hide_bin(process.argv)) alias: 'm', type: 'boolean', describe: 'create config file and populate defaults if it does not already exist' - }).argv; - + }) + .argv; const options = [ { key: 'log_level', desc: 'Level of data to log', default: 'INFO', - /* eslint-disable snakecasejs/snakecasejs */ options: Object.values(Logger.LogLevels), - validators: [x=>Object.values(Logger.LogLevels).includes(x) || `Log level ${x} does not exist`] - /* eslint-enable snakecasejs/snakecasejs */ + validators: [ + x => Object.values(Logger.LogLevels).includes(x) || `Log level ${x} does not exist` + ] }, { key: 'bind_address', @@ -110,68 +110,71 @@ const options = [ } ]; -function make_default_config(){ +const make_default_config = () => { let content = header.split('\n'); options.forEach(option => { content = content.concat(option.desc.split('\n').map(x=>`# ${x}`)); - if(option.options) + if (option.options) { content.push('# Options: ' + option.options.join(', ')); + } content.push(`${option.key}: ${option.default}`); - + content.push(''); // New line between }); return content.join('\n'); -} +}; logger.info(`Loading Configuration from ${argv.config}`); -if(argv['make-config']) +if (argv['make-config']) { logger.debug('Make configuration flag is set'); +} -if(!!argv['make-config'] && !fss.exists_sync(argv.config)){ +if (!!argv['make-config'] && !fss.exists_sync(argv.config)) { logger.info('Writing default configuration...'); try { - fss.write_file_sync(argv.config, make_default_config()); - } catch (err) { - logger.error('Error writing default configuration:', err.message); + fss.write_file_sync(argv.config, make_default_config()); + } catch (e) { + logger.error('Error writing default configuration:', e.message); process.exit(1); } } -var config = {}; +let config = {}; logger.debug('Reading config file'); -try{ +try { const cfg_content = fss.read_file_sync(argv.config); config = yaml.load(cfg_content); -}catch(err){ +} catch(err) { logger.error('Error reading configuration file:', err.message); process.exit(1); } logger.debug('Validating config entries'); -var errored=false; +let errored = false; -options.forEach(option => { +options.for_each(option => { logger.debug('Checking option', option.key); - var cfg_val = config[option.key]; + let cfg_val = config[option.key]; - if(cfg_val == undefined){ + if (cfg_val === undefined) { errored = true; logger.error(`Config key ${option.key} does not exist on currently loaded configuration`); return; } - option.validators.forEach(validator => { - var response = validator(cfg_val); - if(response !== true){ + option.validators.for_each(validator => { + let response = validator(cfg_val); + + if (!response) { errored = true; logger.error(`Config option ${option.key} failed validation:`, response); return; @@ -179,9 +182,10 @@ options.forEach(option => { }); }); -if(errored) process.exit(1); +if (errored) { + process.exit(1); +} logger.info('Configuration successfully loaded'); module.exports = config; - diff --git a/api/src/executor/job.js b/api/src/executor/job.js index 046cd53..ba739c4 100644 --- a/api/src/executor/job.js +++ b/api/src/executor/job.js @@ -1,5 +1,5 @@ const logger = require('logplease').create('executor/job'); -const { v4: uuidv4 } = require('uuid'); +const {v4: uuidv4} = require('uuid'); const cp = require('child_process'); const path = require('path'); const config = require('../config'); @@ -12,11 +12,12 @@ const job_states = { EXECUTED: Symbol('Executed and ready for cleanup') }; -var uid=0; -var gid=0; +let uid = 0; +let gid = 0; class Job { - constructor({runtime, files, args, stdin, timeouts, main}){ + + constructor({ runtime, files, args, stdin, timeouts, main, alias }) { this.uuid = uuidv4(); this.runtime = runtime; this.files = files; @@ -24,9 +25,13 @@ class Job { this.stdin = stdin; this.timeouts = timeouts; this.main = main; + this.alias = alias; - if(!this.files.map(f=>f.name).includes(this.main)) + let file_list = this.files.map(f => f.name); + + if (!file_list.includes(this.main)) { throw new Error(`Main file "${this.main}" will not be written to disk`); + } this.uid = config.runner_uid_min + uid; this.gid = config.runner_gid_min + gid; @@ -41,34 +46,30 @@ class Job { this.dir = path.join(config.data_directory, globals.data_directories.jobs, this.uuid); } - async prime(){ + async prime() { logger.info(`Priming job uuid=${this.uuid}`); logger.debug('Writing files to job cache'); - await fs.mkdir(this.dir, {mode:0o700}); - - const files = this.files.map(({name: file_name, content}) => { - return fs.write_file(path.join(this.dir, file_name), content); - }); - - await Promise.all(files); - logger.debug(`Transfering ownership uid=${this.uid} gid=${this.gid}`); - await fs.chown(this.dir, this.uid, this.gid); - - const chowns = this.files.map(({name:file_name}) => { - return fs.chown(path.join(this.dir, file_name), this.uid, this.gid); - }); - await Promise.all(chowns); + await fs.mkdir(this.dir, { mode:0o700 }); + await fs.chown(this.dir, this.uid, this.gid); + + for (const file of this.files) { + let file_path = path.join(this.dir, file.name); + + await fs.write_file(file_path, file.content); + await fs.chown(file_path, this.uid, this.gid); + } this.state = job_states.PRIMED; + logger.debug('Primed job'); } - async safe_call(file, args, timeout){ - return await new Promise((resolve, reject) => { + async safe_call(file, args, timeout) { + return new Promise((resolve, reject) => { const unshare = config.enable_unshare ? ['unshare','-n','-r'] : []; const prlimit = [ @@ -87,70 +88,91 @@ class Job { var stderr = ''; const proc = cp.spawn(proc_call[0], proc_call.splice(1) ,{ - env: this.runtime.env_vars, + env: { + ...this.runtime.env_vars, + PISTON_ALIAS: this.alias + }, stdio: 'pipe', cwd: this.dir, uid: this.uid, gid: this.gid, detached: true //give this process its own process group }); - + proc.stdin.write(this.stdin); proc.stdin.end(); - - const kill_timeout = setTimeout(_ => proc.kill('SIGKILL'), timeout); + const kill_timeout = set_timeout(_ => proc.kill('SIGKILL'), timeout); - proc.stderr.on('data', d=>{if(stderr.length>config.output_max_size) proc.kill('SIGKILL'); else stderr += d;}); - proc.stdout.on('data', d=>{if(stdout.length>config.output_max_size) proc.kill('SIGKILL'); else stdout += d;}); + proc.stderr.on('data', data => { + if (stderr.length > config.output_max_size) { + proc.kill('SIGKILL'); + } else { + stderr += data; + } + }); + + proc.stdout.on('data', data => { + if (stdout.length > config.output_max_size) { + proc.kill('SIGKILL'); + } else { + stdout += data; + } + }); + + const exit_cleanup = () => { + clear_timeout(kill_timeout); - function exit_cleanup(){ - clearTimeout(kill_timeout); proc.stderr.destroy(); proc.stdout.destroy(); - try{ + + try { process.kill(-proc.pid, 'SIGKILL'); - }catch{ + } catch { // Process will be dead already, so nothing to kill. } - } + }; proc.on('exit', (code, signal)=>{ exit_cleanup(); - - resolve({stdout, stderr, code, signal}); + + resolve({ stdout, stderr, code, signal }); }); proc.on('error', (err) => { exit_cleanup(); - reject({error: err, stdout, stderr}); + reject({ error: err, stdout, stderr }); }); }); } - async execute(){ - if(this.state != job_states.PRIMED) + async execute() { + if (this.state !== job_states.PRIMED) { throw new Error('Job must be in primed state, current state: ' + this.state.toString()); + } logger.info(`Executing job uuid=${this.uuid} uid=${this.uid} gid=${this.gid} runtime=${this.runtime.toString()}`); logger.debug('Compiling'); - var compile = undefined; - if(this.runtime.compiled) + let compile; + + if (this.runtime.compiled) { compile = await this.safe_call( path.join(this.runtime.pkgdir, 'compile'), - this.files.map(x=>x.name), - this.timeouts.compile); - + this.files.map(x => x.name), + this.timeouts.compile + ); + } logger.debug('Running'); const run = await this.safe_call( path.join(this.runtime.pkgdir, 'run'), [this.main, ...this.args], - this.timeouts.run); + this.timeouts.run + ); this.state = job_states.EXECUTED; @@ -158,13 +180,15 @@ class Job { compile, run }; - } - async cleanup(){ + async cleanup() { logger.info(`Cleaning up job uuid=${this.uuid}`); - await fs.rm(this.dir, {recursive: true, force: true}); + await fs.rm(this.dir, { recursive: true, force: true }); } + } -module.exports = {Job}; \ No newline at end of file +module.exports = { + Job +}; diff --git a/api/src/executor/routes.js b/api/src/executor/routes.js index fe09d63..3cb4fe2 100644 --- a/api/src/executor/routes.js +++ b/api/src/executor/routes.js @@ -6,41 +6,49 @@ const { Job } = require('./job'); const { body } = require('express-validator'); module.exports = { + run_job_validators: [ body('language') - .isString(), // eslint-disable-line snakecasejs/snakecasejs + .isString(), body('version') - .isString(), // eslint-disable-line snakecasejs/snakecasejs + .isString(), // isSemVer requires it to be a version, not a selector body('files') - .isArray(), // eslint-disable-line snakecasejs/snakecasejs + .isArray(), body('files.*.name') - .isString() // eslint-disable-line snakecasejs/snakecasejs + .isString() .bail() .not() .contains('/'), body('files.*.content') - .isString(), // eslint-disable-line snakecasejs/snakecasejs + .isString(), body('compile_timeout') - .isNumeric(), // eslint-disable-line snakecasejs/snakecasejs + .isNumeric(), body('run_timeout') - .isNumeric(), // eslint-disable-line snakecasejs/snakecasejs + .isNumeric(), body('stdin') - .isString(), // eslint-disable-line snakecasejs/snakecasejs + .isString(), body('args') .isArray(), body('args.*') - .isString() // eslint-disable-line snakecasejs/snakecasejs + .isString() ], - async run_job(req, res){ - // POST /jobs - + // POST /jobs + async run_job(req, res) { const runtime = get_latest_runtime_matching_language_version(req.body.language, req.body.version); - if(runtime == undefined) return res.json_error(`${req.body.language}-${req.body.version} runtime is unknown`, 400); + + if (runtime === undefined) { + return res + .status(400) + .send({ + message: `${req.body.language}-${req.body.version} runtime is unknown` + }); + } const job = new Job({ runtime, + alias: req.body.language, files: req.body.files, args: req.body.args, stdin: req.body.stdin, @@ -54,8 +62,12 @@ module.exports = { await job.prime(); const result = await job.execute(); - res.json_success(result); await job.cleanup(); + + return res + .status(200) + .send(result); } -}; \ No newline at end of file + +}; diff --git a/api/src/globals.js b/api/src/globals.js index c9bd427..300558e 100644 --- a/api/src/globals.js +++ b/api/src/globals.js @@ -5,7 +5,7 @@ const platform = `${is_docker() ? 'docker' : 'baremetal'}-${ fss.read_file_sync('/etc/os-release') .toString() .split('\n') - .find(x=>x.startsWith('ID')) + .find(x => x.startsWith('ID')) .replace('ID=','') }`; @@ -17,4 +17,4 @@ module.exports = { version: require('../package.json').version, platform, pkg_installed_file: '.ppman-installed' //Used as indication for if a package was installed -}; \ No newline at end of file +}; diff --git a/api/src/index.js b/api/src/index.js index 1325243..63d1393 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -9,117 +9,103 @@ const fs = require('fs/promises'); const fss = require('fs'); const body_parser = require('body-parser'); const runtime = require('./runtime'); -const {validationResult} = require('express-validator'); //eslint-disable-line snakecasejs/snakecasejs +const { validationResult } = require('express-validator'); const logger = Logger.create('index'); const app = express(); (async () => { logger.info('Setting loglevel to',config.log_level); - Logger.setLogLevel(config.log_level); //eslint-disable-line snakecasejs/snakecasejs - + Logger.setLogLevel(config.log_level); logger.debug('Ensuring data directories exist'); - Object.values(globals.data_directories).forEach(dir => { - var data_path = path.join(config.data_directory, dir); + + Object.values(globals.data_directories).for_each(dir => { + let data_path = path.join(config.data_directory, dir); + logger.debug(`Ensuring ${data_path} exists`); - if(!fss.exists_sync(data_path)){ + + if (!fss.exists_sync(data_path)) { logger.info(`${data_path} does not exist.. Creating..`); - try{ + + try { fss.mkdir_sync(data_path); - }catch(err){ - logger.error(`Failed to create ${data_path}: `, err.message); + } catch(e) { + logger.error(`Failed to create ${data_path}: `, e.message); } } - }); logger.info('Loading packages'); const pkgdir = path.join(config.data_directory,globals.data_directories.packages); const pkglist = await fs.readdir(pkgdir); + const languages = await Promise.all( pkglist.map(lang=> fs.readdir(path.join(pkgdir,lang)) .then(x=>x.map(y=>path.join(pkgdir, lang, y))) )); - const installed_languages = languages.flat() - .filter(pkg=>fss.exists_sync(path.join(pkg, globals.pkg_installed_file))); + + const installed_languages = languages + .flat() + .filter(pkg => fss.exists_sync(path.join(pkg, globals.pkg_installed_file))); installed_languages.forEach(pkg => new runtime.Runtime(pkg)); logger.info('Starting API Server'); - logger.debug('Constructing Express App'); - - logger.debug('Registering custom message wrappers'); - - express.response.json_error = function(message, code) { - this.status(code); - return this.json({success: false, message, code}); - }; - - express.response.json_success = function(obj) { - return this.json({success: true, data: obj}); - }; - logger.debug('Registering middleware'); - app.use(body_parser.urlencoded({extended: true})); + app.use(body_parser.urlencoded({ extended: true })); app.use(body_parser.json()); + const validate = (req, res, next) => { + const errors = validationResult(req); + + if (!errors.isEmpty()) { + return res + .status(422) + .send({ + message: errors.array() + }); + } - function validate(req, res, next) { - const errors = validationResult(req); //eslint-disable-line snakecasejs/snakecasejs - if (!errors.isEmpty()) //eslint-disable-line snakecasejs/snakecasejs - return res.json_error(errors.array(), 422); next(); - } + }; logger.debug('Registering Routes'); const ppman_routes = require('./ppman/routes'); const executor_routes = require('./executor/routes'); - - app.get('/packages', - ppman_routes.package_list - ); - - app.post('/packages/:language/:version', - ppman_routes.package_install - ); - - app.delete('/packages/:language/:version', - ppman_routes.package_uninstall - ); - + app.get('/packages', ppman_routes.package_list); + app.post('/packages/:language/:version', ppman_routes.package_install); + app.delete('/packages/:language/:version', ppman_routes.package_uninstall); app.post('/jobs', executor_routes.run_job_validators, validate, - executor_routes.run_job); + executor_routes.run_job + ); + app.get('/runtimes', (req, res) => { + const runtimes = runtime + .map(rt => { + return { + language: rt.language, + version: rt.version.raw, + author: rt.author, + aliases: rt.aliases + }; + }); - function list_runtimes(_, res){ - const runtimes = runtime.map(rt => ( - { - language: rt.language, - version: rt.version.raw, - author: rt.author, - aliases: rt.aliases - } - )); - - return res.json_success({ - runtimes - }); - } - - app.get('/runtimes', list_runtimes); - - logger.debug('Calling app.listen'); - const [address,port] = config.bind_address.split(':'); - - app.listen(port, address, ()=>{ - logger.info('API server started on', config.bind_address); + return res + .status(200) + .send(runtimes); }); -})(); \ No newline at end of file + logger.debug('Calling app.listen'); + const [ address, port ] = config.bind_address.split(':'); + + app.listen(port, address, () => { + logger.info('API server started on', config.bind_address); + }); +})(); diff --git a/api/src/ppman/package.js b/api/src/ppman/package.js index 66a29b7..0f4c78d 100644 --- a/api/src/ppman/package.js +++ b/api/src/ppman/package.js @@ -11,66 +11,73 @@ const crypto = require('crypto'); const runtime = require('../runtime'); class Package { - constructor({language, version, download, checksum}){ + + constructor({ language, version, download, checksum }){ this.language = language; this.version = semver.parse(version); this.checksum = checksum; this.download = download; } - get installed(){ + get installed() { return fss.exists_sync(path.join(this.install_path, globals.pkg_installed_file)); } - get download_url(){ - return this.download; - } - - get install_path(){ - return path.join(config.data_directory, + get install_path() { + return path.join( + config.data_directory, globals.data_directories.packages, this.language, - this.version.raw); + this.version.raw + ); } - async install(){ - if(this.installed) throw new Error('Already installed'); + async install() { + if (this.installed) { + throw new Error('Already installed'); + } + logger.info(`Installing ${this.language}-${this.version.raw}`); - if(fss.exists_sync(this.install_path)){ + if (fss.exists_sync(this.install_path)) { logger.warn(`${this.language}-${this.version.raw} has residual files. Removing them.`); - await fs.rm(this.install_path, {recursive: true, force: true}); + await fs.rm(this.install_path, { recursive: true, force: true }); } logger.debug(`Making directory ${this.install_path}`); await fs.mkdir(this.install_path, {recursive: true}); + logger.debug(`Downloading package from ${this.download} in to ${this.install_path}`); + const pkgpath = path.join(this.install_path, 'pkg.tar.gz'); + const download = await fetch(this.download); - logger.debug(`Downloading package from ${this.download_url} in to ${this.install_path}`); - const pkgpath = path.join(this.install_path, "pkg.tar.gz"); - const download = await fetch(this.download_url); const file_stream = fss.create_write_stream(pkgpath); await new Promise((resolve, reject) => { - download.body.pipe(file_stream) - download.body.on("error", reject) - file_stream.on("finish", resolve) + download.body.pipe(file_stream); + download.body.on('error', reject); + + file_stream.on('finish', resolve); }); logger.debug('Validating checksums'); - logger.debug(`Assert sha256(pkg.tar.gz) == ${this.checksum}`) + logger.debug(`Assert sha256(pkg.tar.gz) == ${this.checksum}`); const cs = crypto.create_hash("sha256") .update(fss.readFileSync(pkgpath)) .digest('hex'); - if(cs != this.checksum) throw new Error(`Checksum miss-match want: ${val} got: ${cs}`); + + if (cs !== this.checksum) { + throw new Error(`Checksum miss-match want: ${val} got: ${cs}`); + } logger.debug(`Extracting package files from archive ${pkgpath} in to ${this.install_path}`); - await new Promise((resolve, reject)=>{ + await new Promise((resolve, reject) => { const proc = cp.exec(`bash -c 'cd "${this.install_path}" && tar xzf ${pkgpath}'`); - proc.once('exit', (code,_)=>{ - if(code == 0) resolve(); - else reject(new Error('Failed to extract package')); + + proc.once('exit', (code, _) => { + code === 0 ? resolve() : reject(); }); + proc.stdout.pipe(process.stdout); proc.stderr.pipe(process.stderr); @@ -80,28 +87,35 @@ class Package { logger.debug('Registering runtime'); new runtime.Runtime(this.install_path); - logger.debug('Caching environment'); const get_env_command = `cd ${this.install_path}; source environment; env`; - const envout = await new Promise((resolve, reject)=>{ - var stdout = ''; - const proc = cp.spawn('env',['-i','bash','-c',`${get_env_command}`], { - stdio: ['ignore', 'pipe', 'pipe']}); - proc.once('exit', (code,_)=>{ - if(code == 0) resolve(stdout); - else reject(new Error('Failed to cache environment')); + const envout = await new Promise((resolve, reject) => { + let stdout = ''; + + const proc = cp + .spawn( + 'env', + ['-i','bash','-c',`${get_env_command}`], + { + stdio: ['ignore', 'pipe', 'pipe'] + } + ); + + proc.once('exit', (code, _) => { + code === 0 ? resolve(stdout) : reject(); }); - proc.stdout.on('data', (data)=>{ + proc.stdout.on('data', data => { stdout += data; }); proc.once('error', reject); }); - const filtered_env = envout.split('\n') - .filter(l=>!['PWD','OLDPWD','_', 'SHLVL'].includes(l.split('=',2)[0])) + const filtered_env = envout + .split('\n') + .filter(l => !['PWD','OLDPWD','_', 'SHLVL'].includes(l.split('=',2)[0])) .join('\n'); await fs.write_file(path.join(this.install_path, '.env'), filtered_env); @@ -116,7 +130,9 @@ class Package { version: this.version.raw }; } + } - -module.exports = {Package}; \ No newline at end of file +module.exports = { + Package +}; diff --git a/api/src/ppman/routes.js b/api/src/ppman/routes.js index c4f0b8a..fc8bbaf 100644 --- a/api/src/ppman/routes.js +++ b/api/src/ppman/routes.js @@ -4,66 +4,98 @@ const fetch = require('node-fetch'); const config = require('../config'); const { Package } = require('./package'); +const get_package_list = async () => { + const repo_content = await fetch(config.repo_url).then(x => x.text()); -async function get_package_list(){ - const repo_content = await fetch(config.repo_url).then(x=>x.text()); - - const entries = repo_content.split('\n').filter(x=>x.length > 0); + const entries = repo_content + .split('\n') + .filter(x => x.length > 0); return entries.map(line => { - const [language, version, checksum, download] = line.split(',',4); - return new Package({language, version, checksum, download}); - }) -} + const [ language, version, checksum, download ] = line.split(',', 4); + return new Package({ + language, + version, + checksum, + download + }); + }); +}; -async function get_package(lang, version){ +const get_package = async (lang, version) => { const packages = await get_package_list(); - const candidates = packages.filter( - pkg => pkg.language == lang && semver.satisfies(pkg.version, version) - ); - return candidates.sort((a,b)=>semver.rcompare(a.version,b.version))[0] || null; -} -module.exports = { - - async package_list(req, res){ - // GET /packages - logger.debug('Request to list packages'); - - const packages = await get_package_list(); - - res.json_success({ - packages: packages.map(pkg=>({ - language: pkg.language, - language_version: pkg.version.raw, - installed: pkg.installed - })) + const candidates = packages + .filter(pkg => { + return pkg.language == lang && semver.satisfies(pkg.version, version) }); - }, - async package_install(req,res){ - // POST /packages/:language/:version + candidates.sort((a, b) => semver.rcompare(a.version, b.version)); + return candidates[0] || null; +}; + +module.exports = { + + // GET /packages + async package_list(req, res) { + logger.debug('Request to list packages'); + + let packages = await get_package_list(); + + packages = packages + .map(pkg => { + return { + language: pkg.language, + language_version: pkg.version.raw, + installed: pkg.installed + }; + }); + + return res + .status(200) + .send(packages); + }, + + // POST /packages/:language/:version + async package_install(req, res) { logger.debug('Request to install package'); const pkg = await get_package(req.params.language, req.params.version); - if(pkg == null) return res.json_error(`Requested package ${req.params.language}-${req.params.version} does not exist`, 404); - try{ - const response = await pkg.install(); - return res.json_success(response); - }catch(err){ - logger.error(`Error while installing package ${pkg.language}-${pkg.version}:`, err.message); - res.json_error(err.message,500); + if (pkg == null) { + return res + .status(404) + .send({ + message: `Requested package ${req.params.language}-${req.params.version} does not exist` + }); } - + try { + const response = await pkg.install(); + + return res + .status(200) + .send(response); + } catch(e) { + logger.error(`Error while installing package ${pkg.language}-${pkg.version}:`, e.message); + + return res + .status(500) + .send({ + message: e.message + }); + } }, - async package_uninstall(req,res){ - // DELETE /packages/:language/:version - //res.json(req.body); //TODO - res.json_error('not implemented', 500); + // DELETE /packages/:language/:version + async package_uninstall(req, res) { + return res + .status(500) + .send({ + message: 'Not implemented' + }); } -}; \ No newline at end of file + +}; diff --git a/api/src/runtime.js b/api/src/runtime.js index 5a01891..2603835 100644 --- a/api/src/runtime.js +++ b/api/src/runtime.js @@ -8,53 +8,60 @@ const path = require('path'); const runtimes = []; class Runtime { - #env_vars - #compiled + constructor(package_dir){ - const {language, version, author, build_platform, aliases} = JSON.parse( + let info = JSON.parse( fss.read_file_sync(path.join(package_dir, 'pkg-info.json')) ); + const { language, version, author, build_platform, aliases } = info; + this.pkgdir = package_dir; this.language = language; this.version = semver.parse(version); this.author = author; this.aliases = aliases; - if(build_platform != globals.platform){ - logger.warn(`Package ${language}-${version} was built for platform ${build_platform}, but our platform is ${globals.platform}`); + if (build_platform !== globals.platform) { + logger.warn( + `Package ${language}-${version} was built for platform ${build_platform}, ` + + `but our platform is ${globals.platform}` + ); } - + logger.debug(`Package ${language}-${version} was loaded`); + runtimes.push(this); } - get env_file_path(){ - return path.join(this.pkgdir, 'environment'); + get compiled() { + if (this._compiled === undefined) { + this._compiled = fss.exists_sync(path.join(this.pkgdir, 'compile')); + } + + return this._compiled; } - get compiled(){ - if(this.#compiled === undefined) this.#compiled = fss.exists_sync(path.join(this.pkgdir, 'compile')); - return this.#compiled; - } - - get env_vars(){ - if(!this.#env_vars){ + get env_vars() { + if (!this._env_vars) { const env_file = path.join(this.pkgdir, '.env'); const env_content = fss.read_file_sync(env_file).toString(); - this.#env_vars = {}; + + this._env_vars = {}; + env_content .trim() .split('\n') .map(line => line.split('=',2)) .forEach(([key,val]) => { - this.#env_vars[key.trim()] = val.trim(); + this._env_vars[key.trim()] = val.trim(); }); } - return this.#env_vars; + + return this._env_vars; } - toString(){ + toString() { return `${this.language}-${this.version.raw}`; } } @@ -68,4 +75,3 @@ module.exports.get_latest_runtime_matching_language_version = function(lang, ver return module.exports.get_runtimes_matching_language_version(lang, ver) .sort((a,b) => semver.rcompare(a.version, b.version))[0]; }; - diff --git a/cli/commands/ppman_commands/list.js b/cli/commands/ppman_commands/list.js index 5d6584e..b4ad16c 100644 --- a/cli/commands/ppman_commands/list.js +++ b/cli/commands/ppman_commands/list.js @@ -18,7 +18,7 @@ exports.handler = async function({axios}){ const packages = await axios.get('/packages'); - const pkg_msg = packages.data.data.packages + const pkg_msg = packages.data .map(msg_format.color) .join('\n'); diff --git a/docker-compose.yaml b/docker-compose.yaml index 8b5f62f..0a321a4 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -11,11 +11,11 @@ services: - ./data/piston:/piston - ./repo:/repo tmpfs: - - /piston/jobs + - /piston/jobs:exec piston_fs_repo: #Temporary solution until CI works build: repo - command: ['deno-1.7.5'] # Only build deno + command: ['typescript-4.2.3'] # Only build typescript volumes: - - ./repo:/repo - - ./packages:/packages \ No newline at end of file + - ./repo:/piston/repo + - ./packages:/piston/packages \ No newline at end of file diff --git a/packages/.gitignore b/packages/.gitignore index 92bd97e..d98ab0b 100644 --- a/packages/.gitignore +++ b/packages/.gitignore @@ -1,8 +1,8 @@ -*/* +*/*/* *.pkg.tar.gz -!*/metadata.json -!*/build.sh -!*/environment -!*/run -!*/compile -!*/test.* \ No newline at end of file +!*/*/metadata.json +!*/*/build.sh +!*/*/environment +!*/*/run +!*/*/compile +!*/*/test.* \ No newline at end of file diff --git a/packages/CONTRIBUTING.MD b/packages/CONTRIBUTING.MD index 0c5381a..499cff8 100644 --- a/packages/CONTRIBUTING.MD +++ b/packages/CONTRIBUTING.MD @@ -8,11 +8,11 @@ In the example of NodeJS, we would call this `node`, after the main binary. ## Creating new languages -See [deno-1.7.5/](deno-1.7.5/) or any other directory for examples. +See [deno/1.7.5/](deno/1.7.5/) or any other directory for examples. 1. Create a new branch on your fork of engineer-man/piston -2. Create a directory named `[language]-[version]`. See Naming Languages for how to determine the name for your language +2. Create directories named `[language]/[version]`. See Naming Languages for how to determine the name for your language 3. Create a file named `build.sh`, adding a shebang for bash `#!/bin/bash` on the first line. In this file put any steps to compile the specified langauge. diff --git a/packages/Makefile b/packages/Makefile index 80360f5..c0cf6fe 100644 --- a/packages/Makefile +++ b/packages/Makefile @@ -1,4 +1,4 @@ -PACKAGES=$(shell find * -maxdepth 0 -type d) +PACKAGES=$(subst /,-,$(shell find * -maxdepth 1 -mindepth 1 -type d)) BUILD_PLATFORM=$(or ${PLATFORM},baremetal-$(shell grep -oP "^ID=\K.+" /etc/os-release)) help: @@ -9,14 +9,16 @@ help: build build-all: $(addsuffix .pkg.tar.gz, ${PACKAGES}) -%.pkg.tar.gz: %/ %/pkg-info.json - cd $< && chmod +x ./build.sh && ./build.sh - rm -f $@ - tar czf $@ $* --transform='s|$*||' + +define PKG_RULE +$(1).pkg.tar.gz: $(subst -,/,$(1))/ $(subst -,/,$(1))/pkg-info.json + cd $$< && chmod +x ./build.sh && ./build.sh + rm -f $$@ + tar czf $$@ $$< --transform='s|$$<||' +endef + +$(foreach pkg,$(PACKAGES),$(eval $(call PKG_RULE,$(pkg)))) %/pkg-info.json: %/metadata.json jq '.build_platform="${BUILD_PLATFORM}"' $< > $@ - - - diff --git a/packages/bash/5.1.0/build.sh b/packages/bash/5.1.0/build.sh new file mode 100755 index 0000000..67ba7b8 --- /dev/null +++ b/packages/bash/5.1.0/build.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# Put instructions to build your package in here +PREFIX=$(realpath $(dirname $0)) + +mkdir -p build + +cd build + +curl "https://ftp.gnu.org/gnu/bash/bash-5.1.tar.gz" -o bash.tar.gz + +tar xzf bash.tar.gz --strip-components=1 + +# === autoconf based === +./configure --prefix "$PREFIX" + +make -j$(nproc) +make install -j$(nproc) +cd ../ +rm -rf build diff --git a/packages/bash/5.1.0/environment b/packages/bash/5.1.0/environment new file mode 100644 index 0000000..780b668 --- /dev/null +++ b/packages/bash/5.1.0/environment @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put 'export' statements here for environment variables +export PATH=$PWD/bin:$PATH diff --git a/packages/bash/5.1.0/metadata.json b/packages/bash/5.1.0/metadata.json new file mode 100644 index 0000000..acd4c6b --- /dev/null +++ b/packages/bash/5.1.0/metadata.json @@ -0,0 +1,6 @@ +{ + "language": "bash", + "version": "5.1.0", + "aliases": ["sh"], + "author": "Thomas Hobson " +} diff --git a/packages/bash/5.1.0/run b/packages/bash/5.1.0/run new file mode 100644 index 0000000..be4ec50 --- /dev/null +++ b/packages/bash/5.1.0/run @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put instructions to run the runtime +bash $* diff --git a/packages/bash/5.1.0/test.bash b/packages/bash/5.1.0/test.bash new file mode 100644 index 0000000..727518f --- /dev/null +++ b/packages/bash/5.1.0/test.bash @@ -0,0 +1 @@ +echo "OK" \ No newline at end of file diff --git a/packages/dart/2.12.1/build.sh b/packages/dart/2.12.1/build.sh new file mode 100755 index 0000000..e01d7ce --- /dev/null +++ b/packages/dart/2.12.1/build.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +curl -L "https://storage.googleapis.com/dart-archive/channels/stable/release/2.12.1/sdk/dartsdk-linux-x64-release.zip" -o dart.zip + +unzip dart.zip +rm dart.zip + +cp -r dart-sdk/* . +rm -rf dart-sdk + +chmod -R +rx bin \ No newline at end of file diff --git a/packages/dart/2.12.1/environment b/packages/dart/2.12.1/environment new file mode 100644 index 0000000..780b668 --- /dev/null +++ b/packages/dart/2.12.1/environment @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put 'export' statements here for environment variables +export PATH=$PWD/bin:$PATH diff --git a/packages/dart/2.12.1/metadata.json b/packages/dart/2.12.1/metadata.json new file mode 100644 index 0000000..388121e --- /dev/null +++ b/packages/dart/2.12.1/metadata.json @@ -0,0 +1,6 @@ +{ + "language": "dart", + "version": "2.12.1", + "aliases": [], + "author": "Thomas Hobson " +} diff --git a/packages/dart/2.12.1/run b/packages/dart/2.12.1/run new file mode 100644 index 0000000..dfdbd40 --- /dev/null +++ b/packages/dart/2.12.1/run @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put instructions to run the runtime +dart run $* diff --git a/packages/dart/2.12.1/test.dart b/packages/dart/2.12.1/test.dart new file mode 100644 index 0000000..27e87b2 --- /dev/null +++ b/packages/dart/2.12.1/test.dart @@ -0,0 +1,3 @@ +void main() { + print('OK'); +} \ No newline at end of file diff --git a/packages/deno-1.7.5/build.sh b/packages/deno/1.7.5/build.sh similarity index 100% rename from packages/deno-1.7.5/build.sh rename to packages/deno/1.7.5/build.sh diff --git a/packages/deno-1.7.5/environment b/packages/deno/1.7.5/environment similarity index 100% rename from packages/deno-1.7.5/environment rename to packages/deno/1.7.5/environment diff --git a/packages/deno-1.7.5/metadata.json b/packages/deno/1.7.5/metadata.json similarity index 100% rename from packages/deno-1.7.5/metadata.json rename to packages/deno/1.7.5/metadata.json diff --git a/packages/deno-1.7.5/run b/packages/deno/1.7.5/run similarity index 100% rename from packages/deno-1.7.5/run rename to packages/deno/1.7.5/run diff --git a/packages/deno-1.7.5/test.ts b/packages/deno/1.7.5/test.ts similarity index 100% rename from packages/deno-1.7.5/test.ts rename to packages/deno/1.7.5/test.ts diff --git a/packages/gawk/5.1.0/build.sh b/packages/gawk/5.1.0/build.sh new file mode 100644 index 0000000..25a5566 --- /dev/null +++ b/packages/gawk/5.1.0/build.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# Put instructions to build your package in here +PREFIX=$(realpath $(dirname $0)) + +mkdir -p build + +cd build + +curl "https://ftp.gnu.org/gnu/gawk/gawk-5.1.0.tar.gz" -o gawk.tar.gz + +tar xzf gawk.tar.gz --strip-components=1 + +# === autoconf based === +./configure --prefix "$PREFIX" + +make -j$(nproc) +make install -j$(nproc) +cd ../ +rm -rf build diff --git a/packages/gawk/5.1.0/compile b/packages/gawk/5.1.0/compile new file mode 100644 index 0000000..e37a74c --- /dev/null +++ b/packages/gawk/5.1.0/compile @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +# Put instructions to compile source code, remove this file if the language does not require this stage diff --git a/packages/gawk/5.1.0/environment b/packages/gawk/5.1.0/environment new file mode 100644 index 0000000..780b668 --- /dev/null +++ b/packages/gawk/5.1.0/environment @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put 'export' statements here for environment variables +export PATH=$PWD/bin:$PATH diff --git a/packages/gawk/5.1.0/metadata.json b/packages/gawk/5.1.0/metadata.json new file mode 100644 index 0000000..a4f3ae2 --- /dev/null +++ b/packages/gawk/5.1.0/metadata.json @@ -0,0 +1,6 @@ +{ + "language": "gawk", + "version": "5.1.0", + "aliases": ["awk"], + "author": "Thomas Hobson " +} diff --git a/packages/gawk/5.1.0/run b/packages/gawk/5.1.0/run new file mode 100644 index 0000000..567b400 --- /dev/null +++ b/packages/gawk/5.1.0/run @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put instructions to run the runtime +gawk-5.1.0 -f $* diff --git a/packages/gawk/5.1.0/test.awk b/packages/gawk/5.1.0/test.awk new file mode 100644 index 0000000..25e1bd3 --- /dev/null +++ b/packages/gawk/5.1.0/test.awk @@ -0,0 +1 @@ +{print "OK"} \ No newline at end of file diff --git a/packages/gcc/10.2.0/build.sh b/packages/gcc/10.2.0/build.sh new file mode 100755 index 0000000..942e4ac --- /dev/null +++ b/packages/gcc/10.2.0/build.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Put instructions to build your package in here +[[ -d "bin" ]] && exit 0 +PREFIX=$(realpath $(dirname $0)) + +mkdir -p build obj + +cd build + +curl "https://ftp.gnu.org/gnu/gcc/gcc-10.2.0/gcc-10.2.0.tar.gz" -o gcc.tar.gz + +tar xzf gcc.tar.gz --strip-components=1 + +./contrib/download_prerequisites + +cd ../obj + +# === autoconf based === +../build/configure --prefix "$PREFIX" --enable-languages=c,c++,d --disable-multilib --disable-bootstrap + +make -j$(nproc) +make install -j$(nproc) +cd ../ +rm -rf build obj diff --git a/packages/gcc/10.2.0/compile b/packages/gcc/10.2.0/compile new file mode 100644 index 0000000..e83346d --- /dev/null +++ b/packages/gcc/10.2.0/compile @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Put instructions to compile source code, remove this file if the language does not require this stage + + +case "${PISTON_ALIAS}" in + gcc | c) + gcc -std=c11 $* -lm + ;; + g++ | c++ | cpp) + g++ -std=c++17 $* + ;; + gccgo | go) + gccgo $* + ;; + gdc | d) + gdc $* + ;; + *) + echo "How did you get here? (${PISTON_ALIAS})" + exit 1 + ;; +esac + +chmod +x a.out \ No newline at end of file diff --git a/packages/gcc/10.2.0/environment b/packages/gcc/10.2.0/environment new file mode 100644 index 0000000..780b668 --- /dev/null +++ b/packages/gcc/10.2.0/environment @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put 'export' statements here for environment variables +export PATH=$PWD/bin:$PATH diff --git a/packages/gcc/10.2.0/metadata.json b/packages/gcc/10.2.0/metadata.json new file mode 100644 index 0000000..8f3e9b5 --- /dev/null +++ b/packages/gcc/10.2.0/metadata.json @@ -0,0 +1,6 @@ +{ + "language": "gcc", + "version": "10.2.0", + "aliases": ["c","g++","c++","cpp","gdc","d"], + "author": "Thomas Hobson " +} diff --git a/packages/gcc/10.2.0/run b/packages/gcc/10.2.0/run new file mode 100644 index 0000000..63e3443 --- /dev/null +++ b/packages/gcc/10.2.0/run @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# Put instructions to run the runtime + +shift # Discard main filename +./a.out $* diff --git a/packages/gcc/10.2.0/test.c b/packages/gcc/10.2.0/test.c new file mode 100644 index 0000000..fafae75 --- /dev/null +++ b/packages/gcc/10.2.0/test.c @@ -0,0 +1,6 @@ +#include + +int main(void) { + printf("OK"); + return 0; +} \ No newline at end of file diff --git a/packages/gcc/10.2.0/test.cpp b/packages/gcc/10.2.0/test.cpp new file mode 100644 index 0000000..9d0499e --- /dev/null +++ b/packages/gcc/10.2.0/test.cpp @@ -0,0 +1,6 @@ +#include + +int main(void) { + printf("OK"); + return 0; +} \ No newline at end of file diff --git a/packages/gcc/10.2.0/test.d b/packages/gcc/10.2.0/test.d new file mode 100644 index 0000000..e74851d --- /dev/null +++ b/packages/gcc/10.2.0/test.d @@ -0,0 +1,5 @@ +import std.stdio; + +void main() { + writeln("OK"); +} \ No newline at end of file diff --git a/packages/init b/packages/init new file mode 100755 index 0000000..2bf65cc --- /dev/null +++ b/packages/init @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +if [[ $# -lt 3 ]]; then + echo "Usage: $0 [name] [version] [source]" + echo "" + echo "Initializes an empty package" + exit 1 +fi + +NAME=$1 +VERSION=$2 +AUTHOR="$(git config user.name) <$(git config user.email)>" +SOURCE=$3 + +DIR=$NAME/$VERSION + +mkdir -p $DIR + +build_instructions(){ + echo 'PREFIX=$(realpath $(dirname $0))' + echo + echo 'mkdir -p build' + echo + echo 'cd build' + echo + echo "curl \"$SOURCE\" -o $NAME.tar.gz" + echo + echo "tar xzf $NAME.tar.gz --strip-components=1" + echo + + echo "# === autoconf based ===" + echo './configure --prefix "$PREFIX"' + echo + echo 'make -j$(nproc)' + echo 'make install -j$(nproc)' + + echo 'cd ../' + echo 'rm -rf build' + +} + +cd $DIR + +for name in build.sh environment run compile; do + echo "#!/usr/bin/env bash" > "$name" + echo "" >> "$name" +done + +echo "# Put instructions to build your package in here" >> build.sh +echo "" +build_instructions >> build.sh + +echo "# Put 'export' statements here for environment variables" >> environment +echo "export PATH=\$PWD/bin:\$PATH" >> environment + +echo "# Put instructions to run the runtime" >> run +echo "$NAME-$VERSION \$*" >> run + +echo "# Put instructions to compile source code, remove this file if the language does not require this stage" >> compile + +jq '.language = "'$NAME'" | .version = "'$VERSION'" | .aliases = [] | .author = "'"$AUTHOR"'"' <<< "{}" > metadata.json + +cd - > /dev/null + +echo $DIR \ No newline at end of file diff --git a/packages/java/15.0.2/build.sh b/packages/java/15.0.2/build.sh new file mode 100755 index 0000000..3d56ee0 --- /dev/null +++ b/packages/java/15.0.2/build.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# Put instructions to build your package in here + +curl "https://download.java.net/java/GA/jdk15.0.2/0d1cfde4252546c6931946de8db48ee2/7/GPL/openjdk-15.0.2_linux-x64_bin.tar.gz" -o java.tar.gz + +tar xzf java.tar.gz --strip-components=1 +rm java.tar.gz diff --git a/packages/java/15.0.2/environment b/packages/java/15.0.2/environment new file mode 100644 index 0000000..780b668 --- /dev/null +++ b/packages/java/15.0.2/environment @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put 'export' statements here for environment variables +export PATH=$PWD/bin:$PATH diff --git a/packages/java/15.0.2/metadata.json b/packages/java/15.0.2/metadata.json new file mode 100644 index 0000000..2f24706 --- /dev/null +++ b/packages/java/15.0.2/metadata.json @@ -0,0 +1,6 @@ +{ + "language": "java", + "version": "15.0.2", + "aliases": [], + "author": "Thomas Hobson " +} diff --git a/packages/java/15.0.2/run b/packages/java/15.0.2/run new file mode 100644 index 0000000..2215edd --- /dev/null +++ b/packages/java/15.0.2/run @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put instructions to run the runtime +java $* diff --git a/packages/java/15.0.2/test.java b/packages/java/15.0.2/test.java new file mode 100644 index 0000000..2dc0eaa --- /dev/null +++ b/packages/java/15.0.2/test.java @@ -0,0 +1,5 @@ +public class HelloWorld { + public static void main(String[] args) { + System.out.println("OK"); + } +} \ No newline at end of file diff --git a/packages/jelly/0.1.31/build.sh b/packages/jelly/0.1.31/build.sh new file mode 100755 index 0000000..8aec708 --- /dev/null +++ b/packages/jelly/0.1.31/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +source ../../python/3.9.1/build.sh + +mkdir -p build + +git clone -q https://github.com/DennisMitchell/jellylanguage.git build/jelly +cd build/jelly +../../bin/python3.9 setup.py install --optimize=1 + +cd ../../ +rm -rf build \ No newline at end of file diff --git a/packages/node-15.10.0/environment b/packages/jelly/0.1.31/environment similarity index 100% rename from packages/node-15.10.0/environment rename to packages/jelly/0.1.31/environment diff --git a/packages/jelly/0.1.31/metadata.json b/packages/jelly/0.1.31/metadata.json new file mode 100644 index 0000000..bf63814 --- /dev/null +++ b/packages/jelly/0.1.31/metadata.json @@ -0,0 +1,6 @@ +{ + "language": "jelly", + "version": "0.1.31", + "author": "Thomas Hobson ", + "aliases": [] +} \ No newline at end of file diff --git a/packages/jelly/0.1.31/run b/packages/jelly/0.1.31/run new file mode 100644 index 0000000..7f4dd38 --- /dev/null +++ b/packages/jelly/0.1.31/run @@ -0,0 +1 @@ +jelly fu $* \ No newline at end of file diff --git a/packages/jelly/0.1.31/test.jelly b/packages/jelly/0.1.31/test.jelly new file mode 100644 index 0000000..b32bbcd --- /dev/null +++ b/packages/jelly/0.1.31/test.jelly @@ -0,0 +1 @@ +“OK” \ No newline at end of file diff --git a/packages/kotlin/1.4.31/build.sh b/packages/kotlin/1.4.31/build.sh new file mode 100755 index 0000000..4ea535d --- /dev/null +++ b/packages/kotlin/1.4.31/build.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +source ../../java/15.0.2/build.sh + +curl -L "https://github.com/JetBrains/kotlin/releases/download/v1.4.31/kotlin-compiler-1.4.31.zip" -o kotlin.zip +unzip kotlin.zip +rm kotlin.zip + +cp -r kotlinc/* . +rm -rf kotlinc \ No newline at end of file diff --git a/packages/kotlin/1.4.31/compile b/packages/kotlin/1.4.31/compile new file mode 100644 index 0000000..8be38a7 --- /dev/null +++ b/packages/kotlin/1.4.31/compile @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put instructions to compile source code, remove this file if the language does not require this stage +kotlinc $* -include-runtime -d code.jar \ No newline at end of file diff --git a/packages/kotlin/1.4.31/environment b/packages/kotlin/1.4.31/environment new file mode 100644 index 0000000..780b668 --- /dev/null +++ b/packages/kotlin/1.4.31/environment @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put 'export' statements here for environment variables +export PATH=$PWD/bin:$PATH diff --git a/packages/kotlin/1.4.31/metadata.json b/packages/kotlin/1.4.31/metadata.json new file mode 100644 index 0000000..87ffdf8 --- /dev/null +++ b/packages/kotlin/1.4.31/metadata.json @@ -0,0 +1,6 @@ +{ + "language": "kotlin", + "version": "1.4.31", + "aliases": ["kt"], + "author": "Thomas Hobson " +} diff --git a/packages/kotlin/1.4.31/run b/packages/kotlin/1.4.31/run new file mode 100644 index 0000000..d7c9501 --- /dev/null +++ b/packages/kotlin/1.4.31/run @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put instructions to run the runtime +java -jar code.jar \ No newline at end of file diff --git a/packages/kotlin/1.4.31/test.kt b/packages/kotlin/1.4.31/test.kt new file mode 100644 index 0000000..31acf7b --- /dev/null +++ b/packages/kotlin/1.4.31/test.kt @@ -0,0 +1,3 @@ +fun main() { + println("OK") +} \ No newline at end of file diff --git a/packages/mono-6.12.0/build.sh b/packages/mono/6.12.0/build.sh similarity index 51% rename from packages/mono-6.12.0/build.sh rename to packages/mono/6.12.0/build.sh index 59fb3ad..31bfaa9 100755 --- a/packages/mono-6.12.0/build.sh +++ b/packages/mono/6.12.0/build.sh @@ -1,6 +1,8 @@ #!/bin/bash -mkdir -p build/tmp build/mono +PREFIX=$(realpath $(dirname $0)) + +mkdir -p build/mono cd build curl "https://download.mono-project.com/sources/mono/mono-6.12.0.122.tar.xz" -o mono.tar.xz @@ -8,12 +10,10 @@ tar xf mono.tar.xz --strip-components=1 -C mono cd mono -./configure --prefix /piston/packages/mono/6.12.0/mono-6.12.0 +./configure --prefix "$PREFIX" make -j$(nproc) -DESTDIR=build/tmp make install -j$(nproc) - -mv build/tmp/piston/packages/mono/6.12.0/mono-6.12.0 ../../mono-6.12.0 +make install -j$(nproc) cd ../../ rm -rf build diff --git a/packages/mono-6.12.0/compile b/packages/mono/6.12.0/compile similarity index 100% rename from packages/mono-6.12.0/compile rename to packages/mono/6.12.0/compile diff --git a/packages/mono-6.12.0/environment b/packages/mono/6.12.0/environment similarity index 100% rename from packages/mono-6.12.0/environment rename to packages/mono/6.12.0/environment diff --git a/packages/mono-6.12.0/metadata.json b/packages/mono/6.12.0/metadata.json similarity index 100% rename from packages/mono-6.12.0/metadata.json rename to packages/mono/6.12.0/metadata.json diff --git a/packages/mono-6.12.0/run b/packages/mono/6.12.0/run similarity index 100% rename from packages/mono-6.12.0/run rename to packages/mono/6.12.0/run diff --git a/packages/mono-6.12.0/test.cs b/packages/mono/6.12.0/test.cs similarity index 100% rename from packages/mono-6.12.0/test.cs rename to packages/mono/6.12.0/test.cs diff --git a/packages/nasm/2.15.5/build.sh b/packages/nasm/2.15.5/build.sh new file mode 100755 index 0000000..1e1f4c3 --- /dev/null +++ b/packages/nasm/2.15.5/build.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# Put instructions to build your package in here +PREFIX=$(realpath $(dirname $0)) + +mkdir -p build + +cd build + +curl -L "https://www.nasm.us/pub/nasm/releasebuilds/2.15.05/nasm-2.15.05.tar.gz" -o nasm.tar.gz + +tar xzf nasm.tar.gz --strip-components=1 + +# === autoconf based === +./configure --prefix "$PREFIX" + +make -j$(nproc) +make install -j$(nproc) +cd ../ +rm -rf build diff --git a/packages/nasm/2.15.5/compile b/packages/nasm/2.15.5/compile new file mode 100644 index 0000000..a8fe6da --- /dev/null +++ b/packages/nasm/2.15.5/compile @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# Put instructions to compile source code, remove this file if the language does not require this stage + + +case "${PISTON_ALIAS}" in + nasm) + nasm -f elf32 -o binary.o $* + ld -m elf_i386 binary.o -o binary + ;; + nasm64) + nasm -f elf64 -o binary.o $* + ld -m elf_x86_64 binary.o -o binary + ;; + *) + echo "How did you get here? (${PISTON_ALIAS})" + exit 1 + ;; +esac + +chmod +x ./binary \ No newline at end of file diff --git a/packages/nasm/2.15.5/environment b/packages/nasm/2.15.5/environment new file mode 100644 index 0000000..780b668 --- /dev/null +++ b/packages/nasm/2.15.5/environment @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put 'export' statements here for environment variables +export PATH=$PWD/bin:$PATH diff --git a/packages/nasm/2.15.5/metadata.json b/packages/nasm/2.15.5/metadata.json new file mode 100644 index 0000000..e9d1507 --- /dev/null +++ b/packages/nasm/2.15.5/metadata.json @@ -0,0 +1,6 @@ +{ + "language": "nasm", + "version": "2.15.5", + "aliases": ["nasm64"], + "author": "Thomas Hobson " +} diff --git a/packages/nasm/2.15.5/run b/packages/nasm/2.15.5/run new file mode 100644 index 0000000..53a6099 --- /dev/null +++ b/packages/nasm/2.15.5/run @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +# Put instructions to run the runtime +shift +./binary $* diff --git a/packages/nasm/2.15.5/test.nasm.asm b/packages/nasm/2.15.5/test.nasm.asm new file mode 100644 index 0000000..d1e5a57 --- /dev/null +++ b/packages/nasm/2.15.5/test.nasm.asm @@ -0,0 +1,16 @@ +SECTION .DATA +good: db 'OK',10 +txtlen: equ $-good + +SECTION .TEXT +GLOBAL _start + +_start: +mov eax,4 +mov ebx,1 +mov ecx,good +mov edx,txtlen +int 80h +mov eax,1 +mov ebx,0 +int 80h \ No newline at end of file diff --git a/packages/nasm/2.15.5/test.nasm64.asm b/packages/nasm/2.15.5/test.nasm64.asm new file mode 100644 index 0000000..20ea316 --- /dev/null +++ b/packages/nasm/2.15.5/test.nasm64.asm @@ -0,0 +1,18 @@ +SECTION .data + good: db "OK", 0x0 + txtlen: equ $ - good + +SECTION .text +GLOBAL _start + +_start: + ;sys_write + mov rax, 1 + mov rdi, 1 + mov rsi, good + mov rdx, txtlen + syscall + ;sys_exit + mov rax, 60 + mov rdi, 0 + syscall \ No newline at end of file diff --git a/packages/node-15.10.0/build.sh b/packages/node/15.10.0/build.sh similarity index 100% rename from packages/node-15.10.0/build.sh rename to packages/node/15.10.0/build.sh diff --git a/packages/node/15.10.0/environment b/packages/node/15.10.0/environment new file mode 100644 index 0000000..bd0ff98 --- /dev/null +++ b/packages/node/15.10.0/environment @@ -0,0 +1 @@ +export PATH=$PWD/bin:$PATH \ No newline at end of file diff --git a/packages/node-15.10.0/metadata.json b/packages/node/15.10.0/metadata.json similarity index 100% rename from packages/node-15.10.0/metadata.json rename to packages/node/15.10.0/metadata.json diff --git a/packages/node-15.10.0/run b/packages/node/15.10.0/run similarity index 100% rename from packages/node-15.10.0/run rename to packages/node/15.10.0/run diff --git a/packages/node-15.10.0/test.js b/packages/node/15.10.0/test.js similarity index 100% rename from packages/node-15.10.0/test.js rename to packages/node/15.10.0/test.js diff --git a/packages/php-8.0.2/build.sh b/packages/php-8.0.2/build.sh deleted file mode 100755 index ba78728..0000000 --- a/packages/php-8.0.2/build.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -mkdir -p build/tmp build/php -cd build - -curl "https://www.php.net/distributions/php-8.0.2.tar.gz" -o php.tar.gz -tar xzf php.tar.gz --strip-components=1 -C php - -cd php - - -./configure --prefix /piston/packages/php/8.0.2/php-8.0.2 - -make -j$(nproc) -INSTALL_ROOT=build/tmp make install -j$(nproc) - - -mv build/tmp/piston/packages/php/8.0.2/php-8.0.2 ../../php-8.0.2 - - diff --git a/packages/php/8.0.2/build.sh b/packages/php/8.0.2/build.sh new file mode 100755 index 0000000..0a94615 --- /dev/null +++ b/packages/php/8.0.2/build.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +PREFIX=$(realpath $(dirname $0)) + +mkdir -p build/php +cd build + +curl "https://www.php.net/distributions/php-8.0.2.tar.gz" -o php.tar.gz +tar xzf php.tar.gz --strip-components=1 -C php + +cd php + + +./configure --prefix "$PREFIX" + +make -j$(nproc) +make install -j$(nproc) + +cd ../../ +rm -rf build \ No newline at end of file diff --git a/packages/php-8.0.2/environment b/packages/php/8.0.2/environment similarity index 100% rename from packages/php-8.0.2/environment rename to packages/php/8.0.2/environment diff --git a/packages/php-8.0.2/metadata.json b/packages/php/8.0.2/metadata.json similarity index 100% rename from packages/php-8.0.2/metadata.json rename to packages/php/8.0.2/metadata.json diff --git a/packages/php-8.0.2/run b/packages/php/8.0.2/run similarity index 100% rename from packages/php-8.0.2/run rename to packages/php/8.0.2/run diff --git a/packages/php-8.0.2/test.php b/packages/php/8.0.2/test.php similarity index 100% rename from packages/php-8.0.2/test.php rename to packages/php/8.0.2/test.php diff --git a/packages/python-3.9.1/environment b/packages/python-3.9.1/environment deleted file mode 100644 index 98fd770..0000000 --- a/packages/python-3.9.1/environment +++ /dev/null @@ -1 +0,0 @@ -export PATH=$PWD:$PATH \ No newline at end of file diff --git a/packages/python-3.9.1/build.sh b/packages/python/3.9.1/build.sh similarity index 51% rename from packages/python-3.9.1/build.sh rename to packages/python/3.9.1/build.sh index 1ee0843..875a191 100755 --- a/packages/python-3.9.1/build.sh +++ b/packages/python/3.9.1/build.sh @@ -1,10 +1,20 @@ #!/bin/bash +PREFIX=$(realpath $(dirname $0)) + +mkdir -p build + +cd build + curl "https://www.python.org/ftp/python/3.9.1/Python-3.9.1.tgz" -o python.tar.gz tar xzf python.tar.gz --strip-components=1 rm python.tar.gz -./configure --prefix /piston/packages/python/3.9.1/python-3.9.1 +./configure --prefix "$PREFIX" --with-ensurepip=install make -j$(nproc) -ln -s python python3.9 +make install -j$(nproc) + +cd .. + +rm -rf build diff --git a/packages/python/3.9.1/environment b/packages/python/3.9.1/environment new file mode 100644 index 0000000..bd0ff98 --- /dev/null +++ b/packages/python/3.9.1/environment @@ -0,0 +1 @@ +export PATH=$PWD/bin:$PATH \ No newline at end of file diff --git a/packages/python-3.9.1/metadata.json b/packages/python/3.9.1/metadata.json similarity index 100% rename from packages/python-3.9.1/metadata.json rename to packages/python/3.9.1/metadata.json diff --git a/packages/python-3.9.1/run b/packages/python/3.9.1/run similarity index 100% rename from packages/python-3.9.1/run rename to packages/python/3.9.1/run diff --git a/packages/python-3.9.1/test.py b/packages/python/3.9.1/test.py similarity index 100% rename from packages/python-3.9.1/test.py rename to packages/python/3.9.1/test.py diff --git a/packages/typescript/4.2.3/build.sh b/packages/typescript/4.2.3/build.sh new file mode 100755 index 0000000..83ab333 --- /dev/null +++ b/packages/typescript/4.2.3/build.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +source ../../node/15.10.0/build.sh + +source ./environment + +bin/npm install -g typescript@4.2.3 \ No newline at end of file diff --git a/packages/typescript/4.2.3/compile b/packages/typescript/4.2.3/compile new file mode 100644 index 0000000..1258d16 --- /dev/null +++ b/packages/typescript/4.2.3/compile @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +# Put instructions to compile source code, remove this file if the language does not require this stage + +tsc $* \ No newline at end of file diff --git a/packages/typescript/4.2.3/environment b/packages/typescript/4.2.3/environment new file mode 100644 index 0000000..780b668 --- /dev/null +++ b/packages/typescript/4.2.3/environment @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Put 'export' statements here for environment variables +export PATH=$PWD/bin:$PATH diff --git a/packages/typescript/4.2.3/metadata.json b/packages/typescript/4.2.3/metadata.json new file mode 100644 index 0000000..f4a54de --- /dev/null +++ b/packages/typescript/4.2.3/metadata.json @@ -0,0 +1,6 @@ +{ + "language": "typescript", + "version": "4.2.3", + "aliases": ["ts","node-ts","tsc"], + "author": "Thomas Hobson " +} diff --git a/packages/typescript/4.2.3/run b/packages/typescript/4.2.3/run new file mode 100644 index 0000000..dfd4249 --- /dev/null +++ b/packages/typescript/4.2.3/run @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# Put instructions to run the runtime + +CODE=$(sed 's/ts$/js/' <<<"$1") +shift + +node $CODE $* diff --git a/packages/typescript/4.2.3/test.ts b/packages/typescript/4.2.3/test.ts new file mode 100644 index 0000000..56ed4a0 --- /dev/null +++ b/packages/typescript/4.2.3/test.ts @@ -0,0 +1 @@ +console.log("OK") \ No newline at end of file diff --git a/repo/entrypoint.sh b/repo/entrypoint.sh index 83e7c73..54261dc 100755 --- a/repo/entrypoint.sh +++ b/repo/entrypoint.sh @@ -1,11 +1,11 @@ -cd /packages +cd /piston/packages for pkg in "$@" do make -j16 $pkg.pkg.tar.gz done -cd /repo +cd /piston/repo ./mkindex.sh python3 -m http.server \ No newline at end of file diff --git a/shell.nix b/shell.nix index f9063bc..f43b1b4 100644 --- a/shell.nix +++ b/shell.nix @@ -1,5 +1,5 @@ { pkgs ? import {} }: pkgs.mkShell { # nativeBuildInputs is usually what you want -- tools you need to run - nativeBuildInputs = [ pkgs.nodejs-15_x pkgs.yarn ]; + nativeBuildInputs = [ pkgs.nodejs-15_x pkgs.yarn pkgs.jq ]; } \ No newline at end of file