Skip to content

Commit 2ac043d

Browse files
committed
gradle-plugin: Preliminary support for 21w39a+ bundler artifacts
1 parent 28dd534 commit 2ac043d

File tree

13 files changed

+700
-139
lines changed

13 files changed

+700
-139
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* This file is part of VanillaGradle, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) SpongePowered <https://www.spongepowered.org>
5+
* Copyright (c) contributors
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*/
25+
package org.spongepowered.gradle.vanilla.internal.bundler;
26+
27+
import org.immutables.value.Value;
28+
import org.spongepowered.gradle.vanilla.internal.model.GroupArtifactVersion;
29+
30+
/**
31+
* A single entry in a bundle.
32+
*
33+
* <p>In bundle format version {@code 1.0}, these elements are declared as
34+
* rows of tab-separated values.</p>
35+
*/
36+
@Value.Immutable
37+
public interface BundleElement {
38+
39+
/**
40+
* Create a new bundle element.
41+
*
42+
* @param sha256 the sha-265 hash
43+
* @param id the ID of the bundle element
44+
* @param path the path in the jar
45+
* @return a new element
46+
*/
47+
static BundleElement of(final String sha256, final String id, final String path) {
48+
return new BundleElementImpl(sha256, id, path);
49+
}
50+
51+
/**
52+
* The expected hash of the file in the jar.
53+
*
54+
* @return SHA-265 hash string
55+
*/
56+
@Value.Parameter
57+
String sha256();
58+
59+
/**
60+
* The maven coordinates corresponding to this artifact.
61+
*
62+
* @return the maven coordinates
63+
*/
64+
@Value.Parameter
65+
String id();
66+
67+
/**
68+
* The path of the index entry in the jar.
69+
*
70+
* @return the path relative to the jar
71+
*/
72+
@Value.Parameter
73+
String path();
74+
75+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*
2+
* This file is part of VanillaGradle, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) SpongePowered <https://www.spongepowered.org>
5+
* Copyright (c) contributors
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*/
25+
package org.spongepowered.gradle.vanilla.internal.bundler;
26+
27+
import org.cadixdev.atlas.jar.JarFile;
28+
import org.cadixdev.atlas.jar.JarPath;
29+
import org.cadixdev.bombe.jar.AbstractJarEntry;
30+
import org.cadixdev.bombe.jar.JarManifestEntry;
31+
import org.checkerframework.checker.nullness.qual.Nullable;
32+
import org.immutables.value.Value;
33+
34+
import java.io.BufferedReader;
35+
import java.io.ByteArrayInputStream;
36+
import java.io.IOException;
37+
import java.io.InputStream;
38+
import java.io.InputStreamReader;
39+
import java.nio.charset.StandardCharsets;
40+
import java.nio.file.Path;
41+
import java.util.Collections;
42+
import java.util.Optional;
43+
import java.util.Set;
44+
import java.util.jar.Manifest;
45+
import java.util.stream.Collectors;
46+
import java.util.stream.Stream;
47+
48+
@Value.Immutable
49+
public abstract class BundlerMetadata {
50+
51+
private static final JarPath MANIFEST = new JarPath("META-INF/MANIFEST.MF");
52+
53+
private static final JarPath LIBRARIES_LIST = new JarPath("META-INF/libraries.list");
54+
55+
private static final JarPath VERSIONS_LIST = new JarPath("META-INF/versions.list");
56+
57+
private static final JarPath MAIN_CLASS = new JarPath("META-INF/main-class");
58+
59+
/**
60+
* Attempt to read bundler metadata from a jar.
61+
*
62+
* <p>If the jar is not a Minecraft bundler jar, an empty {@link Optional} will be returned.</p>
63+
*
64+
* @param jar the jar to read
65+
* @return parsed metadata
66+
*/
67+
public static Optional<BundlerMetadata> read(final Path jar) throws IOException {
68+
try (final JarFile file = new JarFile(jar)) {
69+
final Manifest manifest = ((JarManifestEntry) file.get(BundlerMetadata.MANIFEST)).getManifest();
70+
final @Nullable String formatVersion = manifest.getMainAttributes().getValue(FormatVersion.MANIFEST_ATTRIBUTE);
71+
if (formatVersion == null) {
72+
return Optional.empty();
73+
}
74+
75+
final FormatVersion parsed = FormatVersion.parse(formatVersion);
76+
77+
// load information:
78+
// server jar
79+
final BundleElement serverJar;
80+
try (final Stream<BundleElement> stream = BundlerMetadata.readIndex(file, "versions")) {
81+
serverJar = stream.findFirst()
82+
.orElse(null);
83+
}
84+
85+
if (serverJar == null) {
86+
throw new IllegalArgumentException("Missing server jar from versions list");
87+
}
88+
89+
// libraries list
90+
final Set<BundleElement> libraries;
91+
try (final Stream<BundleElement> elements = BundlerMetadata.readIndex(file, "libraries")) {
92+
libraries = Collections.unmodifiableSet(elements.collect(Collectors.toSet()));
93+
}
94+
95+
// main class
96+
final AbstractJarEntry mainClassEntry = file.getClass(BundlerMetadata.MAIN_CLASS);
97+
if (mainClassEntry == null) {
98+
throw new IllegalArgumentException("Missing main class entry in bundle");
99+
}
100+
101+
final String mainClass = new String(mainClassEntry.getContents(), StandardCharsets.UTF_8).trim();
102+
103+
return Optional.of(BundlerMetadata.of(parsed, libraries, serverJar, mainClass));
104+
}
105+
}
106+
107+
public static BundlerMetadata of(final FormatVersion version, final Set<BundleElement> libraries, final BundleElement server, final @Nullable String mainClass) {
108+
return new BundlerMetadataImpl(version, libraries, server, mainClass);
109+
}
110+
111+
private static Stream<BundleElement> readIndex(final JarFile jar, final String index) throws IOException {
112+
final JarPath path = new JarPath("META-INF/" + index + ".list");
113+
final @Nullable AbstractJarEntry entry = jar.get(path);
114+
if (entry == null) {
115+
return Stream.empty();
116+
}
117+
118+
final InputStream is = new ByteArrayInputStream(entry.getContents());
119+
final BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
120+
return reader.lines()
121+
.map(x -> x.split("\t"))
122+
.map(line -> BundleElement.of(line[0], line[1], "META-INF/" + index + "/" + line[2]))
123+
.onClose(() -> {
124+
try {
125+
reader.close();
126+
} catch (final IOException ex) {
127+
throw new RuntimeException(ex);
128+
}
129+
});
130+
}
131+
132+
/**
133+
* The bundler format used by this jar.
134+
*
135+
* <p>While VanillaGradle only knows about versions that existed at the time
136+
* of its release, we will attempt to read future versions as well.</p>
137+
*
138+
* @return the format version
139+
*/
140+
@Value.Parameter
141+
public abstract FormatVersion version();
142+
143+
/**
144+
* Libraries packed in the jar as dependencies for the server.
145+
*
146+
* @return the library elements
147+
*/
148+
@Value.Parameter
149+
public abstract Set<BundleElement> libraries();
150+
151+
/**
152+
* Get a bundle element describing the server itself.
153+
*
154+
* @return an index entry describing the server
155+
*/
156+
@Value.Parameter
157+
public abstract BundleElement server();
158+
159+
/**
160+
* The main class to execute.
161+
*
162+
* @return the main class
163+
*/
164+
@Value.Parameter
165+
public abstract @Nullable String mainClass();
166+
167+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* This file is part of VanillaGradle, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) SpongePowered <https://www.spongepowered.org>
5+
* Copyright (c) contributors
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*/
25+
package org.spongepowered.gradle.vanilla.internal.bundler;
26+
27+
import org.immutables.value.Value;
28+
29+
/**
30+
* A version of the Minecraft bundler metadata format.
31+
*/
32+
@Value.Immutable(builder = false)
33+
public interface FormatVersion extends Comparable<FormatVersion> {
34+
35+
/**
36+
* An attribute in the manifest of bundler jars containing a format version.
37+
*
38+
* @see #parse(String)
39+
*/
40+
String MANIFEST_ATTRIBUTE = "Bundler-Format";
41+
42+
/**
43+
* Parse the manifest attribute version.
44+
*
45+
* @param attribute the attribute value
46+
* @return a parsed version
47+
* @throws NumberFormatException if any elements of the attribute are non-numeric
48+
* @throws IllegalArgumentException if the version does not have at least two elements
49+
*/
50+
static FormatVersion parse(final String attribute) {
51+
final String[] split = attribute.split("\\.");
52+
if (split.length < 2) {
53+
throw new IllegalArgumentException("Invalid version " + attribute);
54+
}
55+
return FormatVersion.of(
56+
Integer.parseInt(split[0]),
57+
Integer.parseInt(split[1])
58+
);
59+
}
60+
61+
/**
62+
* Create a format version directly.
63+
*
64+
* @param major the major version
65+
* @param minor the minor version
66+
* @return a new format version object
67+
*/
68+
static FormatVersion of(final int major, final int minor) {
69+
return new FormatVersionImpl(major, minor);
70+
}
71+
72+
/**
73+
* Major version. Indicates incompatible changes.
74+
*
75+
* @return the major version
76+
*/
77+
@Value.Parameter
78+
int major();
79+
80+
/**
81+
* Minor version. Indicates additions and other compatible changes.
82+
*
83+
* @return the minor version
84+
*/
85+
@Value.Parameter
86+
int minor();
87+
88+
/**
89+
* Whether a version of {@code other} can interpret data in this format version.
90+
*
91+
* @param other the compared version
92+
* @return whether other is compatible with this version's data
93+
*/
94+
default boolean compatibleWith(final FormatVersion other) {
95+
return other.major() == this.major()
96+
&& other.minor() >= this.minor();
97+
}
98+
99+
@Override
100+
default int compareTo(final FormatVersion other) {
101+
if (this.major() != other.major()) {
102+
return Integer.compare(this.major(), other.major());
103+
} else {
104+
return Integer.compare(this.minor(), other.minor());
105+
}
106+
}
107+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* This file is part of VanillaGradle, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) SpongePowered <https://www.spongepowered.org>
5+
* Copyright (c) contributors
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*/
25+
@ImmutablesStyle
26+
package org.spongepowered.gradle.vanilla.internal.bundler;
27+
28+
import org.spongepowered.gradle.vanilla.internal.util.ImmutablesStyle;

subprojects/gradle-plugin/src/main/java/org/spongepowered/gradle/vanilla/internal/model/GroupArtifactVersion.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ public static GroupArtifactVersion of(final String group, final String artifact,
3434
return new GroupArtifactVersionImpl(group, artifact, version);
3535
}
3636

37+
public static GroupArtifactVersion parse(final String notation) {
38+
final String[] split = notation.split(":");
39+
if (split.length > 4 || split.length < 2) {
40+
throw new IllegalArgumentException("Unsupported notation '" + notation + "', must be in the format of group:artifact[:version[:classifier]]");
41+
}
42+
return GroupArtifactVersion.of(split[0], split[1], split.length > 2 ? split[2] : null);
43+
}
44+
3745
GroupArtifactVersion() {
3846
}
3947

0 commit comments

Comments
 (0)