Skip to content

Commit e453d8b

Browse files
authored
Sanitize project name when using directory name (#47)
* 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? * Added unit test for testDeriveProjectName
1 parent 304203c commit e453d8b

File tree

4 files changed

+48
-2
lines changed

4 files changed

+48
-2
lines changed

Sources/Container-Compose/Commands/ComposeDown.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public struct ComposeDown: AsyncParsableCommand {
8686
"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."
8787
)
8888
} else {
89-
projectName = URL(fileURLWithPath: cwd).lastPathComponent // Default to directory name
89+
projectName = deriveProjectName(cwd: cwd)
9090
print("Info: No 'name' field found in docker-compose.yml. Using directory name as project name: \(projectName ?? "")")
9191
}
9292

Sources/Container-Compose/Commands/ComposeUp.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public struct ComposeUp: AsyncParsableCommand, @unchecked Sendable {
119119
"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."
120120
)
121121
} else {
122-
projectName = URL(fileURLWithPath: cwd).lastPathComponent // Default to directory name
122+
projectName = deriveProjectName(cwd: cwd)
123123
print("Info: No 'name' field found in docker-compose.yml. Using directory name as project name: \(projectName ?? "")")
124124
}
125125

Sources/Container-Compose/Helper Functions.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ public func resolveVariable(_ value: String, with envVars: [String: String]) ->
9393
return resolvedValue
9494
}
9595

96+
/// Derives a project name from the current working directory. It replaces any '.' characters with
97+
/// '_' to ensure compatibility with container naming conventions.
98+
///
99+
/// - Parameter cwd: The current working directory path.
100+
/// - Returns: A sanitized project name suitable for container naming.
101+
public func deriveProjectName(cwd: String) -> String {
102+
// We need to replace '.' with _ because it is not supported in the container name
103+
let projectName = URL(fileURLWithPath: cwd).lastPathComponent.replacingOccurrences(of: ".", with: "_")
104+
return projectName
105+
}
106+
96107
extension String: @retroactive Error {}
97108

98109
/// A structure representing the result of a command-line process execution.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===----------------------------------------------------------------------===//
2+
// Copyright © 2025 Morris Richman and the Container-Compose project authors. All rights reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// https://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//===----------------------------------------------------------------------===//
16+
17+
import Testing
18+
import Foundation
19+
@testable import ContainerComposeCore
20+
21+
@Suite("Helper Functions Tests")
22+
struct HelperFunctionsTests {
23+
24+
@Test("Derive project name from current working directory - contains dot")
25+
func testDeriveProjectName() throws {
26+
var cwd = "/Users/user/Projects/My.Project"
27+
var projectName = deriveProjectName(cwd: cwd)
28+
#expect(projectName == "My_Project")
29+
30+
cwd = ".devcontainers"
31+
projectName = deriveProjectName(cwd: cwd)
32+
#expect(projectName == "_devcontainers")
33+
}
34+
35+
}

0 commit comments

Comments
 (0)