Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ jobs:
include:
- os: macos-12
swift_version: 5.6
xcode: /Applications/Xcode_13.3.app/Contents/Developer
xcode: /Applications/Xcode_13.4.app/Contents/Developer
- os: macos-11
swift_version: 5.5
xcode: /Applications/Xcode_13.2.1.app/Contents/Developer
- os: ubuntu-20.04
swift_version: 5.5
name: Build on ${{ matrix.os }} with Swift ${{ matrix.swift_version }}
timeout-minutes: 40
runs-on: ${{ matrix.os }}

steps:
Expand Down
4 changes: 2 additions & 2 deletions .swiftformat
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
--ifdef noindent
--stripunusedargs closure-only
--disable andOperator
--swiftversion 5.2
--maxwidth 100
--swiftversion 5.5
--maxwidth 120
29 changes: 19 additions & 10 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ let package = Package(
url: "https://github.com/apple/swift-tools-support-core.git",
.branch("release/5.6")
),
.package(url: "https://github.com/vapor/vapor.git", from: "4.53.0"),
.package(url: "https://github.com/vapor/vapor.git", from: "4.57.1"),
.package(url: "https://github.com/apple/swift-crypto.git", from: "1.1.0"),
.package(url: "https://github.com/JohnSundell/Splash.git", from: "0.16.0"),
.package(
Expand Down
32 changes: 27 additions & 5 deletions Sources/CartonCLI/Commands/TestRunners/NodeTestRunner.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Carton contributors
// Copyright 2022 Carton contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -21,16 +21,39 @@ private enum Constants {
static let entrypoint = Entrypoint(fileName: "testNode.js", sha256: testNodeEntrypointSHA256)
}

/// Test runner for Node.js.
struct NodeTestRunner: TestRunner {
let testFilePath: AbsolutePath
let listTestCases: Bool
let testCases: [String]
let terminal: InteractiveWriter

func run() async throws {
terminal.write("\nRunning the test bundle with NodeJS:\n", inColor: .yellow)
let (_, _, filePath) = Constants.entrypoint.paths(on: localFileSystem)
var nodeArguments = ["node", filePath.pathString, testFilePath.pathString]
terminal.write("\nRunning the test bundle with Node.js:\n", inColor: .yellow)

let (_, _, entrypointPath) = Constants.entrypoint.paths(on: localFileSystem)

// Allow Node.js to resolve modules from resource directories by making them relative to the entrypoint path.
let buildDirectory = testFilePath.parentDirectory
let staticDirectory = entrypointPath.parentDirectory

// Clean up existing symlinks before creating new ones.
for existingSymlink in try localFileSystem.resourcesDirectoryNames(relativeTo: staticDirectory) {
try localFileSystem.removeFileTree(staticDirectory.appending(component: existingSymlink))
}

let resourceDirectories = try localFileSystem.resourcesDirectoryNames(relativeTo: buildDirectory)

// Create new symlink for each resource directory.
for resourcesDirectoryName in resourceDirectories {
try localFileSystem.createSymbolicLink(
staticDirectory.appending(component: resourcesDirectoryName),
pointingAt: buildDirectory.appending(component: resourcesDirectoryName),
relative: false
)
}

var nodeArguments = ["node", entrypointPath.pathString, testFilePath.pathString]
if listTestCases {
nodeArguments.append(contentsOf: ["--", "-l"])
} else if !testCases.isEmpty {
Expand All @@ -39,5 +62,4 @@ struct NodeTestRunner: TestRunner {
}
try await Process.run(nodeArguments, terminal)
}

}
6 changes: 6 additions & 0 deletions Sources/CartonHelpers/Process.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,18 @@ public extension TSCBasic.Process {
// swiftlint:disable:next function_body_length
static func run(
_ arguments: [String],
environment: [String: String] = [:],
loadingMessage: String = "Running...",
parser: ProcessOutputParser? = nil,
_ terminal: InteractiveWriter
) async throws {
terminal.clearLine()
terminal.write("\(loadingMessage)\n", inColor: .yellow)

if !environment.isEmpty {
terminal.write(environment.map { "\($0)=\($1)" }.joined(separator: " ") + " ")
}

let processName = arguments[0].first == "/" ?
AbsolutePath(arguments[0]).basename : arguments[0]

Expand All @@ -98,6 +103,7 @@ public extension TSCBasic.Process {

let process = Process(
arguments: arguments,
environment: ProcessEnv.vars.merging(environment) { _, new in new },
outputRedirection: .stream(stdout: stdout, stderr: stderr),
verbose: true,
startNewProcessGroup: true
Expand Down
28 changes: 14 additions & 14 deletions Sources/CartonKit/Server/Application.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,27 @@ extension Application {

get("main.wasm") {
// stream the file
$0.eventLoop
.makeSucceededFuture($0.fileio.streamFile(at: configuration.mainWasmPath.pathString))
$0.fileio.streamFile(at: configuration.mainWasmPath.pathString)
}

// Serve resources for all targets at their respective paths.
let buildDirectory = configuration.mainWasmPath.parentDirectory

for directoryName in try localFileSystem.resourcesDirectoryNames(relativeTo: buildDirectory) {
get(.constant(directoryName), "**") {
$0.eventLoop.makeSucceededFuture($0.fileio.streamFile(at: AbsolutePath(
buildDirectory.appending(component: directoryName),
$0.parameters.getCatchall().joined(separator: "/")
).pathString))
func requestHandler(_ directoryName: String) -> ((Request) -> Response) {
{ (request: Request) -> Response in
request.fileio.streamFile(
at: AbsolutePath(
buildDirectory.appending(component: directoryName),
request.parameters.getCatchall().joined(separator: "/")
).pathString
)
}
}

for directoryName in try localFileSystem.resourcesDirectoryNames(relativeTo: buildDirectory) {
get(.constant(directoryName), "**", use: requestHandler(directoryName))
}

let inferredMainTarget = configuration.manifest.targets.first {
configuration.product?.targets.contains($0.name) == true
}
Expand All @@ -84,11 +89,6 @@ extension Application {
guard let mainTarget = inferredMainTarget else { return }

let resourcesPath = configuration.manifest.resourcesPath(for: mainTarget)
get("**") {
$0.eventLoop.makeSucceededFuture($0.fileio.streamFile(at: AbsolutePath(
buildDirectory.appending(component: resourcesPath),
$0.parameters.getCatchall().joined(separator: "/")
).pathString))
}
get("**", use: requestHandler(resourcesPath))
}
}
2 changes: 1 addition & 1 deletion Sources/CartonKit/Server/HTML.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ extension HTML: ResponseEncodable {
}

public static func indexPage(customContent: String?, entrypointName: String) -> String {
let scriptTag = #"<script type="text/javascript" src="\#(entrypointName)"></script>"#
let scriptTag = #"<script type="module" src="\#(entrypointName)"></script>"#
if let customContent = customContent {
return customContent.replacingOccurrences(
of: "</head>",
Expand Down
2 changes: 1 addition & 1 deletion Sources/CartonKit/Server/Server.swift
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ public actor Server {
/// Blocking function that starts the HTTP server.
public nonisolated func run() async throws {
// Explicitly hop to another thread to avoid blocking the thread that is running the actor executor
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<(), Error>) in
Thread {
Task {
do {
Expand Down
20 changes: 9 additions & 11 deletions Sources/CartonKit/Server/StaticArchive.swift

Large diffs are not rendered by default.

17 changes: 9 additions & 8 deletions Sources/SwiftToolchain/Toolchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import TSCBasic
import TSCUtility
import WasmTransformer

public let compatibleJSKitVersion = Version(0, 14, 0)
public let compatibleJSKitVersion = Version(0, 15, 0)

enum ToolchainError: Error, CustomStringConvertible {
case directoryDoesNotExist(AbsolutePath)
Expand Down Expand Up @@ -86,10 +86,10 @@ extension PackageDependency {
default: break
}
if let exactVersion = exactVersion {
return exactVersion == compatibleJSKitVersion
return exactVersion >= compatibleJSKitVersion
}
if let versionRange = versionRange {
return versionRange.upperBound >= compatibleJSKitVersion
return versionRange.lowerBound >= compatibleJSKitVersion
}
return false
}
Expand Down Expand Up @@ -127,7 +127,8 @@ public final class Toolchain {
self.terminal = terminal
if let workingDirectory = fileSystem.currentWorkingDirectory {
let swiftc = swiftPath.parentDirectory.appending(component: "swiftc")
manifest = await Result { try await Manifest.from(path: workingDirectory, swiftc: swiftc, fileSystem: fileSystem, terminal: terminal)
manifest = await Result {
try await Manifest.from(path: workingDirectory, swiftc: swiftc, fileSystem: fileSystem, terminal: terminal)
}
} else {
manifest = .failure(ToolchainError.noWorkingDirectory)
Expand All @@ -147,7 +148,7 @@ public final class Toolchain {
}

private func inferDevProduct(hint: String?) throws -> ProductDescription? {
let manifest = try self.manifest.get()
let manifest = try manifest.get()

var candidateProducts = manifest.products
.filter { $0.type == .executable }
Expand Down Expand Up @@ -201,7 +202,7 @@ public final class Toolchain {
}

public func inferSourcesPaths() throws -> [AbsolutePath] {
let manifest = try self.manifest.get()
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Change applied by the formatter.

let manifest = try manifest.get()

let targetPaths = manifest.targets.compactMap { target -> String? in

Expand All @@ -224,7 +225,7 @@ public final class Toolchain {
}

private func emitJSKitWarningIfNeeded() throws {
let manifest = try self.manifest.get()
let manifest = try manifest.get()
guard let jsKit = manifest.dependencies.first(where: {
$0.nameForTargetDependencyResolutionOnly == "JavaScriptKit"
}) else {
Expand Down Expand Up @@ -305,7 +306,7 @@ public final class Toolchain {
public func buildTestBundle(
flavor: BuildFlavor
) async throws -> AbsolutePath {
let manifest = try self.manifest.get()
let manifest = try manifest.get()
let binPath = try inferBinPath(isRelease: flavor.isRelease)
let testProductName = "\(manifest.displayName)PackageTests"
let testBundlePath = binPath.appending(component: "\(testProductName).wasm")
Expand Down
42 changes: 29 additions & 13 deletions Sources/carton-release/HashArchive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,34 @@ struct HashArchive: AsyncParsableCommand {
)

try localFileSystem.createDirectory(dotFilesStaticPath, recursive: true)
let hashes = try await ["dev", "bundle", "test", "testNode"].asyncMap { entrypoint -> (String, String) in
try await Process.run(["npm", "run", entrypoint], terminal)
let entrypointPath = AbsolutePath(staticPath, "\(entrypoint).js")
let dotFilesEntrypointPath = dotFilesStaticPath.appending(component: "\(entrypoint).js")
try localFileSystem.removeFileTree(dotFilesEntrypointPath)
try localFileSystem.copy(from: entrypointPath, to: dotFilesEntrypointPath)

return (entrypoint, try SHA256().hash(localFileSystem.readFileContents(entrypointPath))
.hexadecimalRepresentation.uppercased())
}
let hashes = try await (["dev", "bundle", "test", "testNode"])
.asyncMap { entrypoint -> (String, String) in
let filename = "\(entrypoint).js"
var arguments = [
"npx", "esbuild", "--bundle", "entrypoint/\(filename)", "--outfile=static/\(filename)",
]

if entrypoint == "testNode" {
arguments.append(contentsOf: [
"--format=cjs", "--platform=node",
"--external:./JavaScriptKit_JavaScriptKit.resources/Runtime/index.js",
])
} else {
arguments.append(contentsOf: [
"--format=esm",
"--external:./JavaScriptKit_JavaScriptKit.resources/Runtime/index.mjs",
])
}

try await Process.run(arguments, terminal)
let entrypointPath = AbsolutePath(staticPath, filename)
let dotFilesEntrypointPath = dotFilesStaticPath.appending(component: filename)
try localFileSystem.removeFileTree(dotFilesEntrypointPath)
try localFileSystem.copy(from: entrypointPath, to: dotFilesEntrypointPath)

return (entrypoint, try SHA256().hash(localFileSystem.readFileContents(entrypointPath))
.hexadecimalRepresentation.uppercased())
}

try localFileSystem.writeFileContents(
staticPath.appending(component: "so_sanitizer.wasm"),
Expand Down Expand Up @@ -83,10 +101,8 @@ struct HashArchive: AsyncParsableCommand {
public let \($0)EntrypointSHA256 = ByteString([
\(arrayString(from: $1))
])


"""
}.joined())
}.joined(separator: "\n\n"))

public let staticArchiveContents = "\(staticArchiveContents.withData { $0.base64EncodedString() })"
"""
Expand Down
Loading