11/*
2- * Copyright 2016-2025 DiffPlug
2+ * Copyright 2016-2026 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.
1515 */
1616package com .diffplug .spotless ;
1717
18+ import static com .diffplug .common .base .Errors .asRuntime ;
19+ import static com .diffplug .common .base .StandardSystemProperty .USER_DIR ;
20+ import static com .diffplug .common .base .StandardSystemProperty .USER_HOME ;
21+ import static com .diffplug .common .base .Suppliers .memoize ;
22+ import static com .diffplug .common .collect .ImmutableSet .copyOf ;
23+ import static com .diffplug .common .io .Files .asByteSink ;
24+ import static com .diffplug .common .io .Files .createParentDirs ;
25+ import static java .nio .file .Files .walk ;
26+ import static java .util .Objects .requireNonNull ;
27+ import static org .gradle .api .attributes .Bundling .BUNDLING_ATTRIBUTE ;
28+ import static org .gradle .api .attributes .Bundling .EXTERNAL ;
29+ import static org .gradle .api .attributes .Category .CATEGORY_ATTRIBUTE ;
30+ import static org .gradle .api .attributes .Category .LIBRARY ;
31+ import static org .gradle .api .attributes .java .TargetJvmEnvironment .STANDARD_JVM ;
32+ import static org .gradle .api .attributes .java .TargetJvmEnvironment .TARGET_JVM_ENVIRONMENT_ATTRIBUTE ;
33+
1834import java .io .File ;
1935import java .io .IOException ;
2036import java .io .ObjectInputStream ;
2743import java .util .function .Supplier ;
2844
2945import org .gradle .api .Project ;
30- import org .gradle .api .artifacts .Configuration ;
3146import org .gradle .api .artifacts .Dependency ;
3247import org .gradle .api .artifacts .ResolveException ;
3348import org .gradle .api .artifacts .dsl .RepositoryHandler ;
3651import org .gradle .api .attributes .java .TargetJvmEnvironment ;
3752import org .gradle .testfixtures .ProjectBuilder ;
3853
39- import com .diffplug .common .base .Errors ;
40- import com .diffplug .common .base .StandardSystemProperty ;
41- import com .diffplug .common .base .Suppliers ;
4254import com .diffplug .common .collect .ImmutableSet ;
4355import com .diffplug .common .io .Files ;
4456
4557public class TestProvisioner {
4658 public static Project gradleProject (File dir ) {
47- File userHome = new File (StandardSystemProperty .USER_HOME .value ());
4859 return ProjectBuilder .builder ()
49- .withGradleUserHomeDir (new File (userHome , ".gradle" ))
60+ .withGradleUserHomeDir (new File (new File ( requireNonNull ( USER_HOME . value ())) , ".gradle" ))
5061 .withProjectDir (dir )
5162 .build ();
5263 }
@@ -61,21 +72,22 @@ public static Project gradleProject(File dir) {
6172 */
6273 private static Provisioner createWithRepositories (Consumer <RepositoryHandler > repoConfig ) {
6374 // Running this takes ~3 seconds the first time it is called. Probably because of classloading.
64- File tempDir = Files .createTempDir ();
65- Project project = TestProvisioner .gradleProject (tempDir );
75+ var tempDir = Files .createTempDir ();
76+ var project = TestProvisioner .gradleProject (tempDir );
6677 repoConfig .accept (project .getRepositories ());
6778 return (withTransitives , mavenCoords ) -> {
68- Dependency [] deps = mavenCoords .stream ()
69- .map (project .getDependencies ()::create )
70- .toArray (Dependency []::new );
71- Configuration config = project .getConfigurations ().detachedConfiguration (deps );
79+ var config = project
80+ .getConfigurations ()
81+ .detachedConfiguration (mavenCoords .stream ()
82+ .map (project .getDependencies ()::create )
83+ .toArray (Dependency []::new ));
7284 config .setTransitive (withTransitives );
7385 config .setDescription (mavenCoords .toString ());
7486 config .attributes (attr -> {
75- attr .attribute (Category . CATEGORY_ATTRIBUTE , project .getObjects ().named (Category .class , Category . LIBRARY ));
76- attr .attribute (Bundling . BUNDLING_ATTRIBUTE , project .getObjects ().named (Bundling .class , Bundling . EXTERNAL ));
87+ attr .attribute (CATEGORY_ATTRIBUTE , project .getObjects ().named (Category .class , LIBRARY ));
88+ attr .attribute (BUNDLING_ATTRIBUTE , project .getObjects ().named (Bundling .class , EXTERNAL ));
7789 // Add this attribute for resolving Guava dependency, see https://github.com/google/guava/issues/6801.
78- attr .attribute (TargetJvmEnvironment . TARGET_JVM_ENVIRONMENT_ATTRIBUTE , project .getObjects ().named (TargetJvmEnvironment .class , TargetJvmEnvironment . STANDARD_JVM ));
90+ attr .attribute (TARGET_JVM_ENVIRONMENT_ATTRIBUTE , project .getObjects ().named (TargetJvmEnvironment .class , STANDARD_JVM ));
7991 });
8092 try {
8193 return config .resolve ();
@@ -84,75 +96,63 @@ private static Provisioner createWithRepositories(Consumer<RepositoryHandler> re
8496 throw new RuntimeException ("Error resolving configuration: " + config .getDescription (), e );
8597 } finally {
8698 // delete the temp dir
87- try {
88- java . nio . file . Files . walk ( tempDir . toPath ())
99+ try ( var walkStream = walk ( tempDir . toPath ())) {
100+ walkStream
89101 .sorted (Comparator .reverseOrder ())
90102 .map (Path ::toFile )
91103 .forEach (File ::delete );
92- } catch (IOException e ) {
93- throw Errors .asRuntime (e );
94- }
104+ } catch (IOException ignored ) {}
95105 }
96106 };
97107 }
98108
99109 /** Creates a Provisioner which will cache the result of previous calls. */
100110 @ SuppressWarnings ("unchecked" )
101- private static Provisioner caching (String name , Supplier <Provisioner > input ) {
102- File spotlessDir = new File (StandardSystemProperty .USER_DIR .value ()).getParentFile ();
103- File testlib = new File (spotlessDir , "testlib" );
104- File cacheFile = new File (testlib , "build/tmp/testprovisioner." + name + ".cache" );
105-
106- Map <ImmutableSet <String >, ImmutableSet <File >> cached ;
107- if (cacheFile .exists ()) {
108- try (ObjectInputStream inputStream = new ObjectInputStream (Files .asByteSource (cacheFile ).openBufferedStream ())) {
109- cached = (Map <ImmutableSet <String >, ImmutableSet <File >>) inputStream .readObject ();
110- } catch (IOException | ClassNotFoundException e ) {
111- throw Errors .asRuntime (e );
112- }
113- } else {
114- cached = new HashMap <>();
115- try {
116- Files .createParentDirs (cacheFile );
117- } catch (IOException e ) {
118- throw Errors .asRuntime (e );
119- }
120- }
111+ private static Provisioner caching (Supplier <Provisioner > input ) {
112+ var file = new File (
113+ new File (new File (requireNonNull (USER_DIR .value ())).getParentFile (), "testlib" ),
114+ "build/tmp/testprovisioner.mavenCentral.cache" );
115+ var cache = getImmutableSetImmutableSetMap (file );
121116 return (withTransitives , mavenCoordsRaw ) -> {
122- ImmutableSet < String > mavenCoords = ImmutableSet . copyOf (mavenCoordsRaw );
117+ var mavenCoords = copyOf (mavenCoordsRaw );
123118 synchronized (TestProvisioner .class ) {
124- ImmutableSet < File > result = cached .get (mavenCoords );
119+ var result = cache .get (mavenCoords );
125120 // double-check that depcache pruning hasn't removed them since our cache cached them
126- boolean needsToBeSet = result == null || !result .stream ().allMatch (file -> file .exists () && file .isFile () && file .length () > 0 );
127- if (needsToBeSet ) {
128- result = ImmutableSet .copyOf (input .get ().provisionWithTransitives (withTransitives , mavenCoords ));
129- cached .put (mavenCoords , result );
130- try (ObjectOutputStream outputStream = new ObjectOutputStream (Files .asByteSink (cacheFile ).openBufferedStream ())) {
131- outputStream .writeObject (cached );
121+ if (result == null || !result .stream ().allMatch (it -> it .exists () && it .isFile () && it .length () > 0 )) {
122+ result = copyOf (input .get ().provisionWithTransitives (withTransitives , mavenCoords ));
123+ cache .put (mavenCoords , result );
124+ try (var outputStream = new ObjectOutputStream (asByteSink (file ).openBufferedStream ())) {
125+ outputStream .writeObject (cache );
132126 } catch (IOException e ) {
133- throw Errors . asRuntime (e );
127+ throw asRuntime (e );
134128 }
135129 }
136130 return result ;
137131 }
138132 };
139133 }
140134
141- /** Creates a Provisioner for the mavenCentral repo. */
142- public static Provisioner mavenCentral () {
143- return MAVEN_CENTRAL .get ();
144- }
145-
146- private static final Supplier <Provisioner > MAVEN_CENTRAL = Suppliers .memoize (() -> caching ("mavenCentral" , () -> createWithRepositories (RepositoryHandler ::mavenCentral )));
147-
148- /** Creates a Provisioner for the local maven repo for development purpose. */
149- public static Provisioner mavenLocal () {
150- return createWithRepositories (RepositoryHandler ::mavenLocal );
135+ @ SuppressWarnings ("unchecked" )
136+ private static Map <ImmutableSet <String >, ImmutableSet <File >> getImmutableSetImmutableSetMap (final File cacheFile ) {
137+ if (cacheFile .exists ()) {
138+ try (var in = new ObjectInputStream (Files .asByteSource (cacheFile ).openBufferedStream ())) {
139+ return (Map <ImmutableSet <String >, ImmutableSet <File >>) in .readObject ();
140+ } catch (IOException | ClassNotFoundException e ) {
141+ throw asRuntime (e );
142+ }
143+ } else {
144+ try {
145+ createParentDirs (cacheFile );
146+ return new HashMap <>();
147+ } catch (IOException e ) {
148+ throw asRuntime (e );
149+ }
150+ }
151151 }
152152
153- /** Creates a Provisioner for the Sonatype snapshots maven repo for development purpose . */
154- public static Provisioner snapshots () {
155- return createWithRepositories ( repo -> repo . maven ( setup -> setup . setUrl ( "https://oss.sonatype.org/content/repositories/snapshots" )) );
153+ /** Creates a Provisioner for the mavenCentral repo. */
154+ public static Provisioner mavenCentral () {
155+ return memoize (() -> caching (() -> createWithRepositories ( RepositoryHandler :: mavenCentral ))). get ( );
156156 }
157157
158158}
0 commit comments