Execute method in parallel using async/await - javascript

I am working on building multiple languages when running a gradle command for an angular application.
Below is the code which is used to build all the localized files.
The buildAllLanguageVersion() method is called to build the language one by one by iterating over all the available build languages.
function buildAllLanguageVersion() {
return new Promise(async (accept, reject) => {
const doneLanguages = [];
const applicationBase = "APPNAME";
for (let language of buildLanguages) {
const ret = await buildingLanguage(language);
doneLanguages.push(ret);
}
accept(doneLanguages);
});
}
function buildingLanguage(buildLanguage) {
return new Promise(accept => {
console.log("Language building" + buildLanguage);
const languagePath = path.resolve(`./src/i18n/messages.${buildLanguage}.xlf`);
const languageFile = fs.existsSync(languagePath) ? buildLanguage : "en";
if (languageFile !== buildLanguage && !fs.existsSync(languagePath)) {
console.error(
"Language file does not exist." +
buildLanguage
);
}
exec.exec(`${folder} build --configuration=dynamic`, (error, stdout, stderror) => {
if (error) {
throw "Build failed: " + error;
}
accept(buildLanguage);
});
});
}
The above code is working fine when I have to build a language in a sequential order. And for a language to build it took almost 3-5 minutes. I am using 7 different languages for now in the application.
My question is how I can call the method in parallel so that I can reduce the build time.
So far i have tried Promise.all() in the method buildAllLanguageVersion() to call the method buildingLanguage() in parallel, but that didn't help. The methods are getting called at a time(in parallel) but the build is getting failed with below error.
14:31:17 D:\ls\workspace\Generic_commit\APP\app-name\tools\build-all.js:129
14:31:17 throw "Build failed: " + error;
14:31:17 ^
14:31:17 Build failed: Error: Command failed: D:\ls\workspace\Generic_commit\APP\app-name\node_modules\.bin\ng.cmd build --configuration=dynamic
14:31:17
14:31:17 ERROR in ngcc is already running at process with id 5252.
14:31:17 If you are running multiple builds in parallel then you should pre-process your node_modules via the command line ngcc tool before starting the builds;
14:31:17 See https://v9.angular.io/guide/ivy#speeding-up-ngcc-compilation.
14:31:17 (If you are sure no ngcc process is running then you should delete the lock-file at D:/ls/workspace/Generic_commit/APP/app-name/node_modules/#angular/compiler-cli/ngcc/_ngcc_lock_file_.)
I tried removing the _ngcc_lock_file_ but that didn't help.

Related

How to wait until vscode.windows.terminal operation is over?

When I execute a testing witch need the ending result of a vscode.windows.terminal the testing gave me a false positive. I need wait until the terminal operation end in order to execute the asserts.
I use a class named Stack witch have a pom file. My test start with the execution of cd and mvn clean install using the vscode.windows.terminal. The idea of the test assertion is verify the existence of the target file.
const buildProgram = () => {
const terminal = vscode.window.createTerminal();
terminal.show();
terminal.sendText('cd ' + stackDirectory);
terminal.sendText('mvn clean install');
}
it("Stack Project build taget directory exists", function() {
const promise = Promise.all([buildProgram()])
.then(() => {
return fs.existsSync(stackDirectory + "/target");
});
expect(promise).to.eventually.equal(false);
});
This test runs without problem but in the end the target directory is not created.
Here is a function which listens for terminal exit then resolves promise. Essensially we sendText(yourCommandHere+";exit") such that the terminal exits after executing your command, and then listen for that exit.
Additionally, I would believe that when sending multiple commands its better to send them on one line, eg: terminal.sendText(command+";", false); terminal.sendText(command2+";exit") such that we assure the commands are run in the correct order.
export async function callInInteractiveTerminal(
command: string,
shellPath?: string,
name?: string,
location?: vscode.TerminalLocation
): Promise<vscode.TerminalExitStatus> {
const terminal = vscode.window.createTerminal({
shellPath,
name,
location: location ? location : vscode.TerminalLocation.Panel,
});
terminal.show();
terminal.sendText(command, false);
terminal.sendText("; exit");
return new Promise((resolve, reject) => {
const disposeToken = vscode.window.onDidCloseTerminal(
async (closedTerminal) => {
if (closedTerminal === terminal) {
disposeToken.dispose();
if (terminal.exitStatus !== undefined) {
resolve(terminal.exitStatus);
} else {
reject("Terminal exited with undefined status");
}
}
}
);
});
}
After further research it seems this function only works when terminalLocation is TerminalLocation.Panel, not TerminalLocation.Editor.
I'm also a little worried that a fast command might have the exit run before the eventlistener starts, but it works for my use case since i only use it when the terminal needs human interaction.
I find a possible solution replacing the test for this:
it("Stack Project build taget directory exists", function() {
buildProgram();
return new Promise((resolve, reject) => setTimeout(function(){
// Assert here.
if(fs.existsSync(stackDirectory + "/target")){
resolve();
}
reject();
}, 5000));
}).timeout('7s');
I don't really like the idea of using timeout but I don't find a way to say if the terminal is busy.

gulp-git: Using push results in a stream error

I'm trying to push to my remote repository using the gulp-git module from npm. The add & commit portion runs fine, but it runs into a stream error when trying to perform the remote push.
bump: function () {
var branch = argv.branch || 'development';
fs.readFile('./package.json', function (err, data) {
if (err) { return ; }
return gulp.src(['./package.json', './bower.json'])
.pipe(git.add())
.pipe(git.commit('chore(core): bump to ' + JSON.parse(data).version))
.pipe(git.push('origin', branch, function(err) {
if(err) throw (err);
}));
});
}
The stack trace:
C:\src\git\ig\node_modules\gulp-git\node_modules\through2\node_modules\readable-stream\lib_stream_readable.js:623
var written = dest.write(chunk);
^
TypeError: undefined is not a function
at write (C:\src\git\ig\node_modules\gulp-git\node_modules\through2\node_modules\readable-stream\lib_stream_readable.js:623:24)
at flow (C:\src\git\ig\node_modules\gulp-git\node_modules\through2\node_modules\readable-stream\lib_stream_readable.js:632:7)
at DestroyableTransform.pipeOnReadable (C:\src\git\ig\node_modules\gulp-git\node_modules\through2\node_modules\readable-stream\lib_stream_readable.js:664:5)
at DestroyableTransform.emit (events.js:104:17)
at emitReadable_ (C:\src\git\ig\node_modules\gulp-git\node_modules\through2\node_modules\readable-stream\lib_stream_readable.js:448:10)
at emitReadable (C:\src\git\ig\node_modules\gulp-git\node_modules\through2\node_modules\readable-stream\lib_stream_readable.js:444:5)
at readableAddChunk (C:\src\git\ig\node_modules\gulp-git\node_modules\through2\node_modules\readable-stream\lib_stream_readable.js:187:9)
at DestroyableTransform.Readable.push (C:\src\git\ig\node_modules\gulp-git\node_modules\through2\node_modules\readable-stream\lib_stream_readable.js:149:10)
at DestroyableTransform.Transform.push (C:\src\git\ig\node_modules\gulp-git\node_modules\through2\node_modules\readable-stream\lib_stream_transform.js:145:32)
at Array.forEach (native)
I'm running gulp-git version 1.6.0. It looks like they are at 1.7.0. Maybe the upgrade path would help however this seems like a pretty standard usage of the command, so I think it's something I'm doing wrong.
With help from stevelacy (the project admin) I was able to make it work with this code change:
.pipe(git.commit('chore(core): bump to ' + JSON.parse(data).version))
.on('end', function() {
git.push('origin', branch, function(err) {
if(err) throw (err);
});
});
It turns out that the git push command cannot be done from a stream as of yet.

Nicely throwing an error in gulp task

I am creating a gulp task which might fail under certain circumstances.
gulp.task('favicon', function () {
try {
require('child_process').execSync('icotool --version');
} catch( e ) {
var err = new Error( 'Unix bash and icotool required for generating favicon' );
throw err;
}
return gulp.src('', {read: false})
.pipe(shell([
'./generate-favicon.sh'
]));
});
When running my task via gulp and running into the error, the error will be presented rather ugly.
I would like to present the error in a way as it is done by e.g. jslint gulp-util's PluginError.
It actually works to just create a PluginError there and throw it but that doesn't seem quite right.
Another solution not that nice would be to set
err.showStack = false;
for at least a little nicer error output. A gulp.task.Error would be nice.
From what I've seen its not great to throw an error from gulp. But I found this blog entry that I used to work for me.
http://gotofritz.net/blog/geekery/how-to-generate-error-in-gulp-task/
Edit: gulp-util has been deprecated. Instead, use the plugin-error package.
My Example:
var gulp = require('gulp');
var error = require('plugin-error');
gulp.task('deploy', function(cb) {
if(typeof(specialId) === 'undefined') {
var err = new PluginError({
plugin: 'deploy',
message: 'specialId is empty.'
});
}
}

Performing command line actions synchronously after Yeoman generator has finished

I'm building a Yeoman generator and after it has finished I want to perform some command line actions like 'npm install', 'bower install' and 'grunt less'. I'm using spawnCommand for this and I nested all actions using event listeners to perform them synchronously. However, to avoid this endless nesting, I'm looking for a cleaner implementation, to make it easily expandable.
Perfectly, I would like to have an array with commands (like ['npm install', 'grunt install', 'less:dev']) and have this processed synchronously with proper error detection.
// Install npm packages
this.spawnCommand('npm', ['install'])
.on('exit', function (err) {
if (err) {
this.log.error('npm package installation failed. Please run \'npm install\' and \'bower install\'. Error: ' + err);
} else {
// Install bower packages
this.spawnCommand('bower', ['install'])
.on('exit', function (err) {
if (err) {
this.log.error('bower package installation failed. Please run \'bower install\'. Error: ' + err);
} else {
this.spawnCommand('grunt', ['less'])
.on('exit', function (err) {
if (err) {
this.log.error('Less compilation failed. Please run \'grunt less:dev\'. Error: ' + err);
} else {
}
}.bind(this));
}
}.bind(this));
}
}.bind(this));
Something like this? (untested though):
this.processTask = function (task) {
this.spawnCommand(task.cmd, task.args)
.on('exit', function (err) {
if (err) {
this.log.error('task failed. Error: ' + err);
} else {
this.emit('nextTask');
}
});
};
this.on('nextTask' function(){
var next = this.tasks.shift();
if (next){
this.processTask(next);
} else {
console.log('we are done');
}
}.bind(this));
//preparing the list of tasks:
this.tasks = [];
this.tasks.push({cmd: 'npm', args:['install']});
this.tasks.push({cmd: 'bower', args:['install']});
this.tasks.push({cmd: 'grunt', args:['less']});
//start first task
this.processTask(this.tasks.shift());
I used execSync from Node.js and it seems to work, eg:
var child_process = require('child_process');
var result = execSync('grunt less');
Node.js 0.12 and io.js 1.10 support execSync:
child_process.execSync(command[, options])
and returns, "Buffer|String The stdout from the command", which may be an error code.
API documentation.
The back story about the synchronous API.
You can make a script like init.sh and put your commands that need to be run in order in it, like:
#!/usr/bin/env bash
npm install
your-funky-command
gulp something-special
gulp
...then wherever you need to put the spawnCommand code (I do it in end method), add somehting like this:
var done = this.async();
this.spawnCommand('sh', ['init.sh'], /* maybe cwd? {cwd: 'src'} */)
.on('close', done);
Ain't pretty or anything but it works, and it's obvious.
Optionally, if you need one command to only run if the prev succeeded, do this:
#!/usr/bin/env bash
npm install \
&& your-funky-command \
&& gulp something-special \
&& gulp
(Bonus advantage is that now your app init logic is no longer tied to Yo.)

Testing node application with Mocha and Should

I am javascript+node beginner and also relatively new to asynchronous programming style. I am comfortable with Ruby and Rails and now trying to teach myself node.
I am working on a node app where I need to fetch data from Facebook for which I am using the 'facebook-api' node package.
I am using a BDD approach ( newcomer here as well, never used rspec much in ruby) with mocha + should.js.
Here is some of the early code I have written:
lib/facebook_adapter.js
var raw = require('facebook-api').raw;
function getFacebookData(facebookpage,callback)
{
raw("GET",facebookpage,[],function(error,data){
if (error)
{
conosle.log(error);
}
else
{
var facebook_data = {};
facebook_data.likes = data.likes;
facebook_data.talking_about = data.talking_about;
}
callback(facebook_data);
});
}
module.exports = {
'getFacebookData' : getFacebookData
};
test/facebook.test.js
'use strict';
var assert = require('assert')
,should = require('should')
,facebook_adapter = require('../lib/facebook_adapter');
describe('FacebookAdapter',function(){
it('should fetch the like and followcount for a brand name from Graph API',function(done){
facebook_adapter.getFacebookData('Edelman', function(facebook_data){
for ( var prop in facebook_data)
{
console.log('meoww');
facebook_data[prop].should.be.a('number');
}
done();
});
});
});
To execute mocha test, I have a makefile in the root directory of the express application. Here is the content:
test:
#./node_modules/.bin/mocha -u tdd
.PHONY: test
Now, when executing the tests, I always end up with the error:
․․․meoww
meoww
․․
✖ 2 of 4 tests failed:
1) FacebookAdapter should fetch the like and followcount for a brand name from Graph API:
Error: global leaks detected: data_array, parsed
at Runner.checkGlobals (/Users/myth/Learn/Code/Projects/socialindex/node_modules/mocha/lib/runner.js:167:21)
at Runner.<anonymous> (/Users/myth/Learn/Code/Projects/socialindex/node_modules/mocha/lib/runner.js:58:44)
at Runner.EventEmitter.emit (events.js:126:20)
at Runner.uncaught (/Users/myth/Learn/Code/Projects/socialindex/node_modules/mocha/lib/runner.js:466:10)
at process.Runner.run (/Users/myth/Learn/Code/Projects/socialindex/node_modules/mocha/lib/runner.js:508:10)
at process.EventEmitter.emit (events.js:126:20)
2) FacebookAdapter should fetch the like and followcount for a brand name from Graph API:
Error: global leaks detected: data_array, parsed
at Runner.checkGlobals (/Users/myth/Learn/Code/Projects/socialindex/node_modules/mocha/lib/runner.js:167:21)
at Runner.<anonymous> (/Users/myth/Learn/Code/Projects/socialindex/node_modules/mocha/lib/runner.js:58:44)
at Runner.EventEmitter.emit (events.js:126:20)
at Runner.uncaught (/Users/myth/Learn/Code/Projects/socialindex/node_modules/mocha/lib/runner.js:466:10)
at process.Runner.run (/Users/myth/Learn/Code/Projects/socialindex/node_modules/mocha/lib/runner.js:508:10)
at process.EventEmitter.emit (events.js:126:20)
Why is the test executing twice? I dont also seem to be misusing any globals as well. Why the error?

Categories