Detect swift version, serve /main.wasm

This commit is contained in:
Max Desiatov 2020-06-04 21:31:32 +01:00
parent 12bc3af1a7
commit 74d42393bb
No known key found for this signature in database
GPG Key ID: FE08EBF9CF58CBA2
17 changed files with 277 additions and 60 deletions

View File

@ -1,5 +1,6 @@
{
"editor.tabSize": 2,
"editor.formatOnSave": true,
"editor.formatOnType": true
"editor.formatOnType": true,
"licenser.author": "Carton contributors"
}

2
.vscode/tasks.json vendored
View File

@ -6,7 +6,7 @@
{
"label": "build and run",
"type": "shell",
"command": "swift build && .build/debug/carton dev"
"command": "swift build && cd TestApp && ../.build/debug/carton dev --target TestApp"
}
]
}

View File

@ -60,8 +60,8 @@
"repositoryURL": "https://github.com/apple/swift-argument-parser",
"state": {
"branch": null,
"revision": "9f04d1ff1afbccd02279338a2c91e5f27c45e93a",
"version": "0.0.5"
"revision": "3d79b2b5a2e5af52c14e462044702ea7728f5770",
"version": "0.1.0"
}
},
{

View File

@ -7,7 +7,7 @@ let package = Package(
name: "carton",
platforms: [.macOS(.v10_15)],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser", .upToNextMinor(from: "0.0.5")),
.package(url: "https://github.com/apple/swift-argument-parser", .upToNextMinor(from: "0.1.0")),
.package(url: "https://github.com/vapor/vapor.git", from: "4.5.0"),
.package(url: "https://github.com/apple/swift-tools-support-core.git", .upToNextMinor(from: "0.1.3")),
.package(url: "https://github.com/swift-server/async-http-client.git", from: "1.1.1"),

View File

@ -1,9 +1,23 @@
// 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 ArgumentParser
struct Carton: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "📦 Watcher, bundler, and test runner for your SwiftWasm apps.",
subcommands: [Dev.self, Test.self, Prod.self],
subcommands: [Dev.self, Test.self, Dist.self],
defaultSubcommand: Dev.self
)
}

View File

@ -1,49 +1,79 @@
// 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 ArgumentParser
import Foundation
import ShellOut
struct ProductType: Codable {
let executable: String?
let library: [String]
}
/**
Simple Product structure from package dump
*/
struct Product: Codable {
let name: String
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
}
struct Target: Codable {
let name: String
let type: TargetType
}
struct Dev: ParsableCommand {
@Option(help: "Specify name of an executable target in development.")
var target: String?
static var configuration = CommandConfiguration(
abstract: "Watch the current directory, host the app, rebuild on change."
)
func run() throws {
let output = try shellOut(to: "swift", arguments: ["package", "dump-package"])
let swiftPath: String
if
let data = FileManager.default.contents(atPath: ".swift-version"),
// get the first line of the file
let swiftVersion = String(data: data, encoding: .utf8)?.components(
separatedBy: CharacterSet.newlines
).first {
swiftPath = FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent(".swiftenv")
.appendingPathComponent("versions")
.appendingPathComponent(swiftVersion)
.appendingPathComponent("usr")
.appendingPathComponent("bin")
.appendingPathComponent("swift")
.path
} else {
swiftPath = "swift"
}
let output = try shellOut(to: swiftPath, arguments: ["package", "dump-package"])
guard let data = output.data(using: .utf8)
else { fatalError("failed to decode `swift package dump-package` output") }
try print(JSONDecoder().decode(Package.self, from: data))
try Server.run()
let package = try JSONDecoder().decode(Package.self, from: data)
var candidateNames = package.targets.filter { $0.type == .regular }.map(\.name)
if let target = target {
candidateNames = candidateNames.filter { $0 == target }
guard candidateNames.count == 1 else {
fatalError("""
failed to disambiguate the development target,
make sure `\(target)` is present in Package.swift
""")
}
}
guard candidateNames.count == 1 else {
fatalError("""
failed to disambiguate the development target,
pass one of \(candidateNames) to the --target flag
""")
}
let path = try shellOut(
to: swiftPath,
arguments: ["build", "--triple", "wasm32-unknown-wasi", "--show-bin-path"]
)
let mainWasmURL = URL(fileURLWithPath: path).appendingPathComponent(candidateNames[0])
try Server.run(mainWasmPath: mainWasmURL.path)
}
}

21
Sources/carton/Dist.swift Normal file
View File

@ -0,0 +1,21 @@
// 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 ArgumentParser
struct Dist: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Produce a distribution bundle ready for deployment."
)
}

View File

@ -0,0 +1,45 @@
// 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.
struct ProductType: Codable {
let executable: String?
let library: [String]
}
/**
Simple Product structure from package dump
*/
struct Product: Codable {
let name: String
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
}
struct Target: Codable {
let name: String
let type: TargetType
}

View File

@ -1,7 +0,0 @@
import ArgumentParser
struct Prod: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Produce a production app bundle ready for deployment."
)
}

View File

@ -1,3 +1,17 @@
// 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 HypertextLiteral
import Vapor

View File

@ -1,12 +1,27 @@
// 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 Vapor
struct Server {
static func run() throws {
static func run(mainWasmPath: String) throws {
var env = Environment.development
try LoggingSystem.bootstrap(from: &env)
let app = Application(env)
defer { app.shutdown() }
try configure(app)
try configure(app, mainWasmPath: mainWasmPath)
try app.run()
}
}

View File

@ -1,10 +1,28 @@
// 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 Foundation
import Vapor
// configures your application
public func configure(_ app: Application) throws {
let directory = app.directory.publicDirectory
public func configure(_ app: Application, mainWasmPath: String) throws {
let directory = FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent(".carton")
.appendingPathComponent("static")
.path
app.middleware.use(FileMiddleware(publicDirectory: directory))
// register routes
try routes(app)
try routes(app, mainWasmPath: mainWasmPath)
}

View File

@ -1,14 +1,28 @@
// 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 HypertextLiteral
import Vapor
func routes(_ app: Application) throws {
func routes(_ app: Application, mainWasmPath: String) throws {
app.get { _ -> HTML in
#"""
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="index.js"></script>
<script type="text/javascript" src="index.js"></script>
</head>
<body>
<h1>Hello!</h1>
@ -16,4 +30,9 @@ func routes(_ app: Application) throws {
</html>
"""#
}
app.get("main.wasm") { (request: Request) in
// stream the file
request.eventLoop.makeSucceededFuture(request.fileio.streamFile(at: mainWasmPath))
}
}

View File

@ -1,3 +1,17 @@
// 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 ArgumentParser
struct Test: ParsableCommand {

View File

@ -1 +1,15 @@
// 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.
Carton.main()

View File

@ -1,13 +1,10 @@
// swift-tools-version:5.3
// swift-tools-version:5.2
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "CartonTestApp",
products: [
.executable(name: "TestApp", targets: ["TestApp"]),
],
dependencies: [
.package(url: "https://github.com/kateinoigakukun/JavaScriptKit", .revision("b245ad5")),
],

View File

@ -1,3 +1,25 @@
// 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 JavaScriptKit
print("Hello world!")
let alert = JSObjectRef.global.alert.function!
let document = JSObjectRef.global.document.object!
let divElement = document.createElement!("div").object!
divElement.innerText = "Hello, world"
let body = document.body.object!
_ = body.appendChild!(divElement)
print("hello, world")