Skip to content

Commit e7f3e25

Browse files
committed
feat: adopt google-java-format 1.35.0 and chunk large file lists
Chunk positional .java args into batches of 30 (matching --glob= behaviour) so xargs invocations with many files do not rely on a single JVM process.
1 parent bc95339 commit e7f3e25

1 file changed

Lines changed: 79 additions & 88 deletions

File tree

index.js

Lines changed: 79 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,75 @@ const LOCATION = __dirname;
1414

1515
// Glob pattern option name
1616
const GLOB_OPTION = "--glob=";
17+
const CHUNK_SIZE = 30;
1718

1819
function errorFromExitCode(exitCode) {
1920
return new Error(`google-java-format exited with exit code ${exitCode}.`);
2021
}
2122

23+
function isJavaFile(arg) {
24+
return !arg.startsWith("-") && arg.endsWith(".java");
25+
}
26+
27+
function splitJarArgs(args) {
28+
if (args[0] === "-jar") {
29+
return {
30+
prefix: args.slice(0, 2),
31+
rest: args.slice(2),
32+
};
33+
}
34+
return { prefix: [], rest: args };
35+
}
36+
37+
function splitFlagsAndFiles(args) {
38+
const flags = [];
39+
const files = [];
40+
for (const arg of args) {
41+
if (isJavaFile(arg)) files.push(arg);
42+
else flags.push(arg);
43+
}
44+
return { flags, files };
45+
}
46+
47+
function runSpawn(nativeBinary, args, stdio, done) {
48+
const proc = spawn(nativeBinary, args, { stdio: stdio });
49+
proc.on("close", function (exit) {
50+
if (exit) done(errorFromExitCode(exit));
51+
else done();
52+
});
53+
return proc;
54+
}
55+
56+
function runChunks(nativeBinary, prefix, flags, files, stdio, done) {
57+
const chunks = [];
58+
for (let i = 0; i < files.length; i += CHUNK_SIZE) {
59+
chunks.push(files.slice(i, i + CHUNK_SIZE));
60+
}
61+
62+
async.series(
63+
chunks.map((chunk) => (callback) => {
64+
runSpawn(nativeBinary, prefix.concat(flags, chunk), stdio, callback);
65+
}),
66+
(err) => {
67+
if (err) {
68+
done(err);
69+
return;
70+
}
71+
if (files.length > 1) {
72+
console.log("\n");
73+
console.log(
74+
`ran google-java-format on ${files.length} ${
75+
files.length === 1 ? "file" : "files"
76+
}`
77+
);
78+
}
79+
done();
80+
}
81+
);
82+
}
83+
2284
/**
2385
* Starts a child process running the native google-java-format binary.
24-
*
25-
* @param file a Vinyl virtual file reference
26-
* @param enc the encoding to use for reading stdout
27-
* @param style valid argument to google-java-format's '-style' flag
28-
* @param done callback invoked when the child process terminates
29-
* @returns {stream.Readable} the formatted code as a Readable stream
3086
*/
3187
function googleJavaFormat(file, enc, style, done) {
3288
let args = [`-style=${style}`, file.path];
@@ -36,22 +92,16 @@ function googleJavaFormat(file, enc, style, done) {
3692
process.stderr,
3793
]);
3894
if (result) {
39-
// must be ChildProcess
4095
result.stdout.setEncoding(enc);
4196
return result.stdout;
42-
} else {
43-
// We shouldn't be able to reach this line, because it's not possible to
44-
// set the --glob arg in this function.
45-
throw new Error("Can't get output stream when --glob flag is set");
4697
}
98+
throw new Error("Can't get output stream when --glob flag is set");
4799
}
48100

49101
/**
50102
* Spawn the google-java-format binary with given arguments.
51103
*/
52104
function spawnGoogleJavaFormat(args, done, stdio) {
53-
// WARNING: This function's interface should stay stable across versions for the cross-version
54-
// loading below to work.
55105
let nativeBinary;
56106

57107
try {
@@ -62,91 +112,43 @@ function spawnGoogleJavaFormat(args, done, stdio) {
62112
}
63113

64114
if (args.find((a) => a === "-version" || a === "--version")) {
65-
// Print our version.
66-
// This makes it impossible to format files called '-version' or '--version'. That's a feature.
67-
// minimist & Co don't support single dash args, which we need to match binary google-java-format.
68115
console.log(`google-java-format NPM version ${VERSION} at ${LOCATION}`);
69116
args = ["--version"];
70117
}
71118

72-
// Add the library in, with java 16 compat
73119
args = [
74120
"-jar",
75121
`${LOCATION}/lib/google-java-format-1.35.0-all-deps.jar`,
76122
].concat(args);
77123

78-
// extract glob, if present
79124
const filesGlob = getGlobArg(args);
80-
81125
if (filesGlob) {
82-
// remove glob from arg list
83126
args = args.filter((arg) => arg.indexOf(GLOB_OPTION) === -1);
84-
85127
const files = globSync(filesGlob);
128+
const { prefix, rest } = splitJarArgs(args);
129+
const { flags } = splitFlagsAndFiles(rest);
130+
runChunks(nativeBinary, prefix, flags, files, stdio, done);
131+
return;
132+
}
86133

87-
// split file array into chunks of 30
88-
let i,
89-
j,
90-
chunks = [],
91-
chunkSize = 30;
92-
93-
for (i = 0, j = files.length; i < j; i += chunkSize) {
94-
chunks.push(files.slice(i, i + chunkSize));
95-
}
134+
const { prefix, rest } = splitJarArgs(args);
135+
const { flags, files } = splitFlagsAndFiles(rest);
96136

97-
// launch a new process for each chunk
98-
async.series(
99-
chunks.map(function (chunk) {
100-
return function (callback) {
101-
const googlejavaFormatProcess = spawn(
102-
nativeBinary,
103-
args.concat(chunk),
104-
{ stdio: stdio }
105-
);
106-
googlejavaFormatProcess.on("close", function (exit) {
107-
if (exit !== 0) callback(errorFromExitCode(exit));
108-
else callback();
109-
});
110-
};
111-
}),
112-
function (err) {
113-
if (err) {
114-
done(err);
115-
return;
116-
}
117-
console.log("\n");
118-
console.log(
119-
`ran google-java-format on ${files.length} ${
120-
files.length === 1 ? "file" : "files"
121-
}`
122-
);
123-
done();
124-
}
125-
);
126-
} else {
127-
const googlejavaFormatProcess = spawn(nativeBinary, args, { stdio: stdio });
128-
googlejavaFormatProcess.on("close", function (exit) {
129-
if (exit) {
130-
done(errorFromExitCode(exit));
131-
} else {
132-
done();
133-
}
134-
});
135-
return googlejavaFormatProcess;
137+
if (files.length > CHUNK_SIZE) {
138+
runChunks(nativeBinary, prefix, flags, files, stdio, done);
139+
return;
136140
}
141+
142+
return runSpawn(nativeBinary, prefix.concat(flags, files), stdio, done);
137143
}
138144

139145
function main() {
140-
// Find google-java-format in node_modules of the project of the .js file, or cwd.
141146
const nonDashArgs = process.argv.filter(
142147
(arg, idx) => idx > 1 && arg[0] != "-"
143148
);
144149

145-
// Using the last file makes it less likely to collide with google-java-format's argument parsing.
146150
const lastFileArg = nonDashArgs[nonDashArgs.length - 1];
147-
const basedir = lastFileArg
148-
? path.dirname(lastFileArg) // relative to the last .js file given.
149-
: process.cwd(); // or relative to the cwd()
151+
const basedir = lastFileArg ? path.dirname(lastFileArg) : process.cwd();
150152
let resolvedGoogleJavaFormat;
151153
let googleJavaFormatLocation;
152154
try {
@@ -155,6 +157,7 @@ function main() {
155157
} catch (e) {
156158
// Ignore and use the google-java-format that came with this package.
157159
}
160+
158161
let actualSpawnFn;
159162
if (!resolvedGoogleJavaFormat) {
160163
actualSpawnFn = spawnGoogleJavaFormat;
@@ -165,9 +168,8 @@ function main() {
165168
`Incompatible google-java-format loaded from ${googleJavaFormatLocation}`
166169
);
167170
}
168-
// Run google-java-format.
171+
169172
try {
170-
// Pass all arguments to google-java-format, including e.g. -version etc.
171173
actualSpawnFn(
172174
process.argv.slice(2),
173175
function (e) {
@@ -186,25 +188,14 @@ function main() {
186188
}
187189
}
188190

189-
/**
190-
* @returns the native `java` binary for the current platform
191-
* @throws when the `java` executable can not be found
192-
*/
193191
function getNativeBinary() {
194192
let nativeBinary = "java";
195-
const platform = os.platform();
196-
const arch = os.arch();
197-
if (platform === "win32") {
193+
if (os.platform() === "win32") {
198194
nativeBinary = "java.exe";
199195
}
200196
return nativeBinary;
201197
}
202198

203-
/**
204-
* Filters the arguments to return the value of the `--glob=` option.
205-
*
206-
* @returns The value of the glob option or null if not found
207-
*/
208199
function getGlobArg(args) {
209200
const found = args.find((a) => a.startsWith(GLOB_OPTION));
210201
return found ? found.substring(GLOB_OPTION.length) : null;

0 commit comments

Comments
 (0)