diff --git a/docs/app/docs/devbox_examples/languages/php.md b/docs/app/docs/devbox_examples/languages/php.md index 6c52173b80d..7cedb128ed1 100644 --- a/docs/app/docs/devbox_examples/languages/php.md +++ b/docs/app/docs/devbox_examples/languages/php.md @@ -53,7 +53,7 @@ Use `devbox services start|stop php-fpm` to start PHP-FPM in the background. ```bash PHPFPM_PORT=8082 PHPFPM_ERROR_LOG_FILE={PROJECT_DIR}/.devbox/virtenv/php/php-fpm.log -PHPFPM_PID_FILE={PROJECT_DIR}/.devbox/virtenv/php/php-fpm.log +PHPFPM_PID_FILE={PROJECT_DIR}/.devbox/virtenv/php/php-fpm.pid PHPRC={PROJECT_DIR}/devbox.d/php/php.ini ``` @@ -62,4 +62,4 @@ PHPRC={PROJECT_DIR}/devbox.d/php/php.ini * {PROJECT_DIR}/devbox.d/php81/php-fpm.conf * {PROJECT_DIR}/devbox.d/php81/php.ini -You can modify these file to configure PHP or your PHP-FPM server +You can modify these files to configure PHP or your PHP-FPM server diff --git a/internal/impl/devbox.go b/internal/impl/devbox.go index c5fe22ece9b..e63d9deea5c 100644 --- a/internal/impl/devbox.go +++ b/internal/impl/devbox.go @@ -499,7 +499,7 @@ func (d *Devbox) Services() (services.Services, error) { return nil, err } - userSvcs := services.FromProcessComposeYaml(d.projectDir) + userSvcs := services.FromUserProcessCompose(d.projectDir) svcSet := lo.Assign(pluginSvcs, userSvcs) keys := make([]string, 0, len(svcSet)) @@ -514,7 +514,6 @@ func (d *Devbox) Services() (services.Services, error) { } return result, nil - } func (d *Devbox) StartServices(ctx context.Context, serviceNames ...string) error { diff --git a/internal/plugin/files.go b/internal/plugin/files.go index a5a22e404a4..7f1f24dce62 100644 --- a/internal/plugin/files.go +++ b/internal/plugin/files.go @@ -18,11 +18,11 @@ func getConfigIfAny(pkg *nix.Input, projectDir string) (*config, error) { return nil, errors.WithStack(err) } - // Try to find perfect match first for _, file := range configFiles { if file.IsDir() || strings.HasSuffix(file.Name(), ".go") { continue } + // Try to find perfect match first content, err := plugins.BuiltIn.ReadFile(file.Name()) if err != nil { return nil, errors.WithStack(err) diff --git a/internal/plugin/info.go b/internal/plugin/info.go index 6f65cd3b935..f8d8392bb8a 100644 --- a/internal/plugin/info.go +++ b/internal/plugin/info.go @@ -63,15 +63,19 @@ func printReadme(cfg *config, w io.Writer, markdown bool) error { } func printServices(cfg *config, w io.Writer, markdown bool) error { - if len(cfg.Services) == 0 { + svcs, err := cfg.Services() + if err != nil { + return errors.WithStack(err) + } + if len(svcs) == 0 { return nil } services := "" - for _, service := range cfg.Services { + for _, service := range svcs { services += fmt.Sprintf("* %[1]s\n", service.Name) } - _, err := fmt.Fprintf( + _, err = fmt.Fprintf( w, "%sServices:\n%s\nUse `devbox services start|stop [service]` to interact with services\n\n", lo.Ternary(markdown, "### ", ""), diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index 4a2dfd299d3..c82ec962ba2 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -43,7 +43,6 @@ type config struct { Packages []string `json:"packages"` Env map[string]string `json:"env"` Readme string `json:"readme"` - Services services.Services `json:"services"` Shell struct { // InitHook contains commands that will run at shell startup. @@ -60,6 +59,13 @@ func (c *config) ProcessComposeYaml() (string, bool) { return "", false } +func (c *config) Services() (services.Services, error) { + if file, ok := c.ProcessComposeYaml(); ok { + return services.FromProcessCompose(file) + } + return nil, nil +} + func (m *Manager) Include(included string) error { name, err := m.parseInclude(included) if err != nil { diff --git a/internal/plugin/services.go b/internal/plugin/services.go index abb942a2f24..eda0757d649 100644 --- a/internal/plugin/services.go +++ b/internal/plugin/services.go @@ -4,17 +4,18 @@ package plugin import ( + "fmt" + "os" + "go.jetpack.io/devbox/internal/nix" "go.jetpack.io/devbox/internal/services" ) -// TODO: this should have PluginManager as receiver so we can build once with -// pkgs, includes, etc func (m *Manager) GetServices( pkgs []*nix.Input, includes []string, ) (services.Services, error) { - svcs := services.Services{} + allSvcs := services.Services{} allPkgs := append([]*nix.Input(nil), pkgs...) for _, include := range includes { @@ -34,15 +35,15 @@ func (m *Manager) GetServices( continue } - if file, ok := conf.ProcessComposeYaml(); ok { - svc := services.Service{ - Name: conf.Name, - Env: conf.Env, - ProcessComposePath: file, - } - svcs[conf.Name] = svc + svcs, err := conf.Services() + if err != nil { + fmt.Fprintf(os.Stderr, "error reading services in plugin \"%s\", skipping", conf.Name) + continue + } + for name, svc := range svcs { + allSvcs[name] = svc } - } - return svcs, nil + + return allSvcs, nil } diff --git a/internal/services/config.go b/internal/services/config.go index 7ce47ba7ddd..5eed5b06a22 100644 --- a/internal/services/config.go +++ b/internal/services/config.go @@ -14,13 +14,13 @@ import ( "go.jetpack.io/devbox/internal/cuecfg" ) -func FromProcessComposeYaml(projectDir string) Services { - // TODO need to handle if a filepath is passed in +func FromUserProcessCompose(projectDir string) Services { processComposeYaml := lookupProcessCompose(projectDir, "") if processComposeYaml == "" { return nil } - userSvcs, err := readProcessCompose(processComposeYaml) + + userSvcs, err := FromProcessCompose(processComposeYaml) if err != nil { fmt.Fprintf(os.Stderr, "error reading process-compose.yaml: %s, skipping", err) return nil @@ -28,7 +28,7 @@ func FromProcessComposeYaml(projectDir string) Services { return userSvcs } -func readProcessCompose(path string) (Services, error) { +func FromProcessCompose(path string) (Services, error) { processCompose := &types.Project{} services := Services{} err := errors.WithStack(cuecfg.ParseFile(path, processCompose)) diff --git a/internal/services/manager.go b/internal/services/manager.go index da0559bcb2f..0c524621698 100644 --- a/internal/services/manager.go +++ b/internal/services/manager.go @@ -167,9 +167,7 @@ func StartProcessManager( } for _, s := range availableServices { - if file, hasComposeYaml := s.ProcessComposeYaml(); hasComposeYaml { - flags = append(flags, "-f", file) - } + flags = append(flags, "-f", s.ProcessComposePath) } if processComposeBackground { diff --git a/internal/services/services.go b/internal/services/services.go index cfa36203063..6bce565f2f6 100644 --- a/internal/services/services.go +++ b/internal/services/services.go @@ -1,105 +1,11 @@ // Copyright 2023 Jetpack Technologies Inc and contributors. All rights reserved. // Use of this source code is governed by the license in the LICENSE file. -//lint:file-ignore U1000 Ignore unused function temporarily for debugging package services -import ( - "encoding/json" - "fmt" - "io" - "os" - - "github.com/a8m/envsubst" - "github.com/fatih/color" - "github.com/pkg/errors" - - "go.jetpack.io/devbox/internal/envir" -) - -type Services map[string]Service +type Services map[string]Service // name -> Service type Service struct { - Name string `json:"name"` - Env map[string]string `json:"-"` - RawPort string `json:"port"` - Start string `json:"start"` - Stop string `json:"stop"` + Name string ProcessComposePath string } - -// TODO: (john) Since moving to process-compose, our services no longer use the old `toggleServices` function. We'll need to clean a lot of this up in a later PR. - -type serviceAction int - -const ( - startService serviceAction = iota - stopService -) - -func printProxyURL(w io.Writer, services Services) error { // TODO: remove it? - if !envir.IsDevboxCloud() { - return nil - } - - hostname, err := os.Hostname() - if err != nil { - return errors.WithStack(err) - } - - printGeneric := false - for _, service := range services { - if port, _ := service.Port(); port != "" { - color.New(color.FgHiGreen).Fprintf( - w, - "To access %s on this vm use: %s-%s.svc.devbox.sh\n", - service.Name, - hostname, - port, - ) - } else { - printGeneric = true - } - } - - if printGeneric { - color.New(color.FgHiGreen).Fprintf( - w, - "To access other services on this vm use: %s-.svc.devbox.sh\n", - hostname, - ) - } - return nil -} - -func (s *Service) Port() (string, error) { - if s.RawPort == "" { - return "", nil - } - return envsubst.String(s.RawPort) -} - -func (s *Service) ProcessComposeYaml() (string, bool) { - return s.ProcessComposePath, true -} - -func (s *Service) StartName() string { - return fmt.Sprintf("%s-service-start", s.Name) -} - -func (s *Service) StopName() string { - return fmt.Sprintf("%s-service-stop", s.Name) -} - -func (s *Services) UnmarshalJSON(b []byte) error { - var m map[string]Service - if err := json.Unmarshal(b, &m); err != nil { - return err - } - *s = make(Services) - for name, svc := range m { - svc.Name = name - (*s)[name] = svc - } - return nil -} diff --git a/internal/wrapnix/wrapper.go b/internal/wrapnix/wrapper.go index 3583881ee22..2b80822969d 100644 --- a/internal/wrapnix/wrapper.go +++ b/internal/wrapnix/wrapper.go @@ -17,7 +17,6 @@ import ( "go.jetpack.io/devbox/internal/cmdutil" "go.jetpack.io/devbox/internal/nix" "go.jetpack.io/devbox/internal/plugin" - "go.jetpack.io/devbox/internal/services" ) type devboxer interface { @@ -25,7 +24,6 @@ type devboxer interface { ShellEnvHash(ctx context.Context) (string, error) ShellEnvHashKey() string ProjectDir() string - Services() (services.Services, error) } //go:embed wrapper.sh.tmpl @@ -39,11 +37,6 @@ func CreateWrappers(ctx context.Context, devbox devboxer) error { return err } - services, err := devbox.Services() - if err != nil { - return err - } - // Remove all old wrappers _ = os.RemoveAll(filepath.Join(devbox.ProjectDir(), plugin.WrapperPath)) @@ -52,28 +45,6 @@ func CreateWrappers(ctx context.Context, devbox devboxer) error { _ = os.MkdirAll(destPath, 0755) bashPath := cmdutil.GetPathOrDefault("bash", "/bin/bash") - for _, service := range services { - if err = createWrapper(&createWrapperArgs{ - devboxer: devbox, - BashPath: bashPath, - Command: service.Start, - Env: service.Env, - ShellEnvHash: shellEnvHash, - destPath: filepath.Join(destPath, service.StartName()), - }); err != nil { - return err - } - if err = createWrapper(&createWrapperArgs{ - devboxer: devbox, - BashPath: bashPath, - Command: service.Stop, - Env: service.Env, - ShellEnvHash: shellEnvHash, - destPath: filepath.Join(destPath, service.StopName()), - }); err != nil { - return err - } - } bins, err := devbox.NixBins(ctx) if err != nil { diff --git a/plugins/README.md b/plugins/README.md index 9cb05892b49..7f12ec281e0 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -38,21 +38,16 @@ Plugins are defined as JSON Template files, using the following schema: "": "" }, "create_files": { - "": "", + "": "" }, "init_hook": [ "" - ], - "services": { - "service_name": { - "start": "", - "stop": "", - "port": - } - } + ] } ``` +A plugin can define services by adding a `process-compose.yaml` file in its `create_files` stanza. See process compose [docs](https://github.com/F1bonacc1/process-compose) or existing plugins in this directory for examples. + ### Plugin Lifecycle Plugins are activated whenever a developer runs `devbox shell`, runs a script with `devbox run`, or starts a service using `devbox services start|restart`. The lifecycle of a devbox shell with plugins goes in the following order. @@ -122,12 +117,6 @@ You should use this to copy starter config files or templates needed to run the A single `bash` command or list of `bash` commands that should run before the user's shell is initialized. This will run every time a shell is started, so you should avoid any resource heavy or long running processes in this step. -#### `services` *object* - -A map of services that your plugin exposes to the user through `devbox services`. Services should have a `start` command and `stop` command defined so that Devbox can safely start and stop your service. You can optionally specify a `port` for Devbox to use along with automatic port forwarding in Devbox Cloud - -For more details, see our [Services Documentation](https://www.jetpack.io/devbox/docs/guides/services/) - ## Tips for Writing Plugins * Only add plugins for packages that require configuration to work with Devbox. diff --git a/plugins/apacheHttpd.json b/plugins/apacheHttpd.json index 2734426b55e..eff221e957e 100644 --- a/plugins/apacheHttpd.json +++ b/plugins/apacheHttpd.json @@ -1,6 +1,6 @@ { "name": "apache", - "version": "0.0.1", + "version": "0.0.2", "match": "^(apache|apacheHttpd)$", "readme": "If you with to edit the config file, please copy it out of the .devbox directory.", "env": { @@ -14,12 +14,5 @@ "{{ .DevboxDir }}/httpd.conf": "apache/httpd.conf", "{{ .DevboxDirRoot }}/web/index.html": "web/index.html", "{{ .Virtenv }}/process-compose.yaml": "apache/process-compose.yaml" - }, - "services": { - "apache": { - "port": "$HTTPD_PORT", - "start": "apachectl start -f $HTTPD_CONFDIR/httpd.conf", - "stop": "apachectl stop -f $HTTPD_CONFDIR/httpd.conf" - } } } diff --git a/plugins/caddy.json b/plugins/caddy.json index cdaf6068030..f3bffecddc7 100644 --- a/plugins/caddy.json +++ b/plugins/caddy.json @@ -1,6 +1,6 @@ { "name": "caddy", - "version": "0.0.2", + "version": "0.0.3", "readme": "You can customize the config used by the caddy service by modifying the Caddyfile in devbox.d/caddy, or by changing the CADDY_CONFIG environment variable to point to a custom config. The custom config must be either JSON or Caddyfile format.", "env": { "CADDY_CONFIG": "{{ .DevboxDir }}/Caddyfile", @@ -11,11 +11,5 @@ "{{ .DevboxDir }}/Caddyfile": "caddy/Caddyfile", "{{ .DevboxDirRoot }}/web/index.html": "web/index.html", "{{ .Virtenv }}/process-compose.yaml": "caddy/process-compose.yaml" - }, - "services": { - "caddy": { - "start": "caddy start --config $CADDY_CONFIG", - "stop": "caddy stop --config $CADDY_CONFIG" - } } } \ No newline at end of file diff --git a/plugins/mariadb.json b/plugins/mariadb.json index 6d9e368445b..ca321975e61 100644 --- a/plugins/mariadb.json +++ b/plugins/mariadb.json @@ -1,6 +1,6 @@ { "name": "mariadb", - "version": "0.0.1", + "version": "0.0.2", "match": "^mariadb_?[0-9]*$", "readme": "* This plugin wraps mysqld and mysql_install_db to work in your local project\n* This plugin will create a new database for your project in MYSQL_DATADIR if one doesn't exist on shell init\n* Use mysqld to manually start the server, and `mysqladmin -u root shutdown` to manually stop it", "env": { @@ -23,11 +23,5 @@ "init_hook": [ "bash {{ .Virtenv }}/setup_db.sh" ] - }, - "services": { - "mariadb": { - "start": "mysqld 2> $MYSQL_HOME/mysql.log & MYSQL_PID=$! && echo 'Starting mysqld... check mariadb_logs for details'", - "stop": "mysqladmin -u root shutdown" - } } } \ No newline at end of file diff --git a/plugins/nginx.json b/plugins/nginx.json index cdd04b3de94..4d5d3efa8cc 100644 --- a/plugins/nginx.json +++ b/plugins/nginx.json @@ -1,6 +1,6 @@ { "name": "nginx", - "version": "0.0.1", + "version": "0.0.2", "readme": "nginx can be configured with env variables\n\nTo customize:\n* Use $NGINX_CONFDIR to change the configuration directory\n* Use $NGINX_LOGDIR to change the log directory\n* Use $NGINX_PIDDIR to change the pid directory\n* Use $NGINX_RUNDIR to change the run directory\n* Use $NGINX_SITESDIR to change the sites directory\n* Use $NGINX_TMPDIR to change the tmp directory. Use $NGINX_USER to change the user\n* Use $NGINX_GROUP to customize.", "env": { "NGINX_CONFDIR": "{{ .DevboxDir }}/nginx.conf", @@ -13,11 +13,5 @@ "{{ .DevboxDir }}/nginx.conf": "nginx/nginx.conf", "{{ .DevboxDir }}/fastcgi.conf": "nginx/fastcgi.conf", "{{ .DevboxDirRoot }}/web/index.html": "web/index.html" - }, - "services": { - "nginx": { - "start": "nginx -p $NGINX_PATH_PREFIX -c $NGINX_CONFDIR -e error.log -g \"pid nginx.pid;\"", - "stop": "pkill nginx" - } } } diff --git a/plugins/php.json b/plugins/php.json index 4dbfec902f6..7faced71980 100644 --- a/plugins/php.json +++ b/plugins/php.json @@ -1,6 +1,6 @@ { "name": "php", - "version": "0.0.1", + "version": "0.0.2", "match": "^php[0-9]*$", "readme": "PHP is compiled with default extensions. If you would like to use non-default extensions you can add them with devbox add php81Extensions.{extension} . For example, for the memcache extension you can do `devbox add php81Extensions.memcached`.", "packages": [ @@ -18,11 +18,5 @@ "{{ .DevboxDir }}/php.ini": "php/php.ini", "{{ .Virtenv }}/process-compose.yaml": "php/process-compose.yaml", "{{ .Virtenv }}/flake.nix": "php/flake.nix" - }, - "services": { - "php-fpm": { - "start": "php-fpm -y {{ .DevboxDir }}/php-fpm.conf", - "stop": "pkill php-fpm" - } } } diff --git a/plugins/postgresql.json b/plugins/postgresql.json index 3da49c6ad8d..7504ed3abf8 100644 --- a/plugins/postgresql.json +++ b/plugins/postgresql.json @@ -1,6 +1,6 @@ { "name": "postgresql", - "version": "0.0.1", + "version": "0.0.2", "match": "^postgresql(_[0-9]+)?$", "readme": "To initialize the database run `initdb`.", "env": { @@ -10,11 +10,5 @@ "create_files": { "{{ .Virtenv }}/data": "", "{{ .Virtenv }}/process-compose.yaml": "postgresql/process-compose.yaml" - }, - "services": { - "postgresql": { - "start": "pg_ctl start -l {{ .Virtenv }}/logfile -o \"-k {{ .Virtenv }}\"", - "stop": "pg_ctl stop" - } } } diff --git a/plugins/redis.json b/plugins/redis.json index 3714e3a2051..1b636ac186b 100644 --- a/plugins/redis.json +++ b/plugins/redis.json @@ -1,6 +1,6 @@ { "name": "redis", - "version": "0.0.1", + "version": "0.0.2", "match": "^redis$", "readme": "Running `devbox services start redis` will start redis as a daemon in the background. \n\nYou can manually start Redis in the foreground by running `redis-server $REDIS_CONF --port $REDIS_PORT`. \n\nLogs, pidfile, and data dumps are stored in `.devbox/virtenv/redis`. You can change this by modifying the `dir` directive in `devbox.d/redis/redis.conf`", "env": { @@ -10,11 +10,5 @@ "create_files": { "{{ .DevboxDir }}/redis.conf": "redis/redis.conf", "{{ .Virtenv }}/process-compose.yaml": "redis/process-compose.yaml" - }, - "services": { - "redis": { - "start": "redis-server $REDIS_CONF --port $REDIS_PORT --daemonize yes", - "stop": "redis-cli shutdown" - } } } \ No newline at end of file diff --git a/plugins/ruby.json b/plugins/ruby.json index 6fbadca56b1..aeedc0f6ec3 100644 --- a/plugins/ruby.json +++ b/plugins/ruby.json @@ -5,7 +5,6 @@ "env": { "RUBY_CONFDIR": "{{ .Virtenv }}", "GEMRC": "{{ .Virtenv }}/.gemrc", - "GEM_HOME": "{{ .Virtenv }}", - "PATH": "{{ .Virtenv }}/bin:$PATH" + "GEM_HOME": "{{ .Virtenv }}" } }