Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add experimental-destination configuration subcommand #6252

Merged
merged 4 commits into from
Mar 10, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
7 changes: 4 additions & 3 deletions Sources/CoreCommands/SwiftToolObservabilityHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public struct SwiftToolObservabilityHandler: ObservabilityHandlerProvider {
self.outputHandler.outputStream
}

func wait(timeout: DispatchTime) {
public func wait(timeout: DispatchTime) {
self.outputHandler.wait(timeout: timeout)
}

Expand Down Expand Up @@ -198,7 +198,8 @@ extension ObservabilitySystem {
public static func swiftTool(
outputStream: OutputByteStream = stdoutStream,
logLevel: Basics.Diagnostic.Severity = .warning
) -> ObservabilitySystem {
.init(SwiftToolObservabilityHandler(outputStream: stdoutStream, logLevel: logLevel))
) -> (ObservabilitySystem, SwiftToolObservabilityHandler) {
Copy link
Contributor Author

@MaxDesiatov MaxDesiatov Mar 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is needed to allow getting a reference to SwiftToolObservabilityHandler and calling wait(timeout:) on it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine, but at some point we should consider if these new command should become aligned with the other commands so they dont need this kind of external access

Copy link
Contributor Author

@MaxDesiatov MaxDesiatov Mar 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a better way to address that within this PR. Turns out static func swiftTool was used just once in DestinationCommand, it made more sense to move its implementation over there, so there's no need for this tuple-returning function anymore.

let handler = SwiftToolObservabilityHandler(outputStream: stdoutStream, logLevel: logLevel)
return (ObservabilitySystem(handler), handler)
}
}
3 changes: 3 additions & 0 deletions Sources/CrossCompilationDestinationsTool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors

add_library(CrossCompilationDestinationsTool
Configuration/ConfigureDestination.swift
Configuration/ResetConfiguration.swift
Configuration/ShowConfiguration.swift
DestinationCommand.swift
InstallDestination.swift
ListDestinations.swift
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import ArgumentParser

struct ConfigureDestination: ParsableCommand {
static let configuration = CommandConfiguration(
commandName: "configuration",
abstract: """
Manages configuration options for installed cross-compilation destinations.
""",
subcommands: [
ResetConfiguration.self,
ShowConfiguration.self,
]
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import ArgumentParser
import Basics
import CoreCommands
import PackageModel

import struct TSCBasic.AbsolutePath

struct ResetConfiguration: DestinationCommand {
static let configuration = CommandConfiguration(
commandName: "reset",
abstract: """
Resets configuration properties currently applied to a given destination and run-time triple. If no specific \
property is specified, all of them are reset for the destination.
"""
)

@OptionGroup(visibility: .hidden)
var locations: LocationOptions

@Flag(help: "Reset custom configuration for a path to a directory containing the SDK root.")
var sdkRootPath = false

@Flag(help: "Reset custom configuration for a path to a directory containing Swift resources for dynamic linking.")
var swiftResourcesPath = false

@Flag(help: "Reset custom configuration for a path to a directory containing Swift resources for static linking.")
var swiftStaticResourcesPath = false

@Flag(help: "Reset custom configuration for a path to a directory containing headers.")
var includeSearchPath = false

@Flag(help: "Reset custom configuration for a path to a directory containing libraries.")
var librarySearchPath = false

@Flag(help: "Reset custom configuration for a path to a toolset file.")
var toolsetPath = false

@Argument(
help: """
An identifier of an already installed destination. Use the `list` subcommand to see all available \
identifiers.
"""
)
var destinationID: String

@Argument(help: "The run-time triple of the destination to configure.")
var runTimeTriple: String

func run(
buildTimeTriple: Triple,
_ destinationsDirectory: AbsolutePath,
_ observabilityScope: ObservabilityScope
) throws {
let configurationStore = try DestinationConfigurationStore(
buildTimeTriple: buildTimeTriple,
destinationsDirectoryPath: destinationsDirectory,
fileSystem: fileSystem,
observabilityScope: observabilityScope
)

let triple = try Triple(runTimeTriple)

guard var destination = try configurationStore.readConfiguration(
destinationID: destinationID,
runTimeTriple: triple
) else {
throw DestinationError.destinationNotFound(
artifactID: destinationID,
builtTimeTriple: buildTimeTriple,
runTimeTriple: triple
)
}

var configuration = destination.pathsConfiguration
var shouldResetAll = true

if sdkRootPath {
configuration.sdkRootPath = nil
shouldResetAll = false
}

if swiftResourcesPath {
configuration.swiftResourcesPath = nil
shouldResetAll = false
}

if swiftStaticResourcesPath {
configuration.swiftResourcesPath = nil
shouldResetAll = false
}

if includeSearchPath {
configuration.includeSearchPaths = nil
shouldResetAll = false
}

if librarySearchPath {
configuration.librarySearchPaths = nil
shouldResetAll = false
}

if toolsetPath {
configuration.toolsetPaths = nil
shouldResetAll = false
}

if shouldResetAll {
if try !configurationStore.resetConfiguration(destinationID: destinationID, runTimeTriple: triple) {
observabilityScope.emit(
warning: "No configuration for destination \(destinationID)"
)
}
} else {
try configurationStore.updateConfiguration(destinationID: destinationID, destination: destination)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import ArgumentParser
import Basics
import CoreCommands
import PackageModel

import struct TSCBasic.AbsolutePath

struct ShowConfiguration: DestinationCommand {
static let configuration = CommandConfiguration(
commandName: "show",
abstract: """
Prints all configuration properties currently applied to a given destination and run-time triple.
"""
)

@OptionGroup(visibility: .hidden)
var locations: LocationOptions

@Argument(
help: """
An identifier of an already installed destination. Use the `list` subcommand to see all available \
identifiers.
"""
)
var destinationID: String

@Argument(help: "The run-time triple of the destination to configure.")
var runTimeTriple: String

func run(
buildTimeTriple: Triple,
_ destinationsDirectory: AbsolutePath,
_ observabilityScope: ObservabilityScope
) throws {
let configurationStore = try DestinationConfigurationStore(
buildTimeTriple: buildTimeTriple,
destinationsDirectoryPath: destinationsDirectory,
fileSystem: fileSystem,
observabilityScope: observabilityScope
)

let triple = try Triple(runTimeTriple)

guard let configuration = try configurationStore.readConfiguration(
destinationID: destinationID,
runTimeTriple: triple
)?.pathsConfiguration else {
throw DestinationError.destinationNotFound(
artifactID: destinationID,
builtTimeTriple: buildTimeTriple,
runTimeTriple: triple
)
}

print(configuration)
}
}

extension Destination.PathsConfiguration: CustomStringConvertible {
public var description: String {
"""
sdkRootPath: \(sdkRootPath.configurationString)
swiftResourcesPath: \(swiftResourcesPath.configurationString)
swiftStaticResourcesPath: \(swiftStaticResourcesPath.configurationString)
includeSearchPaths: \(includeSearchPaths.configurationString)
librarySearchPaths: \(librarySearchPaths.configurationString)
toolsetPaths: \(toolsetPaths.configurationString)
"""
}
}

extension Optional where Wrapped == AbsolutePath {
fileprivate var configurationString: String {
self?.pathString ?? "not set"
}
}

extension Optional where Wrapped == [AbsolutePath] {
fileprivate var configurationString: String {
self?.map(\.pathString).description ?? "not set"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,30 @@
//===----------------------------------------------------------------------===//

import ArgumentParser
import Basics
import CoreCommands
import TSCBasic
import Dispatch
import PackageModel

import struct TSCBasic.AbsolutePath
import protocol TSCBasic.FileSystem
import var TSCBasic.localFileSystem

/// A protocol for functions and properties common to all destination subcommands.
protocol DestinationCommand: ParsableCommand {
/// Common locations options provided by ArgumentParser.
var locations: LocationOptions { get }

/// Run a command operating on cross-compilation destinations, passing it required configuration values.
/// - Parameters:
/// - buildTimeTriple: triple of the machine this command is running on.
/// - destinationsDirectory: directory containing destination artifact bundles and their configuration.
/// - observabilityScope: observability scope used for logging.
func run(
buildTimeTriple: Triple,
_ destinationsDirectory: AbsolutePath,
_ observabilityScope: ObservabilityScope
) throws
}

extension DestinationCommand {
Expand All @@ -43,4 +60,30 @@ extension DestinationCommand {

return destinationsDirectory
}

public func run() throws {
let (observabilitySystem, observabilityHandler) = ObservabilitySystem.swiftTool(logLevel: .info)
let observabilityScope = observabilitySystem.topScope
let destinationsDirectory = try self.getOrCreateDestinationsDirectory()

let hostToolchain = try UserToolchain(destination: Destination.hostDestination())
let triple = Triple.getHostTriple(usingSwiftCompiler: hostToolchain.swiftCompilerPath)

var commandError: Error? = nil
do {
try self.run(buildTimeTriple: triple, destinationsDirectory, observabilityScope)
if observabilityScope.errorsReported {
throw ExitCode.failure
}
} catch {
commandError = error
}

// wait for all observability items to process
observabilityHandler.wait(timeout: .now() + 5)

if let error = commandError {
throw error
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ struct InstallDestination: DestinationCommand {
@Argument(help: "A local filesystem path or a URL of an artifact bundle to install.")
var bundlePathOrURL: String

func run() throws {
let observabilitySystem = ObservabilitySystem.swiftTool()
let observabilityScope = observabilitySystem.topScope
let destinationsDirectory = try self.getOrCreateDestinationsDirectory()

func run(
buildTimeTriple: Triple,
_ destinationsDirectory: AbsolutePath,
_ observabilityScope: ObservabilityScope
) throws {
if
let bundleURL = URL(string: bundlePathOrURL),
let scheme = bundleURL.scheme,
Expand Down Expand Up @@ -78,6 +78,6 @@ struct InstallDestination: DestinationCommand {
throw StringError("Argument `\(bundlePathOrURL)` is neither a valid filesystem path nor a URL.")
}

print("Destination artifact bundle at `\(bundlePathOrURL)` successfully installed.")
observabilityScope.emit(info: "Destination artifact bundle at `\(bundlePathOrURL)` successfully installed.")
}
}
Loading