Documentation
¶
Overview ¶
Package workspace provides project root detection by walking up from a starting directory to find marker files (.gtb/manifest.yaml, go.mod, .git).
This is a utility package — it has no integration with Props or the command lifecycle. Tool authors use it to scope commands to the current project context.
Usage ¶
ws, err := workspace.DetectFromCWD(afero.NewOsFs(), workspace.DefaultMarkers...)
if err != nil {
return errors.Wrap(err, "not inside a project")
}
fmt.Println("Project root:", ws.Root)
Index ¶
Examples ¶
Constants ¶
const DefaultMaxDepth = 100
DefaultMaxDepth is the maximum number of parent directories to search before giving up. Prevents runaway scanning on deeply nested paths.
Variables ¶
var DefaultMarkers = []string{
".gtb/manifest.yaml",
"go.mod",
".git",
}
DefaultMarkers is the standard set of marker files used to detect project boundaries. Checked in order — the first match wins.
var ErrNotFound = errors.New("workspace not found: no marker file detected")
ErrNotFound is returned when no marker file is found before reaching the filesystem root or the max depth.
Functions ¶
This section is empty.
Types ¶
type Option ¶
type Option func(*detectConfig)
Option configures the Detect function.
func WithMaxDepth ¶
WithMaxDepth sets the maximum number of parent directories to search. Default: DefaultMaxDepth (100).
type Workspace ¶
type Workspace struct {
// Root is the absolute path to the project root directory.
Root string
// Marker is the marker file or directory that was found
// (e.g. ".gtb/manifest.yaml", "go.mod", ".git").
Marker string
}
Workspace represents a detected project boundary.
func Detect ¶
Detect walks up from startDir looking for any of the given marker files. Returns the first match. Returns ErrNotFound if no marker is found before reaching the filesystem root or the max depth.
Markers are checked in order at each directory level — the first match wins. This means ".gtb/manifest.yaml" takes precedence over "go.mod" when using DefaultMarkers.
Example ¶
package main
import (
"fmt"
"github.com/spf13/afero"
"github.com/phpboyscout/go-tool-base/pkg/workspace"
)
func main() {
fs := afero.NewMemMapFs()
// Create a project with a go.mod
_ = afero.WriteFile(fs, "/home/user/project/go.mod", []byte("module example"), 0o644)
_ = fs.MkdirAll("/home/user/project/pkg/cmd", 0o755)
// Detect from a nested directory
ws, err := workspace.Detect(fs, "/home/user/project/pkg/cmd", workspace.DefaultMarkers)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Root:", ws.Root)
fmt.Println("Marker:", ws.Marker)
}
Output: Root: /home/user/project Marker: go.mod
Example (CustomMarkers) ¶
package main
import (
"fmt"
"github.com/spf13/afero"
"github.com/phpboyscout/go-tool-base/pkg/workspace"
)
func main() {
fs := afero.NewMemMapFs()
_ = afero.WriteFile(fs, "/project/package.json", []byte("{}"), 0o644)
_ = fs.MkdirAll("/project/src/components", 0o755)
ws, err := workspace.Detect(fs, "/project/src/components", []string{"package.json"})
if err != nil {
return
}
fmt.Println("Root:", ws.Root)
}
Output: Root: /project