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, err := config.NewConfig("")
28 if err != nil {
29 return err
30 }
31
32 ctx = config.WithContext(ctx, cfg)
33 cmd.SetContext(ctx)
34
35 // Create custom hooks directory if it doesn't exist
36 customHooksPath := filepath.Join(cfg.DataPath, "hooks")
37 if _, err := os.Stat(customHooksPath); err != nil && os.IsNotExist(err) {
38 os.MkdirAll(customHooksPath, os.ModePerm) // nolint: errcheck
39 // Generate update hook example without executable permissions
40 hookPath := filepath.Join(customHooksPath, "update.sample")
41 // nolint: gosec
42 if err := os.WriteFile(hookPath, []byte(updateHookExample), 0744); err != nil {
43 return fmt.Errorf("failed to generate update hook example: %w", err)
44 }
45 }
46
47 // Create log directory if it doesn't exist
48 logPath := filepath.Join(cfg.DataPath, "log")
49 if _, err := os.Stat(logPath); err != nil && os.IsNotExist(err) {
50 os.MkdirAll(logPath, os.ModePerm) // nolint: errcheck
51 }
52
53 s, err := server.NewServer(ctx)
54 if err != nil {
55 return fmt.Errorf("start server: %w", err)
56 }
57
58 done := make(chan os.Signal, 1)
59 lch := make(chan error, 1)
60 go func() {
61 defer close(lch)
62 defer close(done)
63 lch <- s.Start()
64 }()
65
66 signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
67 <-done
68
69 ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
70 defer cancel()
71 if err := s.Shutdown(ctx); err != nil {
72 return err
73 }
74
75 // wait for serve to finish
76 return <-lch
77 },
78 }
79)