Skip to content

Commit

Permalink
Follow P2 contract of cached file's extension (eclipse-tycho#2938)
Browse files Browse the repository at this point in the history
P2 relies on correct file extensions to parse cached files.

Fixes eclipse-tycho#2938

See
eclipse-equinox/p2#355
  • Loading branch information
basilevs committed Oct 21, 2023
1 parent a9b7b40 commit 8ef7422
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,16 @@ public synchronized File fetchFile(URI uri, HttpTransportFactory transportFactor
}
updateHeader(response, code);
if (isRedirected(code)) {
return SharedHttpCacheStorage.this.getCacheEntry(getRedirect(uri), logger)
File cachedFile = SharedHttpCacheStorage.this.getCacheEntry(getRedirect(uri), logger)
.getCacheFile(transportFactory);
// https://github.com/eclipse-tycho/tycho/issues/2938
// Redirect may change extension. P2's SimpleMetadataRepositoryFactory relies on
// accurate file extension to be cached.
// Copying file to accommodate original request and its file extension.
// Once https://github.com/eclipse-equinox/p2/issues/355 is fixed, cachedFile
// may be returned directly without copying.
FileUtils.copyFile(cachedFile, file);
return file;
}
if (exits) {
FileUtils.forceDelete(file);
Expand Down
4 changes: 4 additions & 0 deletions tycho-its/projects/target.content_jar/category.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<site>
<feature id="issue_2938_reproducer"/>
</site>
49 changes: 49 additions & 0 deletions tycho-its/projects/target.content_jar/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>tycho-its-project.p2Repository.slicerDependencies</groupId>
<artifactId>aggregator</artifactId>
<version>1.0.0</version>
<packaging>eclipse-repository</packaging>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-maven-plugin</artifactId>
<version>${tycho-version}</version>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>target-platform-configuration</artifactId>
<version>${tycho-version}</version>
<configuration>
<resolver>p2</resolver>
<executionEnvironment>JavaSE-11</executionEnvironment>
<target>
<file>targetplatform.target</file>
</target>
<environments>
<environment>
<os>win32</os>
<ws>win32</ws>
<arch>x86_64</arch>
</environment>
<environment>
<os>linux</os>
<ws>gtk</ws>
<arch>x86_64</arch>
</environment>
</environments>
</configuration>
</plugin>
</plugins>
</build>

</project>
11 changes: 11 additions & 0 deletions tycho-its/projects/target.content_jar/targetplatform.target
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<target name="p2Repository.slicerDependencies" sequenceNumber="1">
<locations>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="slicer" includeSource="true" type="InstallableUnit">
<repository id="repoA" location="url"/>

<unit id="issue_2938_reproducer.feature.group" version="0.0.0"/>
</location>
</locations>
</target>
Binary file added tycho-its/repositories/content_jar/artifacts.jar
Binary file not shown.
Binary file added tycho-its/repositories/content_jar/content.jar
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*******************************************************************************
* Copyright (c) 2023, 2023 Sonatype Inc. and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Vasili Gulevich - initial implementation
*******************************************************************************/
package org.eclipse.tycho.test.tycho2938;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;

import org.apache.commons.io.FileUtils;
import org.apache.maven.it.VerificationException;
import org.apache.maven.it.Verifier;
import org.eclipse.tycho.test.AbstractTychoIntegrationTest;
import org.eclipse.tycho.test.util.HttpServer;
import org.eclipse.tycho.test.util.ResourceUtil;
import org.eclipse.tycho.test.util.TargetDefinitionUtil;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public class ContentJarTest extends AbstractTychoIntegrationTest {
private HttpServer server;
@Rule
public final TemporaryFolder temporaryFolder = new TemporaryFolder();

@Before
public void startServer() throws Exception {
server = HttpServer.startServer();
File originalResource = ResourceUtil.resolveTestResource("repositories/content_jar");
FileUtils.copyDirectory(originalResource, temporaryFolder.getRoot());
}

@After
public void stopServer() throws Exception {
if (server != null) {
server.stop();
}
}

private void mangleFileNames(Path repositoryRoot) throws IOException {
Files.walkFileTree(repositoryRoot, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.move(file, file.getParent().resolve(file.getFileName() + "_invalid"));
return super.visitFile(file, attrs);
}
});
}

@Test
public void noRedirect() throws Exception {
File repositoryRoot = temporaryFolder.getRoot();
String repoUrl = server.addServer("repoA", repositoryRoot);
Verifier verifier = getVerifier("target.content_jar", false);
File platformFile = new File(verifier.getBasedir(), "targetplatform.target");
TargetDefinitionUtil.setRepositoryURLs(platformFile, "repoA", repoUrl);
verifier.executeGoals(Arrays.asList("package"));
verifier.verifyErrorFreeLog();
}

@Test
public void redirectKeepFilename() throws Exception {
File repositoryRoot = temporaryFolder.getRoot();
String repoUrl = server.addServer("repoA", repositoryRoot);
String redirectedUrl = server.addRedirect("repoB", originalPath -> repoUrl + originalPath);
Verifier verifier = getVerifier("target.content_jar", false);
File platformFile = new File(verifier.getBasedir(), "targetplatform.target");
TargetDefinitionUtil.setRepositoryURLs(platformFile, "repoA", redirectedUrl);
verifier.executeGoals(Arrays.asList("package"));
verifier.verifyErrorFreeLog();
}

@Test
public void redirectToBadLocation() throws Exception {
File repositoryRoot = temporaryFolder.getRoot();
String repoUrl = server.addServer("repoA", repositoryRoot);
String redirectedUrl = server.addRedirect("repoB", originalPath -> repoUrl + originalPath + "_invalid");
Verifier verifier = getVerifier("target.content_jar", false);
File platformFile = new File(verifier.getBasedir(), "targetplatform.target");
TargetDefinitionUtil.setRepositoryURLs(platformFile, "repoA", redirectedUrl);
Assert.assertThrows(VerificationException.class, () -> verifier.executeGoal("package"));

verifier.verifyTextInLog("No repository found at " + redirectedUrl);
}

@Test
public void redirectToMangledLocations() throws Exception {
File repositoryRoot = temporaryFolder.getRoot();
mangleFileNames(repositoryRoot.toPath());
String mangledRepoUrl = server.addServer("repoA", repositoryRoot);

// https://github.com/eclipse-tycho/tycho/issues/2938
// Redirect may change extension.
String originaRepoUrl = server.addRedirect("repoB", originalPath -> mangledRepoUrl + originalPath + "_invalid");

Verifier verifier = getVerifier("target.content_jar", false);
File platformFile = new File(verifier.getBasedir(), "targetplatform.target");
TargetDefinitionUtil.setRepositoryURLs(platformFile, "repoA", originaRepoUrl);
verifier.executeGoals(Arrays.asList("package"));
verifier.verifyErrorFreeLog();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

Expand Down Expand Up @@ -74,6 +76,21 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
}
}

private static class RedirectServlet extends HttpServlet {
private final Function<String, String> relativeUrlToNewUrl;

public RedirectServlet(Function<String, String> relativeUrlToNewUrl2) {
super();
this.relativeUrlToNewUrl = relativeUrlToNewUrl2;
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect(relativeUrlToNewUrl.apply(req.getServletPath()));
}

}

private static final int BIND_ATTEMPTS = 20;

private final Server server;
Expand Down Expand Up @@ -155,16 +172,32 @@ public String addServer(String contextName, final File content) {
ServletContextHandler context = new ServletContextHandler(contexts, URIUtil.SLASH + contextName);
context.setResourceBase(content.getAbsolutePath());

addMonitoring(contextName, context);
try {
context.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
return getUrl(contextName);
}

private void addMonitoring(String contextName, ServletContextHandler context) {
MonitoringServlet monitoringServlet = new MonitoringServlet();
contextName2servletsMap.put(contextName, monitoringServlet);
context.addServlet(new ServletHolder(monitoringServlet), URIUtil.SLASH);
contexts.addHandler(context);
}

public String addRedirect(String contextName, Function<String, String> relativeUrlToNewUrl) {
ServletContextHandler context = new ServletContextHandler(contexts, URIUtil.SLASH + contextName);
context.addServlet(new ServletHolder(new RedirectServlet(relativeUrlToNewUrl)), URIUtil.SLASH);
try {
context.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
return getUrl(contextName);

}

public String getUrl(String contextName) {
Expand Down

0 comments on commit 8ef7422

Please sign in to comment.