OLD | NEW |
| (Empty) |
1 #!/usr/bin/env node | |
2 'use strict'; | |
3 | |
4 var fs = require('fs'); | |
5 var os = require('os'); | |
6 var path = require('path'); | |
7 var spawn = require('child_process').spawn; | |
8 var globby = require('globby'); | |
9 var async = require('async'); | |
10 | |
11 var VERSION = '1.0.45'; | |
12 var LOCATION = __filename; | |
13 var CLANG_FORMAT_NODE_MODULES_PATH = path.resolve(__dirname, '..', '..', 'node_m
odules', 'clang-format'); | |
14 | |
15 /** | |
16 * Start a child process running the native clang-format binary. | |
17 * @param file a Vinyl virtual file reference | |
18 * @param enc the encoding to use for reading stdout | |
19 * @param style valid argument to clang-format's '-style' flag | |
20 * @param done callback invoked when the child process terminates | |
21 * @returns {Stream} the formatted code | |
22 */ | |
23 function clangFormat(file, enc, style, done) { | |
24 var args = ['-style=' + style, file.path]; | |
25 return spawnClangFormat(args, done, ['ignore', 'pipe', process.stderr]).stdout
; | |
26 } | |
27 | |
28 /** | |
29 * Spawn the clang-format binary with given arguments. | |
30 */ | |
31 function spawnClangFormat(args, done, stdio) { | |
32 // WARNING: This function's interface should stay stable across versions for t
he cross-version | |
33 // loading below to work. | |
34 if (args.indexOf('-version') !== -1 || args.indexOf('--version') !== -1) { | |
35 // Print our version. | |
36 // This makes it impossible to format files called '-version' or '--version'
. That's a feature. | |
37 // minimist & Co don't support single dash args, which we need to match bina
ry clang-format. | |
38 console.log('clang-format NPM version', VERSION, 'at', LOCATION); | |
39 process.exit(0); | |
40 } | |
41 var nativeBinary; | |
42 if (os.platform() === 'win32') | |
43 nativeBinary = CLANG_FORMAT_NODE_MODULES_PATH + '/bin/win32/clang-format.exe
'; | |
44 else | |
45 nativeBinary = CLANG_FORMAT_NODE_MODULES_PATH + '/bin/' + os.platform() + '_
' + os.arch() + '/clang-format'; | |
46 | |
47 if (!fs.existsSync(nativeBinary)) { | |
48 message = 'FATAL: This module doesn\'t bundle the clang-format executable fo
r your platform. ' + | |
49 '(' + os.platform() + '_' + os.arch() + ')\n' + | |
50 'Consider installing it with your native package manager instead.\n'; | |
51 throw new Error(message); | |
52 } | |
53 | |
54 // extract glob, if present | |
55 var globString = args.filter(function(arg) { | |
56 return arg.indexOf('--glob=') === 0; | |
57 }) | |
58 .map(function(arg) { | |
59 return arg.replace('--glob=', ''); | |
60 }) | |
61 .shift(); | |
62 | |
63 // extract ignore, if present | |
64 var ignore = args.filter(function(arg) { | |
65 return arg.indexOf('--ignore=') === 0; | |
66 }) | |
67 .map(function(arg) { | |
68 return arg.replace('--ignore=', ''); | |
69 }) | |
70 .shift(); | |
71 | |
72 if (globString) { | |
73 var globs = globString.split(','); | |
74 // remove glob and ignore from arg list | |
75 args = args.filter(function(arg) { | |
76 return arg.indexOf('--glob=') === -1; | |
77 }) | |
78 .filter(function(arg) { | |
79 return arg.indexOf('--ignore=') === -1; | |
80 }); | |
81 | |
82 var options = {}; | |
83 if (ignore) | |
84 options.ignore = ignore.split(','); | |
85 | |
86 | |
87 return globby(globs, options).then(function(files) { | |
88 // split file array into chunks of 30 | |
89 var i, j, chunks = [], chunkSize = 30; | |
90 for (i = 0, j = files.length; i < j; i += chunkSize) | |
91 chunks.push(files.slice(i, i + chunkSize)); | |
92 | |
93 | |
94 // launch a new process for each chunk | |
95 async.series( | |
96 chunks.map(function(chunk) { | |
97 return function(callback) { | |
98 var clangFormatProcess = spawn(nativeBinary, args.concat(chunk), {
stdio: stdio}); | |
99 clangFormatProcess.on('close', function(exit) { | |
100 if (exit !== 0) | |
101 callback(exit); | |
102 else | |
103 callback(null, exit); | |
104 }); | |
105 }; | |
106 }), | |
107 function(err, results) { | |
108 if (err) | |
109 done(err); | |
110 console.log('\n'); | |
111 console.log('ran clang-format on', files.length, files.length === 1
? 'file' : 'files'); | |
112 done(results.shift() || 0); | |
113 }); | |
114 }); | |
115 } else { | |
116 var clangFormatProcess = spawn(nativeBinary, args, {stdio: stdio}); | |
117 clangFormatProcess.on('close', function(exit) { | |
118 if (exit) | |
119 done(exit); | |
120 }); | |
121 return clangFormatProcess; | |
122 } | |
123 } | |
124 | |
125 function main() { | |
126 try { | |
127 // Pass all arguments to clang-format, including e.g. -version etc. | |
128 spawnClangFormat(process.argv.slice(2), process.exit, 'inherit'); | |
129 } catch (e) { | |
130 process.stdout.write(e.message); | |
131 process.exit(1); | |
132 } | |
133 } | |
134 | |
135 module.exports = clangFormat; | |
136 module.exports.version = VERSION; | |
137 module.exports.location = LOCATION; | |
138 module.exports.spawnClangFormat = spawnClangFormat; | |
139 | |
140 if (require.main === module) | |
141 main(); | |
OLD | NEW |