Skip to content

Commit e6993a4

Browse files
authored
Allow configuring the number of threads (#173)
1 parent e2c896d commit e6993a4

5 files changed

Lines changed: 93 additions & 8 deletions

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ When combined with a watching task (such as [grunt-contrib-watch][watch]), even
3737

3838
## Options
3939

40+
### `threads`
41+
42+
* Type: `String`, `Boolean`, `Number`
43+
* Default: `auto`, which is the number of threads -1
44+
45+
Use this option to control the number of threads that grunt-htmllint will use when validating a big number of files. This will spawn as many Java processes as the number of threads.
46+
4047
### `ignore`
4148

4249
* Type: `Array`, `String`, or `RegExp`

lib/getThreads.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict';
2+
3+
const os = require('os');
4+
5+
// eslint-disable-next-line unicorn/explicit-length-check
6+
const CPUS = os.cpus() && os.cpus().length;
7+
const THREADS = CPUS > 2 ? CPUS - 1 : 1;
8+
9+
function getThreads(config) {
10+
const { threads } = config;
11+
12+
switch (threads) {
13+
case 'auto':
14+
case -1:
15+
case '':
16+
case true:
17+
case null:
18+
case undefined:
19+
return THREADS;
20+
case 0:
21+
case 1:
22+
case false:
23+
return 1;
24+
default:
25+
if (threads > 1) {
26+
return threads;
27+
}
28+
}
29+
}
30+
31+
module.exports = getThreads;

lib/htmllint.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
'use strict';
22

3-
const os = require('os');
43
const path = require('path');
54
const { execFile } = require('child_process');
65
const async = require('async');
76
const chunkify = require('./chunkify.js');
8-
const javaDetect = require('./javaDetect.js');
7+
const getThreads = require('./getThreads.js');
98
const javaArgs = require('./javaArgs.js');
9+
const javaDetect = require('./javaDetect.js');
1010
const parseErrorMessages = require('./parseErrorMessages.js');
1111
const processErrorMessages = require('./processErrorMessages.js');
1212

@@ -20,10 +20,6 @@ const MAX_CHARS = 5000;
2020
*/
2121
const MAX_BUFFER = 20_000 * 1024;
2222

23-
// eslint-disable-next-line unicorn/explicit-length-check
24-
const CPUS = os.cpus() && os.cpus().length;
25-
const THREADS = CPUS > 2 ? CPUS - 1 : 1;
26-
2723
function htmllint(config, done) {
2824
if (config.files.length === 0) {
2925
return done(null, []);
@@ -42,8 +38,9 @@ function htmllint(config, done) {
4238

4339
const files = config.files.map(file => path.normalize(file));
4440
const chunks = chunkify(files, MAX_CHARS);
41+
const threads = getThreads(config);
4542

46-
async.mapLimit(chunks, THREADS, (chunk, cb) => {
43+
async.mapLimit(chunks, threads, (chunk, cb) => {
4744
const args = javaArgs(java, chunk, config);
4845

4946
execFile('java', args, { maxBuffer: MAX_BUFFER, shell: true }, (error, stdout, stderr) => {

tasks/html.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ module.exports = grunt => {
2121
force: false,
2222
absoluteFilePathsForReporter: false,
2323
errorlevels: ['info', 'warning', 'error'],
24-
noLangDetect: false
24+
noLangDetect: false,
25+
threads: 'auto'
2526
});
2627
const { force } = options;
2728
let { reporterOutput } = options;

test/threads_test.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
3+
const assert = require('assert').strict;
4+
const os = require('os');
5+
const getThreads = require('../lib/getThreads.js');
6+
7+
// eslint-disable-next-line unicorn/explicit-length-check
8+
const CPUS = os.cpus() && os.cpus().length;
9+
const THREADS = CPUS > 2 ? CPUS - 1 : 1;
10+
11+
describe('getThreads', () => {
12+
it('should use the number of available threads -1', done => {
13+
const config = {};
14+
15+
for (const option of ['auto', -1, '', true, null, undefined]) {
16+
config.threads = option;
17+
const expected = THREADS;
18+
const actual = getThreads(config);
19+
20+
assert.equal(actual, expected, `"thread: ${option}" failed!`);
21+
}
22+
23+
done();
24+
});
25+
26+
it('should return 1 with false, 0, or 1', done => {
27+
const config = {};
28+
29+
for (const option of [0, 1, false]) {
30+
config.threads = option;
31+
const expected = 1;
32+
const actual = getThreads(config);
33+
assert.equal(actual, expected);
34+
}
35+
36+
done();
37+
});
38+
39+
it('should return the number of threads', done => {
40+
const config = {
41+
threads: 4
42+
};
43+
const expected = 4;
44+
const actual = getThreads(config);
45+
46+
assert.equal(actual, expected);
47+
done();
48+
});
49+
});

0 commit comments

Comments
 (0)