mirror of https://github.com/databricks/cli.git
Fix `panic: $HOME is not set` (#1027)
This PR adds error to `env.UserHomeDir(ctx)` Fixes https://github.com/databricks/setup-cli/issues/73 --------- Co-authored-by: Pieter Noordhuis <pieter.noordhuis@databricks.com>
This commit is contained in:
parent
4d8d825746
commit
65458cbde6
|
@ -19,13 +19,17 @@ func newClearCacheCommand() *cobra.Command {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = os.Remove(project.PathInLabs(ctx, "databrickslabs-repositories.json"))
|
||||
cache, err := project.PathInLabs(ctx, "databrickslabs-repositories.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = os.Remove(cache)
|
||||
logger := log.GetLogger(ctx)
|
||||
for _, prj := range projects {
|
||||
logger.Info("clearing labs project cache", slog.String("name", prj.Name))
|
||||
_ = os.RemoveAll(prj.CacheDir(ctx))
|
||||
_ = os.RemoveAll(prj.CacheDir())
|
||||
// recreating empty cache folder for downstream apps to work normally
|
||||
_ = prj.EnsureFoldersExist(ctx)
|
||||
_ = prj.EnsureFoldersExist()
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/databricks/cli/cmd/labs/project"
|
||||
"github.com/databricks/cli/libs/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -30,7 +31,8 @@ func New(ctx context.Context) *cobra.Command {
|
|||
)
|
||||
all, err := project.Installed(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Errorf(ctx, "Cannot retrieve installed labs: %s", err)
|
||||
return cmd
|
||||
}
|
||||
for _, v := range all {
|
||||
v.Register(cmd)
|
||||
|
|
|
@ -16,7 +16,10 @@ type labsMeta struct {
|
|||
}
|
||||
|
||||
func allRepos(ctx context.Context) (github.Repositories, error) {
|
||||
cacheDir := project.PathInLabs(ctx)
|
||||
cacheDir, err := project.PathInLabs(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cache := github.NewRepositoryCache("databrickslabs", cacheDir)
|
||||
return cache.Load(ctx)
|
||||
}
|
||||
|
|
|
@ -54,15 +54,15 @@ func (e *Entrypoint) NeedsWarehouse() bool {
|
|||
|
||||
func (e *Entrypoint) Prepare(cmd *cobra.Command) (map[string]string, error) {
|
||||
ctx := cmd.Context()
|
||||
libDir := e.EffectiveLibDir(ctx)
|
||||
libDir := e.EffectiveLibDir()
|
||||
environment := map[string]string{
|
||||
"DATABRICKS_CLI_VERSION": build.GetInfo().Version,
|
||||
"DATABRICKS_LABS_CACHE_DIR": e.CacheDir(ctx),
|
||||
"DATABRICKS_LABS_CONFIG_DIR": e.ConfigDir(ctx),
|
||||
"DATABRICKS_LABS_STATE_DIR": e.StateDir(ctx),
|
||||
"DATABRICKS_LABS_CACHE_DIR": e.CacheDir(),
|
||||
"DATABRICKS_LABS_CONFIG_DIR": e.ConfigDir(),
|
||||
"DATABRICKS_LABS_STATE_DIR": e.StateDir(),
|
||||
"DATABRICKS_LABS_LIB_DIR": libDir,
|
||||
}
|
||||
if e.IsPythonProject(ctx) {
|
||||
if e.IsPythonProject() {
|
||||
e.preparePython(ctx, environment)
|
||||
}
|
||||
cfg, err := e.validLogin(cmd)
|
||||
|
@ -112,7 +112,7 @@ func (e *Entrypoint) preparePython(ctx context.Context, environment map[string]s
|
|||
// Here we are also supporting the "src" layout for python projects.
|
||||
//
|
||||
// See https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH
|
||||
libDir := e.EffectiveLibDir(ctx)
|
||||
libDir := e.EffectiveLibDir()
|
||||
// The intention for every install is to be sandboxed - not dependent on anything else than Python binary.
|
||||
// Having ability to override PYTHONPATH in the mix will break this assumption. Need strong evidence that
|
||||
// this is really needed.
|
||||
|
@ -139,21 +139,28 @@ func (e *Entrypoint) joinPaths(paths ...string) string {
|
|||
return strings.Join(paths, string(os.PathListSeparator))
|
||||
}
|
||||
|
||||
func (e *Entrypoint) envAwareConfig(ctx context.Context) *config.Config {
|
||||
func (e *Entrypoint) envAwareConfig(ctx context.Context) (*config.Config, error) {
|
||||
home, err := env.UserHomeDir(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &config.Config{
|
||||
ConfigFile: filepath.Join(env.UserHomeDir(ctx), ".databrickscfg"),
|
||||
ConfigFile: filepath.Join(home, ".databrickscfg"),
|
||||
Loaders: []config.Loader{
|
||||
env.NewConfigLoader(ctx),
|
||||
config.ConfigAttributes,
|
||||
config.ConfigFile,
|
||||
},
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *Entrypoint) envAwareConfigWithProfile(ctx context.Context, profile string) *config.Config {
|
||||
cfg := e.envAwareConfig(ctx)
|
||||
func (e *Entrypoint) envAwareConfigWithProfile(ctx context.Context, profile string) (*config.Config, error) {
|
||||
cfg, err := e.envAwareConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.Profile = profile
|
||||
return cfg
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (e *Entrypoint) getLoginConfig(cmd *cobra.Command) (*loginConfig, *config.Config, error) {
|
||||
|
@ -164,11 +171,18 @@ func (e *Entrypoint) getLoginConfig(cmd *cobra.Command) (*loginConfig, *config.C
|
|||
profileOverride := e.profileOverride(cmd)
|
||||
if profileOverride != "" {
|
||||
log.Infof(ctx, "Overriding login profile: %s", profileOverride)
|
||||
return &loginConfig{}, e.envAwareConfigWithProfile(ctx, profileOverride), nil
|
||||
cfg, err := e.envAwareConfigWithProfile(ctx, profileOverride)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &loginConfig{}, cfg, nil
|
||||
}
|
||||
lc, err := e.loadLoginConfig(ctx)
|
||||
isNoLoginConfig := errors.Is(err, fs.ErrNotExist)
|
||||
defaultConfig := e.envAwareConfig(ctx)
|
||||
defaultConfig, err := e.envAwareConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if isNoLoginConfig && !e.IsBundleAware && e.isAuthConfigured(defaultConfig) {
|
||||
log.Debugf(ctx, "Login is configured via environment variables")
|
||||
return &loginConfig{}, defaultConfig, nil
|
||||
|
@ -181,7 +195,11 @@ func (e *Entrypoint) getLoginConfig(cmd *cobra.Command) (*loginConfig, *config.C
|
|||
}
|
||||
if e.IsAccountLevel {
|
||||
log.Debugf(ctx, "Using account-level login profile: %s", lc.AccountProfile)
|
||||
return lc, e.envAwareConfigWithProfile(ctx, lc.AccountProfile), nil
|
||||
cfg, err := e.envAwareConfigWithProfile(ctx, lc.AccountProfile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return lc, cfg, nil
|
||||
}
|
||||
if e.IsBundleAware {
|
||||
err = root.TryConfigureBundle(cmd, []string{})
|
||||
|
@ -194,7 +212,11 @@ func (e *Entrypoint) getLoginConfig(cmd *cobra.Command) (*loginConfig, *config.C
|
|||
}
|
||||
}
|
||||
log.Debugf(ctx, "Using workspace-level login profile: %s", lc.WorkspaceProfile)
|
||||
return lc, e.envAwareConfigWithProfile(ctx, lc.WorkspaceProfile), nil
|
||||
cfg, err := e.envAwareConfigWithProfile(ctx, lc.WorkspaceProfile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return lc, cfg, nil
|
||||
}
|
||||
|
||||
func (e *Entrypoint) validLogin(cmd *cobra.Command) (*config.Config, error) {
|
||||
|
|
|
@ -29,7 +29,10 @@ func (d *devInstallation) Install(ctx context.Context) error {
|
|||
}
|
||||
_, err := d.Installer.validLogin(d.Command)
|
||||
if errors.Is(err, ErrNoLoginConfig) {
|
||||
cfg := d.Installer.envAwareConfig(ctx)
|
||||
cfg, err := d.Installer.envAwareConfig(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lc := &loginConfig{Entrypoint: d.Installer.Entrypoint}
|
||||
_, err = lc.askWorkspace(ctx, cfg)
|
||||
if err != nil {
|
||||
|
@ -39,7 +42,7 @@ func (d *devInstallation) Install(ctx context.Context) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("ask for account: %w", err)
|
||||
}
|
||||
err = lc.EnsureFoldersExist(ctx)
|
||||
err = lc.EnsureFoldersExist()
|
||||
if err != nil {
|
||||
return fmt.Errorf("folders: %w", err)
|
||||
}
|
||||
|
@ -97,7 +100,10 @@ func NewUpgrader(cmd *cobra.Command, name string) (*installer, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("remote: %w", err)
|
||||
}
|
||||
prj.folder = PathInLabs(cmd.Context(), name)
|
||||
prj.folder, err = PathInLabs(cmd.Context(), name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &installer{
|
||||
Project: prj,
|
||||
version: version,
|
||||
|
@ -111,7 +117,10 @@ type fetcher struct {
|
|||
|
||||
func (f *fetcher) checkReleasedVersions(cmd *cobra.Command, version string) (string, error) {
|
||||
ctx := cmd.Context()
|
||||
cacheDir := PathInLabs(ctx, f.name, "cache")
|
||||
cacheDir, err := PathInLabs(ctx, f.name, "cache")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// `databricks labs isntall X` doesn't know which exact version to fetch, so first
|
||||
// we fetch all versions and then pick the latest one dynamically.
|
||||
versions, err := github.NewReleaseCache("databrickslabs", f.name, cacheDir).Load(ctx)
|
||||
|
|
|
@ -12,10 +12,13 @@ import (
|
|||
"github.com/databricks/cli/libs/env"
|
||||
)
|
||||
|
||||
func PathInLabs(ctx context.Context, dirs ...string) string {
|
||||
homdeDir := env.UserHomeDir(ctx)
|
||||
prefix := []string{homdeDir, ".databricks", "labs"}
|
||||
return filepath.Join(append(prefix, dirs...)...)
|
||||
func PathInLabs(ctx context.Context, dirs ...string) (string, error) {
|
||||
homeDir, err := env.UserHomeDir(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
prefix := []string{homeDir, ".databricks", "labs"}
|
||||
return filepath.Join(append(prefix, dirs...)...), nil
|
||||
}
|
||||
|
||||
func tryLoadAndParseJSON[T any](jsonFile string) (*T, error) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"github.com/databricks/cli/folders"
|
||||
"github.com/databricks/cli/libs/env"
|
||||
"github.com/databricks/cli/libs/log"
|
||||
)
|
||||
|
||||
|
@ -26,7 +27,13 @@ func projectInDevMode(ctx context.Context) (*Project, error) {
|
|||
}
|
||||
|
||||
func Installed(ctx context.Context) (projects []*Project, err error) {
|
||||
labsDir, err := os.ReadDir(PathInLabs(ctx))
|
||||
root, err := PathInLabs(ctx)
|
||||
if errors.Is(err, env.ErrNoHomeEnv) {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
labsDir, err := os.ReadDir(root)
|
||||
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -44,7 +51,7 @@ func Installed(ctx context.Context) (projects []*Project, err error) {
|
|||
if projectDev != nil && v.Name() == projectDev.Name {
|
||||
continue
|
||||
}
|
||||
labsYml := PathInLabs(ctx, v.Name(), "lib", "labs.yml")
|
||||
labsYml := filepath.Join(root, v.Name(), "lib", "labs.yml")
|
||||
prj, err := Load(ctx, labsYml)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
continue
|
||||
|
|
|
@ -55,7 +55,7 @@ func (h *hook) runHook(cmd *cobra.Command) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("prepare: %w", err)
|
||||
}
|
||||
libDir := h.EffectiveLibDir(ctx)
|
||||
libDir := h.EffectiveLibDir()
|
||||
args := []string{}
|
||||
if strings.HasSuffix(h.Script, ".py") {
|
||||
args = append(args, h.virtualEnvPython(ctx))
|
||||
|
@ -80,14 +80,20 @@ type installer struct {
|
|||
}
|
||||
|
||||
func (i *installer) Install(ctx context.Context) error {
|
||||
err := i.EnsureFoldersExist(ctx)
|
||||
err := i.EnsureFoldersExist()
|
||||
if err != nil {
|
||||
return fmt.Errorf("folders: %w", err)
|
||||
}
|
||||
i.folder = PathInLabs(ctx, i.Name)
|
||||
i.folder, err = PathInLabs(ctx, i.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w, err := i.login(ctx)
|
||||
if err != nil && errors.Is(err, databrickscfg.ErrNoConfiguration) {
|
||||
cfg := i.Installer.envAwareConfig(ctx)
|
||||
cfg, err := i.Installer.envAwareConfig(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w, err = databricks.NewWorkspaceClient((*databricks.Config)(cfg))
|
||||
if err != nil {
|
||||
return fmt.Errorf("no ~/.databrickscfg: %w", err)
|
||||
|
@ -138,7 +144,7 @@ func (i *installer) warningf(text string, v ...any) {
|
|||
}
|
||||
|
||||
func (i *installer) cleanupLib(ctx context.Context) error {
|
||||
libDir := i.LibDir(ctx)
|
||||
libDir := i.LibDir()
|
||||
err := os.RemoveAll(libDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("remove all: %w", err)
|
||||
|
@ -157,7 +163,10 @@ func (i *installer) login(ctx context.Context) (*databricks.WorkspaceClient, err
|
|||
}
|
||||
cfg, err := i.metaEntrypoint(ctx).validLogin(i.cmd)
|
||||
if errors.Is(err, ErrNoLoginConfig) {
|
||||
cfg = i.Installer.envAwareConfig(ctx)
|
||||
cfg, err = i.Installer.envAwareConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("valid: %w", err)
|
||||
}
|
||||
|
@ -188,7 +197,7 @@ func (i *installer) downloadLibrary(ctx context.Context) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("cleanup: %w", err)
|
||||
}
|
||||
libTarget := i.LibDir(ctx)
|
||||
libTarget := i.LibDir()
|
||||
// we may support wheels, jars, and golang binaries. but those are not zipballs
|
||||
if i.IsZipball() {
|
||||
feedback <- fmt.Sprintf("Downloading and unpacking zipball for %s", i.version)
|
||||
|
@ -254,10 +263,10 @@ func (i *installer) setupPythonVirtualEnvironment(ctx context.Context, w *databr
|
|||
}
|
||||
|
||||
func (i *installer) installPythonDependencies(ctx context.Context, spec string) error {
|
||||
if !i.IsPythonProject(ctx) {
|
||||
if !i.IsPythonProject() {
|
||||
return nil
|
||||
}
|
||||
libDir := i.LibDir(ctx)
|
||||
libDir := i.LibDir()
|
||||
log.Debugf(ctx, "Installing Python dependencies for: %s", libDir)
|
||||
// maybe we'll need to add call one of the two scripts:
|
||||
// - python3 -m ensurepip --default-pip
|
||||
|
@ -281,6 +290,6 @@ func (i *installer) runInstallHook(ctx context.Context) error {
|
|||
if i.Installer.Script == "" {
|
||||
return nil
|
||||
}
|
||||
log.Debugf(ctx, "Launching installer script %s in %s", i.Installer.Script, i.LibDir(ctx))
|
||||
log.Debugf(ctx, "Launching installer script %s in %s", i.Installer.Script, i.LibDir())
|
||||
return i.Installer.runHook(i.cmd)
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ func installerContext(t *testing.T, server *httptest.Server) context.Context {
|
|||
ctx = github.WithUserContentOverride(ctx, server.URL)
|
||||
ctx = env.WithUserHomeDir(ctx, t.TempDir())
|
||||
// trick release cache to thing it went to github already
|
||||
cachePath := project.PathInLabs(ctx, "blueprint", "cache")
|
||||
cachePath, _ := project.PathInLabs(ctx, "blueprint", "cache")
|
||||
err := os.MkdirAll(cachePath, ownerRWXworldRX)
|
||||
require.NoError(t, err)
|
||||
bs := []byte(`{"refreshed_at": "2033-01-01T00:00:00.92857+02:00","data": [{"tag_name": "v0.3.15"}]}`)
|
||||
|
@ -317,8 +317,8 @@ func TestInstallerWorksForDevelopment(t *testing.T) {
|
|||
|
||||
// development installer assumes it's in the active virtualenv
|
||||
ctx = env.Set(ctx, "PYTHON_BIN", py)
|
||||
|
||||
err = os.WriteFile(filepath.Join(env.UserHomeDir(ctx), ".databrickscfg"), []byte(fmt.Sprintf(`
|
||||
home, _ := env.UserHomeDir(ctx)
|
||||
err = os.WriteFile(filepath.Join(home, ".databrickscfg"), []byte(fmt.Sprintf(`
|
||||
[profile-one]
|
||||
host = %s
|
||||
token = ...
|
||||
|
@ -399,7 +399,7 @@ func TestUpgraderWorksForReleases(t *testing.T) {
|
|||
py, _ = filepath.Abs(py)
|
||||
ctx = env.Set(ctx, "PYTHON_BIN", py)
|
||||
|
||||
cachePath := project.PathInLabs(ctx, "blueprint", "cache")
|
||||
cachePath, _ := project.PathInLabs(ctx, "blueprint", "cache")
|
||||
bs := []byte(`{"refreshed_at": "2033-01-01T00:00:00.92857+02:00","data": [{"tag_name": "v0.4.0"}]}`)
|
||||
err := os.WriteFile(filepath.Join(cachePath, "databrickslabs-blueprint-releases.json"), bs, ownerRW)
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -49,6 +49,11 @@ func readFromBytes(ctx context.Context, labsYmlRaw []byte) (*Project, error) {
|
|||
if project.Uninstaller != nil {
|
||||
project.Uninstaller.Entrypoint = e
|
||||
}
|
||||
rootDir, err := PathInLabs(ctx, project.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
project.rootDir = rootDir
|
||||
return &project, nil
|
||||
}
|
||||
|
||||
|
@ -63,7 +68,8 @@ type Project struct {
|
|||
MinPython string `yaml:"min_python"`
|
||||
Commands []*proxy `yaml:"commands,omitempty"`
|
||||
|
||||
folder string
|
||||
folder string
|
||||
rootDir string
|
||||
}
|
||||
|
||||
func (p *Project) IsZipball() bool {
|
||||
|
@ -108,22 +114,22 @@ func (p *Project) fileExists(name string) bool {
|
|||
return err == nil
|
||||
}
|
||||
|
||||
func (p *Project) projectFilePath(ctx context.Context, name string) string {
|
||||
return filepath.Join(p.EffectiveLibDir(ctx), name)
|
||||
func (p *Project) projectFilePath(name string) string {
|
||||
return filepath.Join(p.EffectiveLibDir(), name)
|
||||
}
|
||||
|
||||
func (p *Project) IsPythonProject(ctx context.Context) bool {
|
||||
if p.fileExists(p.projectFilePath(ctx, "setup.py")) {
|
||||
func (p *Project) IsPythonProject() bool {
|
||||
if p.fileExists(p.projectFilePath("setup.py")) {
|
||||
return true
|
||||
}
|
||||
if p.fileExists(p.projectFilePath(ctx, "pyproject.toml")) {
|
||||
if p.fileExists(p.projectFilePath("pyproject.toml")) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Project) IsDeveloperMode(ctx context.Context) bool {
|
||||
return p.folder != "" && !strings.HasPrefix(p.LibDir(ctx), p.folder)
|
||||
func (p *Project) IsDeveloperMode() bool {
|
||||
return p.folder != "" && !strings.HasPrefix(p.LibDir(), p.folder)
|
||||
}
|
||||
|
||||
func (p *Project) HasFolder() bool {
|
||||
|
@ -161,36 +167,32 @@ func (p *Project) Register(parent *cobra.Command) {
|
|||
}
|
||||
}
|
||||
|
||||
func (p *Project) rootDir(ctx context.Context) string {
|
||||
return PathInLabs(ctx, p.Name)
|
||||
func (p *Project) CacheDir() string {
|
||||
return filepath.Join(p.rootDir, "cache")
|
||||
}
|
||||
|
||||
func (p *Project) CacheDir(ctx context.Context) string {
|
||||
return filepath.Join(p.rootDir(ctx), "cache")
|
||||
func (p *Project) ConfigDir() string {
|
||||
return filepath.Join(p.rootDir, "config")
|
||||
}
|
||||
|
||||
func (p *Project) ConfigDir(ctx context.Context) string {
|
||||
return filepath.Join(p.rootDir(ctx), "config")
|
||||
func (p *Project) LibDir() string {
|
||||
return filepath.Join(p.rootDir, "lib")
|
||||
}
|
||||
|
||||
func (p *Project) LibDir(ctx context.Context) string {
|
||||
return filepath.Join(p.rootDir(ctx), "lib")
|
||||
}
|
||||
|
||||
func (p *Project) EffectiveLibDir(ctx context.Context) string {
|
||||
if p.IsDeveloperMode(ctx) {
|
||||
func (p *Project) EffectiveLibDir() string {
|
||||
if p.IsDeveloperMode() {
|
||||
// developer is working on a local checkout, that is not inside of installed root
|
||||
return p.folder
|
||||
}
|
||||
return p.LibDir(ctx)
|
||||
return p.LibDir()
|
||||
}
|
||||
|
||||
func (p *Project) StateDir(ctx context.Context) string {
|
||||
return filepath.Join(p.rootDir(ctx), "state")
|
||||
func (p *Project) StateDir() string {
|
||||
return filepath.Join(p.rootDir, "state")
|
||||
}
|
||||
|
||||
func (p *Project) EnsureFoldersExist(ctx context.Context) error {
|
||||
dirs := []string{p.CacheDir(ctx), p.ConfigDir(ctx), p.LibDir(ctx), p.StateDir(ctx)}
|
||||
func (p *Project) EnsureFoldersExist() error {
|
||||
dirs := []string{p.CacheDir(), p.ConfigDir(), p.LibDir(), p.StateDir()}
|
||||
for _, v := range dirs {
|
||||
err := os.MkdirAll(v, ownerRWXworldRX)
|
||||
if err != nil {
|
||||
|
@ -209,11 +211,11 @@ func (p *Project) Uninstall(cmd *cobra.Command) error {
|
|||
}
|
||||
ctx := cmd.Context()
|
||||
log.Infof(ctx, "Removing project: %s", p.Name)
|
||||
return os.RemoveAll(p.rootDir(ctx))
|
||||
return os.RemoveAll(p.rootDir)
|
||||
}
|
||||
|
||||
func (p *Project) virtualEnvPath(ctx context.Context) string {
|
||||
if p.IsDeveloperMode(ctx) {
|
||||
if p.IsDeveloperMode() {
|
||||
// When a virtual environment has been activated, the VIRTUAL_ENV environment variable
|
||||
// is set to the path of the environment. Since explicitly activating a virtual environment
|
||||
// is not required to use it, VIRTUAL_ENV cannot be relied upon to determine whether a virtual
|
||||
|
@ -225,14 +227,14 @@ func (p *Project) virtualEnvPath(ctx context.Context) string {
|
|||
logger.Debugf(ctx, "(development mode) using active virtual environment from: %s", activatedVenv)
|
||||
return activatedVenv
|
||||
}
|
||||
nonActivatedVenv, err := python.DetectVirtualEnvPath(p.EffectiveLibDir(ctx))
|
||||
nonActivatedVenv, err := python.DetectVirtualEnvPath(p.EffectiveLibDir())
|
||||
if err == nil {
|
||||
logger.Debugf(ctx, "(development mode) using virtual environment from: %s", nonActivatedVenv)
|
||||
return nonActivatedVenv
|
||||
}
|
||||
}
|
||||
// by default, we pick Virtual Environment from DATABRICKS_LABS_STATE_DIR
|
||||
return filepath.Join(p.StateDir(ctx), "venv")
|
||||
return filepath.Join(p.StateDir(), "venv")
|
||||
}
|
||||
|
||||
func (p *Project) virtualEnvPython(ctx context.Context) string {
|
||||
|
@ -247,13 +249,13 @@ func (p *Project) virtualEnvPython(ctx context.Context) string {
|
|||
}
|
||||
|
||||
func (p *Project) loginFile(ctx context.Context) string {
|
||||
if p.IsDeveloperMode(ctx) {
|
||||
if p.IsDeveloperMode() {
|
||||
// developers may not want to pollute the state in
|
||||
// ~/.databricks/labs/X/config while the version is not yet
|
||||
// released
|
||||
return p.projectFilePath(ctx, ".databricks-login.json")
|
||||
return p.projectFilePath(".databricks-login.json")
|
||||
}
|
||||
return filepath.Join(p.ConfigDir(ctx), "login.json")
|
||||
return filepath.Join(p.ConfigDir(), "login.json")
|
||||
}
|
||||
|
||||
func (p *Project) loadLoginConfig(ctx context.Context) (*loginConfig, error) {
|
||||
|
@ -268,11 +270,11 @@ func (p *Project) loadLoginConfig(ctx context.Context) (*loginConfig, error) {
|
|||
}
|
||||
|
||||
func (p *Project) versionFile(ctx context.Context) string {
|
||||
return filepath.Join(p.StateDir(ctx), "version.json")
|
||||
return filepath.Join(p.StateDir(), "version.json")
|
||||
}
|
||||
|
||||
func (p *Project) InstalledVersion(ctx context.Context) (*version, error) {
|
||||
if p.IsDeveloperMode(ctx) {
|
||||
if p.IsDeveloperMode() {
|
||||
return &version{
|
||||
Version: "*",
|
||||
Date: time.Now(),
|
||||
|
@ -300,12 +302,12 @@ func (p *Project) writeVersionFile(ctx context.Context, ver string) error {
|
|||
// giving users hints when they need to update their installations.
|
||||
func (p *Project) checkUpdates(cmd *cobra.Command) error {
|
||||
ctx := cmd.Context()
|
||||
if p.IsDeveloperMode(ctx) {
|
||||
if p.IsDeveloperMode() {
|
||||
// skipping update check for projects in developer mode, that
|
||||
// might not be installed yet
|
||||
return nil
|
||||
}
|
||||
r := github.NewReleaseCache("databrickslabs", p.Name, p.CacheDir(ctx))
|
||||
r := github.NewReleaseCache("databrickslabs", p.Name, p.CacheDir())
|
||||
versions, err := r.Load(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -60,7 +60,7 @@ func (cp *proxy) runE(cmd *cobra.Command, _ []string) error {
|
|||
cmd.OutOrStdout(),
|
||||
cmd.ErrOrStderr(),
|
||||
process.WithEnvs(envs))
|
||||
if errors.Is(err, fs.ErrNotExist) && cp.IsPythonProject(ctx) {
|
||||
if errors.Is(err, fs.ErrNotExist) && cp.IsPythonProject() {
|
||||
msg := "cannot find Python %s. Please re-run: databricks labs install %s"
|
||||
return fmt.Errorf(msg, cp.MinPython, cp.Name)
|
||||
}
|
||||
|
@ -113,9 +113,9 @@ func (cp *proxy) commandInput(cmd *cobra.Command) ([]string, error) {
|
|||
}
|
||||
args := []string{}
|
||||
ctx := cmd.Context()
|
||||
if cp.IsPythonProject(ctx) {
|
||||
if cp.IsPythonProject() {
|
||||
args = append(args, cp.virtualEnvPython(ctx))
|
||||
libDir := cp.EffectiveLibDir(cmd.Context())
|
||||
libDir := cp.EffectiveLibDir()
|
||||
entrypoint := filepath.Join(libDir, cp.Main)
|
||||
args = append(args, entrypoint)
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ func newShowCommand() *cobra.Command {
|
|||
}
|
||||
name := args[0]
|
||||
for _, v := range installed {
|
||||
isDev := name == "." && v.IsDeveloperMode(ctx)
|
||||
isDev := name == "." && v.IsDeveloperMode()
|
||||
isMatch := name == v.Name
|
||||
if !(isDev || isMatch) {
|
||||
continue
|
||||
|
@ -45,10 +45,10 @@ func newShowCommand() *cobra.Command {
|
|||
return cmdio.Render(ctx, map[string]any{
|
||||
"name": v.Name,
|
||||
"description": v.Description,
|
||||
"cache_dir": v.CacheDir(ctx),
|
||||
"config_dir": v.ConfigDir(ctx),
|
||||
"lib_dir": v.EffectiveLibDir(ctx),
|
||||
"is_python": v.IsPythonProject(ctx),
|
||||
"cache_dir": v.CacheDir(),
|
||||
"config_dir": v.ConfigDir(),
|
||||
"lib_dir": v.EffectiveLibDir(),
|
||||
"is_python": v.IsPythonProject(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -76,7 +76,10 @@ func GetPath(ctx context.Context) (string, error) {
|
|||
configFile = "~/.databrickscfg"
|
||||
}
|
||||
if strings.HasPrefix(configFile, "~") {
|
||||
homedir := env.UserHomeDir(ctx)
|
||||
homedir, err := env.UserHomeDir(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
configFile = filepath.Join(homedir, configFile[1:])
|
||||
}
|
||||
return configFile, nil
|
||||
|
@ -108,7 +111,11 @@ func LoadProfiles(ctx context.Context, fn ProfileMatchFunction) (file string, pr
|
|||
// Replace homedir with ~ if applicable.
|
||||
// This is to make the output more readable.
|
||||
file = filepath.Clean(f.Path())
|
||||
homedir := filepath.Clean(env.UserHomeDir(ctx))
|
||||
home, err := env.UserHomeDir(ctx)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
homedir := filepath.Clean(home)
|
||||
if strings.HasPrefix(file, homedir) {
|
||||
file = "~" + file[len(homedir):]
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package env
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"errors"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -76,12 +76,15 @@ func WithUserHomeDir(ctx context.Context, value string) context.Context {
|
|||
return Set(ctx, homeEnvVar(), value)
|
||||
}
|
||||
|
||||
func UserHomeDir(ctx context.Context) string {
|
||||
// ErrNoHomeEnv indicates the absence of $HOME env variable
|
||||
var ErrNoHomeEnv = errors.New("$HOME is not set")
|
||||
|
||||
func UserHomeDir(ctx context.Context) (string, error) {
|
||||
home := Get(ctx, homeEnvVar())
|
||||
if home == "" {
|
||||
panic(fmt.Errorf("$HOME is not set"))
|
||||
return "", ErrNoHomeEnv
|
||||
}
|
||||
return home
|
||||
return home, nil
|
||||
}
|
||||
|
||||
// All returns environment variables that are defined in both os.Environ
|
||||
|
|
|
@ -51,6 +51,7 @@ func TestContext(t *testing.T) {
|
|||
func TestHome(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx = WithUserHomeDir(ctx, "...")
|
||||
home := UserHomeDir(ctx)
|
||||
home, err := UserHomeDir(ctx)
|
||||
assert.Equal(t, "...", home)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue