Files
kage/cli/serve.go
T
wehub-resource-sync 9c9576b5b9
ci / test (macos-latest) (push) Has been cancelled
ci / test (ubuntu-latest) (push) Has been cancelled
ci / lint (push) Has been cancelled
ci / govulncheck (push) Has been cancelled
ci / tidy (push) Has been cancelled
ci / webview (push) Has been cancelled
ci / windows-gui (push) Has been cancelled
release / check (push) Has been cancelled
release / release (push) Has been cancelled
Docs / build (push) Has been cancelled
Docs / deploy-pages (push) Has been cancelled
Docs / deploy-cloudflare (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-14 10:24:05 +08:00

76 lines
1.9 KiB
Go

package cli
import (
"context"
"fmt"
"net"
"net/http"
"os"
"path/filepath"
"time"
"github.com/spf13/cobra"
)
func newServeCmd() *cobra.Command {
var addr string
cmd := &cobra.Command{
Use: "serve [dir]",
Short: "Preview a cloned folder in your browser",
Long: "serve runs a local static file server over a cloned folder so you can click\n" +
"through the mirror exactly as a visitor would. With no dir it serves the\n" +
"current directory.",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
dir := "."
if len(args) == 1 {
dir = args[0]
}
return runServe(cmd.Context(), dir, addr)
},
}
cmd.Flags().StringVarP(&addr, "addr", "a", "127.0.0.1:8800", "address to listen on")
return cmd
}
func runServe(ctx context.Context, dir, addr string) error {
info, err := os.Stat(dir)
if err != nil {
return fmt.Errorf("cannot serve %q: %w", dir, err)
}
if !info.IsDir() {
return fmt.Errorf("%q is not a directory", dir)
}
abs, _ := filepath.Abs(dir)
ln, err := net.Listen("tcp", addr)
if err != nil {
return fmt.Errorf("cannot listen on %s: %w", addr, err)
}
srv := &http.Server{Handler: http.FileServer(http.Dir(abs))}
fmt.Fprintln(os.Stderr, styleTitle.Render("kage serve")+" "+styleDim.Render(abs))
fmt.Fprintln(os.Stderr, " open "+styleAccent.Render("http://"+ln.Addr().String()))
fmt.Fprintln(os.Stderr, styleDim.Render(" press Ctrl-C to stop"))
srvErr := make(chan error, 1)
go func() { srvErr <- srv.Serve(ln) }()
select {
case err := <-srvErr:
if err != nil && err != http.ErrServerClosed {
return err
}
case <-ctx.Done():
shutdownCtx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
if err := srv.Shutdown(shutdownCtx); err != nil {
_ = srv.Close()
}
if err := <-srvErr; err != nil && err != http.ErrServerClosed {
return err
}
}
return nil
}