diff options
Diffstat (limited to 'lib/compile-handler.js')
-rw-r--r-- | lib/compile-handler.js | 207 |
1 files changed, 0 insertions, 207 deletions
diff --git a/lib/compile-handler.js b/lib/compile-handler.js deleted file mode 100644 index 0e506ea0f..000000000 --- a/lib/compile-handler.js +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) 2012-2017, Matt Godbolt -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -var child_process = require('child_process'), - temp = require('temp'), - fs = require('fs'), - path = require('path'), - httpProxy = require('http-proxy'), - denodeify = require('denodeify'), - quote = require('shell-quote'), - _ = require('underscore-node'), - logger = require('./logger').logger, - utils = require('./utils'), - CompilationEnvironment = require('./compilation-env').CompilationEnvironment, - Raven = require('raven'); - -temp.track(); - -var oneTimeInit = false; - -function initialise(gccProps, compilerEnv) { - if (oneTimeInit) return; - oneTimeInit = true; - var tempDirCleanupSecs = gccProps("tempDirCleanupSecs", 600); - logger.info("Cleaning temp dirs every " + tempDirCleanupSecs + " secs"); - setInterval(function () { - if (compilerEnv.isBusy()) { - logger.warn("Skipping temporary file clean up as compiler environment is busy"); - return; - } - temp.cleanup(function (err, stats) { - if (err) logger.error("Error cleaning directories: ", err); - if (stats) logger.debug("Directory cleanup stats:", stats); - }); - }, tempDirCleanupSecs * 1000); -} - -function CompileHandler(gccProps, compilerProps) { - this.compilersById = {}; - this.compilerEnv = new CompilationEnvironment(gccProps, compilerProps); - initialise(gccProps, this.compilerEnv); - this.factories = {}; - this.stat = denodeify(fs.stat); - - this.create = function (compiler) { - var type = compiler.compilerType || "default"; - if (this.factories[type] === undefined) { - var compilerPath = './compilers/' + type; - logger.info("Loading compiler from", compilerPath); - this.factories[type] = require(compilerPath); - } - if (path.isAbsolute(compiler.exe)) { - // Try stat'ing the compiler to cache its mtime and only re-run it if it - // has changed since the last time. - return this.stat(compiler.exe) - .then(_.bind(function (res) { - var cached = this.compilersById[compiler.id]; - if (cached && cached.mtime.getTime() === res.mtime.getTime()) { - logger.debug(compiler.id + " is unchanged"); - return cached; - } - return this.factories[type](compiler, this.compilerEnv) - .then(function (compiler) { - if (compiler) compiler.mtime = res.mtime; - return compiler; - }); - }, this)) - .catch(function (err) { - logger.warn("Unable to stat compiler binary", err); - return null; - }); - } else { - return this.factories[type](compiler, this.compilerEnv); - } - }; - - this.setCompilers = function (compilers) { - return Promise.all(_.map(compilers, this.create, this)) - .then(_.compact) - .then(compilers => { - _.each(compilers, compiler => this.compilersById[compiler.compiler.id] = compiler); - return _.map(compilers, compiler => compiler.getInfo()); - }) - .catch(err => logger.error(err)); - }; - var proxy = httpProxy.createProxyServer({}); - var textBanner = compilerProps('textBanner'); - - this.handler = _.bind(function compile(req, res, next) { - var source, options, backendOptions, filters, compiler; - if (req.is('json')) { - // JSON-style request - compiler = this.compilersById[req.compiler || req.body.compiler]; - if (!compiler) return next(); - var requestOptions = req.body.options; - source = req.body.source; - options = requestOptions.userArguments; - backendOptions = requestOptions.compilerOptions; - filters = requestOptions.filters || compiler.getDefaultFilters(); - } else { - // API-style - compiler = this.compilersById[req.compiler]; - if (!compiler) return next(); - source = req.body; - options = req.query.options; - // By default we get the default filters. - filters = compiler.getDefaultFilters(); - // If specified exactly, we'll take that with ?filters=a,b,c - if (req.query.filters) { - filters = _.object(_.map(req.query.filters.split(","), function (filter) { - return [filter, true]; - })); - } - // Add a filter. ?addFilters=binary - _.each((req.query.addFilters || "").split(","), function (filter) { - filters[filter] = true; - }); - // Remove a filter. ?removeFilter=intel - _.each((req.query.removeFilters || "").split(","), function (filter) { - delete filters[filter]; - }); - } - var remote = compiler.getRemote(); - if (remote) { - req.url = req.originalUrl; // Undo any routing that was done to get here (i.e. /api/* path has been removed) - proxy.web(req, res, {target: remote}, function (e) { - logger.error("Proxy error: ", e); - next(e); - }); - return; - } - - if (source === undefined) { - return next(new Error("Bad request")); - } - options = _.chain(quote.parse(options || '') - .map(x => typeof(x) === "string" ? x : x.pattern)) - .compact() - .value(); - - function textify(array) { - return _.pluck(array || [], 'text').join("\n"); - } - - compiler.compile(source, options, backendOptions, filters).then( - function (result) { - if (req.accepts(['text', 'json']) === 'json') { - res.set('Content-Type', 'application/json'); - res.end(JSON.stringify(result)); - } else { - res.set('Content-Type', 'text/plain'); - try { - if (!_.isEmpty(textBanner)) res.write('# ' + textBanner + "\n"); - res.write(textify(result.asm)); - if (result.code !== 0) res.write("\n# Compiler exited with result code " + result.code); - if (!_.isEmpty(result.stdout)) res.write("\nStandard out:\n" + textify(result.stdout)); - if (!_.isEmpty(result.stderr)) res.write("\nStandard error:\n" + textify(result.stderr)); - } catch (ex) { - Raven.captureException(ex, {req: req}); - res.write("Error handling request: " + ex); - } - res.end('\n'); - } - }, - function (error) { - logger.error("Error during compilation", error); - if (typeof(error) !== "string") { - if (error.code) { - if (typeof(error.stderr) === "string") { - error.stdout = utils.parseOutput(error.stdout); - error.stderr = utils.parseOutput(error.stderr); - } - res.end(JSON.stringify(error)); - return; - } - error = "Internal Compiler Explorer error: " + (error.stack || error); - } - res.end(JSON.stringify({code: -1, stderr: [{text: error}]})); - } - ); - }, this); -} - -module.exports = { - CompileHandler: CompileHandler -}; |