Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 31 additions & 7 deletions devbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/pkg/errors"
"go.jetpack.io/devbox/boxcli/usererr"
"go.jetpack.io/devbox/cuecfg"
"go.jetpack.io/devbox/debug"
"go.jetpack.io/devbox/docker"
"go.jetpack.io/devbox/nix"
"go.jetpack.io/devbox/pkgslice"
Expand All @@ -33,17 +34,19 @@ func InitConfig(dir string) (created bool, err error) {
// Devbox provides an isolated development environment that contains a set of
// Nix packages.
type Devbox struct {
cfg *Config
cfg *Config
// srcDir is the directory where the config file (devbox.json) resides
srcDir string
}

// Open opens a devbox by reading the config file in dir.
func Open(dir string) (*Devbox, error) {
cfgPath := filepath.Join(dir, configFilename)

if !plansdk.FileExists(cfgPath) {
return nil, missingDevboxJSONError(dir)
cfgDir, err := findConfigDir(dir)
if err != nil {
return nil, err
}
cfgPath := filepath.Join(cfgDir, configFilename)

cfg, err := ReadConfig(cfgPath)
if err != nil {
Expand All @@ -52,7 +55,7 @@ func Open(dir string) (*Devbox, error) {

box := &Devbox{
cfg: cfg,
srcDir: dir,
srcDir: cfgDir,
}
return box, nil
}
Expand Down Expand Up @@ -226,7 +229,7 @@ func (d *Devbox) generateBuildFiles() error {
func missingDevboxJSONError(dir string) error {

// We try to prettify the `dir` before printing
if dir == "." {
if dir == "." || dir == "" {
dir = "this directory"
} else {
// Instead of a long absolute directory, print the relative directory
Expand All @@ -240,5 +243,26 @@ func missingDevboxJSONError(dir string) error {
}
}
}
return usererr.New("No devbox.json found in %s. Did you run `devbox init` yet?", dir)
return usererr.New("No devbox.json found in %s, or any parent directories. Did you run `devbox init` yet?", dir)
}

func findConfigDir(dir string) (string, error) {

// Sanitize the directory and use the absolute path as canonical form
cur, err := filepath.Abs(dir)
if err != nil {
return "", errors.WithStack(err)
}

for cur != "/" {
debug.Log("finding %s in dir: %s\n", configFilename, cur)
if plansdk.FileExists(filepath.Join(cur, configFilename)) {
return cur, nil
}
cur = filepath.Dir(cur)
}
if plansdk.FileExists(filepath.Join(cur, configFilename)) {
return cur, nil
}
return "", missingDevboxJSONError(dir)
}
12 changes: 12 additions & 0 deletions devbox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/bmatcuk/doublestar/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.jetpack.io/devbox/planner/plansdk"
)

Expand All @@ -28,6 +29,10 @@ func TestDevbox(t *testing.T) {
}

func testExample(t *testing.T, testPath string) {

currentDir, err := os.Getwd()
require.New(t).NoError(err)

baseDir := filepath.Dir(testPath)
t.Run(baseDir, func(t *testing.T) {
assert := assert.New(t)
Expand All @@ -36,6 +41,13 @@ func testExample(t *testing.T, testPath string) {

box, err := Open(baseDir)
assert.NoErrorf(err, "%s should be a valid devbox project", baseDir)

// Just for tests, we make srcDir be a relative path so that the paths in plan.json
// of various test cases have relative paths. Absolute paths are a no-go because they'd
// be of the form `/Users/savil/...`, which are not generalized and cannot be checked in.
box.srcDir, err = filepath.Rel(currentDir, box.srcDir)
assert.NoErrorf(err, "expect to construct relative path from %s relative to base %s", box.srcDir, currentDir)

plan, err := box.ShellPlan()
assert.NoError(err, "devbox plan should not fail")

Expand Down