// Generated by CoffeeScript 1.12.6 var QEMU_BIN_NAME, QEMU_VERSION, cacheHighlightStream, copyQemu, generateConnectOpts, getQemuPath, hasQemu, installQemu, parseBuildArgs, platformNeedsQemu, tarDirectory; QEMU_VERSION = 'v2.5.50-resin-execve'; QEMU_BIN_NAME = 'qemu-execve'; exports.appendOptions = function(opts) { return opts.concat([ { signature: 'docker', parameter: 'docker', description: 'Path to a local docker socket', alias: 'P' }, { signature: 'dockerHost', parameter: 'dockerHost', description: 'The address of the host containing the docker daemon', alias: 'h' }, { signature: 'dockerPort', parameter: 'dockerPort', description: 'The port on which the host docker daemon is listening', alias: 'p' }, { signature: 'ca', parameter: 'ca', description: 'Docker host TLS certificate authority file' }, { signature: 'cert', parameter: 'cert', description: 'Docker host TLS certificate file' }, { signature: 'key', parameter: 'key', description: 'Docker host TLS key file' }, { signature: 'tag', parameter: 'tag', description: 'The alias to the generated image', alias: 't' }, { signature: 'buildArg', parameter: 'arg', description: 'Set a build-time variable (eg. "-B \'ARG=value\'"). Can be specified multiple times.', alias: 'B' }, { signature: 'nocache', description: "Don't use docker layer caching when building", boolean: true }, { signature: 'emulated', description: 'Run an emulated build using Qemu', boolean: true, alias: 'e' } ]); }; exports.generateConnectOpts = generateConnectOpts = function(opts) { var Promise, _, fs; Promise = require('bluebird'); fs = require('mz/fs'); _ = require('lodash'); return Promise["try"](function() { var certBodies, connectOpts; connectOpts = {}; if ((opts.docker != null) && (opts.dockerHost == null)) { connectOpts.socketPath = opts.docker; } else if ((opts.dockerHost != null) && (opts.docker == null)) { connectOpts.host = opts.dockerHost; connectOpts.port = opts.dockerPort || 2376; } else if ((opts.docker != null) && (opts.dockerHost != null)) { throw new Error("Both a local docker socket and docker host have been provided. Don't know how to continue."); } else { connectOpts.socketPath = '/var/run/docker.sock'; } if ((opts.ca != null) || (opts.cert != null) || (opts.key != null)) { if (!((opts.ca != null) && (opts.cert != null) && (opts.key != null))) { throw new Error('You must provide a CA, certificate and key in order to use TLS'); } certBodies = { ca: fs.readFile(opts.ca, 'utf-8'), cert: fs.readFile(opts.cert, 'utf-8'), key: fs.readFile(opts.key, 'utf-8') }; return Promise.props(certBodies).then(function(toMerge) { return _.merge(connectOpts, toMerge); }); } return connectOpts; }); }; exports.tarDirectory = tarDirectory = function(dir) { var Promise, fs, getFiles, klaw, pack, path, streamToPromise, tar; Promise = require('bluebird'); tar = require('tar-stream'); klaw = require('klaw'); path = require('path'); fs = require('mz/fs'); streamToPromise = require('stream-to-promise'); getFiles = function() { return streamToPromise(klaw(dir)).filter(function(item) { return !item.stats.isDirectory(); }).map(function(item) { return item.path; }); }; pack = tar.pack(); return getFiles(dir).map(function(file) { var relPath; relPath = path.relative(path.resolve(dir), file); return Promise.join(relPath, fs.stat(file), fs.readFile(file), function(filename, stats, data) { return pack.entryAsync({ name: filename, size: stats.size, mode: stats.mode }, data); }); }).then(function() { pack.finalize(); return pack; }); }; cacheHighlightStream = function() { var EOL, colors, es, extractArrowMessage; colors = require('colors/safe'); es = require('event-stream'); EOL = require('os').EOL; extractArrowMessage = function(message) { var arrowTest, match; arrowTest = /^\s*-+>\s*(.+)/i; if ((match = arrowTest.exec(message))) { return match[1]; } else { return void 0; } }; return es.mapSync(function(data) { var msg; msg = extractArrowMessage(data); if ((msg != null) && msg.toLowerCase() === 'using cache') { data = colors.bgGreen.black(msg); } return data + EOL; }); }; parseBuildArgs = function(args, onError) { var _, buildArgs; _ = require('lodash'); if (!_.isArray(args)) { args = [args]; } buildArgs = {}; args.forEach(function(str) { var pair; pair = /^([^\s]+?)=(.*)$/.exec(str); if (pair != null) { return buildArgs[pair[1]] = pair[2]; } else { return onError(str); } }); return buildArgs; }; exports.runBuild = function(params, options, getBundleInfo, logStreams) { var Promise, dockerBuild, doodles, es, logging, logs, path, qemuPath, resolver, transpose; Promise = require('bluebird'); dockerBuild = require('resin-docker-build'); resolver = require('resin-bundle-resolve'); es = require('event-stream'); doodles = require('resin-doodles'); transpose = require('docker-qemu-transpose'); path = require('path'); logging = require('../utils/logging'); if (params.source == null) { params.source = '.'; } logs = ''; qemuPath = ''; return Promise["try"](function() { if (!(options.emulated && platformNeedsQemu())) { return; } return hasQemu().then(function(present) { if (!present) { logging.logInfo(logStreams, 'Installing qemu for ARM emulation...'); return installQemu(); } }).then(function() { return copyQemu(params.source); }).then(function(binPath) { return qemuPath = path.relative(params.source, binPath); }); }).then(function() { return tarDirectory(params.source); }).then(function(tarStream) { return new Promise(function(resolve, reject) { var hooks; hooks = { buildSuccess: function(image) { var doodle; if (options.tag != null) { console.log("Tagging image as " + options.tag); } doodle = doodles.getDoodle(); console.log(); console.log(doodle); console.log(); return resolve({ image: image, log: logs + '\n' + doodle + '\n' }); }, buildFailure: reject, buildStream: function(stream) { var buildThroughStream, logThroughStream, newStream; if (options.emulated) { logging.logInfo(logStreams, 'Running emulated build'); } getBundleInfo(options).then(function(info) { var arch, bundle, deviceType; if (info == null) { logging.logWarn(logStreams, 'Warning: No architecture/device type or application information provided.\n Dockerfile/project pre-processing will not be performed.'); return tarStream; } else { arch = info[0], deviceType = info[1]; bundle = new resolver.Bundle(tarStream, deviceType, arch); return resolver.resolveBundle(bundle, resolver.getDefaultResolvers()).then(function(resolved) { logging.logInfo(logStreams, "Building " + resolved.projectType + " project"); return resolved.tarStream; }); } }).then(function(buildStream) { if (options.emulated && platformNeedsQemu()) { return transpose.transposeTarStream(buildStream, { hostQemuPath: qemuPath, containerQemuPath: "/tmp/" + QEMU_BIN_NAME }); } else { return buildStream; } }).then(function(buildStream) { return buildStream.pipe(stream); })["catch"](reject); logThroughStream = es.through(function(data) { logs += data.toString(); return this.emit('data', data); }); if (options.emulated && platformNeedsQemu()) { buildThroughStream = transpose.getBuildThroughStream({ hostQemuPath: qemuPath, containerQemuPath: "/tmp/" + QEMU_BIN_NAME }); newStream = stream.pipe(buildThroughStream); } else { newStream = stream; } return newStream.pipe(logThroughStream).pipe(cacheHighlightStream()).pipe(logStreams.build); } }; return generateConnectOpts(options).then(function(connectOpts) { var builder, opts; logging.logDebug(logStreams, 'Connecting with the following options:'); logging.logDebug(logStreams, JSON.stringify(connectOpts, null, ' ')); builder = new dockerBuild.Builder(connectOpts); opts = {}; if (options.tag != null) { opts['t'] = options.tag; } if (options.nocache != null) { opts['nocache'] = true; } if (options.buildArg != null) { opts['buildargs'] = parseBuildArgs(options.buildArg, function(arg) { return logging.logWarn(logStreams, "Could not parse variable: '" + arg + "'"); }); } return builder.createBuildStream(opts, hooks, reject); }); }); }); }; exports.bufferImage = function(docker, imageId, bufferFile) { var Promise, image, imageMetadata, streamUtils; Promise = require('bluebird'); streamUtils = require('./streams'); image = docker.getImage(imageId); imageMetadata = image.inspectAsync(); return Promise.join(image.get(), imageMetadata.get('Size'), function(imageStream, imageSize) { return streamUtils.buffer(imageStream, bufferFile).tap(function(bufferedStream) { return bufferedStream.length = imageSize; }); }); }; exports.getDocker = function(options) { var Docker, Promise; Docker = require('dockerode'); Promise = require('bluebird'); return generateConnectOpts(options).then(function(connectOpts) { connectOpts['Promise'] = Promise; return new Docker(connectOpts); }); }; hasQemu = function() { var fs; fs = require('mz/fs'); return getQemuPath().then(fs.stat)["return"](true).catchReturn(false); }; getQemuPath = function() { var fs, path, resin; resin = require('resin-sdk-preconfigured'); path = require('path'); fs = require('mz/fs'); return resin.settings.get('binDirectory').then(function(binDir) { return fs.access(binDir)["catch"]({ code: 'ENOENT' }, function() { return fs.mkdir(binDir); }).then(function() { return path.join(binDir, QEMU_BIN_NAME); }); }); }; platformNeedsQemu = function() { var os; os = require('os'); return os.platform() === 'linux'; }; installQemu = function() { var fs, request, zlib; request = require('request'); fs = require('fs'); zlib = require('zlib'); return getQemuPath().then(function(qemuPath) { return new Promise(function(resolve, reject) { var installStream, qemuUrl; installStream = fs.createWriteStream(qemuPath); qemuUrl = "https://github.com/resin-io/qemu/releases/download/" + QEMU_VERSION + "/" + QEMU_BIN_NAME + ".gz"; return request(qemuUrl).pipe(zlib.createGunzip()).pipe(installStream).on('error', reject).on('finish', resolve); }); }); }; copyQemu = function(context) { var binDir, binPath, fs, path; path = require('path'); fs = require('mz/fs'); binDir = path.join(context, '.resin'); binPath = path.join(binDir, QEMU_BIN_NAME); return fs.access(binDir)["catch"]({ code: 'ENOENT' }, function() { return fs.mkdir(binDir); }).then(function() { return getQemuPath(); }).then(function(qemu) { return new Promise(function(resolve, reject) { var read, write; read = fs.createReadStream(qemu); write = fs.createWriteStream(binPath); return read.pipe(write).on('error', reject).on('finish', resolve); }); }).then(function() { return fs.chmod(binPath, '755'); })["return"](binPath); };