Skip to content

Commit

Permalink
Move default cache to ./cache so we don't pollute the repo output wit…
Browse files Browse the repository at this point in the history
…h cache

Download and cache version json files
Rework version detection/document general reasoning.
Set timestamp of version commits to releaseTime of that version.
  • Loading branch information
LexManos committed Jan 20, 2023
1 parent ec37e47 commit 312b6ed
Show file tree
Hide file tree
Showing 7 changed files with 430 additions and 265 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ out
*.idea
*.iml

output
output
/cache/
368 changes: 135 additions & 233 deletions src/main/java/net/minecraftforge/snowblower/Generator.java

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions src/main/java/net/minecraftforge/snowblower/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

public class Main {
Expand All @@ -27,7 +28,7 @@ public class Main {
public static void main(String[] args) throws IOException, GitAPIException, URISyntaxException {
OptionParser parser = new OptionParser();
OptionSpec<File> outputO = parser.accepts("output", "Output directory to put the git directory in").withRequiredArg().ofType(File.class).required();
OptionSpec<File> cacheO = parser.accepts("cache", "Cache directory to hold all files related to a version. If omitted, goes to {output}/build/cache.")
OptionSpec<File> cacheO = parser.accepts("cache", "Cache directory to hold all files related to a version. If omitted, goes to ./cache.")
.withRequiredArg().ofType(File.class);
OptionSpec<File> extraMappingsO = parser.accepts("extra-mappings", "When set, points to a directory with extra mappings files").withRequiredArg().ofType(File.class);
OptionSpec<String> startVerO = parser.accepts("start-ver", "The starting Minecraft version to generate from (inclusive)").withRequiredArg().ofType(String.class).defaultsTo(V1_14_4.toString());
Expand All @@ -51,7 +52,7 @@ public static void main(String[] args) throws IOException, GitAPIException, URIS

File output = options.valueOf(outputO);
File cache = options.valueOf(cacheO);
Path cachePath = cache == null ? output.toPath().resolve("build").resolve("cache") : cache.toPath();
Path cachePath = cache == null ? Paths.get("cache"): cache.toPath();
File extraMappings = options.valueOf(extraMappingsO);
Path extraMappingsPath = extraMappings == null ? null : extraMappings.toPath();
boolean startOver = options.has(startOverO);
Expand Down
15 changes: 11 additions & 4 deletions src/main/java/net/minecraftforge/snowblower/data/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,27 @@

package net.minecraftforge.snowblower.data;

import javax.net.ssl.HttpsURLConnection;
import net.minecraftforge.snowblower.util.Util;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;

public record Version(Map<String, Download> downloads, List<Library> libraries, JavaVersion javaVersion) {
public static Version query(URL url) throws IOException {
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.connect();
return VersionManifestV2.GSON.fromJson(new InputStreamReader(urlConnection.getInputStream()), Version.class);
return Util.downloadJson(url, Version.class);
}

public static Version load(Path file) throws IOException {
try (var in = new InputStreamReader(Files.newInputStream(file))) {
return Util.GSON.fromJson(in, Version.class);
}
}

public record Download(String path, String sha1, int size, URL url) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,33 @@

package net.minecraftforge.snowblower.data;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;
import net.minecraftforge.snowblower.util.Util;
import net.minecraftforge.srgutils.MinecraftVersion;

import javax.net.ssl.HttpsURLConnection;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;

public record VersionManifestV2(VersionInfo[] versions) {
private static final URL VERSION_MANIFEST_V2_URL;
static final Gson GSON = new GsonBuilder()
.registerTypeAdapter(MinecraftVersion.class, (JsonDeserializer<MinecraftVersion>) (json, typeOfT, context) -> MinecraftVersion.from(json.getAsString()))
.create();

static {
try {
VERSION_MANIFEST_V2_URL = new URL("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json");
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public record VersionManifestV2(
LatestInfo latest,
VersionInfo[] versions) {

public static VersionManifestV2 query() throws IOException {
HttpsURLConnection urlConnection = (HttpsURLConnection) VERSION_MANIFEST_V2_URL.openConnection();
urlConnection.connect();
return GSON.fromJson(new InputStreamReader(urlConnection.getInputStream()), VersionManifestV2.class);
return Util.downloadJson(Util.makeURL("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json"), VersionManifestV2.class);
}

public record VersionInfo(MinecraftVersion id, String type, URL url) {}
}
public record LatestInfo(
MinecraftVersion release,
MinecraftVersion snapshot
) {}

public record VersionInfo(
MinecraftVersion id,
String type,
URL url,
Date time,
Date releaseTime,
String sha1,
int complianceLevel
) {}
}
181 changes: 181 additions & 0 deletions src/main/java/net/minecraftforge/snowblower/tasks/init/InitTask.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* Copyright (c) Forge Development LLC
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.minecraftforge.snowblower.tasks.init;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Date;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;

import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;

import net.minecraftforge.snowblower.Generator;
import net.minecraftforge.snowblower.Main;
import net.minecraftforge.snowblower.util.Cache;
import net.minecraftforge.snowblower.util.Util;
import net.minecraftforge.srgutils.MinecraftVersion;

public class InitTask {
private final Consumer<String> logger;
private final Path root;
private final Git git;

public InitTask(Consumer<String> logger, Path root, Git git) {
this.logger = logger;
this.root = root;
this.git = git;
}

public void cleanup() throws IOException {
for (var file : new String[]{"Snowblower.txt", ".gitattributes", ".gitignore", "gradlew", "gradlew.bat", "gradle"}) {
var target = this.root.resolve(file);
if (Files.isDirectory(target))
Util.deleteRecursive(target);
else if (Files.exists(target))
Files.delete(target);
}
}

public boolean validate(boolean fresh, MinecraftVersion start) throws IOException, GitAPIException {
var meta = new Cache().comment(
"Source files created by Snowblower",
"https://github.com/MinecraftForge/Snowblower")
.put("Snowblower", getGitCommitHash()) // Now that I moved this to its own package, we could use the package hash. But I like the git commit.
.put("Start", start.toString());

var metaPath = root.resolve("Snowblower.txt");
if (!fresh && !meta.isValid(metaPath)) {
logger.accept("The starting commit on this branch does not have matching metadata.");
logger.accept("This could be due to a different Snowblower version or a different starting Minecraft version.");
logger.accept("Please choose a different branch with --branch or add the --start-over flag and try again.");
return false;
}

if (fresh || !Files.exists(metaPath)) {
// Create metadata file
meta.write(metaPath);
Util.add(git, metaPath);

// Create some git metadata files to make life sane
var attrs = root.resolve(".gitattributes");
Util.writeLines(attrs,
"* text eol=lf",
"*.java text eol=lf",
"*.json text eol=lf",
"*.xml text eol=lf",
"*.bin binary",
"*.png binary",
"*.gif binary",
"*.nbt binary"
);
Util.add(git, attrs);

var ignore = root.resolve(".gitignore");
Util.writeLines(ignore,
".gradle",
"build",
"",
"# Eclipse",
".settings",
".metadata",
".classpath",
".project",
"bin",
"",
"# IntelliJ",
"out",
"*.idea",
"*.iml"
);
Util.add(git, ignore);

try {
Path copyParentFolder = Util.isDev() ? Util.getSourcePath() : Util.getPath(Main.class.getResource("/resource_root.txt").toURI()).getParent();
List<String> toCopy = List.of("gradlew", "gradlew.bat", "gradle");
AddCommand addCmd = git.add();

for (String filename : toCopy) {
Path copyPath = copyParentFolder.resolve(filename);
if (Files.isRegularFile(copyPath)) {
Files.copy(copyPath, root.resolve(filename), StandardCopyOption.REPLACE_EXISTING);
} else {
Files.walkFileTree(copyPath, new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path destinationPath = root.resolve(copyParentFolder.relativize(file).toString());
Files.createDirectories(destinationPath.getParent());
Files.copy(file, destinationPath, StandardCopyOption.REPLACE_EXISTING);
return FileVisitResult.CONTINUE;
}
});
}
addCmd.addFilepattern(filename);
}

addCmd.call();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}

Util.commit(git, "Initial commit", new Date(1));

DirCache dirCache = git.getRepository().lockDirCache();
dirCache.getEntry("gradlew").setFileMode(FileMode.EXECUTABLE_FILE);
dirCache.write();
dirCache.commit();

PosixFileAttributeView posixFileAttributeView = Files.getFileAttributeView(root.resolve("gradlew"), PosixFileAttributeView.class);
if (posixFileAttributeView != null) {
Set<PosixFilePermission> perms = posixFileAttributeView.readAttributes().permissions();
perms.addAll(EnumSet.of(PosixFilePermission.OWNER_EXECUTE, PosixFilePermission.GROUP_EXECUTE, PosixFilePermission.OTHERS_EXECUTE));
posixFileAttributeView.setPermissions(perms);
}
}

return true;
}

private static String getGitCommitHash() {
String implVersion = Generator.class.getPackage().getImplementationVersion();
if (implVersion != null)
return implVersion.substring(implVersion.indexOf('(') + 1, implVersion.indexOf(')'));

try {
// This should never be a jar if the implementation version is missing, so we don't need Util#getPath
Path folderPath = Path.of(Util.getCodeSourceUri());

while (!Files.exists(folderPath.resolve(".git"))) {
folderPath = folderPath.getParent();
if (folderPath == null)
return "unknown";
}

try (Git sourceGit = Git.open(folderPath.toFile())) {
ObjectId headId = sourceGit.getRepository().resolve(Constants.HEAD);
return headId == null ? "unknown" : headId.getName();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Loading

0 comments on commit 312b6ed

Please sign in to comment.