Skip to content

Commit

Permalink
Generate script: Don't write .cc or .h files if unchanged
Browse files Browse the repository at this point in the history
The generation script now checks whether the file has changed before writing it to `/src` or `/include`. This is to improve compilation time when testing changes to generated code.

It works by creating a `/temp` directory, writing the generated code to `/temp/src` and `/temp/include`, then syncing those folders with `/src` and `/include` by deleting files  that no longer exist and copying files that have changed or been added since the last code generation. Finally the `/temp` directory is deleted

If `/src` and `/include` don't exist (i.e. it's the first time the generation script has been run), `/temp/src` will be copied to `/src` and `/temp/include` will be copied to `/include`.
  • Loading branch information
Kyle Smith committed Jul 26, 2016
1 parent 7cfcf99 commit 4c1a277
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 34 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
/lib/nodegit.js
/node_modules/
/src/
/temp/
/test/coverage/
/test/home/
/test/repos/
Expand Down
2 changes: 1 addition & 1 deletion generate/scripts/generateMissingTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = function generateMissingTests() {
var testFilePath = path.join(testFilesPath, idef.filename + ".js");
var result = {};

var file = utils.readFile(testFilePath);
var file = utils.readLocalFile(testFilePath);
if (file) {
var fieldsResult = [];
var functionsResult = [];
Expand Down
71 changes: 41 additions & 30 deletions generate/scripts/generateNativeCode.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,27 @@ module.exports = function generateNativeCode() {
};

var partials = {
asyncFunction: utils.readFile("templates/partials/async_function.cc"),
callbackHelpers: utils.readFile("templates/partials/callback_helpers.cc"),
convertFromV8: utils.readFile("templates/partials/convert_from_v8.cc"),
convertToV8: utils.readFile("templates/partials/convert_to_v8.cc"),
doc: utils.readFile("templates/partials/doc.cc"),
fields: utils.readFile("templates/partials/fields.cc"),
guardArguments: utils.readFile("templates/partials/guard_arguments.cc"),
syncFunction: utils.readFile("templates/partials/sync_function.cc"),
fieldAccessors: utils.readFile("templates/partials/field_accessors.cc"),
traits: utils.readFile("templates/partials/traits.h")
asyncFunction: utils.readLocalFile("templates/partials/async_function.cc"),
callbackHelpers: utils.readLocalFile("templates/partials/callback_helpers.cc"),
convertFromV8: utils.readLocalFile("templates/partials/convert_from_v8.cc"),
convertToV8: utils.readLocalFile("templates/partials/convert_to_v8.cc"),
doc: utils.readLocalFile("templates/partials/doc.cc"),
fields: utils.readLocalFile("templates/partials/fields.cc"),
guardArguments: utils.readLocalFile("templates/partials/guard_arguments.cc"),
syncFunction: utils.readLocalFile("templates/partials/sync_function.cc"),
fieldAccessors: utils.readLocalFile("templates/partials/field_accessors.cc"),
traits: utils.readLocalFile("templates/partials/traits.h")
};

var templates = {
class_content: utils.readFile("templates/templates/class_content.cc"),
struct_content: utils.readFile("templates/templates/struct_content.cc"),
class_header: utils.readFile("templates/templates/class_header.h"),
struct_header: utils.readFile("templates/templates/struct_header.h"),
binding: utils.readFile("templates/templates/binding.gyp"),
nodegitCC: utils.readFile("templates/templates/nodegit.cc"),
nodegitJS: utils.readFile("templates/templates/nodegit.js"),
enums: utils.readFile("templates/templates/enums.js")
class_content: utils.readLocalFile("templates/templates/class_content.cc"),
struct_content: utils.readLocalFile("templates/templates/struct_content.cc"),
class_header: utils.readLocalFile("templates/templates/class_header.h"),
struct_header: utils.readLocalFile("templates/templates/struct_header.h"),
binding: utils.readLocalFile("templates/templates/binding.gyp"),
nodegitCC: utils.readLocalFile("templates/templates/nodegit.cc"),
nodegitJS: utils.readLocalFile("templates/templates/nodegit.js"),
enums: utils.readLocalFile("templates/templates/enums.js")
};

var filters = {
Expand Down Expand Up @@ -99,28 +99,32 @@ module.exports = function generateNativeCode() {
return !idef.ignore;
});

const tempDirPath = path.resolve(__dirname, "../../temp");
const tempSrcDirPath = path.join(tempDirPath, "src");
const tempIncludeDirPath = path.join(tempDirPath, "include");

fse.remove(path.resolve(__dirname, "../../src")).then(function() {
return fse.remove(path.resolve(__dirname, "../../include"));
}).then(function() {
return fse.copy(path.resolve(__dirname, "../templates/manual/include"), path.resolve(__dirname, "../../include"));
const finalSrcDirPath = path.join(__dirname, '../../src');
const finalIncludeDirPath = path.join(__dirname, '../../include');

fse.remove(tempDirPath).then(function() {
return fse.copy(path.resolve(__dirname, "../templates/manual/include"), tempIncludeDirPath);
}).then(function() {
return fse.copy(path.resolve(__dirname, "../templates/manual/src"), path.resolve(__dirname, "../../src"));
return fse.copy(path.resolve(__dirname, "../templates/manual/src"), tempSrcDirPath);
}).then(function() {
// Write out single purpose templates.
utils.writeFile("../binding.gyp", beautify(templates.binding.render(enabled)), "binding.gyp");
utils.writeFile("../src/nodegit.cc", templates.nodegitCC.render(enabled), "nodegit.cc");
utils.writeFile("../temp/src/nodegit.cc", templates.nodegitCC.render(enabled), "nodegit.cc");
utils.writeFile("../lib/nodegit.js", beautify(templates.nodegitJS.render(enabled)), "nodegit.js");
// Write out all the classes.
enabled.forEach(function(idef) {
if (idef.type && idef.type != "enum") {
utils.writeFile(
"../src/" + idef.filename + ".cc",
"../temp/src/" + idef.filename + ".cc",
templates[idef.type + "_content"].render(idef),
idef.type + "_content.cc"
);
utils.writeFile(
"../include/" + idef.filename + ".h",
"../temp/include/" + idef.filename + ".h",
templates[idef.type + "_header"].render(idef),
idef.type + "_header.h"
);
Expand All @@ -133,17 +137,24 @@ module.exports = function generateNativeCode() {
if (astyle) {
return exec(
"astyle --options=\".astylerc\" "
+ path.resolve(__dirname, "../../src") + "/*.cc "
+ path.resolve(__dirname, "../../include") + "/*.h"
+ tempSrcDirPath + "/*.cc "
+ tempIncludeDirPath + "/*.h"
).then(function() {
return exec(
"rm "
+ path.resolve(__dirname, "../../src") + "/*.cc.orig "
+ path.resolve(__dirname, "../../include") + "/*.h.orig "
+ tempSrcDirPath + "/*.cc.orig "
+ tempIncludeDirPath + "/*.h.orig "
);
});
}
}, function() {})
}).then(function() {
return Promise.all([
utils.syncDirs(tempSrcDirPath, finalSrcDirPath),
utils.syncDirs(tempIncludeDirPath, finalIncludeDirPath),
]);
}).then(function() {
return fse.remove(tempDirPath);
}).catch(console.log);

};
Expand Down
84 changes: 82 additions & 2 deletions generate/scripts/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const fse = require("fs-extra");
const walk = require("walk");

const fs = require("fs");
const path = require("path");
Expand All @@ -10,7 +11,7 @@ var util = {
pointerRegex: /\s*\*\s*/,
doublePointerRegex: /\s*\*\*\s*/,

readFile: function(file) {
readLocalFile: function(file) {
try {
return fs.readFileSync(local(file)).toString();
}
Expand All @@ -19,6 +20,15 @@ var util = {
}
},

readFile: function(filePath) {
try {
return fs.readFileSync(filePath).toString();
}
catch (unhandledException) {
return "";
}
},

writeFile: function(file, content, header) {
try {
var file = local(file);
Expand Down Expand Up @@ -62,14 +72,84 @@ var util = {
}).join("");
},

getFilePathsRelativeToDir: function(dir) {
const files = [];
const walker = walk.walk(dir, { followLinks: false });
if (!util.isDirectory(dir)) {
return Promise.resolve([]);
}

return new Promise(function(resolve, reject) {
walker.on('file', function(root, stat, next) {
files.push(path.relative(dir, path.join(root, stat.name)));
next();
});

walker.on('end', function() {
resolve(files);
});

walker.on('errors', function() {
reject();
});
});
},

isFile: function(path) {
var isFile;
try {
isFile = fse.statSync(path).isFile();
} catch(e) {
isFile = false;
}

return isFile;
},

isDirectory: function(path) {
var isDirectory;
try {
isDirectory = fse.statSync(path).isDirectory();
} catch(e) {
isDirectory = false;
}

return isDirectory;
},

isPointer: function(type) {
return util.pointerRegex.test(type) || util.doublePointerRegex.test(type);
},

isDoublePointer: function(type) {
return util.doublePointerRegex.test(type);
}
},

syncDirs: function(fromDir, toDir) {
return Promise.all([
util.getFilePathsRelativeToDir(toDir),
util.getFilePathsRelativeToDir(fromDir)
]).then(function(filePaths) {
const toFilePaths = filePaths[0];
const fromFilePaths = filePaths[1];

// Delete files that aren't in fromDir
toFilePaths.forEach(function(filePath) {
if (!util.isFile(path.join(fromDir, filePath))) {
fse.remove(path.join(toDir, filePath));
}
});

// Copy files that don't exist in toDir or have different contents
fromFilePaths.forEach(function(filePath) {
const toFilePath = path.join(toDir, filePath);
const fromFilePath = path.join(fromDir, filePath);
if (!util.isFile(toFilePath) || util.readFile(toFilePath) !== util.readFile(fromFilePath)) {
fse.copy(fromFilePath, toFilePath);
}
});
});
}
};

module.exports = util;
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
"js-beautify": "~1.5.10",
"jshint": "~2.8.0",
"lcov-result-merger": "~1.0.2",
"mocha": "~2.3.4"
"mocha": "~2.3.4",
"walk": "^2.3.9"
},
"vendorDependencies": {
"libssh2": "1.6.0",
Expand Down

0 comments on commit 4c1a277

Please sign in to comment.