diff --git a/src/Microsoft.Tye.Core/ApplicationFactory.cs b/src/Microsoft.Tye.Core/ApplicationFactory.cs index dfaaf289..522e1d73 100644 --- a/src/Microsoft.Tye.Core/ApplicationFactory.cs +++ b/src/Microsoft.Tye.Core/ApplicationFactory.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Tye.ConfigModel; @@ -112,7 +113,8 @@ namespace Microsoft.Tye Args = configService.Args, Replicas = configService.Replicas ?? 1, DockerFile = configService.DockerFile != null ? Path.Combine(source.DirectoryName, configService.DockerFile) : null, - DockerFileContext = configService.DockerFileContext != null ? Path.Combine(source.DirectoryName, configService.DockerFileContext) : null + // Supplying an absolute path with trailing slashes fails for DockerFileContext when calling docker build, so trim trailing slash. + DockerFileContext = GetDockerFileContext(source, configService) }; service = container; } @@ -323,6 +325,32 @@ namespace Microsoft.Tye return root; } + private static string? GetDockerFileContext(FileInfo source, ConfigService configService) + { + if (configService.DockerFileContext == null) + { + return null; + } + + // On windows, calling docker build with an aboslute path that ends in a trailing slash fails, + // but it's the exact opposite on linux, where it needs to have the trailing slash. + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return Path.TrimEndingDirectorySeparator(Path.Combine(source.DirectoryName, configService.DockerFileContext)); + } + else + { + var path = Path.Combine(source.DirectoryName, configService.DockerFileContext); + + if (!Path.EndsInDirectorySeparator(path)) + { + return path += Path.DirectorySeparatorChar; + } + + return path; + } + } + private static ConfigApplication GetNestedConfig(ConfigApplication rootConfig, string? file) { var nestedConfig = ConfigFactory.FromFile(new FileInfo(file)); diff --git a/src/Microsoft.Tye.Hosting/DockerRunner.cs b/src/Microsoft.Tye.Hosting/DockerRunner.cs index 0006ed26..49d53e7f 100644 --- a/src/Microsoft.Tye.Hosting/DockerRunner.cs +++ b/src/Microsoft.Tye.Hosting/DockerRunner.cs @@ -208,7 +208,7 @@ namespace Microsoft.Tye.Hosting { var dockerBuildResult = await ProcessUtil.RunAsync( $"docker", - $"build \"{docker.DockerFileContext?.DirectoryName ?? docker.DockerFile.DirectoryName}\" -t {dockerImage} -f \"{docker.DockerFile}\"", + $"build \"{docker.DockerFileContext?.FullName}\" -t {dockerImage} -f \"{docker.DockerFile}\"", docker.WorkingDirectory, throwOnError: false); diff --git a/src/tye/ApplicationBuilderExtensions.cs b/src/tye/ApplicationBuilderExtensions.cs index 53aaaf3a..dae5de1f 100644 --- a/src/tye/ApplicationBuilderExtensions.cs +++ b/src/tye/ApplicationBuilderExtensions.cs @@ -57,6 +57,10 @@ namespace Microsoft.Tye { dockerRunInfo.DockerFileContext = new FileInfo(container.DockerFileContext); } + else + { + dockerRunInfo.DockerFileContext = new FileInfo(dockerRunInfo.DockerFile.DirectoryName); + } } foreach (var mapping in container.Volumes) diff --git a/test/E2ETest/TyeRunTests.cs b/test/E2ETest/TyeRunTests.cs index f0a4ced2..0614c2be 100644 --- a/test/E2ETest/TyeRunTests.cs +++ b/test/E2ETest/TyeRunTests.cs @@ -701,6 +701,12 @@ services: bindings: - containerPort: 80 protocol: http +- name: backend2 + dockerFile: ./Dockerfile + dockerFileContext: ./backend + bindings: + - containerPort: 80 + protocol: http - name: frontend project: frontend/frontend.csproj"; @@ -721,11 +727,14 @@ services: { var frontendUri = await GetServiceUrl(client, uri, "frontend"); var backendUri = await GetServiceUrl(client, uri, "backend"); + var backend2Uri = await GetServiceUrl(client, uri, "backend2"); var backendResponse = await client.GetAsync(backendUri); + var backend2Response = await client.GetAsync(backend2Uri); var frontendResponse = await client.GetAsync(frontendUri); Assert.True(backendResponse.IsSuccessStatusCode); + Assert.True(backend2Response.IsSuccessStatusCode); Assert.True(frontendResponse.IsSuccessStatusCode); }); }