Skip to content

Allow a custom manifest loader to provide custom environment variables #3659

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

Merged
Merged
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
6 changes: 3 additions & 3 deletions Sources/PackageLoading/ManifestLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -590,8 +590,8 @@ public final class ManifestLoader: ManifestLoaderProtocol {
stream <<< packageIdentity
stream <<< manifestContents
stream <<< toolsVersion.description
for key in env.keys.sorted(by: >) {
stream <<< key <<< env[key]! // forced unwrap safe
for (key, value) in env.sorted(by: { $0.key > $1.key }) {
stream <<< key <<< value
}
stream <<< swiftpmVersion
return stream.bytes.sha256Checksum
Expand Down Expand Up @@ -763,7 +763,7 @@ public final class ManifestLoader: ManifestLoaderProtocol {
cmd += ["-o", compiledManifestFile.pathString]

// Compile the manifest.
let compilerResult = try Process.popen(arguments: cmd)
let compilerResult = try Process.popen(arguments: cmd, environment: toolchain.swiftCompilerEnvironment)
let compilerOutput = try (compilerResult.utf8Output() + compilerResult.utf8stderrOutput()).spm_chuzzle()
result.compilerOutput = compilerOutput

Expand Down
21 changes: 13 additions & 8 deletions Sources/PackageModel/ToolchainConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,33 @@

import TSCBasic

/// Toolchain configuration required for evaluation os swift code such as the manifests or plugins
/// Toolchain configuration required for evaluation of swift code such as the manifests or plugins
///
/// These requirements are abstracted out to make it easier to add support for
/// using the package manager with alternate toolchains in the future.
public struct ToolchainConfiguration {
/// The path of the swift compiler.
public let swiftCompiler: AbsolutePath
public var swiftCompiler: AbsolutePath

/// Extra flags to pass the Swift compiler.
public let swiftCompilerFlags: [String]
/// Extra arguments to pass the Swift compiler (defaults to the empty string).
public var swiftCompilerFlags: [String]

/// Environment to pass to the Swift compiler (defaults to the inherited environment).
public var swiftCompilerEnvironment: [String: String]

/// The path of the library resources.
public let libDir: AbsolutePath
public var libDir: AbsolutePath

/// The bin directory.
public let binDir: AbsolutePath?
public var binDir: AbsolutePath?

/// The path to SDK root.
///
/// If provided, it will be passed to the swift interpreter.
public let sdkRoot: AbsolutePath?
public var sdkRoot: AbsolutePath?

/// XCTest Location
public let xctestLocation: AbsolutePath?
public var xctestLocation: AbsolutePath?

/// Creates the set of manifest resources associated with a `swiftc` executable.
///
Expand All @@ -47,13 +50,15 @@ public struct ToolchainConfiguration {
public init(
swiftCompiler: AbsolutePath,
swiftCompilerFlags: [String] = [],
swiftCompilerEnvironment: [String: String] = ProcessEnv.vars,
libDir: AbsolutePath? = nil,
binDir: AbsolutePath? = nil,
sdkRoot: AbsolutePath? = nil,
xctestLocation: AbsolutePath? = nil
) {
self.swiftCompiler = swiftCompiler
self.swiftCompilerFlags = swiftCompilerFlags
self.swiftCompilerEnvironment = swiftCompilerEnvironment
self.libDir = libDir ?? Self.libDir(forBinDir: swiftCompiler.parentDirectory)
self.binDir = binDir
self.sdkRoot = sdkRoot
Expand Down
2 changes: 1 addition & 1 deletion Sources/Workspace/DefaultPluginScriptRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner {
let compiledExec = cacheDir.appending(component: "compiled-plugin")
command += ["-o", compiledExec.pathString]

let result = try Process.popen(arguments: command)
let result = try Process.popen(arguments: command, environment: toolchain.swiftCompilerEnvironment)
let output = try (result.utf8Output() + result.utf8stderrOutput()).spm_chuzzle() ?? ""
if result.exitStatus != .terminated(code: 0) {
// TODO: Make this a proper error.
Expand Down
49 changes: 49 additions & 0 deletions Tests/PackageLoadingTests/PD_5_0_LoadingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -547,4 +547,53 @@ class PackageDescription5_0LoadingTests: PackageDescriptionLoadingTests {
XCTAssertEqual(manifest.dependencies, [])
}
}

func testManifestLoaderEnvironment() throws {
try testWithTemporaryDirectory { path in
let fs = localFileSystem

let packagePath = path.appending(component: "pkg")
let manifestPath = packagePath.appending(component: "Package.swift")
try fs.writeFileContents(manifestPath) { stream in
stream <<< """
// swift-tools-version:5
import PackageDescription

let package = Package(
name: "Trivial",
targets: [
.target(
name: "foo",
dependencies: []),
]
)
"""
}

let moduleTraceFilePath = path.appending(component: "swift-module-trace")
var toolchain = ToolchainConfiguration.default
toolchain.swiftCompilerEnvironment["SWIFT_LOADED_MODULE_TRACE_FILE"] = moduleTraceFilePath.pathString
let manifestLoader = ManifestLoader(
toolchain: toolchain,
serializedDiagnostics: true,
isManifestSandboxEnabled: false,
cacheDir: nil)

let diagnostics = DiagnosticsEngine()
let manifest = try manifestLoader.load(
at: manifestPath.parentDirectory,
packageKind: .local,
packageLocation: manifestPath.pathString,
toolsVersion: .v5,
fileSystem: fs,
diagnostics: diagnostics
)

XCTAssertTrue(diagnostics.diagnostics.isEmpty)
XCTAssertEqual(manifest.name, "Trivial")

let moduleTraceJSON = try XCTUnwrap(try localFileSystem.readFileContents(moduleTraceFilePath).validDescription)
XCTAssert(moduleTraceJSON.contains("PackageDescription"))
}
}
}