Skip to content

Commit 2c6a662

Browse files
committed
Polish the container.archive* implementation
1 parent 74a625d commit 2c6a662

File tree

2 files changed

+81
-10
lines changed

2 files changed

+81
-10
lines changed

api-client/src/main/kotlin/de/gesellix/docker/remote/api/client/ContainerApi.kt

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212
package de.gesellix.docker.remote.api.client
1313

14+
import com.squareup.moshi.Moshi
1415
import de.gesellix.docker.engine.DockerClientConfig
1516
import de.gesellix.docker.engine.RequestMethod.*
1617
import de.gesellix.docker.remote.api.ContainerChangeResponseItem
@@ -40,9 +41,12 @@ import kotlinx.coroutines.flow.collect
4041
import kotlinx.coroutines.launch
4142
import kotlinx.coroutines.runBlocking
4243
import kotlinx.coroutines.withTimeout
44+
import okio.source
45+
import java.io.InputStream
4346
import java.net.HttpURLConnection.HTTP_NOT_FOUND
4447
import java.net.HttpURLConnection.HTTP_NOT_MODIFIED
4548
import java.net.Proxy
49+
import java.util.*
4650

4751
class ContainerApi(dockerClientConfig: DockerClientConfig = defaultClientConfig, proxy: Proxy?) : ApiClient(dockerClientConfig, proxy) {
4852
constructor(dockerClientConfig: DockerClientConfig = defaultClientConfig) : this(dockerClientConfig, null)
@@ -66,15 +70,15 @@ class ContainerApi(dockerClientConfig: DockerClientConfig = defaultClientConfig,
6670
* @throws ServerException If the API returns a server error response
6771
*/
6872
@Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class)
69-
fun containerArchive(id: String, path: String) {
73+
fun containerArchive(id: String, path: String): java.io.File {
7074
val localVariableConfig = containerArchiveRequestConfig(id = id, path = path)
7175

72-
val localVarResponse = request<Any?>(
76+
val localVarResponse = request<java.io.File?>(
7377
localVariableConfig
7478
)
7579

7680
return when (localVarResponse.responseType) {
77-
ResponseType.Success -> Unit
81+
ResponseType.Success -> (localVarResponse as Success<*>).data as java.io.File
7882
ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.")
7983
ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.")
8084
ResponseType.ClientError -> {
@@ -123,15 +127,23 @@ class ContainerApi(dockerClientConfig: DockerClientConfig = defaultClientConfig,
123127
* @throws ServerException If the API returns a server error response
124128
*/
125129
@Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class)
126-
fun containerArchiveInfo(id: String, path: String) {
130+
fun containerArchiveInfo(id: String, path: String): Any? {
127131
val localVariableConfig = containerArchiveInfoRequestConfig(id = id, path = path)
128132

129133
val localVarResponse = request<Any?>(
130134
localVariableConfig
131135
)
132136

133-
return when (localVarResponse.responseType) {
134-
ResponseType.Success -> Unit
137+
when (localVarResponse.responseType) {
138+
ResponseType.Success -> {
139+
val stats = localVarResponse.headers["X-Docker-Container-Path-Stat".lowercase()]?.first()
140+
return if (stats == null) {
141+
null
142+
} else {
143+
val jsonAdapter = Moshi.Builder().build().adapter(Map::class.java)
144+
jsonAdapter.fromJson(String(Base64.getDecoder().decode(stats)))
145+
}
146+
}
135147
ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.")
136148
ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.")
137149
ResponseType.ClientError -> {
@@ -441,7 +453,8 @@ class ContainerApi(dockerClientConfig: DockerClientConfig = defaultClientConfig,
441453
*/
442454
@Suppress("UNCHECKED_CAST")
443455
@Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class)
444-
fun containerCreate(body: ContainerCreateRequest, name: String?): ContainerCreateResponse {
456+
@JvmOverloads
457+
fun containerCreate(body: ContainerCreateRequest, name: String? = ""): ContainerCreateResponse {
445458
val localVariableConfig = containerCreateRequestConfig(body = body, name = name)
446459

447460
val localVarResponse = request<ContainerCreateResponse>(
@@ -1653,7 +1666,7 @@ class ContainerApi(dockerClientConfig: DockerClientConfig = defaultClientConfig,
16531666
* @throws ServerException If the API returns a server error response
16541667
*/
16551668
@Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class)
1656-
fun putContainerArchive(id: String, path: String, inputStream: java.io.File, noOverwriteDirNonDir: String?, copyUIDGID: String?) {
1669+
fun putContainerArchive(id: String, path: String, inputStream: InputStream, noOverwriteDirNonDir: String?, copyUIDGID: String?) {
16571670
val localVariableConfig = putContainerArchiveRequestConfig(id = id, path = path, inputStream = inputStream, noOverwriteDirNonDir = noOverwriteDirNonDir, copyUIDGID = copyUIDGID)
16581671

16591672
val localVarResponse = request<Any?>(
@@ -1685,8 +1698,8 @@ class ContainerApi(dockerClientConfig: DockerClientConfig = defaultClientConfig,
16851698
* @param copyUIDGID If &#x60;1&#x60;, &#x60;true&#x60;, then it will copy UID/GID maps to the dest file or dir (optional)
16861699
* @return RequestConfig
16871700
*/
1688-
fun putContainerArchiveRequestConfig(id: String, path: String, inputStream: java.io.File, noOverwriteDirNonDir: String?, copyUIDGID: String?): RequestConfig {
1689-
val localVariableBody: Any? = inputStream
1701+
fun putContainerArchiveRequestConfig(id: String, path: String, inputStream: InputStream, noOverwriteDirNonDir: String?, copyUIDGID: String?): RequestConfig {
1702+
val localVariableBody: Any = inputStream.source()
16901703
val localVariableQuery: MultiValueMap = mutableMapOf<String, List<String>>()
16911704
.apply {
16921705
put("path", listOf(path))

api-client/src/test/java/de/gesellix/docker/remote/api/client/ContainerApiIntegrationTest.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import de.gesellix.docker.remote.api.ContainerUpdateRequest;
1010
import de.gesellix.docker.remote.api.ContainerUpdateResponse;
1111
import de.gesellix.docker.remote.api.EngineApiClient;
12+
import de.gesellix.docker.remote.api.ExecConfig;
13+
import de.gesellix.docker.remote.api.ExecStartConfig;
14+
import de.gesellix.docker.remote.api.IdResponse;
1215
import de.gesellix.docker.remote.api.RestartPolicy;
1316
import de.gesellix.docker.remote.api.core.Cancellable;
1417
import de.gesellix.docker.remote.api.core.ClientException;
@@ -20,13 +23,20 @@
2023
import de.gesellix.docker.remote.api.testutil.DockerEngineAvailable;
2124
import de.gesellix.docker.remote.api.testutil.Failsafe;
2225
import de.gesellix.docker.remote.api.testutil.InjectDockerClient;
26+
import de.gesellix.docker.remote.api.testutil.TarUtil;
2327
import de.gesellix.docker.remote.api.testutil.TestImage;
28+
import okio.Okio;
2429
import org.junit.jupiter.api.BeforeEach;
2530
import org.junit.jupiter.api.Test;
2631
import org.slf4j.Logger;
2732

33+
import java.io.File;
34+
import java.io.FileInputStream;
35+
import java.io.IOException;
36+
import java.io.InputStream;
2837
import java.time.Duration;
2938
import java.util.ArrayList;
39+
import java.util.Arrays;
3040
import java.util.HashMap;
3141
import java.util.List;
3242
import java.util.Map;
@@ -165,6 +175,54 @@ public void containerExport() {
165175
removeContainer(engineApiClient, "container-export");
166176
}
167177

178+
@Test
179+
public void containerArchiveInfoGetAndPut() throws IOException {
180+
imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null);
181+
182+
ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest(
183+
null, null, null,
184+
false, false, false,
185+
null,
186+
false, null, null,
187+
null,
188+
singletonList("-"),
189+
null,
190+
null,
191+
testImage.getImageWithTag(),
192+
null, null, null,
193+
null, null,
194+
null,
195+
singletonMap(LABEL_KEY, LABEL_VALUE),
196+
null, null,
197+
null,
198+
null,
199+
null
200+
);
201+
containerApi.containerCreate(containerCreateRequest, "container-archive-info-test");
202+
containerApi.containerStart("container-archive-info-test", null);
203+
204+
File archive = containerApi.containerArchive("container-archive-info-test", "/gattaca.txt");
205+
File extractedDir = new TarUtil().unTar(archive);
206+
String fileContent = Okio.buffer(Okio.source(new File(extractedDir, "gattaca.txt"))).readUtf8();
207+
assertEquals("The wind\ncaught it.\n", fileContent.replaceAll("\r", ""));
208+
209+
IdResponse containerExec = engineApiClient.getExecApi().containerExec(
210+
"container-archive-info-test",
211+
new ExecConfig(null, null, null, null, null, null,
212+
Arrays.asList("mkdir", "/tmp/test/"), null, null, null));
213+
engineApiClient.getExecApi().execStart(
214+
containerExec.getId(),
215+
new ExecStartConfig(null, null));
216+
217+
InputStream archiveStream = new FileInputStream(archive);
218+
containerApi.putContainerArchive("container-archive-info-test", "/tmp/test/", archiveStream, null, null);
219+
220+
Map<String, Object> archiveCopyInfo = (Map<String, Object>) containerApi.containerArchiveInfo("container-archive-info-test", "/tmp/test/gattaca.txt");
221+
assertEquals("gattaca.txt", archiveCopyInfo == null ? null : archiveCopyInfo.get("name"));
222+
223+
removeContainer(engineApiClient, "container-archive-info-test");
224+
}
225+
168226
@Test
169227
public void containerInspect() {
170228
imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null);

0 commit comments

Comments
 (0)