Skip to content

Commit fed585e

Browse files
authored
Destinations: add configuration set subcommand (#6261)
To update destinations configuration we need a new subcommand to complement existing `configuration show` and `configuration reset` subcommands. Added new `SetConfiguration` type with the implementation. Additionally, new `ConfigurationCommand` protocol was added that inherits from and extends `DestinationCommand` protocol to provide configuration-specific properties and arguments. This new protocol allows reusing common configuration code. Also improved logging in `ResetConfiguration` to make it clear which properties were reset.
1 parent 357166a commit fed585e

File tree

7 files changed

+274
-45
lines changed

7 files changed

+274
-45
lines changed

Sources/CrossCompilationDestinationsTool/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
88

99
add_library(CrossCompilationDestinationsTool
10+
Configuration/ConfigurationCommand.swift
1011
Configuration/ConfigureDestination.swift
1112
Configuration/ResetConfiguration.swift
13+
Configuration/SetConfiguration.swift
1214
Configuration/ShowConfiguration.swift
1315
DestinationCommand.swift
1416
InstallDestination.swift
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ArgumentParser
14+
import Basics
15+
import PackageModel
16+
17+
import struct TSCBasic.AbsolutePath
18+
19+
protocol ConfigurationCommand: DestinationCommand {
20+
/// An identifier of an already installed destination.
21+
var destinationID: String { get }
22+
23+
/// A run-time triple of the destination specified by `destinationID` identifier string.
24+
var runTimeTriple: String { get }
25+
26+
/// Run a command related to configuration of cross-compilation destinations, passing it required configuration
27+
/// values.
28+
/// - Parameters:
29+
/// - buildTimeTriple: triple of the machine this command is running on.
30+
/// - runTimeTriple: triple of the machine on which cross-compiled code will run on.
31+
/// - destination: destination configuration fetched that matches currently set `destinationID` and
32+
/// `runTimeTriple`.
33+
/// - configurationStore: storage for configuration properties that this command operates on.
34+
/// - destinationsDirectory: directory containing destination artifact bundles and their configuration.
35+
/// - observabilityScope: observability scope used for logging.
36+
func run(
37+
buildTimeTriple: Triple,
38+
runTimeTriple: Triple,
39+
_ destination: Destination,
40+
_ configurationStore: DestinationConfigurationStore,
41+
_ destinationsDirectory: AbsolutePath,
42+
_ observabilityScope: ObservabilityScope
43+
) throws
44+
}
45+
46+
extension ConfigurationCommand {
47+
func run(
48+
buildTimeTriple: Triple,
49+
_ destinationsDirectory: AbsolutePath,
50+
_ observabilityScope: ObservabilityScope
51+
) throws {
52+
let configurationStore = try DestinationConfigurationStore(
53+
buildTimeTriple: buildTimeTriple,
54+
destinationsDirectoryPath: destinationsDirectory,
55+
fileSystem: fileSystem,
56+
observabilityScope: observabilityScope
57+
)
58+
let runTimeTriple = try Triple(self.runTimeTriple)
59+
60+
guard let destination = try configurationStore.readConfiguration(
61+
destinationID: destinationID,
62+
runTimeTriple: runTimeTriple
63+
) else {
64+
throw DestinationError.destinationNotFound(
65+
artifactID: destinationID,
66+
builtTimeTriple: buildTimeTriple,
67+
runTimeTriple: runTimeTriple
68+
)
69+
}
70+
71+
try run(
72+
buildTimeTriple: buildTimeTriple,
73+
runTimeTriple: runTimeTriple,
74+
destination,
75+
configurationStore,
76+
destinationsDirectory,
77+
observabilityScope
78+
)
79+
}
80+
}

Sources/CrossCompilationDestinationsTool/Configuration/ConfigureDestination.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct ConfigureDestination: ParsableCommand {
2020
""",
2121
subcommands: [
2222
ResetConfiguration.self,
23+
SetConfiguration.self,
2324
ShowConfiguration.self,
2425
]
2526
)

Sources/CrossCompilationDestinationsTool/Configuration/ResetConfiguration.swift

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import PackageModel
1717

1818
import struct TSCBasic.AbsolutePath
1919

20-
struct ResetConfiguration: DestinationCommand {
20+
struct ResetConfiguration: ConfigurationCommand {
2121
static let configuration = CommandConfiguration(
2222
commandName: "reset",
2323
abstract: """
@@ -55,75 +55,81 @@ struct ResetConfiguration: DestinationCommand {
5555
)
5656
var destinationID: String
5757

58-
@Argument(help: "The run-time triple of the destination to configure.")
58+
@Argument(help: "A run-time triple of the destination specified by `destination-id` identifier string.")
5959
var runTimeTriple: String
6060

6161
func run(
6262
buildTimeTriple: Triple,
63+
runTimeTriple: Triple,
64+
_ destination: Destination,
65+
_ configurationStore: DestinationConfigurationStore,
6366
_ destinationsDirectory: AbsolutePath,
6467
_ observabilityScope: ObservabilityScope
6568
) throws {
66-
let configurationStore = try DestinationConfigurationStore(
67-
buildTimeTriple: buildTimeTriple,
68-
destinationsDirectoryPath: destinationsDirectory,
69-
fileSystem: fileSystem,
70-
observabilityScope: observabilityScope
71-
)
72-
73-
let triple = try Triple(runTimeTriple)
74-
75-
guard var destination = try configurationStore.readConfiguration(
76-
destinationID: destinationID,
77-
runTimeTriple: triple
78-
) else {
79-
throw DestinationError.destinationNotFound(
80-
artifactID: destinationID,
81-
builtTimeTriple: buildTimeTriple,
82-
runTimeTriple: triple
83-
)
84-
}
85-
8669
var configuration = destination.pathsConfiguration
8770
var shouldResetAll = true
71+
var resetProperties = [String]()
8872

8973
if sdkRootPath {
9074
configuration.sdkRootPath = nil
9175
shouldResetAll = false
76+
resetProperties.append(CodingKeys.sdkRootPath.stringValue)
9277
}
9378

9479
if swiftResourcesPath {
9580
configuration.swiftResourcesPath = nil
9681
shouldResetAll = false
82+
resetProperties.append(CodingKeys.swiftResourcesPath.stringValue)
9783
}
9884

9985
if swiftStaticResourcesPath {
10086
configuration.swiftResourcesPath = nil
10187
shouldResetAll = false
88+
resetProperties.append(CodingKeys.swiftStaticResourcesPath.stringValue)
10289
}
10390

10491
if includeSearchPath {
10592
configuration.includeSearchPaths = nil
10693
shouldResetAll = false
94+
resetProperties.append(CodingKeys.includeSearchPath.stringValue)
10795
}
10896

10997
if librarySearchPath {
11098
configuration.librarySearchPaths = nil
11199
shouldResetAll = false
100+
resetProperties.append(CodingKeys.librarySearchPath.stringValue)
112101
}
113102

114103
if toolsetPath {
115104
configuration.toolsetPaths = nil
116105
shouldResetAll = false
106+
resetProperties.append(CodingKeys.toolsetPath.stringValue)
117107
}
118108

119109
if shouldResetAll {
120-
if try !configurationStore.resetConfiguration(destinationID: destinationID, runTimeTriple: triple) {
110+
if try !configurationStore.resetConfiguration(destinationID: destinationID, runTimeTriple: runTimeTriple) {
121111
observabilityScope.emit(
122112
warning: "No configuration for destination \(destinationID)"
123113
)
114+
} else {
115+
observabilityScope.emit(
116+
info: """
117+
All configuration properties of destination `\(destinationID) for run-time triple \
118+
`\(runTimeTriple)` were successfully reset.
119+
"""
120+
)
124121
}
125122
} else {
123+
var destination = destination
124+
destination.pathsConfiguration = configuration
126125
try configurationStore.updateConfiguration(destinationID: destinationID, destination: destination)
126+
127+
observabilityScope.emit(
128+
info: """
129+
These properties of destination `\(destinationID) for run-time triple \
130+
`\(runTimeTriple)` were successfully reset: \(resetProperties.joined(separator: ", ")).
131+
"""
132+
)
127133
}
128134
}
129135
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ArgumentParser
14+
import Basics
15+
import CoreCommands
16+
import PackageModel
17+
18+
import struct TSCBasic.AbsolutePath
19+
20+
struct SetConfiguration: ConfigurationCommand {
21+
static let configuration = CommandConfiguration(
22+
commandName: "set",
23+
abstract: """
24+
Sets configuration options for installed cross-compilation destinations.
25+
"""
26+
)
27+
28+
@OptionGroup(visibility: .hidden)
29+
var locations: LocationOptions
30+
31+
@Option(help: "A path to a directory containing the SDK root.")
32+
var sdkRootPath: String? = nil
33+
34+
@Option(help: "A path to a directory containing Swift resources for dynamic linking.")
35+
var swiftResourcesPath: String? = nil
36+
37+
@Option(help: "A path to a directory containing Swift resources for static linking.")
38+
var swiftStaticResourcesPath: String? = nil
39+
40+
@Option(
41+
parsing: .singleValue,
42+
help: """
43+
A path to a directory containing headers. Multiple paths can be specified by providing this option multiple \
44+
times to the command.
45+
"""
46+
)
47+
var includeSearchPath: [String] = []
48+
49+
@Option(
50+
parsing: .singleValue,
51+
help: """
52+
"A path to a directory containing libraries. Multiple paths can be specified by providing this option multiple \
53+
times to the command.
54+
"""
55+
)
56+
var librarySearchPath: [String] = []
57+
58+
@Option(
59+
parsing: .singleValue,
60+
help: """
61+
"A path to a toolset file. Multiple paths can be specified by providing this option multiple times to the command.
62+
"""
63+
)
64+
var toolsetPath: [String] = []
65+
66+
@Argument(
67+
help: """
68+
An identifier of an already installed destination. Use the `list` subcommand to see all available \
69+
identifiers.
70+
"""
71+
)
72+
var destinationID: String
73+
74+
@Argument(help: "The run-time triple of the destination to configure.")
75+
var runTimeTriple: String
76+
77+
func run(
78+
buildTimeTriple: Triple,
79+
runTimeTriple: Triple,
80+
_ destination: Destination,
81+
_ configurationStore: DestinationConfigurationStore,
82+
_ destinationsDirectory: AbsolutePath,
83+
_ observabilityScope: ObservabilityScope
84+
) throws {
85+
var configuration = destination.pathsConfiguration
86+
var updatedProperties = [String]()
87+
88+
let currentWorkingDirectory = fileSystem.currentWorkingDirectory
89+
90+
if let sdkRootPath = sdkRootPath {
91+
configuration.sdkRootPath = try AbsolutePath(validating: sdkRootPath, relativeTo: currentWorkingDirectory)
92+
updatedProperties.append(CodingKeys.sdkRootPath.stringValue)
93+
}
94+
95+
if let swiftResourcesPath = swiftResourcesPath {
96+
configuration.swiftResourcesPath =
97+
try AbsolutePath(validating: swiftResourcesPath, relativeTo: currentWorkingDirectory)
98+
updatedProperties.append(CodingKeys.swiftResourcesPath.stringValue)
99+
}
100+
101+
if let swiftStaticResourcesPath = swiftStaticResourcesPath {
102+
configuration.swiftResourcesPath =
103+
try AbsolutePath(validating: swiftStaticResourcesPath, relativeTo: currentWorkingDirectory)
104+
updatedProperties.append(CodingKeys.swiftStaticResourcesPath.stringValue)
105+
}
106+
107+
if !includeSearchPath.isEmpty {
108+
configuration.includeSearchPaths =
109+
try includeSearchPath.map { try AbsolutePath(validating: $0, relativeTo: currentWorkingDirectory) }
110+
updatedProperties.append(CodingKeys.includeSearchPath.stringValue)
111+
}
112+
113+
if !librarySearchPath.isEmpty {
114+
configuration.librarySearchPaths =
115+
try librarySearchPath.map { try AbsolutePath(validating: $0, relativeTo: currentWorkingDirectory) }
116+
updatedProperties.append(CodingKeys.librarySearchPath.stringValue)
117+
}
118+
119+
if !toolsetPath.isEmpty {
120+
configuration.toolsetPaths =
121+
try toolsetPath.map { try AbsolutePath(validating: $0, relativeTo: currentWorkingDirectory) }
122+
updatedProperties.append(CodingKeys.toolsetPath.stringValue)
123+
}
124+
125+
guard !updatedProperties.isEmpty else {
126+
observabilityScope.emit(
127+
error: """
128+
No properties of destination `\(destinationID) for run-time triple `\(runTimeTriple)` were updated \
129+
since none were specified. Pass `--help` flag to see the list of all available properties.
130+
"""
131+
)
132+
return
133+
}
134+
135+
var destination = destination
136+
destination.pathsConfiguration = configuration
137+
try configurationStore.updateConfiguration(destinationID: destinationID, destination: destination)
138+
139+
observabilityScope.emit(
140+
info: """
141+
These properties of destination `\(destinationID) for run-time triple \
142+
`\(runTimeTriple)` were successfully updated: \(updatedProperties.joined(separator: ", ")).
143+
"""
144+
)
145+
}
146+
}
147+
148+
extension AbsolutePath {
149+
fileprivate init(validating string: String, relativeTo basePath: AbsolutePath?) throws {
150+
if let basePath = basePath {
151+
try self.init(validating: string, relativeTo: basePath)
152+
} else {
153+
try self.init(validating: string)
154+
}
155+
}
156+
}

0 commit comments

Comments
 (0)