From 7efa1460887bb72df41a61de76102c3ca5de8db4 Mon Sep 17 00:00:00 2001 From: Nick Krempel Date: Wed, 17 Aug 2016 17:49:04 +0100 Subject: [PATCH] Add support for environment variables in config.pb.json strings --- WORKSPACE | 5 ++ .../me/dinowernli/grpc/polyglot/config/BUILD | 1 + .../polyglot/config/ConfigurationLoader.java | 52 ++++++++++++++++++- third_party/commons-lang/BUILD | 9 ++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 third_party/commons-lang/BUILD diff --git a/WORKSPACE b/WORKSPACE index 0d38f9f..1f2dd2e 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -139,3 +139,8 @@ maven_jar( name = "google_gson_artifact", artifact = "com.google.code.gson:gson:2.6.2", ) + +maven_jar( + name = "apache_commons_lang3_artifact", + artifact = "org.apache.commons:commons-lang3:3.4", +) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/BUILD b/src/main/java/me/dinowernli/grpc/polyglot/config/BUILD index 3fbcd15..9d452d1 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/BUILD +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/BUILD @@ -7,6 +7,7 @@ java_library( "//src/main/proto:config_proto", "//src/main/java/me/dinowernli/grpc/polyglot/protobuf", "//third_party/args4j", + "//third_party/commons-lang", "//third_party/grpc", "//third_party/guava", "//third_party/netty", diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java index 8dd9f16..3cf3449 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java @@ -6,13 +6,18 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; +import com.google.protobuf.Descriptors; +import com.google.protobuf.Message; import com.google.protobuf.util.JsonFormat; +import org.apache.commons.lang3.text.StrSubstitutor; + import polyglot.ConfigProto.Configuration; import polyglot.ConfigProto.ConfigurationSet; import polyglot.ConfigProto.OutputConfiguration.Destination; @@ -53,13 +58,58 @@ public static ConfigurationLoader forFile(Path configFile) { ConfigurationSet.Builder configSetBuilder = ConfigurationSet.newBuilder(); String fileContent = Joiner.on('\n').join(Files.readAllLines(configFile)); JsonFormat.parser().merge(fileContent, configSetBuilder); + expandEnvironmentVariables(configSetBuilder); return ConfigurationLoader.forConfigSet(configSetBuilder.build()); } catch (IOException e) { throw new RuntimeException("Unable to read config file: " + configFile.toString(), e); } } - @VisibleForTesting + /** + * Expand all references to environment variables occurring in string fields (arbitrarily nested) + * in the given Protobuf message builder. + */ + private static void expandEnvironmentVariables(Message.Builder builder) { + expandVariables(builder, System.getenv()); + } + + /** + * Expand all references to variables (using the dollar and curly braces syntax) occurring in + * string fields (arbitrarily nested) in the given Protobuf message builder, using a given map + * of variable names to values. + */ + private static void expandVariables(Message.Builder builder, Map vars) { + for (Map.Entry field : builder.getAllFields().entrySet()) { + Descriptors.FieldDescriptor desc = field.getKey(); + Object value = field.getValue(); + switch (desc.getType()) { + case STRING: + if (desc.isRepeated()) { + int index = 0; + for (Object item : (List)value) { + builder.setRepeatedField(desc, index, StrSubstitutor.replace((String)item, vars)); + ++index; + } + } else { + builder.setField(desc, StrSubstitutor.replace((String)value, vars)); + } + break; + case MESSAGE: + case GROUP: + if (desc.isRepeated()) { + int count = builder.getRepeatedFieldCount(desc); + for (int i = 0; i < count; ++i) { + expandVariables(builder.getRepeatedFieldBuilder(desc, i), vars); + } + } else { + expandVariables(builder.getFieldBuilder(desc), vars); + } + break; + } + } + } + + @VisibleForTesting ConfigurationLoader(Optional configSet, Optional overrides) { this.configSet = configSet; this.overrides = overrides; diff --git a/third_party/commons-lang/BUILD b/third_party/commons-lang/BUILD new file mode 100644 index 0000000..3db89ac --- /dev/null +++ b/third_party/commons-lang/BUILD @@ -0,0 +1,9 @@ +package(default_visibility = ["//visibility:public"]) + +java_library( + name = "commons-lang", + exports = [ + "@apache_commons_lang3_artifact//jar", + ], + licenses = ["permissive"], +)