-
Notifications
You must be signed in to change notification settings - Fork 223
Expand file tree
/
Copy pathsync.go
More file actions
168 lines (150 loc) · 6.68 KB
/
Copy pathsync.go
File metadata and controls
168 lines (150 loc) · 6.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package environments
import (
"context"
"os"
"path/filepath"
"github.com/databricks/cli/cmd/root"
"github.com/databricks/cli/libs/cmdctx"
"github.com/databricks/cli/libs/env"
libslocalenv "github.com/databricks/cli/libs/localenv"
"github.com/spf13/cobra"
)
// envConstraintSource is the environment variable that overrides the constraint
// source with a full base URL (used e.g. by tests pointing at a local server).
// When unset, the base URL is derived from the hosting repo via
// libslocalenv.RepoConstraintBaseURL (which reads its own repo env var).
const envConstraintSource = "DATABRICKS_LOCALENV_CONSTRAINT_SOURCE"
func newSetupLocalCommand() *cobra.Command {
cmd := &cobra.Command{
Use: libslocalenv.CommandVerb,
Short: "Provision a local Python environment matched to a Databricks compute target",
Long: `Provision (or update) a local Python environment matched to a Databricks compute target.
Resolves the target to an environment key, fetches the pinned Python version,
databricks-connect version, and dependency constraints published for that key,
then provisions a matched .venv with uv. A project with no pyproject.toml is
initialized from scratch; an existing pyproject.toml is merged in place (its
env-owned sections are refreshed, user-owned content is preserved).`,
// Hidden until the environment constraints repository is publicly
// available: the command is runnable for dogfooding but stays out of
// help and completion until it is unveiled.
Hidden: true,
}
// The target is selected via flags; reject stray positional args rather than
// silently ignoring them.
cmd.Args = cobra.NoArgs
cmd.PreRunE = root.MustWorkspaceClient
addTargetFlags(cmd)
cmd.RunE = func(cmd *cobra.Command, args []string) error {
return runPipeline(cmd)
}
return cmd
}
// addTargetFlags adds the shared target and mode flags to a command.
func addTargetFlags(cmd *cobra.Command) {
cmd.Flags().String("cluster-id", "", "cluster ID to use as the compute target")
cmd.Flags().String("cluster-name", "", "cluster name to use as the compute target (resolved to an ID via the Clusters API)")
cmd.Flags().String("serverless-version", "", "serverless version to use as the compute target (e.g. 5)")
cmd.Flags().String("job-id", "", "job ID to use as the compute target")
cmd.Flags().Bool("constraints-only", false, "apply the Python version and constraints without adding the databricks-connect dependency")
cmd.Flags().Bool("dry-run", false, "compute the plan without writing files or provisioning")
cmd.Flags().String("constraint-source-url", "", "URL for the constraint source (overrides "+envConstraintSource+")")
// Hide constraint-source-url from casual --help output; it is a power-user escape hatch.
_ = cmd.Flags().MarkHidden("constraint-source-url")
// The mutual exclusivity of the target flags is enforced in the pipeline's
// preflight (as E_USAGE) rather than via cmd.MarkFlagsMutuallyExclusive, so
// the conflict is reported through the phase/JSON contract the --output json
// consumer relies on, instead of a bare pre-RunE Cobra error.
}
// runPipeline builds and runs the setup-local Pipeline.
func runPipeline(cmd *cobra.Command) error {
ctx := cmd.Context()
cluster, _ := cmd.Flags().GetString("cluster-id")
clusterName, _ := cmd.Flags().GetString("cluster-name")
serverless, _ := cmd.Flags().GetString("serverless-version")
job, _ := cmd.Flags().GetString("job-id")
constraintsOnly, _ := cmd.Flags().GetBool("constraints-only")
check, _ := cmd.Flags().GetBool("dry-run")
constraintSource, _ := cmd.Flags().GetString("constraint-source-url")
targetFlags := libslocalenv.TargetFlags{
Cluster: cluster,
ClusterName: clusterName,
Serverless: serverless,
Job: job,
}
// Flag validation (including mutual exclusivity) happens in the pipeline's
// preflight, so a conflict is reported as E_USAGE through the phase/JSON
// contract rather than as a bare error here.
mode := libslocalenv.ModeDefault
if constraintsOnly {
mode = libslocalenv.ModeConstraintsOnly
}
constraintBaseURL := resolveConstraintBaseURL(ctx, constraintSource)
projectDir, err := os.Getwd()
if err != nil {
return err
}
cacheDir, err := os.UserCacheDir()
if err != nil {
return err
}
cacheDir = filepath.Join(cacheDir, "databricks", "localenv")
// The bundle is only a fallback: ResolveTarget consults it solely when no
// explicit --cluster-id/--cluster-name/--serverless-version/--job-id flag is set. Skip the bundle load
// entirely when a flag is present — it would otherwise re-run TryConfigureBundle
// (a second full load) and re-print any bundle load-time diagnostics for nothing.
var bt libslocalenv.BundleTarget
if cluster == "" && clusterName == "" && serverless == "" && job == "" {
bt = bundleTarget(cmd)
}
w := cmdctx.WorkspaceClient(ctx)
p := &libslocalenv.Pipeline{
Mode: mode,
Check: check,
ProjectDir: projectDir,
ConstraintBaseURL: constraintBaseURL,
CacheDir: cacheDir,
Flags: targetFlags,
Compute: sdkCompute{w: w},
Bundle: bt,
PM: libslocalenv.NewUvManager(),
}
res, pipelineErr := p.Run(ctx)
return renderResult(ctx, cmd, res, pipelineErr)
}
// resolveConstraintBaseURL returns the constraint base URL using ordered precedence:
// an explicit --constraint-source-url flag, then a full-URL override from
// DATABRICKS_LOCALENV_CONSTRAINT_SOURCE, then the URL derived from the hosting repo
// (libslocalenv.RepoConstraintBaseURL). All three may be unset, in which case it
// returns "" and the pipeline reports the missing source at the fetch phase.
func resolveConstraintBaseURL(ctx context.Context, flagValue string) string {
if flagValue != "" {
return flagValue
}
if v, ok := env.Lookup(ctx, envConstraintSource); ok && v != "" {
return v
}
return libslocalenv.RepoConstraintBaseURL(ctx)
}
// bundleTarget reads the active bundle (if any) and maps its compute configuration
// to a libslocalenv.BundleTarget.
//
// Only the top-level bundle.cluster_id field is consulted here; serverless is not
// recorded in the bundle config, so Selected=true is set only when a cluster ID is
// present. If the bundle is absent or has no cluster_id, Selected=false is returned
// so the pipeline falls through to requiring an explicit flag.
//
// TODO: extend once bundle config exposes a serverless field at the bundle level.
func bundleTarget(cmd *cobra.Command) libslocalenv.BundleTarget {
b := root.TryConfigureBundle(cmd)
if b == nil {
return libslocalenv.BundleTarget{Selected: false}
}
clusterID := b.Config.Bundle.ClusterId
if clusterID == "" {
return libslocalenv.BundleTarget{Selected: false}
}
return libslocalenv.BundleTarget{
ClusterID: clusterID,
Selected: true,
}
}