diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/GenerateDevBundle.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/GenerateDevBundle.kt index 423c44e4..ce46d834 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/GenerateDevBundle.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/GenerateDevBundle.kt @@ -29,7 +29,6 @@ import io.papermc.paperweight.util.* import io.papermc.paperweight.util.constants.* import io.papermc.paperweight.util.data.* import java.io.ByteArrayOutputStream -import java.nio.charset.Charset import java.nio.file.Files import java.nio.file.Path import java.util.Locale @@ -319,9 +318,6 @@ abstract class GenerateDevBundle : DefaultTask() { return asString(outBytes) } - private fun asString(out: ByteArrayOutputStream) = String(out.toByteArray(), Charset.defaultCharset()) - .replace(System.getProperty("line.separator"), "\n") - @Suppress("SameParameterValue") private fun createBundleConfig(dataTargetDir: String, patchTargetDir: String): DevBundleConfig { return DevBundleConfig( diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/project-util.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/project-util.kt index c719fa48..b99221ee 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/project-util.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/project-util.kt @@ -50,6 +50,8 @@ fun Project.setupServerProject( packagesToFix: Provider?>, reobfMappings: Provider, ): ServerTasks? { + testPathLength(providers) + if (!projectDir.exists()) { return null } diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt index 8b131d59..30787bd2 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt @@ -29,6 +29,7 @@ import io.papermc.paperweight.DownloadService import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.constants.* +import java.io.ByteArrayOutputStream import java.io.File import java.io.InputStream import java.io.OutputStream @@ -36,6 +37,7 @@ import java.lang.management.ManagementFactory import java.lang.reflect.Type import java.net.URI import java.net.URL +import java.nio.charset.Charset import java.nio.file.Path import java.nio.file.Paths import java.security.MessageDigest @@ -45,6 +47,7 @@ import java.util.Locale import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.ThreadLocalRandom +import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicLong import kotlin.io.path.* import org.cadixdev.lorenz.merge.MergeResult @@ -57,6 +60,7 @@ import org.gradle.api.file.RegularFile import org.gradle.api.file.RegularFileProperty import org.gradle.api.invocation.Gradle import org.gradle.api.logging.LogLevel +import org.gradle.api.logging.Logging import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.provider.Property import org.gradle.api.provider.Provider @@ -348,6 +352,60 @@ fun FileCollection.toJarClassProviderRoots(): List = files.as .map { p -> ClassProviderRoot.fromJar(p) } .toList() +fun asString(out: ByteArrayOutputStream) = String(out.toByteArray(), Charset.defaultCharset()) + .replace(System.lineSeparator(), "\n") + +fun testPathLength(providers: ProviderFactory) { + if (!providers.gradleProperty("paperweight.windowsLongPathWarning").map { it.toBoolean() }.orElse(true).get()) { + return + } + if (System.getProperty("os.name").lowercase().contains("win")) { + val registryQuery = + "reg query HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\FileSystem /v LongPathsEnabled" + val proc = ProcessBuilder() + .command(registryQuery.split(" ")) + .redirectErrorStream(true) + .start() + val outBytes = ByteArrayOutputStream() + val outFuture = redirect(proc.inputStream, outBytes) + if (!proc.waitFor(10L, TimeUnit.SECONDS)) { + proc.destroyForcibly() + throw PaperweightException("Command '$registryQuery' did not finish after 10 seconds, killed process") + } + outFuture.get(500L, TimeUnit.MILLISECONDS) + val out = asString(outBytes) + + val gitQuery = "git config --global --get core.longpaths" + val gitProc = ProcessBuilder() + .command(gitQuery.split(" ")) + .redirectErrorStream(true) + .start() + val gitOutBytes = ByteArrayOutputStream() + val gitOutFuture = redirect(gitProc.inputStream, gitOutBytes) + if (!gitProc.waitFor(10L, TimeUnit.SECONDS)) { + gitProc.destroyForcibly() + throw PaperweightException("Command '$gitQuery' did not finish after 10 seconds, killed process") + } + gitOutFuture.get(500L, TimeUnit.MILLISECONDS) + val gitOut = asString(gitOutBytes) + + if (out.contains("LongPathsEnabled REG_DWORD 0x1") && gitOut.contains("true")) { + return + } + val logger = Logging.getLogger("paperweight-path-length-warning") + logger.warn( + """paperweight uses long paths that may exceed the Windows MAX_PATH limit depending on where the project is located. +To avoid build failures and disable this warning, do one of the following: +1) Enable long paths in Windows and Git: + Windows documentation: https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation + Git command: git config --global core.longpaths true +2) Clone and build the project in WSL (this will also improve build speed) + +This warning can also be disabled by setting the gradle property 'paperweight.windowsLongPathWarning' to 'false'.""" + ) + } +} + private fun javaVersion(): Int { val version = System.getProperty("java.specification.version") val parts = version.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()