Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions Sources/ContainerizationOCI/Platform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,27 @@ public struct Platform: Sendable, Equatable {
return .init(arch: normalized.arch, os: "linux", variant: normalized.variant)
}

/// The computed description, for example, `linux/arm64/v8`.
/// The computed description, for example, `linux/amd64` or `linux/arm/v7`.
///
/// `arm64`'s only defined variant is `v8`, which `==` and `hash` already treat as
/// equivalent to a `nil` variant. The redundant `v8` is therefore omitted so that
/// two equal arm64 platforms (one with `variant == nil`, one with `"v8"`) describe
/// identically as `linux/arm64`, rather than drifting between `arm64` and
/// `arm64/v8`. See apple/container#1542.
public var description: String {
let architecture = architecture
if let variant = variant {
if let variant, !Self.isRedundantVariant(variant, for: architecture) {
return "\(os)/\(architecture)/\(variant)"
}
return "\(os)/\(architecture)"
}

/// Whether `variant` is the canonical default for `architecture` and can be omitted
/// from the rendered description without losing information.
private static func isRedundantVariant(_ variant: String, for architecture: String) -> Bool {
architecture == "arm64" && variant == "v8"
}

/// The CPU architecture, for example, `amd64` or `arm64`.
public var architecture: String {
Self.normalizeArch(_rawArch).arch
Expand Down
36 changes: 36 additions & 0 deletions Tests/ContainerizationOCITests/OCIPlatformTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,40 @@ struct OCIPlatformTests {
set.insert(withoutVariant)
#expect(set.contains(withV8), "arm64/v8 must be found in a Set that contains arm64 with nil variant")
}

// MARK: - description consistency (issue apple/container#1542)

@Test func arm64_nilAndV8_sameDescription() {
let withoutVariant = Platform(arch: "arm64", os: "linux", variant: nil)
let withV8 = Platform(arch: "arm64", os: "linux", variant: "v8")
#expect(
withoutVariant.description == withV8.description,
"equal arm64 platforms must produce the same description"
)
}

@Test func arm64_descriptionDropsRedundantV8() {
let withV8 = Platform(arch: "arm64", os: "linux", variant: "v8")
#expect(withV8.description == "linux/arm64", "arm64/v8 is canonical arm64, rendered without the redundant variant")
}

@Test func arm64_nilVariantDescription() {
let withoutVariant = Platform(arch: "arm64", os: "linux", variant: nil)
#expect(withoutVariant.description == "linux/arm64")
}

@Test func arm64_fromStringWithV8DescriptionIsCanonical() throws {
let parsed = try Platform(from: "linux/arm64/v8")
#expect(parsed.description == "linux/arm64", "parsing arm64/v8 then describing must yield the canonical short form")
}

@Test func arm_v7_descriptionKeepsVariant() {
let armv7 = Platform(arch: "arm", os: "linux", variant: "v7")
#expect(armv7.description == "linux/arm/v7", "non-redundant variants such as arm/v7 must be preserved")
}

@Test func amd64_descriptionUnaffected() {
let amd64 = Platform(arch: "amd64", os: "linux")
#expect(amd64.description == "linux/amd64")
}
}