// Package bundle is the top level package for Databricks Application Bundles. // // A bundle is represented by the [Bundle] type. It consists of configuration // and runtime state, such as a client to a Databricks workspace. // Every mutation to a bundle's configuration or state is represented as a [Mutator]. // This interface makes every mutation observable and lets us reason about sequencing. package bundle import ( "os" "path/filepath" "sync" "github.com/databricks/bricks/bundle/config" "github.com/databricks/databricks-sdk-go" "github.com/hashicorp/terraform-exec/tfexec" ) type Bundle struct { Config config.Root // Store a pointer to the workspace client. // It can be initialized on demand after loading the configuration. clientOnce sync.Once client *databricks.WorkspaceClient // Stores an initialized copy of this bundle's Terraform wrapper. Terraform *tfexec.Terraform } func Load(path string) (*Bundle, error) { bundle := &Bundle{ Config: config.Root{ Path: path, }, } err := bundle.Config.Load(filepath.Join(path, config.FileName)) if err != nil { return nil, err } return bundle, nil } // MustLoad returns a bundle configuration. // It returns an error if a bundle was not found or could not be loaded. func MustLoad() (*Bundle, error) { root, err := mustGetRoot() if err != nil { return nil, err } return Load(root) } // TryLoad returns a bundle configuration if there is one, but doesn't fail if there isn't one. // It returns an error if a bundle was found but could not be loaded. // It returns a `nil` bundle if a bundle was not found. func TryLoad() (*Bundle, error) { root, err := tryGetRoot() if err != nil { return nil, err } // No root is fine in this function. if root == "" { return nil, nil } return Load(root) } func (b *Bundle) WorkspaceClient() *databricks.WorkspaceClient { b.clientOnce.Do(func() { var err error b.client, err = b.Config.Workspace.Client() if err != nil { panic(err) } }) return b.client } var cacheDirName = filepath.Join(".databricks", "bundle") // CacheDir returns directory to use for temporary files for this bundle. // Scoped to the bundle's environment. func (b *Bundle) CacheDir(paths ...string) (string, error) { if b.Config.Bundle.Environment == "" { panic("environment not set") } // Fixed components of the result path. parts := []string{ // Anchor at bundle root directory. b.Config.Path, // Static cache directory. cacheDirName, // Scope with environment name. b.Config.Bundle.Environment, } // Append dynamic components of the result path. parts = append(parts, paths...) // Make directory if it doesn't exist yet. dir := filepath.Join(parts...) err := os.MkdirAll(dir, 0700) if err != nil { return "", err } return dir, nil }