Skip to content

Commit c4eb759

Browse files
HannesWelleclipse-tycho-bot
authored andcommitted
Support resource links to nested files and folders
Generally support the resolution of links from file-system resources (files and folders) located within any folder, not only to top-level resources. Also ensure links are processed in the order recorded in the .project file to allow more specific links to be listed and considered first. (cherry picked from commit 20afff2)
1 parent b26ed0a commit c4eb759

2 files changed

Lines changed: 109 additions & 33 deletions

File tree

tycho-metadata-model/src/main/java/org/eclipse/tycho/model/project/ProjectParser.java

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,10 @@ public static EclipseProject parse(Path path) throws IOException {
7979
Map<String, URI> variablesMap = variables.stream()
8080
.collect(Collectors.toMap(ProjectVariable::name, ProjectVariable::value));
8181
NodeList linkNodes = root.getElementsByTagName("link");
82-
Set<LinkDescription> links = IntStream.range(0, linkNodes.getLength()).mapToObj(i -> linkNodes.item(i))
82+
Collection<LinkDescription> links = IntStream.range(0, linkNodes.getLength()).mapToObj(linkNodes::item)
8383
.map(Element.class::cast).map(e -> parseLink(e)).filter(Objects::nonNull)
84-
.collect(Collectors.toSet());
84+
// Maintain order from project-file to allow more specific links to be listed first
85+
.distinct().toList();
8586

8687
return new EclipseProject() {
8788

@@ -139,12 +140,8 @@ public Path getFile(Path path) {
139140
return path;
140141
}
141142
Path relative = location.relativize(path);
142-
for (LinkDescription link : links) {
143-
if (relative.startsWith(link.name())) {
144-
return resolvePath(link, relative, location, variablesMap);
145-
}
146-
}
147-
return path;
143+
Path resolved = resolveLinks(links, relative, location, variablesMap);
144+
return resolved != null ? resolved : path;
148145
}
149146

150147
@Override
@@ -169,7 +166,23 @@ private static Path uriToPath(URI uri) {
169166
return null;
170167
}
171168

172-
static Path resolvePath(LinkDescription link, Path path, Path projectLocation, Map<String, URI> variablesMap) {
169+
static Path resolveLinks(Collection<LinkDescription> links, Path relative, Path projectLocation,
170+
Map<String, URI> variablesMap) {
171+
for (LinkDescription link : links) {
172+
boolean isFile = link.type() == LinkDescription.FILE;
173+
174+
if (isFile && relative.equals(link.name())) {
175+
return resolvePath(link, projectLocation, variablesMap);
176+
177+
} else if (!isFile && relative.startsWith(link.name())) {
178+
Path target = resolvePath(link, projectLocation, variablesMap);
179+
return appendRemaining(target, link.name(), relative);
180+
}
181+
}
182+
return null;
183+
}
184+
185+
private static Path resolvePath(LinkDescription link, Path projectLocation, Map<String, URI> variablesMap) {
173186
Path linkPath;
174187
if (link.location() != null) {
175188
linkPath = link.location();
@@ -190,21 +203,13 @@ static Path resolvePath(LinkDescription link, Path path, Path projectLocation, M
190203
} else {
191204
return null;
192205
}
193-
if (link.type() == LinkDescription.FILE) {
194-
//the path must actually match each others as it is a file!
195-
if (path.getNameCount() > 1) {
196-
return null;
197-
}
198-
}
199206

200207
Path result = resolveVariables(linkPath, projectLocation, variablesMap);
201208
if (result == null) {
202209
return null;
203210
}
204211
result = projectLocation.resolve(result);
205-
result = appendRemaining(path, result);
206212
result = result.normalize();
207-
208213
return result;
209214
}
210215

@@ -300,12 +305,18 @@ private static Path dotDotTimes(int count) {
300305

301306
private static Path appendRemaining(Path path, Path resolvedPath) {
302307
int count = path.getNameCount();
303-
for (int i = 1; i < count; i++) {
304-
resolvedPath = resolvedPath.resolve(path.getName(i));
308+
if (count > 1) {
309+
resolvedPath = resolvedPath.resolve(path.subpath(1, count));
305310
}
306311
return resolvedPath;
307312
}
308313

314+
private static Path appendRemaining(Path path, Path added, Path appendix) {
315+
return path != null && added.getNameCount() < appendix.getNameCount()
316+
? path.resolve(appendix.subpath(added.getNameCount(), appendix.getNameCount()))
317+
: path;
318+
}
319+
309320
private static ProjectVariable parseVariable(Element element) {
310321
try {
311322
String name = element.getElementsByTagName("name").item(0).getTextContent();

tycho-metadata-model/src/test/java/org/eclipse/tycho/model/project/ProjectParserTest.java

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
*******************************************************************************/
1313
package org.eclipse.tycho.model.project;
1414

15+
import static org.eclipse.tycho.model.project.ProjectParser.resolveLinks;
1516
import static org.junit.jupiter.api.Assertions.assertEquals;
1617
import static org.junit.jupiter.api.Assertions.assertNull;
1718

1819
import java.net.URI;
1920
import java.nio.file.Path;
21+
import java.util.List;
2022
import java.util.Map;
2123

2224
import org.eclipse.tycho.model.project.ProjectParser.LinkDescription;
@@ -46,109 +48,172 @@ public class ProjectParserTest {
4648
@Test
4749
void testLinkNoLocationOrUri() throws Exception {
4850
LinkDescription link = new LinkDescription(Path.of("link"), LinkDescription.FOLDER, null, null);
49-
Path result = ProjectParser.resolvePath(link, Path.of("link/subdir"), PROJECT_PATH, VARS);
51+
Path result = resolveLinks(List.of(link), Path.of("link/subdir"), PROJECT_PATH, VARS);
5052
assertNull(result);
5153
}
5254

5355
@Test
5456
void testLinkDirSimpleCase() throws Exception {
5557
LinkDescription link = new LinkDescription(Path.of("link"), LinkDescription.FOLDER, null,
5658
URI.create("foo/bar"));
57-
Path result = ProjectParser.resolvePath(link, Path.of("link/subdir"), PROJECT_PATH, VARS);
59+
Path result = resolveLinks(List.of(link), Path.of("link/subdir"), PROJECT_PATH, VARS);
5860
assertEquals(Path.of("/path/to/project/foo/bar/subdir"), result);
5961
}
6062

6163
@Test
6264
void testLinkDirProjectLoc() throws Exception {
6365
LinkDescription link = new LinkDescription(Path.of("link"), LinkDescription.FOLDER, null,
6466
URI.create("PROJECT_LOC/bar"));
65-
Path result = ProjectParser.resolvePath(link, Path.of("link/subdir"), PROJECT_PATH, VARS);
67+
Path result = resolveLinks(List.of(link), Path.of("link/subdir"), PROJECT_PATH, VARS);
6668
assertEquals(Path.of("/path/to/project/bar/subdir"), result);
6769
}
6870

6971
@Test
7072
void testLinkDirParent1ProjectLoc() throws Exception {
7173
LinkDescription link = new LinkDescription(Path.of("link"), LinkDescription.FOLDER, null,
7274
URI.create("PARENT-1-PROJECT_LOC/otherproject"));
73-
Path result = ProjectParser.resolvePath(link, Path.of("link/subdir"), PROJECT_PATH, VARS);
75+
Path result = resolveLinks(List.of(link), Path.of("link/subdir"), PROJECT_PATH, VARS);
7476
assertEquals(Path.of("/path/to/otherproject/subdir"), result);
7577
}
7678

7779
@Test
7880
void testLinkDirParent2ProjectLoc() throws Exception {
7981
LinkDescription link = new LinkDescription(Path.of("link"), LinkDescription.FOLDER, null,
8082
URI.create("PARENT-2-PROJECT_LOC/anotherdir"));
81-
Path result = ProjectParser.resolvePath(link, Path.of("link/subdir"), PROJECT_PATH, VARS);
83+
Path result = resolveLinks(List.of(link), Path.of("link/subdir"), PROJECT_PATH, VARS);
8284
assertEquals(Path.of("/path/anotherdir/subdir"), result);
8385
}
8486

8587
@Test
8688
void testLinkDirVarExpandEndingInProjectLoc() throws Exception {
8789
LinkDescription link = new LinkDescription(Path.of("link"), LinkDescription.FOLDER, null, URI.create("FOO1/x"));
88-
Path result = ProjectParser.resolvePath(link, Path.of("link/subdir"), PROJECT_PATH, VARS);
90+
Path result = resolveLinks(List.of(link), Path.of("link/subdir"), PROJECT_PATH, VARS);
8991
assertEquals(Path.of("/path/to/project/other/dir/bar/foo/x/subdir"), result);
9092
}
9193

9294
@Test
9395
void testLinkDirVarExpandEndingInParent1ProjectLoc() throws Exception {
9496
LinkDescription link = new LinkDescription(Path.of("link"), LinkDescription.FOLDER, null, URI.create("FOO2/x"));
95-
Path result = ProjectParser.resolvePath(link, Path.of("link/subdir"), PROJECT_PATH, VARS);
97+
Path result = resolveLinks(List.of(link), Path.of("link/subdir"), PROJECT_PATH, VARS);
9698
assertEquals(Path.of("/path/to/otherproject/dir/bar/foo/x/subdir"), result);
9799
}
98100

99101
@Test
100102
void testLinkDirRecursion() throws Exception {
101103
LinkDescription link = new LinkDescription(Path.of("link"), LinkDescription.FOLDER, null,
102104
URI.create("RECURSION1/x"));
103-
Path result = ProjectParser.resolvePath(link, Path.of("link/subdir"), PROJECT_PATH, VARS);
105+
Path result = resolveLinks(List.of(link), Path.of("link/subdir"), PROJECT_PATH, VARS);
104106
assertNull(result);
105107
}
106108

107109
@Test
108110
void testLinkDirVarExpandLiteral() throws Exception {
109111
LinkDescription link = new LinkDescription(Path.of("link"), LinkDescription.FOLDER, null,
110112
URI.create("LITERAL/x"));
111-
Path result = ProjectParser.resolvePath(link, Path.of("link/subdir"), PROJECT_PATH, VARS);
113+
Path result = resolveLinks(List.of(link), Path.of("link/subdir"), PROJECT_PATH, VARS);
112114
assertEquals(Path.of("/path/to/project/value/x/subdir"), result);
113115
}
114116

115117
@Test
116118
void testLinkDirVarExpandFailingKeepDollarVariable() throws Exception {
117119
LinkDescription link = new LinkDescription(Path.of("link"), LinkDescription.FOLDER, null,
118120
URI.create("UNKNOWN/x"));
119-
Path result = ProjectParser.resolvePath(link, Path.of("link/subdir"), PROJECT_PATH, VARS);
121+
Path result = resolveLinks(List.of(link), Path.of("link/subdir"), PROJECT_PATH, VARS);
120122
assertEquals(Path.of("/path/to/project/${DONTKNOW}/foo/x/subdir"), result);
121123
}
122124

123125
@Test
124126
void testLinkDirAbsolutePathInsteadOfUri() throws Exception {
125127
LinkDescription link = new LinkDescription(Path.of("link"), LinkDescription.FOLDER, Path.of("/absolute/path"),
126128
null);
127-
Path result = ProjectParser.resolvePath(link, Path.of("link/subdir"), PROJECT_PATH, VARS);
129+
Path result = resolveLinks(List.of(link), Path.of("link/subdir"), PROJECT_PATH, VARS);
128130
assertEquals(Path.of("/absolute/path/subdir"), result);
129131
}
130132

131133
@Test
132134
void testLinkFileSimpleCase() throws Exception {
133135
LinkDescription link = new LinkDescription(Path.of("link.txt"), LinkDescription.FILE, null,
134136
URI.create("linktarget.txt"));
135-
Path result = ProjectParser.resolvePath(link, Path.of("link.txt"), PROJECT_PATH, VARS);
137+
Path result = resolveLinks(List.of(link), Path.of("link.txt"), PROJECT_PATH, VARS);
136138
assertEquals(Path.of("/path/to/project/linktarget.txt"), result);
137139
}
138140

141+
@Test
142+
void testLinkFileInDirSimpleCase() throws Exception {
143+
LinkDescription link = new LinkDescription(Path.of("folder/link.txt"), LinkDescription.FILE, null,
144+
URI.create("linktarget.txt"));
145+
Path result = resolveLinks(List.of(link), Path.of("folder/link.txt"), PROJECT_PATH, VARS);
146+
assertEquals(Path.of("/path/to/project/linktarget.txt"), result);
147+
}
148+
149+
@Test
150+
void testLinkedFileInDirSimpleCase() throws Exception {
151+
LinkDescription link = new LinkDescription(Path.of("link.txt"), LinkDescription.FILE, null,
152+
URI.create("folder/linktarget.txt"));
153+
Path result = resolveLinks(List.of(link), Path.of("link.txt"), PROJECT_PATH, VARS);
154+
assertEquals(Path.of("/path/to/project/folder/linktarget.txt"), result);
155+
}
156+
157+
@Test
158+
void testLinkFileFromDirToDirSimpleCase() throws Exception {
159+
LinkDescription link = new LinkDescription(Path.of("folder/link.txt"), LinkDescription.FILE, null,
160+
URI.create("folder/linktarget.txt"));
161+
Path result = resolveLinks(List.of(link), Path.of("folder/link.txt"), PROJECT_PATH, VARS);
162+
assertEquals(Path.of("/path/to/project/folder/linktarget.txt"), result);
163+
}
164+
165+
@Test
166+
void testLinkedFileInLinkedDir() throws Exception {
167+
LinkDescription fileLink = new LinkDescription(Path.of("folder/link.txt"), LinkDescription.FILE, null,
168+
URI.create("folder/linktarget.txt"));
169+
LinkDescription folderLink = new LinkDescription(Path.of("folder"), LinkDescription.FOLDER, null,
170+
URI.create("foldertarget"));
171+
172+
List<LinkDescription> links = List.of(fileLink, folderLink); // expect file to be resolved
173+
assertEquals(Path.of("/path/to/project/folder/linktarget.txt"),
174+
resolveLinks(links, Path.of("folder/link.txt"), PROJECT_PATH, VARS));
175+
links = List.of(folderLink, fileLink); // expect folder to be resolved
176+
assertEquals(Path.of("/path/to/project/foldertarget/link.txt"),
177+
resolveLinks(List.of(folderLink, fileLink), Path.of("folder/link.txt"), PROJECT_PATH, VARS));
178+
}
179+
180+
@Test
181+
void testLinkedNestedDirSimpleCase() throws Exception {
182+
LinkDescription link = new LinkDescription(Path.of("folder"), LinkDescription.FOLDER, null,
183+
URI.create("folder/foldertarget2"));
184+
Path result = resolveLinks(List.of(link), Path.of("folder/link.txt"), PROJECT_PATH, VARS);
185+
assertEquals(Path.of("/path/to/project/folder/foldertarget2/link.txt"), result);
186+
}
187+
188+
@Test
189+
void testLinkToNestedDirSimpleCase() throws Exception {
190+
LinkDescription link = new LinkDescription(Path.of("folder/folder2"), LinkDescription.FOLDER, null,
191+
URI.create("foldertarget"));
192+
Path result = resolveLinks(List.of(link), Path.of("folder/folder2/link.txt"), PROJECT_PATH, VARS);
193+
assertEquals(Path.of("/path/to/project/foldertarget/link.txt"), result);
194+
}
195+
196+
@Test
197+
void testLinkDirFromDirToDirSimpleCase() throws Exception {
198+
LinkDescription link = new LinkDescription(Path.of("folder/folder2"), LinkDescription.FOLDER, null,
199+
URI.create("folder/foldertarget2"));
200+
Path result = resolveLinks(List.of(link), Path.of("folder/folder2/link.txt"), PROJECT_PATH, VARS);
201+
assertEquals(Path.of("/path/to/project/folder/foldertarget2/link.txt"), result);
202+
}
203+
139204
@Test
140205
void testLinkFileAbsolutePathInsteadOfUri() throws Exception {
141206
LinkDescription link = new LinkDescription(Path.of("link.txt"), LinkDescription.FILE,
142207
Path.of("/path/to/some/txtfile.txt"), null);
143-
Path result = ProjectParser.resolvePath(link, Path.of("link.txt"), PROJECT_PATH, VARS);
208+
Path result = resolveLinks(List.of(link), Path.of("link.txt"), PROJECT_PATH, VARS);
144209
assertEquals(Path.of("/path/to/some/txtfile.txt"), result);
145210
}
146211

147212
@Test
148213
void testLinkFileIllegalSegmentAfterFile() throws Exception {
149214
LinkDescription link = new LinkDescription(Path.of("link.txt"), LinkDescription.FILE,
150215
Path.of("/path/to/some/txtfile.txt"), null);
151-
Path result = ProjectParser.resolvePath(link, Path.of("link.txt/thisisinvalid"), PROJECT_PATH, VARS);
216+
Path result = resolveLinks(List.of(link), Path.of("link.txt/thisisinvalid"), PROJECT_PATH, VARS);
152217
assertNull(result);
153218
}
154219

0 commit comments

Comments
 (0)