From c804241589383a7038a247bbc4da33792098eb50 Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Thu, 29 Jan 2026 19:09:24 +0100 Subject: [PATCH 1/2] Sanitize project name when using directory name We use the directory name as project name if none is specified. However directory names can contain a '.', which seems an invalid character for container names - at least I get errors when creating from `.devcontainers`. This PR just replaces '.' with '_', however there might be more forbidden characters we should replace? --- Sources/Container-Compose/Commands/ComposeDown.swift | 2 +- Sources/Container-Compose/Commands/ComposeUp.swift | 2 +- Sources/Container-Compose/Helper Functions.swift | 11 +++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Sources/Container-Compose/Commands/ComposeDown.swift b/Sources/Container-Compose/Commands/ComposeDown.swift index 9108900..9db241b 100644 --- a/Sources/Container-Compose/Commands/ComposeDown.swift +++ b/Sources/Container-Compose/Commands/ComposeDown.swift @@ -86,7 +86,7 @@ public struct ComposeDown: AsyncParsableCommand { "Note: The 'name' field currently only affects container naming (e.g., '\(name)-serviceName'). Full project-level isolation for other resources (networks, implicit volumes) is not implemented by this tool." ) } else { - projectName = URL(fileURLWithPath: cwd).lastPathComponent // Default to directory name + projectName = deriveProjectName(cwd: cwd) print("Info: No 'name' field found in docker-compose.yml. Using directory name as project name: \(projectName ?? "")") } diff --git a/Sources/Container-Compose/Commands/ComposeUp.swift b/Sources/Container-Compose/Commands/ComposeUp.swift index 4b6adc6..3446d81 100644 --- a/Sources/Container-Compose/Commands/ComposeUp.swift +++ b/Sources/Container-Compose/Commands/ComposeUp.swift @@ -119,7 +119,7 @@ public struct ComposeUp: AsyncParsableCommand, @unchecked Sendable { "Note: The 'name' field currently only affects container naming (e.g., '\(name)-serviceName'). Full project-level isolation for other resources (networks, implicit volumes) is not implemented by this tool." ) } else { - projectName = URL(fileURLWithPath: cwd).lastPathComponent // Default to directory name + projectName = deriveProjectName(cwd: cwd) print("Info: No 'name' field found in docker-compose.yml. Using directory name as project name: \(projectName ?? "")") } diff --git a/Sources/Container-Compose/Helper Functions.swift b/Sources/Container-Compose/Helper Functions.swift index 9e38521..9a21a2b 100644 --- a/Sources/Container-Compose/Helper Functions.swift +++ b/Sources/Container-Compose/Helper Functions.swift @@ -93,6 +93,17 @@ public func resolveVariable(_ value: String, with envVars: [String: String]) -> return resolvedValue } +/// Derives a project name from the current working directory. It replaces any '.' characters with +/// '_' to ensure compatibility with container naming conventions. +/// +/// - Parameter cwd: The current working directory path. +/// - Returns: A sanitized project name suitable for container naming. +public func deriveProjectName(cwd: String) -> String { + // We need to replace '.' with _ because it is not supported in the container name + let projectName = URL(fileURLWithPath: cwd).lastPathComponent.replacingOccurrences(of: ".", with: "_") + return projectName +} + extension String: @retroactive Error {} /// A structure representing the result of a command-line process execution. From d4c2c2805b5a8c4c7fe83441bf70f0a1f3d41d75 Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Fri, 30 Jan 2026 16:44:30 +0100 Subject: [PATCH 2/2] Added unit test for testDeriveProjectName --- .../HelperFunctionsTests.swift | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Tests/Container-Compose-StaticTests/HelperFunctionsTests.swift diff --git a/Tests/Container-Compose-StaticTests/HelperFunctionsTests.swift b/Tests/Container-Compose-StaticTests/HelperFunctionsTests.swift new file mode 100644 index 0000000..158c126 --- /dev/null +++ b/Tests/Container-Compose-StaticTests/HelperFunctionsTests.swift @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// Copyright © 2025 Morris Richman and the Container-Compose project authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//===----------------------------------------------------------------------===// + +import Testing +import Foundation +@testable import ContainerComposeCore + +@Suite("Helper Functions Tests") +struct HelperFunctionsTests { + + @Test("Derive project name from current working directory - contains dot") + func testDeriveProjectName() throws { + var cwd = "/Users/user/Projects/My.Project" + var projectName = deriveProjectName(cwd: cwd) + #expect(projectName == "My_Project") + + cwd = ".devcontainers" + projectName = deriveProjectName(cwd: cwd) + #expect(projectName == "_devcontainers") + } + +} \ No newline at end of file