Use libSwiftPM instead of custom model types (#194)
* Use libSwiftPM instead of custom model types #120 * Update SwiftPM dependencies * Add wrapper to handle discrepancy between encoded and decoded Manifest * Try to fix 5.2 dependency resolving * Try to fix 5.2 dependency resolving Co-authored-by: Max Desiatov <max@desiatov.com>
This commit is contained in:
parent
9753432846
commit
4ef7b5339e
|
@ -82,6 +82,24 @@
|
|||
"version": "1.1.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-driver",
|
||||
"repositoryURL": "https://github.com/apple/swift-driver.git",
|
||||
"state": {
|
||||
"branch": "release/5.4",
|
||||
"revision": "b71abc6384dcf3e765854e2b28b83c618d3726a6",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "llbuild",
|
||||
"repositoryURL": "https://github.com/apple/swift-llbuild.git",
|
||||
"state": {
|
||||
"branch": "release/5.4",
|
||||
"revision": "eb56a00ed9dfd62c2ce4ec86183ff0bc0afda997",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-log",
|
||||
"repositoryURL": "https://github.com/apple/swift-log.git",
|
||||
|
@ -145,13 +163,22 @@
|
|||
"version": "1.9.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftPM",
|
||||
"repositoryURL": "https://github.com/apple/swift-package-manager.git",
|
||||
"state": {
|
||||
"branch": "release/5.4",
|
||||
"revision": "9c96dd770834d4b02c680cbf63949fab75fb6cca",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-tools-support-core",
|
||||
"repositoryURL": "https://github.com/apple/swift-tools-support-core.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "243beea77d20db46647a3de4765c96e2c801c7c7",
|
||||
"version": "0.1.12"
|
||||
"branch": "release/5.4",
|
||||
"revision": "bc7961701fd94104528b017e969f63ea40bdb22b",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -180,6 +207,15 @@
|
|||
"revision": "2b06a70dfcfa76a2e5079f60e3ae911511f09db0",
|
||||
"version": "2.1.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Yams",
|
||||
"repositoryURL": "https://github.com/jpsim/Yams.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "9003d51672e516cc59297b7e96bff1dfdedcb4ea",
|
||||
"version": "4.0.4"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -26,9 +26,14 @@ let package = Package(
|
|||
url: "https://github.com/apple/swift-argument-parser.git",
|
||||
.upToNextMinor(from: "0.3.0")
|
||||
),
|
||||
.package(
|
||||
name: "SwiftPM",
|
||||
url: "https://github.com/apple/swift-package-manager.git",
|
||||
.branch("release/5.4")
|
||||
),
|
||||
.package(
|
||||
url: "https://github.com/apple/swift-tools-support-core.git",
|
||||
.upToNextMinor(from: "0.1.10")
|
||||
.branch("release/5.4")
|
||||
),
|
||||
.package(url: "https://github.com/OpenCombine/OpenCombine.git", from: "0.10.0"),
|
||||
.package(url: "https://github.com/vapor/vapor.git", from: "4.29.3"),
|
||||
|
@ -65,7 +70,6 @@ let package = Package(
|
|||
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||
.product(name: "Crypto", package: "swift-crypto"),
|
||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
||||
.product(name: "Vapor", package: "vapor"),
|
||||
"CartonHelpers",
|
||||
openCombineProduct,
|
||||
|
@ -76,7 +80,7 @@ let package = Package(
|
|||
name: "SwiftToolchain",
|
||||
dependencies: [
|
||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
||||
.product(name: "SwiftPMDataModel", package: "SwiftPM"),
|
||||
"CartonHelpers",
|
||||
openCombineProduct,
|
||||
"WasmTransformer",
|
||||
|
@ -86,7 +90,6 @@ let package = Package(
|
|||
name: "CartonHelpers",
|
||||
dependencies: [
|
||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
||||
openCombineProduct,
|
||||
"Splash",
|
||||
]
|
||||
|
@ -107,7 +110,6 @@ let package = Package(
|
|||
dependencies: [
|
||||
"Carton",
|
||||
"CartonHelpers",
|
||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
||||
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||
]
|
||||
),
|
||||
|
|
|
@ -20,9 +20,14 @@ let package = Package(
|
|||
url: "https://github.com/apple/swift-argument-parser.git",
|
||||
.upToNextMinor(from: "0.3.0")
|
||||
),
|
||||
.package(
|
||||
name: "SwiftPM",
|
||||
url: "https://github.com/apple/swift-package-manager.git",
|
||||
.branch("release/5.4")
|
||||
),
|
||||
.package(
|
||||
url: "https://github.com/apple/swift-tools-support-core.git",
|
||||
.upToNextMinor(from: "0.1.10")
|
||||
.branch("release/5.4")
|
||||
),
|
||||
.package(url: "https://github.com/OpenCombine/OpenCombine.git", from: "0.10.0"),
|
||||
.package(url: "https://github.com/vapor/vapor.git", from: "4.29.3"),
|
||||
|
@ -59,7 +64,6 @@ let package = Package(
|
|||
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||
.product(name: "Crypto", package: "swift-crypto"),
|
||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
||||
.product(name: "Vapor", package: "vapor"),
|
||||
"CartonHelpers",
|
||||
"OpenCombine",
|
||||
|
@ -70,6 +74,7 @@ let package = Package(
|
|||
name: "SwiftToolchain",
|
||||
dependencies: [
|
||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||
.product(name: "SwiftPMDataModel", package: "SwiftPM"),
|
||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
||||
"CartonHelpers",
|
||||
"OpenCombine",
|
||||
|
@ -92,7 +97,6 @@ let package = Package(
|
|||
dependencies: [
|
||||
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
||||
"CartonHelpers",
|
||||
]
|
||||
),
|
||||
|
|
|
@ -16,6 +16,7 @@ import ArgumentParser
|
|||
import CartonHelpers
|
||||
import CartonKit
|
||||
import Crypto
|
||||
import PackageModel
|
||||
import SwiftToolchain
|
||||
import TSCBasic
|
||||
import WasmTransformer
|
||||
|
@ -105,7 +106,7 @@ struct Bundle: ParsableCommand {
|
|||
buildDirectory: AbsolutePath,
|
||||
bundleDirectory: AbsolutePath,
|
||||
toolchain: Toolchain,
|
||||
product: Product
|
||||
product: ProductDescription
|
||||
) throws {
|
||||
// Rename the final binary to use a part of its hash to bust browsers and CDN caches.
|
||||
let optimizedHash = try localFileSystem.readFileContents(optimizedPath).hexSHA256.prefix(16)
|
||||
|
@ -137,9 +138,9 @@ struct Bundle: ParsableCommand {
|
|||
))
|
||||
)
|
||||
|
||||
let package = try toolchain.package.get()
|
||||
for target in package.targets where target.type == .regular && !target.resources.isEmpty {
|
||||
let targetPath = package.resourcesPath(for: target)
|
||||
let manifest = try toolchain.manifest.get()
|
||||
for target in manifest.targets where target.type == .regular && !target.resources.isEmpty {
|
||||
let targetPath = manifest.resourcesPath(for: target)
|
||||
let resourcesPath = buildDirectory.appending(component: targetPath)
|
||||
let targetDirectory = bundleDirectory.appending(component: targetPath)
|
||||
|
||||
|
@ -154,13 +155,13 @@ struct Bundle: ParsableCommand {
|
|||
swiftlint:disable:next line_length
|
||||
https://forums.swift.org/t/pitch-ability-to-declare-executable-targets-in-swiftpm-manifests-to-support-main/41968
|
||||
*/
|
||||
let inferredMainTarget = package.targets.first {
|
||||
let inferredMainTarget = manifest.targets.first {
|
||||
product.targets.contains($0.name)
|
||||
}
|
||||
|
||||
guard let mainTarget = inferredMainTarget else { return }
|
||||
|
||||
let targetPath = package.resourcesPath(for: mainTarget)
|
||||
let targetPath = manifest.resourcesPath(for: mainTarget)
|
||||
let resourcesPath = buildDirectory.appending(component: targetPath)
|
||||
for file in try localFileSystem.traverseRecursively(resourcesPath) {
|
||||
let targetPath = bundleDirectory.appending(component: file.basename)
|
||||
|
|
|
@ -47,7 +47,10 @@ struct Dev: ParsableCommand {
|
|||
@Option(name: .shortAndLong, help: "Set the HTTP port the development server will run on.")
|
||||
var port = 8080
|
||||
|
||||
@Option(name: .shortAndLong, help: "Set the location where the development server will run. Default is `127.0.0.1`.")
|
||||
@Option(
|
||||
name: .shortAndLong,
|
||||
help: "Set the location where the development server will run. Default is `127.0.0.1`."
|
||||
)
|
||||
var host = "127.0.0.1"
|
||||
|
||||
@Flag(name: .long, help: "Skip automatically opening app in system browser.")
|
||||
|
@ -114,7 +117,7 @@ struct Dev: ParsableCommand {
|
|||
host: host,
|
||||
customIndexContent: HTML.readCustomIndexPage(at: customIndexPage, on: localFileSystem),
|
||||
// swiftlint:disable:next force_try
|
||||
package: try! toolchain.package.get(),
|
||||
manifest: try! toolchain.manifest.get(),
|
||||
product: inferredProduct,
|
||||
entrypoint: Self.entrypoint
|
||||
),
|
||||
|
|
|
@ -96,7 +96,7 @@ struct Test: ParsableCommand {
|
|||
host: host,
|
||||
customIndexContent: nil,
|
||||
// swiftlint:disable:next force_try
|
||||
package: try! toolchain.package.get(),
|
||||
manifest: try! toolchain.manifest.get(),
|
||||
product: nil,
|
||||
entrypoint: Self.entrypoint
|
||||
),
|
||||
|
|
|
@ -26,8 +26,8 @@ public extension StringProtocol {
|
|||
var chromeStackTrace: [StackTraceItem] {
|
||||
split(separator: "\n").dropFirst().compactMap {
|
||||
if let webpackMatch = webpackRegex.matchGroups(in: String($0)).first,
|
||||
let symbol = webpackMatch.first,
|
||||
let location = webpackMatch.last
|
||||
let symbol = webpackMatch.first,
|
||||
let location = webpackMatch.last
|
||||
{
|
||||
return StackTraceItem(symbol: symbol, location: location, kind: .javaScript)
|
||||
} else if
|
||||
|
|
|
@ -162,9 +162,9 @@ public struct DiagnosticsParser: ProcessOutputParser {
|
|||
var groupedMessages = [[CustomDiagnostic]]()
|
||||
for message in messages {
|
||||
if let lastLineStr = groupedMessages.last?.last?.line,
|
||||
let lastLine = Int(lastLineStr),
|
||||
let line = Int(message.line),
|
||||
lastLine == line - 1 || lastLine == line
|
||||
let lastLine = Int(lastLineStr),
|
||||
let line = Int(message.line),
|
||||
lastLine == line - 1 || lastLine == line
|
||||
{
|
||||
groupedMessages[groupedMessages.count - 1].append(message)
|
||||
} else {
|
||||
|
|
|
@ -26,8 +26,8 @@ public extension StringProtocol {
|
|||
var firefoxStackTrace: [StackTraceItem] {
|
||||
split(separator: "\n").compactMap {
|
||||
if let webpackMatch = webpackRegex.matchGroups(in: String($0)).first,
|
||||
let symbol = webpackMatch.first,
|
||||
let location = webpackMatch.last
|
||||
let symbol = webpackMatch.first,
|
||||
let location = webpackMatch.last
|
||||
{
|
||||
return StackTraceItem(symbol: symbol, location: location, kind: .javaScript)
|
||||
} else if
|
||||
|
|
|
@ -26,7 +26,7 @@ public extension StringProtocol {
|
|||
var safariStackTrace: [StackTraceItem] {
|
||||
split(separator: "\n").compactMap {
|
||||
if let wasmMatch = wasmRegex.matchGroups(in: String($0)).first,
|
||||
let symbol = wasmMatch.first
|
||||
let symbol = wasmMatch.first
|
||||
{
|
||||
return StackTraceItem(
|
||||
symbol: demangle(symbol),
|
||||
|
|
|
@ -19,7 +19,7 @@ extension StringProtocol {
|
|||
func matches(regex: NSRegularExpression) -> String.SubSequence? {
|
||||
let str = String(self)
|
||||
guard let range = str.range(of: regex),
|
||||
range.upperBound < str.endIndex
|
||||
range.upperBound < str.endIndex
|
||||
else { return nil }
|
||||
return str[range.upperBound..<str.endIndex]
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ extension StringProtocol {
|
|||
let str = String(self)
|
||||
let range = NSRange(location: 0, length: utf16.count)
|
||||
guard let match = regex.firstMatch(in: str, options: [], range: range),
|
||||
let matchRange = Range(match.range, in: str)
|
||||
let matchRange = Range(match.range, in: str)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ extension StringProtocol {
|
|||
let str = String(self)
|
||||
let range = NSRange(location: 0, length: utf16.count)
|
||||
guard let matches = regex.matches(in: str, options: [], range: range).first,
|
||||
let matchRange = Range(matches.range(withName: name), in: str)
|
||||
let matchRange = Range(matches.range(withName: name), in: str)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ extension StringProtocol {
|
|||
func match(of regex: NSRegularExpression, named name: String) -> String.SubSequence? {
|
||||
let str = String(self)
|
||||
guard let range = str.range(of: regex, named: name),
|
||||
range.upperBound < str.endIndex && range.lowerBound >= str.startIndex
|
||||
range.upperBound < str.endIndex && range.lowerBound >= str.startIndex
|
||||
else { return nil }
|
||||
return str[range]
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ private extension StringProtocol {
|
|||
_ labelB: TestsParser.Regex.Label
|
||||
) -> (String.SubSequence, String.SubSequence)? {
|
||||
guard let a = match(of: regex, named: labelA.rawValue),
|
||||
let b = match(of: regex, named: labelB.rawValue)
|
||||
let b = match(of: regex, named: labelB.rawValue)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
@ -93,10 +93,10 @@ public struct TestsParser: ProcessOutputParser {
|
|||
|
||||
enum Assertion: String, CaseIterable {
|
||||
case equal = "Equal",
|
||||
greaterThan = "GreaterThan",
|
||||
lessThan = "LessThan",
|
||||
greaterThanOrEqual = "GreaterThanOrEqual",
|
||||
lessThanOrEqual = "LessThanOrEqual"
|
||||
greaterThan = "GreaterThan",
|
||||
lessThan = "LessThan",
|
||||
greaterThanOrEqual = "GreaterThanOrEqual",
|
||||
lessThanOrEqual = "LessThanOrEqual"
|
||||
|
||||
var funcName: String {
|
||||
"XCTAssert\(rawValue)"
|
||||
|
@ -178,20 +178,20 @@ public struct TestsParser: ProcessOutputParser {
|
|||
if let suite = line.match(of: Regex.suiteStarted, labelled: .suite) {
|
||||
suites.append(.init(name: suite, cases: []))
|
||||
} else if let testCase = line.match(of: Regex.caseFinished, labelled: .testCase),
|
||||
let suite = line.match(of: Regex.caseFinished, labelled: .suite),
|
||||
let suiteIdx = suites.firstIndex(where: { $0.name == suite }),
|
||||
let status = line.match(of: Regex.caseFinished, labelled: .status),
|
||||
let duration = line.match(of: Regex.caseFinished, labelled: .duration)
|
||||
let suite = line.match(of: Regex.caseFinished, labelled: .suite),
|
||||
let suiteIdx = suites.firstIndex(where: { $0.name == suite }),
|
||||
let status = line.match(of: Regex.caseFinished, labelled: .status),
|
||||
let duration = line.match(of: Regex.caseFinished, labelled: .duration)
|
||||
{
|
||||
suites[suiteIdx].cases.append(
|
||||
.init(name: testCase, passed: status == "passed", duration: duration, problems: [])
|
||||
)
|
||||
} else if let problem = line.matches(regex: Regex.problem),
|
||||
let path = line.match(of: Regex.problem, labelled: .path),
|
||||
let lineNum = line.match(of: Regex.problem, labelled: .line),
|
||||
let status = line.match(of: Regex.problem, labelled: .status),
|
||||
let suite = line.match(of: Regex.problem, labelled: .suite),
|
||||
let testCase = line.match(of: Regex.problem, labelled: .testCase)
|
||||
let path = line.match(of: Regex.problem, labelled: .path),
|
||||
let lineNum = line.match(of: Regex.problem, labelled: .line),
|
||||
let status = line.match(of: Regex.problem, labelled: .status),
|
||||
let suite = line.match(of: Regex.problem, labelled: .suite),
|
||||
let testCase = line.match(of: Regex.problem, labelled: .testCase)
|
||||
{
|
||||
let diag = DiagnosticsParser.CustomDiagnostic(
|
||||
kind: DiagnosticsParser.CustomDiagnostic.Kind(rawValue: String(status)) ?? .note,
|
||||
|
@ -202,7 +202,7 @@ public struct TestsParser: ProcessOutputParser {
|
|||
message: String(problem)
|
||||
)
|
||||
if let suiteIdx = suites.firstIndex(where: { $0.name == suite }),
|
||||
let caseIdx = suites[suiteIdx].cases.firstIndex(where: { $0.name == testCase })
|
||||
let caseIdx = suites[suiteIdx].cases.firstIndex(where: { $0.name == testCase })
|
||||
{
|
||||
suites[suiteIdx].cases[caseIdx].problems.append(diag)
|
||||
} else {
|
||||
|
@ -212,7 +212,7 @@ public struct TestsParser: ProcessOutputParser {
|
|||
}
|
||||
for problem in unmappedProblems {
|
||||
if let suiteIdx = suites.firstIndex(where: { $0.name == problem.suite }),
|
||||
let caseIdx = suites[suiteIdx].cases.firstIndex(where: { $0.name == problem.testCase })
|
||||
let caseIdx = suites[suiteIdx].cases.firstIndex(where: { $0.name == problem.testCase })
|
||||
{
|
||||
suites[suiteIdx].cases[caseIdx].problems.append(problem.problem)
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ public struct TestsParser: ProcessOutputParser {
|
|||
}
|
||||
// Get the line of code from the file and output it for context.
|
||||
if let lineNum = Int(problem.line),
|
||||
lineNum > 0
|
||||
lineNum > 0
|
||||
{
|
||||
var fileContents: String?
|
||||
if let fileBuf = fileBufs.first(where: { $0.path == problem.file })?.contents {
|
||||
|
|
|
@ -146,7 +146,7 @@ public final class ProcessRunner {
|
|||
}
|
||||
|
||||
public func waitUntilFinished() throws {
|
||||
try await { completion in
|
||||
try tsc_await { completion in
|
||||
subscription = publisher
|
||||
.sink(
|
||||
receiveCompletion: { completion($0.result) },
|
||||
|
|
|
@ -69,7 +69,7 @@ public struct Entrypoint {
|
|||
|
||||
let client = HTTPClient(eventLoopGroupProvider: .createNew)
|
||||
let request = try HTTPClient.Request.get(url: staticArchiveURL)
|
||||
let response: HTTPClient.Response = try await {
|
||||
let response: HTTPClient.Response = try tsc_await {
|
||||
client.execute(request: request).whenComplete($0)
|
||||
}
|
||||
try client.syncShutdown()
|
||||
|
@ -91,7 +91,7 @@ public struct Entrypoint {
|
|||
terminal.logLookup("Unpacking the archive: ", archiveFile)
|
||||
|
||||
try fileSystem.createDirectory(staticDir)
|
||||
try await {
|
||||
try tsc_await {
|
||||
ZipArchiver().extract(from: archiveFile, to: staticDir, completion: $0)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import Foundation
|
||||
import PackageModel
|
||||
import SwiftToolchain
|
||||
import TSCBasic
|
||||
import Vapor
|
||||
|
@ -23,8 +24,8 @@ extension Application {
|
|||
let host: String
|
||||
let mainWasmPath: AbsolutePath
|
||||
let customIndexContent: String?
|
||||
let package: SwiftToolchain.Package
|
||||
let product: Product?
|
||||
let manifest: Manifest
|
||||
let product: ProductDescription?
|
||||
let entrypoint: Entrypoint
|
||||
let onWebSocketOpen: (WebSocket, DestinationEnvironment) -> ()
|
||||
let onWebSocketClose: (WebSocket) -> ()
|
||||
|
@ -63,10 +64,10 @@ extension Application {
|
|||
}
|
||||
|
||||
let buildDirectory = configuration.mainWasmPath.parentDirectory
|
||||
for target in configuration.package.targets
|
||||
for target in configuration.manifest.targets
|
||||
where target.type == .regular && !target.resources.isEmpty
|
||||
{
|
||||
let resourcesPath = configuration.package.resourcesPath(for: target)
|
||||
let resourcesPath = configuration.manifest.resourcesPath(for: target)
|
||||
get(.constant(resourcesPath), "**") {
|
||||
$0.eventLoop.makeSucceededFuture($0.fileio.streamFile(at: AbsolutePath(
|
||||
buildDirectory.appending(component: resourcesPath),
|
||||
|
@ -75,13 +76,13 @@ extension Application {
|
|||
}
|
||||
}
|
||||
|
||||
let inferredMainTarget = configuration.package.targets.first {
|
||||
let inferredMainTarget = configuration.manifest.targets.first {
|
||||
configuration.product?.targets.contains($0.name) == true
|
||||
}
|
||||
|
||||
guard let mainTarget = inferredMainTarget else { return }
|
||||
|
||||
let resourcesPath = configuration.package.resourcesPath(for: mainTarget)
|
||||
let resourcesPath = configuration.manifest.resourcesPath(for: mainTarget)
|
||||
get("**") {
|
||||
$0.eventLoop.makeSucceededFuture($0.fileio.streamFile(at: AbsolutePath(
|
||||
buildDirectory.appending(component: resourcesPath),
|
||||
|
|
|
@ -18,6 +18,7 @@ import Combine
|
|||
#else
|
||||
import OpenCombine
|
||||
#endif
|
||||
import PackageModel
|
||||
import SwiftToolchain
|
||||
import TSCBasic
|
||||
import Vapor
|
||||
|
@ -83,8 +84,8 @@ public final class Server {
|
|||
let port: Int
|
||||
let host: String
|
||||
let customIndexContent: String?
|
||||
let package: SwiftToolchain.Package
|
||||
let product: Product?
|
||||
let manifest: Manifest
|
||||
let product: ProductDescription?
|
||||
let entrypoint: Entrypoint
|
||||
|
||||
public init(
|
||||
|
@ -95,8 +96,8 @@ public final class Server {
|
|||
port: Int,
|
||||
host: String,
|
||||
customIndexContent: String?,
|
||||
package: SwiftToolchain.Package,
|
||||
product: Product?,
|
||||
manifest: Manifest,
|
||||
product: ProductDescription?,
|
||||
entrypoint: Entrypoint
|
||||
) {
|
||||
self.builder = builder
|
||||
|
@ -106,7 +107,7 @@ public final class Server {
|
|||
self.port = port
|
||||
self.host = host
|
||||
self.customIndexContent = customIndexContent
|
||||
self.package = package
|
||||
self.manifest = manifest
|
||||
self.product = product
|
||||
self.entrypoint = entrypoint
|
||||
}
|
||||
|
@ -137,7 +138,7 @@ public final class Server {
|
|||
host: configuration.host,
|
||||
mainWasmPath: configuration.mainWasmPath,
|
||||
customIndexContent: configuration.customIndexContent,
|
||||
package: configuration.package,
|
||||
manifest: configuration.manifest,
|
||||
product: configuration.product,
|
||||
entrypoint: configuration.entrypoint,
|
||||
onWebSocketOpen: { [weak self] ws, environment in
|
||||
|
|
|
@ -92,7 +92,7 @@ public final class Builder {
|
|||
}
|
||||
|
||||
public func runAndWaitUntilFinished() throws {
|
||||
try await { completion in
|
||||
try tsc_await { completion in
|
||||
subscription = run()
|
||||
.sink(
|
||||
receiveCompletion: { completion($0.result) },
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
// Copyright 2020 Carton contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import CartonHelpers
|
||||
import Foundation
|
||||
import PackageModel
|
||||
import TSCBasic
|
||||
|
||||
extension Manifest {
|
||||
static func from(swiftPath: AbsolutePath, terminal: InteractiveWriter) throws -> Manifest {
|
||||
terminal.write("\nParsing package manifest: ", inColor: .yellow)
|
||||
terminal.write("\(swiftPath) package dump-package\n")
|
||||
let output = try Data(processDataOutput([swiftPath.pathString, "package", "dump-package"]))
|
||||
let decoder = JSONDecoder()
|
||||
let unencodedValues = DumpedManifest.Unencoded(
|
||||
path: swiftPath,
|
||||
url: swiftPath.asURL.absoluteString,
|
||||
version: nil
|
||||
)
|
||||
decoder.userInfo[DumpedManifest.unencodedKey] = unencodedValues
|
||||
let dumpedManifest = try decoder.decode(DumpedManifest.self, from: output)
|
||||
return dumpedManifest.manifest
|
||||
}
|
||||
|
||||
public func resourcesPath(for target: TargetDescription) -> String {
|
||||
"\(name)_\(target.name).resources"
|
||||
}
|
||||
}
|
||||
|
||||
public enum PackageType: String {
|
||||
case empty
|
||||
case library
|
||||
case executable
|
||||
case systemModule = "system-module"
|
||||
case manifest
|
||||
}
|
||||
|
||||
// MARK: Custom Decodable Wrappers
|
||||
|
||||
// TODO: Remove this struct when we move to `Swift 5.4`
|
||||
/// A temprary wrapper for decoding `PackageDependencyDescription` since
|
||||
/// `productFilter` is not available in dumped JSON with pre-5.4 compilers.
|
||||
struct DumpedPackageDependencyDescription: Decodable {
|
||||
var dependendy: PackageDependencyDescription
|
||||
|
||||
private enum CodingKeys: CodingKey {
|
||||
case name, url, requirement, productFilter
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let name = try container.decode(String.self, forKey: .name)
|
||||
let url = try container.decode(String.self, forKey: .url)
|
||||
let requirement = try container.decode(
|
||||
PackageDependencyDescription.Requirement.self,
|
||||
forKey: .requirement
|
||||
)
|
||||
let productFilter = try? container.decode(ProductFilter.self, forKey: .productFilter)
|
||||
dependendy = PackageDependencyDescription(
|
||||
name: name,
|
||||
url: url,
|
||||
requirement: requirement,
|
||||
productFilter: productFilter ?? .nothing
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around `Manifest` needed for decoding from `dump-package` output,
|
||||
/// since when encoding several (required for initialization) keys are skipped.
|
||||
/// When decoding this wrapper, callers must provide an `unencodedKey` in the
|
||||
/// decoder's `userInfo`.
|
||||
struct DumpedManifest: Decodable {
|
||||
var manifest: Manifest
|
||||
|
||||
static let unencodedKey = CodingUserInfoKey(rawValue: "unencoded")!
|
||||
|
||||
/// The skipped keys during `dump-package` encoding
|
||||
struct Unencoded {
|
||||
let path: AbsolutePath
|
||||
let url: String
|
||||
let version: Version?
|
||||
}
|
||||
|
||||
private enum CodingKeys: CodingKey {
|
||||
case name, toolsVersion,
|
||||
pkgConfig, providers, cLanguageStandard, cxxLanguageStandard, swiftLanguageVersions,
|
||||
dependencies, products, targets, platforms, packageKind, revision,
|
||||
defaultLocalization
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
guard let unencoded = decoder.userInfo[DumpedManifest.unencodedKey] as? Unencoded else {
|
||||
let context = DecodingError.Context(
|
||||
codingPath: [],
|
||||
debugDescription: "Unencoded values are missing from Decoder's userInfo"
|
||||
)
|
||||
throw DecodingError.dataCorrupted(context)
|
||||
}
|
||||
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let name = try container.decode(String.self, forKey: .name)
|
||||
let toolsVersion = try container.decode(ToolsVersion.self, forKey: .toolsVersion)
|
||||
let pkgConfig = try container.decode(String?.self, forKey: .pkgConfig)
|
||||
let providers = try container.decode(
|
||||
[SystemPackageProviderDescription]?.self,
|
||||
forKey: .providers
|
||||
)
|
||||
let cLanguageStandard = try container.decode(String?.self, forKey: .cLanguageStandard)
|
||||
let cxxLanguageStandard = try container.decode(String?.self, forKey: .cxxLanguageStandard)
|
||||
let swiftLanguageVersions = try container.decode(
|
||||
[SwiftLanguageVersion]?.self,
|
||||
forKey: .swiftLanguageVersions
|
||||
)
|
||||
// TODO: Change to `PackageDependencyDescription` when we move to `Swift 5.4`
|
||||
let dependencies = try container.decode(
|
||||
[DumpedPackageDependencyDescription].self,
|
||||
forKey: .dependencies
|
||||
)
|
||||
let products = try container.decode([ProductDescription].self, forKey: .products)
|
||||
let targets = try container.decode([TargetDescription].self, forKey: .targets)
|
||||
let platforms = try container.decode([PlatformDescription].self, forKey: .platforms)
|
||||
// TODO: Change to non-optional when we move to `Swift 5.4`
|
||||
// `packageKind` is not available in dumped JSON with pre-5.4 compilers.
|
||||
let packageKind = try? container.decode(PackageReference.Kind.self, forKey: .packageKind)
|
||||
manifest = Manifest(
|
||||
name: name,
|
||||
platforms: platforms,
|
||||
path: unencoded.path,
|
||||
url: unencoded.url,
|
||||
version: unencoded.version,
|
||||
toolsVersion: toolsVersion,
|
||||
packageKind: packageKind ?? .root,
|
||||
pkgConfig: pkgConfig,
|
||||
providers: providers,
|
||||
cLanguageStandard: cLanguageStandard,
|
||||
cxxLanguageStandard: cxxLanguageStandard,
|
||||
swiftLanguageVersions: swiftLanguageVersions,
|
||||
dependencies: dependencies.map(\.dependendy),
|
||||
products: products,
|
||||
targets: targets
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
// Copyright 2020 Carton contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import CartonHelpers
|
||||
import Foundation
|
||||
import TSCBasic
|
||||
|
||||
/**
|
||||
Simple Package structure from package dump
|
||||
*/
|
||||
public struct Package: Codable {
|
||||
public let name: String
|
||||
public let products: [Product]
|
||||
public let targets: [Target]
|
||||
public let dependencies: [Dependency]?
|
||||
|
||||
public struct Dependency: Codable {
|
||||
let name: String
|
||||
let requirement: Requirement
|
||||
|
||||
struct Requirement: Codable {
|
||||
let range: [Range]?
|
||||
let branch: [String]?
|
||||
let revision: [String]?
|
||||
let exact: [String]?
|
||||
|
||||
struct Range: Codable {
|
||||
let lowerBound: String
|
||||
let upperBound: String
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init(with swiftPath: AbsolutePath, _ terminal: InteractiveWriter) throws {
|
||||
terminal.write("\nParsing package manifest: ", inColor: .yellow)
|
||||
terminal.write("\(swiftPath) package dump-package\n")
|
||||
let output = try Data(processDataOutput([swiftPath.pathString, "package", "dump-package"]))
|
||||
|
||||
self = try JSONDecoder().decode(Package.self, from: output)
|
||||
}
|
||||
|
||||
public func resourcesPath(for target: Target) -> String {
|
||||
"\(name)_\(target.name).resources"
|
||||
}
|
||||
}
|
||||
|
||||
struct ProductType: Codable {
|
||||
let executable: String?
|
||||
let library: [String]?
|
||||
}
|
||||
|
||||
/**
|
||||
Simple Product structure from package dump
|
||||
*/
|
||||
public struct Product: Codable {
|
||||
let name: String
|
||||
let type: ProductType
|
||||
|
||||
/** List of names of targets that this product is composed of. Can be used to infer actual
|
||||
target descriptions used in this product.
|
||||
*/
|
||||
public let targets: [String]
|
||||
}
|
||||
|
||||
public enum TargetType: String, Codable {
|
||||
case regular
|
||||
case test
|
||||
case system
|
||||
}
|
||||
|
||||
public struct Target: Codable {
|
||||
public let name: String
|
||||
public let type: TargetType
|
||||
public let path: String?
|
||||
public let resources: [Resource]
|
||||
}
|
||||
|
||||
public struct Resource: Codable {
|
||||
public let path: String
|
||||
public let rule: Rule
|
||||
|
||||
public enum Rule: String, Codable {
|
||||
case copy
|
||||
case process
|
||||
}
|
||||
}
|
||||
|
||||
public enum PackageType: String {
|
||||
case empty
|
||||
case library
|
||||
case executable
|
||||
case systemModule = "system-module"
|
||||
case manifest
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
import CartonHelpers
|
||||
import Foundation
|
||||
import PackageModel
|
||||
import TSCBasic
|
||||
import TSCUtility
|
||||
|
||||
|
@ -67,16 +68,29 @@ enum ToolchainError: Error, CustomStringConvertible {
|
|||
}
|
||||
}
|
||||
|
||||
extension Package.Dependency.Requirement {
|
||||
extension PackageDependencyDescription.Requirement {
|
||||
var isJavaScriptKitCompatible: Bool {
|
||||
if let upperBound = range?.first?.upperBound, let version = Version(string: upperBound) {
|
||||
return version >= compatibleJSKitVersion
|
||||
switch self {
|
||||
case let .exact(version):
|
||||
return version == compatibleJSKitVersion
|
||||
case let .range(range):
|
||||
return range.upperBound >= compatibleJSKitVersion
|
||||
case .localPackage:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return exact?.compactMap { Version(string: $0) } == [compatibleJSKitVersion]
|
||||
}
|
||||
|
||||
var version: String {
|
||||
revision?.first ?? range?.first?.lowerBound ?? ""
|
||||
var versionDescription: String {
|
||||
switch self {
|
||||
case let .exact(version):
|
||||
return version.description
|
||||
case let .range(range):
|
||||
return range.lowerBound.description
|
||||
default:
|
||||
return "(Unknown)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +100,7 @@ public final class Toolchain {
|
|||
|
||||
private let version: String
|
||||
private let swiftPath: AbsolutePath
|
||||
public let package: Result<Package, Error>
|
||||
public let manifest: Result<Manifest, Error>
|
||||
|
||||
public init(
|
||||
for versionSpec: String? = nil,
|
||||
|
@ -99,7 +113,7 @@ public final class Toolchain {
|
|||
self.version = version
|
||||
self.fileSystem = fileSystem
|
||||
self.terminal = terminal
|
||||
package = Result { try Package(with: swiftPath, terminal) }
|
||||
manifest = Result { try Manifest.from(swiftPath: swiftPath, terminal: terminal) }
|
||||
}
|
||||
|
||||
private func inferBinPath(isRelease: Bool) throws -> AbsolutePath {
|
||||
|
@ -114,11 +128,11 @@ public final class Toolchain {
|
|||
return AbsolutePath(binPath)
|
||||
}
|
||||
|
||||
private func inferDevProduct(hint: String?) throws -> Product? {
|
||||
let package = try self.package.get()
|
||||
private func inferDevProduct(hint: String?) throws -> ProductDescription? {
|
||||
let manifest = try self.manifest.get()
|
||||
|
||||
var candidateProducts = package.products
|
||||
.filter { $0.type.library == nil }
|
||||
var candidateProducts = manifest.products
|
||||
.filter { $0.type == .executable }
|
||||
|
||||
if let productName = hint {
|
||||
candidateProducts = candidateProducts.filter { $0.name == productName }
|
||||
|
@ -152,7 +166,7 @@ public final class Toolchain {
|
|||
}
|
||||
|
||||
private func inferManifestDirectory() throws -> AbsolutePath {
|
||||
guard (try? package.get()) != nil, var cwd = fileSystem.currentWorkingDirectory else {
|
||||
guard (try? manifest.get()) != nil, var cwd = fileSystem.currentWorkingDirectory else {
|
||||
throw ToolchainError.missingPackageManifest
|
||||
}
|
||||
|
||||
|
@ -169,15 +183,15 @@ public final class Toolchain {
|
|||
}
|
||||
|
||||
public func inferSourcesPaths() throws -> [AbsolutePath] {
|
||||
let package = try self.package.get()
|
||||
let manifest = try self.manifest.get()
|
||||
|
||||
let targetPaths = package.targets.compactMap { target -> String? in
|
||||
let targetPaths = manifest.targets.compactMap { target -> String? in
|
||||
|
||||
guard let path = target.path else {
|
||||
switch target.type {
|
||||
case .regular:
|
||||
return RelativePath("Sources").appending(component: target.name).pathString
|
||||
case .test, .system:
|
||||
case .test, .system, .executable, .binary:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -194,20 +208,20 @@ public final class Toolchain {
|
|||
public func buildCurrentProject(
|
||||
product: String?,
|
||||
isRelease: Bool
|
||||
) throws -> (builderArguments: [String], mainWasmPath: AbsolutePath, Product) {
|
||||
) throws -> (builderArguments: [String], mainWasmPath: AbsolutePath, ProductDescription) {
|
||||
guard let product = try inferDevProduct(hint: product)
|
||||
else { throw ToolchainError.noExecutableProduct }
|
||||
|
||||
let package = try self.package.get()
|
||||
if let jsKit = package.dependencies?.first(where: { $0.name == "JavaScriptKit" }),
|
||||
!jsKit.requirement.isJavaScriptKitCompatible
|
||||
let manifest = try self.manifest.get()
|
||||
if let jsKit = manifest.dependencies.first(where: { $0.name == "JavaScriptKit" }),
|
||||
!jsKit.requirement.isJavaScriptKitCompatible
|
||||
{
|
||||
let version = jsKit.requirement.version
|
||||
let versionDescription = jsKit.requirement.versionDescription
|
||||
|
||||
terminal.write(
|
||||
"""
|
||||
|
||||
This version of JavaScriptKit \(version) is not known to be compatible with \
|
||||
This version of JavaScriptKit \(versionDescription) is not known to be compatible with \
|
||||
carton \(cartonVersion). Please specify a JavaScriptKit dependency on version \
|
||||
\(compatibleJSKitVersion) in your `Package.swift`.\n
|
||||
|
||||
|
@ -246,9 +260,9 @@ public final class Toolchain {
|
|||
isRelease: Bool,
|
||||
_ environment: DestinationEnvironment
|
||||
) throws -> AbsolutePath {
|
||||
let package = try self.package.get()
|
||||
let manifest = try self.manifest.get()
|
||||
let binPath = try inferBinPath(isRelease: isRelease)
|
||||
let testProductName = "\(package.name)PackageTests"
|
||||
let testProductName = "\(manifest.name)PackageTests"
|
||||
let testBundlePath = binPath.appending(component: "\(testProductName).wasm")
|
||||
terminal.logLookup("- test bundle to run: ", testBundlePath.pathString)
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ extension ToolchainSystem {
|
|||
var subscriptions = [AnyCancellable]()
|
||||
let request = try HTTPClient.Request.get(url: url)
|
||||
|
||||
_ = try await { (completion: @escaping (Result<(), Error>) -> ()) in
|
||||
_ = try tsc_await { (completion: @escaping (Result<(), Error>) -> ()) in
|
||||
client.execute(request: request, delegate: delegate).futureResult.whenComplete { _ in
|
||||
subject.send(completion: .finished)
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ extension ToolchainSystem {
|
|||
path: path,
|
||||
reportHead: {
|
||||
guard $0.status == .ok,
|
||||
let totalBytes = $0.headers.first(name: "Content-Length").flatMap(Int.init)
|
||||
let totalBytes = $0.headers.first(name: "Content-Length").flatMap(Int.init)
|
||||
else {
|
||||
subject.send(completion: .failure(ToolchainError.invalidResponseCode($0.status.code)))
|
||||
return
|
||||
|
|
|
@ -104,8 +104,8 @@ public class ToolchainSystem {
|
|||
) throws -> String {
|
||||
if let versionSpec = versionSpec {
|
||||
if let url = URL(string: versionSpec),
|
||||
let filename = url.pathComponents.last,
|
||||
let match = versionRegEx.matchGroups(in: filename).first?.first
|
||||
let filename = url.pathComponents.last,
|
||||
let match = versionRegEx.matchGroups(in: filename).first?.first
|
||||
{
|
||||
terminal.logLookup("Inferred swift version: ", match)
|
||||
return match
|
||||
|
@ -152,7 +152,7 @@ public class ToolchainSystem {
|
|||
terminal.logLookup("Fetching release assets from ", releaseURL)
|
||||
let decoder = JSONDecoder()
|
||||
let request = try HTTPClient.Request.get(url: releaseURL)
|
||||
let release = try await {
|
||||
let release = try tsc_await {
|
||||
client.execute(request: request).flatMapResult { response -> Result<Release, Error> in
|
||||
guard (200..<300).contains(response.status.code), let body = response.body else {
|
||||
return .failure(ToolchainError.invalidResponse(
|
||||
|
@ -267,10 +267,10 @@ public class ToolchainSystem {
|
|||
|
||||
public func fetchLocalSwiftVersion() throws -> String? {
|
||||
guard fileSystem.isFile(swiftVersionPath),
|
||||
let version = try fileSystem.readFileContents(swiftVersionPath)
|
||||
.validDescription?
|
||||
// get the first line of the file
|
||||
.components(separatedBy: CharacterSet.newlines).first
|
||||
let version = try fileSystem.readFileContents(swiftVersionPath)
|
||||
.validDescription?
|
||||
// get the first line of the file
|
||||
.components(separatedBy: CharacterSet.newlines).first
|
||||
else { return nil }
|
||||
|
||||
return version
|
||||
|
|
|
@ -23,7 +23,7 @@ struct Formula: ParsableCommand {
|
|||
let archiveURL = "https://github.com/swiftwasm/carton/archive/\(version).tar.gz"
|
||||
|
||||
let client = HTTPClient(eventLoopGroupProvider: .createNew)
|
||||
let response: HTTPClient.Response = try await {
|
||||
let response: HTTPClient.Response = try tsc_await {
|
||||
client.get(url: archiveURL).whenComplete($0)
|
||||
}
|
||||
try client.syncShutdown()
|
||||
|
|
Loading…
Reference in New Issue