0
# Compose File Processing
1
2
Docker Compose file parsing, validation, and service definition extraction with support for multiple compose files and project naming.
3
4
## Capabilities
5
6
### ComposeFiles
7
8
Manages multiple compose files and aggregates their service definitions while handling project naming and service conflicts.
9
10
```java { .api }
11
/**
12
* Container for multiple compose files with aggregated service definitions
13
*/
14
public class ComposeFiles {
15
16
/**
17
* Creates a ComposeFiles instance from a list of compose files
18
* @param composeFiles List of compose file objects to process
19
* @throws IllegalArgumentException If service name conflicts exist
20
*/
21
public ComposeFiles(List<File> composeFiles);
22
23
/**
24
* Gets all service names across all compose files
25
* @return Set of unique service names
26
*/
27
public Set<String> getAllServiceNames();
28
29
/**
30
* Gets all service definitions from all compose files
31
* @return Map of service name to service definition
32
*/
33
public Map<String, ComposeServiceDefinition> getServiceDefinitions();
34
35
/**
36
* Gets the project name from the compose files
37
* @return Project name or null if not specified
38
*/
39
public String getProjectName();
40
41
/**
42
* Gets the list of compose files
43
* @return List of File objects
44
*/
45
public List<File> getFiles();
46
}
47
```
48
49
**Usage Examples:**
50
51
```java
52
import io.quarkus.devservices.deployment.compose.*;
53
import java.io.File;
54
import java.util.List;
55
56
// Process multiple compose files
57
List<File> files = List.of(
58
new File("docker-compose.yml"),
59
new File("docker-compose.override.yml"),
60
new File("compose-dev-services.yml")
61
);
62
63
ComposeFiles composeFiles = new ComposeFiles(files);
64
65
// Get aggregated information
66
Set<String> allServices = composeFiles.getAllServiceNames();
67
Map<String, ComposeServiceDefinition> definitions = composeFiles.getServiceDefinitions();
68
String projectName = composeFiles.getProjectName();
69
70
// Process each service
71
for (String serviceName : allServices) {
72
ComposeServiceDefinition definition = definitions.get(serviceName);
73
74
System.out.println("Service: " + serviceName);
75
System.out.println("Container: " + definition.getContainerName());
76
System.out.println("Ports: " + definition.getPorts());
77
System.out.println("Labels: " + definition.getLabels());
78
System.out.println("Profiles: " + definition.getProfiles());
79
}
80
81
// Use in ComposeProject
82
ComposeProject project = new ComposeProject.Builder(composeFiles, "docker")
83
.withProject(projectName != null ? projectName : "default-project")
84
.build();
85
```
86
87
### ComposeFile
88
89
Parses and validates individual Docker Compose files, extracting service definitions and project metadata.
90
91
```java { .api }
92
/**
93
* Representation of a docker-compose file with parsing and validation
94
*/
95
public class ComposeFile {
96
97
/**
98
* Creates a ComposeFile by parsing the given file
99
* @param composeFile File object pointing to compose file
100
* @throws IllegalArgumentException If file cannot be parsed
101
*/
102
public ComposeFile(File composeFile);
103
104
/**
105
* Gets the project name specified in the compose file
106
* @return Project name or null if not specified
107
*/
108
public String getProjectName();
109
110
/**
111
* Gets all service definitions from this compose file
112
* @return Map of service name to service definition
113
*/
114
public Map<String, ComposeServiceDefinition> getServiceDefinitions();
115
}
116
```
117
118
**Usage Examples:**
119
120
```java
121
// Parse a single compose file
122
File composeFile = new File("docker-compose.yml");
123
ComposeFile compose = new ComposeFile(composeFile);
124
125
// Get project and service information
126
String projectName = compose.getProjectName();
127
Map<String, ComposeServiceDefinition> services = compose.getServiceDefinitions();
128
129
System.out.println("Project: " + (projectName != null ? projectName : "unnamed"));
130
System.out.println("Services found: " + services.size());
131
132
// Process each service
133
for (Map.Entry<String, ComposeServiceDefinition> entry : services.entrySet()) {
134
String serviceName = entry.getKey();
135
ComposeServiceDefinition definition = entry.getValue();
136
137
System.out.println("\nService: " + serviceName);
138
if (definition.getContainerName() != null) {
139
System.out.println(" Container: " + definition.getContainerName());
140
}
141
if (definition.hasHealthCheck()) {
142
System.out.println(" Has health check: true");
143
}
144
if (!definition.getPorts().isEmpty()) {
145
System.out.println(" Exposed ports: " + definition.getPorts());
146
}
147
if (!definition.getProfiles().isEmpty()) {
148
System.out.println(" Profiles: " + definition.getProfiles());
149
}
150
}
151
152
// Handle parsing errors
153
try {
154
ComposeFile invalidFile = new ComposeFile(new File("invalid.yml"));
155
} catch (IllegalArgumentException e) {
156
System.err.println("Failed to parse compose file: " + e.getMessage());
157
}
158
```
159
160
### ComposeServiceDefinition
161
162
Represents an individual service definition from a Docker Compose file with access to all service configuration.
163
164
```java { .api }
165
/**
166
* Represents a service definition in a docker-compose file
167
*/
168
public class ComposeServiceDefinition {
169
170
/**
171
* Creates a service definition from compose data
172
* @param serviceName Name of the service
173
* @param definitionMap Raw service definition data from YAML
174
*/
175
public ComposeServiceDefinition(String serviceName, Map<String, ?> definitionMap);
176
177
/**
178
* Gets the service name
179
* @return Service name
180
*/
181
public String getServiceName();
182
183
/**
184
* Gets the container name if specified
185
* @return Container name or null if using default naming
186
*/
187
public String getContainerName();
188
189
/**
190
* Gets the exposed ports for this service
191
* @return List of ExposedPort objects, empty if no ports exposed
192
*/
193
public List<ExposedPort> getPorts();
194
195
/**
196
* Checks if the service has a health check defined
197
* @return true if health check is configured
198
*/
199
public boolean hasHealthCheck();
200
201
/**
202
* Gets all labels defined for this service
203
* @return Map of label keys to values, empty if no labels
204
*/
205
public Map<String, Object> getLabels();
206
207
/**
208
* Gets the profiles this service belongs to
209
* @return List of profile names, empty if no profiles
210
*/
211
public List<String> getProfiles();
212
}
213
```
214
215
**Usage Examples:**
216
217
```java
218
// Working with service definitions
219
ComposeServiceDefinition webService = serviceDefinitions.get("web");
220
221
// Basic service information
222
String serviceName = webService.getServiceName(); // "web"
223
String containerName = webService.getContainerName(); // "my-web-app" or null
224
225
// Port configuration
226
List<ExposedPort> ports = webService.getPorts();
227
for (ExposedPort port : ports) {
228
System.out.println("Exposed port: " + port.getPort());
229
}
230
231
// Health check configuration
232
if (webService.hasHealthCheck()) {
233
System.out.println("Service has health check configured");
234
// Health check details are handled by wait strategies
235
}
236
237
// Labels for configuration and wait strategies
238
Map<String, Object> labels = webService.getLabels();
239
String waitForLogs = (String) labels.get("quarkus.compose.wait-for.logs");
240
String portTimeout = (String) labels.get("quarkus.compose.wait-for.ports.timeout");
241
String configPort = (String) labels.get("quarkus.compose.config.port.8080");
242
243
if (waitForLogs != null) {
244
System.out.println("Wait for log message: " + waitForLogs);
245
}
246
247
// Profile-based conditional logic
248
List<String> profiles = webService.getProfiles();
249
boolean isDevService = profiles.contains("development");
250
boolean isTestService = profiles.contains("testing");
251
252
if (isDevService) {
253
System.out.println("Service is part of development profile");
254
}
255
256
// Creating service definitions programmatically (for testing)
257
Map<String, Object> serviceData = Map.of(
258
"image", "postgres:13",
259
"container_name", "dev-postgres",
260
"ports", List.of("5432:5432"),
261
"environment", Map.of("POSTGRES_PASSWORD", "secret"),
262
"labels", Map.of(
263
"quarkus.compose.config.port.5432", "DATABASE_URL",
264
"quarkus.compose.wait-for.logs", "database system is ready to accept connections"
265
),
266
"profiles", List.of("development", "testing")
267
);
268
269
ComposeServiceDefinition dbService = new ComposeServiceDefinition("database", serviceData);
270
```
271
272
### ComposeServiceWaitStrategyTarget
273
274
Implements Testcontainers wait strategy interface for compose services, providing container inspection and port information.
275
276
```java { .api }
277
/**
278
* A WaitStrategyTarget that represents a container in a docker-compose file
279
*/
280
public class ComposeServiceWaitStrategyTarget implements WaitStrategyTarget, Supplier<InspectContainerResponse> {
281
282
/**
283
* Creates a wait strategy target for a compose service container
284
* @param dockerClient Docker client for container operations
285
* @param container Container information from Docker API
286
*/
287
public ComposeServiceWaitStrategyTarget(DockerClient dockerClient, Container container);
288
289
/**
290
* Gets the exposed ports for this container
291
* @return List of exposed port numbers
292
*/
293
@Override
294
public List<Integer> getExposedPorts();
295
296
/**
297
* Gets the container ID
298
* @return Full container ID
299
*/
300
@Override
301
public String getContainerId();
302
303
/**
304
* Gets the service name from compose labels
305
* @return Service name
306
*/
307
public String getServiceName();
308
309
/**
310
* Gets the container number within the service
311
* @return Container number (1-based)
312
*/
313
public int getContainerNumber();
314
315
/**
316
* Gets the formatted container name
317
* @return Container name in format "service-number"
318
*/
319
public String getContainerName();
320
321
/**
322
* Gets detailed container information
323
* @return Container inspection response
324
*/
325
@Override
326
public InspectContainerResponse getContainerInfo();
327
328
/**
329
* Supplier interface implementation
330
* @return Container inspection response
331
*/
332
@Override
333
public InspectContainerResponse get();
334
}
335
```
336
337
**Usage Examples:**
338
339
```java
340
// Working with service wait strategy targets
341
List<ComposeServiceWaitStrategyTarget> services = composeProject.getServices();
342
343
for (ComposeServiceWaitStrategyTarget service : services) {
344
// Basic service information
345
String serviceName = service.getServiceName();
346
String containerName = service.getContainerName();
347
String containerId = service.getContainerId();
348
int containerNumber = service.getContainerNumber();
349
350
System.out.println("Service: " + serviceName);
351
System.out.println("Container: " + containerName + " (" + containerId.substring(0, 12) + ")");
352
353
// Port information
354
List<Integer> exposedPorts = service.getExposedPorts();
355
System.out.println("Exposed ports: " + exposedPorts);
356
357
// Detailed container inspection
358
InspectContainerResponse containerInfo = service.getContainerInfo();
359
String imageName = containerInfo.getConfig().getImage();
360
String status = containerInfo.getState().getStatus();
361
362
System.out.println("Image: " + imageName);
363
System.out.println("Status: " + status);
364
365
// Network information
366
Map<String, NetworkSettings> networks = containerInfo.getNetworkSettings().getNetworks();
367
for (Map.Entry<String, NetworkSettings> network : networks.entrySet()) {
368
String networkName = network.getKey();
369
String ipAddress = network.getValue().getIpAddress();
370
System.out.println("Network: " + networkName + " -> " + ipAddress);
371
}
372
}
373
374
// Using as Testcontainers wait strategy target
375
WaitStrategy healthCheck = Wait.forHealthcheck();
376
WaitStrategy logMessage = Wait.forLogMessage("Server started", 1);
377
WaitStrategy httpEndpoint = Wait.forHttp("/health").forStatusCode(200);
378
379
for (ComposeServiceWaitStrategyTarget service : services) {
380
if (service.getServiceName().equals("web-api")) {
381
// Apply wait strategy
382
try {
383
httpEndpoint.waitUntilReady(service);
384
System.out.println("Web API service is ready");
385
} catch (Exception e) {
386
System.err.println("Web API failed to become ready: " + e.getMessage());
387
}
388
}
389
}
390
```