1616package com .diffplug .spotless .cli ;
1717
1818import java .nio .charset .Charset ;
19- import java .nio .file .Files ;
2019import java .nio .file .Path ;
2120import java .util .List ;
21+ import java .util .function .BiConsumer ;
2222import java .util .stream .Collectors ;
2323
2424import javax .annotation .Nonnull ;
2525
2626import com .diffplug .spotless .Formatter ;
2727import com .diffplug .spotless .FormatterStep ;
2828import com .diffplug .spotless .LineEnding ;
29+ import com .diffplug .spotless .LintState ;
2930import com .diffplug .spotless .ThrowingEx ;
3031import com .diffplug .spotless .cli .core .TargetResolver ;
3132import com .diffplug .spotless .cli .execution .SpotlessExecutionStrategy ;
@@ -70,41 +71,70 @@ public Integer executeSpotlessAction(@Nonnull List<FormatterStep> formatterSteps
7071 .steps (formatterSteps )
7172 .build ()) {
7273
73- boolean success = targetResolver .resolveTargets ()
74+ ResultType resultType = targetResolver .resolveTargets () // TODO result
7475 .parallel () // needed?
75- .map (target -> this .executeFormatter (formatter , target ))
76- .filter (result -> result .success && result .updated != null )
77- .peek (this ::writeBack )
78- .allMatch (result -> result .success );
76+ .map (path -> ThrowingEx .get (() -> new Result (path , LintState .of (formatter , path .toFile ())))) // TODO handle suppressions, see SpotlessTaskImpl
77+ .map (result -> this .handleResult (formatter , result ))
78+ .reduce (ResultType .CLEAN , ResultType ::combineWith );
7979 System .out .println ("Hello " + getClass ().getSimpleName () + ", abc! Files: " + new TargetResolver (targets ).resolveTargets ().collect (Collectors .toList ()));
80- System .out .println ("success : " + success );
80+ System .out .println ("result : " + resultType );
8181 formatterSteps .forEach (step -> System .out .println ("Step: " + step ));
8282 return 0 ;
8383 }
8484 }
8585
86- private Result executeFormatter (Formatter formatter , Path target ) {
87- System .out .println ("Formatting file: " + target + " in Thread " + Thread .currentThread ().getName ());
88- String targetContent = ThrowingEx .get (() -> Files .readString (target , Charset .defaultCharset ())); // TODO charset!
89-
90- String computed = formatter .compute (targetContent , target .toFile ());
91- // computed is null if file already up to date
92- return new Result (target , true , computed );
93- }
94-
95- private void writeBack (Result result ) {
96- if (result .updated != null ) {
97- ThrowingEx .run (() -> Files .writeString (result .target , result .updated , Charset .defaultCharset ())); // TODO charset!
86+ private ResultType handleResult (Formatter formatter , Result result ) {
87+ if (result .lintState .isClean ()) {
88+ System .out .println ("File is clean: " + result .target .toFile ().getName ());
89+ return ResultType .CLEAN ;
90+ }
91+ if (result .lintState .getDirtyState ().didNotConverge ()) {
92+ System .out .println ("File did not converge: " + result .target .toFile ().getName ());
93+ return ResultType .DID_NOT_CONVERGE ;
94+ }
95+ this .spotlessMode .action .accept (formatter , result );
96+ return ResultType .DIRTY ;
97+
98+ /*
99+ if (lintState.getDirtyState().isClean()) {
100+ // Remove previous output if it exists
101+ Files.deleteIfExists(cleanFile.toPath());
102+ } else if (lintState.getDirtyState().didNotConverge()) {
103+ getLogger().warn("Skipping '{}' because it does not converge. Run {@code spotlessDiagnose} to understand why", relativePath);
104+ } else {
105+ Path parentDir = cleanFile.toPath().getParent();
106+ if (parentDir == null) {
107+ throw new IllegalStateException("Every file has a parent folder. But not: " + cleanFile);
108+ }
109+ Files.createDirectories(parentDir);
110+ // Need to copy the original file to the tmp location just to remember the file attributes
111+ Files.copy(input.toPath(), cleanFile.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
112+
113+ getLogger().info(String.format("Writing clean file: %s", cleanFile));
114+ lintState.getDirtyState().writeCanonicalTo(cleanFile);
115+ }
116+ if (!lintState.isHasLints()) {
117+ Files.deleteIfExists(lintFile.toPath());
118+ } else {
119+ LinkedHashMap<String, List<Lint>> lints = lintState.getLintsByStep(formatter);
120+ SerializableMisc.toFile(lints, lintFile);
98121 }
99- // System.out.println("Writing back to file:" + result.target + " with content:\n" + result.updated);
122+ */
100123 }
101124
125+ // private void writeBack(Result result) {
126+ // if (result.updated != null) {
127+ // ThrowingEx.run(() -> Files.writeString(result.target, result.updated, Charset.defaultCharset())); // TODO charset!
128+ // }
129+ // System.out.println("Writing back to file:" + result.target + " with content:\n" + result.updated);
130+ // }
131+
102132 public static void main (String ... args ) {
103133 if (args .length == 0 ) {
104134 // args = new String[]{"--version"};
105135 // args = new String[]{"license-header", "--header-file", "CHANGES.md", "--delimiter-for", "java", "license-header", "--header", "abc"};
106136
107- args = new String []{"--target" , "src/poc/java/**/*.java" , "--encoding=UTF-8" , "license-header" , "--header" , "abc" , "--delimiter-for" , "java" , "license-header" , "--header-file" , "TestHeader.txt" };
137+ args = new String []{"--mode=CHECK" , "-- target" , "src/poc/java/**/*.java" , "--encoding=UTF-8" , "license-header" , "--header" , "abc" , "--delimiter-for" , "java" , "license-header" , "--header-file" , "TestHeader.txt" };
108138 // args = new String[]{"--version"};
109139 }
110140 int exitCode = new CommandLine (new SpotlessCLI ())
@@ -115,18 +145,46 @@ public static void main(String... args) {
115145 }
116146
117147 private enum SpotlessMode {
118- CHECK , APPLY
148+ CHECK (((formatter , result ) -> {
149+ if (result .lintState .isHasLints ()) {
150+ result .lintState .asStringOneLine (result .target .toFile (), formatter );
151+ } else {
152+ System .out .println (String .format ("%s is violating formatting rules." , result .target ));
153+ }
154+ })), APPLY (((formatter , result ) -> ThrowingEx .run (() -> result .lintState .getDirtyState ().writeCanonicalTo (result .target .toFile ()))));
155+
156+ private final BiConsumer <Formatter , Result > action ;
157+
158+ SpotlessMode (BiConsumer <Formatter , Result > action ) {
159+ this .action = action ;
160+ }
161+
162+ }
163+
164+ private enum ResultType {
165+ CLEAN , DIRTY , DID_NOT_CONVERGE ;
166+
167+ ResultType combineWith (ResultType other ) {
168+ if (this == other ) {
169+ return this ;
170+ }
171+ if (this == DID_NOT_CONVERGE || other == DID_NOT_CONVERGE ) {
172+ return DID_NOT_CONVERGE ;
173+ }
174+ if (this == DIRTY || other == DIRTY ) {
175+ return DIRTY ;
176+ }
177+ throw new IllegalStateException ("Unexpected combination of result types: " + this + " and " + other );
178+ }
119179 }
120180
121181 private static final class Result {
122182 private final Path target ;
123- private final boolean success ;
124- private final String updated ;
183+ private final LintState lintState ;
125184
126- public Result (Path target , boolean success , String updated ) {
185+ public Result (Path target , LintState lintState ) {
127186 this .target = target ;
128- this .success = success ;
129- this .updated = updated ;
187+ this .lintState = lintState ;
130188 }
131189 }
132190}
0 commit comments