mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This was originally a separate library since it was copied directly from the legacy SwiftPM library. However it's since been changed a bunch, and ought to be able leverage SwiftXcodeGen utilities such as RelativePath. Fold it into SwiftXcodeGen. I considered splitting out the utility code from SwiftXcodeGen into a new library, but unfortunately that currently regresses performance (even with max CMO). The module organization doesn't really currently matter since we don't expose any products.
171 lines
4.3 KiB
Swift
171 lines
4.3 KiB
Swift
//===--- SchemeGenerator.swift --------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2024 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
struct Scheme {
|
|
var name: String
|
|
var buildAction: BuildAction
|
|
var runAction: RunAction?
|
|
var replaceExisting: Bool
|
|
|
|
init(_ name: String, replaceExisting: Bool, buildTargets: [BuildTarget]) {
|
|
self.name = name
|
|
self.replaceExisting = replaceExisting
|
|
self.buildAction = .init(targets: buildTargets)
|
|
}
|
|
|
|
init(_ name: String, replaceExisting: Bool, buildTargets: BuildTarget...) {
|
|
self.init(
|
|
name, replaceExisting: replaceExisting, buildTargets: buildTargets
|
|
)
|
|
}
|
|
|
|
mutating func addBuildTarget(
|
|
_ target: Xcode.Target, in path: RelativePath
|
|
) {
|
|
buildAction.targets.append(.init(target, in: path))
|
|
}
|
|
}
|
|
|
|
extension Scheme {
|
|
struct BuildAction {
|
|
var targets: [BuildTarget]
|
|
}
|
|
|
|
struct BuildTarget {
|
|
var name: String
|
|
var container: RelativePath
|
|
|
|
init(_ target: Xcode.Target, in path: RelativePath) {
|
|
self.name = target.name
|
|
self.container = path
|
|
}
|
|
|
|
init(_ name: String, in path: RelativePath) {
|
|
self.name = name
|
|
self.container = path
|
|
}
|
|
}
|
|
|
|
struct RunAction {
|
|
var path: AbsolutePath
|
|
}
|
|
}
|
|
|
|
struct SchemeGenerator {
|
|
let containerDir: AbsolutePath
|
|
let disableAutoCreation: Bool
|
|
|
|
var schemes: [Scheme] = []
|
|
|
|
init(in containerDir: AbsolutePath, disableAutoCreation: Bool = true) {
|
|
self.containerDir = containerDir
|
|
self.disableAutoCreation = disableAutoCreation
|
|
}
|
|
}
|
|
|
|
extension SchemeGenerator {
|
|
mutating func add(_ scheme: Scheme) {
|
|
schemes.append(scheme)
|
|
}
|
|
}
|
|
|
|
extension SchemeGenerator {
|
|
private func disableAutoCreationIfNeeded() throws {
|
|
guard disableAutoCreation else { return }
|
|
|
|
var relPath: RelativePath = "xcshareddata/WorkspaceSettings.xcsettings"
|
|
if containerDir.hasExtension(.xcodeproj) {
|
|
relPath = "project.xcworkspace/\(relPath)"
|
|
}
|
|
let settingsPath = containerDir.appending(relPath)
|
|
|
|
let workspaceSettings = """
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
|
|
<false/>
|
|
</dict>
|
|
</plist>
|
|
"""
|
|
|
|
try settingsPath.write(workspaceSettings)
|
|
log.info("Generated '\(settingsPath)'")
|
|
}
|
|
|
|
private func writeScheme(_ scheme: Scheme) throws {
|
|
let path = containerDir.appending(
|
|
"xcshareddata/xcschemes/\(scheme.name).xcscheme"
|
|
)
|
|
|
|
// Don't overwrite if we haven't been asked to.
|
|
if !scheme.replaceExisting && path.exists {
|
|
return
|
|
}
|
|
|
|
var plist = """
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<Scheme LastUpgradeVersion = "9999" version = "1.3">
|
|
<BuildAction parallelizeBuildables = "YES" buildImplicitDependencies = "YES">
|
|
<BuildActionEntries>
|
|
|
|
"""
|
|
for buildTarget in scheme.buildAction.targets {
|
|
plist += """
|
|
<BuildActionEntry buildForTesting = "YES" buildForRunning = "YES" buildForProfiling = "YES" buildForArchiving = "YES" buildForAnalyzing = "YES">
|
|
<BuildableReference
|
|
BuildableIdentifier = "primary"
|
|
BuildableName = "\(buildTarget.name)"
|
|
BlueprintName = "\(buildTarget.name)"
|
|
ReferencedContainer = "container:\(buildTarget.container)">
|
|
</BuildableReference>
|
|
</BuildActionEntry>
|
|
|
|
"""
|
|
}
|
|
plist += """
|
|
</BuildActionEntries>
|
|
</BuildAction>
|
|
|
|
"""
|
|
|
|
if let runAction = scheme.runAction {
|
|
plist += """
|
|
<LaunchAction>
|
|
<PathRunnable
|
|
FilePath = "\(runAction.path.escaped(addQuotesIfNeeded: false))">
|
|
</PathRunnable>
|
|
</LaunchAction>
|
|
|
|
"""
|
|
}
|
|
|
|
plist += """
|
|
</Scheme>
|
|
"""
|
|
|
|
try path.write(plist)
|
|
log.info("Generated '\(path)'")
|
|
}
|
|
|
|
private func writeSchemes() throws {
|
|
for scheme in schemes {
|
|
try writeScheme(scheme)
|
|
}
|
|
}
|
|
|
|
func write() throws {
|
|
try disableAutoCreationIfNeeded()
|
|
try writeSchemes()
|
|
}
|
|
}
|