From 8d7669afc320bf488ad40354c18827627a93ffee Mon Sep 17 00:00:00 2001 From: RW Date: Sun, 20 Jul 2025 14:26:49 +0200 Subject: [PATCH 1/3] docs: link file server guide and dependabot group --- .github/dependabot.yml | 3 ++ README.md | 35 +++++++++++++ cmd/fileserver/app/app.go | 65 ++++++++++++++++++++++++ cmd/fileserver/app/app_test.go | 50 +++++++++++++++++++ cmd/fileserver/main.go | 56 +++++++++++++++++++++ cmd/root.go | 2 +- cmd/serve.go | 90 ++++++++++++++++++++++++++++++++++ cmd/serve_test.go | 27 ++++++++++ docs/guide/fileserver.md | 43 ++++++++++++++++ go.mod | 16 ++++++ go.sum | 36 ++++++++++++++ 11 files changed, 422 insertions(+), 1 deletion(-) create mode 100644 cmd/fileserver/app/app.go create mode 100644 cmd/fileserver/app/app_test.go create mode 100644 cmd/fileserver/main.go create mode 100644 cmd/serve.go create mode 100644 cmd/serve_test.go create mode 100644 docs/guide/fileserver.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5f38232..9d2feb6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -29,6 +29,9 @@ updates: - "github.com/jarcoal/httpmock" - "github.com/stretchr/testify" - "gopkg.in/check.v1" + gofiber: + patterns: + - "github.com/gofiber/*" - package-ecosystem: "github-actions" directory: "/" # Location of package manifests default_labels: diff --git a/README.md b/README.md index 2393514..34f0dd0 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,41 @@ fiber dev [flags] -t, --target string target path for go build (default ".") ``` +## fiber serve + +### Synopsis + +Serve static files + +See the [File server guide](docs/guide/fileserver.md) for more details. + +```bash +fiber serve [flags] +``` + +### Options + +```text + --addr string address to listen on (default ":3000") + --browse enable directory browsing + --cache duration cache duration (default 10s) + --cert string TLS certificate file + --compress enable compression + --cors enable CORS middleware + --dir string directory to serve (default ".") + --download force file downloads + --health enable health check endpoints (default true) + --index string comma-separated list of index files (default "index.html") + --key string TLS private key file + --logger enable logger middleware (default true) + --maxage int Cache-Control max-age header in seconds + --path string request path to serve (default "/") + --prefork enable prefork mode + --quiet disable startup message + --range enable byte range requests + -h, --help help for serve +``` + ## fiber new ### Synopsis diff --git a/cmd/fileserver/app/app.go b/cmd/fileserver/app/app.go new file mode 100644 index 0000000..f235eb3 --- /dev/null +++ b/cmd/fileserver/app/app.go @@ -0,0 +1,65 @@ +package fileserver + +import ( + "strings" + "time" + + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/cors" + "github.com/gofiber/fiber/v3/middleware/healthcheck" + "github.com/gofiber/fiber/v3/middleware/logger" + "github.com/gofiber/fiber/v3/middleware/recover" + "github.com/gofiber/fiber/v3/middleware/static" +) + +// Options holds the settings for the file server. +type Options struct { + Dir string + Path string + Logger bool + Cors bool + Health bool + Browse bool + Download bool + Compress bool + Cache time.Duration + MaxAge int + Index string + ByteRange bool +} + +// NewApp creates a Fiber application using the provided options. +func NewApp(o Options) *fiber.App { + app := fiber.New() + + // Recover should be registered first to handle panics from later middleware. + app.Use(recover.New()) + + if o.Logger { + app.Use(logger.New()) + } + if o.Cors { + app.Use(cors.New()) + } + + if o.Health { + app.Get(healthcheck.DefaultLivenessEndpoint, healthcheck.NewHealthChecker()) + app.Get(healthcheck.DefaultReadinessEndpoint, healthcheck.NewHealthChecker()) + app.Get(healthcheck.DefaultStartupEndpoint, healthcheck.NewHealthChecker()) + } + + cfgStatic := static.Config{ + Browse: o.Browse, + Download: o.Download, + Compress: o.Compress, + ByteRange: o.ByteRange, + CacheDuration: o.Cache, + MaxAge: o.MaxAge, + } + if o.Index != "" { + cfgStatic.IndexNames = strings.Split(o.Index, ",") + } + app.Use(o.Path, static.New(o.Dir, cfgStatic)) + + return app +} diff --git a/cmd/fileserver/app/app_test.go b/cmd/fileserver/app/app_test.go new file mode 100644 index 0000000..bda636d --- /dev/null +++ b/cmd/fileserver/app/app_test.go @@ -0,0 +1,50 @@ +package fileserver + +import ( + "io" + "net/http/httptest" + "os" + "path/filepath" + "runtime" + "testing" + "time" + + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/healthcheck" + "github.com/stretchr/testify/require" +) + +func TestNewAppHealthEndpoints(t *testing.T) { + t.Parallel() + opts := Options{Dir: t.TempDir(), Path: "/", Health: true} + app := NewApp(opts) + + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, healthcheck.DefaultLivenessEndpoint, nil)) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, fiber.StatusOK, resp.StatusCode) +} + +func TestNewAppServeIndex(t *testing.T) { + t.Parallel() + + if runtime.GOOS == "windows" { + t.Skip("skipping on windows") + } + + dir := t.TempDir() + err := os.WriteFile(filepath.Join(dir, "index.html"), []byte("hello"), 0o600) + require.NoError(t, err) + + opts := Options{Dir: dir, Path: "/", Index: "index.html", Cache: time.Second} + app := NewApp(opts) + + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, fiber.StatusOK, resp.StatusCode) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Contains(t, string(body), "hello") +} diff --git a/cmd/fileserver/main.go b/cmd/fileserver/main.go new file mode 100644 index 0000000..22a1cad --- /dev/null +++ b/cmd/fileserver/main.go @@ -0,0 +1,56 @@ +package main + +import ( + "flag" + "time" + + fileserver "github.com/gofiber/cli/cmd/fileserver/app" + "github.com/gofiber/fiber/v3" + fiberlog "github.com/gofiber/fiber/v3/log" +) + +func main() { + dir := flag.String("dir", ".", "directory to serve") + addr := flag.String("addr", ":3000", "address to listen on") + path := flag.String("path", "/", "request path to serve") + enableLogger := flag.Bool("logger", true, "enable logger middleware") + enableCors := flag.Bool("cors", false, "enable CORS middleware") + enableHealth := flag.Bool("health", true, "enable health check endpoints") + cert := flag.String("cert", "", "TLS certificate file") + key := flag.String("key", "", "TLS private key file") + browse := flag.Bool("browse", false, "enable directory browsing") + download := flag.Bool("download", false, "force file downloads") + compress := flag.Bool("compress", false, "enable compression") + cache := flag.Duration("cache", 10*time.Second, "cache duration") + maxAge := flag.Int("maxage", 0, "Cache-Control max-age header in seconds") + index := flag.String("index", "index.html", "comma-separated list of index files") + byteRange := flag.Bool("range", false, "enable byte range requests") + prefork := flag.Bool("prefork", false, "enable prefork mode") + disableStartup := flag.Bool("quiet", false, "disable startup message") + flag.Parse() + + app := fileserver.NewApp(fileserver.Options{ + Dir: *dir, + Path: *path, + Logger: *enableLogger, + Cors: *enableCors, + Health: *enableHealth, + Browse: *browse, + Download: *download, + Compress: *compress, + Cache: *cache, + MaxAge: *maxAge, + Index: *index, + ByteRange: *byteRange, + }) + + cfg := fiber.ListenConfig{EnablePrefork: *prefork, DisableStartupMessage: *disableStartup} + if *cert != "" && *key != "" { + cfg.CertFile = *cert + cfg.CertKeyFile = *key + } + + if err := app.Listen(*addr, cfg); err != nil { + fiberlog.Fatalf("failed to start server: %v", err) + } +} diff --git a/cmd/root.go b/cmd/root.go index c5156f6..27f01fd 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -72,7 +72,7 @@ func init() { rootCmd.Long = getLongDescription() rootCmd.AddCommand( - versionCmd, newCmd, devCmd, upgradeCmd, migrateCmd, + versionCmd, newCmd, devCmd, serveCmd, upgradeCmd, migrateCmd, ) } diff --git a/cmd/serve.go b/cmd/serve.go new file mode 100644 index 0000000..f49167e --- /dev/null +++ b/cmd/serve.go @@ -0,0 +1,90 @@ +package cmd + +import ( + "fmt" + "time" + + fileserver "github.com/gofiber/cli/cmd/fileserver/app" + "github.com/gofiber/fiber/v3" + "github.com/spf13/cobra" +) + +var ( + serveDir string + serveAddr string + servePath string + serveLogger bool + serveCors bool + serveHealth bool + serveCert string + serveKey string + serveBrowse bool + serveDownload bool + serveCompress bool + serveCache time.Duration + serveMaxAge int + serveIndex string + serveByteRange bool + servePrefork bool + serveQuiet bool +) + +func init() { + serveCmd.Flags().StringVar(&serveDir, "dir", ".", "directory to serve") + serveCmd.Flags().StringVar(&serveAddr, "addr", ":3000", "address to listen on") + serveCmd.Flags().StringVar(&servePath, "path", "/", "request path to serve") + serveCmd.Flags().BoolVar(&serveLogger, "logger", true, "enable logger middleware") + serveCmd.Flags().BoolVar(&serveCors, "cors", false, "enable CORS middleware") + serveCmd.Flags().BoolVar(&serveHealth, "health", true, "enable health check endpoints") + serveCmd.Flags().StringVar(&serveCert, "cert", "", "TLS certificate file") + serveCmd.Flags().StringVar(&serveKey, "key", "", "TLS private key file") + serveCmd.Flags().BoolVar(&serveBrowse, "browse", false, "enable directory browsing") + serveCmd.Flags().BoolVar(&serveDownload, "download", false, "force file downloads") + serveCmd.Flags().BoolVar(&serveCompress, "compress", false, "enable compression") + serveCmd.Flags().DurationVar(&serveCache, "cache", 10*time.Second, "cache duration") + serveCmd.Flags().IntVar(&serveMaxAge, "maxage", 0, "Cache-Control max-age header in seconds") + serveCmd.Flags().StringVar(&serveIndex, "index", "index.html", "comma-separated list of index files") + serveCmd.Flags().BoolVar(&serveByteRange, "range", false, "enable byte range requests") + serveCmd.Flags().BoolVar(&servePrefork, "prefork", false, "enable prefork mode") + serveCmd.Flags().BoolVar(&serveQuiet, "quiet", false, "disable startup message") + + rootCmd.AddCommand(serveCmd) +} + +var serveCmd = &cobra.Command{ + Use: "serve", + Short: "Serve static files", + RunE: serveRunE, +} + +var listen = func(app *fiber.App, addr string, cfg fiber.ListenConfig) error { + return app.Listen(addr, cfg) +} + +func serveRunE(_ *cobra.Command, _ []string) error { + app := fileserver.NewApp(fileserver.Options{ + Dir: serveDir, + Path: servePath, + Logger: serveLogger, + Cors: serveCors, + Health: serveHealth, + Browse: serveBrowse, + Download: serveDownload, + Compress: serveCompress, + Cache: serveCache, + MaxAge: serveMaxAge, + Index: serveIndex, + ByteRange: serveByteRange, + }) + + cfg := fiber.ListenConfig{EnablePrefork: servePrefork, DisableStartupMessage: serveQuiet} + if serveCert != "" && serveKey != "" { + cfg.CertFile = serveCert + cfg.CertKeyFile = serveKey + } + + if err := listen(app, serveAddr, cfg); err != nil { + return fmt.Errorf("failed to start server: %w", err) + } + return nil +} diff --git a/cmd/serve_test.go b/cmd/serve_test.go new file mode 100644 index 0000000..af5a95a --- /dev/null +++ b/cmd/serve_test.go @@ -0,0 +1,27 @@ +package cmd + +import ( + "errors" + "testing" + + "github.com/gofiber/fiber/v3" + "github.com/stretchr/testify/require" +) + +func Test_ServeRunE(t *testing.T) { + old := listen + listen = func(_ *fiber.App, _ string, _ fiber.ListenConfig) error { return nil } + defer func() { listen = old }() + + _, err := runCobraCmd(serveCmd, "--dir=.") + require.NoError(t, err) +} + +func Test_ServeRunE_Error(t *testing.T) { + old := listen + listen = func(_ *fiber.App, _ string, _ fiber.ListenConfig) error { return errors.New("fail") } + defer func() { listen = old }() + + _, err := runCobraCmd(serveCmd, "--dir=.") + require.Error(t, err) +} diff --git a/docs/guide/fileserver.md b/docs/guide/fileserver.md new file mode 100644 index 0000000..9712d62 --- /dev/null +++ b/docs/guide/fileserver.md @@ -0,0 +1,43 @@ +--- +id: fileserver +title: "📂 File Server" +sidebar_position: 9 +--- + +Fiber ships with a configurable file server located in the `cmd/fileserver` +directory. It can serve static files from any directory and supports TLS for +secure connections. The server is also available via the `fiber serve` command. + +You can still run the program directly with `go run ./cmd/fileserver` or build +it using `go build -o fileserver ./cmd/fileserver`. + +## Usage + +Run the command specifying the directory and optional TLS certificate +and key files: + +```bash +fiber serve -dir ./public -addr :8443 -cert cert.pem -key key.pem +``` + +### Flags + +- `-dir` – directory to serve (default `.`) +- `-addr` – address to listen on (default `:3000`) +- `-path` – URL path to mount the directory (default `/`) +- `-logger` – enable request logging (default `true`) +- `-cors` – enable CORS middleware +- `-health` – expose `/livez`, `/readyz` and `/startupz` endpoints (default `true`) +- `-cert` – path to TLS certificate file +- `-key` – path to TLS private key file +- `-browse` – enable directory listing +- `-download` – force file downloads instead of in-browser viewing +- `-compress` – enable serving of pre-compressed assets +- `-cache` – cache duration (e.g. `30s`) +- `-maxage` – Cache-Control max-age in seconds +- `-index` – comma-separated list of index files +- `-range` – enable byte range requests +- `-prefork` – start server in prefork mode +- `-quiet` – disable the startup banner + +When both `-cert` and `-key` are provided the server automatically enables TLS. diff --git a/go.mod b/go.mod index 6c3fee4..53d4e3e 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/charmbracelet/bubbletea v1.3.6 github.com/containerd/console v1.0.5 github.com/fsnotify/fsnotify v1.9.0 + github.com/gofiber/fiber/v3 v3.0.0-beta.4 github.com/jarcoal/httpmock v1.4.0 github.com/muesli/termenv v0.16.0 github.com/spf13/cobra v1.9.1 @@ -16,6 +17,7 @@ require ( ) require ( + github.com/andybalholm/brotli v1.1.1 // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/charmbracelet/colorprofile v0.3.1 // indirect @@ -25,19 +27,33 @@ require ( github.com/charmbracelet/x/term v0.2.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/gofiber/schema v1.2.0 // indirect + github.com/gofiber/utils/v2 v2.0.0-beta.7 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/kr/text v0.2.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/spf13/pflag v1.0.6 // indirect + github.com/tinylib/msgp v1.2.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.58.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.31.0 // indirect golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.34.0 // indirect golang.org/x/text v0.27.0 // indirect diff --git a/go.sum b/go.sum index 4b5e675..6da7806 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= @@ -28,16 +30,31 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gofiber/fiber/v3 v3.0.0-beta.4 h1:KzDSavvhG7m81NIsmnu5l3ZDbVS4feCidl4xlIfu6V0= +github.com/gofiber/fiber/v3 v3.0.0-beta.4/go.mod h1:/WFUoHRkZEsGHyy2+fYcdqi109IVOFbVwxv1n1RU+kk= +github.com/gofiber/schema v1.2.0 h1:j+ZRrNnUa/0ZuWrn/6kAtAufEr4jCJ+JuTURAMxNSZg= +github.com/gofiber/schema v1.2.0/go.mod h1:YYwj01w3hVfaNjhtJzaqetymL56VW642YS3qZPhuE6c= +github.com/gofiber/utils/v2 v2.0.0-beta.7 h1:NnHFrRHvhrufPABdWajcKZejz9HnCWmT/asoxRsiEbQ= +github.com/gofiber/utils/v2 v2.0.0-beta.7/go.mod h1:J/M03s+HMdZdvhAeyh76xT72IfVqBzuz/OJkrMa7cwU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jarcoal/httpmock v1.4.0 h1:BvhqnH0JAYbNudL2GMJKgOHe2CtKlzJ/5rWKyp+hc2k= github.com/jarcoal/httpmock v1.4.0/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= @@ -54,6 +71,8 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -66,15 +85,32 @@ github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po= +github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.58.0 h1:GGB2dWxSbEprU9j0iMJHgdKYJVDyjrOwF9RE59PbRuE= +github.com/valyala/fasthttp v1.58.0/go.mod h1:SYXvHHaFp7QZHGKSHmoMipInhrI5StHrhDTYVEjK/Kw= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= From 8f1dcc9a48c2d87374e839a0920df2e2ce0432a9 Mon Sep 17 00:00:00 2001 From: RW Date: Sun, 20 Jul 2025 14:52:02 +0200 Subject: [PATCH 2/3] Fix dependabot.yml schema --- .github/dependabot.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9d2feb6..6c36693 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,13 +4,10 @@ version: 2 updates: - package-ecosystem: "gomod" directory: "/" # Location of package manifests - default_labels: + labels: - "🤖 Dependencies" schedule: interval: "daily" - automerged_updates: - - match: - dependency_name: "gofiber/fiber/*" groups: charmbracelet: patterns: @@ -34,7 +31,7 @@ updates: - "github.com/gofiber/*" - package-ecosystem: "github-actions" directory: "/" # Location of package manifests - default_labels: + labels: - "🤖 Dependencies" schedule: interval: "daily" From d9bca8e0f87457f3972fea5f0fd30b8fed6654f1 Mon Sep 17 00:00:00 2001 From: RW Date: Sun, 20 Jul 2025 14:52:22 +0200 Subject: [PATCH 3/3] Fix lint issues in file server --- cmd/fileserver/app/app.go | 6 +++--- cmd/fileserver/app/app_test.go | 4 ++-- cmd/fileserver/main.go | 38 +++++++++++++++++----------------- go.mod | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/cmd/fileserver/app/app.go b/cmd/fileserver/app/app.go index f235eb3..e6fcd72 100644 --- a/cmd/fileserver/app/app.go +++ b/cmd/fileserver/app/app.go @@ -16,15 +16,15 @@ import ( type Options struct { Dir string Path string + Index string + Cache time.Duration + MaxAge int Logger bool Cors bool Health bool Browse bool Download bool Compress bool - Cache time.Duration - MaxAge int - Index string ByteRange bool } diff --git a/cmd/fileserver/app/app_test.go b/cmd/fileserver/app/app_test.go index bda636d..8c0f0d0 100644 --- a/cmd/fileserver/app/app_test.go +++ b/cmd/fileserver/app/app_test.go @@ -21,7 +21,7 @@ func TestNewAppHealthEndpoints(t *testing.T) { resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, healthcheck.DefaultLivenessEndpoint, nil)) require.NoError(t, err) - defer resp.Body.Close() + t.Cleanup(func() { require.NoError(t, resp.Body.Close()) }) require.Equal(t, fiber.StatusOK, resp.StatusCode) } @@ -41,7 +41,7 @@ func TestNewAppServeIndex(t *testing.T) { resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) require.NoError(t, err) - defer resp.Body.Close() + t.Cleanup(func() { require.NoError(t, resp.Body.Close()) }) require.Equal(t, fiber.StatusOK, resp.StatusCode) body, err := io.ReadAll(resp.Body) diff --git a/cmd/fileserver/main.go b/cmd/fileserver/main.go index 22a1cad..dae2613 100644 --- a/cmd/fileserver/main.go +++ b/cmd/fileserver/main.go @@ -1,33 +1,33 @@ package main import ( - "flag" "time" fileserver "github.com/gofiber/cli/cmd/fileserver/app" "github.com/gofiber/fiber/v3" fiberlog "github.com/gofiber/fiber/v3/log" + "github.com/spf13/pflag" ) func main() { - dir := flag.String("dir", ".", "directory to serve") - addr := flag.String("addr", ":3000", "address to listen on") - path := flag.String("path", "/", "request path to serve") - enableLogger := flag.Bool("logger", true, "enable logger middleware") - enableCors := flag.Bool("cors", false, "enable CORS middleware") - enableHealth := flag.Bool("health", true, "enable health check endpoints") - cert := flag.String("cert", "", "TLS certificate file") - key := flag.String("key", "", "TLS private key file") - browse := flag.Bool("browse", false, "enable directory browsing") - download := flag.Bool("download", false, "force file downloads") - compress := flag.Bool("compress", false, "enable compression") - cache := flag.Duration("cache", 10*time.Second, "cache duration") - maxAge := flag.Int("maxage", 0, "Cache-Control max-age header in seconds") - index := flag.String("index", "index.html", "comma-separated list of index files") - byteRange := flag.Bool("range", false, "enable byte range requests") - prefork := flag.Bool("prefork", false, "enable prefork mode") - disableStartup := flag.Bool("quiet", false, "disable startup message") - flag.Parse() + dir := pflag.String("dir", ".", "directory to serve") + addr := pflag.String("addr", ":3000", "address to listen on") + path := pflag.String("path", "/", "request path to serve") + enableLogger := pflag.Bool("logger", true, "enable logger middleware") + enableCors := pflag.Bool("cors", false, "enable CORS middleware") + enableHealth := pflag.Bool("health", true, "enable health check endpoints") + cert := pflag.String("cert", "", "TLS certificate file") + key := pflag.String("key", "", "TLS private key file") + browse := pflag.Bool("browse", false, "enable directory browsing") + download := pflag.Bool("download", false, "force file downloads") + compress := pflag.Bool("compress", false, "enable compression") + cache := pflag.Duration("cache", 10*time.Second, "cache duration") + maxAge := pflag.Int("maxage", 0, "Cache-Control max-age header in seconds") + index := pflag.String("index", "index.html", "comma-separated list of index files") + byteRange := pflag.Bool("range", false, "enable byte range requests") + prefork := pflag.Bool("prefork", false, "enable prefork mode") + disableStartup := pflag.Bool("quiet", false, "disable startup message") + pflag.Parse() app := fileserver.NewApp(fileserver.Options{ Dir: *dir, diff --git a/go.mod b/go.mod index 53d4e3e..e3650b6 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/jarcoal/httpmock v1.4.0 github.com/muesli/termenv v0.16.0 github.com/spf13/cobra v1.9.1 + github.com/spf13/pflag v1.0.6 github.com/stretchr/testify v1.10.0 golang.org/x/mod v0.25.0 ) @@ -45,7 +46,6 @@ require ( github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/spf13/pflag v1.0.6 // indirect github.com/tinylib/msgp v1.2.5 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.58.0 // indirect