|
23 | 23 | import java.util.HashMap; |
24 | 24 | import java.util.Map; |
25 | 25 | import java.util.Set; |
| 26 | +import java.util.regex.Matcher; |
| 27 | +import java.util.regex.Pattern; |
26 | 28 |
|
27 | 29 | /** |
28 | 30 | * Representation of a docker-compose file, with partial parsing for validation and extraction of a minimal set of |
@@ -144,7 +146,8 @@ private void validateNoContainerNameSpecified(String serviceName, Map<String, ?> |
144 | 146 | private void findServiceImageName(String serviceName, Map<String, ?> serviceDefinitionMap) { |
145 | 147 | Object result = serviceDefinitionMap.get("image"); |
146 | 148 | if (result instanceof String) { |
147 | | - final String imageName = (String) result; |
| 149 | + final String rawImageName = (String) result; |
| 150 | + final String imageName = substituteEnvironmentVariables(rawImageName); |
148 | 151 | log.debug("Resolved dependency image for Docker Compose in {}: {}", composeFileName, imageName); |
149 | 152 | serviceNameToImageNames.put(serviceName, Sets.newHashSet(imageName)); |
150 | 153 | } |
@@ -192,4 +195,89 @@ private void findImageNamesInDockerfile(String serviceName, Map<String, ?> servi |
192 | 195 | } |
193 | 196 | } |
194 | 197 | } |
| 198 | + |
| 199 | + /** |
| 200 | + * Substitutes environment variables in a string following Docker Compose variable substitution rules. |
| 201 | + * Supports patterns like ${VAR}, ${VAR:-default}, and $VAR. |
| 202 | + * |
| 203 | + * @param text the text containing variables to substitute |
| 204 | + * @return the text with variables substituted with their environment values |
| 205 | + */ |
| 206 | + private String substituteEnvironmentVariables(String text) { |
| 207 | + if (text == null) { |
| 208 | + return null; |
| 209 | + } |
| 210 | + |
| 211 | + // Pattern for ${VAR} or ${VAR:-default} or ${VAR-default} |
| 212 | + Pattern bracedPattern = Pattern.compile("\\$\\{([^}]+)\\}"); |
| 213 | + // Pattern for $VAR (word characters only) |
| 214 | + Pattern simplePattern = Pattern.compile("\\$([a-zA-Z_][a-zA-Z0-9_]*)"); |
| 215 | + |
| 216 | + String result = text; |
| 217 | + |
| 218 | + // Handle ${VAR} and ${VAR:-default} patterns first |
| 219 | + Matcher bracedMatcher = bracedPattern.matcher(result); |
| 220 | + StringBuffer sb = new StringBuffer(); |
| 221 | + while (bracedMatcher.find()) { |
| 222 | + String varExpression = bracedMatcher.group(1); |
| 223 | + String replacement = expandVariableExpression(varExpression); |
| 224 | + bracedMatcher.appendReplacement(sb, Matcher.quoteReplacement(replacement)); |
| 225 | + } |
| 226 | + bracedMatcher.appendTail(sb); |
| 227 | + result = sb.toString(); |
| 228 | + |
| 229 | + // Handle $VAR patterns |
| 230 | + Matcher simpleMatcher = simplePattern.matcher(result); |
| 231 | + sb = new StringBuffer(); |
| 232 | + while (simpleMatcher.find()) { |
| 233 | + String varName = simpleMatcher.group(1); |
| 234 | + String value = getVariableValue(varName); |
| 235 | + if (value != null) { |
| 236 | + simpleMatcher.appendReplacement(sb, Matcher.quoteReplacement(value)); |
| 237 | + } else { |
| 238 | + simpleMatcher.appendReplacement(sb, Matcher.quoteReplacement(simpleMatcher.group(0))); |
| 239 | + } |
| 240 | + } |
| 241 | + simpleMatcher.appendTail(sb); |
| 242 | + |
| 243 | + return sb.toString(); |
| 244 | + } |
| 245 | + |
| 246 | + /** |
| 247 | + * Gets the value of a variable, checking environment variables first, then system properties. |
| 248 | + */ |
| 249 | + private String getVariableValue(String varName) { |
| 250 | + String value = System.getenv(varName); |
| 251 | + if (value == null) { |
| 252 | + value = System.getProperty(varName); |
| 253 | + } |
| 254 | + return value; |
| 255 | + } |
| 256 | + |
| 257 | + /** |
| 258 | + * Expands a variable expression that may contain default values. |
| 259 | + * Handles formats like "VAR", "VAR:-default", and "VAR-default". |
| 260 | + */ |
| 261 | + private String expandVariableExpression(String expression) { |
| 262 | + // Check for default value patterns |
| 263 | + if (expression.contains(":-")) { |
| 264 | + // ${VAR:-default} - use default if VAR is unset or empty |
| 265 | + String[] parts = expression.split(":-", 2); |
| 266 | + String varName = parts[0]; |
| 267 | + String defaultValue = parts.length > 1 ? parts[1] : ""; |
| 268 | + String value = getVariableValue(varName); |
| 269 | + return (value != null && !value.isEmpty()) ? value : defaultValue; |
| 270 | + } else if (expression.contains("-")) { |
| 271 | + // ${VAR-default} - use default if VAR is unset (but not if empty) |
| 272 | + String[] parts = expression.split("-", 2); |
| 273 | + String varName = parts[0]; |
| 274 | + String defaultValue = parts.length > 1 ? parts[1] : ""; |
| 275 | + String value = getVariableValue(varName); |
| 276 | + return (value != null) ? value : defaultValue; |
| 277 | + } else { |
| 278 | + // Simple variable ${VAR} |
| 279 | + String value = getVariableValue(expression); |
| 280 | + return value != null ? value : "${" + expression + "}"; |
| 281 | + } |
| 282 | + } |
195 | 283 | } |
0 commit comments