diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 88f45aac96..0d651c92f5 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -10,5 +10,6 @@ ### Bundles * Add validation that served_models and served_entities are not used at the same time. Add client side translation logic. ([#3880](https://github.com/databricks/cli/pull/3880)) +* Fix handling of `file://` URIs in job libraries: `file://relative/path` uploads local files, while `file:///absolute/path` references runtime container assets. ([#3884](https://github.com/databricks/cli/pull/3884)) ### API Changes diff --git a/bundle/libraries/local_path.go b/bundle/libraries/local_path.go index 543c8d2d68..8d5ad67b20 100644 --- a/bundle/libraries/local_path.go +++ b/bundle/libraries/local_path.go @@ -24,9 +24,14 @@ import ( // - s3:/mybucket/myfile.txt // - /Users/jane@doe.com/myfile.txt func IsLocalPath(p string) bool { - // If the path has the explicit file scheme, it's a local path. + // If the path has the explicit file scheme, check if it's an absolute path. + // file:///absolute/path is a runtime container path (remote). + // file://relative/path is a local path to be uploaded. if strings.HasPrefix(p, "file://") { - return true + // Extract the path after file:// + pathAfterScheme := strings.TrimPrefix(p, "file://") + // If it's an absolute path (starts with /), it's a runtime path, not local + return !path.IsAbs(pathAfterScheme) } // If the path has another scheme, it's a remote path. diff --git a/bundle/libraries/local_path_test.go b/bundle/libraries/local_path_test.go index bca8d7ad9f..9fba31a80f 100644 --- a/bundle/libraries/local_path_test.go +++ b/bundle/libraries/local_path_test.go @@ -8,22 +8,31 @@ import ( ) func TestIsLocalPath(t *testing.T) { - // Relative paths, paths with the file scheme, and Windows paths. + // Relative paths and Windows paths. assert.True(t, IsLocalPath("some/local/path")) assert.True(t, IsLocalPath("./some/local/path")) - assert.True(t, IsLocalPath("file://path/to/package")) assert.True(t, IsLocalPath("C:\\path\\to\\package")) assert.True(t, IsLocalPath("myfile.txt")) assert.True(t, IsLocalPath("./myfile.txt")) assert.True(t, IsLocalPath("../myfile.txt")) - assert.True(t, IsLocalPath("file:///foo/bar/myfile.txt")) - // Absolute paths. + // file:// with relative paths (local files to upload). + assert.True(t, IsLocalPath("file://path/to/package")) + assert.True(t, IsLocalPath("file://foo/bar/myfile.txt")) + assert.True(t, IsLocalPath("file://./relative.jar")) + assert.True(t, IsLocalPath("file://../lib/package.whl")) + + // Absolute paths without scheme (remote). assert.False(t, IsLocalPath("/some/full/path")) assert.False(t, IsLocalPath("/Workspace/path/to/package")) assert.False(t, IsLocalPath("/Users/path/to/package")) - // Paths with schemes. + // file:/// with absolute paths (runtime container paths - remote). + assert.False(t, IsLocalPath("file:///foo/bar/myfile.txt")) + assert.False(t, IsLocalPath("file:///opt/spark/jars/driver.jar")) + assert.False(t, IsLocalPath("file:///")) + assert.False(t, IsLocalPath("file:///absolute/path")) + // Paths with other schemes (remote). assert.False(t, IsLocalPath("dbfs://path/to/package")) assert.False(t, IsLocalPath("dbfs:/path/to/package")) assert.False(t, IsLocalPath("s3://path/to/package"))