Skip to content

Commit

Permalink
the swift 6 language mode (#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
kphrx authored Oct 6, 2024
2 parents 3a7906a + 27c6dbb commit 29faec9
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 51 deletions.
9 changes: 3 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,22 @@ jobs:
build:

runs-on: ubuntu-latest
container: swift:${{ matrix.swift-version }}
strategy:
matrix:
swift-version:
- '5.9'
- '5.10'
- '6.0-noble'

steps:
- uses: actions/checkout@v4
- uses: swift-actions/setup-swift@v2
with:
swift-version: ${{ matrix.swift-version }}
- name: Restore dependencies cache
uses: actions/cache@v4
with:
path: |
.build/repositories
.build/checkouts
.build/workspace-state.json
key: ${{ runner.os }}-swiftpm-${{ hashFiles('**/Package.*') }}
key: ${{ runner.os }}-swiftpm-${{ hashFiles('Package.*') }}

- name: Install dependencies
run: swift package resolve
Expand Down
29 changes: 23 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
# ================================
FROM swift:6.0-noble AS build

# Install OS updates and, if needed, sqlite3
# Install OS updates
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
&& apt-get -q update \
&& apt-get -q dist-upgrade -y\
&& apt-get -q dist-upgrade -y \
&& apt-get install -y libjemalloc-dev \
&& rm -rf /var/lib/apt/lists/*

# Set up a build area
Expand All @@ -17,20 +18,27 @@ WORKDIR /build
# as long as your Package.swift/Package.resolved
# files do not change.
COPY ./Package.* ./
RUN swift package resolve
RUN swift package resolve \
$([ -f ./Package.resolved ] && echo "--force-resolved-versions" || true)

# Copy entire repo into container
COPY . .

# Build everything, with optimizations
RUN swift build -c release
# Build everything, with optimizations, with static linking, and using jemalloc
# N.B.: The static version of jemalloc is incompatible with the static Swift runtime.
RUN swift build -c release \
--static-swift-stdlib \
-Xlinker -ljemalloc

# Switch to the staging area
WORKDIR /staging

# Copy main executable to staging area
RUN cp "$(swift build --package-path /build -c release --show-bin-path)/App" ./

# Copy static swift backtracer binary to staging area
RUN cp "/usr/libexec/swift/linux/swift-backtrace-static" ./

# Copy resources bundled by SPM to staging area
RUN find -L "$(swift build --package-path /build -c release --show-bin-path)/" -regex '.*\.resources$' -exec cp -Ra {} ./ \;

Expand All @@ -42,14 +50,20 @@ RUN [ -d /build/Resources ] && { mv /build/Resources ./Resources && chmod -R a-w
# ================================
# Run image
# ================================
FROM swift:6.0-noble-slim
FROM ubuntu:noble

# Make sure all system packages are up to date, and install only essential packages.
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
&& apt-get -q update \
&& apt-get -q dist-upgrade -y \
&& apt-get -q install -y \
libjemalloc2 \
ca-certificates \
tzdata \
# If your app or its dependencies import FoundationNetworking, also install `libcurl4`.
# libcurl4 \
# If your app or its dependencies import FoundationXML, also install `libxml2`.
# libxml2 \
&& rm -r /var/lib/apt/lists/*

# Create a vapor user and group with /app as its home directory
Expand All @@ -61,6 +75,9 @@ WORKDIR /app
# Copy built executable and any staged resources from builder
COPY --from=build --chown=vapor:vapor /staging /app

# Provide configuration needed by the built-in crash reporter and some sensible default behaviors.
ENV SWIFT_BACKTRACE=enable=yes,sanitize=yes,threads=all,images=all,interactive=no,swift-backtrace=./swift-backtrace-static

# Ensure all further commands run as the vapor user
USER vapor:vapor

Expand Down
7 changes: 4 additions & 3 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"originHash" : "3e1d947d03a8598e6628256397b1eda22dfa6246648e1147359e0165e3ec971b",
"pins" : [
{
"identity" : "async-http-client",
Expand Down Expand Up @@ -104,8 +105,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/queues.git",
"state" : {
"revision" : "3dc80954c672effa188d01a15f56bf358c34beac",
"version" : "1.13.0"
"revision" : "d867b5be81c612de5e048eb929784fed8df4affc",
"version" : "1.15.1"
}
},
{
Expand Down Expand Up @@ -316,5 +317,5 @@
}
}
],
"version" : 2
"version" : 3
}
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version: 5.9
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription
Expand All @@ -12,6 +12,7 @@ let package = Package(
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"),
.package(url: "https://github.com/vapor/fluent.git", from: "4.0.0"),
.package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.0.0"),
.package(url: "https://github.com/vapor/queues.git", from: "1.15.0"),
.package(url: "https://github.com/vapor/queues-redis-driver.git", from: "1.0.0"),
.package(url: "https://github.com/vapor/leaf.git", from: "4.0.0"),
],
Expand Down
4 changes: 1 addition & 3 deletions Sources/Jobs/Dispatched/PollingPlcServerExportJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ struct PollingPlcServerExportJob: AsyncJob {
var url: URI = "https://plc.directory/export"
url.query =
if let after = after.map({ date in
let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
return dateFormatter.string(from: date)
return date.formatted(Date.ISO8601FormatStyle(includingFractionalSeconds: true))
}) {
"count=\(count)&after=\(after)"
} else {
Expand Down
6 changes: 3 additions & 3 deletions Sources/Middleware/RouteLoggingMiddleware.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Vapor

class RouteLoggingMiddleware: Middleware {
struct RouteLoggingMiddleware: AsyncMiddleware {
let logLevel: Logger.Level = .info

func respond(to request: Request, chainingTo next: Responder) -> EventLoopFuture<Response> {
func respond(to request: Request, chainingTo next: AsyncResponder) async throws -> Response {
let query =
if let query = request.url.query {
"?\(query.removingPercentEncoding ?? query)"
Expand All @@ -13,6 +13,6 @@ class RouteLoggingMiddleware: Middleware {
request.logger.log(
level: self.logLevel,
"\(request.method) \(request.url.path.removingPercentEncoding ?? request.url.path)\(query)")
return next.respond(to: request)
return try await next.respond(to: request)
}
}
12 changes: 6 additions & 6 deletions Sources/configure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import QueuesRedisDriver
import Vapor

func registerCustomCoder() {
// milliseconds RFC 3339 encoder/decoder
let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
// milliseconds RFC 3339 FormatStyle
let formatStyle = Date.ISO8601FormatStyle(includingFractionalSeconds: true)

let encoder = JSONEncoder.custom(
dates: .custom({ (date, encoder) in
var container = encoder.singleValueContainer()
try container.encode(dateFormatter.string(from: date))
try container.encode(date.formatted(formatStyle))
}))
ContentConfiguration.global.use(encoder: encoder, for: .json)
ContentConfiguration.global.use(encoder: encoder, for: .jsonAPI)
Expand All @@ -20,13 +19,14 @@ func registerCustomCoder() {
dates: .custom({ decoder in
let container = try decoder.singleValueContainer()
let string = try container.decode(String.self)
guard let date = dateFormatter.date(from: string) else {
do {
return try formatStyle.parse(string)
} catch {
throw DecodingError.dataCorrupted(
DecodingError.Context(
codingPath: decoder.codingPath,
debugDescription: "Expected date string to be ISO8601-formatted."))
}
return date
}))
ContentConfiguration.global.use(decoder: decoder, for: .json)
ContentConfiguration.global.use(decoder: decoder, for: .jsonAPI)
Expand Down
42 changes: 19 additions & 23 deletions Sources/entrypoint.swift
Original file line number Diff line number Diff line change
@@ -1,39 +1,35 @@
import Dispatch
import Logging
import NIOCore
import NIOPosix
import Vapor

/// This extension is temporary and can be removed once Vapor gets this support.
extension Vapor.Application {
fileprivate static let baseExecutionQueue = DispatchQueue(label: "vapor.codes.entrypoint")

fileprivate func runFromAsyncMainEntrypoint() async throws {
try await withCheckedThrowingContinuation { continuation in
Vapor.Application.baseExecutionQueue.async { [self] in
do {
try self.run()
continuation.resume()
} catch {
continuation.resume(throwing: error)
}
}
}
}
}

@main
enum Entrypoint {
static func main() async throws {
var env = try Environment.detect()
try LoggingSystem.bootstrap(from: &env)

let app = try await Application.make(env)
defer { app.shutdown() }

try await configure(app)
// This attempts to install NIO as the Swift Concurrency global executor.
// You can enable it if you'd like to reduce the amount of context switching between NIO and Swift Concurrency.
// Note: this has caused issues with some libraries that use `.wait()` and cleanly shutting down.
// If enabled, you should be careful about calling async functions before this point as it can cause assertion failures.
let executorTakeoverSuccess =
NIOSingletons.unsafeTryInstallSingletonPosixEventLoopGroupAsConcurrencyGlobalExecutor()
app.logger.debug(
"Tried to install SwiftNIO's EventLoopGroup as Swift's global concurrency executor",
metadata: ["success": .stringConvertible(executorTakeoverSuccess)])

do {
try await app.runFromAsyncMainEntrypoint()
try await configure(app)
} catch {
exit(1)
app.logger.report(error: error)
try? await app.asyncShutdown()
throw error
}

try await app.execute()
try await app.asyncShutdown()
}
}

0 comments on commit 29faec9

Please sign in to comment.