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
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,15 @@ class CopyFilesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, FilesBasedBui
override func constructTasksForRule(_ rule: any BuildRuleAction, _ group: FileToBuildGroup, _ buildFilesContext: BuildFilesProcessingContext, _ scope: MacroEvaluationScope, _ delegate: any TaskGenerationDelegate) async {
let dstFolder = computeOutputDirectory(scope)

// FIXME: Merge the region variant.
// Merge the region variant.
// Since this behavior was not always here, some people have hardcoded lproj directories in their destination folder path.
// Only add an additional component if there isn't one already.
var locDST = dstFolder
if !locDST.containsRegionVariantPathComponent {
locDST = dstFolder.join(group.regionVariantPathComponent)
}

let cbc = CommandBuildContext(producer: context, scope: scope, inputs: group.files, isPreferredArch: buildFilesContext.belongsToPreferredArch, buildPhaseInfo: buildFilesContext.buildPhaseInfo(for: rule), resourcesDir: dstFolder, unlocalizedResourcesDir: dstFolder)
let cbc = CommandBuildContext(producer: context, scope: scope, inputs: group.files, isPreferredArch: buildFilesContext.belongsToPreferredArch, buildPhaseInfo: buildFilesContext.buildPhaseInfo(for: rule), resourcesDir: locDST, unlocalizedResourcesDir: dstFolder)
await constructTasksForRule(rule, cbc, delegate)
}

Expand Down
18 changes: 18 additions & 0 deletions Sources/SWBUtil/Path.swift
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,24 @@ public struct Path: Serializable, Sendable {
return nil
}

/// `true` if the path contains any .lproj directories as path components.
public var containsRegionVariantPathComponent: Bool {
var path = self.join("File.strings") // since regionVariantName looks at parent dir
while !path.isRoot && !path.isEmpty {
if path.regionVariantName != nil {
return true
} else {
let parent = path.dirname
if parent == path {
break
} else {
path = parent
}
}
}
return false
}

/// Return true if the pathname is conformant to path restrictions on the platform.
///
/// Check the Unicode string representation of the path for reserved characters that cannot be represented as a path.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,83 @@ fileprivate struct InstallLocTaskConstructionTests: CoreBasedTests {
}
}

@Test(.requireSDKs(.macOS))
func copyFilesRulesMergeRegion() async throws {
let testProject = TestProject(
"aProject",
groupTree: TestGroup(
"SomeFiles", path: "Sources",
children: [
TestVariantGroup("Localizable.strings", children: [
TestFile("en.lproj/Localizable.strings", regionVariantName: "en"),
TestFile("ja.lproj/Localizable.strings", regionVariantName: "ja"),
TestFile("zh_TW.lproj/Localizable.strings", regionVariantName: "zh_TW"),
]),
]),
buildConfigurations: [
TestBuildConfiguration(
"Debug",
buildSettings: [
"PRODUCT_NAME": "$(TARGET_NAME)",
"GENERATE_INFOPLIST_FILE": "YES",
"APPLY_RULES_IN_COPY_FILES": "YES"
]),
],
targets: [
TestStandardTarget(
"CoreFoo", type: .framework,
buildPhases: [
TestCopyFilesBuildPhase([
"Localizable.strings",
], destinationSubfolder: .absolute, destinationSubpath: "/System/Library/Bundles/MyBundle.bundle", onlyForDeployment: true),
TestCopyFilesBuildPhase([
"Localizable.strings",
], destinationSubfolder: .builtProductsDir, destinationSubpath: "OtherProduct.bundle", onlyForDeployment: false),
]
)
])
let tester = try await TaskConstructionTester(getCore(), testProject)

// installloc single language
await tester.checkBuild(BuildParameters(action: .installLoc, configuration: "Release", overrides: ["INSTALLLOC_LANGUAGE": "ja"]), runDestination: .macOS) { results in
results.checkTarget("CoreFoo") { target in
results.checkTaskExists(.matchTarget(target), .matchRule(["Copy", "/tmp/Test/aProject/build/Debug/OtherProduct.bundle/ja.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/ja.lproj/Localizable.strings"]))
results.checkTaskExists(.matchTarget(target), .matchRule(["Copy", "/tmp/aProject.dst/System/Library/Bundles/MyBundle.bundle/ja.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/ja.lproj/Localizable.strings"]))
}

results.checkNoDiagnostics()
}

// installloc multi-language
await tester.checkBuild(BuildParameters(action: .installLoc, configuration: "Release", overrides: ["INSTALLLOC_LANGUAGE": "ja zh_TW"]), runDestination: .macOS) { results in
results.checkTarget("CoreFoo") { target in
results.checkTaskExists(.matchTarget(target), .matchRule(["Copy", "/tmp/Test/aProject/build/Debug/OtherProduct.bundle/ja.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/ja.lproj/Localizable.strings"]))
results.checkTaskExists(.matchTarget(target), .matchRule(["Copy", "/tmp/aProject.dst/System/Library/Bundles/MyBundle.bundle/ja.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/ja.lproj/Localizable.strings"]))

results.checkTaskExists(.matchTarget(target), .matchRule(["Copy", "/tmp/Test/aProject/build/Debug/OtherProduct.bundle/zh_TW.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/zh_TW.lproj/Localizable.strings"]))
results.checkTaskExists(.matchTarget(target), .matchRule(["Copy", "/tmp/aProject.dst/System/Library/Bundles/MyBundle.bundle/zh_TW.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/zh_TW.lproj/Localizable.strings"]))
}

results.checkNoDiagnostics()
}

// install
await tester.checkBuild(BuildParameters(action: .install, configuration: "Release"), runDestination: .macOS) { results in
results.checkTarget("CoreFoo") { target in
results.checkTaskExists(.matchTarget(target), .matchRule(["CopyStringsFile", "/tmp/Test/aProject/build/Debug/OtherProduct.bundle/en.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/en.lproj/Localizable.strings"]))
results.checkTaskExists(.matchTarget(target), .matchRule(["CopyStringsFile", "/tmp/aProject.dst/System/Library/Bundles/MyBundle.bundle/en.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/en.lproj/Localizable.strings"]))

results.checkTaskExists(.matchTarget(target), .matchRule(["CopyStringsFile", "/tmp/Test/aProject/build/Debug/OtherProduct.bundle/ja.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/ja.lproj/Localizable.strings"]))
results.checkTaskExists(.matchTarget(target), .matchRule(["CopyStringsFile", "/tmp/aProject.dst/System/Library/Bundles/MyBundle.bundle/ja.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/ja.lproj/Localizable.strings"]))

results.checkTaskExists(.matchTarget(target), .matchRule(["CopyStringsFile", "/tmp/Test/aProject/build/Debug/OtherProduct.bundle/zh_TW.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/zh_TW.lproj/Localizable.strings"]))
results.checkTaskExists(.matchTarget(target), .matchRule(["CopyStringsFile", "/tmp/aProject.dst/System/Library/Bundles/MyBundle.bundle/zh_TW.lproj/Localizable.strings", "/tmp/Test/aProject/Sources/zh_TW.lproj/Localizable.strings"]))
}

results.checkNoDiagnostics()
}
}

@Test(.requireSDKs(.iOS))
func installLocForFramework() async throws {
let testProject = TestProject(
Expand Down
Loading