Repository navigation
Custom file roots should be considered valid server managed roots. #8232
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 5 commits
cbf0b17
69e68d5
c4cc43d
375f8e0
c8f108d
8b8ab33
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -193,57 +193,69 @@ private FileContentServiceImpl() | |
| } | ||
|
|
||
| @Override | ||
| @NotNull | ||
| public List<Container> getContainersForFilePath(java.nio.file.Path path) | ||
| public @Nullable Container getContainerForFilePath(java.nio.file.Path path) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can see that in practice this doesn't happen, but two containers could point to the same directory as a pipeline root. I'm not sure what the usage of this method are and how this is meant to be resolved, or if it's fine to be arbitrary? |
||
| { | ||
| // Ignore cloud files for now | ||
| if (FileUtil.hasCloudScheme(path)) | ||
| return Collections.emptyList(); | ||
| return null; | ||
|
|
||
| // Anchor on the most specific root holding the path: the site default root or a custom file root | ||
| Container anchor = null; | ||
| java.nio.file.Path anchorPath = null; | ||
| java.nio.file.Path defaultRootPath = getSiteDefaultRoot().toPath(); | ||
| if (URIUtil.isDescendant(defaultRootPath.toUri(), path.toUri())) | ||
| { | ||
| anchor = ContainerManager.getRoot(); | ||
| anchorPath = defaultRootPath; | ||
| } | ||
|
|
||
| // If the path is under the default root, do optimistic simple match for containers under the default root | ||
| File defaultRoot = getSiteDefaultRoot(); | ||
| java.nio.file.Path defaultRootPath = defaultRoot.toPath(); | ||
| if (path.startsWith(defaultRootPath)) | ||
| for (FileRoot root : FileRootManager.get().getFileRoots()) | ||
| { | ||
| java.nio.file.Path rel = defaultRootPath.relativize(path); | ||
| if (rel.getNameCount() > 0) | ||
| // Skip cloud roots before resolving: resolution goes through CloudStoreService, which may be absent or misconfigured | ||
| if (isCloudFileRoot(root.getPath())) | ||
| continue; | ||
| Container c = ContainerManager.getForId(root.getContainer()); | ||
| if (c == null || c.isRoot() || isUseDefaultRoot(c)) | ||
| continue; | ||
| java.nio.file.Path rootPath = getExistingFileRootPath(c); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. check hasCloudScheme() in this loop somewhere too?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a short circuit on line 215 but cloud scheme paths should get resolved during |
||
| if (rootPath != null && URIUtil.isDescendant(rootPath.toUri(), path.toUri()) && (anchorPath == null || URIUtil.isDescendant(anchorPath.toUri(), rootPath.toUri()))) | ||
| { | ||
| Container root = ContainerManager.getRoot(); | ||
| Container next = root; | ||
| while (rel.getNameCount() > 0) | ||
| { | ||
| // check if there exists a child container that matches the next path segment | ||
| java.nio.file.Path top = rel.subpath(0, 1); | ||
| assert top != null; | ||
| Container child = next.getChild(top.getFileName().toString()); | ||
| if (child == null) | ||
| break; | ||
| anchor = c; | ||
| anchorPath = rootPath; | ||
| } | ||
| } | ||
|
|
||
| next = child; | ||
| if (anchor == null) | ||
| return null; | ||
|
|
||
| if(rel.getNameCount() > 1) | ||
| { | ||
| rel = rel.subpath(1, rel.getNameCount()); | ||
| } | ||
| else | ||
| { | ||
| break; | ||
| } | ||
| } | ||
| // Child folder roots default to a matching subdirectory, so walk the path's segments down the container tree | ||
| List<Container> candidates = new ArrayList<>(List.of(anchor)); | ||
| Container next = anchor; | ||
|
|
||
| if (next != null && !next.equals(root)) | ||
| { | ||
| // verify our naive file path is correct for the container -- it may have a file root other than the default | ||
| java.nio.file.Path fileRoot = getFileRootPath(next); | ||
| if (fileRoot != null && path.startsWith(fileRoot)) | ||
| return Collections.singletonList(next); | ||
| } | ||
| } | ||
| for (java.nio.file.Path segment : anchorPath.relativize(path)) | ||
| { | ||
| next = next.getChild(segment.toString()); | ||
| if (next == null) | ||
| break; | ||
| candidates.add(next); | ||
| } | ||
|
|
||
| // TODO: Create cache of file root and pipeline root paths -> list of containers | ||
| // A folder may have its own root elsewhere, so take the deepest candidate whose actual root holds the path | ||
| for (Container c : candidates.reversed()) | ||
| { | ||
| if (c.isRoot()) | ||
| continue; | ||
| java.nio.file.Path fileRoot = getExistingFileRootPath(c); | ||
| if (fileRoot != null && URIUtil.isDescendant(fileRoot.toUri(), path.toUri())) | ||
| return c; | ||
| } | ||
|
|
||
| return Collections.emptyList(); | ||
| return null; | ||
| } | ||
|
|
||
| private @Nullable java.nio.file.Path getExistingFileRootPath(@NotNull Container c) | ||
| { | ||
| return isFileRootDisabled(c) ? null : resolveFileRootPath(c, false); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -1849,6 +1861,33 @@ public void fileRootsTest() | |
|
|
||
| } | ||
|
|
||
| @Test | ||
| public void testContainerForFilePath() | ||
| { | ||
| //pre-clean | ||
| cleanup(); | ||
|
|
||
| FileContentService svc = FileContentService.get(); | ||
| Assert.assertNotNull(svc); | ||
|
|
||
| Container project1 = ContainerManager.createContainer(ContainerManager.getRoot(), PROJECT1, TestContext.get().getUser()); | ||
| Container subfolder1 = ContainerManager.createContainer(project1, PROJECT1_SUBFOLDER1, TestContext.get().getUser()); | ||
| Container project2 = ContainerManager.createContainer(ContainerManager.getRoot(), PROJECT2, TestContext.get().getUser()); | ||
|
|
||
| java.nio.file.Path project2File = svc.getFileRootPath(project2, ContentType.files).resolve(TXT_FILE); | ||
| Assert.assertEquals("Default root path", project2, svc.getContainerForFilePath(project2File)); | ||
|
|
||
| File testRoot = getTestRoot(); | ||
| svc.setFileRoot(project1, testRoot); | ||
|
|
||
| java.nio.file.Path subfolderFile = svc.getFileRootPath(subfolder1, ContentType.files).resolve(TXT_FILE); | ||
| Assert.assertEquals("Inherited custom root path", subfolder1, svc.getContainerForFilePath(subfolderFile)); | ||
| Assert.assertEquals("Custom root path", project1, svc.getContainerForFilePath(testRoot.toPath().resolve("unmatched").resolve(TXT_FILE))); | ||
|
|
||
| java.nio.file.Path unmanaged = svc.getSiteDefaultRoot().toPath().resolve(FILE_ROOT_SUFFIX + "Unmanaged").resolve(TXT_FILE); | ||
| Assert.assertNull("Unmanaged path", svc.getContainerForFilePath(unmanaged)); | ||
| } | ||
|
|
||
| private void assertPathsEqual(String msg, File expected, File actual) | ||
| { | ||
| String expectedPath = FileUtil.getAbsoluteCaseSensitiveFile(expected).getPath(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
claude code review came up with a few high level findings that might be worth reviewing before human code review: