mirror of https://github.com/databricks/cli.git
158 lines
4.0 KiB
Go
158 lines
4.0 KiB
Go
package template
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
|
|
"github.com/databricks/cli/libs/cmdio"
|
|
"github.com/databricks/cli/libs/filer"
|
|
"github.com/databricks/cli/libs/telemetry"
|
|
"github.com/databricks/cli/libs/telemetry/events"
|
|
)
|
|
|
|
const (
|
|
libraryDirName = "library"
|
|
templateDirName = "template"
|
|
schemaFileName = "databricks_template_schema.json"
|
|
)
|
|
|
|
type TemplateOpts struct {
|
|
// file path containing user defined config values
|
|
ConfigFilePath string
|
|
// root of the template definition
|
|
TemplateFS fs.FS
|
|
// filer to use for writing the initialized template
|
|
OutputFiler filer.Filer
|
|
// If true, we'll include the enum template args in the telemetry payload..
|
|
IsDatabricksOwned bool
|
|
// Name of the template. For non-Databricks owned templates, this is set to
|
|
// custom.
|
|
Name string
|
|
}
|
|
|
|
type Template struct {
|
|
TemplateOpts
|
|
|
|
// internal object used to prompt user for config values and store them.
|
|
config *config
|
|
|
|
// internal object user to render the template.
|
|
renderer *renderer
|
|
}
|
|
|
|
// This function resolves input to use to materialize the template in two steps.
|
|
// 1. First, this function loads any user specified input configuration if the user
|
|
// has provided a config file path.
|
|
// 2. For any values that are required by the template but not provided in the config
|
|
// file, this function prompts the user for them.
|
|
func (t *Template) resolveTemplateInput(ctx context.Context) error {
|
|
if _, err := fs.Stat(t.TemplateFS, schemaFileName); errors.Is(err, fs.ErrNotExist) {
|
|
return fmt.Errorf("not a bundle template: expected to find a template schema file at %s", schemaFileName)
|
|
}
|
|
|
|
var err error
|
|
t.config, err = newConfig(ctx, t.TemplateFS, schemaFileName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Read and assign config values from file
|
|
if t.ConfigFilePath != "" {
|
|
err = t.config.assignValuesFromFile(t.ConfigFilePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
helpers := loadHelpers(ctx)
|
|
t.renderer, err = newRenderer(ctx, t.config.values, helpers, t.TemplateFS, templateDirName, libraryDirName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Print welcome message
|
|
welcome := t.config.schema.WelcomeMessage
|
|
if welcome != "" {
|
|
welcome, err = t.renderer.executeTemplate(welcome)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cmdio.LogString(ctx, welcome)
|
|
}
|
|
|
|
// Prompt user for any missing config values. Assign default values if
|
|
// terminal is not TTY
|
|
err = t.config.promptOrAssignDefaultValues(t.renderer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return t.config.validate()
|
|
}
|
|
|
|
func (t *Template) printSuccessMessage(ctx context.Context) error {
|
|
success := t.config.schema.SuccessMessage
|
|
if success == "" {
|
|
cmdio.LogString(ctx, "✨ Successfully initialized template")
|
|
return nil
|
|
}
|
|
|
|
success, err := t.renderer.executeTemplate(success)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cmdio.LogString(ctx, success)
|
|
return nil
|
|
}
|
|
|
|
func (t *Template) logTelemetry(ctx context.Context) error {
|
|
// Only log telemetry input for Databricks owned templates. This is to prevent
|
|
// accidentally collecting PUII from custom user templates.
|
|
templateEnumArgs := map[string]string{}
|
|
if t.IsDatabricksOwned {
|
|
templateEnumArgs = t.config.enumValues()
|
|
}
|
|
|
|
event := telemetry.DatabricksCliLog{
|
|
BundleInitEvent: &events.BundleInitEvent{
|
|
Uuid: bundleUuid,
|
|
TemplateName: t.Name,
|
|
TemplateEnumArgs: templateEnumArgs,
|
|
},
|
|
}
|
|
|
|
return telemetry.Log(ctx, telemetry.FrontendLogEntry{
|
|
DatabricksCliLog: event,
|
|
})
|
|
}
|
|
|
|
// This function materializes the input templates as a project, using user defined
|
|
// configurations.
|
|
func (t *Template) Materialize(ctx context.Context) error {
|
|
err := t.resolveTemplateInput(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Walk the template file tree and compute in-memory representations of the
|
|
// output files.
|
|
err = t.renderer.walk()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Flush the output files to disk.
|
|
err = t.renderer.persistToDisk(ctx, t.OutputFiler)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = t.printSuccessMessage(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return t.logTelemetry(ctx)
|
|
}
|