Preserve user-defined test targets across Package.swift regeneration
This commit is contained in:
parent
f305df0eff
commit
b13f7976cc
4 changed files with 114 additions and 2 deletions
|
|
@ -256,7 +256,12 @@ extension CodeGenerator {
|
|||
\(products) ],
|
||||
targets: [
|
||||
\(cTargets)
|
||||
\(swiftTargets)\(smokeTarget) ]
|
||||
\(swiftTargets)\(smokeTarget)
|
||||
// === USER TARGETS — preserved across generations ===
|
||||
// BEGIN_USER_TARGETS
|
||||
|
||||
// END_USER_TARGETS
|
||||
]
|
||||
)
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -24,4 +24,39 @@ public struct CodeGenerator {
|
|||
}
|
||||
return files
|
||||
}
|
||||
|
||||
// MARK: - User target preservation
|
||||
|
||||
/// Preserves user-defined targets between `// BEGIN_USER_TARGETS` and
|
||||
/// `// END_USER_TARGETS` markers when regenerating Package.swift.
|
||||
///
|
||||
/// If the existing file has content between the markers, it is spliced
|
||||
/// into the freshly generated output. If either file lacks the markers,
|
||||
/// the generated output is returned unchanged.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - generated: The freshly generated Package.swift content.
|
||||
/// - existing: The existing Package.swift on disk (if any).
|
||||
/// - Returns: The generated content with user targets spliced in.
|
||||
public static func preserveUserTargets(generated: String, existing: String) -> String {
|
||||
let beginMarker = "// BEGIN_USER_TARGETS"
|
||||
let endMarker = "// END_USER_TARGETS"
|
||||
|
||||
guard let genStart = generated.range(of: beginMarker),
|
||||
let genEnd = generated.range(of: endMarker, range: genStart.upperBound..<generated.endIndex) else {
|
||||
return generated
|
||||
}
|
||||
|
||||
// Default to keeping the generated gap (blank line and indent)
|
||||
var userContent = String(generated[genStart.upperBound..<genEnd.lowerBound])
|
||||
|
||||
if let exStart = existing.range(of: beginMarker),
|
||||
let exEnd = existing.range(of: endMarker, range: exStart.upperBound..<existing.endIndex) {
|
||||
userContent = String(existing[exStart.upperBound..<exEnd.lowerBound])
|
||||
}
|
||||
|
||||
var result = generated
|
||||
result.replaceSubrange(genStart.upperBound..<genEnd.lowerBound, with: userContent)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,8 +78,16 @@ struct GeneratorCLI {
|
|||
}
|
||||
|
||||
// Write scaffolding (Package.swift, C module maps, umbrella headers)
|
||||
let scaffolding = CodeGenerator.generateMonorepoScaffolding(
|
||||
var scaffolding = CodeGenerator.generateMonorepoScaffolding(
|
||||
analysis: analysis, includeSmokeTarget: args.includeSmokeTarget)
|
||||
|
||||
// Preserve user-defined targets in Package.swift across generations
|
||||
let existingPkgPath = outputRoot.appendingPathComponent("Package.swift")
|
||||
let existingPkg = (try? String(contentsOf: existingPkgPath, encoding: .utf8)) ?? ""
|
||||
if let pkgContent = scaffolding["Package.swift"] {
|
||||
scaffolding["Package.swift"] = CodeGenerator.preserveUserTargets(
|
||||
generated: pkgContent, existing: existingPkg)
|
||||
}
|
||||
for (relativePath, content) in scaffolding.sorted(by: { $0.key < $1.key }) {
|
||||
let fileURL = outputRoot.appendingPathComponent(relativePath)
|
||||
try FileManager.default.createDirectory(at: fileURL.deletingLastPathComponent(), withIntermediateDirectories: true)
|
||||
|
|
|
|||
|
|
@ -96,3 +96,67 @@ func testPackageScaffoldingAdw() {
|
|||
#expect(scaffolding["Sources/CAdw/module.modulemap"]?.contains("link \"adwaita-1\"") == true)
|
||||
#expect(scaffolding["Sources/CAdw/CAdw.h"]?.contains("#include <adwaita.h>") == true)
|
||||
}
|
||||
|
||||
// MARK: - User target preservation
|
||||
|
||||
@Test("generateMonorepoScaffolding includes user targets marker block")
|
||||
func testMonorepoPackageHasUserTargetMarkers() {
|
||||
// Build minimal MultiPackageAnalysis with one module
|
||||
let repo = Repository(
|
||||
namespaces: [Namespace(name: "Gtk", version: "4.0",
|
||||
cSharedLibrary: "libgtk-4.so.1", cIdentifierPrefix: "Gtk")]
|
||||
)
|
||||
let analysis = MultiPackageAnalysis(
|
||||
repositories: ["Gtk": repo],
|
||||
directDependencies: ["Gtk": []],
|
||||
transitiveDependencies: ["Gtk": []],
|
||||
implicitImports: ["Gtk": []],
|
||||
packageConfigs: [:]
|
||||
)
|
||||
let scaffolding = CodeGenerator.generateMonorepoScaffolding(analysis: analysis)
|
||||
let pkg = scaffolding["Package.swift"] ?? ""
|
||||
#expect(pkg.contains("// BEGIN_USER_TARGETS"))
|
||||
#expect(pkg.contains("// END_USER_TARGETS"))
|
||||
}
|
||||
|
||||
@Test("preserveUserTargets splices user block from existing into generated")
|
||||
func testPreserveUserTargets() {
|
||||
let existing = """
|
||||
targets: [
|
||||
.systemLibrary(name: "CGLib"),
|
||||
// BEGIN_USER_TARGETS
|
||||
.testTarget(name: "MyTests", dependencies: ["GLib"]),
|
||||
// END_USER_TARGETS
|
||||
]
|
||||
"""
|
||||
|
||||
let generated = """
|
||||
targets: [
|
||||
.systemLibrary(name: "CGLib"),
|
||||
// BEGIN_USER_TARGETS
|
||||
|
||||
// END_USER_TARGETS
|
||||
]
|
||||
"""
|
||||
let result = CodeGenerator.preserveUserTargets(generated: generated, existing: existing)
|
||||
#expect(result.contains("MyTests"))
|
||||
#expect(result != generated, "Result should differ from generated since existing has content")
|
||||
#expect(result.contains("// BEGIN_USER_TARGETS"))
|
||||
#expect(result.contains("// END_USER_TARGETS"))
|
||||
#expect(result.contains(".testTarget(name:"))
|
||||
}
|
||||
|
||||
@Test("preserveUserTargets returns generated unchanged when existing has no markers")
|
||||
func testPreserveUserTargetsFirstGeneration() {
|
||||
let generated = """
|
||||
targets: [
|
||||
.systemLibrary(name: "CGLib"),
|
||||
// BEGIN_USER_TARGETS
|
||||
|
||||
// END_USER_TARGETS
|
||||
]
|
||||
"""
|
||||
|
||||
let result = CodeGenerator.preserveUserTargets(generated: generated, existing: "")
|
||||
#expect(result == generated)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue