Skip to content

Commit 4ed7074

Browse files
authored
Add support to allow multiple prettier instances for different target source sets (#1565 fixes #1162)
2 parents fc3f6ff + 3333519 commit 4ed7074

File tree

16 files changed

+224
-65
lines changed

16 files changed

+224
-65
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1212
## [Unreleased]
1313
### Added
1414
* CleanThat Java Refactorer. ([#1560](https://github.com/diffplug/spotless/pull/1560))
15+
* Introduce `LazyArgLogger` to allow for lazy evaluation of log messages in slf4j logging. ([#1565](https://github.com/diffplug/spotless/pull/1565))
1516
### Fixed
17+
* Allow multiple instances of the same npm-based formatter to be used by separating their `node_modules` directories. ([#1565](https://github.com/diffplug/spotless/pull/1565))
1618
* `ktfmt` default style uses correct continuation indent. ([#1562](https://github.com/diffplug/spotless/pull/1562))
1719

1820
## [2.34.1] - 2023-02-05
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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;
17+
18+
import java.util.function.Supplier;
19+
20+
/**
21+
* This is a utility class to allow for lazy evaluation of arguments to be passed to a logger
22+
* and thus avoid unnecessary computation of the arguments if the log level is not enabled.
23+
*/
24+
public final class LazyArgLogger {
25+
26+
private final Supplier<Object> argSupplier;
27+
28+
private LazyArgLogger(Supplier<Object> argSupplier) {
29+
this.argSupplier = argSupplier;
30+
}
31+
32+
public static LazyArgLogger lazy(Supplier<Object> argSupplier) {
33+
return new LazyArgLogger(argSupplier);
34+
}
35+
36+
@Override
37+
public String toString() {
38+
return String.valueOf(argSupplier.get());
39+
}
40+
}

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.diffplug.spotless.npm;
1717

18+
import static com.diffplug.spotless.LazyArgLogger.lazy;
1819
import static java.util.Objects.requireNonNull;
1920

2021
import java.io.File;
@@ -115,7 +116,7 @@ protected void prepareNodeServerLayout() throws IOException {
115116
// If any config files are provided, we need to make sure they are at the same location as the node modules
116117
// as eslint will try to resolve plugin/config names relatively to the config file location and some
117118
// eslint configs contain relative paths to additional config files (such as tsconfig.json e.g.)
118-
FormattedPrinter.SYSOUT.print("Copying config file <%s> to <%s> and using the copy", origEslintConfig.getEslintConfigPath(), nodeServerLayout.nodeModulesDir());
119+
logger.info("Copying config file <{}> to <{}> and using the copy", origEslintConfig.getEslintConfigPath(), nodeServerLayout.nodeModulesDir());
119120
File configFileCopy = NpmResourceHelper.copyFileToDir(origEslintConfig.getEslintConfigPath(), nodeServerLayout.nodeModulesDir());
120121
this.eslintConfigInUse = this.origEslintConfig.withEslintConfigPath(configFileCopy).verify();
121122
}
@@ -125,7 +126,7 @@ protected void prepareNodeServerLayout() throws IOException {
125126
@Nonnull
126127
public FormatterFunc createFormatterFunc() {
127128
try {
128-
FormattedPrinter.SYSOUT.print("creating formatter function (starting server)");
129+
logger.info("Creating formatter function (starting server)");
129130
ServerProcessInfo eslintRestServer = npmRunServer();
130131
EslintRestService restService = new EslintRestService(eslintRestServer.getBaseUrl());
131132
return Closeable.ofDangerous(() -> endServer(restService, eslintRestServer), new EslintFilePathPassingFormatterFunc(locations.projectDir(), nodeServerLayout.nodeModulesDir(), eslintConfigInUse, restService));
@@ -135,7 +136,7 @@ public FormatterFunc createFormatterFunc() {
135136
}
136137

137138
private void endServer(BaseNpmRestService restService, ServerProcessInfo restServer) throws Exception {
138-
FormattedPrinter.SYSOUT.print("Closing formatting function (ending server).");
139+
logger.info("Closing formatting function (ending server).");
139140
try {
140141
restService.shutdown();
141142
} catch (Throwable t) {
@@ -161,7 +162,7 @@ public EslintFilePathPassingFormatterFunc(File projectDir, File nodeModulesDir,
161162

162163
@Override
163164
public String applyWithFile(String unix, File file) throws Exception {
164-
FormattedPrinter.SYSOUT.print("formatting String '" + unix.substring(0, Math.min(50, unix.length())) + "[...]' in file '" + file + "'");
165+
logger.info("formatting String '{}[...]' in file '{}'", lazy(() -> unix.substring(0, Math.min(50, unix.length()))), file);
165166

166167
Map<FormatOption, Object> eslintCallOptions = new HashMap<>();
167168
setConfigToCallOptions(eslintCallOptions);

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

Lines changed: 0 additions & 42 deletions
This file was deleted.

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

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,44 @@
1818
import java.io.File;
1919
import java.nio.file.Files;
2020
import java.nio.file.Path;
21+
import java.util.regex.Matcher;
22+
import java.util.regex.Pattern;
2123
import java.util.stream.Stream;
2224

2325
import com.diffplug.spotless.ThrowingEx;
2426

2527
class NodeServerLayout {
2628

29+
private static final Pattern PACKAGE_JSON_NAME_PATTERN = Pattern.compile("\"name\"\\s*:\\s*\"([^\"]+)\"");
30+
2731
private final File nodeModulesDir;
2832
private final File packageJsonFile;
33+
34+
private final File packageLockJsonFile;
35+
2936
private final File serveJsFile;
3037
private final File npmrcFile;
3138

32-
NodeServerLayout(File buildDir, String stepName) {
33-
this.nodeModulesDir = new File(buildDir, "spotless-node-modules-" + stepName);
39+
NodeServerLayout(File buildDir, String packageJsonContent) {
40+
this.nodeModulesDir = new File(buildDir, nodeModulesDirName(packageJsonContent));
3441
this.packageJsonFile = new File(nodeModulesDir, "package.json");
42+
this.packageLockJsonFile = new File(nodeModulesDir, "package-lock.json");
3543
this.serveJsFile = new File(nodeModulesDir, "serve.js");
3644
this.npmrcFile = new File(nodeModulesDir, ".npmrc");
3745
}
3846

47+
private static String nodeModulesDirName(String packageJsonContent) {
48+
String md5Hash = NpmResourceHelper.md5(packageJsonContent);
49+
Matcher matcher = PACKAGE_JSON_NAME_PATTERN.matcher(packageJsonContent);
50+
if (!matcher.find()) {
51+
throw new IllegalArgumentException("package.json must contain a name property");
52+
}
53+
String packageName = matcher.group(1);
54+
return String.format("%s-node-modules-%s", packageName, md5Hash);
55+
}
56+
3957
File nodeModulesDir() {
58+
4059
return nodeModulesDir;
4160
}
4261

@@ -52,17 +71,16 @@ public File npmrcFile() {
5271
return npmrcFile;
5372
}
5473

55-
static File getBuildDirFromNodeModulesDir(File nodeModulesDir) {
56-
return nodeModulesDir.getParentFile();
57-
}
58-
5974
public boolean isLayoutPrepared() {
6075
if (!nodeModulesDir().isDirectory()) {
6176
return false;
6277
}
6378
if (!packageJsonFile().isFile()) {
6479
return false;
6580
}
81+
if (!packageLockJsonFile.isFile()) {
82+
return false;
83+
}
6684
if (!serveJsFile().isFile()) {
6785
return false;
6886
}
@@ -82,4 +100,14 @@ public boolean isNodeModulesPrepared() {
82100
}
83101
});
84102
}
103+
104+
@Override
105+
public String toString() {
106+
return String.format(
107+
"NodeServerLayout[nodeModulesDir=%s, packageJsonFile=%s, serveJsFile=%s, npmrcFile=%s]",
108+
this.nodeModulesDir,
109+
this.packageJsonFile,
110+
this.serveJsFile,
111+
this.npmrcFile);
112+
}
85113
}

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,13 @@ protected NpmFormatterStepStateBase(String stepName, NpmConfig npmConfig, NpmFor
5656
this.stepName = requireNonNull(stepName);
5757
this.npmConfig = requireNonNull(npmConfig);
5858
this.locations = locations;
59-
this.nodeServerLayout = new NodeServerLayout(locations.buildDir(), stepName);
59+
this.nodeServerLayout = new NodeServerLayout(locations.buildDir(), npmConfig.getPackageJsonContent());
6060
}
6161

6262
protected void prepareNodeServerLayout() throws IOException {
63+
final long started = System.currentTimeMillis();
64+
// maybe introduce trace logger?
65+
logger.info("Preparing {} for npm step {}.", this.nodeServerLayout, getClass().getName());
6366
NpmResourceHelper.assertDirectoryExists(nodeServerLayout.nodeModulesDir());
6467
NpmResourceHelper.writeUtf8StringToFile(nodeServerLayout.packageJsonFile(),
6568
this.npmConfig.getPackageJsonContent());
@@ -70,12 +73,14 @@ protected void prepareNodeServerLayout() throws IOException {
7073
} else {
7174
NpmResourceHelper.deleteFileIfExists(nodeServerLayout.npmrcFile());
7275
}
76+
logger.info("Prepared {} for npm step {} in {} ms.", this.nodeServerLayout, getClass().getName(), System.currentTimeMillis() - started);
7377
}
7478

7579
protected void prepareNodeServer() throws IOException {
76-
FormattedPrinter.SYSOUT.print("running npm install");
80+
final long started = System.currentTimeMillis();
81+
logger.info("running npm install in {} for npm step {}", this.nodeServerLayout.nodeModulesDir(), getClass().getName());
7782
runNpmInstall(nodeServerLayout.nodeModulesDir());
78-
FormattedPrinter.SYSOUT.print("npm install finished");
83+
logger.info("npm install finished in {} ms in {} for npm step {}", System.currentTimeMillis() - started, this.nodeServerLayout.nodeModulesDir(), getClass().getName());
7984
}
8085

8186
private void runNpmInstall(File npmProjectDir) throws IOException {

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.nio.file.Path;
2222
import java.nio.file.Paths;
2323
import java.nio.file.StandardCopyOption;
24+
import java.security.MessageDigest;
2425
import java.time.Duration;
2526
import java.util.Arrays;
2627
import java.util.Objects;
@@ -122,4 +123,20 @@ static File copyFileToDirAtSubpath(File file, File targetDir, String relativePat
122123
throw ThrowingEx.asRuntime(e);
123124
}
124125
}
126+
127+
static String md5(File file) {
128+
return md5(readUtf8StringFromFile(file));
129+
}
130+
131+
static String md5(String fileContent) {
132+
MessageDigest md = ThrowingEx.get(() -> MessageDigest.getInstance("MD5"));
133+
md.update(fileContent.getBytes(StandardCharsets.UTF_8));
134+
byte[] digest = md.digest();
135+
// convert byte array digest to hex string
136+
StringBuilder sb = new StringBuilder();
137+
for (byte b : digest) {
138+
sb.append(String.format("%02x", b & 0xff));
139+
}
140+
return sb.toString();
141+
}
125142
}

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

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

18+
import static com.diffplug.spotless.LazyArgLogger.lazy;
1819
import static java.util.Objects.requireNonNull;
1920

2021
import java.io.File;
@@ -86,7 +87,7 @@ private static class State extends NpmFormatterStepStateBase implements Serializ
8687
@Nonnull
8788
public FormatterFunc createFormatterFunc() {
8889
try {
89-
FormattedPrinter.SYSOUT.print("creating formatter function (starting server)");
90+
logger.info("creating formatter function (starting server)");
9091
ServerProcessInfo prettierRestServer = npmRunServer();
9192
PrettierRestService restService = new PrettierRestService(prettierRestServer.getBaseUrl());
9293
String prettierConfigOptions = restService.resolveConfig(this.prettierConfig.getPrettierConfigPath(), this.prettierConfig.getOptions());
@@ -97,7 +98,7 @@ public FormatterFunc createFormatterFunc() {
9798
}
9899

99100
private void endServer(PrettierRestService restService, ServerProcessInfo restServer) throws Exception {
100-
FormattedPrinter.SYSOUT.print("Closing formatting function (ending server).");
101+
logger.info("Closing formatting function (ending server).");
101102
try {
102103
restService.shutdown();
103104
} catch (Throwable t) {
@@ -119,7 +120,7 @@ public PrettierFilePathPassingFormatterFunc(String prettierConfigOptions, Pretti
119120

120121
@Override
121122
public String applyWithFile(String unix, File file) throws Exception {
122-
FormattedPrinter.SYSOUT.print("formatting String '" + unix.substring(0, Math.min(50, unix.length())) + "[...]' in file '" + file + "'");
123+
logger.info("formatting String '{}[...]' in file '{}'", lazy(() -> unix.substring(0, Math.min(50, unix.length()))), file);
123124

124125
final String prettierConfigOptionsWithFilepath = assertFilepathInConfigOptions(file);
125126
try {

lib/src/main/resources/com/diffplug/spotless/npm/eslint-package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "spotless-eslint-formatter-step",
2+
"name": "spotless-eslint",
33
"version": "2.0.0",
44
"description": "Spotless formatter step for running eslint as a rest service.",
55
"repository": "https://github.com/diffplug/spotless",

lib/src/main/resources/com/diffplug/spotless/npm/prettier-package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "spotless-prettier-formatter-step",
2+
"name": "spotless-prettier",
33
"version": "2.0.0",
44
"description": "Spotless formatter step for running prettier as a rest service.",
55
"repository": "https://github.com/diffplug/spotless",

0 commit comments

Comments
 (0)