diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java index c2c122d68e01e..35cc15a7ba009 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java @@ -32,6 +32,7 @@ import io.quarkus.deployment.pkg.builditem.NativeImageBuildItem; import io.quarkus.deployment.pkg.builditem.NativeImageSourceJarBuildItem; import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem; +import io.quarkus.deployment.util.FileUtil; public class NativeImageBuildStep { @@ -82,8 +83,12 @@ public NativeImageBuildItem build(NativeConfig nativeConfig, NativeImageSourceJa String containerRuntime = nativeConfig.containerRuntime.orElse("docker"); // E.g. "/usr/bin/docker run -v {{PROJECT_DIR}}:/project --rm quarkus/graalvm-native-image" nativeImage = new ArrayList<>(); - Collections.addAll(nativeImage, containerRuntime, "run", "-v", - outputDir.toAbsolutePath() + ":/project:z"); + + String outputPath = outputDir.toAbsolutePath().toString(); + if (IS_WINDOWS) { + outputPath = FileUtil.translateToVolumePath(outputPath); + } + Collections.addAll(nativeImage, containerRuntime, "run", "-v", outputPath + ":/project:z"); if (IS_LINUX) { if ("docker".equals(containerRuntime)) { diff --git a/core/deployment/src/main/java/io/quarkus/deployment/util/FileUtil.java b/core/deployment/src/main/java/io/quarkus/deployment/util/FileUtil.java index cafb22c254750..24607ced1447e 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/util/FileUtil.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/util/FileUtil.java @@ -8,6 +8,9 @@ import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class FileUtil { @@ -48,4 +51,30 @@ public static byte[] readFileContents(InputStream inputStream) throws IOExceptio } return out.toByteArray(); } + + /** + * Translates a file path from the Windows Style to a syntax accepted by Docker, + * so that volumes be safely mounted in both Docker for Windows and the legacy + * Docker Toolbox. + *
+ * docker run -v //c/foo/bar:/somewhere (...)
+ *
+ * You should only use this method on Windows-style paths, and not Unix-style + * paths. + * + * @see https://github.com/quarkusio/quarkus/issues/5360 + * @param windowsStylePath A path formatted in Windows-style, e.g. "C:\foo\bar". + * @return A translated path accepted by Docker, e.g. "//c/foo/bar". + */ + public static String translateToVolumePath(String windowsStylePath) { + String translated = windowsStylePath.replace('\\', '/'); + Pattern p = Pattern.compile("^(\\w)(?:$|:(/)?(.*))"); + Matcher m = p.matcher(translated); + if (m.matches()) { + String slash = Optional.ofNullable(m.group(2)).orElse("/"); + String path = Optional.ofNullable(m.group(3)).orElse(""); + return "//" + m.group(1).toLowerCase() + slash + path; + } + return translated; + } } diff --git a/core/deployment/src/test/java/io/quarkus/deployment/util/FileUtilTest.java b/core/deployment/src/test/java/io/quarkus/deployment/util/FileUtilTest.java new file mode 100644 index 0000000000000..dcc09761c4738 --- /dev/null +++ b/core/deployment/src/test/java/io/quarkus/deployment/util/FileUtilTest.java @@ -0,0 +1,28 @@ +package io.quarkus.deployment.util; + +import static io.quarkus.deployment.util.FileUtil.translateToVolumePath; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class FileUtilTest { + + @Test + public void testTranslateToVolumePath() { + // Windows-Style paths are formatted. + assertEquals("//c/", translateToVolumePath("C")); + assertEquals("//c/", translateToVolumePath("C:")); + assertEquals("//c/", translateToVolumePath("C:\\")); + assertEquals("//c/Users", translateToVolumePath("C:\\Users")); + assertEquals("//c/Users/Quarkus/lambdatest-1.0-SNAPSHOT-native-image-source-jar", + translateToVolumePath("C:\\Users\\Quarkus\\lambdatest-1.0-SNAPSHOT-native-image-source-jar")); + + // Side effect for Unix-style path. + assertEquals("//c/Users/Quarkus", translateToVolumePath("c:/Users/Quarkus")); + + // Side effects for fancy inputs - for the sake of documentation. + assertEquals("something/bizarre", translateToVolumePath("something\\bizarre")); + assertEquals("something.bizarre", translateToVolumePath("something.bizarre")); + } + +}