Skip to content

Commit 34bed86

Browse files
authored
feat!(core): redesign loader option system to use option library (#551)
1 parent b0a89d2 commit 34bed86

File tree

15 files changed

+465
-834
lines changed

15 files changed

+465
-834
lines changed

core/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ provides a node-based data structure able to handle a wide variety of configurat
1414
configurate.useAutoValue()
1515
dependencies {
1616
api libs.geantyref
17+
api libs.option
1718
testImplementation libs.checkerQual // needs to be on runtime classpath on Java 8 for object mapper
1819
compileOnlyApi libs.checkerQual
1920
testImplementation libs.guava

core/src/main/java/org/spongepowered/configurate/loader/AbstractConfigurationFormat.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public Set<String> supportedExtensions() {
8888
@Override
8989
public ConfigurationLoader<? extends @NonNull Object> create(final Path file, final ConfigurationNode options) {
9090
return this.builderMaker.get()
91-
.from(LoaderOptionSource.node(options))
91+
.editOptions(opts -> opts.values(ValueSources.node(options)))
9292
.path(file)
9393
.build();
9494
}
@@ -103,7 +103,7 @@ public Set<String> supportedExtensions() {
103103
@Override
104104
public ConfigurationLoader<? extends @NonNull Object> create(final URL url, final ConfigurationNode options) {
105105
return this.builderMaker.get()
106-
.from(LoaderOptionSource.node(options))
106+
.editOptions(opts -> opts.values(ValueSources.node(options)))
107107
.url(url)
108108
.build();
109109
}

core/src/main/java/org/spongepowered/configurate/loader/AbstractConfigurationLoader.java

Lines changed: 89 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
import static org.spongepowered.configurate.loader.ParsingException.UNKNOWN_POS;
2121

2222
import com.google.errorprone.annotations.ForOverride;
23+
import net.kyori.option.Option;
24+
import net.kyori.option.OptionSchema;
25+
import net.kyori.option.OptionState;
26+
import net.kyori.option.value.ValueSource;
27+
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
2328
import org.checkerframework.checker.nullness.qual.Nullable;
2429
import org.spongepowered.configurate.ConfigurateException;
2530
import org.spongepowered.configurate.ConfigurationNode;
@@ -45,6 +50,7 @@
4550
import java.util.Iterator;
4651
import java.util.List;
4752
import java.util.concurrent.Callable;
53+
import java.util.function.Consumer;
4854
import java.util.function.UnaryOperator;
4955
import java.util.regex.Pattern;
5056

@@ -119,7 +125,7 @@ public abstract class AbstractConfigurationLoader<N extends ScopedConfigurationN
119125
protected AbstractConfigurationLoader(final Builder<?, ?> builder, final CommentHandler[] commentHandlers) {
120126
this.source = builder.source();
121127
this.sink = builder.sink();
122-
this.headerMode = builder.headerMode();
128+
this.headerMode = builder.optionState().value(Builder.HEADER_MODE);
123129
this.commentHandlers = UnmodifiableCollections.toList(commentHandlers);
124130
this.defaultOptions = builder.defaultOptions();
125131
}
@@ -264,63 +270,107 @@ public final boolean canSave() {
264270
*/
265271
public abstract static class Builder<T extends Builder<T, L>, L extends AbstractConfigurationLoader<?>> {
266272

267-
protected static final LoaderOptionSource DEFAULT_OPTIONS_SOURCE = LoaderOptionSource.composite(
268-
LoaderOptionSource.systemProperties(),
269-
LoaderOptionSource.environmentVariables()
270-
);
273+
private static final String CONFIGURATE_PREFIX = "configurate";
271274

272-
protected HeaderMode headerMode = HeaderMode.PRESERVE;
275+
private static final OptionSchema.Mutable UNSAFE_SCHEMA = OptionSchema.emptySchema();
276+
protected static final OptionSchema SCHEMA = UNSAFE_SCHEMA.frozenView();
277+
278+
/**
279+
* How to read and emit headers discovered on documents processed by
280+
* the created loader.
281+
*
282+
* @since 4.2.0
283+
*/
284+
public static final Option<HeaderMode> HEADER_MODE = UNSAFE_SCHEMA.enumOption("header", HeaderMode.class, HeaderMode.PRESERVE);
285+
286+
@Deprecated
287+
protected HeaderMode headerMode;
288+
private OptionState.@MonotonicNonNull Builder optionBuilder;
289+
private @Nullable OptionState optionState;
273290
protected @Nullable Callable<BufferedReader> source;
274291
protected @Nullable Callable<BufferedWriter> sink;
275292
protected ConfigurationOptions defaultOptions = ConfigurationOptions.defaults();
276293

277294
/**
278295
* Create a new builder.
279296
*
280-
* <p>This is where any custom default options can be applied.</p>
281-
*
282-
* <p>At the end of this constructor, {@link #from(LoaderOptionSource)}
283-
* should be called with {@link #DEFAULT_OPTIONS_SOURCE} to read any supported
284-
* options from environment variables and system properties.</p>
285-
*
286297
* @since 4.0.0
287298
*/
288299
protected Builder() {}
289300

290301
/**
291-
* Populate this builder by reading options from the provided source.
302+
* Begin building an option state, initialized from the current
303+
* environment.
292304
*
293-
* <p>These options should control all options for the reading and
294-
* representation of nodes produced by this loader, specifically
295-
* excluding the {@link #source()} and {@link #sink()} of the loader,
296-
* and the {@link #defaultOptions()}.</p>
297-
*
298-
* <p>The options read from the provided source are format-defined.</p>
305+
* @return the pre-initialized option state builder
306+
* @since 4.2.0
307+
*/
308+
protected OptionState.Builder optionStateBuilder() {
309+
if (this.optionBuilder == null) {
310+
this.optionState = null;
311+
this.optionBuilder = this.optionSchema().stateBuilder()
312+
.values(ValueSource.systemProperty(CONFIGURATE_PREFIX))
313+
.values(ValueSource.environmentVariable(CONFIGURATE_PREFIX));
314+
}
315+
return this.optionBuilder;
316+
}
317+
318+
/**
319+
* Compute a snapshot of the currently set options for created loaders.
299320
*
300-
* @param source the source to read
301-
* @return this builder (for chaining)
321+
* @return the option state
302322
* @since 4.2.0
303323
*/
304-
public final T from(final LoaderOptionSource source) {
305-
requireNonNull(source, "source");
306-
final @Nullable HeaderMode headerMode = source.getEnum(HeaderMode.class, "header");
307-
if (headerMode != null) {
308-
this.headerMode = headerMode;
324+
public OptionState optionState() {
325+
if (this.optionState == null) {
326+
this.optionState = this.optionStateBuilder().build();
309327
}
310-
this.populate(source);
328+
return this.optionState;
329+
}
330+
331+
/**
332+
* Set the option state for this loader to the provided state.
333+
*
334+
* <p>The provided state must be within the
335+
* {@link #optionSchema() loader's schema}.</p>
336+
*
337+
* @param state the state
338+
* @return this builder
339+
* @since 4.2.0
340+
*/
341+
public T optionState(final OptionState state) {
342+
this.optionBuilder = this.optionSchema().stateBuilder()
343+
.values(state);
344+
this.optionState = null;
345+
311346
return this.self();
312347
}
313348

314349
/**
315-
* Populate options from the provided source.
350+
* Modify the state of loader options set on this loader.
316351
*
317-
* <p>The source will have already been validated for nullness.</p>
352+
* @param builderConsumer a consumer that receives the modifier to
353+
* perform changes
354+
* @return this builder
355+
* @since 4.2.0
356+
*/
357+
public T editOptions(final Consumer<OptionState.Builder> builderConsumer) {
358+
this.optionState = null;
359+
builderConsumer.accept(this.optionStateBuilder());
360+
return this.self();
361+
}
362+
363+
/**
364+
* Get the schema of available options that can be set on this loader.
318365
*
319-
* @param options the options to read
366+
* <p>This schema should inherit from {@link #UNSAFE_SCHEMA}.</p>
367+
*
368+
* @return the option schema
320369
* @since 4.2.0
321370
*/
322371
@ForOverride
323-
protected void populate(final LoaderOptionSource options) {
372+
protected OptionSchema optionSchema() {
373+
return SCHEMA; // fallback
324374
}
325375

326376
@SuppressWarnings("unchecked")
@@ -434,7 +484,7 @@ public T sink(final @Nullable Callable<BufferedWriter> sink) {
434484
* @since 4.0.0
435485
*/
436486
public T headerMode(final HeaderMode mode) {
437-
this.headerMode = requireNonNull(mode, "mode");
487+
this.optionStateBuilder().value(Builder.HEADER_MODE, mode);
438488
return self();
439489
}
440490

@@ -444,8 +494,14 @@ public T headerMode(final HeaderMode mode) {
444494
* @return the header mode
445495
* @since 4.0.0
446496
*/
497+
@SuppressWarnings("deprecation")
447498
public HeaderMode headerMode() {
448-
return this.headerMode;
499+
// manually overridden for some reason?
500+
if (this.headerMode != null) {
501+
this.optionStateBuilder().value(HEADER_MODE, this.headerMode);
502+
this.headerMode = null;
503+
}
504+
return this.optionState().value(HEADER_MODE);
449505
}
450506

451507
/**

0 commit comments

Comments
 (0)