Some simplifications of dynamic CA/Reconcilng using PartialCollection

This commit is contained in:
Kris De Volder
2017-07-28 14:48:57 -07:00
parent 1c25764ff4
commit b520fdc577
7 changed files with 139 additions and 72 deletions

View File

@@ -192,36 +192,30 @@ public class BoshDeploymentManifestSchema implements YamlSchema {
addProp(t_instance_group_env, "bosh", t_params);
addProp(t_instance_group_env, "password", t_ne_string);
YType t_release_version = f.contextAware("ReleaseVersion", new SchemaContextAware<YType>() {
private AbstractType no_dynamic_checks = f.yenumFromDynamicValues("ReleaseVersion",
dc -> PartialCollection.compute(() -> releasesProvider.getModel(dc).getVersions())
)
.addHints("latest")
.parseWith(ValueParsers.NE_STRING);
private AbstractType base_type = f.yenumFromDynamicValues("ReleaseVersion",
dc -> PartialCollection.compute(() -> releasesProvider.getModel(dc).getVersions())
)
.addHints("latest")
.alsoAccept("latest");
@Override
public YType withContext(DynamicSchemaContext dc) throws Exception {
if (StringUtil.hasText(getCurrentEntityProperty(dc,"url"))) {
return no_dynamic_checks;
YType t_release_version = f.yenumFromDynamicValues("ReleaseVersion",
//message formatter:
dc -> (s, values) -> {
String name = getCurrentEntityProperty(dc, "name");
if (StringUtil.hasText(name)) {
return "'"+s+"' is an unknown 'ReleaseVersion[name="+name+"]'. Valid values are: "+values;
} else {
return "'"+s+"' is an unknown 'ReleaseVersion'. Valid values are: "+values;
}
},
//value provider:
dc -> {
PartialCollection<ReleaseData> releases = PartialCollection.compute(() -> releasesProvider.getModel(dc).getReleases());
if (StringUtil.hasText(getCurrentEntityProperty(dc, "url"))) {
releases = releases.addUncertainty();
} else {
String name = getCurrentEntityProperty(dc, "name");
if (StringUtil.hasText(name)) {
return f.yenumFromDynamicValues("ReleaseVersion[name="+name+"]", (_dc) ->
PartialCollection.compute(() -> releasesProvider.getModel(dc).getReleases())
.map(r -> name.equals(r.getName()) ? r.getVersion() : null)
)
.addHints("latest")
.alsoAccept("latest");
releases = releases.map(r -> name.equals(r.getName()) ? r : null);
}
}
return base_type;
return releases.map(r -> r.getVersion()).add("latest");
}
}).treatAsAtomic();
);
YBeanType t_release = f.ybean("Release");
addProp(t_release, "name", t_release_name_def).isPrimary(true);
@@ -244,34 +238,25 @@ public class BoshDeploymentManifestSchema implements YamlSchema {
YType t_stemcell_os_ref = f.yenumFromDynamicValues("StemcellOs", (dc) ->
PartialCollection.compute(() -> stemcellsProvider.getModel(dc).getStemcellOss())
);
YType t_stemcell_version_ref = f.contextAware("StemcellVersion", new SchemaContextAware<YType>() {
YAtomicType baseType = f.yenumFromDynamicValues("StemcellVersion", (dc) ->
PartialCollection.compute(() -> stemcellsProvider.getModel(dc).getVersions())
);
{
baseType.addHints("latest");
baseType.alsoAccept("latest");
}
@Override
public YType withContext(DynamicSchemaContext dc) throws Exception {
StemcellModel currentStemcell = getCurrentStemcell(dc);
if (StringUtil.hasText(currentStemcell.getName())||StringUtil.hasText(currentStemcell.getOs())) {
Predicate<StemcellData> filter = currentStemcell.createVersionFilter();
YAtomicType filteredType = f.yenumFromDynamicValues("StemcellVersion["+filter+"]", (_dc) -> {
//Note: it doesn't really matter whether we use _dc or dc in code below as they should be the same.
Predicate<StemcellData> versionFilter = currentStemcell.createVersionFilter();
return PartialCollection.compute(() -> stemcellsProvider.getModel(dc).getStemcells())
.map(sc -> versionFilter.test(sc) ? sc.getVersion() : null);
});
filteredType.addHints("latest");
filteredType.alsoAccept("latest");
return filteredType;
YType t_stemcell_version_ref = f.yenumFromDynamicValues("StemcellVersion",
(dc) -> (parseString, validValues) -> {
try {
Predicate<StemcellData> filter = getCurrentStemcell(dc).createVersionFilter();
if (filter!=StemcellModel.ALLWAYS_TRUE_FILTER) {
return "'"+parseString+"' is an unknown 'StemcellVersion["+filter+"]'. Valid values are: "+validValues;
}
} catch (Exception e) {
//ignore (parse error most likely)
}
return baseType;
return "'"+parseString+"' is an unknown 'StemcellVersion'. Valid values are: "+validValues;
},
(dc) -> {
Predicate<StemcellData> filter = getCurrentStemcell(dc).createVersionFilter();
return PartialCollection.compute(() -> stemcellsProvider.getModel(dc).getStemcells())
.map(sc -> filter.test(sc) ? sc.getVersion() : null)
.add("latest");
}
}).treatAsAtomic();
);
addProp(t_stemcell, "alias", t_stemcell_alias_def).isRequired(true);
addProp(t_stemcell, "version", t_stemcell_version_ref).isRequired(true);

View File

@@ -21,6 +21,16 @@ import org.yaml.snakeyaml.nodes.Node;
*/
public class StemcellModel {
public static final Predicate<StemcellData> ALLWAYS_TRUE_FILTER = new Predicate<StemcellData>() {
@Override
public boolean test(StemcellData sc) {
return true;
}
@Override
public String toString() {
return "true";
}
};
private Node node;
public StemcellModel(Node node) {
@@ -79,16 +89,7 @@ public class StemcellModel {
}
};
} else {
return new Predicate<StemcellData>() {
@Override
public boolean test(StemcellData sc) {
return true;
}
@Override
public String toString() {
return "true";
}
};
return ALLWAYS_TRUE_FILTER;
}
}

View File

@@ -1122,8 +1122,8 @@ public class BoshEditorTest {
);
editor.ignoreProblem(YamlSchemaProblems.MISSING_PROPERTY);
editor.assertProblems(
"123.4|unknown 'StemcellVersion[name=centos-agent]'. Valid values are: [222.2, 333.3]",
"333.3|unknown 'StemcellVersion[os=ubuntu]'. Valid values are: [123.4, 222.2]"
"123.4|unknown 'StemcellVersion[name=centos-agent]'. Valid values are: [222.2, 333.3, latest]",
"333.3|unknown 'StemcellVersion[os=ubuntu]'. Valid values are: [123.4, 222.2, latest]"
);
}
@@ -1200,6 +1200,17 @@ public class BoshEditorTest {
"latest<*>"
);
editor = harness.newEditor(
"releases:\n" +
"- name: foo\n" +
" version: <*>"
);
editor.assertContextualCompletions("<*>",
"123.4<*>",
"222.2<*>",
"latest<*>"
);
//Still get all suggestions even when 'url' property is added
editor = harness.newEditor(
"releases:\n" +
@@ -1213,6 +1224,19 @@ public class BoshEditorTest {
"latest<*>"
);
editor = harness.newEditor(
"releases:\n" +
"- name: foo\n" +
" url: blah\n" +
" version: <*>"
);
editor.assertContextualCompletions("<*>",
"123.4<*>",
"222.2<*>",
"333.3<*>",
"latest<*>"
);
}
@Test public void reconcileReleaseVersion() throws Exception {
@@ -1228,10 +1252,13 @@ public class BoshEditorTest {
"releases:\n" +
"- version: bogus\n" +
"- version: url-makes-this-possibly-correct\n" +
" url: file:///relesease-folder/blah-release.tar.gz"
" url: file:///relesease-folder/blah-release.tar.gz\n"+
"- name: bar\n" +
" version: url-makes-this-also-possibly-correct\n" +
" url: file:///relesease-folder/other-release.tar.gz"
);
editor.ignoreProblem(YamlSchemaProblems.MISSING_PROPERTY);
editor.assertProblems("bogus|unknown 'ReleaseVersion'. Valid values are: [123.4, 222.2, 333.3]");
editor.assertProblems("bogus|unknown 'ReleaseVersion'. Valid values are: [123.4, 222.2, 333.3, latest]");
editor = harness.newEditor(
"releases:\n" +
@@ -1240,7 +1267,32 @@ public class BoshEditorTest {
"- version: bogus\n"
);
editor.ignoreProblem(YamlSchemaProblems.MISSING_PROPERTY);
editor.assertProblems("bogus|unknown 'ReleaseVersion'. Valid values are: [123.4, 222.2, 333.3]");
editor.assertProblems("bogus|unknown 'ReleaseVersion'. Valid values are: [123.4, 222.2, 333.3, latest]");
editor = harness.newEditor(
"releases:\n" +
"- name: foo\n" +
" version: 123.4\n"
);
editor.ignoreProblem(YamlSchemaProblems.MISSING_PROPERTY);
editor.assertProblems(/*NONE*/);
editor = harness.newEditor(
"releases:\n" +
"- name: foo\n" +
" version: 222.2\n"
);
editor.ignoreProblem(YamlSchemaProblems.MISSING_PROPERTY);
editor.assertProblems(/*NONE*/);
editor = harness.newEditor(
"releases:\n" +
"- name: foo\n" +
" version: 333.3\n"
);
editor.ignoreProblem(YamlSchemaProblems.MISSING_PROPERTY);
editor.assertProblems("333.3|unknown 'ReleaseVersion[name=foo]'. Valid values are: [123.4, 222.2, latest]");
}

View File

@@ -64,7 +64,7 @@ public class EnumValueParser implements ValueParser {
PartialCollection<String> values = this.values.get();
// If values is not known (null) then just assume the str is acceptable.
// If values is not fully known then just assume the str is acceptable.
if (values == null || !values.isComplete() || values.getElements().contains(str)) {
return str;
} else {

View File

@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.util;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.Callable;
@@ -132,4 +133,7 @@ public class PartialCollection<T> {
return explanation;
}
public PartialCollection<T> add(@SuppressWarnings("unchecked") T... values) {
return addAll(Arrays.asList(values));
}
}

View File

@@ -855,7 +855,7 @@ public class YTypeFactory {
return ((YTypedPropertyImpl)prop).copy();
}
public YAtomicType yenumFromHints(String name, BiFunction<String, Collection<String>, String> errorMessageFormatter, SchemaContextAware<PartialCollection<YValueHint>> values) {
public YAtomicType yenumFromHints(String name, SchemaContextAware<BiFunction<String, Collection<String>, String>> errorMessageFormatter, SchemaContextAware<PartialCollection<YValueHint>> values) {
YAtomicType t = yatomic(name);
t.setHintProvider(values);
t.parseWith((DynamicSchemaContext dc) -> {
@@ -865,7 +865,11 @@ public class YTypeFactory {
return new EnumValueParser(name, strings) {
@Override
protected String createErrorMessage(String parseString, Collection<String> values) {
return errorMessageFormatter.apply(parseString, values);
try {
return errorMessageFormatter.withContext(dc).apply(parseString, values);
} catch (Exception e) {
return super.createErrorMessage(parseString, values);
}
}
};
}
@@ -874,10 +878,22 @@ public class YTypeFactory {
return t;
}
public YAtomicType yenumFromDynamicValues(String name,
SchemaContextAware<BiFunction<String, Collection<String>, String>> errorMessageFormatter,
SchemaContextAware<PartialCollection<String>> values
) {
return yenumFromHints(name,
//Error message formatter:
errorMessageFormatter,
//Hints provider:
(dc) -> hints(values.withContext(dc))
);
}
public YAtomicType yenumFromDynamicValues(String name, SchemaContextAware<PartialCollection<String>> values) {
return yenumFromHints(name,
//Error message formatter:
(parseString, validValues) -> "'"+parseString+"' is an unknown '"+name+"'. Valid values are: "+validValues,
(dc) -> (parseString, validValues) -> "'"+parseString+"' is an unknown '"+name+"'. Valid values are: "+validValues,
//Hints provider:
(dc) -> hints(values.withContext(dc))
);
@@ -887,7 +903,7 @@ public class YTypeFactory {
return new EnumTypeBuilder(name, values);
}
public YAtomicType yenum(String name, BiFunction<String, Collection<String>, String> errorMessageFormatter, SchemaContextAware<Collection<String>> values) {
public YAtomicType yenum(String name, SchemaContextAware<BiFunction<String, Collection<String>, String>> errorMessageFormatter, SchemaContextAware<Collection<String>> values) {
YAtomicType t = yatomic(name);
t.setHintProvider((dc) -> {
return PartialCollection.compute(() -> values.withContext(dc))
@@ -897,12 +913,21 @@ public class YTypeFactory {
EnumValueParser enumParser = new EnumValueParser(name, values.withContext(dc)) {
@Override
protected String createErrorMessage(String parseString, Collection<String> values) {
return errorMessageFormatter.apply(parseString, values);
try {
return errorMessageFormatter.withContext(dc).apply(parseString, values);
} catch (Exception e) {
return super.createErrorMessage(parseString, values);
}
}
};
return enumParser;
});
return t;
}
public YAtomicType yenum(String name, BiFunction<String, Collection<String>, String> errorMessageFormatter, SchemaContextAware<Collection<String>> values) {
return yenum(name, (dc) -> errorMessageFormatter, values);
}
public static Collection<String> values(Collection<YValueHint> hints) {

View File

@@ -171,7 +171,7 @@ public class PipelineYmlSchema implements YamlSchema {
t_version.addHints("latest", "every");
t_resource_type_name = f.yenumFromHints("ResourceType Name",
(parseString, validValues) -> {
(dc) -> (parseString, validValues) -> {
return "The '"+parseString+"' Resource Type does not exist. Existing types: "+validValues;
},
(DynamicSchemaContext dc) -> {