Skip to content

Commit a644ee5

Browse files
authored
[plugins] Only create devbox.d files on add (#369)
## Summary This changes plugins so that `devbox.d` files are only created on `add` and not on other commands. Following discussion with @loreto I was going to return error if any of the files are missing, but I'm afraid this will backfire. Specifically there are plugin files that are non-essential to plugin. Two immediate examples: * nginx plugin creates a `web/index.html` example page. * php plugin creates a php-fpm config which is not needed if you don't want to use php-fpm. Currently this PR simply takes no action if a given file is missing. I think that's probably Ok for now. Some possible solutions: * We could mark certain files as "optional" but this would complicate the plugin json. * We could save some data in `devbox.d/devbox.lock` to keep track of plugins we've already generated files for so we don't go it again. * We could move optional files to `.devbox`. This makes sense for web/index.html but for some files like php-fpm.conf it doesn't. ## How was it tested? ```sh devbox add nginx rm devbox.d/nginx/nginx.conf devbox add nginx # verified it got recreated rm devbox.d/nginx/nginx.conf devbox shell # verified it was not recreated ```
1 parent 153d977 commit a644ee5

File tree

4 files changed

+58
-23
lines changed

4 files changed

+58
-23
lines changed

internal/impl/devbox.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ func InitConfig(dir string) (created bool, err error) {
5050
type Devbox struct {
5151
cfg *Config
5252
// configDir is the directory where the config file (devbox.json) resides
53-
configDir string
54-
writer io.Writer
53+
configDir string
54+
pluginManager *pkgcfg.Manager
55+
writer io.Writer
5556
}
5657

5758
// TODO savil. dir is technically path since it could be a dir or file
@@ -73,9 +74,10 @@ func Open(dir string, writer io.Writer) (*Devbox, error) {
7374
}
7475

7576
box := &Devbox{
76-
cfg: cfg,
77-
configDir: cfgDir,
78-
writer: writer,
77+
cfg: cfg,
78+
configDir: cfgDir,
79+
pluginManager: pkgcfg.NewManager(),
80+
writer: writer,
7981
}
8082
return box, nil
8183
}
@@ -108,6 +110,7 @@ func (d *Devbox) Add(pkgs ...string) error {
108110
return err
109111
}
110112

113+
d.pluginManager.ApplyOptions(pkgcfg.WithAddMode())
111114
if err := d.ensurePackagesAreInstalled(install); err != nil {
112115
return err
113116
}
@@ -473,7 +476,7 @@ func (d *Devbox) generateShellFiles() error {
473476
if err != nil {
474477
return err
475478
}
476-
return generateForShell(d.configDir, plan)
479+
return generateForShell(d.configDir, plan, d.pluginManager)
477480
}
478481

479482
func (d *Devbox) profileDir() (string, error) {

internal/impl/generate.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ var tmplFS embed.FS
2424

2525
var shellFiles = []string{"development.nix", "shell.nix"}
2626

27-
func generateForShell(rootPath string, plan *plansdk.ShellPlan) error {
27+
func generateForShell(rootPath string, plan *plansdk.ShellPlan, pluginManager *pkgcfg.Manager) error {
2828
outPath := filepath.Join(rootPath, ".devbox/gen")
2929

3030
for _, file := range shellFiles {
@@ -51,7 +51,7 @@ func generateForShell(rootPath string, plan *plansdk.ShellPlan) error {
5151

5252
if featureflag.PKGConfig.Enabled() {
5353
for _, pkg := range plan.DevPackages {
54-
if err := pkgcfg.CreateFilesAndShowReadme(pkg, rootPath); err != nil {
54+
if err := pluginManager.CreateFilesAndShowReadme(pkg, rootPath); err != nil {
5555
return err
5656
}
5757
}

internal/pkgcfg/manager.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package pkgcfg
2+
3+
type Manager struct {
4+
addMode bool
5+
}
6+
7+
type managerOption func(*Manager)
8+
9+
func NewManager(opts ...managerOption) *Manager {
10+
m := &Manager{}
11+
m.ApplyOptions(opts...)
12+
return m
13+
}
14+
15+
func WithAddMode() managerOption {
16+
return func(m *Manager) {
17+
m.addMode = true
18+
}
19+
}
20+
21+
func (m *Manager) ApplyOptions(opts ...managerOption) {
22+
for _, opt := range opts {
23+
opt(m)
24+
}
25+
}

internal/pkgcfg/pkgcfg.go

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ import (
1616
)
1717

1818
const (
19-
VirtenvBinPath = ".devbox/virtenv/bin"
20-
VirtenvPath = ".devbox/virtenv"
19+
devboxDirName = "devbox.d"
20+
devboxHiddenDirName = ".devbox"
21+
VirtenvBinPath = ".devbox/virtenv/bin"
22+
VirtenvPath = ".devbox/virtenv"
2123
)
2224

2325
type config struct {
@@ -30,15 +32,15 @@ type config struct {
3032
Services Services `json:"services"`
3133
}
3234

33-
func CreateFilesAndShowReadme(pkg, rootDir string) error {
35+
func (m *Manager) CreateFilesAndShowReadme(pkg, rootDir string) error {
3436
cfg, err := getConfig(pkg, rootDir)
3537
if err != nil {
3638
return err
3739
}
3840
debug.Log("Creating files for package %q create files", pkg)
3941
for filePath, contentPath := range cfg.CreateFiles {
4042

41-
if fileAlreadyExistsAndNotReplaceable(filePath) {
43+
if !m.shouldCreateFile(filePath) {
4244
continue
4345
}
4446

@@ -65,10 +67,10 @@ func CreateFilesAndShowReadme(pkg, rootDir string) error {
6567
}
6668
var buf bytes.Buffer
6769
if err = t.Execute(&buf, map[string]string{
68-
"DevboxDir": filepath.Join(rootDir, "devbox.d", pkg),
69-
"DevboxDirRoot": filepath.Join(rootDir, "devbox.d"),
70+
"DevboxDir": filepath.Join(rootDir, devboxDirName, pkg),
71+
"DevboxDirRoot": filepath.Join(rootDir, devboxDirName),
7072
"DevboxProfileDefault": filepath.Join(rootDir, nix.ProfilePath),
71-
"Virtenv": filepath.Join(rootDir, ".devbox", "virtenv", pkg),
73+
"Virtenv": filepath.Join(rootDir, devboxHiddenDirName, "virtenv", pkg),
7274
}); err != nil {
7375
return errors.WithStack(err)
7476
}
@@ -135,10 +137,10 @@ func buildConfig(pkg, rootDir, content string) (*config, error) {
135137
}
136138
var buf bytes.Buffer
137139
if err = t.Execute(&buf, map[string]string{
138-
"DevboxDir": filepath.Join(rootDir, "devbox.d", pkg),
139-
"DevboxDirRoot": filepath.Join(rootDir, "devbox.d"),
140+
"DevboxDir": filepath.Join(rootDir, devboxDirName, pkg),
141+
"DevboxDirRoot": filepath.Join(rootDir, devboxDirName),
140142
"DevboxProfileDefault": filepath.Join(rootDir, nix.ProfilePath),
141-
"Virtenv": filepath.Join(rootDir, ".devbox", "virtenv", pkg),
143+
"Virtenv": filepath.Join(rootDir, devboxHiddenDirName, "virtenv", pkg),
142144
}); err != nil {
143145
return nil, errors.WithStack(err)
144146
}
@@ -179,12 +181,17 @@ func createSymlink(root, filePath string) error {
179181
return nil
180182
}
181183

182-
func fileAlreadyExistsAndNotReplaceable(filePath string) bool {
183-
// Hidden .devbox files are always replaceable
184-
if strings.HasPrefix(filePath, ".devbox") {
184+
func (m *Manager) shouldCreateFile(filePath string) bool {
185+
// Only create devboxDir files in add mode.
186+
if strings.Contains(filePath, devboxDirName) && !m.addMode {
185187
return false
186188
}
189+
190+
// Hidden .devbox files are always replaceable, so ok to recreate
191+
if strings.Contains(filePath, devboxHiddenDirName) {
192+
return true
193+
}
187194
_, err := os.Stat(filePath)
188-
// File doesn't exist, so we should create it
189-
return err == nil
195+
// File doesn't exist, so we should create it.
196+
return os.IsNotExist(err)
190197
}

0 commit comments

Comments
 (0)