Skip to content
Open
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
99 changes: 73 additions & 26 deletions lib/decking.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,44 +169,91 @@ Decking.prototype._build = function(image, done) {
}

var targetPath = target + "/Dockerfile";
this.logger.log("Building image " + image + " from " + targetPath);

// @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 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() {
var options = {t: image};
if(self.hasArg("--no-cache")) {
self.logger.log("Not using image cache");
options.nocache = true;
}
return res.on("end", done);

self.logger.log("Uploading compressed context...");

// @TODO allow user to specifiy --exclude params to avoid unnecessarily huge tarballs
var tar = child_process.spawn("tar", ["-c", "-", "./"]);

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 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);
});
});
});
});

readStream.pipe(writeStream);
readStream.pipe(writeStream);
}
};

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