1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 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
//
//===----------------------------------------------------------------------===//
import Foundation
import SKSupport
import XCTest
import struct TSCBasic.AbsolutePath
import class TSCBasic.Process
import enum TSCBasic.ProcessEnv
import struct TSCBasic.ProcessResult
/// A SwiftPM package that gets written to disk and for which a Git repository is initialized with a commit tagged
/// `1.0.0`. This repository can then be used as a dependency for another package, usually a `SwiftPMTestProject`.
public class SwiftPMDependencyProject {
/// The scratch directory created for the dependency project.
public let scratchDirectory: URL
/// The directory in which the repository lives.
public var packageDirectory: URL {
return scratchDirectory.appendingPathComponent("MyDependency")
}
private func runGitCommand(_ arguments: [String], workingDirectory: URL) async throws {
enum Error: Swift.Error {
case cannotFindGit
case processedTerminatedWithNonZeroExitCode(ProcessResult)
}
guard let git = await findTool(name: "git") else {
if ProcessEnv.block["SWIFTCI_USE_LOCAL_DEPS"] == nil {
// Never skip the test in CI, similar to what SkipUnless does.
throw XCTSkip("git cannot be found")
}
throw Error.cannotFindGit
}
// We can't use `workingDirectory` because Amazon Linux doesn't support working directories (or at least
// TSCBasic.Process doesn't support working directories on Amazon Linux)
let process = TSCBasic.Process(
arguments: [git.path, "-C", workingDirectory.path] + arguments
)
try process.launch()
let processResult = try await process.waitUntilExit()
guard processResult.exitStatus == .terminated(code: 0) else {
throw Error.processedTerminatedWithNonZeroExitCode(processResult)
}
}
public static let defaultPackageManifest: String = """
// swift-tools-version: 5.7
import PackageDescription
let package = Package(
name: "MyDependency",
products: [.library(name: "MyDependency", targets: ["MyDependency"])],
targets: [.target(name: "MyDependency")]
)
"""
public init(
files: [RelativeFileLocation: String],
manifest: String = defaultPackageManifest,
testName: String = #function
) async throws {
scratchDirectory = try testScratchDir(testName: testName)
var files = files
files["Package.swift"] = manifest
for (fileLocation, markedContents) in files {
let fileURL = fileLocation.url(relativeTo: packageDirectory)
try FileManager.default.createDirectory(
at: fileURL.deletingLastPathComponent(),
withIntermediateDirectories: true
)
try extractMarkers(markedContents).textWithoutMarkers.write(to: fileURL, atomically: true, encoding: .utf8)
}
try await runGitCommand(["init"], workingDirectory: packageDirectory)
try await tag(changedFiles: files.keys.map { $0.url(relativeTo: packageDirectory) }, version: "1.0.0")
}
public func tag(changedFiles: [URL], version: String) async throws {
try await runGitCommand(
["add"] + changedFiles.map(\.path),
workingDirectory: packageDirectory
)
try await runGitCommand(
["-c", "user.name=Dummy", "-c", "user.email=noreply@swift.org", "commit", "-m", "Version \(version)"],
workingDirectory: packageDirectory
)
try await runGitCommand(["tag", version], workingDirectory: self.packageDirectory)
}
deinit {
if cleanScratchDirectories {
try? FileManager.default.removeItem(at: scratchDirectory)
}
}
/// Function that makes sure the project stays alive until this is called. Otherwise, the `SwiftPMDependencyProject`
/// might get deinitialized, which deletes the package on disk.
public func keepAlive() {
withExtendedLifetime(self) { _ in }
}
}
|