Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ This document is intended for Spotless developers.
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).

## [Unreleased]
### Fixed
- `P2Provisioner` now passes cache directory overrides directly to Solstice. ([#2944](https://github.com/diffplug/spotless/pull/2944))
### Changes
- `Formatter` no longer recomputes line-ending normalization (`LineEnding.toUnix`) a second time for every formatter step that changes content, removing redundant O(n) work from the core formatting loop. ([#2934](https://github.com/diffplug/spotless/pull/2934))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public interface P2Provisioner {
*
* @param modelWrapper wrapper around P2Model describing repositories and plugins to install
* @param mavenProvisioner provisioner for Maven dependencies (some P2 bundles are on Maven Central)
* @param cacheDirectory optional cache directory override
* @param cacheDirectory optional cache directory override passed directly to Solstice
* @return ordered list of JAR files forming the classpath
*/
List<File> provisionP2Dependencies(
Expand All @@ -55,7 +55,7 @@ static P2Provisioner createDefault() {
return (modelWrapper, mavenProvisioner, cacheDirectory) -> {
try {
if (cacheDirectory != null) {
CacheLocations.override_p2data = cacheDirectory.toPath().resolve("dev/equo/p2-data").toFile();
CacheLocations.override_p2data = cacheDirectory;
}
P2Model model = modelWrapper.unwrap();
P2QueryResult query = model.query(P2ClientCache.PREFER_OFFLINE, P2QueryCache.ALLOW);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/main/java/com/diffplug/spotless/Formatter.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 DiffPlug
* Copyright 2016-2026 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 2 additions & 0 deletions plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`).

## [Unreleased]
### Added
- Add `cacheDirectory(...)` to `eclipse()`, `eclipseCdt()`, and `greclipse()`; the default P2 cache is `$GRADLE_USER_HOME/caches/p2-data`. ([#2944](https://github.com/diffplug/spotless/pull/2944))
### Changes
- Improved formatting performance by eliminating redundant per-step line-ending normalization in the core formatter loop. ([#2934](https://github.com/diffplug/spotless/pull/2934))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,19 @@ public GrEclipseConfig withP2Mirrors(Map<String, String> mirrors) {
extension.replaceStep(builder.build());
return this;
}

/**
* Overrides the directory used to cache the P2 dependencies fetched by
* Equo/Solstice. Defaults to {@code $GRADLE_USER_HOME/caches/p2-data}.
*
* <p>Useful when the default location is not writable, or when you want to
* place the cache elsewhere.
*/
public GrEclipseConfig cacheDirectory(Object cacheDirectory) {
Objects.requireNonNull(cacheDirectory);
builder.setCacheDirectory(extension.getProject().file(cacheDirectory));
extension.replaceStep(builder.build());
return this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.inject.Inject;

Expand Down Expand Up @@ -81,6 +82,20 @@ public EclipseConfig withP2Mirrors(Map<String, String> mirrors) {
replaceStep(builder.build());
return this;
}

/**
* Overrides the directory used to cache the P2 dependencies fetched by
* Equo/Solstice. Defaults to {@code $GRADLE_USER_HOME/caches/p2-data}.
*
* <p>Useful when the default location is not writable, or when you want to
* place the cache elsewhere.
*/
public EclipseConfig cacheDirectory(Object cacheDirectory) {
Objects.requireNonNull(cacheDirectory);
builder.setCacheDirectory(getProject().file(cacheDirectory));
replaceStep(builder.build());
return this;
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public DedupingProvisioner dedupingProvisioner(Project project) {

public DedupingP2Provisioner dedupingP2Provisioner(Project project) {
return switch (this) {
case ROOT_PROJECT, ROOT_BUILDSCRIPT -> new DedupingP2Provisioner(P2Provisioner.createDefault());
case ROOT_PROJECT, ROOT_BUILDSCRIPT -> new DedupingP2Provisioner(P2Provisioner.createDefault(), defaultP2CacheDirectory(project));
default -> throw Unhandled.enumException(this);
};
}
Expand Down Expand Up @@ -156,6 +156,10 @@ private static Provisioner forConfigurationContainer(Project project, Configurat

private static final Logger LOGGER = LoggerFactory.getLogger(GradleProvisioner.class);

static File defaultP2CacheDirectory(Project project) {
return new File(project.getGradle().getGradleUserHomeDir(), "caches/p2-data");
}

/** Models a request to the provisioner. */
private static class Request {
final boolean withTransitives;
Expand Down Expand Up @@ -199,9 +203,15 @@ public String toString() {
static class DedupingP2Provisioner implements P2Provisioner {
private final Map<P2Request, List<File>> cache = new HashMap<>();
private final P2Provisioner p2Provisioner;
@Nullable private final File defaultCacheDirectory;

public DedupingP2Provisioner(P2Provisioner p2Provisioner) {
this(p2Provisioner, null);
}

public DedupingP2Provisioner(P2Provisioner p2Provisioner, @Nullable File defaultCacheDirectory) {
this.p2Provisioner = p2Provisioner;
this.defaultCacheDirectory = defaultCacheDirectory;
}

@Override
Expand All @@ -210,33 +220,35 @@ public synchronized List<File> provisionP2Dependencies(
Provisioner mavenProvisioner,
@Nullable File cacheDirectory) throws IOException {

File effectiveCacheDirectory = effectiveCacheDirectory(cacheDirectory);
P2Request req = new P2Request(
List.copyOf(modelWrapper.getP2Repos()),
List.copyOf(modelWrapper.getInstallList()),
Set.copyOf(modelWrapper.getFilterNames()),
List.copyOf(modelWrapper.getPureMaven()),
modelWrapper.isUseMavenCentral(),
cacheDirectory);
effectiveCacheDirectory);

List<File> result = cache.get(req);
if (result != null) {
return result;
}

result = p2Provisioner.provisionP2Dependencies(modelWrapper, mavenProvisioner, cacheDirectory);
result = p2Provisioner.provisionP2Dependencies(modelWrapper, mavenProvisioner, effectiveCacheDirectory);
cache.put(req, List.copyOf(result));
return result;
}

/** A child P2Provisioner which retrieves cached elements only. */
final P2Provisioner cachedOnly = (modelWrapper, mavenProvisioner, cacheDirectory) -> {
File effectiveCacheDirectory = effectiveCacheDirectory(cacheDirectory);
P2Request req = new P2Request(
List.copyOf(modelWrapper.getP2Repos()),
List.copyOf(modelWrapper.getInstallList()),
Set.copyOf(modelWrapper.getFilterNames()),
List.copyOf(modelWrapper.getPureMaven()),
modelWrapper.isUseMavenCentral(),
cacheDirectory);
effectiveCacheDirectory);
List<File> result;
synchronized (cache) {
result = cache.get(req);
Expand All @@ -247,6 +259,10 @@ public synchronized List<File> provisionP2Dependencies(
throw new GradleException("P2 dependencies not predeclared. Add Eclipse formatter configuration to the `spotlessPredeclare` block in the root project.");
};

@Nullable private File effectiveCacheDirectory(@Nullable File cacheDirectory) {
return cacheDirectory != null ? cacheDirectory : defaultCacheDirectory;
}

/**
* Cache key capturing all P2Model state that affects query results.
* Based on P2Model fields from equo-ide:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,20 @@ public EclipseConfig withP2Mirrors(Map<String, String> mirrors) {
return this;
}

/**
* Overrides the directory used to cache the P2 dependencies fetched by
* Equo/Solstice. Defaults to {@code $GRADLE_USER_HOME/caches/p2-data}.
*
* <p>Useful when the default location is not writable, or when you want to
* place the cache elsewhere.
*/
public EclipseConfig cacheDirectory(Object cacheDirectory) {
Objects.requireNonNull(cacheDirectory);
builder.setCacheDirectory(getProject().file(cacheDirectory));
replaceStep(builder.build());
return this;
}

}

/** Removes newlines between type annotations and types. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ P2Provisioner p2ProvisionerFor(SpotlessExtension spotless) {
return predeclaredP2Provisioner.cachedOnly;
} else {
return p2Provisioner.computeIfAbsent(spotless.project.getPath(),
unused -> new GradleProvisioner.DedupingP2Provisioner(P2Provisioner.createDefault()));
unused -> new GradleProvisioner.DedupingP2Provisioner(P2Provisioner.createDefault(), GradleProvisioner.defaultP2CacheDirectory(spotless.project)));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Stream;

Expand Down Expand Up @@ -262,6 +263,72 @@ void cachedOnlyCacheHitReturnsResult() throws IOException {
assertThat(result).isNotEmpty();
}

@Test
void defaultCacheDirectoryUsedWhenNoOverride() throws IOException {
AtomicReference<File> capturedCacheDirectory = new AtomicReference<>();
File defaultCacheDirectory = new File("gradle-home/caches/p2-data");
P2Provisioner underlying = (modelWrapper, mavenProvisioner, cacheDirectory) -> {
capturedCacheDirectory.set(cacheDirectory);
return List.of(new File("/mock/p2.jar"));
};
GradleProvisioner.DedupingP2Provisioner deduping = new GradleProvisioner.DedupingP2Provisioner(underlying, defaultCacheDirectory);

P2ModelWrapper model = createMockModel(
List.of("https://download.eclipse.org/eclipse/updates/4.26/"),
List.of("org.eclipse.jdt.core"),
Set.of(),
List.of(),
true,
null);

deduping.provisionP2Dependencies(model, mockProvisioner(), null);

assertThat(capturedCacheDirectory.get()).isEqualTo(defaultCacheDirectory);
}

@Test
void explicitCacheDirectoryOverridesDefault() throws IOException {
AtomicReference<File> capturedCacheDirectory = new AtomicReference<>();
File defaultCacheDirectory = new File("gradle-home/caches/p2-data");
File explicitCacheDirectory = new File("project/.spotless-p2");
P2Provisioner underlying = (modelWrapper, mavenProvisioner, cacheDirectory) -> {
capturedCacheDirectory.set(cacheDirectory);
return List.of(new File("/mock/p2.jar"));
};
GradleProvisioner.DedupingP2Provisioner deduping = new GradleProvisioner.DedupingP2Provisioner(underlying, defaultCacheDirectory);

P2ModelWrapper model = createMockModel(
List.of("https://download.eclipse.org/eclipse/updates/4.26/"),
List.of("org.eclipse.jdt.core"),
Set.of(),
List.of(),
true,
null);

deduping.provisionP2Dependencies(model, mockProvisioner(), explicitCacheDirectory);

assertThat(capturedCacheDirectory.get()).isEqualTo(explicitCacheDirectory);
}

@Test
void cachedOnlyUsesDefaultCacheDirectoryForLookup() throws IOException {
File defaultCacheDirectory = new File("gradle-home/caches/p2-data");
P2Provisioner underlying = mockP2Provisioner(new AtomicInteger(0));
GradleProvisioner.DedupingP2Provisioner deduping = new GradleProvisioner.DedupingP2Provisioner(underlying, defaultCacheDirectory);

P2ModelWrapper model = createMockModel(
List.of("https://download.eclipse.org/eclipse/updates/4.26/"),
List.of("org.eclipse.jdt.core"),
Set.of(),
List.of(),
true,
null);

deduping.provisionP2Dependencies(model, mockProvisioner(), null);

assertThat(deduping.cachedOnly.provisionP2Dependencies(model, mockProvisioner(), null)).isNotEmpty();
}

@Test
void cachedOnlyCacheMissThrowsException() {
P2Provisioner underlying = mockP2Provisioner(new AtomicInteger(0));
Expand Down
3 changes: 3 additions & 0 deletions plugin-maven/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).

## [Unreleased]
### Added
- Add `<cacheDirectory>` to `<eclipse>`, `<greclipse>`, and `<eclipseCdt>` for the Equo/Solstice P2 cache. ([#2944](https://github.com/diffplug/spotless/pull/2944))
### Fixed
- `spotless:apply` no longer aborts on the first file with lints; it now formats all files and reports a single aggregated lint failure across every file, matching the Gradle plugin's behavior. ([#2937](https://github.com/diffplug/spotless/pull/2937))
- `<greclipse>` and `<eclipseCdt>` now default P2 data to the Maven local repository. ([#2944](https://github.com/diffplug/spotless/pull/2944))
### Changes
- Improved formatting performance by eliminating redundant per-step line-ending normalization in the core formatter loop. ([#2934](https://github.com/diffplug/spotless/pull/2934))

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 DiffPlug
* Copyright 2016-2026 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,6 +15,8 @@
*/
package com.diffplug.spotless.maven;

import java.io.File;

import org.eclipse.aether.RepositorySystemSession;

import com.diffplug.spotless.FormatterStep;
Expand All @@ -26,4 +28,8 @@ public interface FormatterStepFactory {
default void init(RepositorySystemSession repositorySystemSession) {
// nothing
}

static File defaultP2CacheDirectory(RepositorySystemSession repositorySystemSession) {
return new File(repositorySystemSession.getLocalRepository().getBasedir(), "dev/equo/p2-data");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.List;

import org.apache.maven.plugins.annotations.Parameter;
import org.eclipse.aether.RepositorySystemSession;

import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.extra.EquoBasedStepBuilder;
Expand All @@ -40,6 +41,9 @@ public class EclipseCdt implements FormatterStepFactory {
@Parameter
private List<P2Mirror> p2Mirrors = new ArrayList<>();

@Parameter
private File cacheDirectory;

@Override
public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) {
EquoBasedStepBuilder eclipseConfig = EclipseCdtFormatterStep.createBuilder(stepConfig.getProvisioner(), stepConfig.getP2Provisioner());
Expand All @@ -49,6 +53,16 @@ public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) {
eclipseConfig.setPreferences(Arrays.asList(settingsFile));
}
eclipseConfig.setP2Mirrors(p2Mirrors);
if (cacheDirectory != null) {
eclipseConfig.setCacheDirectory(cacheDirectory);
}
return eclipseConfig.build();
}

@Override
public void init(RepositorySystemSession repositorySystemSession) {
if (cacheDirectory == null) {
cacheDirectory = FormatterStepFactory.defaultP2CacheDirectory(repositorySystemSession);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.List;

import org.apache.maven.plugins.annotations.Parameter;
import org.eclipse.aether.RepositorySystemSession;

import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.extra.EquoBasedStepBuilder;
Expand All @@ -40,6 +41,9 @@ public class GrEclipse implements FormatterStepFactory {
@Parameter
private List<P2Mirror> p2Mirrors = new ArrayList<>();

@Parameter
private File cacheDirectory;

@Override
public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) {
EquoBasedStepBuilder grEclipseConfig = GrEclipseFormatterStep.createBuilder(stepConfig.getProvisioner(), stepConfig.getP2Provisioner());
Expand All @@ -49,6 +53,16 @@ public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) {
grEclipseConfig.setPreferences(Arrays.asList(settingsFile));
}
grEclipseConfig.setP2Mirrors(p2Mirrors);
if (cacheDirectory != null) {
grEclipseConfig.setCacheDirectory(cacheDirectory);
}
return grEclipseConfig.build();
}

@Override
public void init(RepositorySystemSession repositorySystemSession) {
if (cacheDirectory == null) {
cacheDirectory = FormatterStepFactory.defaultP2CacheDirectory(repositorySystemSession);
}
}
}
Loading
Loading