1package main
2
3import (
4 "context"
5 "fmt"
6 "os"
7 "os/signal"
8 "path/filepath"
9 "syscall"
10 "time"
11
12 "github.com/charmbracelet/soft-serve/server"
13 "github.com/charmbracelet/soft-serve/server/config"
14 "github.com/spf13/cobra"
15)
16
17var (
18 serveCmd = &cobra.Command{
19 Use: "serve",
20 Short: "Start the server",
21 Long: "Start the server",
22 Args: cobra.NoArgs,
23 RunE: func(cmd *cobra.Command, _ []string) error {
24 ctx := cmd.Context()
25
26 // Set up config
27 cfg := config.DefaultConfig()
28 if !cfg.Exist() {
29 if err := cfg.WriteConfig(); err != nil {
30 return fmt.Errorf("failed to write default config: %w", err)
31 }
32 }
33
34 ctx = config.WithContext(ctx, cfg)
35 cmd.SetContext(ctx)
36
37 // Create custom hooks directory if it doesn't exist
38 customHooksPath := filepath.Join(cfg.DataPath, "hooks")
39 if _, err := os.Stat(customHooksPath); err != nil && os.IsNotExist(err) {
40 os.MkdirAll(customHooksPath, os.ModePerm) // nolint: errcheck
41 // Generate update hook example without executable permissions
42 hookPath := filepath.Join(customHooksPath, "update.sample")
43 // nolint: gosec
44 if err := os.WriteFile(hookPath, []byte(updateHookExample), 0744); err != nil {
45 return fmt.Errorf("failed to generate update hook example: %w", err)
46 }
47 }
48
49 // Create log directory if it doesn't exist
50 logPath := filepath.Join(cfg.DataPath, "log")
51 if _, err := os.Stat(logPath); err != nil && os.IsNotExist(err) {
52 os.MkdirAll(logPath, os.ModePerm) // nolint: errcheck
53 }
54
55 s, err := server.NewServer(ctx)
56 if err != nil {
57 return fmt.Errorf("start server: %w", err)
58 }
59
60 done := make(chan os.Signal, 1)
61 lch := make(chan error, 1)
62 go func() {
63 defer close(lch)
64 defer close(done)
65 lch <- s.Start()
66 }()
67
68 signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
69 <-done
70
71 ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
72 defer cancel()
73 if err := s.Shutdown(ctx); err != nil {
74 return err
75 }
76
77 // wait for serve to finish
78 return <-lch
79 },
80 }
81)