diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..fefd25b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,19 @@ +.dockerignore +Dockerfile +.direnv +.git +/bin +public/ +*_templ.go +/tmp +/rest +out +node_modules +.air.toml +.env +.envrc +.gitignore +*.db +flake.lock +flake.nix + diff --git a/.gitignore b/.gitignore index a790c69..85ac143 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,7 @@ public/htmx*.js .direnv /tmp db/queries/**/*.go -*.db +/*.db public/*.min.js diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..67b5147 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +FROM node:22-bullseye AS web-builder +WORKDIR /web +COPY package.json package-lock.json ./ +RUN npm install +COPY Makefile ./ +COPY views ./views +COPY tailwind.config.js ./ +RUN make web-build + +FROM golang:1.22.1 AS builder +WORKDIR /app +COPY Makefile ./ +RUN make build-dependencies +COPY go.mod go.sum ./ +RUN go mod download +COPY . . +COPY --from=web-builder /web/public ./public +RUN --mount=type=cache,target=/root/.cache/go-build \ + ./bin/templ generate && GOOS=linux GOARCH=amd64 go build -o /app/redmage main.go + + +FROM gcr.io/distroless/base:nonroot +WORKDIR /app +COPY --from=builder /app/redmage /app/redmage +ENV REDMAGE_FLAGS_CONTAINERIZED=true +ENV REDMAGE_DB_STRING=/app/db/data.db +ENV REDMAGE_PUBSUB_DB_NAME=/app/db/pubsub.db +ENV REDMAGE_DOWNLOAD_DIRECTORY=/app/downloads +ENV REDMAGE_RUNTIME_ENVIRONMENT=production +CMD [ "/app/redmage", "serve" ] diff --git a/Makefile b/Makefile index 2c3d03b..c122e8f 100644 --- a/Makefile +++ b/Makefile @@ -27,8 +27,15 @@ build-dependencies: @if ! command -v templ > /dev/null; then mkdir -p bin echo "Templ not found in PATH, installing it to $(shell pwd)/bin/templ" - go install github.com/a-h/templ/cmd/templ@v0.2.648 + go install github.com/a-h/templ/cmd/templ@v0.2.663 fi + @if ! command -v goose > /dev/null; then + mkdir -p bin + echo "Goose not found in PATH, installing it to $(shell pwd)/bin/goose" + go install github.com/pressly/goose/v3/cmd/goose@latest + fi + +web-dependencies: @if [ ! -d "node_modules" ]; then echo "Node modules not found, installing them" npm install @@ -69,9 +76,16 @@ build-dependencies: curl -o public/alpinejs-${REDMAGE_WEB_DEPENDENCIES_ALPINEJS_VERSION}.min.js https://cdn.jsdelivr.net/npm/alpinejs@${REDMAGE_WEB_DEPENDENCIES_ALPINEJS_VERSION}/dist/cdn.min.js fi -build: build-dependencies prepare +web-build: web-dependencies + mkdir -p public + npx tailwindcss -i views/style.css -o public/style.css + +build: web-dependencies build-dependencies prepare go build -o redmage +build-docker: migrate-up + GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o redmage + prepare: gen mkdir -p public tailwindcss -i views/style.css -o public/style.css diff --git a/db/db.go b/db/db.go index ab9e778..7703027 100644 --- a/db/db.go +++ b/db/db.go @@ -3,6 +3,8 @@ package db import ( "database/sql" "io/fs" + "os" + "path/filepath" _ "github.com/mattn/go-sqlite3" "github.com/pressly/goose/v3" @@ -19,11 +21,22 @@ var Migrations fs.FS func Open(cfg *config.Config) (*sql.DB, error) { driver := cfg.String("db.driver") dsn := cfg.String("db.string") + if driver == "sqlite3" { + path, err := filepath.Abs(dsn) + if err != nil { + return nil, errs.Wrapw(err, "failed to get absolute path of sqlite3 database", "path", dsn) + } + dir := filepath.Dir(path) + err = os.MkdirAll(dir, 0777) + if err != nil { + return nil, errs.Wrapw(err, "failed to create directory for sqlite3 database", "dir", dir) + } + } db, err := otelsql.Open(driver, dsn, otelsql.WithAttributes( semconv.DBSystemSqlite, )) if err != nil { - return db, errs.Wrapw(err, "failed to open database", "driver", driver) + return db, errs.Wrapw(err, "failed to open database", "driver", driver, "db.string", dsn) } if cfg.Bool("db.automigrate") { goose.SetLogger(goose.NopLogger())