Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 99 additions & 29 deletions lib/decking.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,46 +167,116 @@ Decking.prototype._build = function(image, done) {
if(!target) {
throw new Error("Image " + image + " does not exist in decking.json");
}

var targetPath = target + "/Dockerfile";
this.logger.log("Building image " + image + " from " + targetPath);
var targetDir = (typeof target ==="string" ? target : target.path);
var targetPath = targetDir + "/Dockerfile";

// @TODO for now, always assume we want to build from a Dockerfile
// @TODO need a lot of careful validation here
var readStream = fs.createReadStream(targetPath);
var writeStream = fs.createWriteStream("./Dockerfile");
var self = this;
var buildDep = false;

// ensure we don't try and create the tarball until the local Dockerfile exists
writeStream.on("close", function() {
var options = {t: image};
if(self.hasArg("--no-cache")) {
self.logger.log("Not using image cache");
options.nocache = true;
if(self.hasArg("--no-dependencies")) {
self.logger.log("Not building dependencies");
} else {
// Detecting local dependency
var dockerfileContent = fs.readFileSync(targetPath);
var fromRe = /^\s*from\s*(\S*)/i;
var fromMatch = fromRe.exec(dockerfileContent);
if (fromMatch) {
var dependency = fromMatch[1];
if (this.config.images[dependency]) {
// the dependency is declared in the local images, let's build that one first
buildDep = true;
self.logger.log("Found dependency : " + dependency);
self._build(dependency, function(err) {
if (err) return done(err);
continueFn();
});
}
}
}

self.logger.log("Uploading compressed context...");
if (!buildDep) continueFn();

// @TODO allow user to specifiy --exclude params to avoid unnecessarily huge tarballs
var tar = child_process.spawn("tar", ["-c", "-", "./"]);
function continueFn() {
self.logger.log("Building image " + image + " from " + targetPath);

return self.docker.buildImage(tar.stdout, options, function(err, res) {
fs.unlink("./Dockerfile", function(err) {
if(err) return self.logger.log("[WARN] Could not remove Dockerfile");
});
if(err) return done(err);
if(res.headers["content-type"] === "application/json") {
res.pipe(JSONStream.parse("stream")).pipe(process.stdout);
} else {
// we don't need an if/else but let's keep it for clarity; it'd be too easy to
// skim-read the code and misinterpret the first pipe otherwise
res.pipe(process.stdout);
var buildIn = "current-dir";
// default with what's passed on build command
if (self.hasArg("--build-in-dockerfile-dir")) {
buildIn = "dockerfile-dir";
} else if (self.hasArg("--build-in-current-dir")) {
buildIn = "current-dir";
}
if (typeof target !== "string") {
// taking into account override option in the image definition
buildIn = target["build-in"];
}

function build() {
var options = {t: image};
if(self.hasArg("--no-cache")) {
self.logger.log("Not using image cache");
options.nocache = true;
}
return res.on("end", done);
});
});

readStream.pipe(writeStream);
self.logger.log("Uploading compressed context...");

// @TODO allow user to specifiy --exclude params to avoid unnecessarily huge tarballs
var tarOptions = (buildIn === "dockerfile-dir" ? {cwd: targetDir} : null);
var tar = child_process.spawn("tar", ["-c", "-", "./"], tarOptions);

return self.docker.buildImage(tar.stdout, options, function(err, res) {
if (buildIn === "current-dir") {
fs.unlink("./Dockerfile", function(err) {
if(err) return self.logger.log("[WARN] Could not remove Dockerfile");
});
}
if(err) return done(err);
if(res.headers["content-type"] === "application/json") {
res.pipe(JSONStream.parse("stream")).pipe(process.stdout);
} else {
// we don't need an if/else but let's keep it for clarity; it'd be too easy to
// skim-read the code and misinterpret the first pipe otherwise
res.pipe(process.stdout);
}
var data, error;
res.on("error", done);
res.on("data", function(raw) {
data = (data ? data : '') + raw.toString();
try {
var jsonData = JSON.parse(data);
} catch (e) {
return;
}
if (!jsonData.stream && jsonData.error) {
error = jsonData.error;
}
data = undefined;
});
return res.on("end", function() {
if (error) {
error = new Error("Docker build error: " + error);
}
done(error);
});
});
}

if (buildIn === "current-dir") {
var readStream = fs.createReadStream(targetPath);
var writeStream = fs.createWriteStream("./Dockerfile");

// ensure we don't try and create the tarball until the local Dockerfile exists
writeStream.on("close", function() {
build();
});

readStream.pipe(writeStream);
} else if (buildIn === "dockerfile-dir") {
build();
}
}
};

// ----------
Expand Down