Merge remote-tracking branch 'upstream/dev/1.1' into dev/1.1

# Conflicts:
#	src/main/java/net/fabricmc/loom/configuration/providers/minecraft/SingleJarMinecraftProvider.java
This commit is contained in:
Juuz
2023-02-19 01:37:05 +02:00
7 changed files with 74 additions and 22 deletions

View File

@@ -122,4 +122,9 @@ public abstract class ModSettings implements Named {
@Inject
public abstract Project getProject();
@Override
public String toString() {
return "ModSettings '" + getName() + "'";
}
}

View File

@@ -142,4 +142,9 @@ public abstract class RemapConfigurationSettings implements Named {
private Provider<Boolean> defaultDependencyTransforms() {
return getSourceSet().map(sourceSet -> sourceSet.getName().equals(SourceSet.MAIN_SOURCE_SET_NAME) || sourceSet.getName().equals("client"));
}
@Override
public String toString() {
return "RemapConfigurationSettings '" + getName() + "'";
}
}

View File

@@ -68,6 +68,12 @@ public class SingleJarMinecraftProvider extends MinecraftProvider {
@Override
public void provide() throws Exception {
super.provide();
// Server only JARs are supported on any version, client only JARs are pretty much useless after 1.3.
if (provideClient() && getVersionInfo().isVersionOrNewer("2012-07-25T22:00:00+00:00" /* 1.3 release date */)) {
getProject().getLogger().warn("Using `clientOnlyMinecraftJar()` is not recommended for Minecraft versions 1.3 or newer.");
}
processJar();
}

View File

@@ -42,6 +42,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.FileTime;
import java.time.Duration;
@@ -58,7 +59,7 @@ import org.slf4j.LoggerFactory;
import net.fabricmc.loom.util.AttributeHelper;
import net.fabricmc.loom.util.Checksum;
public class Download {
public final class Download {
private static final String E_TAG = "ETag";
private static final Logger LOGGER = LoggerFactory.getLogger(Download.class);
@@ -73,8 +74,10 @@ public class Download {
private final boolean offline;
private final Duration maxAge;
private final DownloadProgressListener progressListener;
private final HttpClient.Version httpVersion;
private final int downloadAttempt;
Download(URI url, String expectedHash, boolean useEtag, boolean forceDownload, boolean offline, Duration maxAge, DownloadProgressListener progressListener) {
Download(URI url, String expectedHash, boolean useEtag, boolean forceDownload, boolean offline, Duration maxAge, DownloadProgressListener progressListener, HttpClient.Version httpVersion, int downloadAttempt) {
this.url = url;
this.expectedHash = expectedHash;
this.useEtag = useEtag;
@@ -82,6 +85,8 @@ public class Download {
this.offline = offline;
this.maxAge = maxAge;
this.progressListener = progressListener;
this.httpVersion = httpVersion;
this.downloadAttempt = downloadAttempt;
}
private HttpClient getHttpClient() throws DownloadException {
@@ -97,12 +102,14 @@ public class Download {
private HttpRequest getRequest() {
return HttpRequest.newBuilder(url)
.version(httpVersion)
.GET()
.build();
}
private HttpRequest getETagRequest(String etag) {
return HttpRequest.newBuilder(url)
.version(httpVersion)
.GET()
.header("If-None-Match", etag)
.build();
@@ -148,7 +155,7 @@ public class Download {
doDownload(output);
} catch (Throwable throwable) {
tryCleanup(output);
throw error(throwable, "Failed to download (%s) to (%s)", url, output);
throw error(throwable, "Failed to download file from (%s) to (%s)", url, output);
} finally {
progressListener.onEnd();
}
@@ -194,7 +201,7 @@ public class Download {
final long length = Long.parseLong(response.headers().firstValue("Content-Length").orElse("-1"));
AtomicLong totalBytes = new AtomicLong(0);
try (OutputStream outputStream = Files.newOutputStream(output)) {
try (OutputStream outputStream = Files.newOutputStream(output, StandardOpenOption.CREATE_NEW)) {
copyWithCallback(decodeOutput(response), outputStream, value -> {
if (length < 0) {
return;
@@ -203,12 +210,26 @@ public class Download {
progressListener.onProgress(totalBytes.addAndGet(value), length);
});
} catch (IOException e) {
tryCleanup(output);
throw error(e, "Failed to decode and write download output");
}
if (Files.notExists(output)) {
throw error("No file was downloaded");
}
if (length > 0) {
try {
final long actualLength = Files.size(output);
if (actualLength != length) {
throw error("Unexpected file length of %d bytes, expected %d bytes".formatted(actualLength, length));
}
} catch (IOException e) {
throw error(e);
}
}
} else {
tryCleanup(output);
throw error("HTTP request to (%s) returned unsuccessful status (%d)", url, statusCode);
throw error("HTTP request returned unsuccessful status (%d)", statusCode);
}
if (useEtag) {
@@ -261,7 +282,7 @@ public class Download {
}
private boolean requiresDownload(Path output) throws DownloadException {
if (getAndResetLock(output)) {
if (getAndResetLock(output) & downloadAttempt == 1) {
LOGGER.warn("Forcing downloading {} as existing lock file was found. This may happen if the gradle build was forcefully canceled.", output);
return true;
}

View File

@@ -27,6 +27,7 @@ package net.fabricmc.loom.util.download;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -46,6 +47,7 @@ public class DownloadBuilder {
private DownloadProgressListener progressListener = DownloadProgressListener.NONE;
private int maxRetries = 3;
private boolean allowInsecureProtocol = false;
private HttpClient.Version httpVersion = HttpClient.Version.HTTP_2;
private DownloadBuilder(URI url) {
this.url = url;
@@ -100,12 +102,17 @@ public class DownloadBuilder {
return this;
}
private Download build() {
public DownloadBuilder httpVersion(HttpClient.Version httpVersion) {
this.httpVersion = httpVersion;
return this;
}
private Download build(int downloadAttempt) {
if (!allowInsecureProtocol && !isSecureUrl(url)) {
throw new IllegalArgumentException("Cannot create download for url (%s) with insecure protocol".formatted(url.toString()));
}
return new Download(this.url, this.expectedHash, this.useEtag, this.forceDownload, this.offline, maxAge, progressListener);
return new Download(this.url, this.expectedHash, this.useEtag, this.forceDownload, this.offline, maxAge, progressListener, httpVersion, downloadAttempt);
}
public void downloadPathAsync(Path path, DownloadExecutor executor) {
@@ -113,19 +120,19 @@ public class DownloadBuilder {
}
public void downloadPath(Path path) throws DownloadException {
withRetries(() -> {
build().downloadPath(path);
withRetries((download) -> {
download.downloadPath(path);
return null;
});
}
public String downloadString() throws DownloadException {
return withRetries(() -> build().downloadString());
return withRetries(Download::downloadString);
}
public String downloadString(Path cache) throws DownloadException {
return withRetries(() -> {
build().downloadPath(cache);
return withRetries((download) -> {
download.downloadPath(cache);
try {
return Files.readString(cache, StandardCharsets.UTF_8);
@@ -141,10 +148,15 @@ public class DownloadBuilder {
});
}
private <T> T withRetries(DownloadSupplier<T> supplier) throws DownloadException {
private <T> T withRetries(DownloadFunction<T> supplier) throws DownloadException {
for (int i = 1; i <= maxRetries; i++) {
try {
return supplier.get();
if (i == maxRetries) {
// Last ditch attempt, try over HTTP 1.1
httpVersion(HttpClient.Version.HTTP_1_1);
}
return supplier.get(build(i));
} catch (DownloadException e) {
if (i == maxRetries) {
throw new DownloadException(String.format(Locale.ENGLISH, "Failed download after %d attempts", maxRetries), e);
@@ -166,7 +178,7 @@ public class DownloadBuilder {
}
@FunctionalInterface
private interface DownloadSupplier<T> {
T get() throws DownloadException;
private interface DownloadFunction<T> {
T get(Download download) throws DownloadException;
}
}

View File

@@ -27,13 +27,13 @@ package net.fabricmc.loom.test
import org.gradle.util.GradleVersion
class LoomTestConstants {
private final static String NIGHTLY_VERSION = "8.1-20230119104422+0000"
private final static String NIGHTLY_VERSION = "8.1-20230217231705+0000"
private final static boolean NIGHTLY_EXISTS = nightlyExists(NIGHTLY_VERSION)
// Test against the version of Gradle being used to build loom
public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion()
// Test against Gradle 8
public final static String GRADLE_8 = "8.0-rc-2"
public final static String GRADLE_8 = "8.0.1"
// Tests that depend specifically on the nightly will run on the current version when the nightly is not available.
public final static String PRE_RELEASE_GRADLE = NIGHTLY_EXISTS ? NIGHTLY_VERSION : DEFAULT_GRADLE
// Randomly sorted to ensure that all versions can run with a clean gradle home.

View File

@@ -30,13 +30,16 @@ import net.fabricmc.loom.util.download.Download
import net.fabricmc.loom.util.download.DownloadException
import net.fabricmc.loom.util.download.DownloadExecutor
import net.fabricmc.loom.util.download.DownloadProgressListener
import spock.lang.IgnoreIf
import java.nio.file.Files
import java.nio.file.attribute.FileTime
import java.nio.file.Paths
import java.nio.file.attribute.FileTime
import java.time.Duration
import java.time.Instant
class DownloadFileTest extends DownloadTest {
@IgnoreIf({ os.windows }) // Requires admin on windows.
def "Directory: Symlink"() {
setup:
server.get("/symlinkFile") {