2017-07-27 11:07:05 +00:00
// Generated by CoffeeScript 1.12.7
2017-08-04 12:53:31 +00:00
var QEMU _BIN _NAME , QEMU _VERSION , appendConnectionOptions , cacheHighlightStream , copyQemu , ensureDockerSeemsAccessible , generateConnectOpts , getQemuPath , hasQemu , installQemu , parseBuildArgs , platformNeedsQemu , tarDirectory ;
2017-05-04 12:00:48 +00:00
QEMU _VERSION = 'v2.5.50-resin-execve' ;
QEMU _BIN _NAME = 'qemu-execve' ;
2017-03-29 11:03:40 +00:00
2017-08-04 12:53:31 +00:00
exports . appendConnectionOptions = appendConnectionOptions = function ( opts ) {
2017-03-29 11:03:40 +00:00
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'
2017-08-04 12:53:31 +00:00
}
] ) ;
} ;
exports . appendOptions = function ( opts ) {
return appendConnectionOptions ( opts ) . concat ( [
{
2017-04-24 19:05:18 +00:00
signature : 'tag' ,
parameter : 'tag' ,
description : 'The alias to the generated image' ,
alias : 't'
2017-05-10 19:02:52 +00:00
} , {
2017-05-11 11:20:24 +00:00
signature : 'buildArg' ,
2017-05-10 19:02:52 +00:00
parameter : 'arg' ,
2017-05-11 11:20:24 +00:00
description : 'Set a build-time variable (eg. "-B \'ARG=value\'"). Can be specified multiple times.' ,
alias : 'B'
2017-04-24 19:05:18 +00:00
} , {
signature : 'nocache' ,
description : "Don't use docker layer caching when building" ,
boolean : true
2017-05-04 12:00:48 +00:00
} , {
signature : 'emulated' ,
description : 'Run an emulated build using Qemu' ,
boolean : true ,
alias : 'e'
2017-06-23 15:20:16 +00:00
} , {
signature : 'squash' ,
description : 'Squash newly built layers into a single new layer' ,
boolean : true
2017-03-29 11:03:40 +00:00
}
] ) ;
} ;
exports . generateConnectOpts = generateConnectOpts = function ( opts ) {
2017-08-23 12:14:46 +00:00
var Promise , _ , buildDockerodeOpts , fs ;
2017-06-20 10:48:15 +00:00
Promise = require ( 'bluebird' ) ;
2017-08-23 12:14:46 +00:00
buildDockerodeOpts = require ( 'dockerode-options' ) ;
2017-06-20 10:48:15 +00:00
fs = require ( 'mz/fs' ) ;
2017-06-22 11:53:10 +00:00
_ = require ( 'lodash' ) ;
2017-06-20 10:48:15 +00:00
return Promise [ "try" ] ( function ( ) {
2017-06-22 11:53:10 +00:00
var certBodies , connectOpts ;
2017-06-20 10:48:15 +00:00
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." ) ;
2017-08-23 12:14:46 +00:00
} else if ( process . env . DOCKER _HOST ) {
connectOpts = buildDockerodeOpts ( process . env . DOCKER _HOST ) ;
2017-06-20 10:48:15 +00:00
} else {
connectOpts . socketPath = '/var/run/docker.sock' ;
2017-03-29 11:03:40 +00:00
}
2017-06-20 10:48:15 +00:00
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' ) ;
}
2017-06-22 11:53:10 +00:00
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 ) ;
2017-06-20 10:48:15 +00:00
} ) ;
}
return connectOpts ;
} ) ;
2017-03-29 11:03:40 +00:00
} ;
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 ,
2017-05-04 12:00:48 +00:00
size : stats . size ,
mode : stats . mode
2017-03-29 11:03:40 +00:00
} , data ) ;
} ) ;
} ) . then ( function ( ) {
pack . finalize ( ) ;
return pack ;
} ) ;
} ;
2017-05-02 12:27:18 +00:00
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 ;
} ) ;
} ;
2017-05-10 19:02:52 +00:00
parseBuildArgs = function ( args , onError ) {
2017-05-11 11:20:24 +00:00
var _ , buildArgs ;
2017-05-10 19:02:52 +00:00
_ = require ( 'lodash' ) ;
if ( ! _ . isArray ( args ) ) {
args = [ args ] ;
}
2017-05-11 11:20:24 +00:00
buildArgs = { } ;
2017-05-10 19:02:52 +00:00
args . forEach ( function ( str ) {
var pair ;
pair = /^([^\s]+?)=(.*)$/ . exec ( str ) ;
if ( pair != null ) {
2017-05-11 11:20:24 +00:00
return buildArgs [ pair [ 1 ] ] = pair [ 2 ] ;
2017-05-10 19:02:52 +00:00
} else {
return onError ( str ) ;
}
} ) ;
2017-05-11 11:20:24 +00:00
return buildArgs ;
2017-05-10 19:02:52 +00:00
} ;
2017-06-28 16:30:37 +00:00
exports . runBuild = function ( params , options , getBundleInfo , logger ) {
var Promise , dockerBuild , doodles , es , logs , path , qemuPath , resolver , transpose ;
2017-03-29 11:03:40 +00:00
Promise = require ( 'bluebird' ) ;
dockerBuild = require ( 'resin-docker-build' ) ;
resolver = require ( 'resin-bundle-resolve' ) ;
2017-04-24 10:06:53 +00:00
es = require ( 'event-stream' ) ;
2017-04-28 12:44:40 +00:00
doodles = require ( 'resin-doodles' ) ;
2017-05-04 12:00:48 +00:00
transpose = require ( 'docker-qemu-transpose' ) ;
path = require ( 'path' ) ;
2017-04-24 14:55:54 +00:00
if ( params . source == null ) {
params . source = '.' ;
2017-03-29 11:03:40 +00:00
}
2017-04-24 10:06:53 +00:00
logs = '' ;
2017-05-04 12:00:48 +00:00
qemuPath = '' ;
return Promise [ "try" ] ( function ( ) {
if ( ! ( options . emulated && platformNeedsQemu ( ) ) ) {
return ;
}
return hasQemu ( ) . then ( function ( present ) {
if ( ! present ) {
2017-06-28 16:30:37 +00:00
logger . logInfo ( 'Installing qemu for ARM emulation...' ) ;
2017-05-04 12:00:48 +00:00
return installQemu ( ) ;
}
} ) . then ( function ( ) {
return copyQemu ( params . source ) ;
} ) . then ( function ( binPath ) {
2017-06-14 18:50:24 +00:00
return qemuPath = path . relative ( params . source , binPath ) ;
2017-05-04 12:00:48 +00:00
} ) ;
} ) . then ( function ( ) {
return tarDirectory ( params . source ) ;
} ) . then ( function ( tarStream ) {
2017-03-29 11:03:40 +00:00
return new Promise ( function ( resolve , reject ) {
2017-06-20 10:48:15 +00:00
var hooks ;
2017-03-29 11:03:40 +00:00
hooks = {
buildSuccess : function ( image ) {
2017-05-02 12:27:18 +00:00
var doodle ;
doodle = doodles . getDoodle ( ) ;
2017-04-28 12:44:40 +00:00
console . log ( ) ;
2017-05-02 12:27:18 +00:00
console . log ( doodle ) ;
2017-04-28 12:44:40 +00:00
console . log ( ) ;
2017-04-24 10:06:53 +00:00
return resolve ( {
image : image ,
2017-05-02 12:27:18 +00:00
log : logs + '\n' + doodle + '\n'
2017-04-24 10:06:53 +00:00
} ) ;
2017-03-29 11:03:40 +00:00
} ,
buildFailure : reject ,
buildStream : function ( stream ) {
2017-05-04 12:00:48 +00:00
var buildThroughStream , logThroughStream , newStream ;
if ( options . emulated ) {
2017-06-28 16:30:37 +00:00
logger . logInfo ( 'Running emulated build' ) ;
2017-05-04 12:00:48 +00:00
}
2017-03-29 11:03:40 +00:00
getBundleInfo ( options ) . then ( function ( info ) {
var arch , bundle , deviceType ;
if ( info == null ) {
2017-06-28 16:30:37 +00:00
logger . logWarn ( 'Warning: No architecture/device type or application information provided.\n Dockerfile/project pre-processing will not be performed.' ) ;
2017-05-04 12:00:48 +00:00
return tarStream ;
2017-03-29 11:03:40 +00:00
} else {
arch = info [ 0 ] , deviceType = info [ 1 ] ;
bundle = new resolver . Bundle ( tarStream , deviceType , arch ) ;
return resolver . resolveBundle ( bundle , resolver . getDefaultResolvers ( ) ) . then ( function ( resolved ) {
2017-06-28 16:30:37 +00:00
logger . logInfo ( "Building " + resolved . projectType + " project" ) ;
2017-05-04 12:00:48 +00:00
return resolved . tarStream ;
2017-03-29 11:03:40 +00:00
} ) ;
}
2017-05-04 12:00:48 +00:00
} ) . then ( function ( buildStream ) {
if ( options . emulated && platformNeedsQemu ( ) ) {
return transpose . transposeTarStream ( buildStream , {
hostQemuPath : qemuPath ,
2017-06-15 14:36:44 +00:00
containerQemuPath : "/tmp/" + QEMU _BIN _NAME
2017-05-04 12:00:48 +00:00
} ) ;
} else {
return buildStream ;
}
} ) . then ( function ( buildStream ) {
return buildStream . pipe ( stream ) ;
2017-03-29 11:03:40 +00:00
} ) [ "catch" ] ( reject ) ;
2017-05-04 12:00:48 +00:00
logThroughStream = es . through ( function ( data ) {
2017-04-24 10:06:53 +00:00
logs += data . toString ( ) ;
return this . emit ( 'data' , data ) ;
} ) ;
2017-05-04 12:00:48 +00:00
if ( options . emulated && platformNeedsQemu ( ) ) {
buildThroughStream = transpose . getBuildThroughStream ( {
hostQemuPath : qemuPath ,
2017-06-15 14:36:44 +00:00
containerQemuPath : "/tmp/" + QEMU _BIN _NAME
2017-05-04 12:00:48 +00:00
} ) ;
newStream = stream . pipe ( buildThroughStream ) ;
} else {
newStream = stream ;
}
2017-06-28 16:30:37 +00:00
return newStream . pipe ( logThroughStream ) . pipe ( cacheHighlightStream ( ) ) . pipe ( logger . streams . build ) ;
2017-03-29 11:03:40 +00:00
}
} ;
2017-08-10 19:40:05 +00:00
return generateConnectOpts ( options ) . tap ( function ( connectOpts ) {
return ensureDockerSeemsAccessible ( connectOpts ) ;
} ) . then ( function ( connectOpts ) {
2017-06-20 10:48:15 +00:00
var builder , opts ;
2017-06-28 16:30:37 +00:00
logger . logDebug ( 'Connecting with the following options:' ) ;
logger . logDebug ( JSON . stringify ( connectOpts , null , ' ' ) ) ;
2017-06-20 10:48:15 +00:00
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 ) {
2017-06-28 16:30:37 +00:00
return logger . logWarn ( "Could not parse variable: '" + arg + "'" ) ;
2017-06-20 10:48:15 +00:00
} ) ;
}
2017-06-23 15:20:16 +00:00
if ( options . squash != null ) {
opts [ 'squash' ] = true ;
}
2017-06-20 10:48:15 +00:00
return builder . createBuildStream ( opts , hooks , reject ) ;
} ) ;
2017-03-29 11:03:40 +00:00
} ) ;
} ) ;
} ;
2017-06-13 17:28:37 +00:00
exports . bufferImage = function ( docker , imageId , bufferFile ) {
var Promise , image , imageMetadata , streamUtils ;
Promise = require ( 'bluebird' ) ;
2017-06-13 17:28:37 +00:00
streamUtils = require ( './streams' ) ;
2017-03-29 11:03:40 +00:00
image = docker . getImage ( imageId ) ;
2017-06-13 17:28:37 +00:00
imageMetadata = image . inspectAsync ( ) ;
2017-06-15 10:34:26 +00:00
return Promise . join ( image . get ( ) , imageMetadata . get ( 'Size' ) , function ( imageStream , imageSize ) {
2017-06-13 17:28:37 +00:00
return streamUtils . buffer ( imageStream , bufferFile ) . tap ( function ( bufferedStream ) {
return bufferedStream . length = imageSize ;
2017-06-13 17:28:37 +00:00
} ) ;
2017-03-29 11:03:40 +00:00
} ) ;
} ;
exports . getDocker = function ( options ) {
2017-06-20 10:48:15 +00:00
var Docker , Promise ;
2017-03-29 11:03:40 +00:00
Docker = require ( 'dockerode' ) ;
Promise = require ( 'bluebird' ) ;
2017-08-10 19:40:05 +00:00
return generateConnectOpts ( options ) . tap ( function ( connectOpts ) {
return ensureDockerSeemsAccessible ( connectOpts ) ;
} ) . then ( function ( connectOpts ) {
2017-06-20 10:48:15 +00:00
connectOpts [ 'Promise' ] = Promise ;
return new Docker ( connectOpts ) ;
} ) ;
2017-03-29 11:03:40 +00:00
} ;
2017-08-10 19:40:05 +00:00
ensureDockerSeemsAccessible = function ( options ) {
var fs ;
fs = require ( 'mz/fs' ) ;
if ( options . socketPath != null ) {
return fs . access ( options . socketPath , fs . constants . R _OK | fs . constants . W _OK ) [ "return" ] ( true ) [ "catch" ] ( function ( err ) {
throw new Error ( "Docker seems to be unavailable (using socket " + options . socketPath + "). Is it installed, and do you have permission to talk to it?" ) ;
} ) ;
} else {
return Promise . resolve ( true ) ;
}
} ;
2017-05-04 12:00:48 +00:00
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 ) ;
} ;