| 66 | } |
| 67 | |
| 68 | func runWebStart(cmd *cobra.Command, _ []string) error { |
| 69 | absDir, err := filepath.Abs(GetGlobalFlags().TaskDir) |
| 70 | if err != nil { |
| 71 | return fmt.Errorf("invalid directory: %w", err) |
| 72 | } |
| 73 | |
| 74 | info, err := os.Stat(absDir) |
| 75 | if err != nil || !info.IsDir() { |
| 76 | return fmt.Errorf("not a valid directory: %s", absDir) |
| 77 | } |
| 78 | |
| 79 | // Read from viper to support config file values |
| 80 | port := viper.GetInt("web.port") |
| 81 | open := viper.GetBool("web.auto_open_browser") |
| 82 | flags := GetGlobalFlags() |
| 83 | |
| 84 | srv := web.NewServer(web.Config{ |
| 85 | Port: port, |
| 86 | ScanDir: absDir, |
| 87 | Dev: webDev, |
| 88 | Verbose: flags.Verbose, |
| 89 | ReadOnly: viper.GetBool("web.readonly"), |
| 90 | Version: FullVersion(), |
| 91 | Phases: parsePhasesForWeb(), |
| 92 | ListProjects: buildListProjects(), |
| 93 | ResolveProject: buildResolveProject(), |
| 94 | }) |
| 95 | |
| 96 | ctx, cancel := signal.NotifyContext( |
| 97 | context.Background(), |
| 98 | syscall.SIGINT, syscall.SIGTERM, |
| 99 | ) |
| 100 | defer cancel() |
| 101 | |
| 102 | if open { |
| 103 | go openBrowser(fmt.Sprintf("http://localhost:%d", port)) |
| 104 | } |
| 105 | |
| 106 | return srv.Start(ctx) |
| 107 | } |
| 108 | |
| 109 | // parsePhasesForWeb reads phases from viper config and converts to web.PhaseInfo. |
| 110 | func parsePhasesForWeb() []web.PhaseInfo { |