mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-03-28 04:07:01 -05:00
Merge remote-tracking branch 'upstream/dev/1.0' into dev/1.0
# Conflicts: # build.gradle
This commit is contained in:
@@ -88,7 +88,6 @@ dependencies {
|
||||
implementation ('org.ow2.asm:asm-commons:9.3')
|
||||
implementation ('org.ow2.asm:asm-tree:9.3')
|
||||
implementation ('org.ow2.asm:asm-util:9.3')
|
||||
implementation ('com.github.mizosoft.methanol:methanol:1.7.0')
|
||||
implementation ('me.tongfei:progressbar:0.9.0')
|
||||
|
||||
// game handling utils
|
||||
|
||||
@@ -101,6 +101,7 @@ public abstract class AbstractRunTask extends JavaExec {
|
||||
if (canUseArgFile()) {
|
||||
final String content = "-classpath\n" + this.classpath.getFiles().stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.map(AbstractRunTask::quoteArg)
|
||||
.collect(Collectors.joining(System.getProperty("path.separator")));
|
||||
|
||||
try {
|
||||
@@ -120,6 +121,50 @@ public abstract class AbstractRunTask extends JavaExec {
|
||||
return args;
|
||||
}
|
||||
|
||||
// Based off https://github.com/JetBrains/intellij-community/blob/295dd68385a458bdfde638152e36d19bed18b666/platform/util/src/com/intellij/execution/CommandLineWrapperUtil.java#L87
|
||||
private static String quoteArg(String arg) {
|
||||
final String specials = " #'\"\n\r\t\f";
|
||||
|
||||
if (!containsAnyChar(arg, specials)) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
final StringBuilder sb = new StringBuilder(arg.length() * 2);
|
||||
|
||||
for (int i = 0; i < arg.length(); i++) {
|
||||
char c = arg.charAt(i);
|
||||
|
||||
switch (c) {
|
||||
case ' ', '#', '\'' -> sb.append('"').append(c).append('"');
|
||||
case '"' -> sb.append("\"\\\"\"");
|
||||
case '\n' -> sb.append("\"\\n\"");
|
||||
case '\r' -> sb.append("\"\\r\"");
|
||||
case '\t' -> sb.append("\"\\t\"");
|
||||
case '\f' -> sb.append("\"\\f\"");
|
||||
default -> sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// https://github.com/JetBrains/intellij-community/blob/295dd68385a458bdfde638152e36d19bed18b666/platform/util/base/src/com/intellij/openapi/util/text/Strings.java#L100-L118
|
||||
public static boolean containsAnyChar(final @NotNull String value, final @NotNull String chars) {
|
||||
return chars.length() > value.length()
|
||||
? containsAnyChar(value, chars, 0, value.length())
|
||||
: containsAnyChar(chars, value, 0, chars.length());
|
||||
}
|
||||
|
||||
public static boolean containsAnyChar(final @NotNull String value, final @NotNull String chars, final int start, final int end) {
|
||||
for (int i = start; i < end; i++) {
|
||||
if (chars.indexOf(value.charAt(i)) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull JavaExec setClasspath(@NotNull FileCollection classpath) {
|
||||
this.classpath.setFrom(classpath);
|
||||
|
||||
@@ -26,6 +26,7 @@ package net.fabricmc.loom.util.download;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.ProxySelector;
|
||||
@@ -45,10 +46,10 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import com.github.mizosoft.methanol.ProgressTracker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -106,21 +107,10 @@ public class Download {
|
||||
}
|
||||
|
||||
private <T> HttpResponse<T> send(HttpRequest httpRequest, HttpResponse.BodyHandler<T> bodyHandler) throws DownloadException {
|
||||
final ProgressTracker tracker = ProgressTracker.create();
|
||||
final AtomicBoolean started = new AtomicBoolean(false);
|
||||
progressListener.onStart();
|
||||
|
||||
try {
|
||||
return getHttpClient().send(httpRequest, tracker.tracking(bodyHandler, progress -> {
|
||||
if (started.compareAndSet(false, true)) {
|
||||
progressListener.onStart();
|
||||
}
|
||||
|
||||
progressListener.onProgress(progress.totalBytesTransferred(), progress.contentLength());
|
||||
|
||||
if (progress.done()) {
|
||||
progressListener.onEnd(true);
|
||||
}
|
||||
}));
|
||||
return getHttpClient().send(httpRequest, bodyHandler);
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw error(e, "Failed to download (%s)", url);
|
||||
}
|
||||
@@ -139,6 +129,8 @@ public class Download {
|
||||
return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw error(e, "Failed to decode download output");
|
||||
} finally {
|
||||
progressListener.onEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +147,8 @@ public class Download {
|
||||
} catch (Throwable throwable) {
|
||||
tryCleanup(output);
|
||||
throw error(throwable, "Failed to download (%s) to (%s)", url, output);
|
||||
} finally {
|
||||
progressListener.onEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,8 +184,17 @@ public class Download {
|
||||
}
|
||||
|
||||
if (success) {
|
||||
try (InputStream inputStream = decodeOutput(response)) {
|
||||
Files.write(output, inputStream.readAllBytes());
|
||||
final long length = Long.parseLong(response.headers().firstValue("Content-Length").orElse("-1"));
|
||||
AtomicLong totalBytes = new AtomicLong(0);
|
||||
|
||||
try (OutputStream outputStream = Files.newOutputStream(output)) {
|
||||
copyWithCallback(decodeOutput(response), outputStream, value -> {
|
||||
if (length < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
progressListener.onProgress(totalBytes.addAndGet(value), length);
|
||||
});
|
||||
} catch (IOException e) {
|
||||
tryCleanup(output);
|
||||
throw error(e, "Failed to decode and write download output");
|
||||
@@ -230,6 +233,16 @@ public class Download {
|
||||
}
|
||||
}
|
||||
|
||||
private void copyWithCallback(InputStream is, OutputStream os, IntConsumer consumer) throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
|
||||
while ((length = is.read(buffer)) > 0) {
|
||||
os.write(buffer, 0, length);
|
||||
consumer.accept(length);
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream decodeOutput(HttpResponse<InputStream> response) throws IOException {
|
||||
final String encoding = response.headers().firstValue("Content-Encoding").orElse("");
|
||||
|
||||
|
||||
@@ -114,22 +114,21 @@ public class DownloadBuilder {
|
||||
}
|
||||
|
||||
public String downloadString(Path cache) throws DownloadException {
|
||||
withRetries(() -> {
|
||||
return withRetries(() -> {
|
||||
build().downloadPath(cache);
|
||||
return null;
|
||||
});
|
||||
|
||||
try {
|
||||
return Files.readString(cache, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
Files.delete(cache);
|
||||
} catch (IOException ex) {
|
||||
// Ignored
|
||||
}
|
||||
return Files.readString(cache, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
Files.deleteIfExists(cache);
|
||||
} catch (IOException ex) {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
throw new DownloadException("Failed to download and read string", e);
|
||||
}
|
||||
throw new DownloadException("Failed to download and read string", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private <T> T withRetries(DownloadSupplier<T> supplier) throws DownloadException {
|
||||
|
||||
@@ -29,7 +29,7 @@ public interface DownloadProgressListener {
|
||||
|
||||
void onProgress(long bytesTransferred, long contentLength);
|
||||
|
||||
void onEnd(boolean success);
|
||||
void onEnd();
|
||||
|
||||
DownloadProgressListener NONE = new DownloadProgressListener() {
|
||||
@Override
|
||||
@@ -41,7 +41,7 @@ public interface DownloadProgressListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd(boolean success) {
|
||||
public void onEnd() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class GradleDownloadProgressListener implements DownloadProgressListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd(boolean success) {
|
||||
public void onEnd() {
|
||||
Objects.requireNonNull(progressLogger);
|
||||
progressLogger.completed();
|
||||
progressLogger = null;
|
||||
|
||||
@@ -218,7 +218,7 @@ class DownloadFileTest extends DownloadTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
void onEnd(boolean success) {
|
||||
void onEnd() {
|
||||
ended = true
|
||||
}
|
||||
})
|
||||
@@ -250,7 +250,7 @@ class DownloadFileTest extends DownloadTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
void onEnd(boolean success) {
|
||||
void onEnd() {
|
||||
ended = true
|
||||
}
|
||||
})
|
||||
|
||||
@@ -95,4 +95,18 @@ class DownloadStringTest extends DownloadTest {
|
||||
then:
|
||||
result == "Hello World 3"
|
||||
}
|
||||
|
||||
def "String: File cache"() {
|
||||
setup:
|
||||
server.get("/downloadString2") {
|
||||
it.result("Hello World!")
|
||||
}
|
||||
|
||||
when:
|
||||
def output = new File(File.createTempDir(), "file.txt").toPath()
|
||||
def result = Download.create("$PATH/downloadString2").downloadString(output)
|
||||
|
||||
then:
|
||||
result == "Hello World!"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user