Ver código fonte

first commit

main
rpm-mcarman 2 anos atrás
commit
4f75bf4867
15 arquivos alterados com 370 adições e 0 exclusões
  1. +2
    -0
      .dockerignore
  2. +12
    -0
      .gitignore
  3. +88
    -0
      Dockerfile
  4. +41
    -0
      Package.swift
  5. +0
    -0
      Public/.gitkeep
  6. +12
    -0
      Resources/Views/index.leaf
  7. +0
    -0
      Sources/App/Controllers/.gitkeep
  8. +34
    -0
      Sources/App/Controllers/TodoController.swift
  9. +14
    -0
      Sources/App/Migrations/CreateTodo.swift
  10. +19
    -0
      Sources/App/Models/Todo.swift
  11. +24
    -0
      Sources/App/configure.swift
  12. +21
    -0
      Sources/App/entrypoint.swift
  13. +14
    -0
      Sources/App/routes.swift
  14. +15
    -0
      Tests/AppTests/AppTests.swift
  15. +74
    -0
      docker-compose.yml

+ 2
- 0
.dockerignore Ver arquivo

@@ -0,0 +1,2 @@
.build/
.swiftpm/

+ 12
- 0
.gitignore Ver arquivo

@@ -0,0 +1,12 @@
Packages
.build
xcuserdata
*.xcodeproj
DerivedData/
.DS_Store
db.sqlite
.swiftpm
.env
.env.*
! .env.example
.vscode

+ 88
- 0
Dockerfile Ver arquivo

@@ -0,0 +1,88 @@
# ================================
# Build image
# ================================
FROM swift:5.10-jammy 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 --skip-update \
$([ -f ./Package.resolved ] && echo "--force-resolved-versions" || true)

# Copy entire repo into container
COPY . .

# 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 {} ./ \;

# 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 ubuntu:jammy

# 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
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

# 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"]

+ 41
- 0
Package.swift Ver arquivo

@@ -0,0 +1,41 @@
// swift-tools-version:5.10
import PackageDescription

let package = Package(
name: "training_v1",
platforms: [
.macOS(.v13)
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.92.4"),
// 🗄 An ORM for SQL and NoSQL databases.
.package(url: "https://github.com/vapor/fluent.git", from: "4.9.0"),
// 🐘 Fluent driver for Postgres.
.package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.8.0"),
],
targets: [
.executableTarget(
name: "App",
dependencies: [
.product(name: "Fluent", package: "fluent"),
.product(name: "FluentPostgresDriver", package: "fluent-postgres-driver"),
.product(name: "Vapor", package: "vapor"),
],
swiftSettings: swiftSettings
),
.testTarget(
name: "AppTests",
dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor"),
],
swiftSettings: swiftSettings
)
]
)

var swiftSettings: [SwiftSetting] { [
.enableUpcomingFeature("DisableOutwardActorInference"),
.enableExperimentalFeature("StrictConcurrency"),
] }

+ 0
- 0
Public/.gitkeep Ver arquivo


+ 12
- 0
Resources/Views/index.leaf Ver arquivo

@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">

<title>#(title)</title>
</head>

<body>
<h1>#(title)</h1>
</body>
</html>

+ 0
- 0
Sources/App/Controllers/.gitkeep Ver arquivo


+ 34
- 0
Sources/App/Controllers/TodoController.swift Ver arquivo

@@ -0,0 +1,34 @@
import Fluent
import Vapor

struct TodoController: RouteCollection {
func boot(routes: RoutesBuilder) throws {
let todos = routes.grouped("todos")

todos.get(use: { try await self.index(req: $0) })
todos.post(use: { try await self.create(req: $0) })
todos.group(":todoID") { todo in
todo.delete(use: { try await self.delete(req: $0) })
}
}
func index(req: Request) async throws -> [Todo] {
try await Todo.query(on: req.db).all()
}

func create(req: Request) async throws -> Todo {
let todo = try req.content.decode(Todo.self)

try await todo.save(on: req.db)
return todo
}

func delete(req: Request) async throws -> HTTPStatus {
guard let todo = try await Todo.find(req.parameters.get("todoID"), on: req.db) else {
throw Abort(.notFound)
}

try await todo.delete(on: req.db)
return .noContent
}
}

+ 14
- 0
Sources/App/Migrations/CreateTodo.swift Ver arquivo

@@ -0,0 +1,14 @@
import Fluent

struct CreateTodo: AsyncMigration {
func prepare(on database: Database) async throws {
try await database.schema("todos")
.id()
.field("title", .string, .required)
.create()
}

func revert(on database: Database) async throws {
try await database.schema("todos").delete()
}
}

+ 19
- 0
Sources/App/Models/Todo.swift Ver arquivo

@@ -0,0 +1,19 @@
import Fluent
import Vapor

final class Todo: Model, Content {
static let schema = "todos"
@ID(key: .id)
var id: UUID?

@Field(key: "title")
var title: String

init() { }

init(id: UUID? = nil, title: String) {
self.id = id
self.title = title
}
}

+ 24
- 0
Sources/App/configure.swift Ver arquivo

@@ -0,0 +1,24 @@
import NIOSSL
import Fluent
import FluentPostgresDriver
import Vapor

// configures your application
public func configure(_ app: Application) async throws {
// uncomment to serve files from /Public folder
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))

app.databases.use(DatabaseConfigurationFactory.postgres(configuration: .init(
hostname: Environment.get("DATABASE_HOST") ?? "localhost",
port: Environment.get("DATABASE_PORT").flatMap(Int.init(_:)) ?? SQLPostgresConfiguration.ianaPortNumber,
username: Environment.get("DATABASE_USERNAME") ?? "vapor_username",
password: Environment.get("DATABASE_PASSWORD") ?? "vapor_password",
database: Environment.get("DATABASE_NAME") ?? "vapor_database",
tls: .prefer(try .init(configuration: .clientDefault)))
), as: .psql)

app.migrations.add(CreateTodo())

// register routes
try routes(app)
}

+ 21
- 0
Sources/App/entrypoint.swift Ver arquivo

@@ -0,0 +1,21 @@
import Vapor
import Logging

@main
enum Entrypoint {
static func main() async throws {
var env = try Environment.detect()
try LoggingSystem.bootstrap(from: &env)
let app = Application(env)
defer { app.shutdown() }
do {
try await configure(app)
} catch {
app.logger.report(error: error)
throw error
}
try await app.execute()
}
}

+ 14
- 0
Sources/App/routes.swift Ver arquivo

@@ -0,0 +1,14 @@
import Fluent
import Vapor

func routes(_ app: Application) throws {
app.get { req async in
"It works!"
}

app.get("hello") { req async -> String in
"Hello, world!"
}

try app.register(collection: TodoController())
}

+ 15
- 0
Tests/AppTests/AppTests.swift Ver arquivo

@@ -0,0 +1,15 @@
@testable import App
import XCTVapor

final class AppTests: XCTestCase {
func testHelloWorld() async throws {
let app = Application(.testing)
defer { app.shutdown() }
try await configure(app)

try app.test(.GET, "hello", afterResponse: { res in
XCTAssertEqual(res.status, .ok)
XCTAssertEqual(res.body.string, "Hello, world!")
})
}
}

+ 74
- 0
docker-compose.yml Ver arquivo

@@ -0,0 +1,74 @@
# Docker Compose file for Vapor
#
# Install Docker on your system to run and test
# your Vapor app in a production-like environment.
#
# Note: This file is intended for testing and does not
# implement best practices for a production deployment.
#
# Learn more: https://docs.docker.com/compose/reference/
#
# Build images: docker-compose build
# Start app: docker-compose up app
# Start database: docker-compose up db
# Run migrations: docker-compose run migrate
# Stop all: docker-compose down (add -v to wipe db)
#
version: '3.7'

volumes:
db_data:

x-shared_environment: &shared_environment
LOG_LEVEL: ${LOG_LEVEL:-debug}
DATABASE_HOST: db
DATABASE_NAME: vapor_database
DATABASE_USERNAME: vapor_username
DATABASE_PASSWORD: vapor_password
services:
app:
image: :latest
build:
context: .
environment:
<<: *shared_environment
depends_on:
- db
ports:
- '8080:8080'
# user: '0' # uncomment to run as root for testing purposes even though Dockerfile defines 'vapor' user.
command: ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"]
migrate:
image: :latest
build:
context: .
environment:
<<: *shared_environment
depends_on:
- db
command: ["migrate", "--yes"]
deploy:
replicas: 0
revert:
image: :latest
build:
context: .
environment:
<<: *shared_environment
depends_on:
- db
command: ["migrate", "--revert", "--yes"]
deploy:
replicas: 0
db:
image: postgres:16-alpine
volumes:
- db_data:/var/lib/postgresql/data/pgdata
environment:
PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_USER: vapor_username
POSTGRES_PASSWORD: vapor_password
POSTGRES_DB: vapor_database
ports:
- '5432:5432'

Carregando…
Cancelar
Salvar