|
| 1 | +package marimo |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "os/exec" |
| 6 | + "strconv" |
| 7 | + |
| 8 | + "github.com/loft-sh/log" |
| 9 | + |
| 10 | + "github.com/loft-sh/devpod/pkg/command" |
| 11 | + "github.com/loft-sh/devpod/pkg/config" |
| 12 | + "github.com/loft-sh/devpod/pkg/ide" |
| 13 | + "github.com/loft-sh/devpod/pkg/single" |
| 14 | +) |
| 15 | + |
| 16 | +const DefaultServerPort = 10710 |
| 17 | +const ( |
| 18 | + OpenOption = "OPEN" |
| 19 | + AccessToken = "ACCESS_TOKEN" |
| 20 | + BindAddressOption = "BIND_ADDRESS" |
| 21 | +) |
| 22 | + |
| 23 | +var Options = ide.Options{ |
| 24 | + BindAddressOption: { |
| 25 | + Name: BindAddressOption, |
| 26 | + Description: "The address to bind the server to locally. E.g. 0.0.0.0:12345", |
| 27 | + Default: "", |
| 28 | + }, |
| 29 | + AccessToken: { |
| 30 | + Name: AccessToken, |
| 31 | + Description: "Access token to authenticate with the server", |
| 32 | + Default: "NhLpVl4re5PFd3QRFxvQ", |
| 33 | + }, |
| 34 | + OpenOption: { |
| 35 | + Name: OpenOption, |
| 36 | + Description: "If DevPod should automatically open the browser", |
| 37 | + Default: "true", |
| 38 | + Enum: []string{ |
| 39 | + "true", |
| 40 | + "false", |
| 41 | + }, |
| 42 | + }, |
| 43 | +} |
| 44 | + |
| 45 | +type Server struct { |
| 46 | + opts map[string]config.OptionValue |
| 47 | + userName string |
| 48 | + workspaceFolder string |
| 49 | + log log.Logger |
| 50 | +} |
| 51 | + |
| 52 | +func NewServer(workspaceFolder, userName string, opts map[string]config.OptionValue, log log.Logger) *Server { |
| 53 | + return &Server{ |
| 54 | + opts: opts, |
| 55 | + workspaceFolder: workspaceFolder, |
| 56 | + userName: userName, |
| 57 | + log: log, |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +func (s *Server) Install() error { |
| 62 | + if command.ExistsForUser("marimo", s.userName) { |
| 63 | + return nil |
| 64 | + } |
| 65 | + |
| 66 | + // check if pip3 exists |
| 67 | + baseCommand := "" |
| 68 | + if command.ExistsForUser("pip3", s.userName) { |
| 69 | + baseCommand = "pip3" |
| 70 | + } else if command.ExistsForUser("pip", s.userName) { |
| 71 | + baseCommand = "pip" |
| 72 | + } else { |
| 73 | + return fmt.Errorf("seems like neither pip3 nor pip exists, please make sure to install python correctly") |
| 74 | + } |
| 75 | + |
| 76 | + // install notebook command |
| 77 | + runCommand := fmt.Sprintf("%s install marimo", baseCommand) |
| 78 | + args := []string{} |
| 79 | + if s.userName != "" { |
| 80 | + args = append(args, "su", s.userName, "-c", runCommand) |
| 81 | + } else { |
| 82 | + args = append(args, "sh", "-c", runCommand) |
| 83 | + } |
| 84 | + |
| 85 | + // install |
| 86 | + s.log.Infof("Installing marimo...") |
| 87 | + out, err := exec.Command(args[0], args[1:]...).CombinedOutput() |
| 88 | + if err != nil { |
| 89 | + return fmt.Errorf("error installing marimo: %w", command.WrapCommandError(out, err)) |
| 90 | + } |
| 91 | + return s.start() |
| 92 | +} |
| 93 | + |
| 94 | +func (s *Server) start() error { |
| 95 | + return single.Single("marimo.pid", func() (*exec.Cmd, error) { |
| 96 | + s.log.Infof("Starting marimo in background...") |
| 97 | + token := Options.GetValue(s.opts, AccessToken) |
| 98 | + runCommand := fmt.Sprintf("marimo edit --headless --host 0.0.0.0 --port %s --token-password %s", strconv.Itoa(DefaultServerPort), token) |
| 99 | + args := []string{} |
| 100 | + if s.userName != "" { |
| 101 | + args = append(args, "su", s.userName, "-l", "-c", runCommand) |
| 102 | + } else { |
| 103 | + args = append(args, "sh", "-l", "-c", runCommand) |
| 104 | + } |
| 105 | + cmd := exec.Command(args[0], args[1:]...) |
| 106 | + cmd.Dir = s.workspaceFolder |
| 107 | + return cmd, nil |
| 108 | + }) |
| 109 | +} |
0 commit comments