From 0359995a08d60dc83845299a93b30a10e4d4e130 Mon Sep 17 00:00:00 2001 From: Marc Hermans Date: Mon, 17 Jun 2024 15:36:50 +0200 Subject: [PATCH 1/5] Fix ATs not applying. Fix Locale handling in string processing in as many places as I reasonably can. Fix Parallel running Fix Parallel central cache locking Fix recompile not being cached Fix DownloadAssets causing issues in multi project runs Fix DevLogin conventionForRun triggering issues on none Client runs by convention Closes #209 Closes #207 Closes #201 Closes #197 --- build.gradle | 8 +- .../gradle/common/CommonProjectPlugin.java | 5 +- .../common/caching/CentralCacheService.java | 170 +++++++++++++++--- .../dependency/ExtraJarDependencyManager.java | 7 +- .../definition/CommonRuntimeDefinition.java | 2 +- .../extensions/CommonRuntimeExtension.java | 2 - .../renamer/RegexBasedSourceRenamer.java | 2 +- .../CommonRuntimeSpecification.java | 3 +- .../common/runtime/tasks/DefaultRuntime.java | 9 - .../common/runtime/tasks/DownloadAssets.java | 37 ++-- .../tasks/action/DownloadFileAction.java | 33 ++-- .../gradle/common/util/FileCacheUtils.java | 5 +- .../common/util/TaskDependencyUtils.java | 24 ++- .../gradle/common/util/VersionJson.java | 2 +- .../gradle/common/util/hash/Hashing.java | 22 ++- .../dsl/common/util/DistributionType.groovy | 2 +- .../extensions/NeoFormRuntimeExtension.java | 17 +- .../runtime/tasks/RecompileSourceJar.java | 19 ++ .../extensions/DynamicProjectExtension.java | 2 +- .../RuntimeBuilderExtensions.groovy | 10 ++ .../userdev/AccessTransformerTests.groovy | 42 +++++ .../gradle/userdev/CentralCacheTests.groovy | 73 +++++++- .../gradle/userdev/MultiProjectTests.groovy | 106 ++++++++++- .../neoforged/gradle/userdev/RunTests.groovy | 7 +- .../SourceSetConventionTests.groovy | 10 +- .../util/StringCapitalizationUtils.java | 5 +- .../runtime/VanillaRuntimeDefinition.java | 2 +- .../vanilla/runtime/steps/ParchmentStep.java | 21 ++- 28 files changed, 526 insertions(+), 121 deletions(-) diff --git a/build.gradle b/build.gradle index 650c2710f..041228c3a 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ subprojects.forEach { Project subProject -> //General project metadata. Everything has the same version and group. subProject.version = subProject.rootProject.version subProject.group = 'net.neoforged.gradle' - subProject.base.archivesName = "ng-${subProject.name.toLowerCase()}" + subProject.base.archivesName = "ng-${subProject.name.toLowerCase(Locale.ROOT)}" //Setup the java toolchain subProject.java.toolchain.languageVersion = JavaLanguageVersion.of(project.java_version) @@ -167,11 +167,11 @@ subprojects.forEach { subProject -> //Configure the plugin metadata, so we can publish it. evalSubProject.gradlePlugin.plugins { NamedDomainObjectContainer plugins -> - plugins.register(evalSubProject.name.toLowerCase()) { + plugins.register(evalSubProject.name.toLowerCase(Locale.ROOT)) { //Determine the class name and package of the plugin. def pluginFile = evalSubProject.fileTree('src/main/java') - .filter { it.name.toLowerCase() == "${evalSubProject.getName()}plugin.java".toLowerCase() } + .filter { it.name.toLowerCase(Locale.ROOT) == "${evalSubProject.getName()}plugin.java".toLowerCase(Locale.ROOT) } .first() //We need to handle the case of a fresh new project, no files exist yet, so the pluginFile object will be null. @@ -180,7 +180,7 @@ subprojects.forEach { subProject -> pluginClassName = evalSubProject.file('src/main/java/').toPath().relativize(pluginFile.toPath()).toString().replace('/', '.').replace('\\', '.').replace(".java", "") } - def pluginId = 'net.neoforged.gradle.' + evalSubProject.name.toLowerCase() + def pluginId = 'net.neoforged.gradle.' + evalSubProject.name.toLowerCase(Locale.ROOT) try { var propertyValue = evalSubProject.property('pluginId') if (propertyValue != null) { diff --git a/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java b/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java index cd8d19bd8..92993f620 100644 --- a/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java +++ b/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java @@ -57,6 +57,7 @@ import org.jetbrains.gradle.ext.IdeaExtPlugin; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; public class CommonProjectPlugin implements Plugin { @@ -159,7 +160,7 @@ public void apply(Project project) { if (devLogin.getEnabled().get()) { runs.configureEach(run -> { final RunDevLogin runsDevLogin = run.getExtensions().create("devLogin", RunDevLogin.class); - runsDevLogin.getIsEnabled().convention(devLogin.getConventionForRun()); + runsDevLogin.getIsEnabled().convention(devLogin.getConventionForRun().zip(run.getIsClient(), (conventionForRun, isClient) -> conventionForRun && isClient)); }); } @@ -389,6 +390,8 @@ private void applyAfterEvaluate(final Project project) { } }); + + definitionSet.forEach((identifier, definition) -> { definition.configureRun(runImpl); }); diff --git a/common/src/main/java/net/neoforged/gradle/common/caching/CentralCacheService.java b/common/src/main/java/net/neoforged/gradle/common/caching/CentralCacheService.java index 72afc6468..4cf0350de 100644 --- a/common/src/main/java/net/neoforged/gradle/common/caching/CentralCacheService.java +++ b/common/src/main/java/net/neoforged/gradle/common/caching/CentralCacheService.java @@ -6,6 +6,7 @@ import net.neoforged.gradle.common.util.hash.Hasher; import net.neoforged.gradle.common.util.hash.Hashing; import net.neoforged.gradle.util.FileUtils; +import org.apache.commons.io.filefilter.AbstractFileFilter; import org.apache.commons.lang3.SystemUtils; import org.gradle.api.GradleException; import org.gradle.api.Project; @@ -13,6 +14,7 @@ import org.gradle.api.file.Directory; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.RegularFile; +import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.services.BuildService; @@ -25,13 +27,12 @@ import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; import java.text.DateFormat; -import java.util.Comparator; -import java.util.Date; -import java.util.Set; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -120,6 +121,27 @@ public void doCached(Task task, DoCreate onCreate, Provider target) debugLog(task, "Cached task: " + task.getPath() + " finished"); } + public void doCachedDirectory(Task task, DoCreate onCreate, DirectoryProperty output) throws Throwable { + if (!getParameters().getIsEnabled().get()) { + debugLog(task, "Cache is disabled, skipping cache"); + onCreate.create(); + return; + } + + final TaskHasher hasher = new TaskHasher(task); + final String hashDirectoryName = hasher.create().toString(); + final Directory cacheDirectory = getParameters().getCacheDirectory().get().dir(hashDirectoryName); + final Directory targetDirectory = output.get(); + + debugLog(task, "Cache directory: " + cacheDirectory.getAsFile().getAbsolutePath()); + debugLog(task, "Target directory: " + targetDirectory.getAsFile().getAbsolutePath()); + + final File lockFile = new File(cacheDirectory.getAsFile(), "lock"); + debugLog(task, "Lock file: " + lockFile.getAbsolutePath()); + executeCacheLookupOrCreation(task, onCreate, lockFile, cacheDirectory, targetDirectory); + debugLog(task, "Cached task: " + task.getPath() + " finished"); + } + @SuppressWarnings("ResultOfMethodCallIgnored") private void executeCacheLookupOrCreation(Task task, DoCreate onCreate, File lockFile, Directory cacheDirectory, RegularFile targetFile) throws Throwable { if (!lockFile.exists()) { @@ -139,7 +161,7 @@ private void executeCacheLookupOrCreation(Task task, DoCreate onCreate, File loc fileBasedLock.updateAccessTime(); debugLog(task, "Lock acquired on file: " + lockFile.getAbsolutePath()); - executeCacheLookupOrCreationLocked(task, onCreate, cacheDirectory, targetFile.getAsFile(), fileBasedLock.hasPreviousFailure()); + executeCacheLookupOrCreationLocked(task, onCreate, cacheDirectory, targetFile.getAsFile(), fileBasedLock.hasPreviousFailure(), false); // Release the lock when done debugLog(task, "Releasing lock on file: " + lockFile.getAbsolutePath()); @@ -151,15 +173,47 @@ private void executeCacheLookupOrCreation(Task task, DoCreate onCreate, File loc } } - private void executeCacheLookupOrCreationLocked(Task task, DoCreate onCreate, Directory cacheDirectory, File targetFile, boolean failedPreviously) throws Throwable { + + @SuppressWarnings("ResultOfMethodCallIgnored") + private void executeCacheLookupOrCreation(Task task, DoCreate onCreate, File lockFile, Directory cacheDirectory, Directory targetDirectory) throws Throwable { + if (!lockFile.exists()) { + debugLog(task, "Lock file does not exist: " + lockFile.getAbsolutePath()); + try { + lockFile.getParentFile().mkdirs(); + lockFile.createNewFile(); + } catch (IOException e) { + throw new GradleException("Failed to create lock file: " + lockFile.getAbsolutePath(), e); + } + } + + // Acquiring an exclusive lock on the file + debugLog(task, "Acquiring lock on file: " + lockFile.getAbsolutePath()); + try(FileBasedLock fileBasedLock = lockManager.createLock(task, lockFile)) { + try { + fileBasedLock.updateAccessTime(); + debugLog(task, "Lock acquired on file: " + lockFile.getAbsolutePath()); + + executeCacheLookupOrCreationLocked(task, onCreate, cacheDirectory, targetDirectory.getAsFile(), fileBasedLock.hasPreviousFailure(), true); + + // Release the lock when done + debugLog(task, "Releasing lock on file: " + lockFile.getAbsolutePath()); + } catch (Exception ex) { + debugLog(task, "Exception occurred while executing cached task: " + targetDirectory.getAsFile().getAbsolutePath(), ex); + fileBasedLock.markAsFailed(); + throw new GradleException("Cached execution failed for: " + task.getName(), ex); + } + } + } + + private void executeCacheLookupOrCreationLocked(Task task, DoCreate onCreate, Directory cacheDirectory, File targetFile, boolean failedPreviously, boolean isDirectory) throws Throwable { final File cacheFile = new File(cacheDirectory.getAsFile(), targetFile.getName()); final File noCacheFile = new File(cacheDirectory.getAsFile(), "nocache"); if (failedPreviously) { //Previous execution failed debugLog(task, "Last cache run failed: " + cacheFile.getAbsolutePath()); - Files.deleteIfExists(cacheFile.toPath()); - Files.deleteIfExists(noCacheFile.toPath()); + FileUtils.delete(cacheFile.toPath()); + FileUtils.delete(noCacheFile.toPath()); } if (noCacheFile.exists()) { @@ -167,9 +221,16 @@ private void executeCacheLookupOrCreationLocked(Task task, DoCreate onCreate, Di debugLog(task, "Last cache run indicated no output: " + noCacheFile.getAbsolutePath()); logCacheHit(task, noCacheFile); task.setDidWork(false); - Files.deleteIfExists(targetFile.toPath()); + FileUtils.delete(targetFile.toPath()); + if (isDirectory) { + //Create the directory, we always ensure the empty directory will get created! + if (!targetFile.mkdirs()) { + throw new RuntimeException("Failed to create directory: " + targetFile.getAbsolutePath()); + } + } return; } + if (cacheFile.exists()) { debugLog(task, "Cached file exists: " + cacheFile.getAbsolutePath()); if (targetFile.exists() && Hashing.hashFile(cacheFile).equals(Hashing.hashFile(targetFile))) { @@ -181,8 +242,22 @@ private void executeCacheLookupOrCreationLocked(Task task, DoCreate onCreate, Di debugLog(task, "Cached file does not equal target file"); logCacheHit(task, cacheFile); - Files.deleteIfExists(targetFile.toPath()); - Files.copy(cacheFile.toPath(), targetFile.toPath()); + FileUtils.delete(targetFile.toPath()); + if (!isDirectory) { + Files.copy(cacheFile.toPath(), targetFile.toPath()); + } else { + //Copy the directory + Files.walkFileTree(cacheFile.toPath(), new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + final Path relativePath = cacheFile.toPath().relativize(file); + final Path targetPath = targetFile.toPath().resolve(relativePath); + Files.createDirectories(targetPath.getParent()); + Files.copy(file, targetPath); + return FileVisitResult.CONTINUE; + } + }); + } task.setDidWork(false); } else { debugLog(task, "Cached file does not exist: " + cacheFile.getAbsolutePath()); @@ -190,9 +265,12 @@ private void executeCacheLookupOrCreationLocked(Task task, DoCreate onCreate, Di debugLog(task, "Creating output: " + targetFile.getAbsolutePath()); File createdFile = onCreate.create(); + if (isDirectory && !createdFile.isDirectory()) + throw new IllegalStateException("Expected a directory, but got a file: " + createdFile.getAbsolutePath()); + debugLog(task, "Created output: " + createdFile.getAbsolutePath()); - if (!createdFile.exists()) { + if (!createdFile.exists() || (isDirectory && Objects.requireNonNull(createdFile.listFiles()).length == 0)) { //No output was created debugLog(task, "No output was created: " + createdFile.getAbsolutePath()); Files.createFile(noCacheFile.toPath()); @@ -201,7 +279,21 @@ private void executeCacheLookupOrCreationLocked(Task task, DoCreate onCreate, Di //Output was created debugLog(task, "Output was created: " + createdFile.getAbsolutePath()); Files.deleteIfExists(noCacheFile.toPath()); - Files.copy(createdFile.toPath(), cacheFile.toPath()); + if (!isDirectory) { + Files.copy(createdFile.toPath(), cacheFile.toPath()); + } else { + //Copy the directory + Files.walkFileTree(createdFile.toPath(), new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + final Path relativePath = createdFile.toPath().relativize(file); + final Path targetPath = cacheFile.toPath().resolve(relativePath); + Files.createDirectories(targetPath.getParent()); + Files.copy(file, targetPath); + return FileVisitResult.CONTINUE; + } + }); + } } task.setDidWork(true); } @@ -227,13 +319,13 @@ private void logCacheMiss(Task task) { private void debugLog(Task task, String message) { if (getParameters().getDebugCache().get()) { - task.getLogger().lifecycle( " > [" + new Date(System.currentTimeMillis()) + "] (" + ProcessHandle.current().pid() + "): " + message); + task.getLogger().lifecycle( " > [" + System.currentTimeMillis() + "] (" + ProcessHandle.current().pid() + "): " + message); } } private void debugLog(Task task, String message, Exception e) { if (getParameters().getDebugCache().get()) { - task.getLogger().lifecycle( " > [" + new Date(System.currentTimeMillis()) + "] (" + ProcessHandle.current().pid() + "): " + message, e); + task.getLogger().lifecycle( " > [" + System.currentTimeMillis() + "] (" + ProcessHandle.current().pid() + "): " + message, e); } } @@ -282,12 +374,14 @@ public void hash(TaskInputs inputs) throws IOException { }); for (File file : inputs.getFiles()) { - for (Path path : Files.walk(file.toPath()).filter(Files::isRegularFile).toList()) { - debugLog(task, "Hashing task input file: " + path.toAbsolutePath()); - hasher.putString(path.getFileName().toString()); - final HashCode code = hashFunction.hashFile(path.toFile()); - debugLog(task, "Hashing task input file hash: " + code); - hasher.putHash(code); + try(Stream pathStream = Files.walk(file.toPath())) { + for (Path path : pathStream.filter(Files::isRegularFile).toList()) { + debugLog(task, "Hashing task input file: " + path.toAbsolutePath()); + hasher.putString(path.getFileName().toString()); + final HashCode code = hashFunction.hashFile(path.toFile()); + debugLog(task, "Hashing task input file hash: " + code); + hasher.putHash(code); + } } } } @@ -396,6 +490,8 @@ public static boolean isSupported() { return SystemUtils.IS_OS_WINDOWS; } + private static final Map FILE_LOCKS = new ConcurrentHashMap<>(); + private final Task task; private final File lockFile; private final RandomAccessFile lockFileAccess; @@ -415,6 +511,10 @@ public NioBasedFileLock(Task task, File lockFile) { this.fileChannel = this.lockFileAccess.getChannel(); this.fileLock = this.fileChannel.lock(); + final OwnerAwareReentrantLock lock = FILE_LOCKS.computeIfAbsent(lockFile.getAbsolutePath(), s1 -> new OwnerAwareReentrantLock()); + debugLog(task, "Created local thread lock for thread: " + Thread.currentThread().getId() + " - " + Thread.currentThread().getName()); + lock.lock(); + debugLog(task, "Acquired lock on file: " + lockFile.getAbsolutePath()); } catch (IOException e) { throw new RuntimeException("Failed to acquire lock on file: " + lockFile.getAbsolutePath(), e); @@ -427,6 +527,9 @@ public void close() throws Exception { fileChannel.close(); lockFileAccess.close(); + final OwnerAwareReentrantLock lock = FILE_LOCKS.get(lockFile.getAbsolutePath()); + lock.unlock(); + debugLog(task, "Released lock on file: " + lockFile.getAbsolutePath()); } } @@ -464,6 +567,7 @@ public void close() throws Exception { private final class PIDBasedFileLock implements AutoCloseable { + private static final Map FILE_LOCKS = new ConcurrentHashMap<>(); private final Task task; private final File lockFile; @@ -474,6 +578,7 @@ private PIDBasedFileLock(Task task, File lockFile) { } private void lockFile() { + debugLog(task, "Attempting to acquire lock on file: " + lockFile.getAbsolutePath()); while (!attemptFileLock()) { //We attempt a lock every 500ms try { @@ -482,9 +587,10 @@ private void lockFile() { throw new RuntimeException("Failed to acquire lock on file: " + lockFile.getAbsolutePath(), e); } } + debugLog(task, "Lock acquired on file: " + lockFile.getAbsolutePath()); } - private boolean attemptFileLock() { + private synchronized boolean attemptFileLock() { try { if (!lockFile.exists()) { //No lock file exists, create one @@ -498,6 +604,9 @@ private boolean attemptFileLock() { int pid = Integer.parseInt(s); if (ProcessHandle.current().pid() == pid) { debugLog(task, "Lock file is owned by current process: " + lockFile.getAbsolutePath() + " pid: " + pid); + final OwnerAwareReentrantLock lock = FILE_LOCKS.computeIfAbsent(lockFile.getAbsolutePath(), s1 -> new OwnerAwareReentrantLock()); + debugLog(task, "Lock file is held by thread: " + lock.getOwner().getId() + " - " + lock.getOwner().getName() + " current thread: " + Thread.currentThread().getId() + " - " + Thread.currentThread().getName()); + lock.lock(); return true; } @@ -518,6 +627,9 @@ private boolean attemptFileLock() { //No pid found in lock file, we can take over the lock debugLog(task, "Lock file is empty: " + lockFile.getAbsolutePath()); Files.write(lockFile.toPath(), String.valueOf(ProcessHandle.current().pid()).getBytes(), StandardOpenOption.TRUNCATE_EXISTING); + final OwnerAwareReentrantLock lock = FILE_LOCKS.computeIfAbsent(lockFile.getAbsolutePath(), s1 -> new OwnerAwareReentrantLock()); + debugLog(task, "Created local thread lock for thread: " + Thread.currentThread().getId() + " - " + Thread.currentThread().getName()); + lock.lock(); return true; } catch (Exception e) { debugLog(task, "Failed to acquire lock on file: " + lockFile.getAbsolutePath() + " - Failure message: " + e.getLocalizedMessage(), e); @@ -529,6 +641,16 @@ private boolean attemptFileLock() { public void close() throws Exception { debugLog(task, "Releasing lock on file: " + lockFile.getAbsolutePath()); Files.write(lockFile.toPath(), Lists.newArrayList(), StandardOpenOption.TRUNCATE_EXISTING); + if (FILE_LOCKS.containsKey(lockFile.getAbsolutePath())) { + FILE_LOCKS.get(lockFile.getAbsolutePath()).unlock(); + } + } + } + + private static final class OwnerAwareReentrantLock extends ReentrantLock { + @Override + public Thread getOwner() { + return super.getOwner(); } } } diff --git a/common/src/main/java/net/neoforged/gradle/common/dependency/ExtraJarDependencyManager.java b/common/src/main/java/net/neoforged/gradle/common/dependency/ExtraJarDependencyManager.java index 30d92f846..d6bd37664 100644 --- a/common/src/main/java/net/neoforged/gradle/common/dependency/ExtraJarDependencyManager.java +++ b/common/src/main/java/net/neoforged/gradle/common/dependency/ExtraJarDependencyManager.java @@ -16,10 +16,7 @@ import org.gradle.api.tasks.TaskProvider; import javax.inject.Inject; -import java.util.Collections; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; +import java.util.*; public abstract class ExtraJarDependencyManager { @@ -34,7 +31,7 @@ public static String generateServerCoordinateFor(final String version) { } public static String generateCoordinateFor(final DistributionType type, final String version) { - return String.format("net.minecraft:%s:%s:%s-extra", type.getName().toLowerCase(), version, type.getName().toLowerCase()); + return String.format("net.minecraft:%s:%s:%s-extra", type.getName().toLowerCase(Locale.ROOT), version, type.getName().toLowerCase(Locale.ROOT)); } @Inject diff --git a/common/src/main/java/net/neoforged/gradle/common/runtime/definition/CommonRuntimeDefinition.java b/common/src/main/java/net/neoforged/gradle/common/runtime/definition/CommonRuntimeDefinition.java index d1acbd65b..0e9960136 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runtime/definition/CommonRuntimeDefinition.java +++ b/common/src/main/java/net/neoforged/gradle/common/runtime/definition/CommonRuntimeDefinition.java @@ -177,7 +177,7 @@ protected Map buildRunInterpolationData(RunImpl run) { interpolationData.put("runtime_name", specification.getVersionedName()); interpolationData.put("mc_version", specification.getMinecraftVersion()); - interpolationData.put("assets_root", getAssets().get().getOutputDirectory().get().getAsFile().getAbsolutePath()); + interpolationData.put("assets_root", DownloadAssets.getAssetsDirectory(specification.getProject(), specification.getProject().provider(this::getVersionJson)).get().getAsFile().getAbsolutePath()); interpolationData.put("asset_index", getAssets().get().getAssetIndexFile().get().getAsFile().getName().substring(0, getAssets().get().getAssetIndexFile().get().getAsFile().getName().lastIndexOf('.'))); interpolationData.put("natives", getNatives().get().getOutputDirectory().get().getAsFile().getAbsolutePath()); diff --git a/common/src/main/java/net/neoforged/gradle/common/runtime/extensions/CommonRuntimeExtension.java b/common/src/main/java/net/neoforged/gradle/common/runtime/extensions/CommonRuntimeExtension.java index faee4f806..6ab9cba56 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runtime/extensions/CommonRuntimeExtension.java +++ b/common/src/main/java/net/neoforged/gradle/common/runtime/extensions/CommonRuntimeExtension.java @@ -188,8 +188,6 @@ public Set findIn(final Configuration configuration) { protected final TaskProvider createDownloadAssetsTasks(final CommonRuntimeSpecification specification, final Map symbolicDataSources, final File runtimeDirectory, final VersionJson versionJson) { return specification.getProject().getTasks().register(CommonRuntimeUtils.buildTaskName(specification, "downloadAssets"), DownloadAssets.class, task -> { task.getVersionJson().set(versionJson); - - configureCommonRuntimeTaskParameters(task, symbolicDataSources, "downloadAssets", specification, runtimeDirectory); }); } diff --git a/common/src/main/java/net/neoforged/gradle/common/runtime/naming/renamer/RegexBasedSourceRenamer.java b/common/src/main/java/net/neoforged/gradle/common/runtime/naming/renamer/RegexBasedSourceRenamer.java index eaf89a749..b4bebe869 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runtime/naming/renamer/RegexBasedSourceRenamer.java +++ b/common/src/main/java/net/neoforged/gradle/common/runtime/naming/renamer/RegexBasedSourceRenamer.java @@ -185,7 +185,7 @@ private String getMapped(String srg, @Nullable Set blacklist) { String ret = getNames().getOrDefault(srg, srg); if (cap) - ret = ret.substring(0, 1).toUpperCase(Locale.ENGLISH) + ret.substring(1); + ret = ret.substring(0, 1).toUpperCase(Locale.ROOT) + ret.substring(1); return ret; } diff --git a/common/src/main/java/net/neoforged/gradle/common/runtime/specification/CommonRuntimeSpecification.java b/common/src/main/java/net/neoforged/gradle/common/runtime/specification/CommonRuntimeSpecification.java index 1baafa663..a8053ed5b 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runtime/specification/CommonRuntimeSpecification.java +++ b/common/src/main/java/net/neoforged/gradle/common/runtime/specification/CommonRuntimeSpecification.java @@ -15,6 +15,7 @@ import org.gradle.api.provider.Provider; import org.jetbrains.annotations.NotNull; +import java.util.Locale; import java.util.Map; import java.util.function.Consumer; @@ -63,7 +64,7 @@ public String getName() { @NotNull @Override public String getIdentifier() { - return getName() + StringUtils.capitalize(getDistribution().getName().toLowerCase()) + version; + return getName() + StringUtils.capitalize(getDistribution().getName().toLowerCase(Locale.ROOT)) + version; } @Override diff --git a/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/DefaultRuntime.java b/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/DefaultRuntime.java index bbd20a108..f4f4d8755 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/DefaultRuntime.java +++ b/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/DefaultRuntime.java @@ -73,19 +73,10 @@ public String getGroup() { return String.format("NeoGradle/Runtime/%s", name); } - protected Provider getFileInOutputDirectory(final String fileName) { return getOutputDirectory().map(directory -> directory.file(fileName).getAsFile()); } - protected Provider getFileInOutputDirectory(final Provider fileName) { - return getOutputDirectory().flatMap(directory -> fileName.map(f -> directory.file(f).getAsFile())); - } - - protected Provider getRegularFileInOutputDirectory(final Provider fileName) { - return getOutputDirectory().flatMap(directory -> fileName.map(directory::file)); - } - @Internal public abstract MapProperty getRuntimeData(); diff --git a/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/DownloadAssets.java b/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/DownloadAssets.java index 5673d9447..7ca3fb365 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/DownloadAssets.java +++ b/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/DownloadAssets.java @@ -4,11 +4,16 @@ import net.neoforged.gradle.common.CommonProjectPlugin; import net.neoforged.gradle.common.caching.CentralCacheService; import net.neoforged.gradle.common.util.FileCacheUtils; +import net.neoforged.gradle.dsl.common.tasks.WithWorkspace; import net.neoforged.gradle.util.TransformerUtils; import net.neoforged.gradle.common.runtime.tasks.action.DownloadFileAction; import net.neoforged.gradle.common.util.SerializationUtils; import net.neoforged.gradle.common.util.VersionJson; +import org.gradle.api.DefaultTask; +import org.gradle.api.Project; +import org.gradle.api.file.Directory; import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFile; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; @@ -16,26 +21,40 @@ import org.gradle.api.tasks.*; import org.gradle.workers.WorkQueue; import org.gradle.workers.WorkerExecutor; +import org.jetbrains.annotations.NotNull; import javax.inject.Inject; import java.io.File; import java.util.Map; -@SuppressWarnings({"UnstableApiUsage", "ResultOfMethodCallIgnored"}) +@SuppressWarnings({"UnstableApiUsage"}) @CacheableTask -public abstract class DownloadAssets extends DefaultRuntime { +public abstract class DownloadAssets extends DefaultTask implements WithWorkspace { + + private final Provider assetsCache; public DownloadAssets() { - getAssetsDirectory().convention(FileCacheUtils.getAssetsCacheDirectory(getProject()).flatMap(assetsDir -> assetsDir.dir(getVersionJson().map(VersionJson::getId))).map(TransformerUtils.ensureExists())); - getOutputDirectory().convention(getAssetsDirectory()); + this.assetsCache = getAssetsDirectory(getProject(), getVersionJson()); getAssetIndex().convention("asset-index"); getAssetIndexFileName().convention(getAssetIndex().map(index -> index + ".json")); - getAssetIndexFile().convention(getRegularFileInOutputDirectory(getAssetIndexFileName().map(name -> "indexes/" + name))); + getAssetIndexFile().convention(getRegularFileInAssetsDirectory(getAssetIndexFileName().map(name -> "indexes/" + name))); getVersionJson().convention(getVersionJsonFile().map(TransformerUtils.guard(file -> VersionJson.get(file.getAsFile())))); getAssetRepository().convention("https://resources.download.minecraft.net/"); getIsOffline().convention(getProject().getGradle().getStartParameter().isOffline()); } - + + public static @NotNull Provider getAssetsDirectory(final Project project, final Provider versionJsonProvider) { + return FileCacheUtils.getAssetsCacheDirectory(project).flatMap(assetsDir -> assetsDir.dir(versionJsonProvider.map(VersionJson::getId))).map(TransformerUtils.ensureExists()); + } + + protected Provider getFileInAssetsDirectory(final String fileName) { + return assetsCache.map(directory -> directory.file(fileName).getAsFile()); + } + + protected Provider getRegularFileInAssetsDirectory(final Provider fileName) { + return assetsCache.flatMap(directory -> fileName.map(directory::file)); + } + @ServiceReference(CommonProjectPlugin.ASSETS_SERVICE) public abstract Property getAssetsCache(); @@ -67,7 +86,7 @@ private void downloadAssets() { final WorkQueue executor = getWorkerExecutor().noIsolation(); assetIndex.getObjects().values().stream().distinct().forEach((asset) -> { - final Provider assetFile = getFileInOutputDirectory(String.format("objects%s%s", File.separator, asset.getPath())); + final Provider assetFile = getFileInAssetsDirectory(String.format("objects%s%s", File.separator, asset.getPath())); final Provider assetUrl = getAssetRepository() .map(repo -> repo.endsWith("/") ? repo : repo + "/") .map(TransformerUtils.guard(repository -> repository + asset.getPath())); @@ -110,10 +129,6 @@ private void downloadAssets() { @Input public abstract Property getIsOffline(); - @InputDirectory - @PathSensitive(PathSensitivity.NONE) - public abstract DirectoryProperty getAssetsDirectory(); - private static class AssetIndex { private Map objects = Maps.newHashMap(); diff --git a/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/action/DownloadFileAction.java b/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/action/DownloadFileAction.java index fcd6b37fe..70b1fbcce 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/action/DownloadFileAction.java +++ b/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/action/DownloadFileAction.java @@ -106,30 +106,25 @@ public void execute() { } } - private static final class Monitor implements CopyProgressListener { - private final GradleInternalUtils.ProgressLoggerWrapper progress; - - private Monitor(GradleInternalUtils.ProgressLoggerWrapper progress) { - this.progress = progress; - } + private record Monitor(GradleInternalUtils.ProgressLoggerWrapper progress) implements CopyProgressListener { @Override - public void start(CopyProgressEvent evt) { - progress.started(); - progress.incrementDownloadProgress(evt.getReadBytes()); - } + public void start(CopyProgressEvent evt) { + progress.started(); + progress.incrementDownloadProgress(evt.getReadBytes()); + } - @Override - public void progress(CopyProgressEvent evt) { - progress.incrementDownloadProgress(evt.getReadBytes()); - } + @Override + public void progress(CopyProgressEvent evt) { + progress.incrementDownloadProgress(evt.getReadBytes()); + } - @Override - public void end(CopyProgressEvent evt) { - progress.incrementDownloadProgress(evt.getReadBytes()); - progress.completed(); + @Override + public void end(CopyProgressEvent evt) { + progress.incrementDownloadProgress(evt.getReadBytes()); + progress.completed(); + } } - } private static final class Timeout implements TimeoutConstraint { diff --git a/common/src/main/java/net/neoforged/gradle/common/util/FileCacheUtils.java b/common/src/main/java/net/neoforged/gradle/common/util/FileCacheUtils.java index b99ed7feb..83868f87a 100644 --- a/common/src/main/java/net/neoforged/gradle/common/util/FileCacheUtils.java +++ b/common/src/main/java/net/neoforged/gradle/common/util/FileCacheUtils.java @@ -18,6 +18,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Locale; public final class FileCacheUtils { @@ -52,9 +53,9 @@ public static TaskProvider createVers public static TaskProvider createArtifactFileCacheProvidingTask(final Project project, final String minecraftVersion, final DistributionType distributionType, final MinecraftArtifactType type, final TaskProvider versionManifestProvider, final Collection> otherProviders) { final String taskName = NamingConstants.Task.CACHE_VERSION_PREFIX + StringUtils.capitalize( - type.name().toLowerCase() + type.name().toLowerCase(Locale.ROOT) ) + StringUtils.capitalize( - distributionType.getName().toLowerCase() + distributionType.getName().toLowerCase(Locale.ROOT) ) + minecraftVersion; if (project.getTasks().getNames().contains(taskName)) { diff --git a/common/src/main/java/net/neoforged/gradle/common/util/TaskDependencyUtils.java b/common/src/main/java/net/neoforged/gradle/common/util/TaskDependencyUtils.java index 5383e4b6e..bc0154828 100644 --- a/common/src/main/java/net/neoforged/gradle/common/util/TaskDependencyUtils.java +++ b/common/src/main/java/net/neoforged/gradle/common/util/TaskDependencyUtils.java @@ -10,6 +10,7 @@ import net.neoforged.gradle.dsl.common.util.Artifact; import org.gradle.api.Buildable; import org.gradle.api.Project; +import org.gradle.api.ProjectConfigurationException; import org.gradle.api.Task; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; @@ -212,6 +213,12 @@ public void add(@NotNull Object dependency) { } private void processTask(Task task) { + //Tasks that are outside our project are not relevant, they can cause issues in parallel projects anyway + //And their runtimes should not configure our runs anyway! + if (task.getProject() != this.project) { + return; + } + final Optional> rawJarRuntime = this.runtimes.stream().filter(runtime -> runtime.getRawJarTask().get().equals(task)).findFirst(); final Optional> sourceJarRuntime = this.runtimes.stream().filter(runtime -> runtime.getSourceJarTask().get().equals(task)).findFirst(); if (rawJarRuntime.isPresent()) { @@ -226,7 +233,7 @@ private void processTask(Task task) { } private void processConfiguration(Configuration configuration) { - DependencySet dependencies = configuration.getDependencies(); + DependencySet dependencies = configuration.getAllDependencies(); //Grab the original dependencies if we have a replacement extension final DependencyReplacement replacement = project.getExtensions().findByType(DependencyReplacement.class); @@ -244,14 +251,6 @@ private void processConfiguration(Configuration configuration) { return false; } }).forEach(this::add); - - configuration.getExtendsFrom().forEach(this::add); - - if (configuration.isCanBeResolved()) { - for (Task task : configuration.getBuildDependencies().getDependencies(null)) { - add(task); - } - } } private void processSourceDirectorySet(SourceDirectorySet sourceDirectorySet) { @@ -268,6 +267,13 @@ private void processSourceDirectorySet(SourceDirectorySet sourceDirectorySet) { } private void processSourceSet(SourceSet sourceSet) { + //We only care about source sets in our project + //We don't want to configure runtimes for other projects + //This can cause issues with parallel projects + if (SourceSetUtils.getProject(sourceSet) != this.project) { + return; + } + Property> runtimeDefinition = (Property>) sourceSet.getExtensions().findByName("runtimeDefinition"); if (runtimeDefinition != null && runtimeDefinition.isPresent()) { this.add(runtimeDefinition.get()); diff --git a/common/src/main/java/net/neoforged/gradle/common/util/VersionJson.java b/common/src/main/java/net/neoforged/gradle/common/util/VersionJson.java index 8574873cf..19209b939 100644 --- a/common/src/main/java/net/neoforged/gradle/common/util/VersionJson.java +++ b/common/src/main/java/net/neoforged/gradle/common/util/VersionJson.java @@ -400,7 +400,7 @@ public String getName() { } public static OS getCurrent() { - String prop = System.getProperty("os.name").toLowerCase(Locale.ENGLISH); + String prop = System.getProperty("os.name").toLowerCase(Locale.ROOT); for (OS os : OS.values()) { for (String key : os.keys) { if (prop.contains(key)) { diff --git a/common/src/main/java/net/neoforged/gradle/common/util/hash/Hashing.java b/common/src/main/java/net/neoforged/gradle/common/util/hash/Hashing.java index 03c365dec..d479998aa 100644 --- a/common/src/main/java/net/neoforged/gradle/common/util/hash/Hashing.java +++ b/common/src/main/java/net/neoforged/gradle/common/util/hash/Hashing.java @@ -13,6 +13,7 @@ import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.Objects; public class Hashing { private static final HashFunction MD5 = MessageDigestHashFunction.of("MD5"); @@ -355,9 +356,24 @@ public HashCode hashStream(InputStream stream) throws IOException { } public HashCode hashFile(File file) throws IOException { - HashingOutputStream hashingOutputStream = this.primitiveStreamHasher(); - Files.copy(file, hashingOutputStream); - return hashingOutputStream.hash(); + if (file.exists()) { + if (file.isDirectory()) { + final Hasher hasher = this.newHasher(); + + for (File listFile : Objects.requireNonNull(file.listFiles())) { + final HashCode innerHash = this.hashFile(listFile); + hasher.putHash(innerHash); + } + + return hasher.hash(); + } else { + HashingOutputStream hashingOutputStream = this.primitiveStreamHasher(); + Files.copy(file, hashingOutputStream); + return hashingOutputStream.hash(); + } + } else { + return HashCode.fromString(""); + } } private HashingOutputStream primitiveStreamHasher() { diff --git a/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/util/DistributionType.groovy b/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/util/DistributionType.groovy index 156d77a42..a1f90d261 100644 --- a/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/util/DistributionType.groovy +++ b/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/util/DistributionType.groovy @@ -81,6 +81,6 @@ enum DistributionType { * @param suffix The suffix for the task name. */ String createTaskName(final String prefix, final String suffix) { - return "${StringUtils.uncapitalize(prefix)}${StringUtils.capitalize(this.name().toLowerCase())}${StringUtils.capitalize(suffix)}".toString(); + return "${StringUtils.uncapitalize(prefix)}${StringUtils.capitalize(this.name().toLowerCase(Locale.ROOT))}${StringUtils.capitalize(suffix)}".toString(); } } diff --git a/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/extensions/NeoFormRuntimeExtension.java b/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/extensions/NeoFormRuntimeExtension.java index 67b54233d..af8355511 100644 --- a/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/extensions/NeoFormRuntimeExtension.java +++ b/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/extensions/NeoFormRuntimeExtension.java @@ -509,15 +509,24 @@ private static TaskProvider maybeApplyParchment(NeoFormRun File mappingFile = ToolUtilities.resolveTool(project, parchment.getParchmentArtifact().get()); File toolExecutable = ToolUtilities.resolveTool(project, tools.getJST().get()); - task.getInputs().file(mappingFile); + task.getArguments().putFile("mappings", project.provider(() -> mappingFile)); + task.getArguments().putRegularFile("libraries", listLibrariesOutput); + task.getArguments().putRegularFile("input", recompileInput.flatMap(WithOutput::getOutput)); + task.getExecutingJar().set(toolExecutable); - task.getProgramArguments().add(listLibrariesOutput.map(f -> "--libraries-list=" + f.getAsFile().getAbsolutePath())); + task.getProgramArguments().add("--libraries-list"); + task.getProgramArguments().add("{libraries}"); task.getProgramArguments().add("--enable-parchment"); - task.getProgramArguments().add("--parchment-mappings=" + mappingFile.getAbsolutePath()); + task.getProgramArguments().add("--parchment-mappings"); + task.getProgramArguments().add("{mappings}"); task.getProgramArguments().add("--in-format=archive"); task.getProgramArguments().add("--out-format=archive"); - task.getProgramArguments().add(recompileInput.flatMap(WithOutput::getOutput).map(f -> f.getAsFile().getAbsolutePath())); + task.getProgramArguments().add("{input}"); task.getProgramArguments().add("{output}"); + + task.dependsOn(listLibrariesOutput); + task.dependsOn(recompileInput); + configureCommonRuntimeTaskParameters(task, symbolicDataSources, "applyParchment", spec, neoFormDirectory); }); diff --git a/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/tasks/RecompileSourceJar.java b/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/tasks/RecompileSourceJar.java index ccc228022..ec472c17f 100644 --- a/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/tasks/RecompileSourceJar.java +++ b/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/tasks/RecompileSourceJar.java @@ -1,5 +1,7 @@ package net.neoforged.gradle.neoform.runtime.tasks; +import net.neoforged.gradle.common.CommonProjectPlugin; +import net.neoforged.gradle.common.caching.CentralCacheService; import net.neoforged.gradle.common.runtime.tasks.RuntimeArgumentsImpl; import net.neoforged.gradle.common.runtime.tasks.RuntimeMultiArgumentsImpl; import net.neoforged.gradle.dsl.common.runtime.tasks.Runtime; @@ -11,9 +13,11 @@ import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.provider.ProviderFactory; +import org.gradle.api.services.ServiceReference; import org.gradle.api.tasks.*; import org.gradle.api.tasks.compile.JavaCompile; import org.gradle.internal.jvm.Jvm; +import org.gradle.jvm.toolchain.JavaCompiler; import org.gradle.jvm.toolchain.JavaLanguageVersion; import org.gradle.jvm.toolchain.JavaToolchainService; import org.gradle.work.InputChanges; @@ -121,4 +125,19 @@ public Property getJavaVersion() { @Inject @Override public abstract ProviderFactory getProviderFactory(); + + @ServiceReference(CommonProjectPlugin.EXECUTE_SERVICE) + public abstract Property getCacheService(); + + @Override + protected void compile(InputChanges inputs) { + try { + getCacheService().get().doCachedDirectory(this, () -> { + super.compile(inputs); + return getDestinationDirectory().get().getAsFile(); + }, getDestinationDirectory()); + } catch (Throwable e) { + throw new RuntimeException("Failed to recompile using caching.", e); + } + } } diff --git a/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java b/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java index dfeae5e87..47b9dce5b 100644 --- a/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java +++ b/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java @@ -770,7 +770,7 @@ private void configureRunType(final Project project, final RunType runType, fina runType.getClasspath().from(runtimeClasspath); - Provider assetsDir = runtimeDefinition.getAssets().flatMap(DownloadAssets::getAssetsDirectory).map(Directory::getAsFile).map(File::getAbsolutePath); + Provider assetsDir = DownloadAssets.getAssetsDirectory(project, project.provider(runtimeDefinition::getVersionJson)).map(Directory::getAsFile).map(File::getAbsolutePath); // runtimeDefinition.getAssets().flatMap().map(Directory::getAsFile).map(File::getAbsolutePath); Provider assetIndex = runtimeDefinition.getAssets().flatMap(DownloadAssets::getAssetIndex); runType.getRunAdapter().set(run -> { diff --git a/test-utils/src/main/groovy/net/neoforged/gradle/utils/test/extensions/RuntimeBuilderExtensions.groovy b/test-utils/src/main/groovy/net/neoforged/gradle/utils/test/extensions/RuntimeBuilderExtensions.groovy index 099c92cfa..024f919c6 100644 --- a/test-utils/src/main/groovy/net/neoforged/gradle/utils/test/extensions/RuntimeBuilderExtensions.groovy +++ b/test-utils/src/main/groovy/net/neoforged/gradle/utils/test/extensions/RuntimeBuilderExtensions.groovy @@ -43,4 +43,14 @@ class RuntimeBuilderExtensions { static Runtime.Builder disableConventions(final Runtime.Builder self) { self.property("neogradle.subsystems.conventions.enabled", "false") } + + /** + * Enables parallel running for the runtime. + * + * @param self the runtime builder + * @return the runtime builder + */ + static Runtime.Builder enableGradleParallelRunning(final Runtime.Builder self) { + self.property("org.gradle.parallel", "true") + } } diff --git a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/AccessTransformerTests.groovy b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/AccessTransformerTests.groovy index 13115fb6e..043a28610 100644 --- a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/AccessTransformerTests.groovy +++ b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/AccessTransformerTests.groovy @@ -54,6 +54,48 @@ class AccessTransformerTests extends BuilderBasedTestSpecification { initialRun.task(":build").outcome == TaskOutcome.SUCCESS } + def "the userdev runtime supports loading ats from a file after the dependencies block"() { + given: + def project = create("userdev_supports_ats_from_file", { + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + dependencies { + implementation 'net.neoforged:neoforge:+' + } + + minecraft.accessTransformers.file rootProject.file('src/main/resources/META-INF/accesstransformer.cfg') + """) + it.file("src/main/resources/META-INF/accesstransformer.cfg", """public-f net.minecraft.client.Minecraft fixerUpper # fixerUpper""") + it.file("src/main/java/net/neoforged/gradle/userdev/FunctionalTests.java", """ + package net.neoforged.gradle.userdev; + + import net.minecraft.client.Minecraft; + + public class FunctionalTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().fixerUpper.getClass().toString()); + } + } + """) + it.withToolchains() + it.withGlobalCacheDirectory(tempDir) + }) + + when: + def initialRun = project.run { + it.tasks('build') + } + + then: + initialRun.task(":neoFormRecompile").outcome == TaskOutcome.SUCCESS + initialRun.task(":build").outcome == TaskOutcome.SUCCESS + } + def "the userdev runtime supports loading ats from the script"() { given: def project = create("userdev_supports_ats_in_scripts", { diff --git a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/CentralCacheTests.groovy b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/CentralCacheTests.groovy index 325740d57..6960c0f47 100644 --- a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/CentralCacheTests.groovy +++ b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/CentralCacheTests.groovy @@ -90,7 +90,7 @@ class CentralCacheTests extends BuilderBasedTestSpecification { } def "cache_supports_running_gradle_in_parallel"() { - if (System.getProperty("os.name").toLowerCase().contains("windows")) { + if (System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("windows")) { //When we run on windows we do not get the right output, since we use native file locking. return } @@ -207,4 +207,75 @@ class CentralCacheTests extends BuilderBasedTestSpecification { run.task(':build').outcome == TaskOutcome.SUCCESS run.output.contains("Cache is disabled, skipping cache") } + + def "updating an AT after cache run should work."() { + given: + def project = create("userdev_supports_ats_from_file", { + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + minecraft.accessTransformers.file rootProject.file('src/main/resources/META-INF/accesstransformer.cfg') + + dependencies { + implementation 'net.neoforged:neoforge:+' + } + """) + it.file("src/main/resources/META-INF/accesstransformer.cfg", """public-f net.minecraft.client.Minecraft fixerUpper # fixerUpper""") + it.file("src/main/java/net/neoforged/gradle/userdev/FunctionalTests.java", """ + package net.neoforged.gradle.userdev; + + import net.minecraft.client.Minecraft; + + public class FunctionalTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().fixerUpper.getClass().toString()); + } + } + """) + it.withToolchains() + it.withGlobalCacheDirectory(tempDir) + it.property(CentralCacheService.LOG_CACHE_HITS_PROPERTY, "true") + it.property(CentralCacheService.DEBUG_CACHE_PROPERTY, "true") + }) + + when: + def initialRun = project.run { + it.tasks('build') + } + + then: + initialRun.task(":neoFormRecompile").outcome == TaskOutcome.SUCCESS + initialRun.task(":build").outcome == TaskOutcome.SUCCESS + + when: + File atFile = initialRun.file("src/main/resources/META-INF/accesstransformer.cfg") + atFile.delete() + atFile << """public-f net.minecraft.client.Minecraft REGIONAL_COMPLIANCIES # REGIONAL_COMPLIANCIES""" + + File codeFile = initialRun.file("src/main/java/net/neoforged/gradle/userdev/FunctionalTests.java") + codeFile.delete() + codeFile << """ + package net.neoforged.gradle.userdev; + + import net.minecraft.client.Minecraft; + + public class FunctionalTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().REGIONAL_COMPLIANCIES.getClass().toString()); + } + } + """ + + def secondRun = project.run { + it.tasks('build') + } + + then: + secondRun.task(":neoFormRecompile").outcome == TaskOutcome.SUCCESS + secondRun.task(":build").outcome == TaskOutcome.SUCCESS + } } diff --git a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/MultiProjectTests.groovy b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/MultiProjectTests.groovy index ccc1128eb..ffa65a2e0 100644 --- a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/MultiProjectTests.groovy +++ b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/MultiProjectTests.groovy @@ -100,10 +100,11 @@ class MultiProjectTests extends BuilderBasedTestSpecification { then: run.task(':main:writeMinecraftClasspathData').outcome == TaskOutcome.SUCCESS + + def resourcesMainBuildDir = run.file("main/build/resources/main") run.output.contains("Error during pre-loading phase: ERROR: File null is not a valid mod file") || - run.output.contains("Caused by: net.neoforged.fml.ModLoadingException: Loading errors encountered: [\n" + - "\tfml.modloading.brokenfile\n" + - "]")//Validate that we are failing because of the missing mod file, and not something else. + run.output.contains("Caused by: net.neoforged.fml.ModLoadingException: Loading errors encountered:\n" + + "\t- File ${resourcesMainBuildDir.absolutePath} is not a valid mod file")//Validate that we are failing because of the missing mod file, and not something else. } def "multiple projects with neoforge dependencies should run using the central cache"() { @@ -641,7 +642,6 @@ class MultiProjectTests extends BuilderBasedTestSpecification { """) it.withToolchains() it.withGlobalCacheDirectory(tempDir) - it.disableConventions() }) create(rootProject, "api", { @@ -736,4 +736,102 @@ class MultiProjectTests extends BuilderBasedTestSpecification { modSourcesSection.get(2) == " - main" modSourcesSection.get(3) == " - main" } + + + def "multiple projects with neoforge dependencies should run when parallel is enabled"() { + given: + def rootProject = create("multi_neoforge_root_cached", { + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + """) + it.withGlobalCacheDirectory(tempDir) + it.withToolchains() + it.enableGradleParallelRunning() + }) + + def apiProject = create(rootProject, "api", { + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + dependencies { + implementation 'net.neoforged:neoforge:+' + } + """) + it.file("src/main/java/net/neoforged/gradle/apitest/FunctionalTests.java", """ + package net.neoforged.gradle.apitest; + + import net.minecraft.client.Minecraft; + + public class FunctionalTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().getClass().toString()); + } + } + """) + it.withToolchains() + it.withGlobalCacheDirectory(tempDir) + it.plugin(this.pluginUnderTest) + }) + + def mainProject = create(rootProject,"main", { + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + dependencies { + implementation 'net.neoforged:neoforge:+' + implementation project(':api') + } + + runs { + client { + modSource project(':api').sourceSets.main + } + } + """) + it.file("src/main/java/net/neoforged/gradle/main/ApiTests.java", """ + package net.neoforged.gradle.main; + + import net.minecraft.client.Minecraft; + import net.neoforged.gradle.apitest.FunctionalTests; + + public class ApiTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().getClass().toString()); + FunctionalTests.main(args); + } + } + """) + it.withToolchains() + it.withGlobalCacheDirectory(tempDir) + it.plugin(this.pluginUnderTest) + }) + + when: + def run = rootProject.run { + it.tasks(':main:build') + it.stacktrace() + } + + then: + run.task(':main:build').outcome == TaskOutcome.SUCCESS + run.task(':api:neoFormDecompile').outcome == TaskOutcome.SUCCESS || run.task(':api:neoFormDecompile').outcome == TaskOutcome.UP_TO_DATE + run.task(':main:neoFormDecompile').outcome == TaskOutcome.SUCCESS || run.task(':main:neoFormDecompile').outcome == TaskOutcome.UP_TO_DATE + + if (run.task(':api:neoFormDecompile').outcome == TaskOutcome.SUCCESS) + run.task(':main:neoFormDecompile').outcome == TaskOutcome.UP_TO_DATE + else if (run.task(':main:neoFormDecompile').outcome == TaskOutcome.SUCCESS) + run.task(':api:neoFormDecompile').outcome == TaskOutcome.UP_TO_DATE + } } diff --git a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/RunTests.groovy b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/RunTests.groovy index 2b3339039..f9825caa1 100644 --- a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/RunTests.groovy +++ b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/RunTests.groovy @@ -60,10 +60,11 @@ class RunTests extends BuilderBasedTestSpecification { then: run.task(':writeMinecraftClasspathData').outcome == TaskOutcome.SUCCESS + + def resourcesMainBuildDir = run.file("build/resources/main") run.output.contains("Error during pre-loading phase: ERROR: File null is not a valid mod file") || - run.output.contains("Caused by: net.neoforged.fml.ModLoadingException: Loading errors encountered: [\n" + - "\tfml.modloading.brokenfile\n" + - "]")//Validate that we are failing because of the missing mod file, and not something else. + run.output.contains("Caused by: net.neoforged.fml.ModLoadingException: Loading errors encountered:\n" + + "\t- File ${resourcesMainBuildDir.absolutePath} is not a valid mod file")//Validate that we are failing because of the missing mod file, and not something else. } def "runs can be declared before the dependencies block"() { diff --git a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy index b62e89ae1..b73569aaf 100644 --- a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy +++ b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy @@ -248,7 +248,7 @@ class SourceSetConventionTests extends BuilderBasedTestSpecification { } then: - run.output.contains("Run sources: []") + run.output.contains("Run: client has no source sets configured. Please configure at least one source set.") } def "disabling sourceset conventions prevents registration of main sourceset to run"() { @@ -289,7 +289,7 @@ class SourceSetConventionTests extends BuilderBasedTestSpecification { } then: - run.output.contains("Run sources: []") + run.output.contains("Run: client has no source sets configured. Please configure at least one source set.") } def "disabling main source set registration conventions prevents registration of main sourceset to run"() { @@ -330,7 +330,7 @@ class SourceSetConventionTests extends BuilderBasedTestSpecification { } then: - run.output.contains("Run sources: []") + run.output.contains("Run: client has no source sets configured. Please configure at least one source set.") } def "having the conventions for main sourceset registration enabled registers it"() { @@ -356,7 +356,7 @@ class SourceSetConventionTests extends BuilderBasedTestSpecification { } afterEvaluate { - logger.lifecycle("Run sources: \${project.runs.client.modSources.get()}") + logger.lifecycle("Run sources: \${project.runs.client.modSources.all().get()}") } """) it.withToolchains() @@ -370,7 +370,7 @@ class SourceSetConventionTests extends BuilderBasedTestSpecification { then: run.task(':dependencies').outcome == TaskOutcome.SUCCESS - run.output.contains("Run sources: [source set 'main']") + run.output.contains("Run sources: {registration_enabled=[source set 'main']}") } def "disabling sourceset local run runtime registration conventions prevents registration of localRunRuntime"() { diff --git a/utils/src/main/java/net/neoforged/gradle/util/StringCapitalizationUtils.java b/utils/src/main/java/net/neoforged/gradle/util/StringCapitalizationUtils.java index 140e23440..d36d88da2 100644 --- a/utils/src/main/java/net/neoforged/gradle/util/StringCapitalizationUtils.java +++ b/utils/src/main/java/net/neoforged/gradle/util/StringCapitalizationUtils.java @@ -1,6 +1,7 @@ package net.neoforged.gradle.util; import javax.annotation.Nonnull; +import java.util.Locale; /** * Util class for handling string capitalization @@ -13,11 +14,11 @@ private StringCapitalizationUtils() { @Nonnull public static String capitalize(@Nonnull final String toCapitalize) { - return toCapitalize.length() > 1 ? toCapitalize.substring(0, 1).toUpperCase() + toCapitalize.substring(1) : toCapitalize; + return toCapitalize.length() > 1 ? toCapitalize.substring(0, 1).toUpperCase(Locale.ROOT) + toCapitalize.substring(1) : toCapitalize; } @Nonnull public static String deCapitalize(@Nonnull final String toCapitalize) { - return toCapitalize.length() > 1 ? toCapitalize.substring(0, 1).toLowerCase() + toCapitalize.substring(1) : toCapitalize; + return toCapitalize.length() > 1 ? toCapitalize.substring(0, 1).toLowerCase(Locale.ROOT) + toCapitalize.substring(1) : toCapitalize; } } diff --git a/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/VanillaRuntimeDefinition.java b/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/VanillaRuntimeDefinition.java index 07b0b6238..40f1ce60d 100644 --- a/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/VanillaRuntimeDefinition.java +++ b/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/VanillaRuntimeDefinition.java @@ -79,7 +79,7 @@ protected Map buildRunInterpolationData(RunImpl run) { final String fgVersion = this.getClass().getPackage().getImplementationVersion(); interpolationData.put(InterpolationConstants.VERSION_NAME, getSpecification().getMinecraftVersion()); - interpolationData.put(InterpolationConstants.ASSETS_ROOT, getAssets().get().getOutputDirectory().get().getAsFile().getAbsolutePath()); + interpolationData.put(InterpolationConstants.ASSETS_ROOT, DownloadAssets.getAssetsDirectory(run.getProject(), run.getProject().provider(this::getVersionJson)).get().getAsFile().getAbsolutePath()); interpolationData.put(InterpolationConstants.ASSETS_INDEX_NAME, getAssets().get().getAssetIndexFile().get().getAsFile().getName().substring(0, getAssets().get().getAssetIndexFile().get().getAsFile().getName().lastIndexOf('.'))); interpolationData.put(InterpolationConstants.AUTH_ACCESS_TOKEN, "0"); interpolationData.put(InterpolationConstants.USER_TYPE, "legacy"); diff --git a/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/steps/ParchmentStep.java b/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/steps/ParchmentStep.java index 5c4793a2d..2fff73a37 100644 --- a/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/steps/ParchmentStep.java +++ b/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/steps/ParchmentStep.java @@ -14,6 +14,8 @@ import net.neoforged.gradle.vanilla.runtime.VanillaRuntimeDefinition; import net.neoforged.gradle.vanilla.runtime.spec.VanillaRuntimeSpecification; import org.gradle.api.Project; +import org.gradle.api.Transformer; +import org.gradle.api.artifacts.ResolvedArtifact; import org.gradle.api.file.RegularFile; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.TaskProvider; @@ -58,17 +60,24 @@ private static TaskProvider maybeApplyParchment(VanillaRuntim File mappingFile = ToolUtilities.resolveTool(project, parchment.getParchmentArtifact().get()); File toolExecutable = ToolUtilities.resolveTool(project, tools.getJST().get()); - task.getInputs().file(mappingFile); - task.getInputs().file(inputProvidingTask.flatMap(WithOutput::getOutput)); - task.getInputs().file(listLibrariesOutput); + task.getArguments().putFile("mappings", project.provider(() -> mappingFile)); + task.getArguments().putRegularFile("libraries", listLibrariesOutput); + task.getArguments().putRegularFile("input", inputProvidingTask.flatMap(WithOutput::getOutput)); + task.getExecutingJar().set(toolExecutable); - task.getProgramArguments().add(listLibrariesOutput.map(f -> "--libraries-list=" + f.getAsFile().getAbsolutePath())); + task.getProgramArguments().add("--libraries-list"); + task.getProgramArguments().add("{libraries}"); task.getProgramArguments().add("--enable-parchment"); - task.getProgramArguments().add("--parchment-mappings=" + mappingFile.getAbsolutePath()); + task.getProgramArguments().add("--parchment-mappings"); + task.getProgramArguments().add("{mappings}"); task.getProgramArguments().add("--in-format=archive"); task.getProgramArguments().add("--out-format=archive"); - task.getProgramArguments().add(inputProvidingTask.flatMap(WithOutput::getOutput).map(f -> f.getAsFile().getAbsolutePath())); + task.getProgramArguments().add("{input}"); task.getProgramArguments().add("{output}"); + + task.dependsOn(inputProvidingTask); + task.dependsOn(listLibrariesOutput); + configureCommonRuntimeTaskParameters(task, Maps.newHashMap(), "applyParchment", spec, vanillaDirectory); }); } From c5a353aefde0b71706fa9550387127be9e5d36ad Mon Sep 17 00:00:00 2001 From: Marc Hermans Date: Mon, 17 Jun 2024 16:55:30 +0200 Subject: [PATCH 2/5] Fix a case where run lookups could not be converted back due to parent configurations. --- .../dependency/replacement/ReplacementLogic.java | 13 +++++++++++-- .../convention/SourceSetConventionTests.groovy | 5 +---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/net/neoforged/gradle/common/extensions/dependency/replacement/ReplacementLogic.java b/common/src/main/java/net/neoforged/gradle/common/extensions/dependency/replacement/ReplacementLogic.java index 14e4b8f71..910f73158 100644 --- a/common/src/main/java/net/neoforged/gradle/common/extensions/dependency/replacement/ReplacementLogic.java +++ b/common/src/main/java/net/neoforged/gradle/common/extensions/dependency/replacement/ReplacementLogic.java @@ -90,9 +90,18 @@ public NamedDomainObjectContainer getReplacementHa @NotNull @Override - public Dependency optionallyConvertBackToOriginal(Dependency dependency, Configuration configuration) { + public Dependency optionallyConvertBackToOriginal(@NotNull final Dependency dependency, Configuration configuration) { final Dependency originalDependency = originalDependencyLookup.get(dependency, configuration); - return originalDependency == null ? dependency : originalDependency; + if (originalDependency == null && !configuration.getExtendsFrom().isEmpty()) { + //Check if we have a parent configuration that might have the original dependency. + for (Configuration parentConfiguration : configuration.getExtendsFrom()) { + return optionallyConvertBackToOriginal(dependency, parentConfiguration); + } + } else if (originalDependency != null) { + return originalDependency; + } + + return dependency; } /** diff --git a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy index b73569aaf..b6b6db1b8 100644 --- a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy +++ b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy @@ -392,10 +392,6 @@ class SourceSetConventionTests extends BuilderBasedTestSpecification { implementation 'net.neoforged:neoforge:+' localRunRuntime 'org.jgrapht:jgrapht-core:+' } - - runs { - client { } - } """) it.withToolchains() it.withGlobalCacheDirectory(tempDir) @@ -404,6 +400,7 @@ class SourceSetConventionTests extends BuilderBasedTestSpecification { when: def run = project.run { it.tasks(':writeMinecraftClasspathClient') + it.debug() } then: From 94a1ce0fa770f16047a3f2f33390eb548f16c633 Mon Sep 17 00:00:00 2001 From: Marc Hermans Date: Mon, 17 Jun 2024 17:22:44 +0200 Subject: [PATCH 3/5] Remove the debug flag that bricked the tests. --- .../gradle/userdev/convention/SourceSetConventionTests.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy index b6b6db1b8..f2cc66354 100644 --- a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy +++ b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/convention/SourceSetConventionTests.groovy @@ -400,7 +400,6 @@ class SourceSetConventionTests extends BuilderBasedTestSpecification { when: def run = project.run { it.tasks(':writeMinecraftClasspathClient') - it.debug() } then: From b841a98e2057b591af881bda4f0f521947badf9a Mon Sep 17 00:00:00 2001 From: Marc Hermans Date: Mon, 17 Jun 2024 17:26:22 +0200 Subject: [PATCH 4/5] Address Scis review --- .../gradle/common/CommonProjectPlugin.java | 2 -- .../tasks/action/DownloadFileAction.java | 30 +++++++++++-------- .../extensions/DynamicProjectExtension.java | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java b/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java index 92993f620..9e9d64135 100644 --- a/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java +++ b/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java @@ -390,8 +390,6 @@ private void applyAfterEvaluate(final Project project) { } }); - - definitionSet.forEach((identifier, definition) -> { definition.configureRun(runImpl); }); diff --git a/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/action/DownloadFileAction.java b/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/action/DownloadFileAction.java index 70b1fbcce..4a6369ea9 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/action/DownloadFileAction.java +++ b/common/src/main/java/net/neoforged/gradle/common/runtime/tasks/action/DownloadFileAction.java @@ -109,22 +109,22 @@ public void execute() { private record Monitor(GradleInternalUtils.ProgressLoggerWrapper progress) implements CopyProgressListener { @Override - public void start(CopyProgressEvent evt) { - progress.started(); - progress.incrementDownloadProgress(evt.getReadBytes()); - } + public void start(CopyProgressEvent evt) { + progress.started(); + progress.incrementDownloadProgress(evt.getReadBytes()); + } - @Override - public void progress(CopyProgressEvent evt) { - progress.incrementDownloadProgress(evt.getReadBytes()); - } + @Override + public void progress(CopyProgressEvent evt) { + progress.incrementDownloadProgress(evt.getReadBytes()); + } - @Override - public void end(CopyProgressEvent evt) { - progress.incrementDownloadProgress(evt.getReadBytes()); - progress.completed(); - } + @Override + public void end(CopyProgressEvent evt) { + progress.incrementDownloadProgress(evt.getReadBytes()); + progress.completed(); } + } private static final class Timeout implements TimeoutConstraint { @@ -143,9 +143,13 @@ public int getReadTimeout() { public interface Params extends WorkParameters { Property getUrl(); + Property getSha1(); + Property getShouldValidateHash(); + RegularFileProperty getOutputFile(); + Property getIsOffline(); } } diff --git a/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java b/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java index 47b9dce5b..778e2e059 100644 --- a/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java +++ b/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java @@ -770,7 +770,7 @@ private void configureRunType(final Project project, final RunType runType, fina runType.getClasspath().from(runtimeClasspath); - Provider assetsDir = DownloadAssets.getAssetsDirectory(project, project.provider(runtimeDefinition::getVersionJson)).map(Directory::getAsFile).map(File::getAbsolutePath); // runtimeDefinition.getAssets().flatMap().map(Directory::getAsFile).map(File::getAbsolutePath); + Provider assetsDir = DownloadAssets.getAssetsDirectory(project, project.provider(runtimeDefinition::getVersionJson)).map(Directory::getAsFile).map(File::getAbsolutePath); Provider assetIndex = runtimeDefinition.getAssets().flatMap(DownloadAssets::getAssetIndex); runType.getRunAdapter().set(run -> { From 05e60eee84cbb15c090145f49c0e03a402fc5971 Mon Sep 17 00:00:00 2001 From: Marc Hermans Date: Mon, 17 Jun 2024 18:16:08 +0200 Subject: [PATCH 5/5] Cleanup import and add metadata. --- build.gradle | 6 ++++++ .../net/neoforged/gradle/common/CommonProjectPlugin.java | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 041228c3a..e3555bc2b 100644 --- a/build.gradle +++ b/build.gradle @@ -166,6 +166,8 @@ subprojects.forEach { subProject -> evalSubProject.dependencies.functionalTestImplementation project(':test-utils') //Configure the plugin metadata, so we can publish it. + evalSubProject.gradlePlugin.website = "https://github.com/NeoForged/NeoGradle" + evalSubProject.gradlePlugin.vcsUrl = "https://github.com/NeoForged/NeoGradle.git" evalSubProject.gradlePlugin.plugins { NamedDomainObjectContainer plugins -> plugins.register(evalSubProject.name.toLowerCase(Locale.ROOT)) { @@ -192,6 +194,10 @@ subprojects.forEach { subProject -> id = pluginId //And the implementation class. implementationClass = pluginClassName + + displayName = "NeoForged Gradle ${evalSubProject.name.capitalize()} Plugin" + description = "A plugin for NeoForged Gradle, providing ${evalSubProject.name.capitalize()} functionality. Allowing you to setup Minecraft Modding workspaces with ease." + tags = ['minecraft', 'modding', 'gradle', 'neoforged', 'neoforge', evalSubProject.name.toLowerCase(Locale.ROOT)] } } diff --git a/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java b/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java index 9e9d64135..c3c9a3cb5 100644 --- a/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java +++ b/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java @@ -57,7 +57,6 @@ import org.jetbrains.gradle.ext.IdeaExtPlugin; import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; public class CommonProjectPlugin implements Plugin {