angular-cn/tools/build/proto.js

124 lines
4.4 KiB
JavaScript

var fs = require('fs');
var glob = require('glob');
var hashFiles = require('hash-files');
var path = require('path');
var protocDetect = require('./protoc').detect;
var spawn = require('child_process').spawn;
// Hashs all .proto files at `config.dir`, calling `computedCallback` on each
// when done with the original file name and its hash.
// When all files have been hashed, calls `completeCallback` with no parameters.
function _hashProtosTask(config, computedCallback, completeCallback) {
var files = glob.sync(path.join(config.dir, '*.proto'));
var toUpdate = {};
var checkComplete = function() {
for (var key in toUpdate) {
if (toUpdate.hasOwnProperty(key) && toUpdate[key]) {
return false;
}
}
return true;
};
files.forEach(function(file) { toUpdate[file] = true; });
files.forEach(
function(file) {
hashFiles({
algorithm: config.algorithm || 'sha1',
files: [file]
}, function(error, hash) {
computedCallback(file, hash);
toUpdate[file] = false;
if (checkComplete()) {
completeCallback();
}
});
});
}
function _toPbDartExtension(path) {
return path.replace(/\.proto$/, '.pb.dart');
}
module.exports = {
// Generates `.pb.dart` files from all `.proto` files located at `config.dir`.
// This task requires the Dart protoc plugin, which is expected to reside at
// the path specified in `config.plugin`.
generate: function(config, done) {
// Note that while the Dart protoc plugin requires the Dart sdk, this task will be skipped if the
// Dart sdk is not available.
var protoc = protocDetect();
if (!protoc) {
done(new Error('Could not detect protoc - failed to rebuild Dart proto code.'));
return;
}
var protoPaths = glob.sync(path.join(config.dir, '*.proto'));
var spawnArgs = [
'--plugin', config.plugin,
'--proto_path', config.dir,
'--dart_out', config.dir,
].concat(protoPaths);
var proc = spawn(protoc.bin, spawnArgs, {
cwd: '.',
stdio: ['ignore', 2, 'inherit']
});
var failed = false;
var failWithError = function(msg) {
if (failed) return;
failed = true;
done(new Error('Failed while generating transformer boilerplate. Check for output above.\n' +
'Message: ' + msg + '\n' +
'Please run manually: ' + [protoc.bin].concat(spawnArgs).join(' ')));
};
proc.on('error', function(err) { failWithError(String(err)); });
proc.on('exit', function(code, signal) {
if (!code) {
var protocHash = hashFiles.sync({
algorithm: config.algorithm || 'sha1',
files: [config.plugin]
});
var computedCallback = function(fileName, hash) {
var pbDartPath = _toPbDartExtension(fileName);
var toAppend = '/**\n' +
' * Generated with:\n' +
' * ' + path.basename(fileName) + ' (' + hash + ')\n' +
' * ' + protoc.version + '\n' +
' * dart-protoc-plugin (' + protocHash + ')\n' +
' */\n';
fs.appendFileSync(pbDartPath, toAppend);
};
return _hashProtosTask(config, computedCallback, function() { done(); });
} else {
failWithError('Exit code was ' + code);
}
});
},
// Checks that the `.pb.dart` files located at `config.dir` are in sync with
// the `proto` files at the same directory.
// It does this by computing the hash of the `.proto` files and looking for
// that string in the contents of the associated `.pb.dart` file. If one or
// more file(s) do not have that hash present, this task will fail with a
// descriptive error message.
lint: function(config, done) {
var missing = [];
var computedCallback = function(filePath, hash) {
var pbDartPath = _toPbDartExtension(filePath);
if (String(fs.readFileSync(pbDartPath)).indexOf(hash) < 0) {
missing.push(' ' + hash + ' not found in ' + pbDartPath + '\n');
}
};
var completeCallback = function() {
if (missing.length == 0) {
done();
} else {
done(new Error(
'Generated Dart protobuf files are out of date. Please run `gulp gen_protos.dart`.\n' +
missing.join(''))
);
}
};
return _hashProtosTask(config, computedCallback, completeCallback);
}
};