Implement basic test command

This commit is contained in:
Max Desiatov 2020-06-13 22:51:53 +01:00
parent 3a0c68ed88
commit 0695689d3d
No known key found for this signature in database
GPG Key ID: FE08EBF9CF58CBA2
10 changed files with 82 additions and 56 deletions

View File

@ -3,10 +3,10 @@
name: Danger
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
# events but only for the main branch
on:
pull_request:
branches: [master]
branches: [main]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:

View File

@ -2,9 +2,9 @@ name: Build and test
on:
push:
branches: [master]
branches: [main]
pull_request:
branches: [master]
branches: [main]
jobs:
macos_build:

View File

@ -22,12 +22,12 @@ It is currently work in progress, so watch the repository for imminent updates!
- macOS 10.15 and Xcode 11.4 or later for macOS users.
- [Swift 5.2 or later](https://swift.org/download/) for Linux users.
On either platform you should install cross-compilation SwiftWasm toolchain via
[`swiftenv`](https://github.com/kylef/swiftenv) as described in [the SwiftWasm
Book](https://swiftwasm.github.io/swiftwasm-book/GettingStarted.html), in addition to the
On either platform you should install cross-compilation SwiftWasm toolchain via
[`swiftenv`](https://github.com/kylef/swiftenv) as described in [the SwiftWasm
Book](https://swiftwasm.github.io/swiftwasm-book/GettingStarted.html), in addition to the
host Swift 5.2 toolchain mentioned above.
In the future, manual installation of SwiftWasm won't be required, please see issue
In the future, manual installation of SwiftWasm won't be required, please see issue
[#3](https://github.com/swiftwasm/carton/issues/3) for more details.
## Installation
@ -83,6 +83,6 @@ PRs before merging.
### Code of Conduct
This project adheres to the [Contributor Covenant Code of
Conduct](https://github.com/swiftwasm/carton/blob/master/CODE_OF_CONDUCT.md).
Conduct](https://github.com/swiftwasm/carton/blob/main/CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report
unacceptable behavior to conduct@carton.dev.

View File

@ -17,11 +17,11 @@ import Foundation
import OpenCombine
import TSCBasic
struct BuilderError: Error, CustomStringConvertible {
struct ProcessRunnerError: Error, CustomStringConvertible {
let description: String
}
final class Builder {
final class ProcessRunner {
let publisher: AnyPublisher<String, Error>
private var subscription: AnyCancellable?
@ -32,19 +32,6 @@ final class Builder {
.handleEvents(receiveOutput: {
terminal.clearLine()
terminal.write(String($0.dropLast()))
}, receiveCompletion: {
switch $0 {
case .finished:
terminal.write("\nBuild completed successfully\n", inColor: .green, bold: false)
case let .failure(error):
let errorString = String(describing: error)
if errorString.isEmpty {
terminal.write("Build failed, check the build process output above.\n", inColor: .red)
} else {
terminal.write("Build failed and produced following output: \n", inColor: .red)
print(error)
}
}
})
.eraseToAnyPublisher()
@ -79,7 +66,7 @@ final class Builder {
subject.send(completion: .failure(error))
default:
let errorDescription = String(data: Data(stderrBuffer), encoding: .utf8) ?? ""
return subject.send(completion: .failure(BuilderError(description: errorDescription)))
return subject.send(completion: .failure(ProcessRunnerError(description: errorDescription)))
}
}
}

View File

@ -17,16 +17,11 @@ import Foundation
import OpenCombine
import TSCBasic
func processDataOutput(_ arguments: [String]) throws -> Data {
func processDataOutput(_ arguments: [String]) throws -> [UInt8] {
let process = Process(arguments: arguments, startNewProcessGroup: false)
try process.launch()
let result = try process.waitUntilExit()
return try Data(result.output.get())
}
func processStringsOutput(_ arguments: [String]) throws -> [String] {
try String(data: processDataOutput(arguments), encoding: .utf8)?
.components(separatedBy: CharacterSet.newlines) ?? []
return try result.output.get()
}
private let dependency = Dependency(
@ -51,10 +46,9 @@ struct Dev: ParsableCommand {
try dependency.check(on: localFileSystem, terminal)
let swiftPath = try localFileSystem.inferSwiftPath(terminal)
let output = try processDataOutput([swiftPath, "package", "dump-package"])
let package = try JSONDecoder().decode(Package.self, from: output)
var candidateNames = package.targets.filter { $0.type == .regular }.map(\.name)
var candidateNames = try Package(with: swiftPath).targets
.filter { $0.type == .regular }
.map(\.name)
if let target = target {
candidateNames = candidateNames.filter { $0 == target }
@ -74,18 +68,15 @@ struct Dev: ParsableCommand {
}
terminal.logLookup("- development target: ", candidateNames[0])
guard let binPath = try processStringsOutput([
swiftPath, "build", "--triple", "wasm32-unknown-wasi", "--show-bin-path",
]).first else { fatalError("failed to decode UTF8 output of the `swift build` invocation") }
let mainWasmPath = AbsolutePath(binPath).appending(component: candidateNames[0])
let binPath = try localFileSystem.inferBinPath(swiftPath: swiftPath)
let mainWasmPath = binPath.appending(component: candidateNames[0])
terminal.logLookup("- development binary to serve: ", mainWasmPath.pathString)
terminal.preWatcherBuildNotice()
let builderArguments = [swiftPath, "build", "--triple", "wasm32-unknown-wasi"]
try Builder(builderArguments, terminal).waitUntilFinished()
try ProcessRunner(builderArguments, terminal).waitUntilFinished()
guard localFileSystem.exists(mainWasmPath) else {
return terminal.write(

View File

@ -13,6 +13,7 @@
// limitations under the License.
import ArgumentParser
import OpenCombine
import TSCBasic
private let dependency = Dependency(
@ -26,6 +27,16 @@ struct Test: ParsableCommand {
func run() throws {
guard let terminal = TerminalController(stream: stdoutStream)
else { fatalError("failed to create an instance of `TerminalController`") }
try dependency.check(on: localFileSystem, terminal)
// try dependency.check(on: localFileSystem, terminal)
let swiftPath = try localFileSystem.inferSwiftPath(terminal)
let package = try Package(with: swiftPath)
let binPath = try localFileSystem.inferBinPath(swiftPath: swiftPath)
let testBundlePath = binPath.appending(component: "\(package.name)PackageTests.xctest")
terminal.logLookup("- test bundle: ", testBundlePath)
let output = try processStringOutput(["wasmer", testBundlePath.pathString])!
print("output is: \n\(output)")
}
}

View File

@ -15,6 +15,10 @@
import Foundation
import TSCBasic
func processStringOutput(_ arguments: [String]) throws -> String? {
try ByteString(processDataOutput(arguments)).validDescription
}
extension FileSystem {
func traverseRecursively(_ root: AbsolutePath) throws -> [AbsolutePath] {
precondition(isDirectory(root))
@ -54,4 +58,15 @@ extension FileSystem {
return swiftPath
}
func inferBinPath(swiftPath: String) throws -> AbsolutePath {
guard
let output = try processStringOutput([
swiftPath, "build", "--triple", "wasm32-unknown-wasi", "--show-bin-path",
])?.components(separatedBy: CharacterSet.newlines),
let binPath = output.first
else { fatalError("failed to decode UTF8 output of the `swift build` invocation") }
return AbsolutePath(binPath)
}
}

View File

@ -12,6 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
/**
Simple Package structure from package dump
*/
struct Package: Codable {
let name: String
let products: [Product]
let targets: [Target]
init(with swiftPath: String) throws {
let output = try Data(processDataOutput([swiftPath, "package", "dump-package"]))
self = try JSONDecoder().decode(Package.self, from: output)
}
}
struct ProductType: Codable {
let executable: String?
let library: [String]
@ -25,15 +42,6 @@ struct Product: Codable {
let type: ProductType
}
/**
Simple Package structure from package dump
*/
struct Package: Codable {
let name: String
let products: [Product]
let targets: [Target]
}
enum TargetType: String, Codable {
case regular
case test

View File

@ -31,7 +31,7 @@ final class Server {
private var connections = Set<WebSocket>()
private var subscriptions = [AnyCancellable]()
private let watcher: Watcher
private var builder: Builder?
private var builder: ProcessRunner?
private let app: Application
init(
@ -61,11 +61,25 @@ final class Server {
for change in changes.map(\.pathString) {
terminal.write("- \(change)\n", inColor: .cyan)
}
return Builder(builderArguments, terminal)
return ProcessRunner(builderArguments, terminal)
.publisher
.handleEvents(receiveCompletion: { [weak self] in
guard case .finished = $0 else { return }
self?.connections.forEach { $0.send("reload") }
switch $0 {
case .finished:
terminal.write("\nBuild completed successfully\n", inColor: .green, bold: false)
self?.connections.forEach { $0.send("reload") }
case let .failure(error):
let errorString = String(describing: error)
if errorString.isEmpty {
terminal.write(
"Build failed, check the build process output above.\n",
inColor: .red
)
} else {
terminal.write("Build failed and produced following output: \n", inColor: .red)
print(error)
}
}
})
.catch { _ in Empty().eraseToAnyPublisher() }
.eraseToAnyPublisher()