-
Notifications
You must be signed in to change notification settings - Fork 20
/
SmithyExtension.java
213 lines (190 loc) · 8.09 KB
/
SmithyExtension.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package software.amazon.smithy.gradle;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
import org.gradle.api.GradleException;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.Project;
import org.gradle.api.file.Directory;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileSystemLocation;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.Internal;
import software.amazon.smithy.gradle.internal.DefaultSmithySourceDirectorySet;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.StringNode;
import software.amazon.smithy.model.traits.DynamicTrait;
import software.amazon.smithy.utils.IoUtils;
/**
* Gradle configuration settings for Smithy plugins.
*/
public abstract class SmithyExtension {
private static final String SMITHY_BUILD_CONFIG_DEFAULT = "smithy-build.json";
private static final String SMITHY_SOURCE_PROJECTION_DEFAULT = "source";
private static final String OUTPUT_DIRECTORY = "outputDirectory";
private final NamedDomainObjectContainer<SmithySourceDirectorySet> sourceSets;
@Inject
public SmithyExtension(Project project, ObjectFactory objectFactory) {
this.sourceSets = objectFactory.domainObjectContainer(SmithySourceDirectorySet.class,
name -> objectFactory.newInstance(DefaultSmithySourceDirectorySet.class,
objectFactory.sourceDirectorySet(name, name + " Smithy sources"))
);
configureDefaults(project);
}
private void configureDefaults(Project project) {
getSmithyBuildConfigs().convention(project.files(SMITHY_BUILD_CONFIG_DEFAULT));
getSourceProjection().convention(SMITHY_SOURCE_PROJECTION_DEFAULT);
getFork().convention(false);
getFormat().convention(true);
getAllowUnknownTraits().convention(false);
getOutputDirectory().convention(getDefaultOutputDirectory(project));
}
/**
* Collection of {@link org.gradle.api.file.SourceDirectorySet} associated with the {@link SmithyExtension}.
*
* @return container containing {@code SourceDirectorySet}s associated with {@link SmithyExtension}.
*/
public NamedDomainObjectContainer<SmithySourceDirectorySet> getSourceSets() {
return this.sourceSets;
}
/**
* Gets whether to execute the format task on files in the Smithy source set
*
* <p>By default formatting is run on all `.smithy` files in the Smithy
* source set.
*/
public abstract Property<Boolean> getFormat();
/**
* Gets a collection of smithy-build.json files to use when
* building the model.
*
* @return Returns the collection of build configurations.
*/
public abstract Property<FileCollection> getSmithyBuildConfigs();
/**
* Gets the projection name in use by the extension as the source (primary) projection.
*
* @return Returns the projection name. Defaults to "source".
*/
public abstract Property<String> getSourceProjection();
/**
* Get the tags that are searched for in classpaths when determining which
* models are projected into the created JAR.
*
* <p>This plugin will look through the JARs in the buildscript classpath
* to see if they contain a META-INF/MANIFEST.MF attribute named
* "Smithy-Tags" that matches any of the given projection source tags.
* The Smithy models found in each matching JAR are copied into the
* JAR being projected. This allows a projection JAR to aggregate models
* into a single JAR.
*
* @return Returns the tags. This will never return null.
*/
public abstract SetProperty<String> getProjectionSourceTags();
/**
* Get the tags that are added to the JAR.
*
* <p>These tags are placed in the META-INF/MANIFEST.MF attribute named
* "Smithy-Tags" as a comma separated list. JARs with Smithy-Tags can be
* queried when building projections so that the Smithy models found in
* each matching JAR are placed into the projection JAR.
*
* @return Returns the Smithy-Tags values that will be added to the created JAR.
*/
public abstract SetProperty<String> getTags();
/**
* Gets whether unknown traits in the model should be ignored.
*
* <p>By default, the build will fail if unknown traits are encountered.
* This can be set to true to allow unknown traits to pass through the
* model and be loaded as a {@link DynamicTrait}.
*
* @return Returns true if unknown traits are allowed.
*/
public abstract Property<Boolean> getAllowUnknownTraits();
/**
* Gets whether to fork when running the Smithy CLI.
*
* <p>By default, the CLI is run in the same process as Gradle,
* but inside a thread with a custom class loader. This should
* work in most cases, but there is an option to run inside a
* process if necessary.
*
* @return Returns true if the CLI should fork.
*/
public abstract Property<Boolean> getFork();
/**
* Gets the output directory for running Smithy build.
*
* @return Returns the output directory.
*/
public abstract DirectoryProperty getOutputDirectory();
/**
* Convenience method to get the directory containing plugin artifacts.
*
* @param projection projection name
* @param plugin name of plugin to get artifact directory for
*
* @return path to plugin artifact directory
*/
public Provider<Path> getPluginProjectionPath(String projection, String plugin) {
return getOutputDirectory().getAsFile()
.map(file -> SmithyUtils.getProjectionPluginPath(file, projection, plugin));
}
/**
* Gets the default directory to write smithy outputs to.
*
* <p>If an output directory is defined in the smithy-build.json then that is
* used. Otherwise, a smithyprojections output directory under the default gradle
* build directory is used.
*
* @param project gradle project
* @return provider that returns the default output directory
*/
@Internal
private Provider<Directory> getDefaultOutputDirectory(final Project project) {
return getSmithyBuildConfigs()
.flatMap(FileCollection::getElements)
.map(SmithyExtension::getOutputDirFromSmithyBuild)
.map(project::file)
.flatMap(file -> project.getLayout().getBuildDirectory().dir(file.getPath()))
.orElse(SmithyUtils.getProjectionOutputDirProperty(project));
}
private static String getOutputDirFromSmithyBuild(Set<FileSystemLocation> fileSystemLocations) {
return fileSystemLocations.stream()
.map(FileSystemLocation::getAsFile)
.map(File::toPath)
.map(SmithyExtension::parseOutputDirFromBuildConfig)
.filter(Optional::isPresent)
.map(Optional::get)
.reduce((a, b) -> {
throw new GradleException(
"Conflicting output directories defined in provided smithy build configs: "
+ a + ", " + b);
})
.orElse(null);
}
private static Optional<String> parseOutputDirFromBuildConfig(Path buildConfigPath) {
// The smithy-build.json file does not necessarily exist. If it does not exist
// do not try to read the config information
if (!Files.exists(buildConfigPath)) {
return Optional.empty();
}
return Node.parse(IoUtils.readUtf8File(buildConfigPath))
.expectObjectNode()
.getMember(OUTPUT_DIRECTORY)
.map(Node::expectStringNode)
.map(StringNode::getValue);
}
}