Implement resources copying in `carton bundle` (#109)
* Define `resourcesPath` on `SwiftToolchain.Package` * Implement resources copying in `carton bundle` * Remove redundant newline in log output
This commit is contained in:
parent
b2aa6fd62c
commit
1e49463d64
|
@ -21,9 +21,14 @@ private extension String {
|
|||
}
|
||||
|
||||
public extension TerminalController {
|
||||
func logLookup<T: CustomStringConvertible>(_ description: String, _ target: T) {
|
||||
func logLookup<T>(_ description: String, _ target: T, newline: Bool = false)
|
||||
where T: CustomStringConvertible
|
||||
{
|
||||
write(description)
|
||||
write("\(target)\n", inColor: .cyan, bold: true)
|
||||
if newline {
|
||||
write("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func clearWindow() {
|
||||
|
|
|
@ -49,6 +49,10 @@ public struct Package: Codable {
|
|||
|
||||
self = try JSONDecoder().decode(Package.self, from: output)
|
||||
}
|
||||
|
||||
public func resourcesPath(for target: Target) -> String {
|
||||
"\(name)_\(target.name).resources"
|
||||
}
|
||||
}
|
||||
|
||||
struct ProductType: Codable {
|
||||
|
|
|
@ -92,10 +92,11 @@ public final class Toolchain {
|
|||
package = Result { try Package(with: swiftPath, terminal) }
|
||||
}
|
||||
|
||||
private func inferBinPath() throws -> AbsolutePath {
|
||||
private func inferBinPath(isRelease: Bool) throws -> AbsolutePath {
|
||||
guard
|
||||
let output = try processStringOutput([
|
||||
swiftPath.pathString, "build", "--triple", "wasm32-unknown-wasi", "--show-bin-path",
|
||||
swiftPath.pathString, "build", "-c", isRelease ? "release" : "debug",
|
||||
"--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") }
|
||||
|
@ -210,7 +211,7 @@ public final class Toolchain {
|
|||
)
|
||||
}
|
||||
|
||||
let binPath = try inferBinPath()
|
||||
let binPath = try inferBinPath(isRelease: isRelease)
|
||||
let mainWasmPath = binPath.appending(component: product)
|
||||
terminal.logLookup("- development binary to serve: ", mainWasmPath.pathString)
|
||||
|
||||
|
@ -238,7 +239,7 @@ public final class Toolchain {
|
|||
/// Returns an absolute path to the resulting test bundle
|
||||
public func buildTestBundle(isRelease: Bool) throws -> AbsolutePath {
|
||||
let package = try self.package.get()
|
||||
let binPath = try inferBinPath()
|
||||
let binPath = try inferBinPath(isRelease: isRelease)
|
||||
let testBundlePath = binPath.appending(component: "\(package.name)PackageTests.xctest")
|
||||
terminal.logLookup("- test bundle to run: ", testBundlePath.pathString)
|
||||
|
||||
|
|
|
@ -55,32 +55,53 @@ struct Bundle: ParsableCommand {
|
|||
)
|
||||
try terminal.logLookup(
|
||||
"Right after building the main binary size is ",
|
||||
localFileSystem.humanReadableFileSize(mainWasmPath)
|
||||
localFileSystem.humanReadableFileSize(mainWasmPath),
|
||||
newline: true
|
||||
)
|
||||
|
||||
try ProcessRunner(["wasm-strip", mainWasmPath.pathString], terminal).waitUntilFinished()
|
||||
try terminal.logLookup(
|
||||
"After applying `wasm-strip` the main binary size is ",
|
||||
localFileSystem.humanReadableFileSize(mainWasmPath)
|
||||
localFileSystem.humanReadableFileSize(mainWasmPath),
|
||||
newline: true
|
||||
)
|
||||
|
||||
let bundleDir = AbsolutePath(localFileSystem.currentWorkingDirectory!, "Bundle")
|
||||
try localFileSystem.removeFileTree(bundleDir)
|
||||
try localFileSystem.createDirectory(bundleDir)
|
||||
let optimizedPath = AbsolutePath(bundleDir, "main.wasm")
|
||||
let bundleDirectory = AbsolutePath(localFileSystem.currentWorkingDirectory!, "Bundle")
|
||||
try localFileSystem.removeFileTree(bundleDirectory)
|
||||
try localFileSystem.createDirectory(bundleDirectory)
|
||||
let optimizedPath = AbsolutePath(bundleDirectory, "main.wasm")
|
||||
try ProcessRunner(
|
||||
["wasm-opt", "-Os", mainWasmPath.pathString, "-o", optimizedPath.pathString],
|
||||
terminal
|
||||
).waitUntilFinished()
|
||||
try terminal.logLookup(
|
||||
"After applying `wasm-opt` the main binary size is ",
|
||||
localFileSystem.humanReadableFileSize(optimizedPath)
|
||||
localFileSystem.humanReadableFileSize(optimizedPath),
|
||||
newline: true
|
||||
)
|
||||
|
||||
try copyToBundle(
|
||||
terminal: terminal,
|
||||
optimizedPath: optimizedPath,
|
||||
buildDirectory: mainWasmPath.parentDirectory,
|
||||
bundleDirectory: bundleDirectory,
|
||||
toolchain: toolchain
|
||||
)
|
||||
|
||||
terminal.write("Bundle generation finished successfully\n", inColor: .green, bold: true)
|
||||
}
|
||||
|
||||
func copyToBundle(
|
||||
terminal: TerminalController,
|
||||
optimizedPath: AbsolutePath,
|
||||
buildDirectory: AbsolutePath,
|
||||
bundleDirectory: AbsolutePath,
|
||||
toolchain: Toolchain
|
||||
) 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)
|
||||
let mainModuleName = "\(optimizedHash).wasm"
|
||||
let mainModulePath = AbsolutePath(bundleDir, mainModuleName)
|
||||
let mainModulePath = AbsolutePath(bundleDirectory, mainModuleName)
|
||||
try localFileSystem.move(from: optimizedPath, to: mainModulePath)
|
||||
|
||||
// Copy the bundle entrypoint, point to the binary, and give it a cachebuster name.
|
||||
|
@ -95,18 +116,27 @@ struct Bundle: ParsableCommand {
|
|||
)
|
||||
let entrypointName = "\(entrypoint.hexSHA256.prefix(16)).js"
|
||||
try localFileSystem.writeFileContents(
|
||||
AbsolutePath(bundleDir, entrypointName),
|
||||
AbsolutePath(bundleDirectory, entrypointName),
|
||||
bytes: entrypoint
|
||||
)
|
||||
|
||||
try localFileSystem.writeFileContents(
|
||||
AbsolutePath(bundleDir, "index.html"),
|
||||
AbsolutePath(bundleDirectory, "index.html"),
|
||||
bytes: ByteString(encodingAsUTF8: HTML.indexPage(
|
||||
customContent: HTML.readCustomIndexPage(at: customIndexPage, on: localFileSystem),
|
||||
entrypointName: entrypointName
|
||||
))
|
||||
)
|
||||
|
||||
terminal.write("\nBundle generation finished successfully\n", inColor: .green, bold: true)
|
||||
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 resourcesPath = buildDirectory.appending(component: targetPath)
|
||||
let targetDirectory = bundleDirectory.appending(component: targetPath)
|
||||
|
||||
guard localFileSystem.exists(resourcesPath) else { continue }
|
||||
terminal.logLookup("Copying resources to ", targetDirectory)
|
||||
try localFileSystem.copy(from: resourcesPath, to: targetDirectory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ extension Application {
|
|||
|
||||
let buildDirectory = mainWasmPath.parentDirectory
|
||||
for target in package.targets where target.type == .regular && !target.resources.isEmpty {
|
||||
let resourcesPath = "\(package.name)_\(target.name).resources"
|
||||
let resourcesPath = package.resourcesPath(for: target)
|
||||
get(.constant(resourcesPath), "**") {
|
||||
$0.eventLoop.makeSucceededFuture($0.fileio.streamFile(at: AbsolutePath(
|
||||
buildDirectory.appending(component: resourcesPath),
|
||||
|
|
Loading…
Reference in New Issue