Skip to content

Commit e724d88

Browse files
committed
1480: extract NpmApp and npm exec calls
so they can be overwritten later for pnpm
1 parent 050bb45 commit e724d88

13 files changed

+320
-153
lines changed

lib/src/main/java/com/diffplug/spotless/TimedLogger.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ public void run(ThrowingEx.Runnable r) {
192192
}
193193
}
194194

195+
public <T> T call(ThrowingEx.Supplier<T> s) {
196+
try (Timed ignore = timed()) {
197+
return ThrowingEx.get(s);
198+
}
199+
}
200+
195201
public void runChecked(ThrowingEx.Runnable r) throws Exception {
196202
try (Timed ignore = timed()) {
197203
r.run();

lib/src/main/java/com/diffplug/spotless/npm/EslintFormatterStep.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ private static class State extends NpmFormatterStepStateBase implements Serializ
9595
replaceDevDependencies(
9696
NpmResourceHelper.readUtf8StringFromClasspath(EslintFormatterStep.class, "/com/diffplug/spotless/npm/eslint-package.json"),
9797
new TreeMap<>(devDependencies)),
98-
"eslint",
9998
NpmResourceHelper.readUtf8StringFromClasspath(EslintFormatterStep.class,
10099
"/com/diffplug/spotless/npm/common-serve.js",
101100
"/com/diffplug/spotless/npm/eslint-serve.js"),
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2023 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.npm;
17+
18+
import java.util.Objects;
19+
20+
import javax.annotation.Nonnull;
21+
22+
import org.slf4j.Logger;
23+
import org.slf4j.LoggerFactory;
24+
25+
import com.diffplug.spotless.TimedLogger;
26+
27+
public class NodeApp {
28+
29+
private static final Logger logger = LoggerFactory.getLogger(NodeApp.class);
30+
31+
private static final TimedLogger timedLogger = TimedLogger.forLogger(logger);
32+
33+
@Nonnull
34+
protected final NodeServerLayout nodeServerLayout;
35+
36+
@Nonnull
37+
protected final NpmConfig npmConfig;
38+
39+
@Nonnull
40+
protected final NpmProcessFactory npmProcessFactory;
41+
42+
@Nonnull
43+
protected final NpmFormatterStepLocations formatterStepLocations;
44+
45+
public NodeApp(@Nonnull NodeServerLayout nodeServerLayout, @Nonnull NpmConfig npmConfig, @Nonnull NpmProcessFactory npmProcessFactory, @Nonnull NpmFormatterStepLocations formatterStepLocations) {
46+
this.nodeServerLayout = Objects.requireNonNull(nodeServerLayout);
47+
this.npmConfig = Objects.requireNonNull(npmConfig);
48+
this.npmProcessFactory = Objects.requireNonNull(npmProcessFactory);
49+
this.formatterStepLocations = Objects.requireNonNull(formatterStepLocations);
50+
}
51+
52+
boolean needsNpmInstall() {
53+
return !this.nodeServerLayout.isNodeModulesPrepared();
54+
}
55+
56+
boolean needsPrepareNodeAppLayout() {
57+
return !this.nodeServerLayout.isLayoutPrepared();
58+
}
59+
60+
void prepareNodeAppLayout() {
61+
timedLogger.withInfo("Preparing {} for npm step {}.", this.nodeServerLayout, getClass().getName()).run(() -> {
62+
NpmResourceHelper.assertDirectoryExists(nodeServerLayout.nodeModulesDir());
63+
NpmResourceHelper.writeUtf8StringToFile(nodeServerLayout.packageJsonFile(), this.npmConfig.getPackageJsonContent());
64+
if (this.npmConfig.getServeScriptContent() != null) {
65+
NpmResourceHelper.writeUtf8StringToFile(nodeServerLayout.serveJsFile(), this.npmConfig.getServeScriptContent());
66+
} else {
67+
NpmResourceHelper.deleteFileIfExists(nodeServerLayout.serveJsFile());
68+
}
69+
if (this.npmConfig.getNpmrcContent() != null) {
70+
NpmResourceHelper.writeUtf8StringToFile(nodeServerLayout.npmrcFile(), this.npmConfig.getNpmrcContent());
71+
} else {
72+
NpmResourceHelper.deleteFileIfExists(nodeServerLayout.npmrcFile());
73+
}
74+
});
75+
}
76+
77+
void npmInstall() {
78+
timedLogger.withInfo("Installing npm dependencies for {} with {}.", this.nodeServerLayout, this.npmProcessFactory.describe())
79+
.run(() -> npmProcessFactory.createNpmInstallProcess(nodeServerLayout, formatterStepLocations).waitFor());
80+
}
81+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2023 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.npm;
17+
18+
import javax.annotation.Nonnull;
19+
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
22+
23+
import com.diffplug.spotless.ProcessRunner;
24+
import com.diffplug.spotless.TimedLogger;
25+
26+
public class NodeServeApp extends NodeApp {
27+
28+
private static final Logger logger = LoggerFactory.getLogger(NodeApp.class);
29+
30+
private static final TimedLogger timedLogger = TimedLogger.forLogger(logger);
31+
32+
public NodeServeApp(@Nonnull NodeServerLayout nodeServerLayout, @Nonnull NpmConfig npmConfig, @Nonnull NpmProcessFactory npmProcessFactory, @Nonnull NpmFormatterStepLocations formatterStepLocations) {
33+
super(nodeServerLayout, npmConfig, npmProcessFactory, formatterStepLocations);
34+
}
35+
36+
ProcessRunner.LongRunningProcess startNpmServeProcess() {
37+
return timedLogger.withInfo("Starting npm based server in {} with {}.", this.nodeServerLayout.nodeModulesDir(), this.npmProcessFactory.describe())
38+
.call(() -> npmProcessFactory.createNpmServeProcess(nodeServerLayout, formatterStepLocations).start());
39+
}
40+
41+
}

lib/src/main/java/com/diffplug/spotless/npm/NpmConfig.java

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2020 DiffPlug
2+
* Copyright 2016-2023 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,37 +16,32 @@
1616
package com.diffplug.spotless.npm;
1717

1818
import java.io.Serializable;
19+
import java.util.Objects;
1920

2021
import javax.annotation.Nonnull;
2122

2223
class NpmConfig implements Serializable {
2324

2425
private static final long serialVersionUID = 684264546497914877L;
2526

27+
@Nonnull
2628
private final String packageJsonContent;
2729

28-
private final String npmModule;
29-
3030
private final String serveScriptContent;
3131

3232
private final String npmrcContent;
3333

34-
public NpmConfig(String packageJsonContent, String npmModule, String serveScriptContent, String npmrcContent) {
35-
this.packageJsonContent = packageJsonContent;
36-
this.npmModule = npmModule;
34+
public NpmConfig(@Nonnull String packageJsonContent, String serveScriptContent, String npmrcContent) {
35+
this.packageJsonContent = Objects.requireNonNull(packageJsonContent);
3736
this.serveScriptContent = serveScriptContent;
3837
this.npmrcContent = npmrcContent;
3938
}
4039

40+
@Nonnull
4141
public String getPackageJsonContent() {
4242
return packageJsonContent;
4343
}
4444

45-
public String getNpmModule() {
46-
return npmModule;
47-
}
48-
49-
@Nonnull
5045
public String getServeScriptContent() {
5146
return serveScriptContent;
5247
}

lib/src/main/java/com/diffplug/spotless/npm/NpmFormatterStepStateBase.java

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -55,37 +55,22 @@ abstract class NpmFormatterStepStateBase implements Serializable {
5555

5656
private final String stepName;
5757

58+
private final transient NodeServeApp nodeServeApp;
59+
5860
protected NpmFormatterStepStateBase(String stepName, NpmConfig npmConfig, NpmFormatterStepLocations locations) throws IOException {
5961
this.stepName = requireNonNull(stepName);
6062
this.npmConfig = requireNonNull(npmConfig);
6163
this.locations = locations;
6264
this.nodeServerLayout = new NodeServerLayout(locations.buildDir(), npmConfig.getPackageJsonContent());
65+
this.nodeServeApp = new NodeServeApp(nodeServerLayout, npmConfig, new StandardNpmProcessFactory(), locations);
6366
}
6467

6568
protected void prepareNodeServerLayout() throws IOException {
66-
final long started = System.currentTimeMillis();
67-
68-
timedLogger.withInfo("Preparing {} for npm step {}.", this.nodeServerLayout, getClass().getName()).run(() -> {
69-
NpmResourceHelper.assertDirectoryExists(nodeServerLayout.nodeModulesDir());
70-
NpmResourceHelper.writeUtf8StringToFile(nodeServerLayout.packageJsonFile(),
71-
this.npmConfig.getPackageJsonContent());
72-
NpmResourceHelper
73-
.writeUtf8StringToFile(nodeServerLayout.serveJsFile(), this.npmConfig.getServeScriptContent());
74-
if (this.npmConfig.getNpmrcContent() != null) {
75-
NpmResourceHelper.writeUtf8StringToFile(nodeServerLayout.npmrcFile(), this.npmConfig.getNpmrcContent());
76-
} else {
77-
NpmResourceHelper.deleteFileIfExists(nodeServerLayout.npmrcFile());
78-
}
79-
});
69+
nodeServeApp.prepareNodeAppLayout();
8070
}
8171

8272
protected void prepareNodeServer() throws IOException {
83-
timedLogger.withInfo("Running npm install in {} for npm step {}.", this.nodeServerLayout.nodeModulesDir(), getClass().getName())
84-
.run(() -> runNpmInstall(nodeServerLayout.nodeModulesDir()));
85-
}
86-
87-
private void runNpmInstall(File npmProjectDir) throws IOException {
88-
new StandardNpmProcess(npmProjectDir, this.locations.npmExecutable(), this.locations.nodeExecutable()).install();
73+
nodeServeApp.npmInstall();
8974
}
9075

9176
protected void assertNodeServerDirReady() throws IOException {
@@ -100,11 +85,11 @@ protected void assertNodeServerDirReady() throws IOException {
10085
}
10186

10287
protected boolean needsPrepareNodeServer() {
103-
return !this.nodeServerLayout.isNodeModulesPrepared();
88+
return nodeServeApp.needsNpmInstall();
10489
}
10590

10691
protected boolean needsPrepareNodeServerLayout() {
107-
return !this.nodeServerLayout.isLayoutPrepared();
92+
return nodeServeApp.needsPrepareNodeAppLayout();
10893
}
10994

11095
protected ServerProcessInfo npmRunServer() throws ServerStartException, IOException {
@@ -116,7 +101,7 @@ protected ServerProcessInfo npmRunServer() throws ServerStartException, IOExcept
116101
final File serverPortFile = new File(this.nodeServerLayout.nodeModulesDir(), "server.port");
117102
NpmResourceHelper.deleteFileIfExists(serverPortFile);
118103
// start the http server in node
119-
server = new StandardNpmProcess(this.nodeServerLayout.nodeModulesDir(), this.locations.npmExecutable(), this.locations.nodeExecutable()).start();
104+
server = nodeServeApp.startNpmServeProcess();
120105

121106
// await the readiness of the http server - wait for at most 60 seconds
122107
try {
@@ -207,7 +192,7 @@ protected static class ServerStartException extends RuntimeException {
207192
private static final long serialVersionUID = -8803977379866483002L;
208193

209194
public ServerStartException(String message, Throwable cause) {
210-
super(cause);
195+
super(message, cause);
211196
}
212197
}
213198
}

lib/src/main/java/com/diffplug/spotless/npm/NpmProcess.java

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,39 @@
1515
*/
1616
package com.diffplug.spotless.npm;
1717

18-
import com.diffplug.spotless.ProcessRunner;
18+
import java.util.concurrent.ExecutionException;
19+
20+
import com.diffplug.spotless.ProcessRunner.LongRunningProcess;
21+
import com.diffplug.spotless.ProcessRunner.Result;
1922

2023
interface NpmProcess {
21-
void install();
2224

23-
ProcessRunner.LongRunningProcess start();
25+
String describe();
26+
27+
LongRunningProcess start();
28+
29+
default Result waitFor() {
30+
try (LongRunningProcess npmProcess = start()) {
31+
if (npmProcess.waitFor() != 0) {
32+
throw new NpmProcessException("Running npm command '" + describe() + "' failed with exit code: " + npmProcess.exitValue() + "\n\n" + npmProcess.result());
33+
}
34+
return npmProcess.result();
35+
} catch (InterruptedException e) {
36+
throw new NpmProcessException("Running npm command '" + describe() + "' was interrupted.", e);
37+
} catch (ExecutionException e) {
38+
throw new NpmProcessException("Running npm command '" + describe() + "' failed.", e);
39+
}
40+
}
41+
42+
class NpmProcessException extends RuntimeException {
43+
private static final long serialVersionUID = 6424331316676759525L;
44+
45+
public NpmProcessException(String message) {
46+
super(message);
47+
}
48+
49+
public NpmProcessException(String message, Throwable cause) {
50+
super(message, cause);
51+
}
52+
}
2453
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2023 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.npm;
17+
18+
public interface NpmProcessFactory {
19+
NpmProcess createNpmInstallProcess(NodeServerLayout nodeServerLayout, NpmFormatterStepLocations formatterStepLocations);
20+
21+
NpmProcess createNpmServeProcess(NodeServerLayout nodeServerLayout, NpmFormatterStepLocations formatterStepLocations);
22+
23+
default String describe() {
24+
return getClass().getSimpleName();
25+
}
26+
27+
}

lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ private static class State extends NpmFormatterStepStateBase implements Serializ
7070
replaceDevDependencies(
7171
NpmResourceHelper.readUtf8StringFromClasspath(PrettierFormatterStep.class, "/com/diffplug/spotless/npm/prettier-package.json"),
7272
new TreeMap<>(devDependencies)),
73-
"prettier",
7473
NpmResourceHelper.readUtf8StringFromClasspath(PrettierFormatterStep.class,
7574
"/com/diffplug/spotless/npm/common-serve.js",
7675
"/com/diffplug/spotless/npm/prettier-serve.js"),

0 commit comments

Comments
 (0)