2014-11-26 16:56:48 +11:00
package org.spigotmc.builder ;
2018-08-30 09:55:21 +10:00
import com.google.common.base.Preconditions ;
2014-11-26 16:56:48 +11:00
import com.google.common.collect.Iterables ;
2017-11-09 10:46:32 +11:00
import com.google.common.collect.ObjectArrays ;
2019-03-25 21:30:02 +11:00
import com.google.common.hash.HashFunction ;
2014-11-26 16:56:48 +11:00
import com.google.common.hash.Hasher ;
import com.google.common.hash.Hashing ;
import com.google.common.io.ByteStreams ;
2015-01-13 10:11:24 +11:00
import com.google.common.io.CharStreams ;
2014-11-26 16:56:48 +11:00
import com.google.common.io.Files ;
import com.google.common.io.Resources ;
2015-01-13 10:11:24 +11:00
import com.google.gson.Gson ;
2022-11-09 19:27:47 +11:00
import com.google.gson.JsonArray ;
import com.google.gson.JsonElement ;
import com.google.gson.JsonObject ;
2014-11-26 16:56:48 +11:00
import difflib.DiffUtils ;
import difflib.Patch ;
2014-12-12 11:21:43 +11:00
import java.io.BufferedOutputStream ;
2014-11-26 16:56:48 +11:00
import java.io.BufferedReader ;
import java.io.BufferedWriter ;
import java.io.File ;
2014-12-12 11:21:43 +11:00
import java.io.FileDescriptor ;
import java.io.FileNotFoundException ;
2014-11-26 16:56:48 +11:00
import java.io.FileOutputStream ;
import java.io.FileWriter ;
import java.io.IOException ;
import java.io.InputStream ;
import java.io.InputStreamReader ;
import java.io.OutputStream ;
import java.io.PrintStream ;
2018-12-14 10:32:52 +11:00
import java.lang.management.ManagementFactory ;
2014-11-26 16:56:48 +11:00
import java.net.URL ;
2015-01-13 10:11:24 +11:00
import java.net.URLConnection ;
2024-02-05 19:20:12 +11:00
import java.nio.charset.StandardCharsets ;
2021-11-22 09:00:00 +11:00
import java.nio.file.FileSystem ;
2018-12-14 20:17:01 +11:00
import java.nio.file.FileSystemException ;
2021-11-22 09:00:00 +11:00
import java.nio.file.FileSystems ;
2021-03-16 09:00:00 +11:00
import java.nio.file.Path ;
2014-12-08 01:41:20 +02:00
import java.security.KeyManagementException ;
import java.security.NoSuchAlgorithmException ;
2014-12-12 11:21:43 +11:00
import java.security.SecureRandom ;
2014-12-08 01:41:20 +02:00
import java.security.cert.X509Certificate ;
2016-03-01 08:31:47 +11:00
import java.text.MessageFormat ;
2023-02-14 07:12:00 +11:00
import java.util.ArrayList ;
2014-12-06 09:12:53 +11:00
import java.util.Arrays ;
2019-12-21 10:33:33 +11:00
import java.util.Collections ;
2014-11-26 16:56:48 +11:00
import java.util.Date ;
2023-02-11 19:06:32 +11:00
import java.util.EnumSet ;
2014-11-26 16:56:48 +11:00
import java.util.Enumeration ;
2021-01-13 09:27:14 +11:00
import java.util.LinkedList ;
2014-11-26 16:56:48 +11:00
import java.util.List ;
2023-02-11 19:06:32 +11:00
import java.util.Set ;
2024-02-18 12:03:40 +11:00
import java.util.concurrent.TimeUnit ;
2020-06-21 09:42:35 +10:00
import java.util.function.Predicate ;
2021-11-22 09:00:00 +11:00
import java.util.jar.JarFile ;
2014-11-26 16:56:48 +11:00
import java.util.zip.ZipEntry ;
import java.util.zip.ZipFile ;
2014-12-08 01:41:20 +02:00
import javax.net.ssl.HttpsURLConnection ;
import javax.net.ssl.SSLContext ;
import javax.net.ssl.TrustManager ;
import javax.net.ssl.X509TrustManager ;
2015-02-23 09:32:50 +00:00
import joptsimple.OptionSet ;
2014-11-26 16:56:48 +11:00
import lombok.RequiredArgsConstructor ;
import org.apache.commons.io.FileUtils ;
2014-12-12 11:21:43 +11:00
import org.apache.commons.io.output.TeeOutputStream ;
2024-02-18 12:03:40 +11:00
import org.apache.commons.lang3.time.DurationFormatUtils ;
2014-11-26 16:56:48 +11:00
import org.eclipse.jgit.api.Git ;
import org.eclipse.jgit.api.ResetCommand ;
import org.eclipse.jgit.api.errors.GitAPIException ;
2018-12-18 17:04:10 +11:00
import org.eclipse.jgit.api.errors.JGitInternalException ;
2023-02-23 20:50:13 +11:00
import org.eclipse.jgit.lib.GpgConfig ;
2015-09-02 07:32:27 +10:00
import org.eclipse.jgit.lib.StoredConfig ;
2014-11-26 16:56:48 +11:00
import org.eclipse.jgit.revwalk.RevCommit ;
2020-07-06 18:18:00 +10:00
import org.eclipse.jgit.transport.FetchResult ;
2023-02-11 19:06:32 +11:00
import org.eclipse.jgit.transport.RefSpec ;
2021-06-11 15:00:00 +10:00
import org.spigotmc.mapper.MapUtil ;
2024-01-14 12:43:58 +11:00
import org.spigotmc.utils.Constants ;
2024-03-10 09:17:15 +11:00
import org.spigotmc.utils.Flags ;
2014-11-26 16:56:48 +11:00
public class Builder
{
2024-01-14 12:43:58 +11:00
public static File CWD = new File ( " . " ) ;
2024-02-05 19:20:12 +11:00
public static final String LOG_FILE = Constants . LOG_FILE ;
private static final boolean IS_WINDOWS = System . getProperty ( " os.name " ) . startsWith ( " Windows " ) ;
private static final boolean AUTOCRLF = ! " \ n " . equals ( System . getProperty ( " line.separator " ) ) ;
2014-12-12 11:07:46 +11:00
private static boolean dontUpdate ;
2019-12-21 10:33:33 +11:00
private static List < Compile > compile ;
2015-01-12 11:49:04 +11:00
private static boolean generateSource ;
private static boolean generateDocs ;
2015-01-13 10:11:24 +11:00
private static boolean dev ;
2021-06-11 15:00:00 +10:00
private static boolean remapped ;
2023-02-11 19:06:32 +11:00
private static List < PullRequest > pullRequests ;
2017-02-10 18:35:39 +11:00
private static String applyPatchesShell = " sh " ;
2020-07-06 18:18:00 +10:00
private static boolean didClone = false ;
2017-11-09 10:46:32 +11:00
//
2023-06-08 01:30:00 +10:00
private static BuildInfo buildInfo = BuildInfo . DEV ;
2021-01-13 09:27:14 +11:00
//
2017-11-09 10:46:32 +11:00
private static File msysDir ;
2021-01-13 09:27:14 +11:00
private static File maven ;
2014-11-26 16:56:48 +11:00
2024-03-10 09:17:15 +11:00
public static void startBuilder ( String [ ] args , OptionSet options ) throws Exception
2014-11-26 16:56:48 +11:00
{
2024-02-18 12:03:40 +11:00
long start = System . nanoTime ( ) ;
2024-01-14 12:43:58 +11:00
System . out . println ( Arrays . toString ( args ) ) ;
2020-02-01 17:44:27 +11:00
// May be null
String buildVersion = Builder . class . getPackage ( ) . getImplementationVersion ( ) ;
int buildNumber = - 1 ;
if ( buildVersion ! = null )
{
String [ ] split = buildVersion . split ( " - " ) ;
if ( split . length = = 4 )
{
try
{
buildNumber = Integer . parseInt ( split [ 3 ] ) ;
2024-02-05 19:20:12 +11:00
} catch ( NumberFormatException ignored )
2020-02-01 17:44:27 +11:00
{
}
}
}
System . out . println ( " Loading BuildTools version: " + buildVersion + " (# " + buildNumber + " ) " ) ;
System . out . println ( " Java Version: " + JavaVersion . getCurrentVersion ( ) ) ;
2024-02-05 19:20:12 +11:00
System . out . println ( " Current Path: " + CWD . getCanonicalPath ( ) ) ;
2020-02-01 17:44:27 +11:00
2019-04-23 16:38:24 +10:00
if ( CWD . getAbsolutePath ( ) . contains ( " ' " ) | | CWD . getAbsolutePath ( ) . contains ( " # " ) | | CWD . getAbsolutePath ( ) . contains ( " ~ " ) | | CWD . getAbsolutePath ( ) . contains ( " ( " ) | | CWD . getAbsolutePath ( ) . contains ( " ) " ) )
2016-03-26 15:58:22 +11:00
{
2024-01-14 12:43:58 +11:00
System . err . println ( Constants . SPECIAL_CHARACTERS_WARNING ) ;
2024-01-16 19:40:01 +11:00
System . exit ( 1 ) ;
2016-03-26 15:58:22 +11:00
}
2024-03-10 09:17:15 +11:00
if ( options . has ( Flags . HELP_FLAG ) )
{
Flags . PARSER . printHelpOn ( System . out ) ;
2019-03-17 12:40:22 +11:00
System . exit ( 0 ) ;
}
2024-03-10 09:17:15 +11:00
if ( options . has ( Flags . DISABLE_CERT_FLAG ) )
2014-12-12 11:07:46 +11:00
{
2015-02-23 09:32:50 +00:00
disableHttpsCertificateCheck ( ) ;
2014-12-08 01:41:20 +02:00
}
2024-03-10 09:17:15 +11:00
dontUpdate = options . has ( Flags . DONT_UPDATE_FLAG ) ;
generateSource = options . has ( Flags . GENERATE_SOURCE_FLAG ) ;
generateDocs = options . has ( Flags . GENERATE_DOCS_FLAG ) ;
dev = options . has ( Flags . DEV_FLAG ) ;
2023-06-08 01:30:00 +10:00
// Experimental implies dev but with different refs
2024-03-10 09:17:15 +11:00
if ( options . has ( Flags . EXPERIMENTAL_FLAG ) )
2023-06-08 01:30:00 +10:00
{
dev = true ;
buildInfo = BuildInfo . EXPERIMENTAL ;
}
2024-03-10 09:17:15 +11:00
remapped = options . has ( Flags . REMAPPED_FLAG ) ;
compile = options . valuesOf ( Flags . TO_COMPILE_FLAG ) ;
pullRequests = options . valuesOf ( Flags . BUILD_PULL_REQUEST_FLAG ) ;
2023-02-11 19:06:32 +11:00
validatedPullRequestsOptions ( ) ;
2024-03-10 09:17:15 +11:00
if ( options . has ( Flags . SKIP_COMPILE_FLAG ) )
2019-12-21 10:33:33 +11:00
{
compile = Collections . singletonList ( Compile . NONE ) ;
System . err . println ( " --skip-compile is deprecated, please use --compile NONE " ) ;
}
2024-03-10 09:17:15 +11:00
if ( ( dev | | dontUpdate ) & & options . has ( Flags . JENKINS_VERSION_FLAG ) )
2020-01-10 09:19:40 +11:00
{
System . err . println ( " Using --dev or --dont-update with --rev makes no sense, exiting. " ) ;
System . exit ( 1 ) ;
}
2023-02-14 07:12:00 +11:00
if ( compile . isEmpty ( ) & & ! pullRequests . isEmpty ( ) )
{
compile = new ArrayList < > ( ) ;
if ( getPullRequest ( Repository . BUKKIT ) ! = null | | getPullRequest ( Repository . CRAFTBUKKIT ) ! = null )
{
compile . add ( Compile . CRAFTBUKKIT ) ;
}
if ( getPullRequest ( Repository . SPIGOT ) ! = null )
{
compile . add ( Compile . SPIGOT ) ;
}
}
2014-12-12 11:21:43 +11:00
2017-01-30 08:35:51 +11:00
try
2014-11-26 16:56:48 +11:00
{
2017-01-30 08:35:51 +11:00
runProcess ( CWD , " sh " , " -c " , " exit " ) ;
} catch ( Exception ex )
{
2017-11-09 10:46:32 +11:00
if ( IS_WINDOWS )
{
2021-01-13 10:10:20 +11:00
String gitVersion = " PortableGit-2.30.0- " + ( System . getProperty ( " os.arch " ) . endsWith ( " 64 " ) ? " 64 " : " 32 " ) + " -bit " ;
// https://github.com/git-for-windows/git/releases/tag/v2.30.0.windows.1
String gitHash = System . getProperty ( " os.arch " ) . endsWith ( " 64 " ) ? " 6497e30fc6141e3c27af6cc3a081861043a7666dd54f395d47184e8eb75f5d61 " : " b3768c64b6afa082043659c56acb4c3483df6b6e884fdc7e3c769f7e7e99a3a8 " ;
2017-11-09 10:46:32 +11:00
msysDir = new File ( gitVersion , " PortableGit " ) ;
if ( ! msysDir . isDirectory ( ) )
{
System . out . println ( " *** Could not find PortableGit installation, downloading. *** " ) ;
String gitName = gitVersion + " .7z.exe " ;
File gitInstall = new File ( gitVersion , gitName ) ;
2019-03-25 21:30:02 +11:00
gitInstall . deleteOnExit ( ) ;
2017-11-09 10:46:32 +11:00
gitInstall . getParentFile ( ) . mkdirs ( ) ;
if ( ! gitInstall . exists ( ) )
{
2021-01-13 10:10:20 +11:00
download ( " https://github.com/git-for-windows/git/releases/download/v2.30.0.windows.1/ " + gitName , gitInstall , HashFormat . SHA256 , gitHash ) ;
2017-11-09 10:46:32 +11:00
}
System . out . println ( " Extracting downloaded git install " ) ;
// yes to all, silent, don't run. Only -y seems to work
runProcess ( gitInstall . getParentFile ( ) , gitInstall . getAbsolutePath ( ) , " -y " , " -gm2 " , " -nr " ) ;
gitInstall . delete ( ) ;
}
System . out . println ( " *** Using downloaded git " + msysDir + " *** " ) ;
System . out . println ( " *** Please note that this is a beta feature, so if it does not work please also try a manual install of git from https://git-for-windows.github.io/ *** " ) ;
} else
{
System . out . println ( " You must run this jar through bash (msysgit) " ) ;
System . exit ( 1 ) ;
}
2014-11-26 16:56:48 +11:00
}
2019-08-09 20:21:30 +10:00
try
{
runProcess ( CWD , " git " , " --version " ) ;
} catch ( Exception ex )
{
System . out . println ( " Could not successfully run git. Please ensure it is installed and functioning. " + ex . getMessage ( ) ) ;
System . exit ( 1 ) ;
}
2018-01-23 22:41:49 +11:00
2022-01-07 17:45:45 +11:00
try
{
runProcess ( CWD , " java " , " -version " ) ;
} catch ( Exception ex )
{
System . out . println ( " Could not successfully run Java. " + ex . getMessage ( ) ) ;
System . exit ( 1 ) ;
}
2022-01-07 17:43:37 +11:00
if ( ! dontUpdate & & ! dev )
{
2024-03-10 09:17:15 +11:00
String askedVersion = options . valueOf ( Flags . JENKINS_VERSION_FLAG ) ;
2022-01-07 17:43:37 +11:00
System . out . println ( " Attempting to build version: ' " + askedVersion + " ' use --rev <version> to override " ) ;
String verInfo ;
try
{
verInfo = get ( " https://hub.spigotmc.org/versions/ " + askedVersion + " .json " ) ;
} catch ( IOException ex )
{
System . err . println ( " Could not get version " + askedVersion + " does it exist? Try another version or use 'latest' " ) ;
ex . printStackTrace ( ) ;
System . exit ( 1 ) ;
return ;
}
System . out . println ( " Found version " ) ;
System . out . println ( verInfo ) ;
buildInfo = new Gson ( ) . fromJson ( verInfo , BuildInfo . class ) ;
if ( buildNumber ! = - 1 & & buildInfo . getToolsVersion ( ) ! = - 1 & & buildNumber < buildInfo . getToolsVersion ( ) )
{
System . err . println ( " **** Your BuildTools is out of date and will not build the requested version. Please grab a new copy from https://www.spigotmc.org/go/buildtools-dl " ) ;
System . exit ( 1 ) ;
}
2024-03-10 09:17:15 +11:00
if ( ! options . has ( Flags . DISABLE_JAVA_CHECK_FLAG ) )
2022-01-07 17:43:37 +11:00
{
if ( buildInfo . getJavaVersions ( ) = = null )
{
buildInfo . setJavaVersions ( new int [ ]
{
JavaVersion . JAVA_7 . getVersion ( ) , JavaVersion . JAVA_8 . getVersion ( )
} ) ;
}
Preconditions . checkArgument ( buildInfo . getJavaVersions ( ) . length = = 2 , " Expected only two Java versions, got %s " , JavaVersion . printVersions ( buildInfo . getJavaVersions ( ) ) ) ;
JavaVersion curVersion = JavaVersion . getCurrentVersion ( ) ;
JavaVersion minVersion = JavaVersion . getByVersion ( buildInfo . getJavaVersions ( ) [ 0 ] ) ;
JavaVersion maxVersion = JavaVersion . getByVersion ( buildInfo . getJavaVersions ( ) [ 1 ] ) ;
if ( curVersion . getVersion ( ) < minVersion . getVersion ( ) | | curVersion . getVersion ( ) > maxVersion . getVersion ( ) )
{
System . err . println ( " *** The version you have requested to build requires Java versions between " + JavaVersion . printVersions ( buildInfo . getJavaVersions ( ) ) + " , but you are using " + curVersion ) ;
System . err . println ( " *** Please rerun BuildTools using an appropriate Java version. For obvious reasons outdated MC versions do not support Java versions that did not exist at their release. " ) ;
System . exit ( 1 ) ;
}
}
}
2014-11-26 16:56:48 +11:00
File workDir = new File ( " work " ) ;
workDir . mkdir ( ) ;
File bukkit = new File ( " Bukkit " ) ;
2020-07-06 18:18:00 +10:00
if ( ! bukkit . exists ( ) | | ! containsGit ( bukkit ) )
2014-11-26 16:56:48 +11:00
{
clone ( " https://hub.spigotmc.org/stash/scm/spigot/bukkit.git " , bukkit ) ;
}
File craftBukkit = new File ( " CraftBukkit " ) ;
2020-07-06 18:18:00 +10:00
if ( ! craftBukkit . exists ( ) | | ! containsGit ( craftBukkit ) )
2014-11-26 16:56:48 +11:00
{
clone ( " https://hub.spigotmc.org/stash/scm/spigot/craftbukkit.git " , craftBukkit ) ;
}
File spigot = new File ( " Spigot " ) ;
2020-07-06 18:18:00 +10:00
if ( ! spigot . exists ( ) | | ! containsGit ( spigot ) )
2014-11-26 16:56:48 +11:00
{
clone ( " https://hub.spigotmc.org/stash/scm/spigot/spigot.git " , spigot ) ;
}
File buildData = new File ( " BuildData " ) ;
2020-07-06 18:18:00 +10:00
if ( ! buildData . exists ( ) | | ! containsGit ( buildData ) )
2014-11-26 16:56:48 +11:00
{
clone ( " https://hub.spigotmc.org/stash/scm/spigot/builddata.git " , buildData ) ;
}
2015-06-10 16:21:17 +01:00
String m2Home = System . getenv ( " M2_HOME " ) ;
2015-07-29 19:54:14 +10:00
if ( m2Home = = null | | ! ( maven = new File ( m2Home ) ) . exists ( ) )
2014-11-26 16:56:48 +11:00
{
2024-02-18 09:26:09 +11:00
maven = new File ( Constants . MAVEN_FOLDER ) ;
2014-11-26 16:56:48 +11:00
2015-06-10 19:53:41 +10:00
if ( ! maven . exists ( ) )
{
System . out . println ( " Maven does not exist, downloading. Please wait. " ) ;
2024-02-18 09:26:09 +11:00
File mvnTemp = new File ( Constants . MAVEN_FILE ) ;
2015-06-10 19:53:41 +10:00
mvnTemp . deleteOnExit ( ) ;
2014-11-26 16:56:48 +11:00
2024-02-18 09:26:09 +11:00
download ( Constants . MAVEN_DOWNLOAD , mvnTemp , HashFormat . SHA512 , Constants . MAVEN_HASH ) ;
2015-06-10 19:53:41 +10:00
unzip ( mvnTemp , new File ( " . " ) ) ;
2019-03-25 21:30:02 +11:00
mvnTemp . delete ( ) ;
2015-06-10 19:53:41 +10:00
}
2014-11-26 16:56:48 +11:00
}
Git bukkitGit = Git . open ( bukkit ) ;
Git craftBukkitGit = Git . open ( craftBukkit ) ;
Git spigotGit = Git . open ( spigot ) ;
Git buildGit = Git . open ( buildData ) ;
2014-12-12 11:07:46 +11:00
if ( ! dontUpdate )
{
2023-02-11 19:06:32 +11:00
boolean buildDataChanged = pull ( buildGit , buildInfo . getRefs ( ) . getBuildData ( ) , null ) ;
boolean bukkitChanged = pull ( bukkitGit , buildInfo . getRefs ( ) . getBukkit ( ) , getPullRequest ( Repository . BUKKIT ) ) ;
boolean craftBukkitChanged = pull ( craftBukkitGit , buildInfo . getRefs ( ) . getCraftBukkit ( ) , getPullRequest ( Repository . CRAFTBUKKIT ) ) ;
boolean spigotChanged = pull ( spigotGit , buildInfo . getRefs ( ) . getSpigot ( ) , getPullRequest ( Repository . SPIGOT ) ) ;
2020-07-06 18:18:00 +10:00
// Checks if any of the 4 repositories have been updated via a fetch, the --compile-if-changed flag is set and none of the repositories were cloned in this run.
2024-03-10 09:17:15 +11:00
if ( ! buildDataChanged & & ! bukkitChanged & & ! craftBukkitChanged & & ! spigotChanged & & options . has ( Flags . COMPILE_IF_CHANGED_FLAG ) & & ! didClone )
2020-07-06 18:18:00 +10:00
{
System . out . println ( " *** No changes detected in any of the repositories! " ) ;
2024-01-14 12:43:58 +11:00
System . out . println ( " *** Exiting due to the --compile-if-changed " ) ;
System . exit ( 2 ) ;
2020-07-06 18:18:00 +10:00
}
2014-12-12 11:07:46 +11:00
}
2014-11-26 16:56:48 +11:00
2015-02-27 16:27:23 +11:00
VersionInfo versionInfo = new Gson ( ) . fromJson (
2024-02-05 19:20:12 +11:00
Files . asCharSource ( new File ( " BuildData/info.json " ) , StandardCharsets . UTF_8 ) . read ( ) ,
2015-02-27 16:27:23 +11:00
VersionInfo . class
) ;
// Default to 1.8 builds.
if ( versionInfo = = null )
{
2015-07-29 19:54:14 +10:00
versionInfo = new VersionInfo ( " 1.8 " , " bukkit-1.8.at " , " bukkit-1.8-cl.csrg " , " bukkit-1.8-members.csrg " , " package.srg " , null ) ;
2015-02-27 16:27:23 +11:00
}
System . out . println ( " Attempting to build Minecraft with details: " + versionInfo ) ;
2018-12-13 11:00:00 +11:00
if ( buildNumber ! = - 1 & & versionInfo . getToolsVersion ( ) ! = - 1 & & buildNumber < versionInfo . getToolsVersion ( ) )
{
System . err . println ( " " ) ;
System . err . println ( " **** Your BuildTools is out of date and will not build the requested version. Please grab a new copy from https://www.spigotmc.org/go/buildtools-dl " ) ;
System . exit ( 1 ) ;
}
2015-02-27 16:27:23 +11:00
File vanillaJar = new File ( workDir , " minecraft_server. " + versionInfo . getMinecraftVersion ( ) + " .jar " ) ;
2021-11-22 09:00:00 +11:00
File embeddedVanillaJar = new File ( workDir , " server- " + versionInfo . getMinecraftVersion ( ) + " .jar " ) ;
if ( ! checkHash ( vanillaJar , versionInfo ) )
2014-11-26 16:56:48 +11:00
{
2017-02-10 18:35:39 +11:00
if ( versionInfo . getServerUrl ( ) ! = null )
{
2019-03-25 21:30:02 +11:00
download ( versionInfo . getServerUrl ( ) , vanillaJar , HashFormat . MD5 , versionInfo . getMinecraftHash ( ) ) ;
2017-02-10 18:35:39 +11:00
} else
{
2022-11-09 19:27:47 +11:00
download ( getServerVanillaUrl ( versionInfo . getMinecraftVersion ( ) ) , vanillaJar , HashFormat . MD5 , versionInfo . getMinecraftHash ( ) ) ;
2020-01-29 13:06:20 +11:00
}
}
2017-02-10 18:35:39 +11:00
2021-11-22 09:00:00 +11:00
try ( JarFile jar = new JarFile ( vanillaJar ) )
{
ZipEntry entry = jar . getEntry ( " META-INF/versions/ " + versionInfo . getMinecraftVersion ( ) + " /server- " + versionInfo . getMinecraftVersion ( ) + " .jar " ) ;
if ( entry ! = null )
{
if ( ! checkHash ( embeddedVanillaJar , HashFormat . SHA256 , versionInfo . getMinecraftHash ( ) ) )
{
try ( InputStream is = jar . getInputStream ( entry ) )
{
byte [ ] embedded = ByteStreams . toByteArray ( is ) ;
if ( embedded ! = null )
{
Files . write ( embedded , embeddedVanillaJar ) ;
}
}
try ( FileSystem zipfs = FileSystems . newFileSystem ( embeddedVanillaJar . toPath ( ) , ( ClassLoader ) null ) )
{
java . nio . file . Files . delete ( zipfs . getPath ( " /META-INF/MOJANGCS.RSA " ) ) ;
java . nio . file . Files . delete ( zipfs . getPath ( " /META-INF/MOJANGCS.SF " ) ) ;
}
}
vanillaJar = embeddedVanillaJar ;
}
}
2020-01-29 13:06:20 +11:00
if ( versionInfo . getServerUrl ( ) = = null )
{
// Legacy versions can also specify a specific shell to build with which has to be bash-compatible
applyPatchesShell = System . getenv ( ) . get ( " SHELL " ) ;
if ( applyPatchesShell = = null | | applyPatchesShell . trim ( ) . isEmpty ( ) )
{
applyPatchesShell = " bash " ;
2017-02-10 18:35:39 +11:00
}
2014-11-26 16:56:48 +11:00
}
Iterable < RevCommit > mappings = buildGit . log ( )
2019-04-11 09:17:32 +10:00
. addPath ( " mappings/ " )
2014-11-26 16:56:48 +11:00
. setMaxCount ( 1 ) . call ( ) ;
2020-06-21 09:42:35 +10:00
Hasher mappingsHash = HashFormat . MD5 . getHash ( ) . newHasher ( ) ;
2014-11-26 16:56:48 +11:00
for ( RevCommit rev : mappings )
{
2024-02-05 19:20:12 +11:00
mappingsHash . putString ( rev . getName ( ) , StandardCharsets . UTF_8 ) ;
2014-11-26 16:56:48 +11:00
}
String mappingsVersion = mappingsHash . hash ( ) . toString ( ) . substring ( 24 ) ; // Last 8 chars
File finalMappedJar = new File ( workDir , " mapped. " + mappingsVersion + " .jar " ) ;
if ( ! finalMappedJar . exists ( ) )
{
2018-11-24 10:03:35 +11:00
System . out . println ( " Final mapped jar: " + finalMappedJar + " does not exist, creating (please wait)! " ) ;
2014-11-26 16:56:48 +11:00
2021-06-11 15:00:00 +10:00
File classMappings = new File ( " BuildData/mappings/ " + versionInfo . getClassMappings ( ) ) ;
File memberMappings = new File ( " BuildData/mappings/ " + versionInfo . getMemberMappings ( ) ) ;
File fieldMappings = new File ( workDir , " bukkit- " + mappingsVersion + " -fields.csrg " ) ;
if ( versionInfo . getMappingsUrl ( ) ! = null )
{
File mojangMappings = new File ( workDir , " minecraft_server. " + versionInfo . getMinecraftVersion ( ) + " .txt " ) ;
if ( ! mojangMappings . exists ( ) )
{
download ( versionInfo . getMappingsUrl ( ) , mojangMappings ) ;
}
MapUtil mapUtil = new MapUtil ( ) ;
mapUtil . loadBuk ( classMappings ) ;
2021-11-22 09:00:00 +11:00
if ( ! memberMappings . exists ( ) )
2021-06-11 15:00:00 +10:00
{
2021-11-23 11:17:18 +11:00
memberMappings = new File ( workDir , " bukkit- " + mappingsVersion + " -members.csrg " ) ;
2021-11-22 09:00:00 +11:00
mapUtil . makeFieldMaps ( mojangMappings , memberMappings , true ) ;
2021-12-04 09:11:31 +11:00
} else if ( ! fieldMappings . exists ( ) )
{
mapUtil . makeFieldMaps ( mojangMappings , fieldMappings , false ) ;
}
2021-06-11 15:00:00 +10:00
2021-12-04 09:17:12 +11:00
// 1.17+
2021-12-04 09:11:31 +11:00
if ( memberMappings . exists ( ) )
{
2022-12-29 21:09:49 +11:00
runMavenInstall ( CWD , " install:install-file " , " -Dfile= " + memberMappings , " -Dpackaging=csrg " , " -DgroupId=org.spigotmc " ,
2021-11-22 09:00:00 +11:00
" -DartifactId=minecraft-server " , " -Dversion= " + versionInfo . getSpigotVersion ( ) , " -Dclassifier=maps-spigot-members " , " -DgeneratePom=false " ) ;
2021-12-04 09:11:31 +11:00
}
2021-11-22 09:00:00 +11:00
2021-12-04 09:11:31 +11:00
// 1.17
if ( fieldMappings . exists ( ) )
{
2022-12-29 21:09:49 +11:00
runMavenInstall ( CWD , " install:install-file " , " -Dfile= " + fieldMappings , " -Dpackaging=csrg " , " -DgroupId=org.spigotmc " ,
2021-11-22 09:00:00 +11:00
" -DartifactId=minecraft-server " , " -Dversion= " + versionInfo . getSpigotVersion ( ) , " -Dclassifier=maps-spigot-fields " , " -DgeneratePom=false " ) ;
2021-06-11 15:00:00 +10:00
2021-11-22 09:00:00 +11:00
File combinedMappings = new File ( workDir , " bukkit- " + mappingsVersion + " -combined.csrg " ) ;
if ( ! combinedMappings . exists ( ) )
{
mapUtil . makeCombinedMaps ( combinedMappings , memberMappings ) ;
}
2022-12-29 21:09:49 +11:00
runMavenInstall ( CWD , " install:install-file " , " -Dfile= " + combinedMappings , " -Dpackaging=csrg " , " -DgroupId=org.spigotmc " ,
2021-11-22 09:00:00 +11:00
" -DartifactId=minecraft-server " , " -Dversion= " + versionInfo . getSpigotVersion ( ) , " -Dclassifier=maps-spigot " , " -DgeneratePom=false " ) ;
2021-12-04 09:17:12 +11:00
} else
{
// 1.18+
2022-12-29 21:09:49 +11:00
runMavenInstall ( CWD , " install:install-file " , " -Dfile= " + classMappings , " -Dpackaging=csrg " , " -DgroupId=org.spigotmc " ,
2021-12-04 09:17:12 +11:00
" -DartifactId=minecraft-server " , " -Dversion= " + versionInfo . getSpigotVersion ( ) , " -Dclassifier=maps-spigot " , " -DgeneratePom=false " ) ;
2021-11-22 09:00:00 +11:00
}
2021-06-11 15:00:00 +10:00
2021-12-04 09:11:31 +11:00
// 1.17+
2022-12-29 21:09:49 +11:00
runMavenInstall ( CWD , " install:install-file " , " -Dfile= " + mojangMappings , " -Dpackaging=txt " , " -DgroupId=org.spigotmc " ,
2021-07-03 09:29:40 +10:00
" -DartifactId=minecraft-server " , " -Dversion= " + versionInfo . getSpigotVersion ( ) , " -Dclassifier=maps-mojang " , " -DgeneratePom=false " ) ;
2021-06-11 15:00:00 +10:00
}
2014-11-26 16:56:48 +11:00
File clMappedJar = new File ( finalMappedJar + " -cl " ) ;
File mMappedJar = new File ( finalMappedJar + " -m " ) ;
2018-12-13 11:00:00 +11:00
if ( versionInfo . getClassMapCommand ( ) = = null )
{
versionInfo . setClassMapCommand ( " java -jar BuildData/bin/SpecialSource-2.jar map -i {0} -m {1} -o {2} " ) ;
}
2021-06-11 15:00:00 +10:00
runProcess ( CWD , MessageFormat . format ( versionInfo . getClassMapCommand ( ) , vanillaJar . getPath ( ) , classMappings . getPath ( ) , clMappedJar . getPath ( ) ) . split ( " " ) ) ;
2014-12-06 09:12:53 +11:00
2018-12-13 11:00:00 +11:00
if ( versionInfo . getMemberMapCommand ( ) = = null )
{
versionInfo . setMemberMapCommand ( " java -jar BuildData/bin/SpecialSource-2.jar map -i {0} -m {1} -o {2} " ) ;
}
runProcess ( CWD , MessageFormat . format ( versionInfo . getMemberMapCommand ( ) , clMappedJar . getPath ( ) ,
2021-06-11 15:00:00 +10:00
memberMappings . getPath ( ) , mMappedJar . getPath ( ) ) . split ( " " ) ) ;
2014-12-06 09:12:53 +11:00
2018-12-13 11:00:00 +11:00
if ( versionInfo . getFinalMapCommand ( ) = = null )
{
2018-12-14 19:31:53 +11:00
versionInfo . setFinalMapCommand ( " java -jar BuildData/bin/SpecialSource.jar --kill-lvt -i {0} --access-transformer {1} -m {2} -o {3} " ) ;
2018-12-13 11:00:00 +11:00
}
runProcess ( CWD , MessageFormat . format ( versionInfo . getFinalMapCommand ( ) , mMappedJar . getPath ( ) , " BuildData/mappings/ " + versionInfo . getAccessTransforms ( ) ,
2021-06-11 15:00:00 +10:00
( versionInfo . getPackageMappings ( ) = = null ) ? fieldMappings . getPath ( ) : " BuildData/mappings/ " + versionInfo . getPackageMappings ( ) , finalMappedJar . getPath ( ) ) . split ( " " ) ) ;
2014-11-26 16:56:48 +11:00
}
2022-12-29 21:09:49 +11:00
runMavenInstall ( CWD , " install:install-file " , " -Dfile= " + finalMappedJar , " -Dpackaging=jar " , " -DgroupId=org.spigotmc " ,
2021-06-11 15:00:00 +10:00
" -DartifactId=minecraft-server " , " -Dversion= " + ( versionInfo . getSpigotVersion ( ) ! = null ? versionInfo . getSpigotVersion ( ) : versionInfo . getMinecraftVersion ( ) + " -SNAPSHOT " ) ) ;
2014-11-26 16:56:48 +11:00
File decompileDir = new File ( workDir , " decompile- " + mappingsVersion ) ;
if ( ! decompileDir . exists ( ) )
{
decompileDir . mkdir ( ) ;
File clazzDir = new File ( decompileDir , " classes " ) ;
2021-11-23 11:17:18 +11:00
unzip ( finalMappedJar , clazzDir , ( input ) - > input . startsWith ( " net/minecraft " ) ) ;
2016-03-01 09:50:21 +11:00
if ( versionInfo . getDecompileCommand ( ) = = null )
{
versionInfo . setDecompileCommand ( " java -jar BuildData/bin/fernflower.jar -dgs=1 -hdc=0 -rbr=0 -asc=1 -udv=0 {0} {1} " ) ;
}
2014-11-26 16:56:48 +11:00
2016-03-01 09:50:21 +11:00
runProcess ( CWD , MessageFormat . format ( versionInfo . getDecompileCommand ( ) , clazzDir . getPath ( ) , decompileDir . getPath ( ) ) . split ( " " ) ) ;
2014-11-26 16:56:48 +11:00
}
2018-12-14 19:57:43 +11:00
try
{
File latestLink = new File ( workDir , " decompile-latest " ) ;
latestLink . delete ( ) ;
java . nio . file . Files . createSymbolicLink ( latestLink . toPath ( ) , decompileDir . getParentFile ( ) . toPath ( ) . relativize ( decompileDir . toPath ( ) ) ) ;
} catch ( UnsupportedOperationException ex )
{
2018-12-14 20:17:01 +11:00
// Ignore if not possible
} catch ( FileSystemException ex )
{
// Not running as admin on Windows
2018-12-14 19:57:43 +11:00
} catch ( IOException ex )
{
2018-12-14 20:17:01 +11:00
System . out . println ( " Did not create decompile-latest link " + ex . getMessage ( ) ) ;
2018-12-14 19:57:43 +11:00
}
2014-11-26 16:56:48 +11:00
System . out . println ( " Applying CraftBukkit Patches " ) ;
File nmsDir = new File ( craftBukkit , " src/main/java/net " ) ;
if ( nmsDir . exists ( ) )
{
System . out . println ( " Backing up NMS dir " ) ;
FileUtils . moveDirectory ( nmsDir , new File ( workDir , " nms.old. " + System . currentTimeMillis ( ) ) ) ;
}
2021-03-16 09:00:00 +11:00
Path patchDir = new File ( craftBukkit , " nms-patches " ) . toPath ( ) ;
java . nio . file . Files . walk ( patchDir ) . filter ( java . nio . file . Files : : isRegularFile ) . forEach ( ( path ) - >
2014-11-26 16:56:48 +11:00
{
2021-03-16 09:00:00 +11:00
File file = path . toFile ( ) ;
2017-10-19 21:01:43 +11:00
if ( ! file . getName ( ) . endsWith ( " .patch " ) )
{
2021-03-16 09:00:00 +11:00
return ;
2017-10-19 21:01:43 +11:00
}
2021-03-16 09:00:00 +11:00
String relativeName = patchDir . relativize ( path ) . toString ( ) . replace ( " .patch " , " .java " ) ;
String targetFile = ( relativeName . contains ( File . separator ) ) ? relativeName : " net/minecraft/server/ " + relativeName ;
2014-11-26 16:56:48 +11:00
File clean = new File ( decompileDir , targetFile ) ;
File t = new File ( nmsDir . getParentFile ( ) , targetFile ) ;
t . getParentFile ( ) . mkdirs ( ) ;
2021-03-16 09:00:00 +11:00
System . out . println ( " Patching " + relativeName ) ;
2014-11-26 16:56:48 +11:00
2021-03-16 09:00:00 +11:00
try
2014-12-24 09:32:10 +11:00
{
2024-02-05 19:20:12 +11:00
List < String > readFile = Files . readLines ( file , StandardCharsets . UTF_8 ) ;
2021-03-16 09:00:00 +11:00
// Manually append prelude if it is not found in the first few lines.
boolean preludeFound = false ;
for ( int i = 0 ; i < Math . min ( 3 , readFile . size ( ) ) ; i + + )
2014-12-24 09:32:10 +11:00
{
2021-03-16 09:00:00 +11:00
if ( readFile . get ( i ) . startsWith ( " +++ " ) )
{
preludeFound = true ;
break ;
}
}
if ( ! preludeFound )
{
readFile . add ( 0 , " +++ " ) ;
2014-12-24 09:32:10 +11:00
}
2021-03-16 09:00:00 +11:00
Patch parsedPatch = DiffUtils . parseUnifiedDiff ( readFile ) ;
2024-02-05 19:20:12 +11:00
List < ? > modifiedLines = DiffUtils . patch ( Files . readLines ( clean , StandardCharsets . UTF_8 ) , parsedPatch ) ;
2014-11-26 16:56:48 +11:00
2021-11-23 11:17:18 +11:00
try ( BufferedWriter bw = new BufferedWriter ( new FileWriter ( t ) ) )
2021-03-16 09:00:00 +11:00
{
2021-11-23 11:17:18 +11:00
for ( Object line : modifiedLines )
{
bw . write ( ( String ) line ) ;
bw . newLine ( ) ;
}
2021-03-16 09:00:00 +11:00
}
} catch ( Exception ex )
2014-11-26 16:56:48 +11:00
{
2021-03-16 09:00:00 +11:00
throw new RuntimeException ( " Error patching " + relativeName , ex ) ;
2014-11-26 16:56:48 +11:00
}
2021-03-16 09:00:00 +11:00
} ) ;
2014-11-26 16:56:48 +11:00
File tmpNms = new File ( craftBukkit , " tmp-nms " ) ;
FileUtils . copyDirectory ( nmsDir , tmpNms ) ;
craftBukkitGit . branchDelete ( ) . setBranchNames ( " patched " ) . setForce ( true ) . call ( ) ;
2020-06-21 09:42:35 +10:00
craftBukkitGit . checkout ( ) . setCreateBranch ( true ) . setForceRefUpdate ( true ) . setName ( " patched " ) . call ( ) ;
2014-11-26 16:56:48 +11:00
craftBukkitGit . add ( ) . addFilepattern ( " src/main/java/net/ " ) . call ( ) ;
2023-02-23 20:50:13 +11:00
craftBukkitGit . commit ( ) . setGpgConfig ( new GpgConfig ( null , null , null ) ) . setSign ( false ) . setMessage ( " CraftBukkit $ " + new Date ( ) ) . call ( ) ;
2023-02-11 19:06:32 +11:00
PullRequest craftBukkitPullRequest = getPullRequest ( Repository . CRAFTBUKKIT ) ;
craftBukkitGit . checkout ( ) . setName ( ( craftBukkitPullRequest = = null ) ? buildInfo . getRefs ( ) . getCraftBukkit ( ) : " origin/pr/ " + craftBukkitPullRequest . getId ( ) ) . call ( ) ;
2014-11-26 16:56:48 +11:00
FileUtils . moveDirectory ( tmpNms , nmsDir ) ;
2019-04-11 08:59:05 +10:00
if ( versionInfo . getToolsVersion ( ) < 93 )
2014-11-26 16:56:48 +11:00
{
2019-04-11 08:59:05 +10:00
File spigotApi = new File ( spigot , " Bukkit " ) ;
if ( ! spigotApi . exists ( ) )
{
clone ( " file:// " + bukkit . getAbsolutePath ( ) , spigotApi ) ;
}
File spigotServer = new File ( spigot , " CraftBukkit " ) ;
if ( ! spigotServer . exists ( ) )
{
clone ( " file:// " + craftBukkit . getAbsolutePath ( ) , spigotServer ) ;
}
2014-11-26 16:56:48 +11:00
}
// Git spigotApiGit = Git.open( spigotApi );
// Git spigotServerGit = Git.open( spigotServer );
2019-12-21 10:33:33 +11:00
if ( compile = = null | | compile . isEmpty ( ) )
{
2024-02-18 09:09:34 +11:00
if ( dev )
2019-12-21 10:33:33 +11:00
{
compile = Arrays . asList ( Compile . CRAFTBUKKIT , Compile . SPIGOT ) ;
} else
{
compile = Collections . singletonList ( Compile . SPIGOT ) ;
}
}
if ( compile . contains ( Compile . CRAFTBUKKIT ) )
2014-12-12 11:25:00 +11:00
{
System . out . println ( " Compiling Bukkit " ) ;
2022-12-29 21:09:49 +11:00
runMavenAPI ( bukkit , " clean " , " install " ) ;
2015-01-12 11:49:04 +11:00
if ( generateDocs )
{
2022-12-29 21:09:49 +11:00
runMavenAPI ( bukkit , " javadoc:jar " ) ;
2015-01-12 11:49:04 +11:00
}
if ( generateSource )
{
2022-12-29 21:09:49 +11:00
runMavenAPI ( bukkit , " source:jar " ) ;
2015-01-12 11:49:04 +11:00
}
2014-11-26 16:56:48 +11:00
2014-12-12 11:25:00 +11:00
System . out . println ( " Compiling CraftBukkit " ) ;
2022-12-29 21:09:49 +11:00
runMavenServer ( craftBukkit , " clean " , " install " ) ;
2014-12-12 11:25:00 +11:00
}
2014-11-26 16:56:48 +11:00
try
{
2019-12-21 10:33:33 +11:00
if ( compile . contains ( Compile . SPIGOT ) )
2014-12-12 11:25:00 +11:00
{
2023-02-11 19:06:33 +11:00
runProcess ( spigot , applyPatchesShell , " applyPatches.sh " ) ;
System . out . println ( " *** Spigot patches applied! " ) ;
2015-05-24 15:56:49 +01:00
System . out . println ( " Compiling Spigot & Spigot-API " ) ;
2022-12-29 21:09:49 +11:00
runMavenServer ( spigot , " clean " , " install " ) ;
2021-11-22 11:40:32 +11:00
File spigotApi = new File ( spigot , " Spigot-API " ) ;
if ( generateDocs )
{
2022-12-29 21:09:49 +11:00
runMavenAPI ( spigotApi , " javadoc:jar " ) ;
2021-11-22 11:40:32 +11:00
}
if ( generateSource )
{
2022-12-29 21:09:49 +11:00
runMavenAPI ( spigotApi , " source:jar " ) ;
2021-11-22 11:40:32 +11:00
}
2014-12-12 11:25:00 +11:00
}
2014-11-26 16:56:48 +11:00
} catch ( Exception ex )
{
2016-03-01 19:09:59 +11:00
System . err . println ( " Error compiling Spigot. Please check the wiki for FAQs. " ) ;
2024-01-14 12:43:58 +11:00
System . err . println ( " If this does not resolve your issue then please pastebin the entire " + LOG_FILE + " file when seeking support. " ) ;
2014-11-26 16:56:48 +11:00
ex . printStackTrace ( ) ;
2014-11-29 10:49:54 +11:00
System . exit ( 1 ) ;
2014-11-26 16:56:48 +11:00
}
2014-12-07 00:35:01 -05:00
2014-12-12 11:21:43 +11:00
for ( int i = 0 ; i < 35 ; i + + )
{
System . out . println ( " " ) ;
}
2015-04-26 13:10:19 -05:00
2024-02-18 12:03:40 +11:00
long end = System . nanoTime ( ) ;
long duration = TimeUnit . NANOSECONDS . toMillis ( end - start ) ;
if ( duration / 1000F > = 60 )
{
System . out . println ( " Total Time: " + DurationFormatUtils . formatDurationWords ( duration , true , true ) ) ;
} else
{
System . out . println ( " Total Time: " + DurationFormatUtils . formatDuration ( duration , " s.SS' seconds' " ) ) ;
}
System . out . println ( ) ;
2019-12-21 10:33:33 +11:00
System . out . println ( " Success! Everything completed successfully. Copying final .jar files now. " ) ;
2021-06-11 15:00:00 +10:00
2024-01-14 12:43:58 +11:00
String fileExtension = " .jar " ;
String snapshot = " -SNAPSHOT " ;
String experimental = " -experimental " ;
2021-11-24 07:45:09 +11:00
String base = ( versionInfo . getSpigotVersion ( ) ! = null ) ? " - " + versionInfo . getSpigotVersion ( ) : " " ;
String bootstrap = ( versionInfo . getToolsVersion ( ) > = 138 ) ? " -bootstrap " : " " ;
2024-01-14 12:43:58 +11:00
String suffix = base + bootstrap + fileExtension ;
String finalName = " spigot- " + versionInfo . getMinecraftVersion ( ) + fileExtension ;
2024-03-10 09:17:15 +11:00
if ( options . has ( Flags . EXPERIMENTAL_FLAG ) )
2024-01-14 12:43:58 +11:00
{
suffix = versionInfo . getMinecraftVersion ( ) + experimental + snapshot + bootstrap + fileExtension ;
finalName = " spigot- " + versionInfo . getMinecraftVersion ( ) + experimental + fileExtension ;
}
2024-03-10 09:17:15 +11:00
if ( Flags . OUTPUT_NAME_FLAG . value ( options ) ! = null )
2024-01-14 12:43:58 +11:00
{
2024-03-10 09:17:15 +11:00
finalName = Flags . OUTPUT_NAME_FLAG . value ( options ) ;
2024-01-14 12:43:58 +11:00
}
2024-02-18 09:09:34 +11:00
if ( compile . contains ( Compile . CRAFTBUKKIT ) )
2019-12-21 10:33:33 +11:00
{
2024-03-10 09:17:15 +11:00
copyJar ( " CraftBukkit/target " , " craftbukkit " , suffix , new File ( Flags . OUTPUT_DIR_FLAG . value ( options ) , " craftbukkit- " + versionInfo . getMinecraftVersion ( ) + " .jar " ) ) ;
2019-12-21 10:33:33 +11:00
}
2024-01-14 12:43:58 +11:00
2019-12-21 10:33:33 +11:00
if ( compile . contains ( Compile . SPIGOT ) )
2015-04-26 13:10:19 -05:00
{
2024-03-10 09:17:15 +11:00
copyJar ( " Spigot/Spigot-Server/target " , " spigot " , suffix , new File ( Flags . OUTPUT_DIR_FLAG . value ( options ) , finalName ) ) ;
2015-04-26 13:10:19 -05:00
}
2024-01-14 12:43:58 +11:00
System . exit ( 0 ) ;
2014-12-07 00:35:01 -05:00
}
2015-07-29 19:54:14 +10:00
private static boolean checkHash ( File vanillaJar , VersionInfo versionInfo ) throws IOException
{
2021-11-22 09:00:00 +11:00
if ( versionInfo . getShaServerHash ( ) ! = null )
{
return checkHash ( vanillaJar , HashFormat . SHA1 , versionInfo . getShaServerHash ( ) ) ;
} else if ( versionInfo . getMinecraftHash ( ) ! = null )
{
return checkHash ( vanillaJar , HashFormat . MD5 , versionInfo . getMinecraftHash ( ) ) ;
} else
2021-06-11 15:00:00 +10:00
{
2022-01-29 18:32:46 +11:00
return vanillaJar . isFile ( ) ;
2021-06-11 15:00:00 +10:00
}
2021-11-22 09:00:00 +11:00
}
2021-06-11 15:00:00 +10:00
2021-11-22 09:00:00 +11:00
private static boolean checkHash ( File vanillaJar , HashFormat hashFormat , String goodHash ) throws IOException
{
if ( ! vanillaJar . isFile ( ) )
2021-06-11 15:00:00 +10:00
{
2021-11-22 09:00:00 +11:00
return false ;
}
if ( dev )
2021-06-11 15:00:00 +10:00
{
return true ;
}
2021-11-22 09:00:00 +11:00
String hash = Files . asByteSource ( vanillaJar ) . hash ( hashFormat . getHash ( ) ) . toString ( ) ;
boolean result = hash . equals ( goodHash ) ;
2021-06-11 15:00:00 +10:00
if ( ! result )
2015-07-29 19:54:14 +10:00
{
2021-11-22 09:00:00 +11:00
System . err . println ( " **** Warning, Minecraft jar hash of " + hash + " does not match stored hash of " + goodHash ) ;
2015-07-29 19:54:14 +10:00
return false ;
} else
{
System . out . println ( " Found good Minecraft hash ( " + hash + " ) " ) ;
return true ;
}
}
2024-01-14 12:43:58 +11:00
public static String get ( String url ) throws IOException
2015-01-13 10:11:24 +11:00
{
URLConnection con = new URL ( url ) . openConnection ( ) ;
2024-01-14 12:43:58 +11:00
con . setConnectTimeout ( Constants . GENERAL_TIMEOUT_MS ) ;
con . setReadTimeout ( Constants . GENERAL_TIMEOUT_MS ) ;
2015-01-13 10:11:24 +11:00
2021-11-23 11:17:18 +11:00
try ( InputStreamReader r = new InputStreamReader ( con . getInputStream ( ) ) )
2015-01-13 10:11:24 +11:00
{
return CharStreams . toString ( r ) ;
}
}
2021-06-11 15:00:00 +10:00
public static void copyJar ( String path , final String jarPrefix , final String jarSuffix , File outJar ) throws Exception
2014-12-07 00:35:01 -05:00
{
2021-11-23 11:17:18 +11:00
File [ ] files = new File ( path ) . listFiles ( ( dir , name ) - > name . startsWith ( jarPrefix ) & & name . endsWith ( jarSuffix ) ) ;
2017-11-18 09:52:58 +11:00
if ( ! outJar . getParentFile ( ) . isDirectory ( ) )
{
outJar . getParentFile ( ) . mkdirs ( ) ;
}
2014-12-07 00:35:01 -05:00
for ( File file : files )
{
2024-01-14 12:43:58 +11:00
System . out . println ( " Copying " + file . getName ( ) + " to " + outJar . getCanonicalPath ( ) ) ;
2017-11-18 09:52:58 +11:00
Files . copy ( file , outJar ) ;
System . out . println ( " - Saved as " + outJar ) ;
2014-12-07 00:35:01 -05:00
}
2014-11-26 16:56:48 +11:00
}
2023-02-11 19:06:32 +11:00
public static boolean pull ( Git repo , String ref , PullRequest pullRequest ) throws Exception
2014-11-26 16:56:48 +11:00
{
System . out . println ( " Pulling updates for " + repo . getRepository ( ) . getDirectory ( ) ) ;
2018-12-18 17:04:10 +11:00
try
{
repo . reset ( ) . setRef ( " origin/master " ) . setMode ( ResetCommand . ResetType . HARD ) . call ( ) ;
} catch ( JGitInternalException ex )
{
System . err . println ( " *** Warning, could not find origin/master ref, but continuing anyway. " ) ;
System . err . println ( " *** If further errors occur please delete " + repo . getRepository ( ) . getDirectory ( ) . getParent ( ) + " and retry. " ) ;
}
2023-02-11 19:06:32 +11:00
FetchResult result ;
if ( pullRequest ! = null )
{
result = repo . fetch ( ) . setRefSpecs ( new RefSpec ( " +refs/pull-requests/ " + pullRequest . getId ( ) + " /from:refs/remotes/origin/pr/ " + pullRequest . getId ( ) ) ) . call ( ) ;
} else
{
result = repo . fetch ( ) . call ( ) ;
}
2015-01-13 10:11:24 +11:00
System . out . println ( " Successfully fetched updates! " ) ;
2014-11-26 16:56:48 +11:00
2023-02-11 19:06:32 +11:00
if ( pullRequest ! = null )
{
repo . checkout ( ) . setName ( " origin/pr/ " + pullRequest . getId ( ) ) . setForced ( true ) . call ( ) ;
} else
{
repo . reset ( ) . setRef ( ref ) . setMode ( ResetCommand . ResetType . HARD ) . call ( ) ;
}
2015-01-13 10:11:24 +11:00
if ( ref . equals ( " master " ) )
2014-11-26 16:56:48 +11:00
{
2015-01-13 10:11:24 +11:00
repo . reset ( ) . setRef ( " origin/master " ) . setMode ( ResetCommand . ResetType . HARD ) . call ( ) ;
2014-11-26 16:56:48 +11:00
}
2015-01-13 10:11:24 +11:00
System . out . println ( " Checked out: " + ref ) ;
2020-07-06 18:18:00 +10:00
// Return true if fetch changed any tracking refs.
return ! result . getTrackingRefUpdates ( ) . isEmpty ( ) ;
2014-11-26 16:56:48 +11:00
}
2023-02-11 19:06:32 +11:00
public static PullRequest getPullRequest ( Repository repository )
{
for ( PullRequest request : pullRequests )
{
if ( request . getRepository ( ) = = repository )
{
return request ;
}
}
return null ;
}
public static void validatedPullRequestsOptions ( )
{
Set < Repository > repositories = EnumSet . noneOf ( Repository . class ) ;
for ( PullRequest pullRequest : pullRequests )
{
if ( ! repositories . add ( pullRequest . getRepository ( ) ) )
{
throw new RuntimeException ( " Pull request option for repository " + pullRequest . getRepository ( ) + " is present multiple times. Only one per repository can be specified. " ) ;
}
}
}
2022-12-29 21:09:49 +11:00
private static int runMavenInstall ( File workDir , String . . . command ) throws Exception
{
return runMaven0 ( workDir , false , false , command ) ;
}
private static int runMavenAPI ( File workDir , String . . . command ) throws Exception
{
return runMaven0 ( workDir , dev , false , command ) ;
}
private static int runMavenServer ( File workDir , String . . . command ) throws Exception
{
return runMaven0 ( workDir , dev , remapped , command ) ;
}
private static int runMaven0 ( File workDir , boolean dev , boolean remapped , String . . . command ) throws Exception
2021-01-13 09:27:14 +11:00
{
2021-11-23 11:17:18 +11:00
List < String > args = new LinkedList < > ( ) ;
2021-01-13 09:27:14 +11:00
2021-01-13 10:10:20 +11:00
if ( IS_WINDOWS )
2021-01-13 09:27:14 +11:00
{
2021-01-13 10:10:20 +11:00
args . add ( maven . getAbsolutePath ( ) + " /bin/mvn.cmd " ) ;
2021-01-13 09:27:14 +11:00
} else
{
args . add ( " sh " ) ;
args . add ( maven . getAbsolutePath ( ) + " /bin/mvn " ) ;
}
args . add ( " -Dbt.name= " + buildInfo . getName ( ) ) ;
if ( dev )
{
args . add ( " -P " ) ;
args . add ( " development " ) ;
}
2021-06-11 15:00:00 +10:00
if ( remapped )
{
args . add ( " -P " ) ;
args . add ( " remapped " ) ;
}
2021-01-13 09:27:14 +11:00
args . addAll ( Arrays . asList ( command ) ) ;
return runProcess ( workDir , args . toArray ( new String [ args . size ( ) ] ) ) ;
}
2014-12-06 09:12:53 +11:00
public static int runProcess ( File workDir , String . . . command ) throws Exception
2017-11-09 10:46:32 +11:00
{
2021-05-21 08:29:01 +10:00
if ( command [ 0 ] . equals ( " java " ) )
{
command [ 0 ] = System . getProperty ( " java.home " ) + " /bin/ " + command [ 0 ] ;
}
2017-11-09 10:46:32 +11:00
if ( msysDir ! = null )
{
if ( " bash " . equals ( command [ 0 ] ) )
{
command [ 0 ] = " git-bash " ;
}
2021-06-20 09:57:55 +10:00
// BUILDTOOLS-594, etc: Many broken systems lack cmd.exe in PATH for unknown reasons (user error?)
String cmd = System . getenv ( " ComSpec " ) ;
if ( cmd = = null )
{
// Hopefully nothing messes up both PATH and ComSpec (what a broken system)
cmd = " cmd.exe " ;
}
2017-11-09 10:46:32 +11:00
String [ ] shim = new String [ ]
{
2021-06-20 09:57:55 +10:00
cmd , " /D " , " /C "
2017-11-09 10:46:32 +11:00
} ;
command = ObjectArrays . concat ( shim , command , String . class ) ;
}
return runProcess0 ( workDir , command ) ;
}
private static int runProcess0 ( File workDir , String . . . command ) throws Exception
2014-11-26 16:56:48 +11:00
{
2018-11-24 10:03:35 +11:00
Preconditions . checkArgument ( workDir ! = null , " workDir " ) ;
Preconditions . checkArgument ( command ! = null & & command . length > 0 , " Invalid command " ) ;
2015-01-05 14:46:07 +11:00
ProcessBuilder pb = new ProcessBuilder ( command ) ;
pb . directory ( workDir ) ;
pb . environment ( ) . put ( " JAVA_HOME " , System . getProperty ( " java.home " ) ) ;
2024-01-16 19:40:01 +11:00
pb . environment ( ) . put ( " GIT_COMMITTER_NAME " , " BuildTools " ) ;
pb . environment ( ) . put ( " GIT_COMMITTER_EMAIL " , " unconfigured@null.spigotmc.org " ) ;
2018-10-20 15:37:44 +11:00
pb . environment ( ) . remove ( " M2_HOME " ) ; // Just let maven figure this out from where it is invoked
2015-01-05 19:45:18 +11:00
if ( ! pb . environment ( ) . containsKey ( " MAVEN_OPTS " ) )
{
pb . environment ( ) . put ( " MAVEN_OPTS " , " -Xmx1024M " ) ;
}
2018-11-08 20:58:16 +11:00
if ( ! pb . environment ( ) . containsKey ( " _JAVA_OPTIONS " ) )
{
2024-02-10 12:37:22 +11:00
String javaOptions = null ;
2018-12-14 10:32:52 +11:00
for ( String arg : ManagementFactory . getRuntimeMXBean ( ) . getInputArguments ( ) )
{
if ( arg . startsWith ( " -Xmx " ) )
{
2024-02-10 12:37:22 +11:00
javaOptions = arg ;
break ;
2018-12-14 10:32:52 +11:00
}
}
2024-02-10 12:37:22 +11:00
if ( javaOptions ! = null )
{
pb . environment ( ) . put ( " _JAVA_OPTIONS " , javaOptions ) ;
}
2018-11-08 20:58:16 +11:00
}
2021-06-20 10:15:37 +10:00
if ( IS_WINDOWS )
2017-11-09 10:46:32 +11:00
{
String pathEnv = null ;
for ( String key : pb . environment ( ) . keySet ( ) )
{
if ( key . equalsIgnoreCase ( " path " ) )
{
pathEnv = key ;
}
}
if ( pathEnv = = null )
{
throw new IllegalStateException ( " Could not find path variable! " ) ;
}
2021-06-20 10:15:37 +10:00
if ( msysDir ! = null )
{
String path = msysDir . getAbsolutePath ( ) + " ; " + new File ( msysDir , " bin " ) . getAbsolutePath ( ) + " ; " + pb . environment ( ) . get ( pathEnv ) ;
pb . environment ( ) . put ( pathEnv , path ) ;
}
String path = pb . environment ( ) . get ( pathEnv ) ;
// Not strictly correct, but least likely to be a false positive
if ( ! path . contains ( " C: \\ WINDOWS \\ system32; " ) )
{
path = System . getenv ( " SystemRoot " ) + " \\ system32; " + path ;
pb . environment ( ) . put ( pathEnv , path ) ;
}
2017-11-09 10:46:32 +11:00
}
2015-01-05 14:46:07 +11:00
final Process ps = pb . start ( ) ;
2014-11-26 16:56:48 +11:00
2018-12-01 08:27:24 +11:00
new Thread ( new StreamRedirector ( ps . getInputStream ( ) , System . out ) , " System.out redirector " ) . start ( ) ;
new Thread ( new StreamRedirector ( ps . getErrorStream ( ) , System . err ) , " System.err redirector " ) . start ( ) ;
2014-11-26 16:56:48 +11:00
int status = ps . waitFor ( ) ;
if ( status ! = 0 )
{
2014-12-06 09:12:53 +11:00
throw new RuntimeException ( " Error running command, return status !=0: " + Arrays . toString ( command ) ) ;
2014-11-26 16:56:48 +11:00
}
return status ;
}
@RequiredArgsConstructor
private static class StreamRedirector implements Runnable
{
private final InputStream in ;
private final PrintStream out ;
@Override
public void run ( )
{
2021-11-23 11:17:18 +11:00
try ( BufferedReader br = new BufferedReader ( new InputStreamReader ( in ) ) )
2014-11-26 16:56:48 +11:00
{
String line ;
while ( ( line = br . readLine ( ) ) ! = null )
{
out . println ( line ) ;
}
} catch ( IOException ex )
{
2020-06-21 09:42:35 +10:00
throw new RuntimeException ( ex ) ;
2014-11-26 16:56:48 +11:00
}
}
}
public static void unzip ( File zipFile , File targetFolder ) throws IOException
{
unzip ( zipFile , targetFolder , null ) ;
}
public static void unzip ( File zipFile , File targetFolder , Predicate < String > filter ) throws IOException
{
targetFolder . mkdir ( ) ;
2021-11-23 11:17:18 +11:00
try ( ZipFile zip = new ZipFile ( zipFile ) )
2014-11-26 16:56:48 +11:00
{
2017-11-18 09:45:25 +11:00
for ( Enumeration < ? extends ZipEntry > entries = zip . entries ( ) ; entries . hasMoreElements ( ) ; )
2014-11-26 16:56:48 +11:00
{
2017-11-18 09:45:25 +11:00
ZipEntry entry = entries . nextElement ( ) ;
if ( filter ! = null )
2014-11-26 16:56:48 +11:00
{
2020-06-21 09:42:35 +10:00
if ( ! filter . test ( entry . getName ( ) ) )
2017-11-18 09:45:25 +11:00
{
continue ;
}
2014-11-26 16:56:48 +11:00
}
2017-11-18 09:45:25 +11:00
File outFile = new File ( targetFolder , entry . getName ( ) ) ;
2014-11-26 16:56:48 +11:00
2017-11-18 09:45:25 +11:00
if ( entry . isDirectory ( ) )
{
outFile . mkdirs ( ) ;
continue ;
}
if ( outFile . getParentFile ( ) ! = null )
{
outFile . getParentFile ( ) . mkdirs ( ) ;
}
2014-11-26 16:56:48 +11:00
2021-11-23 11:17:18 +11:00
try ( InputStream is = zip . getInputStream ( entry ) ; OutputStream os = new FileOutputStream ( outFile ) ; )
2017-11-18 09:45:25 +11:00
{
ByteStreams . copy ( is , os ) ;
}
2014-11-26 16:56:48 +11:00
2017-11-18 09:45:25 +11:00
System . out . println ( " Extracted: " + outFile ) ;
}
2014-11-26 16:56:48 +11:00
}
}
2015-09-02 07:32:27 +10:00
public static void clone ( String url , File target ) throws GitAPIException , IOException
2014-11-26 16:56:48 +11:00
{
System . out . println ( " Starting clone of " + url + " to " + target ) ;
2021-11-23 11:17:18 +11:00
try ( Git result = Git . cloneRepository ( ) . setURI ( url ) . setDirectory ( target ) . call ( ) )
2014-11-26 16:56:48 +11:00
{
2015-09-02 07:32:27 +10:00
StoredConfig config = result . getRepository ( ) . getConfig ( ) ;
2024-02-05 19:20:12 +11:00
config . setBoolean ( " core " , null , " autocrlf " , AUTOCRLF ) ;
2015-09-02 07:32:27 +10:00
config . save ( ) ;
2014-11-26 16:56:48 +11:00
2020-07-06 18:18:00 +10:00
didClone = true ;
2015-09-02 07:32:27 +10:00
System . out . println ( " Cloned git repository " + url + " to " + target . getAbsolutePath ( ) + " . Current HEAD: " + commitHash ( result ) ) ;
2014-11-26 16:56:48 +11:00
}
}
public static String commitHash ( Git repo ) throws GitAPIException
{
return Iterables . getOnlyElement ( repo . log ( ) . setMaxCount ( 1 ) . call ( ) ) . getName ( ) ;
}
2021-06-11 15:00:00 +10:00
public static File download ( String url , File target ) throws IOException
{
return download ( url , target , HashFormat . SHA1 , " ! " ) ;
}
2019-03-25 21:30:02 +11:00
public static File download ( String url , File target , HashFormat hashFormat , String goodHash ) throws IOException
2014-11-26 16:56:48 +11:00
{
2021-06-11 15:00:00 +10:00
String shaHash = VersionInfo . hashFromUrl ( url ) ;
if ( shaHash ! = null )
{
hashFormat = HashFormat . SHA1 ;
goodHash = shaHash ;
}
2014-11-26 16:56:48 +11:00
System . out . println ( " Starting download of " + url ) ;
byte [ ] bytes = Resources . toByteArray ( new URL ( url ) ) ;
2019-03-25 21:30:02 +11:00
String hash = hashFormat . getHash ( ) . hashBytes ( bytes ) . toString ( ) ;
2014-11-26 16:56:48 +11:00
2019-03-25 21:30:02 +11:00
System . out . println ( " Downloaded file: " + target + " with hash: " + hash ) ;
if ( ! dev & & goodHash ! = null & & ! goodHash . equals ( hash ) )
{
throw new IllegalStateException ( " Downloaded file: " + target + " did not match expected hash: " + goodHash ) ;
}
2014-11-26 16:56:48 +11:00
Files . write ( bytes , target ) ;
return target ;
}
2014-12-08 01:41:20 +02:00
2022-11-09 19:27:47 +11:00
public static String getServerVanillaUrl ( String version ) throws Exception
{
Gson gson = new Gson ( ) ;
String responseManifest = get ( " https://launchermeta.mojang.com/mc/game/version_manifest.json " ) ;
JsonObject manifest = gson . fromJson ( responseManifest , JsonObject . class ) ;
JsonArray manifestVersions = manifest . getAsJsonArray ( " versions " ) ;
for ( JsonElement manifestVersionElement : manifestVersions )
{
if ( manifestVersionElement . isJsonObject ( ) )
{
JsonObject manifestVersion = manifestVersionElement . getAsJsonObject ( ) ;
if ( manifestVersion . get ( " id " ) . getAsString ( ) . equals ( version ) )
{
String urlVersionData = manifestVersion . get ( " url " ) . getAsString ( ) ;
String responseVersionData = get ( urlVersionData ) ;
JsonObject versionData = gson . fromJson ( responseVersionData , JsonObject . class ) ;
return versionData . getAsJsonObject ( " downloads " ) . getAsJsonObject ( " server " ) . get ( " url " ) . getAsString ( ) ;
}
}
}
throw new RuntimeException ( " Error cannot get the URL for legacy server version " + version ) ;
}
2014-12-12 11:21:43 +11:00
public static void disableHttpsCertificateCheck ( )
{
2014-12-08 01:41:20 +02:00
// This globally disables certificate checking
// http://stackoverflow.com/questions/19723415/java-overriding-function-to-disable-ssl-certificate-check
try
{
2014-12-12 11:21:43 +11:00
TrustManager [ ] trustAllCerts = new TrustManager [ ]
{
new X509TrustManager ( )
{
@Override
2024-02-05 19:20:12 +11:00
public X509Certificate [ ] getAcceptedIssuers ( )
2014-12-12 11:21:43 +11:00
{
return null ;
}
@Override
public void checkClientTrusted ( X509Certificate [ ] certs , String authType )
{
}
@Override
public void checkServerTrusted ( X509Certificate [ ] certs , String authType )
{
}
2014-12-08 01:41:20 +02:00
}
} ;
2014-12-12 11:21:43 +11:00
// Trust SSL certs
SSLContext sc = SSLContext . getInstance ( " SSL " ) ;
sc . init ( null , trustAllCerts , new SecureRandom ( ) ) ;
HttpsURLConnection . setDefaultSSLSocketFactory ( sc . getSocketFactory ( ) ) ;
// Trust host names
2021-11-23 11:17:18 +11:00
HttpsURLConnection . setDefaultHostnameVerifier ( ( hostname , session ) - > true ) ;
} catch ( NoSuchAlgorithmException | KeyManagementException ex )
2014-12-08 01:41:20 +02:00
{
2014-12-12 11:21:43 +11:00
System . out . println ( " Failed to disable https certificate check " ) ;
ex . printStackTrace ( System . err ) ;
}
}
2024-01-14 12:43:58 +11:00
public static void logOutput ( OutputStream defaultOut , OutputStream defaultError )
2014-12-12 11:21:43 +11:00
{
try
{
2024-01-14 12:43:58 +11:00
final OutputStream logOut = new BufferedOutputStream ( new FileOutputStream ( new File ( CWD , LOG_FILE ) ) ) ;
2014-12-12 11:21:43 +11:00
Runtime . getRuntime ( ) . addShutdownHook ( new Thread ( )
{
@Override
public void run ( )
{
System . setOut ( new PrintStream ( new FileOutputStream ( FileDescriptor . out ) ) ) ;
System . setErr ( new PrintStream ( new FileOutputStream ( FileDescriptor . err ) ) ) ;
try
{
logOut . close ( ) ;
} catch ( IOException ex )
{
// We're shutting the jvm down anyway.
}
}
} ) ;
2024-01-14 12:43:58 +11:00
System . setOut ( new PrintStream ( new TeeOutputStream ( defaultOut , logOut ) ) ) ;
System . setErr ( new PrintStream ( new TeeOutputStream ( defaultError , logOut ) ) ) ;
2014-12-12 11:21:43 +11:00
} catch ( FileNotFoundException ex )
{
System . err . println ( " Failed to create log file: " + LOG_FILE ) ;
2014-12-08 01:41:20 +02:00
}
}
2019-03-25 21:30:02 +11:00
public enum HashFormat
{
MD5
{
@Override
2020-06-21 09:42:35 +10:00
@SuppressWarnings ( " deprecation " )
2019-03-25 21:30:02 +11:00
public HashFunction getHash ( )
{
return Hashing . md5 ( ) ;
}
2021-06-11 15:00:00 +10:00
} , SHA1
{
@Override
2021-11-23 11:17:18 +11:00
@SuppressWarnings ( " deprecation " )
2021-06-11 15:00:00 +10:00
public HashFunction getHash ( )
{
return Hashing . sha1 ( ) ;
}
2019-03-25 21:30:02 +11:00
} , SHA256
{
@Override
public HashFunction getHash ( )
{
return Hashing . sha256 ( ) ;
}
} , SHA512
{
@Override
public HashFunction getHash ( )
{
return Hashing . sha512 ( ) ;
}
} ;
public abstract HashFunction getHash ( ) ;
}
2020-07-06 18:18:00 +10:00
private static boolean containsGit ( File file )
{
return new File ( file , " .git " ) . isDirectory ( ) ;
}
2014-11-26 16:56:48 +11:00
}