Skip to content

Commit 18c548d

Browse files
committed
Replace transport version utils with a build service
Several transport version build tasks have a need to access the repository-wide transport version resources. Thus far it has been done through several utility methods. This commit moves these utility methods into an encapsulated build service that is shared across the transport version tasks. The advantage is that no paths are used, the build service encapsulates access to the resources and understands internally how to find the correct filesystem path and load it.
1 parent 1235efc commit 18c548d

8 files changed

+325
-255
lines changed

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/GenerateTransportVersionManifestTask.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@
1010
package org.elasticsearch.gradle.internal.transport;
1111

1212
import org.gradle.api.DefaultTask;
13-
import org.gradle.api.file.DirectoryProperty;
1413
import org.gradle.api.file.RegularFileProperty;
14+
import org.gradle.api.provider.Property;
15+
import org.gradle.api.services.ServiceReference;
1516
import org.gradle.api.tasks.InputDirectory;
17+
import org.gradle.api.tasks.Optional;
1618
import org.gradle.api.tasks.OutputFile;
19+
import org.gradle.api.tasks.PathSensitive;
20+
import org.gradle.api.tasks.PathSensitivity;
1721
import org.gradle.api.tasks.TaskAction;
1822

1923
import java.io.IOException;
@@ -24,15 +28,24 @@
2428
import java.nio.file.attribute.BasicFileAttributes;
2529

2630
public abstract class GenerateTransportVersionManifestTask extends DefaultTask {
31+
32+
@ServiceReference("transportVersionResources")
33+
abstract Property<TransportVersionResourcesService> getTransportResources();
34+
2735
@InputDirectory
28-
public abstract DirectoryProperty getDefinitionsDirectory();
36+
@Optional
37+
@PathSensitive(PathSensitivity.RELATIVE)
38+
public Path getDefinitionsDirectory() {
39+
return getTransportResources().get().getDefinitionsDir();
40+
}
2941

3042
@OutputFile
3143
public abstract RegularFileProperty getManifestFile();
3244

3345
@TaskAction
3446
public void generateTransportVersionManifest() throws IOException {
35-
Path definitionsDir = getDefinitionsDirectory().get().getAsFile().toPath();
47+
48+
Path definitionsDir = getDefinitionsDirectory();
3649
Path manifestFile = getManifestFile().get().getAsFile().toPath();
3750
try (var writer = Files.newBufferedWriter(manifestFile)) {
3851
Files.walkFileTree(definitionsDir, new SimpleFileVisitor<>() {

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/TransportVersionReference.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@
1212
import org.gradle.api.attributes.Attribute;
1313
import org.gradle.api.attributes.AttributeContainer;
1414

15+
import java.io.File;
1516
import java.io.IOException;
1617
import java.nio.charset.StandardCharsets;
1718
import java.nio.file.Files;
1819
import java.nio.file.Path;
1920
import java.util.ArrayList;
21+
import java.util.HashSet;
2022
import java.util.List;
23+
import java.util.Set;
2124

2225
import static org.gradle.api.artifacts.type.ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE;
2326

@@ -43,6 +46,14 @@ static void addArtifactAttribute(AttributeContainer attributes) {
4346
attributes.attribute(REFERENCES_ATTRIBUTE, true);
4447
}
4548

49+
static Set<String> collectNames(Iterable<File> referencesFiles) throws IOException {
50+
Set<String> names = new HashSet<>();
51+
for (var referencesFile : referencesFiles) {
52+
listFromFile(referencesFile.toPath()).stream().map(TransportVersionReference::name).forEach(names::add);
53+
}
54+
return names;
55+
}
56+
4657
@Override
4758
public String toString() {
4859
return name + "," + location;

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/TransportVersionReferencesPlugin.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,12 @@
1313
import org.gradle.api.Plugin;
1414
import org.gradle.api.Project;
1515
import org.gradle.api.artifacts.Configuration;
16-
import org.gradle.api.file.Directory;
1716
import org.gradle.api.tasks.SourceSet;
1817
import org.gradle.language.base.plugins.LifecycleBasePlugin;
1918

20-
import static org.elasticsearch.gradle.internal.transport.TransportVersionUtils.getDefinitionsDirectory;
21-
import static org.elasticsearch.gradle.internal.transport.TransportVersionUtils.getResourcesDirectory;
22-
2319
public class TransportVersionReferencesPlugin implements Plugin<Project> {
2420

21+
2522
@Override
2623
public void apply(Project project) {
2724
project.getPluginManager().apply(LifecycleBasePlugin.class);
@@ -46,10 +43,6 @@ public void apply(Project project) {
4643
.register("validateTransportVersionReferences", ValidateTransportVersionReferencesTask.class, t -> {
4744
t.setGroup("Transport Versions");
4845
t.setDescription("Validates that all TransportVersion references used in the project have an associated definition file");
49-
Directory definitionsDir = getDefinitionsDirectory(getResourcesDirectory(project));
50-
if (definitionsDir.getAsFile().exists()) {
51-
t.getDefinitionsDirectory().set(definitionsDir);
52-
}
5346
t.getReferencesFile().set(collectTask.get().getOutputFile());
5447
});
5548
project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME).configure(t -> t.dependsOn(validateTask));

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/TransportVersionResourcesPlugin.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,18 @@
2020

2121
import java.util.Map;
2222

23-
import static org.elasticsearch.gradle.internal.transport.TransportVersionUtils.getDefinitionsDirectory;
24-
import static org.elasticsearch.gradle.internal.transport.TransportVersionUtils.getResourcesDirectory;
25-
2623
public class TransportVersionResourcesPlugin implements Plugin<Project> {
2724

2825
@Override
2926
public void apply(Project project) {
3027
project.getPluginManager().apply(LifecycleBasePlugin.class);
3128

29+
project.getGradle().getSharedServices().registerIfAbsent("transportVersionResources", TransportVersionResourcesService.class, spec -> {
30+
Directory transportResources = project.getLayout().getProjectDirectory().dir("src/main/resources/transport");
31+
spec.getParameters().getResourcesDirectory().set(transportResources);
32+
spec.getParameters().getRootDirectory().set(project.getRootProject().getRootDir());
33+
});
34+
3235
DependencyHandler depsHandler = project.getDependencies();
3336
Configuration tvReferencesConfig = project.getConfigurations().create("globalTvReferences");
3437
tvReferencesConfig.setCanBeConsumed(false);
@@ -46,10 +49,6 @@ public void apply(Project project) {
4649
.register("validateTransportVersionDefinitions", ValidateTransportVersionResourcesTask.class, t -> {
4750
t.setGroup("Transport Versions");
4851
t.setDescription("Validates that all defined TransportVersion constants are used in at least one project");
49-
Directory resourcesDir = getResourcesDirectory(project);
50-
if (resourcesDir.getAsFile().exists()) {
51-
t.getResourcesDirectory().set(resourcesDir);
52-
}
5352
t.getReferencesFiles().setFrom(tvReferencesConfig);
5453
});
5554
project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME).configure(t -> t.dependsOn(validateTask));
@@ -58,7 +57,6 @@ public void apply(Project project) {
5857
.register("generateTransportVersionManifest", GenerateTransportVersionManifestTask.class, t -> {
5958
t.setGroup("Transport Versions");
6059
t.setDescription("Generate a manifest resource for all the known transport version definitions");
61-
t.getDefinitionsDirectory().set(getDefinitionsDirectory(getResourcesDirectory(project)));
6260
t.getManifestFile().set(project.getLayout().getBuildDirectory().file("generated-resources/manifest.txt"));
6361
});
6462
project.getTasks().named(JavaPlugin.PROCESS_RESOURCES_TASK_NAME, Copy.class).configure(t -> {
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.gradle.internal.transport;
11+
12+
import org.gradle.api.file.DirectoryProperty;
13+
import org.gradle.api.services.BuildService;
14+
import org.gradle.api.services.BuildServiceParameters;
15+
import org.gradle.process.ExecOperations;
16+
import org.gradle.process.ExecResult;
17+
18+
import javax.inject.Inject;
19+
20+
import java.io.ByteArrayOutputStream;
21+
import java.io.IOException;
22+
import java.nio.charset.StandardCharsets;
23+
import java.nio.file.Files;
24+
import java.nio.file.Path;
25+
import java.util.ArrayList;
26+
import java.util.Collections;
27+
import java.util.HashMap;
28+
import java.util.HashSet;
29+
import java.util.List;
30+
import java.util.Map;
31+
import java.util.Set;
32+
import java.util.concurrent.atomic.AtomicReference;
33+
import java.util.function.BiFunction;
34+
35+
public abstract class TransportVersionResourcesService implements BuildService<TransportVersionResourcesService.Parameters> {
36+
37+
public interface Parameters extends BuildServiceParameters {
38+
DirectoryProperty getResourcesDirectory();
39+
DirectoryProperty getRootDirectory();
40+
}
41+
42+
@Inject
43+
public abstract ExecOperations getExecOperations();
44+
45+
private static final Path DEFINITIONS_DIR = Path.of("definitions");
46+
private static final Path NAMED_DIR = DEFINITIONS_DIR.resolve("named");
47+
private static final Path INITIAL_DIR = DEFINITIONS_DIR.resolve("initial");
48+
private static final Path LATEST_DIR = Path.of("latest");
49+
50+
private final Path resourcesDir;
51+
private final Path rootDir;
52+
private final AtomicReference<Set<String>> mainResources = new AtomicReference<>(null);
53+
private final AtomicReference<Set<String>> changedResources = new AtomicReference<>(null);
54+
55+
@Inject
56+
public TransportVersionResourcesService(Parameters params) {
57+
this.resourcesDir = params.getResourcesDirectory().get().getAsFile().toPath();
58+
this.rootDir = params.getRootDirectory().get().getAsFile().toPath();
59+
}
60+
61+
/**
62+
* Return the transport version resources directory for this repository.
63+
* This should be an input to any tasks reading resources from this service.
64+
*/
65+
Path getResourcesDir() {
66+
return resourcesDir;
67+
}
68+
69+
/**
70+
* Return the transport version definitions directory for this repository.
71+
* This should be an input to any tasks that only read definitions from this service.
72+
*/
73+
Path getDefinitionsDir() {
74+
return resourcesDir.resolve(DEFINITIONS_DIR);
75+
}
76+
77+
// return the path, relative to the resources dir, of a named definition
78+
private Path getNamedDefinitionRelativePath(String name) {
79+
return NAMED_DIR.resolve(name + ".csv");
80+
}
81+
82+
/** Return all named definitions, mapped by their name. */
83+
Map<String, TransportVersionDefinition> getNamedDefinitions() throws IOException {
84+
Map<String, TransportVersionDefinition> definitions = new HashMap<>();
85+
// temporarily include initial in named until validation understands the distinction
86+
for (var dir : List.of(NAMED_DIR, INITIAL_DIR)) {
87+
try (var definitionsStream = Files.list(resourcesDir.resolve(dir))) {
88+
for (var definitionFile : definitionsStream.toList()) {
89+
String contents = Files.readString(definitionFile, StandardCharsets.UTF_8).strip();
90+
var definition = TransportVersionDefinition.fromString(definitionFile.getFileName().toString(), contents);
91+
definitions.put(definition.name(), definition);
92+
}
93+
}
94+
}
95+
return definitions;
96+
}
97+
98+
/** Test whether the given named definition exists */
99+
TransportVersionDefinition getNamedDefinitionFromMain(String name) {
100+
String resourcePath = getNamedDefinitionRelativePath(name).toString();
101+
return getMainFile(resourcePath, TransportVersionDefinition::fromString);
102+
}
103+
104+
/** Test whether the given named definition exists */
105+
boolean namedDefinitionExists(String name) {
106+
return Files.exists(resourcesDir.resolve(getNamedDefinitionRelativePath(name)));
107+
}
108+
109+
/** Return the path within the repository of the given named definition */
110+
Path getRepositoryPath(TransportVersionDefinition definition) {
111+
return rootDir.relativize(resourcesDir.resolve(getNamedDefinitionRelativePath(definition.name())));
112+
}
113+
114+
/** Read all latest files and return them mapped by their release branch */
115+
Map<String, TransportVersionLatest> getLatestByReleaseBranch() throws IOException {
116+
Map<String, TransportVersionLatest> latests = new HashMap<>();
117+
try (var stream = Files.list(resourcesDir.resolve(LATEST_DIR))) {
118+
for (var latestFile : stream.toList()) {
119+
String contents = Files.readString(latestFile, StandardCharsets.UTF_8).strip();
120+
var latest = TransportVersionLatest.fromString(latestFile.getFileName().toString(), contents);
121+
latests.put(latest.name(), latest);
122+
}
123+
}
124+
return latests;
125+
}
126+
127+
/** Retrieve the latest transport version for the given release branch on main */
128+
TransportVersionLatest getLatestFromMain(String releaseBranch) {
129+
String resourcePath = getLatestRelativePath(releaseBranch).toString();
130+
return getMainFile(resourcePath, TransportVersionLatest::fromString);
131+
}
132+
133+
/** Return the path within the repository of the given latest */
134+
Path getRepositoryPath(TransportVersionLatest latest) {
135+
return rootDir.relativize(resourcesDir.resolve(getLatestRelativePath(latest.branch())));
136+
}
137+
138+
private Path getLatestRelativePath(String releaseBranch) {
139+
return LATEST_DIR.resolve(releaseBranch + ".csv");
140+
}
141+
142+
// Return the transport version resources paths that exist in main
143+
private Set<String> getMainResources() {
144+
if (mainResources.get() == null) {
145+
synchronized (mainResources) {
146+
String output = gitCommand("ls-tree", "--name-only", "-r", "main", ".");
147+
148+
HashSet<String> resources = new HashSet<>();
149+
Collections.addAll(resources, output.split(System.lineSeparator()));
150+
mainResources.set(resources);
151+
}
152+
}
153+
return mainResources.get();
154+
}
155+
156+
// Return the transport version resources paths that have been changed relative to main
157+
private Set<String> getChangedResources() {
158+
if (changedResources.get() == null) {
159+
synchronized (changedResources) {
160+
String output = gitCommand("diff", "--name-only", "main", ".");
161+
162+
HashSet<String> resources = new HashSet<>();
163+
Collections.addAll(resources, output.split(System.lineSeparator()));
164+
changedResources.set(resources);
165+
}
166+
}
167+
return changedResources.get();
168+
}
169+
170+
// Read a trasnport version resource from the main branch, or return null if it doesn't exist on main
171+
private <T> T getMainFile(String resourcePath, BiFunction<String, String, T> parser) {
172+
if (getMainResources().contains(resourcePath) == false) {
173+
return null;
174+
}
175+
String content = gitCommand("show", "main:./" + resourcePath).strip();
176+
return parser.apply(resourcePath, content);
177+
}
178+
179+
// run a git command, relative to the transport version resources directory
180+
private String gitCommand(String... args) {
181+
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
182+
183+
List<String> command = new ArrayList<>();
184+
Collections.addAll(command, "git", "-C", getResourcesDir().toString());
185+
Collections.addAll(command, args);
186+
187+
ExecResult result = getExecOperations().exec(spec -> {
188+
spec.setCommandLine(command);
189+
spec.setStandardOutput(stdout);
190+
spec.setErrorOutput(stdout);
191+
spec.setIgnoreExitValue(true);
192+
});
193+
194+
if (result.getExitValue() != 0) {
195+
throw new RuntimeException(
196+
"git command failed with exit code "
197+
+ result.getExitValue()
198+
+ System.lineSeparator()
199+
+ "command: "
200+
+ String.join(" ", command)
201+
+ System.lineSeparator()
202+
+ "output:"
203+
+ System.lineSeparator()
204+
+ stdout.toString(StandardCharsets.UTF_8)
205+
);
206+
}
207+
208+
return stdout.toString(StandardCharsets.UTF_8);
209+
}
210+
}

0 commit comments

Comments
 (0)