diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..19751ff --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.build/ +.swiftpm/ + diff --git a/Sources/ApiController/Live.swift b/Sources/ApiController/Live.swift index 4ec93e4..5add1ff 100644 --- a/Sources/ApiController/Live.swift +++ b/Sources/ApiController/Live.swift @@ -14,7 +14,6 @@ extension SiteRoute.Api { return try await route.respond(logger: logger) case .componentLoss(let route): return try await route.respond(logger: logger) - } } } diff --git a/Sources/App/Middleware/DependenciesMiddleware.swift b/Sources/App/Middleware/DependenciesMiddleware.swift index 466b5b1..8c6665b 100644 --- a/Sources/App/Middleware/DependenciesMiddleware.swift +++ b/Sources/App/Middleware/DependenciesMiddleware.swift @@ -17,7 +17,7 @@ struct DependenciesMiddleware: AsyncMiddleware { init( database: DatabaseClient, apiController: ApiController = .liveValue, - viewController: ViewController = .testValue + viewController: ViewController = .liveValue ) { self.values = withEscapedDependencies { $0 } self.apiController = apiController diff --git a/Sources/App/configure.swift b/Sources/App/configure.swift index 9a93f42..71fc6ac 100644 --- a/Sources/App/configure.swift +++ b/Sources/App/configure.swift @@ -21,7 +21,7 @@ public func configure( addMiddleware(to: app, database: databaseClient) #if DEBUG // Live reload of the application for development when launched with the `./swift-dev` command - app.lifecycle.use(BrowserSyncHandler()) + // app.lifecycle.use(BrowserSyncHandler()) #endif // Add our route handlers. addRoutes(to: app) @@ -72,10 +72,10 @@ private func setupDatabase( } private func addRoutes(to app: Application) { - // Redirect the index path to purchase order route. - // app.get { req in - // req.redirect(to: SiteRoute.View.router.path(for: .purchaseOrder(.index))) - // } + // Redirect the index path to project route. + app.get { req in + req.redirect(to: SiteRoute.View.router.path(for: .project(.index))) + } app.mount( SiteRoute.router, diff --git a/Sources/DatabaseClient/ComponentPressureLoss.swift b/Sources/DatabaseClient/ComponentPressureLoss.swift index 21a089b..38d60ba 100644 --- a/Sources/DatabaseClient/ComponentPressureLoss.swift +++ b/Sources/DatabaseClient/ComponentPressureLoss.swift @@ -83,7 +83,6 @@ extension ComponentPressureLoss { .field("createdAt", .datetime) .field("updatedAt", .datetime) .field("projectID", .uuid, .required, .references(ProjectModel.schema, "id")) - // .foreignKey("projectID", references: ProjectModel.schema, "id", onDelete: .cascade) .unique(on: "projectID", "name") .create() } diff --git a/Sources/ManualDCore/Routes/ViewRoute.swift b/Sources/ManualDCore/Routes/ViewRoute.swift index a1986c1..2eafa4f 100644 --- a/Sources/ManualDCore/Routes/ViewRoute.swift +++ b/Sources/ManualDCore/Routes/ViewRoute.swift @@ -9,7 +9,7 @@ extension SiteRoute { public enum View: Equatable, Sendable { case project(ProjectRoute) - static let router = OneOf { + public static let router = OneOf { Route(.case(Self.project)) { SiteRoute.View.ProjectRoute.router } diff --git a/Sources/ViewController/Interface.swift b/Sources/ViewController/Interface.swift index 2ef42b6..6fb573a 100644 --- a/Sources/ViewController/Interface.swift +++ b/Sources/ViewController/Interface.swift @@ -38,6 +38,18 @@ extension ViewController { } } -extension ViewController: TestDependencyKey { +extension ViewController: DependencyKey { public static let testValue = Self() + + // FIX: Fix. + public static let liveValue = Self( + view: { _ in + return MainPage { + div { + h1 { "It works!" } + h2 { "Browser sync works!" } + } + } + } + ) } diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..071df30 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,93 @@ +# ================================ +# Build image +# ================================ +FROM docker.io/swift:6.2-noble AS build + +# Install OS updates +RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ + && apt-get -q update \ + && apt-get -q dist-upgrade -y \ + && apt-get install -y libjemalloc-dev + +# Set up a build area +WORKDIR /build + +# First just resolve dependencies. +# This creates a cached layer that can be reused +# as long as your Package.swift/Package.resolved +# files do not change. +COPY ./Package.* ./ +RUN swift package resolve \ + $([ -f ./Package.resolved ] && echo "--force-resolved-versions" || true) + +# Copy entire repo into container +COPY . . + +# Build the application, 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 \ + --product App \ + --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 {} ./ \; + +# Copy any resources from the public directory and views directory if the directories exist +# Ensure that by default, neither the directory nor any of its contents are writable. +RUN [ -d /build/Public ] && { mv /build/Public ./Public && chmod -R a-w ./Public; } || true +RUN [ -d /build/Resources ] && { mv /build/Resources ./Resources && chmod -R a-w ./Resources; } || true + +# ================================ +# Run image +# ================================ +FROM docker.io/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 \ + sqlite3 \ + curl \ + && rm -r /var/lib/apt/lists/* + +# Create a vapor user and group with /app as its home directory +RUN useradd --user-group --create-home --system --skel /dev/null --home-dir /app vapor + +# Switch to the new home directory +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 +ENV LOG_LEVEL=debug + +# Ensure all further commands run as the vapor user +USER vapor:vapor + +# Let Docker bind to port 8080 +EXPOSE 8080 + +# Start the Vapor service when the image is run, default to listening on 8080 in production environment +ENTRYPOINT ["./App"] +CMD ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"] + diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev new file mode 100644 index 0000000..1cc28f4 --- /dev/null +++ b/docker/Dockerfile.dev @@ -0,0 +1,46 @@ +FROM swift:6.2-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 \ + sqlite3 \ + nodejs \ + npm \ + build-essential \ + curl \ + && rm -r /var/lib/apt/lists/* + +# Set up a build area +WORKDIR /app + +# First just resolve dependencies. +# This creates a cached layer that can be reused +# as long as your Package.swift/Package.resolved +# files do not change. +COPY ./Package.* ./ +RUN swift package resolve \ + $([ -f ./Package.resolved ] && echo "--force-resolved-versions" || true) + +# Copy entire repo into container +COPY . . + +RUN curl -L https://github.com/watchexec/watchexec/releases/download/v2.3.2/watchexec-2.3.2-aarch64-unknown-linux-gnu.tar.xz --output watchexec.tar.xz \ + && tar -xvf watchexec.tar.xz \ + && cp ./watchexec-2.3.2-aarch64-unknown-linux-gnu/watchexec /bin + +RUN npm install -g browser-sync + +ENV SWIFT_BACKTRACE=enable=no +ENV LOG_LEVEL=debug + +CMD ["swift", "test"] + diff --git a/justfile b/justfile new file mode 100644 index 0000000..e3cf100 --- /dev/null +++ b/justfile @@ -0,0 +1,7 @@ +docker_image := "manuald" + +build-docker: + @podman build -f docker/Dockerfile.dev -t {{docker_image}}:dev . + +run-dev: + @podman run -it --rm -v $PWD:/app -p 3000:3000 -p 3002:3002 -p 8080:8080 {{docker_image}}:dev ./swift-dev diff --git a/swift-dev b/swift-dev new file mode 100755 index 0000000..badada6 --- /dev/null +++ b/swift-dev @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +touch .build/browser-dev-sync +browser-sync start -p 0.0.0.0:8080 --ws --no-open & +watchexec -w Sources -e .swift -r 'swift build --product App && touch .build/browser-dev-sync' & +watchexec -w .build/browser-dev-sync --ignore-nothing -r '.build/debug/App'