use of no.entur.schema2proto.modifyproto.config.NewField in project schema2proto by entur.
the class ModifyProto method addField.
private void addField(NewField newField, Schema prunedSchema) throws InvalidProtobufException {
MessageType type = (MessageType) prunedSchema.getType(newField.targetMessageType);
if (type == null) {
throw new InvalidProtobufException("Did not find existing type " + newField.targetMessageType);
} else {
List<OptionElement> optionElements = new ArrayList<>();
Options options = new Options(Options.FIELD_OPTIONS, optionElements);
int tag = newField.fieldNumber;
String fieldPackage = StringUtils.substringBeforeLast(newField.type, ".");
if (fieldPackage.equals(newField.type)) {
// no package
fieldPackage = null;
}
Field.Label label = null;
if (StringUtils.trimToNull(newField.label) != null) {
label = Field.Label.valueOf(newField.label.toUpperCase());
}
Location location = new Location("", "", -1, -1);
Field field = new Field(fieldPackage, location, label, newField.name, StringUtils.trimToEmpty(newField.documentation), tag, null, newField.type, options, false, false);
List<Field> updatedFields = new ArrayList<>(type.fields());
updatedFields.add(field);
type.setDeclaredFields(updatedFields);
String importStatement = StringUtils.trimToNull(newField.importProto);
if (importStatement != null) {
String targetPackageName = StringUtils.trimToNull(StringUtils.substringBeforeLast(newField.targetMessageType, "."));
ProtoFile targetFile = prunedSchema.protoFileForPackage(targetPackageName);
if (newField.targetMessageType.equals(targetPackageName)) {
// no package name on target
targetFile = prunedSchema.protoFileForPackage(null);
}
targetFile.imports().add(importStatement);
}
}
}
use of no.entur.schema2proto.modifyproto.config.NewField in project schema2proto by entur.
the class ModifyProtoTest method testAddEnumValue.
@Test
public void testAddEnumValue() throws IOException, InvalidProtobufException, InvalidConfigurationException {
File expected = new File("src/test/resources/modify/expected/nopackagename").getCanonicalFile();
File source = new File("src/test/resources/modify/input/nopackagename").getCanonicalFile();
List<NewField> newFields = new ArrayList<>();
NewField newField = new NewField();
newField.targetMessageType = "A";
// newField.importProto = "importpackage/p.proto";
newField.label = "repeated";
newField.fieldNumber = 100;
newField.name = "new_field";
newField.type = "B";
newFields.add(newField);
ModifyProtoConfiguration configuration = new ModifyProtoConfiguration();
configuration.inputDirectory = source;
configuration.newFields = Collections.singletonList(newField);
modifyProto(configuration);
compareExpectedAndGenerated(expected, "extrafield.proto", generatedRootFolder, "simple.proto");
}
use of no.entur.schema2proto.modifyproto.config.NewField in project schema2proto by entur.
the class ModifyProtoTest method testAddField.
@Test
public void testAddField() throws IOException, InvalidProtobufException, InvalidConfigurationException {
File expected = new File("src/test/resources/modify/expected/nopackagename").getCanonicalFile();
File source = new File("src/test/resources/modify/input/nopackagename").getCanonicalFile();
NewField newField = new NewField();
newField.targetMessageType = "A";
// newField.importProto = "importpackage/p.proto";
newField.label = "repeated";
newField.fieldNumber = 100;
newField.name = "new_field";
newField.type = "B";
ModifyProtoConfiguration configuration = new ModifyProtoConfiguration();
configuration.inputDirectory = source;
configuration.newFields = Collections.singletonList(newField);
modifyProto(configuration);
compareExpectedAndGenerated(expected, "extrafield.proto", generatedRootFolder, "simple.proto");
}
use of no.entur.schema2proto.modifyproto.config.NewField in project schema2proto by entur.
the class ModifyProto method modifyProto.
public void modifyProto(ModifyProtoConfiguration configuration) throws IOException, InvalidProtobufException, InvalidConfigurationException {
SchemaLoader schemaLoader = new SchemaLoader();
// Collect source proto files (but not dependencies). Used to know which files should be written to .proto and which that should remain a dependency.
Collection<File> protoFiles = FileUtils.listFiles(configuration.inputDirectory, new String[] { "proto" }, true);
List<String> protosLoaded = protoFiles.stream().map(e -> configuration.inputDirectory.toURI().relativize(e.toURI()).getPath()).collect(Collectors.toList());
for (String importRootFolder : configuration.customImportLocations) {
schemaLoader.addSource(new File(configuration.basedir, importRootFolder).toPath());
}
schemaLoader.addSource(configuration.inputDirectory);
for (Path s : schemaLoader.sources()) {
LOGGER.info("Linking proto from path {}", s);
}
for (String s : schemaLoader.protos()) {
LOGGER.info("Linking proto {}", s);
}
Schema schema = schemaLoader.load();
// First run initial pruning, then look at the results and add referenced types from xsd.base_type
IdentifierSet.Builder initialIdentifierSet = new IdentifierSet.Builder();
initialIdentifierSet.exclude(configuration.excludes);
initialIdentifierSet.include(configuration.includes);
IdentifierSet finalIterationIdentifiers;
if (configuration.includeBaseTypes) {
finalIterationIdentifiers = followOneMoreLevel(initialIdentifierSet, schema);
} else {
finalIterationIdentifiers = initialIdentifierSet.build();
}
Schema prunedSchema = schema.prune(finalIterationIdentifiers);
for (String s : finalIterationIdentifiers.unusedExcludes()) {
LOGGER.warn("Unused exclude: {} (already excluded elsewhere or explicitly included?)", s);
}
for (String s : finalIterationIdentifiers.unusedIncludes()) {
LOGGER.warn("Unused include: {} (already included elsewhere or explicitly excluded?) ", s);
}
for (NewField newField : configuration.newFields) {
addField(newField, prunedSchema);
}
for (NewEnumConstant newEnumValue : configuration.newEnumConstants) {
addEnumConstant(newEnumValue, prunedSchema);
}
for (MergeFrom mergeFrom : configuration.mergeFrom) {
mergeFromFile(mergeFrom, prunedSchema, configuration);
}
for (FieldOption fieldOption : configuration.fieldOptions) {
addFieldOption(fieldOption, prunedSchema);
}
Set<Boolean> possibleIncompatibilitiesDetected = new HashSet<>();
if (configuration.protoLockFile != null) {
try {
ProtolockBackwardsCompatibilityChecker backwardsCompatibilityChecker = new ProtolockBackwardsCompatibilityChecker();
backwardsCompatibilityChecker.init(configuration.protoLockFile);
ImmutableList<ProtoFile> files = prunedSchema.protoFiles();
files.stream().forEach(file -> possibleIncompatibilitiesDetected.add(backwardsCompatibilityChecker.resolveBackwardIncompatibilities(file)));
} catch (FileNotFoundException e) {
throw new InvalidConfigurationException("Could not find proto.lock file, check configuration");
}
}
if (configuration.includeGoPackageOptions) {
includeGoPackageNameOptions(prunedSchema.protoFiles(), configuration.goPackageSourcePrefix);
}
Set<String> emptyImportLocations = protosLoaded.stream().map(prunedSchema::protoFile).filter(Objects::nonNull).filter(this::isEmptyFile).map(p -> p.location().getPath()).collect(Collectors.toSet());
protosLoaded.stream().map(prunedSchema::protoFile).filter(Objects::nonNull).filter(p -> !isEmptyFile(p)).forEach(file -> {
file.imports().removeIf(emptyImportLocations::contains);
file.publicImports().removeIf(emptyImportLocations::contains);
File outputFile = new File(configuration.outputDirectory, file.location().getPath());
outputFile.getParentFile().mkdirs();
try (Writer writer = new FileWriter(outputFile)) {
writer.write(file.toSchema());
} catch (IOException e) {
throw new RuntimeException(e);
}
LOGGER.info("Wrote file {}", outputFile.getPath());
});
if (configuration.failIfRemovedFields && possibleIncompatibilitiesDetected.contains(Boolean.TRUE)) {
throw new BackwardsCompatibilityCheckException("Backwards incompatibilities detected. Check warnings messages above. To ignore warnings, rerun with -DfailIfRemovedFields=false");
}
}
Aggregations