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"
|
"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",
|
"package": "swift-log",
|
||||||
"repositoryURL": "https://github.com/apple/swift-log.git",
|
"repositoryURL": "https://github.com/apple/swift-log.git",
|
||||||
|
@ -145,13 +163,22 @@
|
||||||
"version": "1.9.1"
|
"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",
|
"package": "swift-tools-support-core",
|
||||||
"repositoryURL": "https://github.com/apple/swift-tools-support-core.git",
|
"repositoryURL": "https://github.com/apple/swift-tools-support-core.git",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": "release/5.4",
|
||||||
"revision": "243beea77d20db46647a3de4765c96e2c801c7c7",
|
"revision": "bc7961701fd94104528b017e969f63ea40bdb22b",
|
||||||
"version": "0.1.12"
|
"version": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -180,6 +207,15 @@
|
||||||
"revision": "2b06a70dfcfa76a2e5079f60e3ae911511f09db0",
|
"revision": "2b06a70dfcfa76a2e5079f60e3ae911511f09db0",
|
||||||
"version": "2.1.2"
|
"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",
|
url: "https://github.com/apple/swift-argument-parser.git",
|
||||||
.upToNextMinor(from: "0.3.0")
|
.upToNextMinor(from: "0.3.0")
|
||||||
),
|
),
|
||||||
|
.package(
|
||||||
|
name: "SwiftPM",
|
||||||
|
url: "https://github.com/apple/swift-package-manager.git",
|
||||||
|
.branch("release/5.4")
|
||||||
|
),
|
||||||
.package(
|
.package(
|
||||||
url: "https://github.com/apple/swift-tools-support-core.git",
|
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/OpenCombine/OpenCombine.git", from: "0.10.0"),
|
||||||
.package(url: "https://github.com/vapor/vapor.git", from: "4.29.3"),
|
.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: "ArgumentParser", package: "swift-argument-parser"),
|
||||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||||
.product(name: "Crypto", package: "swift-crypto"),
|
.product(name: "Crypto", package: "swift-crypto"),
|
||||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
|
||||||
.product(name: "Vapor", package: "vapor"),
|
.product(name: "Vapor", package: "vapor"),
|
||||||
"CartonHelpers",
|
"CartonHelpers",
|
||||||
openCombineProduct,
|
openCombineProduct,
|
||||||
|
@ -76,7 +80,7 @@ let package = Package(
|
||||||
name: "SwiftToolchain",
|
name: "SwiftToolchain",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
.product(name: "SwiftPMDataModel", package: "SwiftPM"),
|
||||||
"CartonHelpers",
|
"CartonHelpers",
|
||||||
openCombineProduct,
|
openCombineProduct,
|
||||||
"WasmTransformer",
|
"WasmTransformer",
|
||||||
|
@ -86,7 +90,6 @@ let package = Package(
|
||||||
name: "CartonHelpers",
|
name: "CartonHelpers",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
|
||||||
openCombineProduct,
|
openCombineProduct,
|
||||||
"Splash",
|
"Splash",
|
||||||
]
|
]
|
||||||
|
@ -107,7 +110,6 @@ let package = Package(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
"Carton",
|
"Carton",
|
||||||
"CartonHelpers",
|
"CartonHelpers",
|
||||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
|
||||||
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
|
|
@ -20,9 +20,14 @@ let package = Package(
|
||||||
url: "https://github.com/apple/swift-argument-parser.git",
|
url: "https://github.com/apple/swift-argument-parser.git",
|
||||||
.upToNextMinor(from: "0.3.0")
|
.upToNextMinor(from: "0.3.0")
|
||||||
),
|
),
|
||||||
|
.package(
|
||||||
|
name: "SwiftPM",
|
||||||
|
url: "https://github.com/apple/swift-package-manager.git",
|
||||||
|
.branch("release/5.4")
|
||||||
|
),
|
||||||
.package(
|
.package(
|
||||||
url: "https://github.com/apple/swift-tools-support-core.git",
|
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/OpenCombine/OpenCombine.git", from: "0.10.0"),
|
||||||
.package(url: "https://github.com/vapor/vapor.git", from: "4.29.3"),
|
.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: "ArgumentParser", package: "swift-argument-parser"),
|
||||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||||
.product(name: "Crypto", package: "swift-crypto"),
|
.product(name: "Crypto", package: "swift-crypto"),
|
||||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
|
||||||
.product(name: "Vapor", package: "vapor"),
|
.product(name: "Vapor", package: "vapor"),
|
||||||
"CartonHelpers",
|
"CartonHelpers",
|
||||||
"OpenCombine",
|
"OpenCombine",
|
||||||
|
@ -70,6 +74,7 @@ let package = Package(
|
||||||
name: "SwiftToolchain",
|
name: "SwiftToolchain",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||||
|
.product(name: "SwiftPMDataModel", package: "SwiftPM"),
|
||||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
||||||
"CartonHelpers",
|
"CartonHelpers",
|
||||||
"OpenCombine",
|
"OpenCombine",
|
||||||
|
@ -92,7 +97,6 @@ let package = Package(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||||
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
.product(name: "AsyncHTTPClient", package: "async-http-client"),
|
||||||
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
|
|
||||||
"CartonHelpers",
|
"CartonHelpers",
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
|
|
@ -16,6 +16,7 @@ import ArgumentParser
|
||||||
import CartonHelpers
|
import CartonHelpers
|
||||||
import CartonKit
|
import CartonKit
|
||||||
import Crypto
|
import Crypto
|
||||||
|
import PackageModel
|
||||||
import SwiftToolchain
|
import SwiftToolchain
|
||||||
import TSCBasic
|
import TSCBasic
|
||||||
import WasmTransformer
|
import WasmTransformer
|
||||||
|
@ -105,7 +106,7 @@ struct Bundle: ParsableCommand {
|
||||||
buildDirectory: AbsolutePath,
|
buildDirectory: AbsolutePath,
|
||||||
bundleDirectory: AbsolutePath,
|
bundleDirectory: AbsolutePath,
|
||||||
toolchain: Toolchain,
|
toolchain: Toolchain,
|
||||||
product: Product
|
product: ProductDescription
|
||||||
) throws {
|
) throws {
|
||||||
// Rename the final binary to use a part of its hash to bust browsers and CDN caches.
|
// 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)
|
let optimizedHash = try localFileSystem.readFileContents(optimizedPath).hexSHA256.prefix(16)
|
||||||
|
@ -137,9 +138,9 @@ struct Bundle: ParsableCommand {
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
|
||||||
let package = try toolchain.package.get()
|
let manifest = try toolchain.manifest.get()
|
||||||
for target in package.targets where target.type == .regular && !target.resources.isEmpty {
|
for target in manifest.targets where target.type == .regular && !target.resources.isEmpty {
|
||||||
let targetPath = package.resourcesPath(for: target)
|
let targetPath = manifest.resourcesPath(for: target)
|
||||||
let resourcesPath = buildDirectory.appending(component: targetPath)
|
let resourcesPath = buildDirectory.appending(component: targetPath)
|
||||||
let targetDirectory = bundleDirectory.appending(component: targetPath)
|
let targetDirectory = bundleDirectory.appending(component: targetPath)
|
||||||
|
|
||||||
|
@ -154,13 +155,13 @@ struct Bundle: ParsableCommand {
|
||||||
swiftlint:disable:next line_length
|
swiftlint:disable:next line_length
|
||||||
https://forums.swift.org/t/pitch-ability-to-declare-executable-targets-in-swiftpm-manifests-to-support-main/41968
|
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)
|
product.targets.contains($0.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let mainTarget = inferredMainTarget else { return }
|
guard let mainTarget = inferredMainTarget else { return }
|
||||||
|
|
||||||
let targetPath = package.resourcesPath(for: mainTarget)
|
let targetPath = manifest.resourcesPath(for: mainTarget)
|
||||||
let resourcesPath = buildDirectory.appending(component: targetPath)
|
let resourcesPath = buildDirectory.appending(component: targetPath)
|
||||||
for file in try localFileSystem.traverseRecursively(resourcesPath) {
|
for file in try localFileSystem.traverseRecursively(resourcesPath) {
|
||||||
let targetPath = bundleDirectory.appending(component: file.basename)
|
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.")
|
@Option(name: .shortAndLong, help: "Set the HTTP port the development server will run on.")
|
||||||
var port = 8080
|
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"
|
var host = "127.0.0.1"
|
||||||
|
|
||||||
@Flag(name: .long, help: "Skip automatically opening app in system browser.")
|
@Flag(name: .long, help: "Skip automatically opening app in system browser.")
|
||||||
|
@ -114,7 +117,7 @@ struct Dev: ParsableCommand {
|
||||||
host: host,
|
host: host,
|
||||||
customIndexContent: HTML.readCustomIndexPage(at: customIndexPage, on: localFileSystem),
|
customIndexContent: HTML.readCustomIndexPage(at: customIndexPage, on: localFileSystem),
|
||||||
// swiftlint:disable:next force_try
|
// swiftlint:disable:next force_try
|
||||||
package: try! toolchain.package.get(),
|
manifest: try! toolchain.manifest.get(),
|
||||||
product: inferredProduct,
|
product: inferredProduct,
|
||||||
entrypoint: Self.entrypoint
|
entrypoint: Self.entrypoint
|
||||||
),
|
),
|
||||||
|
|
|
@ -96,7 +96,7 @@ struct Test: ParsableCommand {
|
||||||
host: host,
|
host: host,
|
||||||
customIndexContent: nil,
|
customIndexContent: nil,
|
||||||
// swiftlint:disable:next force_try
|
// swiftlint:disable:next force_try
|
||||||
package: try! toolchain.package.get(),
|
manifest: try! toolchain.manifest.get(),
|
||||||
product: nil,
|
product: nil,
|
||||||
entrypoint: Self.entrypoint
|
entrypoint: Self.entrypoint
|
||||||
),
|
),
|
||||||
|
|
|
@ -26,8 +26,8 @@ public extension StringProtocol {
|
||||||
var chromeStackTrace: [StackTraceItem] {
|
var chromeStackTrace: [StackTraceItem] {
|
||||||
split(separator: "\n").dropFirst().compactMap {
|
split(separator: "\n").dropFirst().compactMap {
|
||||||
if let webpackMatch = webpackRegex.matchGroups(in: String($0)).first,
|
if let webpackMatch = webpackRegex.matchGroups(in: String($0)).first,
|
||||||
let symbol = webpackMatch.first,
|
let symbol = webpackMatch.first,
|
||||||
let location = webpackMatch.last
|
let location = webpackMatch.last
|
||||||
{
|
{
|
||||||
return StackTraceItem(symbol: symbol, location: location, kind: .javaScript)
|
return StackTraceItem(symbol: symbol, location: location, kind: .javaScript)
|
||||||
} else if
|
} else if
|
||||||
|
|
|
@ -162,9 +162,9 @@ public struct DiagnosticsParser: ProcessOutputParser {
|
||||||
var groupedMessages = [[CustomDiagnostic]]()
|
var groupedMessages = [[CustomDiagnostic]]()
|
||||||
for message in messages {
|
for message in messages {
|
||||||
if let lastLineStr = groupedMessages.last?.last?.line,
|
if let lastLineStr = groupedMessages.last?.last?.line,
|
||||||
let lastLine = Int(lastLineStr),
|
let lastLine = Int(lastLineStr),
|
||||||
let line = Int(message.line),
|
let line = Int(message.line),
|
||||||
lastLine == line - 1 || lastLine == line
|
lastLine == line - 1 || lastLine == line
|
||||||
{
|
{
|
||||||
groupedMessages[groupedMessages.count - 1].append(message)
|
groupedMessages[groupedMessages.count - 1].append(message)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -26,8 +26,8 @@ public extension StringProtocol {
|
||||||
var firefoxStackTrace: [StackTraceItem] {
|
var firefoxStackTrace: [StackTraceItem] {
|
||||||
split(separator: "\n").compactMap {
|
split(separator: "\n").compactMap {
|
||||||
if let webpackMatch = webpackRegex.matchGroups(in: String($0)).first,
|
if let webpackMatch = webpackRegex.matchGroups(in: String($0)).first,
|
||||||
let symbol = webpackMatch.first,
|
let symbol = webpackMatch.first,
|
||||||
let location = webpackMatch.last
|
let location = webpackMatch.last
|
||||||
{
|
{
|
||||||
return StackTraceItem(symbol: symbol, location: location, kind: .javaScript)
|
return StackTraceItem(symbol: symbol, location: location, kind: .javaScript)
|
||||||
} else if
|
} else if
|
||||||
|
|
|
@ -26,7 +26,7 @@ public extension StringProtocol {
|
||||||
var safariStackTrace: [StackTraceItem] {
|
var safariStackTrace: [StackTraceItem] {
|
||||||
split(separator: "\n").compactMap {
|
split(separator: "\n").compactMap {
|
||||||
if let wasmMatch = wasmRegex.matchGroups(in: String($0)).first,
|
if let wasmMatch = wasmRegex.matchGroups(in: String($0)).first,
|
||||||
let symbol = wasmMatch.first
|
let symbol = wasmMatch.first
|
||||||
{
|
{
|
||||||
return StackTraceItem(
|
return StackTraceItem(
|
||||||
symbol: demangle(symbol),
|
symbol: demangle(symbol),
|
||||||
|
|
|
@ -19,7 +19,7 @@ extension StringProtocol {
|
||||||
func matches(regex: NSRegularExpression) -> String.SubSequence? {
|
func matches(regex: NSRegularExpression) -> String.SubSequence? {
|
||||||
let str = String(self)
|
let str = String(self)
|
||||||
guard let range = str.range(of: regex),
|
guard let range = str.range(of: regex),
|
||||||
range.upperBound < str.endIndex
|
range.upperBound < str.endIndex
|
||||||
else { return nil }
|
else { return nil }
|
||||||
return str[range.upperBound..<str.endIndex]
|
return str[range.upperBound..<str.endIndex]
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ extension StringProtocol {
|
||||||
let str = String(self)
|
let str = String(self)
|
||||||
let range = NSRange(location: 0, length: utf16.count)
|
let range = NSRange(location: 0, length: utf16.count)
|
||||||
guard let match = regex.firstMatch(in: str, options: [], range: range),
|
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 {
|
else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ extension StringProtocol {
|
||||||
let str = String(self)
|
let str = String(self)
|
||||||
let range = NSRange(location: 0, length: utf16.count)
|
let range = NSRange(location: 0, length: utf16.count)
|
||||||
guard let matches = regex.matches(in: str, options: [], range: range).first,
|
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 {
|
else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ extension StringProtocol {
|
||||||
func match(of regex: NSRegularExpression, named name: String) -> String.SubSequence? {
|
func match(of regex: NSRegularExpression, named name: String) -> String.SubSequence? {
|
||||||
let str = String(self)
|
let str = String(self)
|
||||||
guard let range = str.range(of: regex, named: name),
|
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 }
|
else { return nil }
|
||||||
return str[range]
|
return str[range]
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ private extension StringProtocol {
|
||||||
_ labelB: TestsParser.Regex.Label
|
_ labelB: TestsParser.Regex.Label
|
||||||
) -> (String.SubSequence, String.SubSequence)? {
|
) -> (String.SubSequence, String.SubSequence)? {
|
||||||
guard let a = match(of: regex, named: labelA.rawValue),
|
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 {
|
else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -93,10 +93,10 @@ public struct TestsParser: ProcessOutputParser {
|
||||||
|
|
||||||
enum Assertion: String, CaseIterable {
|
enum Assertion: String, CaseIterable {
|
||||||
case equal = "Equal",
|
case equal = "Equal",
|
||||||
greaterThan = "GreaterThan",
|
greaterThan = "GreaterThan",
|
||||||
lessThan = "LessThan",
|
lessThan = "LessThan",
|
||||||
greaterThanOrEqual = "GreaterThanOrEqual",
|
greaterThanOrEqual = "GreaterThanOrEqual",
|
||||||
lessThanOrEqual = "LessThanOrEqual"
|
lessThanOrEqual = "LessThanOrEqual"
|
||||||
|
|
||||||
var funcName: String {
|
var funcName: String {
|
||||||
"XCTAssert\(rawValue)"
|
"XCTAssert\(rawValue)"
|
||||||
|
@ -178,20 +178,20 @@ public struct TestsParser: ProcessOutputParser {
|
||||||
if let suite = line.match(of: Regex.suiteStarted, labelled: .suite) {
|
if let suite = line.match(of: Regex.suiteStarted, labelled: .suite) {
|
||||||
suites.append(.init(name: suite, cases: []))
|
suites.append(.init(name: suite, cases: []))
|
||||||
} else if let testCase = line.match(of: Regex.caseFinished, labelled: .testCase),
|
} else if let testCase = line.match(of: Regex.caseFinished, labelled: .testCase),
|
||||||
let suite = line.match(of: Regex.caseFinished, labelled: .suite),
|
let suite = line.match(of: Regex.caseFinished, labelled: .suite),
|
||||||
let suiteIdx = suites.firstIndex(where: { $0.name == suite }),
|
let suiteIdx = suites.firstIndex(where: { $0.name == suite }),
|
||||||
let status = line.match(of: Regex.caseFinished, labelled: .status),
|
let status = line.match(of: Regex.caseFinished, labelled: .status),
|
||||||
let duration = line.match(of: Regex.caseFinished, labelled: .duration)
|
let duration = line.match(of: Regex.caseFinished, labelled: .duration)
|
||||||
{
|
{
|
||||||
suites[suiteIdx].cases.append(
|
suites[suiteIdx].cases.append(
|
||||||
.init(name: testCase, passed: status == "passed", duration: duration, problems: [])
|
.init(name: testCase, passed: status == "passed", duration: duration, problems: [])
|
||||||
)
|
)
|
||||||
} else if let problem = line.matches(regex: Regex.problem),
|
} else if let problem = line.matches(regex: Regex.problem),
|
||||||
let path = line.match(of: Regex.problem, labelled: .path),
|
let path = line.match(of: Regex.problem, labelled: .path),
|
||||||
let lineNum = line.match(of: Regex.problem, labelled: .line),
|
let lineNum = line.match(of: Regex.problem, labelled: .line),
|
||||||
let status = line.match(of: Regex.problem, labelled: .status),
|
let status = line.match(of: Regex.problem, labelled: .status),
|
||||||
let suite = line.match(of: Regex.problem, labelled: .suite),
|
let suite = line.match(of: Regex.problem, labelled: .suite),
|
||||||
let testCase = line.match(of: Regex.problem, labelled: .testCase)
|
let testCase = line.match(of: Regex.problem, labelled: .testCase)
|
||||||
{
|
{
|
||||||
let diag = DiagnosticsParser.CustomDiagnostic(
|
let diag = DiagnosticsParser.CustomDiagnostic(
|
||||||
kind: DiagnosticsParser.CustomDiagnostic.Kind(rawValue: String(status)) ?? .note,
|
kind: DiagnosticsParser.CustomDiagnostic.Kind(rawValue: String(status)) ?? .note,
|
||||||
|
@ -202,7 +202,7 @@ public struct TestsParser: ProcessOutputParser {
|
||||||
message: String(problem)
|
message: String(problem)
|
||||||
)
|
)
|
||||||
if let suiteIdx = suites.firstIndex(where: { $0.name == suite }),
|
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)
|
suites[suiteIdx].cases[caseIdx].problems.append(diag)
|
||||||
} else {
|
} else {
|
||||||
|
@ -212,7 +212,7 @@ public struct TestsParser: ProcessOutputParser {
|
||||||
}
|
}
|
||||||
for problem in unmappedProblems {
|
for problem in unmappedProblems {
|
||||||
if let suiteIdx = suites.firstIndex(where: { $0.name == problem.suite }),
|
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)
|
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.
|
// Get the line of code from the file and output it for context.
|
||||||
if let lineNum = Int(problem.line),
|
if let lineNum = Int(problem.line),
|
||||||
lineNum > 0
|
lineNum > 0
|
||||||
{
|
{
|
||||||
var fileContents: String?
|
var fileContents: String?
|
||||||
if let fileBuf = fileBufs.first(where: { $0.path == problem.file })?.contents {
|
if let fileBuf = fileBufs.first(where: { $0.path == problem.file })?.contents {
|
||||||
|
|
|
@ -146,7 +146,7 @@ public final class ProcessRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func waitUntilFinished() throws {
|
public func waitUntilFinished() throws {
|
||||||
try await { completion in
|
try tsc_await { completion in
|
||||||
subscription = publisher
|
subscription = publisher
|
||||||
.sink(
|
.sink(
|
||||||
receiveCompletion: { completion($0.result) },
|
receiveCompletion: { completion($0.result) },
|
||||||
|
|
|
@ -69,7 +69,7 @@ public struct Entrypoint {
|
||||||
|
|
||||||
let client = HTTPClient(eventLoopGroupProvider: .createNew)
|
let client = HTTPClient(eventLoopGroupProvider: .createNew)
|
||||||
let request = try HTTPClient.Request.get(url: staticArchiveURL)
|
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)
|
client.execute(request: request).whenComplete($0)
|
||||||
}
|
}
|
||||||
try client.syncShutdown()
|
try client.syncShutdown()
|
||||||
|
@ -91,7 +91,7 @@ public struct Entrypoint {
|
||||||
terminal.logLookup("Unpacking the archive: ", archiveFile)
|
terminal.logLookup("Unpacking the archive: ", archiveFile)
|
||||||
|
|
||||||
try fileSystem.createDirectory(staticDir)
|
try fileSystem.createDirectory(staticDir)
|
||||||
try await {
|
try tsc_await {
|
||||||
ZipArchiver().extract(from: archiveFile, to: staticDir, completion: $0)
|
ZipArchiver().extract(from: archiveFile, to: staticDir, completion: $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import PackageModel
|
||||||
import SwiftToolchain
|
import SwiftToolchain
|
||||||
import TSCBasic
|
import TSCBasic
|
||||||
import Vapor
|
import Vapor
|
||||||
|
@ -23,8 +24,8 @@ extension Application {
|
||||||
let host: String
|
let host: String
|
||||||
let mainWasmPath: AbsolutePath
|
let mainWasmPath: AbsolutePath
|
||||||
let customIndexContent: String?
|
let customIndexContent: String?
|
||||||
let package: SwiftToolchain.Package
|
let manifest: Manifest
|
||||||
let product: Product?
|
let product: ProductDescription?
|
||||||
let entrypoint: Entrypoint
|
let entrypoint: Entrypoint
|
||||||
let onWebSocketOpen: (WebSocket, DestinationEnvironment) -> ()
|
let onWebSocketOpen: (WebSocket, DestinationEnvironment) -> ()
|
||||||
let onWebSocketClose: (WebSocket) -> ()
|
let onWebSocketClose: (WebSocket) -> ()
|
||||||
|
@ -63,10 +64,10 @@ extension Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
let buildDirectory = configuration.mainWasmPath.parentDirectory
|
let buildDirectory = configuration.mainWasmPath.parentDirectory
|
||||||
for target in configuration.package.targets
|
for target in configuration.manifest.targets
|
||||||
where target.type == .regular && !target.resources.isEmpty
|
where target.type == .regular && !target.resources.isEmpty
|
||||||
{
|
{
|
||||||
let resourcesPath = configuration.package.resourcesPath(for: target)
|
let resourcesPath = configuration.manifest.resourcesPath(for: target)
|
||||||
get(.constant(resourcesPath), "**") {
|
get(.constant(resourcesPath), "**") {
|
||||||
$0.eventLoop.makeSucceededFuture($0.fileio.streamFile(at: AbsolutePath(
|
$0.eventLoop.makeSucceededFuture($0.fileio.streamFile(at: AbsolutePath(
|
||||||
buildDirectory.appending(component: resourcesPath),
|
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
|
configuration.product?.targets.contains($0.name) == true
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let mainTarget = inferredMainTarget else { return }
|
guard let mainTarget = inferredMainTarget else { return }
|
||||||
|
|
||||||
let resourcesPath = configuration.package.resourcesPath(for: mainTarget)
|
let resourcesPath = configuration.manifest.resourcesPath(for: mainTarget)
|
||||||
get("**") {
|
get("**") {
|
||||||
$0.eventLoop.makeSucceededFuture($0.fileio.streamFile(at: AbsolutePath(
|
$0.eventLoop.makeSucceededFuture($0.fileio.streamFile(at: AbsolutePath(
|
||||||
buildDirectory.appending(component: resourcesPath),
|
buildDirectory.appending(component: resourcesPath),
|
||||||
|
|
|
@ -18,6 +18,7 @@ import Combine
|
||||||
#else
|
#else
|
||||||
import OpenCombine
|
import OpenCombine
|
||||||
#endif
|
#endif
|
||||||
|
import PackageModel
|
||||||
import SwiftToolchain
|
import SwiftToolchain
|
||||||
import TSCBasic
|
import TSCBasic
|
||||||
import Vapor
|
import Vapor
|
||||||
|
@ -83,8 +84,8 @@ public final class Server {
|
||||||
let port: Int
|
let port: Int
|
||||||
let host: String
|
let host: String
|
||||||
let customIndexContent: String?
|
let customIndexContent: String?
|
||||||
let package: SwiftToolchain.Package
|
let manifest: Manifest
|
||||||
let product: Product?
|
let product: ProductDescription?
|
||||||
let entrypoint: Entrypoint
|
let entrypoint: Entrypoint
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
|
@ -95,8 +96,8 @@ public final class Server {
|
||||||
port: Int,
|
port: Int,
|
||||||
host: String,
|
host: String,
|
||||||
customIndexContent: String?,
|
customIndexContent: String?,
|
||||||
package: SwiftToolchain.Package,
|
manifest: Manifest,
|
||||||
product: Product?,
|
product: ProductDescription?,
|
||||||
entrypoint: Entrypoint
|
entrypoint: Entrypoint
|
||||||
) {
|
) {
|
||||||
self.builder = builder
|
self.builder = builder
|
||||||
|
@ -106,7 +107,7 @@ public final class Server {
|
||||||
self.port = port
|
self.port = port
|
||||||
self.host = host
|
self.host = host
|
||||||
self.customIndexContent = customIndexContent
|
self.customIndexContent = customIndexContent
|
||||||
self.package = package
|
self.manifest = manifest
|
||||||
self.product = product
|
self.product = product
|
||||||
self.entrypoint = entrypoint
|
self.entrypoint = entrypoint
|
||||||
}
|
}
|
||||||
|
@ -137,7 +138,7 @@ public final class Server {
|
||||||
host: configuration.host,
|
host: configuration.host,
|
||||||
mainWasmPath: configuration.mainWasmPath,
|
mainWasmPath: configuration.mainWasmPath,
|
||||||
customIndexContent: configuration.customIndexContent,
|
customIndexContent: configuration.customIndexContent,
|
||||||
package: configuration.package,
|
manifest: configuration.manifest,
|
||||||
product: configuration.product,
|
product: configuration.product,
|
||||||
entrypoint: configuration.entrypoint,
|
entrypoint: configuration.entrypoint,
|
||||||
onWebSocketOpen: { [weak self] ws, environment in
|
onWebSocketOpen: { [weak self] ws, environment in
|
||||||
|
|
|
@ -92,7 +92,7 @@ public final class Builder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func runAndWaitUntilFinished() throws {
|
public func runAndWaitUntilFinished() throws {
|
||||||
try await { completion in
|
try tsc_await { completion in
|
||||||
subscription = run()
|
subscription = run()
|
||||||
.sink(
|
.sink(
|
||||||
receiveCompletion: { completion($0.result) },
|
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 CartonHelpers
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import PackageModel
|
||||||
import TSCBasic
|
import TSCBasic
|
||||||
import TSCUtility
|
import TSCUtility
|
||||||
|
|
||||||
|
@ -67,16 +68,29 @@ enum ToolchainError: Error, CustomStringConvertible {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Package.Dependency.Requirement {
|
extension PackageDependencyDescription.Requirement {
|
||||||
var isJavaScriptKitCompatible: Bool {
|
var isJavaScriptKitCompatible: Bool {
|
||||||
if let upperBound = range?.first?.upperBound, let version = Version(string: upperBound) {
|
switch self {
|
||||||
return version >= compatibleJSKitVersion
|
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 {
|
var versionDescription: String {
|
||||||
revision?.first ?? range?.first?.lowerBound ?? ""
|
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 version: String
|
||||||
private let swiftPath: AbsolutePath
|
private let swiftPath: AbsolutePath
|
||||||
public let package: Result<Package, Error>
|
public let manifest: Result<Manifest, Error>
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
for versionSpec: String? = nil,
|
for versionSpec: String? = nil,
|
||||||
|
@ -99,7 +113,7 @@ public final class Toolchain {
|
||||||
self.version = version
|
self.version = version
|
||||||
self.fileSystem = fileSystem
|
self.fileSystem = fileSystem
|
||||||
self.terminal = terminal
|
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 {
|
private func inferBinPath(isRelease: Bool) throws -> AbsolutePath {
|
||||||
|
@ -114,11 +128,11 @@ public final class Toolchain {
|
||||||
return AbsolutePath(binPath)
|
return AbsolutePath(binPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func inferDevProduct(hint: String?) throws -> Product? {
|
private func inferDevProduct(hint: String?) throws -> ProductDescription? {
|
||||||
let package = try self.package.get()
|
let manifest = try self.manifest.get()
|
||||||
|
|
||||||
var candidateProducts = package.products
|
var candidateProducts = manifest.products
|
||||||
.filter { $0.type.library == nil }
|
.filter { $0.type == .executable }
|
||||||
|
|
||||||
if let productName = hint {
|
if let productName = hint {
|
||||||
candidateProducts = candidateProducts.filter { $0.name == productName }
|
candidateProducts = candidateProducts.filter { $0.name == productName }
|
||||||
|
@ -152,7 +166,7 @@ public final class Toolchain {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func inferManifestDirectory() throws -> AbsolutePath {
|
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
|
throw ToolchainError.missingPackageManifest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,15 +183,15 @@ public final class Toolchain {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func inferSourcesPaths() throws -> [AbsolutePath] {
|
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 {
|
guard let path = target.path else {
|
||||||
switch target.type {
|
switch target.type {
|
||||||
case .regular:
|
case .regular:
|
||||||
return RelativePath("Sources").appending(component: target.name).pathString
|
return RelativePath("Sources").appending(component: target.name).pathString
|
||||||
case .test, .system:
|
case .test, .system, .executable, .binary:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,20 +208,20 @@ public final class Toolchain {
|
||||||
public func buildCurrentProject(
|
public func buildCurrentProject(
|
||||||
product: String?,
|
product: String?,
|
||||||
isRelease: Bool
|
isRelease: Bool
|
||||||
) throws -> (builderArguments: [String], mainWasmPath: AbsolutePath, Product) {
|
) throws -> (builderArguments: [String], mainWasmPath: AbsolutePath, ProductDescription) {
|
||||||
guard let product = try inferDevProduct(hint: product)
|
guard let product = try inferDevProduct(hint: product)
|
||||||
else { throw ToolchainError.noExecutableProduct }
|
else { throw ToolchainError.noExecutableProduct }
|
||||||
|
|
||||||
let package = try self.package.get()
|
let manifest = try self.manifest.get()
|
||||||
if let jsKit = package.dependencies?.first(where: { $0.name == "JavaScriptKit" }),
|
if let jsKit = manifest.dependencies.first(where: { $0.name == "JavaScriptKit" }),
|
||||||
!jsKit.requirement.isJavaScriptKitCompatible
|
!jsKit.requirement.isJavaScriptKitCompatible
|
||||||
{
|
{
|
||||||
let version = jsKit.requirement.version
|
let versionDescription = jsKit.requirement.versionDescription
|
||||||
|
|
||||||
terminal.write(
|
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 \
|
carton \(cartonVersion). Please specify a JavaScriptKit dependency on version \
|
||||||
\(compatibleJSKitVersion) in your `Package.swift`.\n
|
\(compatibleJSKitVersion) in your `Package.swift`.\n
|
||||||
|
|
||||||
|
@ -246,9 +260,9 @@ public final class Toolchain {
|
||||||
isRelease: Bool,
|
isRelease: Bool,
|
||||||
_ environment: DestinationEnvironment
|
_ environment: DestinationEnvironment
|
||||||
) throws -> AbsolutePath {
|
) throws -> AbsolutePath {
|
||||||
let package = try self.package.get()
|
let manifest = try self.manifest.get()
|
||||||
let binPath = try inferBinPath(isRelease: isRelease)
|
let binPath = try inferBinPath(isRelease: isRelease)
|
||||||
let testProductName = "\(package.name)PackageTests"
|
let testProductName = "\(manifest.name)PackageTests"
|
||||||
let testBundlePath = binPath.appending(component: "\(testProductName).wasm")
|
let testBundlePath = binPath.appending(component: "\(testProductName).wasm")
|
||||||
terminal.logLookup("- test bundle to run: ", testBundlePath.pathString)
|
terminal.logLookup("- test bundle to run: ", testBundlePath.pathString)
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ extension ToolchainSystem {
|
||||||
var subscriptions = [AnyCancellable]()
|
var subscriptions = [AnyCancellable]()
|
||||||
let request = try HTTPClient.Request.get(url: url)
|
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
|
client.execute(request: request, delegate: delegate).futureResult.whenComplete { _ in
|
||||||
subject.send(completion: .finished)
|
subject.send(completion: .finished)
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ extension ToolchainSystem {
|
||||||
path: path,
|
path: path,
|
||||||
reportHead: {
|
reportHead: {
|
||||||
guard $0.status == .ok,
|
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 {
|
else {
|
||||||
subject.send(completion: .failure(ToolchainError.invalidResponseCode($0.status.code)))
|
subject.send(completion: .failure(ToolchainError.invalidResponseCode($0.status.code)))
|
||||||
return
|
return
|
||||||
|
|
|
@ -104,8 +104,8 @@ public class ToolchainSystem {
|
||||||
) throws -> String {
|
) throws -> String {
|
||||||
if let versionSpec = versionSpec {
|
if let versionSpec = versionSpec {
|
||||||
if let url = URL(string: versionSpec),
|
if let url = URL(string: versionSpec),
|
||||||
let filename = url.pathComponents.last,
|
let filename = url.pathComponents.last,
|
||||||
let match = versionRegEx.matchGroups(in: filename).first?.first
|
let match = versionRegEx.matchGroups(in: filename).first?.first
|
||||||
{
|
{
|
||||||
terminal.logLookup("Inferred swift version: ", match)
|
terminal.logLookup("Inferred swift version: ", match)
|
||||||
return match
|
return match
|
||||||
|
@ -152,7 +152,7 @@ public class ToolchainSystem {
|
||||||
terminal.logLookup("Fetching release assets from ", releaseURL)
|
terminal.logLookup("Fetching release assets from ", releaseURL)
|
||||||
let decoder = JSONDecoder()
|
let decoder = JSONDecoder()
|
||||||
let request = try HTTPClient.Request.get(url: releaseURL)
|
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
|
client.execute(request: request).flatMapResult { response -> Result<Release, Error> in
|
||||||
guard (200..<300).contains(response.status.code), let body = response.body else {
|
guard (200..<300).contains(response.status.code), let body = response.body else {
|
||||||
return .failure(ToolchainError.invalidResponse(
|
return .failure(ToolchainError.invalidResponse(
|
||||||
|
@ -267,10 +267,10 @@ public class ToolchainSystem {
|
||||||
|
|
||||||
public func fetchLocalSwiftVersion() throws -> String? {
|
public func fetchLocalSwiftVersion() throws -> String? {
|
||||||
guard fileSystem.isFile(swiftVersionPath),
|
guard fileSystem.isFile(swiftVersionPath),
|
||||||
let version = try fileSystem.readFileContents(swiftVersionPath)
|
let version = try fileSystem.readFileContents(swiftVersionPath)
|
||||||
.validDescription?
|
.validDescription?
|
||||||
// get the first line of the file
|
// get the first line of the file
|
||||||
.components(separatedBy: CharacterSet.newlines).first
|
.components(separatedBy: CharacterSet.newlines).first
|
||||||
else { return nil }
|
else { return nil }
|
||||||
|
|
||||||
return version
|
return version
|
||||||
|
|
|
@ -23,7 +23,7 @@ struct Formula: ParsableCommand {
|
||||||
let archiveURL = "https://github.com/swiftwasm/carton/archive/\(version).tar.gz"
|
let archiveURL = "https://github.com/swiftwasm/carton/archive/\(version).tar.gz"
|
||||||
|
|
||||||
let client = HTTPClient(eventLoopGroupProvider: .createNew)
|
let client = HTTPClient(eventLoopGroupProvider: .createNew)
|
||||||
let response: HTTPClient.Response = try await {
|
let response: HTTPClient.Response = try tsc_await {
|
||||||
client.get(url: archiveURL).whenComplete($0)
|
client.get(url: archiveURL).whenComplete($0)
|
||||||
}
|
}
|
||||||
try client.syncShutdown()
|
try client.syncShutdown()
|
||||||
|
|
Loading…
Reference in New Issue