mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-06-10 08:37:02 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 624601b1d4 | |||
| a9c3daedb1 | |||
| 1039363de6 |
@@ -1,4 +1,11 @@
|
|||||||
# syntax=docker/dockerfile:latest
|
# syntax=docker/dockerfile:latest
|
||||||
|
FROM docker.io/library/golang:alpine AS aio-container-tools-builder
|
||||||
|
|
||||||
|
# hadolint ignore=DL3022
|
||||||
|
COPY --from=aio-container-tools . /tmp/aio-container-tools/
|
||||||
|
WORKDIR /tmp/aio-container-tools
|
||||||
|
RUN go build -o /usr/local/bin/aio-pg-healthcheck ./cmd/aio-pg-healthcheck
|
||||||
|
|
||||||
FROM php:8.3.30-fpm-alpine3.23
|
FROM php:8.3.30-fpm-alpine3.23
|
||||||
|
|
||||||
ENV PHP_MEMORY_LIMIT=512M
|
ENV PHP_MEMORY_LIMIT=512M
|
||||||
@@ -17,6 +24,7 @@ COPY --chmod=775 Containers/nextcloud/*.sh /
|
|||||||
COPY --chmod=774 Containers/nextcloud/upgrade.exclude /upgrade.exclude
|
COPY --chmod=774 Containers/nextcloud/upgrade.exclude /upgrade.exclude
|
||||||
COPY Containers/nextcloud/config/*.php /
|
COPY Containers/nextcloud/config/*.php /
|
||||||
COPY Containers/nextcloud/supervisord.conf /supervisord.conf
|
COPY Containers/nextcloud/supervisord.conf /supervisord.conf
|
||||||
|
COPY --from=aio-container-tools-builder /usr/local/bin/aio-pg-healthcheck /usr/local/bin/aio-pg-healthcheck
|
||||||
|
|
||||||
# AIO cloning start # Do not remove or change this line!
|
# AIO cloning start # Do not remove or change this line!
|
||||||
COPY app /usr/src/nextcloud/apps/nextcloud-aio
|
COPY app /usr/src/nextcloud/apps/nextcloud-aio
|
||||||
@@ -226,7 +234,6 @@ RUN set -ex; \
|
|||||||
openssl \
|
openssl \
|
||||||
gnupg \
|
gnupg \
|
||||||
git \
|
git \
|
||||||
postgresql-client \
|
|
||||||
tzdata \
|
tzdata \
|
||||||
sudo \
|
sudo \
|
||||||
grep \
|
grep \
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ fi
|
|||||||
# Fix false database connection on old instances
|
# Fix false database connection on old instances
|
||||||
if [ -f "/var/www/html/config/config.php" ]; then
|
if [ -f "/var/www/html/config/config.php" ]; then
|
||||||
sleep 2
|
sleep 2
|
||||||
while ! sudo -E -u www-data psql -d "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB" -c "select now()"; do
|
while ! sudo -E -u www-data /usr/local/bin/aio-pg-healthcheck; do
|
||||||
echo "Waiting for the database to start..."
|
echo "Waiting for the database to start..."
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
# syntax=docker/dockerfile:latest
|
# syntax=docker/dockerfile:latest
|
||||||
|
FROM docker.io/library/golang:alpine AS aio-container-tools-builder
|
||||||
|
|
||||||
|
# hadolint ignore=DL3022
|
||||||
|
COPY --from=aio-container-tools . /tmp/aio-container-tools/
|
||||||
|
WORKDIR /tmp/aio-container-tools
|
||||||
|
RUN go build -o /usr/local/bin/aio-pg-init ./cmd/aio-pg-init \
|
||||||
|
&& go build -o /usr/local/bin/aio-pg-healthcheck ./cmd/aio-pg-healthcheck
|
||||||
|
|
||||||
# From https://github.com/docker-library/postgres/blob/master/17/alpine3.23/Dockerfile
|
# From https://github.com/docker-library/postgres/blob/master/17/alpine3.23/Dockerfile
|
||||||
FROM postgres:17.9-alpine
|
FROM postgres:17.9-alpine
|
||||||
|
|
||||||
COPY --chmod=775 start.sh /start.sh
|
COPY --chmod=775 start.sh /start.sh
|
||||||
|
COPY --from=aio-container-tools-builder /usr/local/bin/aio-pg-init /usr/local/bin/aio-pg-init
|
||||||
|
COPY --from=aio-container-tools-builder /usr/local/bin/aio-pg-healthcheck /usr/local/bin/aio-pg-healthcheck
|
||||||
COPY --chmod=775 healthcheck.sh /healthcheck.sh
|
COPY --chmod=775 healthcheck.sh /healthcheck.sh
|
||||||
COPY --chmod=775 init-user-db.sh /docker-entrypoint-initdb.d/init-user-db.sh
|
COPY --chmod=775 init-user-db.sh /docker-entrypoint-initdb.d/init-user-db.sh
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,4 @@
|
|||||||
|
|
||||||
test -f "/mnt/data/backup-is-running" && exit 0
|
test -f "/mnt/data/backup-is-running" && exit 0
|
||||||
|
|
||||||
psql -d "postgresql://oc_$POSTGRES_USER:$POSTGRES_PASSWORD@127.0.0.1:11000/$POSTGRES_DB" -c "select now()" && exit 0
|
POSTGRES_PORT=11000 /usr/local/bin/aio-pg-healthcheck debug || exec /usr/local/bin/aio-pg-healthcheck
|
||||||
|
|
||||||
psql -d "postgresql://oc_$POSTGRES_USER:$POSTGRES_PASSWORD@127.0.0.1:5432/$POSTGRES_DB" -c "select now()" || exit 1
|
|
||||||
|
|||||||
@@ -3,12 +3,7 @@ set -ex
|
|||||||
|
|
||||||
touch "$DUMP_DIR/initialization.failed"
|
touch "$DUMP_DIR/initialization.failed"
|
||||||
|
|
||||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
POSTGRES_DB_OWNER="oc_$POSTGRES_USER" /usr/local/bin/aio-pg-init
|
||||||
CREATE USER "oc_$POSTGRES_USER" WITH PASSWORD '$POSTGRES_PASSWORD' CREATEDB;
|
|
||||||
ALTER DATABASE "$POSTGRES_DB" OWNER TO "oc_$POSTGRES_USER";
|
|
||||||
GRANT ALL PRIVILEGES ON DATABASE "$POSTGRES_DB" TO "oc_$POSTGRES_USER";
|
|
||||||
GRANT ALL PRIVILEGES ON SCHEMA public TO "oc_$POSTGRES_USER";
|
|
||||||
EOSQL
|
|
||||||
|
|
||||||
rm "$DUMP_DIR/initialization.failed"
|
rm "$DUMP_DIR/initialization.failed"
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
DATADIR="/var/lib/postgresql/data"
|
DATADIR="/var/lib/postgresql/data"
|
||||||
export DUMP_DIR="/mnt/data"
|
export DUMP_DIR="/mnt/data"
|
||||||
DUMP_FILE="$DUMP_DIR/database-dump.sql"
|
DUMP_FILE="$DUMP_DIR/database-dump.sql"
|
||||||
|
# TODO: Do we need this? It's not used anywhere visible
|
||||||
export PGPASSWORD="$POSTGRES_PASSWORD"
|
export PGPASSWORD="$POSTGRES_PASSWORD"
|
||||||
|
|
||||||
# Don't start database as long as backup is running
|
# Don't start database as long as backup is running
|
||||||
@@ -85,7 +86,7 @@ if ( [ -f "$DATADIR/PG_VERSION" ] && [ "$PG_MAJOR" != "$(cat "$DATADIR/PG_VERSIO
|
|||||||
exec docker-entrypoint.sh postgres &
|
exec docker-entrypoint.sh postgres &
|
||||||
|
|
||||||
# Wait for creation
|
# Wait for creation
|
||||||
while ! psql -d "postgresql://oc_$POSTGRES_USER:$POSTGRES_PASSWORD@127.0.0.1:11000/$POSTGRES_DB" -c "select now()"; do
|
while ! env POSTGRES_PORT=11000 POSTGRES_USER="oc_$POSTGRES_USER" /usr/local/bin/aio-pg-healthcheck; do
|
||||||
echo "Waiting for the database to start."
|
echo "Waiting for the database to start."
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
@@ -107,12 +108,7 @@ if ( [ -f "$DATADIR/PG_VERSION" ] && [ "$PG_MAJOR" != "$(cat "$DATADIR/PG_VERSIO
|
|||||||
exit 1
|
exit 1
|
||||||
elif [ "$DB_OWNER" != "oc_$POSTGRES_USER" ]; then
|
elif [ "$DB_OWNER" != "oc_$POSTGRES_USER" ]; then
|
||||||
DIFFERENT_DB_OWNER=1
|
DIFFERENT_DB_OWNER=1
|
||||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
POSTGRES_DB_OWNER="$DB_OWNER" /usr/local/bin/aio-pg-init
|
||||||
CREATE USER "$DB_OWNER" WITH PASSWORD '$POSTGRES_PASSWORD' CREATEDB;
|
|
||||||
ALTER DATABASE "$POSTGRES_DB" OWNER TO "$DB_OWNER";
|
|
||||||
GRANT ALL PRIVILEGES ON DATABASE "$POSTGRES_DB" TO "$DB_OWNER";
|
|
||||||
GRANT ALL PRIVILEGES ON SCHEMA public TO "$DB_OWNER";
|
|
||||||
EOSQL
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Restore database
|
# Restore database
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# aio-container-tools
|
||||||
|
|
||||||
|
Standalone tools for Nextcloud AIO containers, for tasks that shouldn't be executed in a shell environment
|
||||||
|
(e.g. due to string handling issues).
|
||||||
|
|
||||||
|
Golang was chosen because it doesn't require additional runtimes in the containers, and has a pretty easy
|
||||||
|
syntax that is comprehensible even for people without much experience with the language.
|
||||||
|
|
||||||
|
The tools should be built in the container image build process, so they are built for the correct target
|
||||||
|
platform in multi-arch builds. See below for an example.
|
||||||
|
|
||||||
|
## Build process
|
||||||
|
|
||||||
|
To include the binary of `aio-pg-healhcheck` into your container image, include such a snippet into your Containerfile:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM docker.io/library/golang:alpine AS golang-builder
|
||||||
|
|
||||||
|
# hadolint ignore=DL3022
|
||||||
|
COPY --from=aio-container-tools . /tmp/aio-container-tools/
|
||||||
|
RUN cd /tmp/aio-container-tools \
|
||||||
|
&& go build -o /usr/local/bin/aio-pg-healthcheck ./cmd/aio-pg-healthcheck
|
||||||
|
|
||||||
|
FROM your-base-image
|
||||||
|
COPY --from=golang-builder /usr/local/bin/aio-pg-healthcheck /usr/local/bin/
|
||||||
|
```
|
||||||
|
|
||||||
|
To build it you now have to pass the aio-container-tools directory as additional, named build-context like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build \
|
||||||
|
--build-context aio-container-tools=/path/to/all-in-one/aio-container-tools \
|
||||||
|
.
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Remote git variant (without local clone of this repo)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build \
|
||||||
|
--build-context aio-container-tools="https://github.com/nextcloud-releases/all-in-one.git#main:aio-container-tools" \
|
||||||
|
.
|
||||||
|
```
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"github.com/nextcloud/aio-container-tools/internal/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// tryConnect opens a TCP connection to the given database host:port and runs SELECT 1.
|
||||||
|
// Returns nil on success, an error otherwise.
|
||||||
|
func tryConnect(ctx context.Context, host string, port uint16, user, password, database string) error {
|
||||||
|
util.Debugf("attempting connection: host=%s port=%d user=%s database=%s", host, port, user, database)
|
||||||
|
|
||||||
|
cfg, err := pgx.ParseConfig("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cfg.Host = host
|
||||||
|
cfg.Port = port
|
||||||
|
cfg.User = user
|
||||||
|
cfg.Password = password
|
||||||
|
cfg.Database = database
|
||||||
|
|
||||||
|
conn, err := pgx.ConnectConfig(ctx, cfg)
|
||||||
|
if err != nil {
|
||||||
|
util.Debugf("connection failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close(ctx)
|
||||||
|
|
||||||
|
util.Debugf("connection established, running SELECT 1")
|
||||||
|
var result string
|
||||||
|
if err := conn.QueryRow(ctx, "SELECT 1").Scan(&result); err != nil {
|
||||||
|
util.Debugf("SELECT 1 failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
util.Debugf("SELECT 1 returned %q", result)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// envOrDefault returns the value of the named environment variable,
|
||||||
|
// or the provided default if the variable is unset or empty.
|
||||||
|
func envOrDefault(key, defaultVal string) string {
|
||||||
|
if v := os.Getenv(key); v != "" {
|
||||||
|
util.Debugf("env %s = %q", key, v)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
util.Debugf("env %s not set, using default %q", key, defaultVal)
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
debug := flag.Bool("debug", false, "enable debug output")
|
||||||
|
flag.Parse()
|
||||||
|
util.SetDebug(*debug)
|
||||||
|
|
||||||
|
util.Debugf("reading required environment variables")
|
||||||
|
pgUser := util.RequireEnv("POSTGRES_USER")
|
||||||
|
pgPassword := util.RequireEnv("POSTGRES_PASSWORD")
|
||||||
|
pgDB := util.RequireEnv("POSTGRES_DB")
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
pgHost := envOrDefault("POSTGRES_HOST", "127.0.0.1")
|
||||||
|
|
||||||
|
var pgPort uint16 = 5432
|
||||||
|
if portStr := os.Getenv("POSTGRES_PORT"); portStr != "" {
|
||||||
|
util.Debugf("env POSTGRES_PORT = %q", portStr)
|
||||||
|
p, err := strconv.ParseUint(portStr, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "invalid POSTGRES_PORT %q: %v\n", portStr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
pgPort = uint16(p)
|
||||||
|
} else {
|
||||||
|
util.Debugf("env POSTGRES_PORT not set, using default port %d", pgPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
util.Debugf("connecting to: host=%s port=%d user=%s", pgHost, pgPort, pgUser)
|
||||||
|
if err := tryConnect(ctx, pgHost, pgPort, pgUser, pgPassword, pgDB); err == nil {
|
||||||
|
util.Debugf("connection succeeded, exiting 0")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
util.Debugf("connection failed, exiting 1")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"github.com/nextcloud/aio-container-tools/internal/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// quoteLiteral safely quotes a string as a PostgreSQL string literal.
|
||||||
|
// Single quotes are escaped by doubling them. This is safe with
|
||||||
|
// standard_conforming_strings=on (default since PostgreSQL 9.1).
|
||||||
|
func quoteLiteral(s string) string {
|
||||||
|
return "'" + strings.ReplaceAll(s, "'", "''") + "'"
|
||||||
|
}
|
||||||
|
|
||||||
|
// main reimplements init-user-db.sh:
|
||||||
|
// - Creates $POSTGRES_DB_OWNER (falling back to $POSTGRES_USER) with $POSTGRES_PASSWORD and CREATEDB
|
||||||
|
// - Transfers ownership of $POSTGRES_DB to that user
|
||||||
|
// - Grants all privileges on the database and public schema
|
||||||
|
// - Connects using $POSTGRES_USER in all cases
|
||||||
|
func main() {
|
||||||
|
debug := flag.Bool("debug", false, "enable debug output")
|
||||||
|
flag.Parse()
|
||||||
|
util.SetDebug(*debug)
|
||||||
|
|
||||||
|
util.Debugf("reading required environment variables")
|
||||||
|
pgUser := util.RequireEnv("POSTGRES_USER")
|
||||||
|
pgPassword := util.RequireEnv("POSTGRES_PASSWORD")
|
||||||
|
pgDB := util.RequireEnv("POSTGRES_DB")
|
||||||
|
pgDBOwner := util.OptionalEnv("POSTGRES_DB_OWNER", pgUser)
|
||||||
|
|
||||||
|
util.Debugf("building connection config: host=/var/run/postgresql port=5432 user=%s database=%s", pgUser, pgDB)
|
||||||
|
cfg, err := pgx.ParseConfig("")
|
||||||
|
if err != nil {
|
||||||
|
util.ErrorOut(fmt.Errorf("building connection config: %w", err))
|
||||||
|
}
|
||||||
|
cfg.Host = "/var/run/postgresql"
|
||||||
|
cfg.Port = 5432
|
||||||
|
cfg.User = pgUser
|
||||||
|
cfg.Password = pgPassword
|
||||||
|
cfg.Database = pgDB
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
util.Debugf("connecting to postgres via unix socket")
|
||||||
|
conn, err := pgx.ConnectConfig(ctx, cfg)
|
||||||
|
if err != nil {
|
||||||
|
util.ErrorOut(fmt.Errorf("connecting to postgres: %w", err))
|
||||||
|
}
|
||||||
|
defer conn.Close(ctx)
|
||||||
|
util.Debugf("connected successfully")
|
||||||
|
|
||||||
|
dbOwner := pgDBOwner
|
||||||
|
util.Debugf("dbOwner = %q (from POSTGRES_DB_OWNER=%q, POSTGRES_USER=%q)", dbOwner, pgDBOwner, pgUser)
|
||||||
|
// pgx.Identifier.Sanitize() double-quotes and escapes the identifier safely.
|
||||||
|
dbOwnerIdent := pgx.Identifier{dbOwner}.Sanitize()
|
||||||
|
dbIdent := pgx.Identifier{pgDB}.Sanitize()
|
||||||
|
util.Debugf("quoted dbOwnerIdent = %s, dbIdent = %s", dbOwnerIdent, dbIdent)
|
||||||
|
|
||||||
|
statements := []string{
|
||||||
|
fmt.Sprintf("CREATE USER %s WITH PASSWORD %s CREATEDB", dbOwnerIdent, quoteLiteral(pgPassword)),
|
||||||
|
fmt.Sprintf("ALTER DATABASE %s OWNER TO %s", dbIdent, dbOwnerIdent),
|
||||||
|
fmt.Sprintf("GRANT ALL PRIVILEGES ON DATABASE %s TO %s", dbIdent, dbOwnerIdent),
|
||||||
|
fmt.Sprintf("GRANT ALL PRIVILEGES ON SCHEMA public TO %s", dbOwnerIdent),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, stmt := range statements {
|
||||||
|
util.Debugf("executing statement %d/%d: %s", i+1, len(statements), stmt)
|
||||||
|
if _, err := conn.Exec(ctx, stmt); err != nil {
|
||||||
|
util.ErrorOut(fmt.Errorf("executing statement: %w", err))
|
||||||
|
}
|
||||||
|
util.Debugf("statement %d/%d succeeded", i+1, len(statements))
|
||||||
|
}
|
||||||
|
util.Debugf("all statements executed successfully")
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
module github.com/nextcloud/aio-container-tools
|
||||||
|
|
||||||
|
go 1.25.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.8.0 // indirect
|
||||||
|
golang.org/x/text v0.29.0 // indirect
|
||||||
|
)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo=
|
||||||
|
github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||||
|
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var debugEnabled bool
|
||||||
|
|
||||||
|
// SetDebug enables or disables debug output.
|
||||||
|
func SetDebug(enabled bool) {
|
||||||
|
debugEnabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf prints a formatted debug message to stdout when debug mode is enabled.
|
||||||
|
func Debugf(format string, args ...any) {
|
||||||
|
if debugEnabled {
|
||||||
|
fmt.Printf("[debug] "+format+"\n", args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequireEnv returns the value of the named environment variable.
|
||||||
|
// It writes an error to stderr and exits with code 1 if the variable is unset or empty.
|
||||||
|
func RequireEnv(key string) string {
|
||||||
|
v := os.Getenv(key)
|
||||||
|
if v == "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "required environment variable %q is not set\n", key)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
Debugf("env %s = %q", key, v)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionalEnv returns the value of the named environment variable, or fallback if it is unset or empty.
|
||||||
|
func OptionalEnv(key, fallback string) string {
|
||||||
|
v := os.Getenv(key)
|
||||||
|
if v == "" {
|
||||||
|
Debugf("env %s unset, using fallback %q", key, fallback)
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
Debugf("env %s = %q", key, v)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorOut logs the error with a standard prefix and exits with code 1.
|
||||||
|
func ErrorOut(err error) {
|
||||||
|
log.Fatalf("error: %v", err)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user