Skip to content

Commit c554374

Browse files
committed
adding gradle task to allow parsing of v2 format
1 parent ab694c7 commit c554374

File tree

2 files changed

+240
-0
lines changed

2 files changed

+240
-0
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package datadog.gradle.plugin.config
2+
3+
import org.gradle.api.DefaultTask
4+
import org.gradle.api.model.ObjectFactory
5+
import org.gradle.api.tasks.Input
6+
import org.gradle.api.tasks.InputFile
7+
import org.gradle.api.tasks.OutputDirectory
8+
import org.gradle.api.tasks.TaskAction
9+
import com.fasterxml.jackson.core.type.TypeReference
10+
import com.fasterxml.jackson.databind.ObjectMapper
11+
import org.gradle.api.tasks.CacheableTask
12+
import org.gradle.api.tasks.PathSensitive
13+
import org.gradle.api.tasks.PathSensitivity
14+
import java.io.File
15+
import java.io.FileInputStream
16+
import java.io.PrintWriter
17+
import javax.inject.Inject
18+
19+
@CacheableTask
20+
abstract class ParseV2SupportedConfigurationsTask @Inject constructor(
21+
private val objects: ObjectFactory
22+
) : DefaultTask() {
23+
@InputFile
24+
@PathSensitive(PathSensitivity.NONE)
25+
val jsonFile = objects.fileProperty()
26+
27+
@get:OutputDirectory
28+
val destinationDirectory = objects.directoryProperty()
29+
30+
@Input
31+
val className = objects.property(String::class.java)
32+
33+
@TaskAction
34+
fun generate() {
35+
val input = jsonFile.get().asFile
36+
val outputDir = destinationDirectory.get().asFile
37+
val finalClassName = className.get()
38+
outputDir.mkdirs()
39+
40+
// Read JSON (directly from the file, not classpath)
41+
val mapper = ObjectMapper()
42+
val fileData: Map<String, Any?> = FileInputStream(input).use { inStream ->
43+
mapper.readValue(inStream, object : TypeReference<Map<String, Any?>>() {})
44+
}
45+
46+
// Fetch top-level keys of JSON file
47+
@Suppress("UNCHECKED_CAST")
48+
val supportedRaw = fileData["supportedConfigurations"] as Map<String, List<Map<String, Any?>>>
49+
@Suppress("UNCHECKED_CAST")
50+
val deprecated = (fileData["deprecations"] as? Map<String, String>) ?: emptyMap()
51+
52+
// Generate alias map and reverse alias mapping
53+
val supported: Map<String, List<SupportedConfiguration>> = supportedRaw.mapValues { (_, configList) ->
54+
configList.map { configMap ->
55+
SupportedConfiguration(
56+
configMap["version"] as? String,
57+
configMap["type"] as? String,
58+
configMap["default"] as? String,
59+
(configMap["aliases"] as? List<String>) ?: emptyList(),
60+
(configMap["propertyKeys"] as? List<String>) ?: emptyList()
61+
)
62+
}
63+
}
64+
65+
// Top-level mapping from config -> list of aliases.
66+
// Note: This top-level alias mapping will be deprecated once Config Registry is mature enough to understand which version of a config a customer is using
67+
val aliases: Map<String, List<String>> = supported.mapValues { (_, configList) ->
68+
configList.flatMap { it.aliases }.distinct()
69+
}
70+
71+
val aliasMapping = mutableMapOf<String, String>()
72+
for ((canonical, alist) in aliases) {
73+
for (alias in alist) aliasMapping[alias] = canonical
74+
}
75+
76+
// Build the output .java path from the fully-qualified class name
77+
val pkgName = finalClassName.substringBeforeLast('.', "")
78+
val pkgPath = pkgName.replace('.', File.separatorChar)
79+
val simpleName = finalClassName.substringAfterLast('.')
80+
val pkgDir = if (pkgPath.isEmpty()) outputDir else File(outputDir, pkgPath).also { it.mkdirs() }
81+
val generatedFile = File(pkgDir, "$simpleName.java").absolutePath
82+
83+
// Call your existing generator (same signature as in your Java code)
84+
generateJavaFile(
85+
generatedFile,
86+
simpleName,
87+
pkgName,
88+
supported,
89+
aliases,
90+
aliasMapping,
91+
deprecated
92+
)
93+
}
94+
95+
private fun generateJavaFile(
96+
outputPath: String,
97+
className: String,
98+
packageName: String,
99+
supported: Map<String, List<SupportedConfiguration>>,
100+
aliases: Map<String, List<String>>,
101+
aliasMapping: Map<String, String>,
102+
deprecated: Map<String, String>
103+
) {
104+
val outFile = File(outputPath)
105+
outFile.parentFile?.mkdirs()
106+
107+
PrintWriter(outFile).use { out ->
108+
// NOTE: adjust these if you want to match task's className
109+
out.println("package $packageName;")
110+
out.println()
111+
out.println("import java.util.*;")
112+
out.println()
113+
out.println("public final class $className {")
114+
out.println()
115+
out.println(" public static final Map<String, List<SupportedConfiguration>> SUPPORTED;")
116+
out.println()
117+
out.println(" public static final Map<String, List<String>> ALIASES;")
118+
out.println()
119+
out.println(" public static final Map<String, String> ALIAS_MAPPING;")
120+
out.println()
121+
out.println(" public static final Map<String, String> DEPRECATED;")
122+
out.println()
123+
out.println(" static {")
124+
out.println()
125+
126+
// SUPPORTED
127+
out.println(" Map<String, List<SupportedConfiguration>> supportedMap = new HashMap<>();")
128+
for ((key, configList) in supported.toSortedMap()) {
129+
out.print(" supportedMap.put(\"${esc(key)}\", Collections.unmodifiableList(Arrays.asList(")
130+
val configIter = configList.iterator()
131+
while (configIter.hasNext()) {
132+
val config = configIter.next()
133+
out.print("new SupportedConfiguration(")
134+
out.print("${escNullableString(config.version)}, ")
135+
out.print("${escNullableString(config.type)}, ")
136+
out.print("${escNullableString(config.default)}, ")
137+
out.print("Arrays.asList(${quoteList(config.aliases)}), ")
138+
out.print("Arrays.asList(${quoteList(config.propertyKeys)})")
139+
out.print(")")
140+
if (configIter.hasNext()) out.print(", ")
141+
}
142+
out.println(")));\n")
143+
}
144+
out.println(" SUPPORTED = Collections.unmodifiableMap(supportedMap);")
145+
out.println()
146+
147+
// ALIASES
148+
out.println(" // Note: This top-level alias mapping will be deprecated once Config Registry is mature enough to understand which version of a config a customer is using")
149+
out.println(" Map<String, List<String>> aliasesMap = new HashMap<>();")
150+
for ((canonical, list) in aliases.toSortedMap()) {
151+
out.printf(
152+
" aliasesMap.put(\"%s\", Collections.unmodifiableList(Arrays.asList(%s)));\n",
153+
esc(canonical),
154+
quoteList(list)
155+
)
156+
}
157+
out.println(" ALIASES = Collections.unmodifiableMap(aliasesMap);")
158+
out.println()
159+
160+
// ALIAS_MAPPING
161+
out.println(" Map<String, String> aliasMappingMap = new HashMap<>();")
162+
for ((alias, target) in aliasMapping.toSortedMap()) {
163+
out.printf(" aliasMappingMap.put(\"%s\", \"%s\");\n", esc(alias), esc(target))
164+
}
165+
out.println(" ALIAS_MAPPING = Collections.unmodifiableMap(aliasMappingMap);")
166+
out.println()
167+
168+
// DEPRECATED
169+
out.println(" Map<String, String> deprecatedMap = new HashMap<>();")
170+
for ((oldKey, note) in deprecated.toSortedMap()) {
171+
out.printf(" deprecatedMap.put(\"%s\", \"%s\");\n", esc(oldKey), esc(note))
172+
}
173+
out.println(" DEPRECATED = Collections.unmodifiableMap(deprecatedMap);")
174+
out.println()
175+
out.println(" }")
176+
out.println("}")
177+
}
178+
}
179+
180+
private fun quoteList(list: List<String>): String =
181+
list.joinToString(", ") { "\"${esc(it)}\"" }
182+
183+
private fun esc(s: String): String =
184+
s.replace("\\", "\\\\").replace("\"", "\\\"")
185+
186+
private fun escNullableString(s: String?): String =
187+
if (s == null) "null" else "\"${esc(s)}\""
188+
}
189+
190+
data class SupportedConfiguration(
191+
val version: String?,
192+
val type: String?,
193+
val default: String?,
194+
val aliases: List<String>,
195+
val propertyKeys: List<String>
196+
)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package datadog.trace.config.inversion;
2+
3+
import java.util.List;
4+
5+
public class SupportedConfiguration {
6+
private final String version;
7+
private final String type;
8+
private final String defaultValue;
9+
private final List<String> aliases;
10+
private final List<String> propertyKeys;
11+
12+
public SupportedConfiguration(
13+
String version,
14+
String type,
15+
String defaultValue,
16+
List<String> aliases,
17+
List<String> propertyKeys) {
18+
this.version = version;
19+
this.type = type;
20+
this.defaultValue = defaultValue;
21+
this.aliases = aliases;
22+
this.propertyKeys = propertyKeys;
23+
}
24+
25+
public String getVersion() {
26+
return version;
27+
}
28+
29+
public String getType() {
30+
return type;
31+
}
32+
33+
public String getDefaultValue() {
34+
return defaultValue;
35+
}
36+
37+
public List<String> getAliases() {
38+
return aliases;
39+
}
40+
41+
public List<String> getPropertyKeys() {
42+
return propertyKeys;
43+
}
44+
}

0 commit comments

Comments
 (0)