Skip to content

Commit 964dd9b

Browse files
committed
Cleanup all buildscripts
- Change logging strategy to delegate to a consumer - Add log capturing to suspend the printing of log messages - Gradle 8.14 - DownloadUtils multi-release jar, HttpClient for J11+ - Remove FileUtils dependencies on srgutils and commons-io - Optimizations and cleanup for Logging Utils
1 parent effee06 commit 964dd9b

File tree

22 files changed

+827
-642
lines changed

22 files changed

+827
-642
lines changed

build_shared.gradle

Lines changed: 0 additions & 24 deletions
This file was deleted.

download-utils/build.gradle

Lines changed: 77 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,60 +2,111 @@ plugins {
22
id 'java-library'
33
id 'idea'
44
id 'maven-publish'
5-
id 'net.minecraftforge.licenser' version '1.1.1'
6-
id 'net.minecraftforge.gradleutils' version '2.4.13'
5+
alias libs.plugins.licenser
6+
alias libs.plugins.gradleutils
77
}
88

9-
apply from: rootProject.file('build_shared.gradle')
9+
final projectDisplayName = 'Download Utils'
10+
final projectVendor = 'Forge Development LLC'
11+
description = 'Utilities for simple download tasks'
12+
group = 'net.minecraftforge'
13+
version = gitversion.tagOffset
1014

11-
dependencies {
12-
implementation project(':log-utils')
13-
14-
implementation libs.gson
15+
println "Version: $version"
1516

16-
// Static Analysis
17-
compileOnly libs.nulls
18-
}
17+
// IDE linting + no need to say 'sourceSets.java11' every time
18+
final java11 = sourceSets.create('java11')
1919

2020
java {
21-
toolchain.languageVersion = JavaLanguageVersion.of(8)
21+
toolchain.languageVersion = JavaLanguageVersion.of 8
2222
withSourcesJar()
23+
24+
registerFeature(java11.name) {
25+
usingSourceSet java11
26+
capability project.group.toString(), project.name, project.version.toString()
27+
disablePublication()
28+
}
29+
}
30+
31+
configurations {
32+
named(java11.implementationConfigurationName) { extendsFrom implementation }
33+
named(java11.compileOnlyConfigurationName) { extendsFrom compileOnly }
2334
}
2435

25-
jar {
36+
dependencies {
37+
implementation project(':log-utils')
38+
39+
compileOnly libs.nulls
40+
}
41+
42+
tasks.named('jar', Jar) {
2643
manifest {
27-
attributes('Automatic-Module-Name': 'net.minecraftforge.utils.download')
2844
attributes([
29-
'Specification-Title': 'Download Utils',
30-
'Specification-Vendor': 'Forge Development LLC',
31-
'Specification-Version': gitversion.version.info.tag,
32-
'Implementation-Title': 'Download Utils',
33-
'Implementation-Vendor': 'Forge Development LLC',
45+
'Automatic-Module-Name': 'net.minecraftforge.utils.download',
46+
'Multi-Release' : 'true'
47+
])
48+
attributes([
49+
'Specification-Title' : projectDisplayName,
50+
'Specification-Vendor' : projectVendor,
51+
'Specification-Version' : gitversion.info.tag,
52+
'Implementation-Title' : projectDisplayName,
53+
'Implementation-Vendor' : projectVendor,
3454
'Implementation-Version': project.version
35-
] as LinkedHashMap, 'net/minecraftforge/util/download/')
55+
], 'net/minecraftforge/util/download/')
3656
}
57+
58+
into('META-INF/versions/11') {
59+
from java11.output
60+
}
61+
}
62+
63+
tasks.named(java11.compileJavaTaskName, JavaCompile) {
64+
javaCompiler = javaToolchains.compilerFor {
65+
languageVersion = JavaLanguageVersion.of 11
66+
}
67+
}
68+
69+
tasks.withType(JavaCompile).configureEach {
70+
options.encoding = 'UTF-8'
71+
}
72+
73+
license {
74+
header = rootProject.file('LICENSE-header.txt')
75+
newLine = false
76+
exclude '**/*.properties'
77+
}
78+
79+
changelog {
80+
fromBase()
81+
publishAll = false
3782
}
3883

3984
publishing {
4085
publications.register('mavenJava', MavenPublication).configure {
41-
artifactId = project.name
4286
from components.java
4387

88+
artifactId = project.name
89+
4490
pom { pom ->
45-
name = 'Download Utils'
46-
description = 'Utilities for simple download tasks'
91+
name = projectDisplayName
92+
description = project.description
4793

48-
gradleutils.pom.gitHubDetails = pom
94+
gradleutils.pom.setGitHubDetails pom
4995

50-
license gradleutils.pom.licenses.LGPLv2_1
96+
licenses {
97+
license gradleutils.pom.licenses.LGPLv2_1
98+
}
5199

52100
developers {
53-
developer gradleutils.pom.Developers.LexManos
54-
developer gradleutils.pom.Developers.Jonathing
101+
developer gradleutils.pom.developers.LexManos
102+
developer gradleutils.pom.developers.Jonathing
55103
}
56104
}
57105
}
106+
58107
repositories {
59108
maven gradleutils.publishingForgeMaven
60109
}
61110
}
111+
112+
idea.module { downloadSources = downloadJavadoc = true }
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*
2+
* Copyright (c) Forge Development LLC
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.util.download;
6+
7+
import net.minecraftforge.util.logging.Log;
8+
import org.jetbrains.annotations.Nullable;
9+
10+
import java.io.File;
11+
import java.io.FileNotFoundException;
12+
import java.io.IOException;
13+
import java.io.InputStream;
14+
import java.net.HttpURLConnection;
15+
import java.net.URI;
16+
import java.net.URISyntaxException;
17+
import java.net.URLConnection;
18+
import java.net.http.HttpClient;
19+
import java.net.http.HttpRequest;
20+
import java.net.http.HttpResponse;
21+
import java.nio.charset.StandardCharsets;
22+
import java.nio.file.Files;
23+
import java.nio.file.Path;
24+
import java.nio.file.StandardCopyOption;
25+
import java.time.Duration;
26+
import java.util.ArrayList;
27+
import java.util.Locale;
28+
import java.util.function.Supplier;
29+
30+
public final class DownloadUtils {
31+
private static final Duration TIMEOUT = Duration.ofSeconds(5);
32+
private static final int MAX_REDIRECTS = 3;
33+
34+
private static final HttpClient CLIENT = HttpClient
35+
.newBuilder()
36+
.connectTimeout(TIMEOUT)
37+
.followRedirects(HttpClient.Redirect.NEVER)
38+
.build();
39+
40+
private static final HttpRequest.Builder REQUEST_BUILDER = HttpRequest
41+
.newBuilder()
42+
.timeout(TIMEOUT)
43+
.header("User-Agent", "MinecraftForge-Utils")
44+
.header("Accept", "application/json");
45+
46+
private static InputStream connect(String address) throws IOException, InterruptedException {
47+
URI uri;
48+
try {
49+
uri = new URI(address);
50+
} catch (URISyntaxException e) {
51+
throw new IOException(e);
52+
}
53+
54+
// if not http, then try a URLConnection. we might be trying to make a file or jar connection.
55+
// see jdk.internal.net.http.HttpRequestBuilderImpl#checkUri
56+
var scheme = uri.getScheme();
57+
if (scheme == null || !(scheme.equalsIgnoreCase("https") || scheme.equalsIgnoreCase("http"))) {
58+
return uri.toURL().openStream();
59+
}
60+
61+
var redirections = new ArrayList<String>();
62+
HttpResponse<InputStream> con;
63+
for (int redirects = 0; ; redirects++) {
64+
con = CLIENT.send(
65+
REQUEST_BUILDER.uri(uri).build(),
66+
info -> HttpResponse.BodySubscribers.ofInputStream()
67+
);
68+
69+
int res = con.statusCode();
70+
if (res == HttpURLConnection.HTTP_MOVED_PERM || res == HttpURLConnection.HTTP_MOVED_TEMP) {
71+
var header = con.headers().firstValue("Location");
72+
if (header.isEmpty())
73+
throw new IOException(String.format(
74+
"No location header found in redirect response: %s -- previous redirections: [%s]",
75+
uri, String.join(", ", redirections)
76+
));
77+
78+
var location = header.get();
79+
redirections.add(location);
80+
81+
if (redirects == MAX_REDIRECTS - 1) {
82+
throw new IOException(String.format(
83+
"Too many redirects: %s -- redirections: [%s]",
84+
address, String.join(", ", redirections)
85+
));
86+
} else {
87+
Log.debug("Following redirect: " + location);
88+
uri = uri.resolve(location);
89+
}
90+
} else if (res == HttpURLConnection.HTTP_NOT_FOUND) {
91+
throw new FileNotFoundException("Returned 404: " + address);
92+
} else {
93+
break;
94+
}
95+
}
96+
97+
return con.body();
98+
}
99+
100+
/**
101+
* Downloads a string from the given URL, effectively acting as {@code curl}.
102+
*
103+
* @param url The URL to download from
104+
* @return The downloaded string
105+
* @throws IOException If the download failed
106+
*/
107+
public static String downloadString(String url) throws IOException {
108+
try (InputStream stream = connect(url)) {
109+
return new String(stream.readAllBytes(), StandardCharsets.UTF_8);
110+
} catch (IOException e) {
111+
throw e;
112+
} catch (Exception e) {
113+
throw new IOException(e);
114+
}
115+
}
116+
117+
/**
118+
* Downloads a string from the given URL, effectively acting as {@code curl}.
119+
* <p>Returns {@code null} on failure.</p>
120+
*
121+
* @param url The URL to download from
122+
* @return The downloaded string, or {@code null} if the download failed
123+
*/
124+
public static @Nullable String tryDownloadString(boolean silent, String url) {
125+
try {
126+
return downloadString(url);
127+
} catch (IOException e) {
128+
if (!silent) {
129+
Log.warn("Failed to download " + url);
130+
e.printStackTrace(Log.WARN);
131+
}
132+
133+
return null;
134+
}
135+
}
136+
137+
/**
138+
* Downloads a file from the given URL into the target file, effectively acting as {@code wget}.
139+
*
140+
* @param target The file to download to
141+
* @param url The URL to download from
142+
* @throws IOException If the download failed
143+
*/
144+
public static void downloadFile(File target, String url) throws IOException {
145+
downloadFile(false, target, url);
146+
}
147+
148+
/**
149+
* Downloads a file from the given URL into the target file, effectively acting as {@code wget}.
150+
*
151+
* @param silent If no log messages should be sent
152+
* @param target The file to download to
153+
* @param url The URL to download from
154+
* @throws IOException If the download failed
155+
*/
156+
public static void downloadFile(boolean silent, File target, String url) throws IOException {
157+
if (!silent) Log.quiet("Downloading " + url);
158+
159+
try (InputStream stream = connect(url)) {
160+
Path path = target.toPath();
161+
Files.createDirectories(path.getParent());
162+
Files.copy(stream, path, StandardCopyOption.REPLACE_EXISTING);
163+
} catch (IOException e) {
164+
throw e;
165+
} catch (Exception e) {
166+
throw new IOException(e);
167+
}
168+
}
169+
170+
/**
171+
* Attempts to download a file from the given URL into the target file, effectively acting as {@code wget}.
172+
*
173+
* @param target The file to download to
174+
* @param url The URL to download from
175+
* @return {@code true} if the download was successful
176+
*/
177+
public static boolean tryDownloadFile(boolean silent, File target, String url) {
178+
try {
179+
downloadFile(silent, target, url);
180+
return true;
181+
} catch (IOException e) {
182+
if (!silent) {
183+
Log.warn("Failed to download " + url);
184+
e.printStackTrace(Log.WARN);
185+
}
186+
187+
return false;
188+
}
189+
}
190+
}

0 commit comments

Comments
 (0)