Commits
Nothixal authored and md_5 committed a6f7b1bcbc5
1 1 | package org.spigotmc.builder; |
2 2 | |
3 - | import com.google.common.base.Charsets; |
4 3 | import com.google.common.base.Preconditions; |
5 4 | import com.google.common.collect.Iterables; |
6 5 | import com.google.common.collect.ObjectArrays; |
7 6 | import com.google.common.hash.HashFunction; |
8 7 | import com.google.common.hash.Hasher; |
9 8 | import com.google.common.hash.Hashing; |
10 9 | import com.google.common.io.ByteStreams; |
11 10 | import com.google.common.io.CharStreams; |
12 11 | import com.google.common.io.Files; |
13 12 | import com.google.common.io.Resources; |
26 25 | import java.io.FileOutputStream; |
27 26 | import java.io.FileWriter; |
28 27 | import java.io.IOException; |
29 28 | import java.io.InputStream; |
30 29 | import java.io.InputStreamReader; |
31 30 | import java.io.OutputStream; |
32 31 | import java.io.PrintStream; |
33 32 | import java.lang.management.ManagementFactory; |
34 33 | import java.net.URL; |
35 34 | import java.net.URLConnection; |
35 + | import java.nio.charset.StandardCharsets; |
36 36 | import java.nio.file.FileSystem; |
37 37 | import java.nio.file.FileSystemException; |
38 38 | import java.nio.file.FileSystems; |
39 39 | import java.nio.file.Path; |
40 40 | import java.security.KeyManagementException; |
41 41 | import java.security.NoSuchAlgorithmException; |
42 42 | import java.security.SecureRandom; |
43 43 | import java.security.cert.X509Certificate; |
44 44 | import java.text.MessageFormat; |
45 45 | import java.util.ArrayList; |
74 74 | import org.eclipse.jgit.lib.StoredConfig; |
75 75 | import org.eclipse.jgit.revwalk.RevCommit; |
76 76 | import org.eclipse.jgit.transport.FetchResult; |
77 77 | import org.eclipse.jgit.transport.RefSpec; |
78 78 | import org.spigotmc.mapper.MapUtil; |
79 79 | import org.spigotmc.utils.Constants; |
80 80 | |
81 81 | public class Builder |
82 82 | { |
83 83 | |
84 - | public static final String LOG_FILE = Constants.LOG_FILE; |
85 - | public static final boolean IS_WINDOWS = System.getProperty( "os.name" ).startsWith( "Windows" ); |
86 84 | public static File CWD = new File( "." ); |
87 - | private static final boolean autocrlf = !"\n".equals( System.getProperty( "line.separator" ) ); |
85 + | public static final String LOG_FILE = Constants.LOG_FILE; |
86 + | |
87 + | private static final boolean IS_WINDOWS = System.getProperty( "os.name" ).startsWith( "Windows" ); |
88 + | private static final boolean AUTOCRLF = !"\n".equals( System.getProperty( "line.separator" ) ); |
89 + | |
88 90 | private static boolean dontUpdate; |
89 91 | private static List<Compile> compile; |
90 92 | private static boolean generateSource; |
91 93 | private static boolean generateDocs; |
92 94 | private static boolean dev; |
93 95 | private static boolean remapped; |
94 96 | private static List<PullRequest> pullRequests; |
95 97 | private static String applyPatchesShell = "sh"; |
96 98 | private static boolean didClone = false; |
97 99 | // |
108 110 | String buildVersion = Builder.class.getPackage().getImplementationVersion(); |
109 111 | int buildNumber = -1; |
110 112 | if ( buildVersion != null ) |
111 113 | { |
112 114 | String[] split = buildVersion.split( "-" ); |
113 115 | if ( split.length == 4 ) |
114 116 | { |
115 117 | try |
116 118 | { |
117 119 | buildNumber = Integer.parseInt( split[3] ); |
118 - | } catch ( NumberFormatException ex ) |
120 + | } catch ( NumberFormatException ignored ) |
119 121 | { |
120 122 | } |
121 123 | } |
122 124 | } |
123 125 | |
124 126 | System.out.println( "Loading BuildTools version: " + buildVersion + " (#" + buildNumber + ")" ); |
125 127 | System.out.println( "Java Version: " + JavaVersion.getCurrentVersion() ); |
126 - | System.out.println( "Current Path: " + CWD.getAbsolutePath() ); |
128 + | System.out.println( "Current Path: " + CWD.getCanonicalPath() ); |
127 129 | |
128 130 | if ( CWD.getAbsolutePath().contains( "'" ) || CWD.getAbsolutePath().contains( "#" ) || CWD.getAbsolutePath().contains( "~" ) || CWD.getAbsolutePath().contains( "(" ) || CWD.getAbsolutePath().contains( ")" ) ) |
129 131 | { |
130 132 | System.err.println( Constants.SPECIAL_CHARACTERS_WARNING ); |
131 133 | System.exit( 1 ); |
132 134 | } |
133 135 | |
134 136 | if ( CWD.getAbsolutePath().contains( "Dropbox" ) || CWD.getAbsolutePath().contains( "OneDrive" ) ) |
135 137 | { |
136 138 | System.err.println( Constants.NON_STANDARD_PATH_WARNING ); |
137 139 | System.exit( 1 ); |
138 140 | } |
139 141 | |
140 142 | OptionParser parser = new OptionParser(); |
141 143 | OptionSpec<Void> help = parser.accepts( "help", "Show the help" ); |
142 144 | OptionSpec<Void> disableCertFlag = parser.accepts( "disable-certificate-check", "Disable HTTPS certificate check" ); |
143 - | OptionSpec<Void> disableJavaCheck = parser.accepts( "disable-java-check", "Disable Java version check" ); |
145 + | OptionSpec<Void> disableJavaCheckFlag = parser.accepts( "disable-java-check", "Disable Java version check" ); |
144 146 | OptionSpec<Void> dontUpdateFlag = parser.accepts( "dont-update", "Don't pull updates from Git" ); |
145 147 | OptionSpec<Void> skipCompileFlag = parser.accepts( "skip-compile", "Skip compilation" ); |
146 148 | OptionSpec<Void> generateSourceFlag = parser.accepts( "generate-source", "Generate source jar" ); |
147 149 | OptionSpec<Void> generateDocsFlag = parser.accepts( "generate-docs", "Generate Javadoc jar" ); |
148 150 | OptionSpec<Void> devFlag = parser.accepts( "dev", "Development mode" ); |
149 151 | OptionSpec<Void> experimentalFlag = parser.accepts( "experimental", "Build experimental version" ); |
150 152 | OptionSpec<Void> remappedFlag = parser.accepts( "remapped", "Produce and install extra remapped jars" ); |
151 - | OptionSpec<File> outputDir = parser.acceptsAll( Arrays.asList( "o", "output-dir" ), "Final jar output directory" ).withRequiredArg().ofType( File.class ).defaultsTo( CWD ); |
152 - | OptionSpec<String> outputName = parser.accepts( "final-name", "Name of the final jar" ).withRequiredArg(); |
153 - | OptionSpec<String> jenkinsVersion = parser.accepts( "rev", "Version to build" ).withRequiredArg().defaultsTo( "latest" ); |
154 - | OptionSpec<Compile> toCompile = parser.accepts( "compile", "Software to compile" ).withRequiredArg().ofType( Compile.class ).withValuesConvertedBy( new EnumConverter<Compile>( Compile.class ) |
153 + | OptionSpec<File> outputDirFlag = parser.acceptsAll( Arrays.asList( "o", "output-dir" ), "Final jar output directory" ).withRequiredArg().ofType( File.class ).defaultsTo( CWD ); |
154 + | OptionSpec<String> outputNameFlag = parser.accepts( "final-name", "Name of the final jar" ).withRequiredArg(); |
155 + | OptionSpec<String> jenkinsVersionFlag = parser.accepts( "rev", "Version to build" ).withRequiredArg().defaultsTo( "latest" ); |
156 + | OptionSpec<Compile> toCompileFlag = parser.accepts( "compile", "Software to compile" ).withRequiredArg().ofType( Compile.class ).withValuesConvertedBy( new EnumConverter<Compile>( Compile.class ) |
155 157 | { |
156 158 | } ).withValuesSeparatedBy( ',' ); |
157 - | OptionSpec<Void> compileIfChanged = parser.accepts( "compile-if-changed", "Run BuildTools only when changes are detected in the repository" ); |
158 - | OptionSpec<PullRequest> buildPullRequest = parser.acceptsAll( Arrays.asList( "pull-request", "pr" ), "Build specific pull requests" ).withOptionalArg().withValuesConvertedBy( new PullRequest.PullRequestConverter() ); |
159 + | OptionSpec<Void> compileIfChangedFlag = parser.accepts( "compile-if-changed", "Run BuildTools only when changes are detected in the repository" ); |
160 + | OptionSpec<PullRequest> buildPullRequestFlag = parser.acceptsAll( Arrays.asList( "pull-request", "pr" ), "Build specific pull requests" ).withOptionalArg().withValuesConvertedBy( new PullRequest.PullRequestConverter() ); |
159 161 | parser.accepts( "nogui", "Disable the GUI" ); |
160 162 | |
161 163 | OptionSet options = parser.parse( args ); |
162 164 | |
163 165 | if ( options.has( help ) ) |
164 166 | { |
165 167 | parser.printHelpOn( System.out ); |
166 168 | System.exit( 0 ); |
167 169 | } |
168 170 | if ( options.has( disableCertFlag ) ) |
173 175 | generateSource = options.has( generateSourceFlag ); |
174 176 | generateDocs = options.has( generateDocsFlag ); |
175 177 | dev = options.has( devFlag ); |
176 178 | // Experimental implies dev but with different refs |
177 179 | if ( options.has( experimentalFlag ) ) |
178 180 | { |
179 181 | dev = true; |
180 182 | buildInfo = BuildInfo.EXPERIMENTAL; |
181 183 | } |
182 184 | remapped = options.has( remappedFlag ); |
183 - | compile = options.valuesOf( toCompile ); |
184 - | pullRequests = options.valuesOf( buildPullRequest ); |
185 + | compile = options.valuesOf( toCompileFlag ); |
186 + | pullRequests = options.valuesOf( buildPullRequestFlag ); |
185 187 | validatedPullRequestsOptions(); |
186 188 | if ( options.has( skipCompileFlag ) ) |
187 189 | { |
188 190 | compile = Collections.singletonList( Compile.NONE ); |
189 191 | System.err.println( "--skip-compile is deprecated, please use --compile NONE" ); |
190 192 | } |
191 - | if ( ( dev || dontUpdate ) && options.has( jenkinsVersion ) ) |
193 + | if ( ( dev || dontUpdate ) && options.has( jenkinsVersionFlag ) ) |
192 194 | { |
193 195 | System.err.println( "Using --dev or --dont-update with --rev makes no sense, exiting." ); |
194 196 | System.exit( 1 ); |
195 197 | } |
196 198 | if ( compile.isEmpty() && !pullRequests.isEmpty() ) |
197 199 | { |
198 200 | compile = new ArrayList<>(); |
199 201 | if ( getPullRequest( Repository.BUKKIT ) != null || getPullRequest( Repository.CRAFTBUKKIT ) != null ) |
200 202 | { |
201 203 | compile.add( Compile.CRAFTBUKKIT ); |
262 264 | { |
263 265 | runProcess( CWD, "java", "-version" ); |
264 266 | } catch ( Exception ex ) |
265 267 | { |
266 268 | System.out.println( "Could not successfully run Java." + ex.getMessage() ); |
267 269 | System.exit( 1 ); |
268 270 | } |
269 271 | |
270 272 | if ( !dontUpdate && !dev ) |
271 273 | { |
272 - | String askedVersion = options.valueOf( jenkinsVersion ); |
274 + | String askedVersion = options.valueOf( jenkinsVersionFlag ); |
273 275 | System.out.println( "Attempting to build version: '" + askedVersion + "' use --rev <version> to override" ); |
274 276 | |
275 277 | String verInfo; |
276 278 | try |
277 279 | { |
278 280 | verInfo = get( "https://hub.spigotmc.org/versions/" + askedVersion + ".json" ); |
279 281 | } catch ( IOException ex ) |
280 282 | { |
281 283 | System.err.println( "Could not get version " + askedVersion + " does it exist? Try another version or use 'latest'" ); |
282 284 | ex.printStackTrace(); |
287 289 | System.out.println( verInfo ); |
288 290 | |
289 291 | buildInfo = new Gson().fromJson( verInfo, BuildInfo.class ); |
290 292 | |
291 293 | if ( buildNumber != -1 && buildInfo.getToolsVersion() != -1 && buildNumber < buildInfo.getToolsVersion() ) |
292 294 | { |
293 295 | 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" ); |
294 296 | System.exit( 1 ); |
295 297 | } |
296 298 | |
297 - | if ( !options.has( disableJavaCheck ) ) |
299 + | if ( !options.has( disableJavaCheckFlag ) ) |
298 300 | { |
299 301 | if ( buildInfo.getJavaVersions() == null ) |
300 302 | { |
301 303 | buildInfo.setJavaVersions( new int[] |
302 304 | { |
303 305 | JavaVersion.JAVA_7.getVersion(), JavaVersion.JAVA_8.getVersion() |
304 306 | } ); |
305 307 | } |
306 308 | |
307 309 | Preconditions.checkArgument( buildInfo.getJavaVersions().length == 2, "Expected only two Java versions, got %s", JavaVersion.printVersions( buildInfo.getJavaVersions() ) ); |
372 374 | Git buildGit = Git.open( buildData ); |
373 375 | |
374 376 | if ( !dontUpdate ) |
375 377 | { |
376 378 | boolean buildDataChanged = pull( buildGit, buildInfo.getRefs().getBuildData(), null ); |
377 379 | boolean bukkitChanged = pull( bukkitGit, buildInfo.getRefs().getBukkit(), getPullRequest( Repository.BUKKIT ) ); |
378 380 | boolean craftBukkitChanged = pull( craftBukkitGit, buildInfo.getRefs().getCraftBukkit(), getPullRequest( Repository.CRAFTBUKKIT ) ); |
379 381 | boolean spigotChanged = pull( spigotGit, buildInfo.getRefs().getSpigot(), getPullRequest( Repository.SPIGOT ) ); |
380 382 | |
381 383 | // 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. |
382 - | if ( !buildDataChanged && !bukkitChanged && !craftBukkitChanged && !spigotChanged && options.has( compileIfChanged ) && !didClone ) |
384 + | if ( !buildDataChanged && !bukkitChanged && !craftBukkitChanged && !spigotChanged && options.has( compileIfChangedFlag ) && !didClone ) |
383 385 | { |
384 386 | System.out.println( "*** No changes detected in any of the repositories!" ); |
385 387 | System.out.println( "*** Exiting due to the --compile-if-changed" ); |
386 388 | System.exit( 2 ); |
387 389 | } |
388 390 | } |
389 391 | |
390 392 | VersionInfo versionInfo = new Gson().fromJson( |
391 - | Files.asCharSource( new File( "BuildData/info.json" ), Charsets.UTF_8 ).read(), |
393 + | Files.asCharSource( new File( "BuildData/info.json" ), StandardCharsets.UTF_8 ).read(), |
392 394 | VersionInfo.class |
393 395 | ); |
394 396 | // Default to 1.8 builds. |
395 397 | if ( versionInfo == null ) |
396 398 | { |
397 399 | versionInfo = new VersionInfo( "1.8", "bukkit-1.8.at", "bukkit-1.8-cl.csrg", "bukkit-1.8-members.csrg", "package.srg", null ); |
398 400 | } |
399 401 | System.out.println( "Attempting to build Minecraft with details: " + versionInfo ); |
400 402 | |
401 403 | if ( buildNumber != -1 && versionInfo.getToolsVersion() != -1 && buildNumber < versionInfo.getToolsVersion() ) |
455 457 | } |
456 458 | } |
457 459 | |
458 460 | Iterable<RevCommit> mappings = buildGit.log() |
459 461 | .addPath( "mappings/" ) |
460 462 | .setMaxCount( 1 ).call(); |
461 463 | |
462 464 | Hasher mappingsHash = HashFormat.MD5.getHash().newHasher(); |
463 465 | for ( RevCommit rev : mappings ) |
464 466 | { |
465 - | mappingsHash.putString( rev.getName(), Charsets.UTF_8 ); |
467 + | mappingsHash.putString( rev.getName(), StandardCharsets.UTF_8 ); |
466 468 | } |
467 469 | String mappingsVersion = mappingsHash.hash().toString().substring( 24 ); // Last 8 chars |
468 470 | |
469 471 | File finalMappedJar = new File( workDir, "mapped." + mappingsVersion + ".jar" ); |
470 472 | if ( !finalMappedJar.exists() ) |
471 473 | { |
472 474 | System.out.println( "Final mapped jar: " + finalMappedJar + " does not exist, creating (please wait)!" ); |
473 475 | |
474 476 | File classMappings = new File( "BuildData/mappings/" + versionInfo.getClassMappings() ); |
475 477 | File memberMappings = new File( "BuildData/mappings/" + versionInfo.getMemberMappings() ); |
605 607 | String targetFile = ( relativeName.contains( File.separator ) ) ? relativeName : "net/minecraft/server/" + relativeName; |
606 608 | |
607 609 | File clean = new File( decompileDir, targetFile ); |
608 610 | File t = new File( nmsDir.getParentFile(), targetFile ); |
609 611 | t.getParentFile().mkdirs(); |
610 612 | |
611 613 | System.out.println( "Patching " + relativeName ); |
612 614 | |
613 615 | try |
614 616 | { |
615 - | List<String> readFile = Files.readLines( file, Charsets.UTF_8 ); |
617 + | List<String> readFile = Files.readLines( file, StandardCharsets.UTF_8 ); |
616 618 | |
617 619 | // Manually append prelude if it is not found in the first few lines. |
618 620 | boolean preludeFound = false; |
619 621 | for ( int i = 0; i < Math.min( 3, readFile.size() ); i++ ) |
620 622 | { |
621 623 | if ( readFile.get( i ).startsWith( "+++" ) ) |
622 624 | { |
623 625 | preludeFound = true; |
624 626 | break; |
625 627 | } |
626 628 | } |
627 629 | if ( !preludeFound ) |
628 630 | { |
629 631 | readFile.add( 0, "+++" ); |
630 632 | } |
631 633 | |
632 634 | Patch parsedPatch = DiffUtils.parseUnifiedDiff( readFile ); |
633 - | List<?> modifiedLines = DiffUtils.patch( Files.readLines( clean, Charsets.UTF_8 ), parsedPatch ); |
635 + | List<?> modifiedLines = DiffUtils.patch( Files.readLines( clean, StandardCharsets.UTF_8 ), parsedPatch ); |
634 636 | |
635 637 | try ( BufferedWriter bw = new BufferedWriter( new FileWriter( t ) ) ) |
636 638 | { |
637 639 | for ( Object line : modifiedLines ) |
638 640 | { |
639 641 | bw.write( (String) line ); |
640 642 | bw.newLine(); |
641 643 | } |
642 644 | } |
643 645 | } catch ( Exception ex ) |
744 746 | String suffix = base + bootstrap + fileExtension; |
745 747 | |
746 748 | String finalName = "spigot-" + versionInfo.getMinecraftVersion() + fileExtension; |
747 749 | |
748 750 | if ( options.has( experimentalFlag ) ) |
749 751 | { |
750 752 | suffix = versionInfo.getMinecraftVersion() + experimental + snapshot + bootstrap + fileExtension; |
751 753 | finalName = "spigot-" + versionInfo.getMinecraftVersion() + experimental + fileExtension; |
752 754 | } |
753 755 | |
754 - | if ( outputName.value( options ) != null ) |
756 + | if ( outputNameFlag.value( options ) != null ) |
755 757 | { |
756 - | finalName = outputName.value( options ); |
758 + | finalName = outputNameFlag.value( options ); |
757 759 | } |
758 760 | |
759 761 | if ( compile.contains( Compile.CRAFTBUKKIT ) && ( versionInfo.getToolsVersion() < 101 || versionInfo.getToolsVersion() > 104 ) ) |
760 762 | { |
761 - | copyJar( "CraftBukkit/target", "craftbukkit", suffix, new File( outputDir.value( options ), "craftbukkit-" + versionInfo.getMinecraftVersion() + ".jar" ) ); |
763 + | copyJar( "CraftBukkit/target", "craftbukkit", suffix, new File( outputDirFlag.value( options ), "craftbukkit-" + versionInfo.getMinecraftVersion() + ".jar" ) ); |
762 764 | } |
763 765 | |
764 766 | if ( compile.contains( Compile.SPIGOT ) ) |
765 767 | { |
766 - | copyJar( "Spigot/Spigot-Server/target", "spigot", suffix, new File( outputDir.value( options ), finalName ) ); |
768 + | copyJar( "Spigot/Spigot-Server/target", "spigot", suffix, new File( outputDirFlag.value( options ), finalName ) ); |
767 769 | } |
768 770 | |
769 771 | System.exit( 0 ); |
770 772 | } |
771 773 | |
772 774 | private static boolean checkHash(File vanillaJar, VersionInfo versionInfo) throws IOException |
773 775 | { |
774 776 | if ( versionInfo.getShaServerHash() != null ) |
775 777 | { |
776 778 | return checkHash( vanillaJar, HashFormat.SHA1, versionInfo.getShaServerHash() ); |
1125 1127 | } |
1126 1128 | } |
1127 1129 | |
1128 1130 | public static void clone(String url, File target) throws GitAPIException, IOException |
1129 1131 | { |
1130 1132 | System.out.println( "Starting clone of " + url + " to " + target ); |
1131 1133 | |
1132 1134 | try ( Git result = Git.cloneRepository().setURI( url ).setDirectory( target ).call() ) |
1133 1135 | { |
1134 1136 | StoredConfig config = result.getRepository().getConfig(); |
1135 - | config.setBoolean( "core", null, "autocrlf", autocrlf ); |
1137 + | config.setBoolean( "core", null, "autocrlf", AUTOCRLF ); |
1136 1138 | config.save(); |
1137 1139 | |
1138 1140 | didClone = true; |
1139 1141 | System.out.println( "Cloned git repository " + url + " to " + target.getAbsolutePath() + ". Current HEAD: " + commitHash( result ) ); |
1140 1142 | } |
1141 1143 | } |
1142 1144 | |
1143 1145 | public static String commitHash(Git repo) throws GitAPIException |
1144 1146 | { |
1145 1147 | return Iterables.getOnlyElement( repo.log().setMaxCount( 1 ).call() ).getName(); |
1207 1209 | { |
1208 1210 | // This globally disables certificate checking |
1209 1211 | // http://stackoverflow.com/questions/19723415/java-overriding-function-to-disable-ssl-certificate-check |
1210 1212 | try |
1211 1213 | { |
1212 1214 | TrustManager[] trustAllCerts = new TrustManager[] |
1213 1215 | { |
1214 1216 | new X509TrustManager() |
1215 1217 | { |
1216 1218 | |
1217 - | public java.security.cert.X509Certificate[] getAcceptedIssuers() |
1219 + | public X509Certificate[] getAcceptedIssuers() |
1218 1220 | { |
1219 1221 | return null; |
1220 1222 | } |
1221 1223 | |
1222 1224 | |
1223 1225 | public void checkClientTrusted(X509Certificate[] certs, String authType) |
1224 1226 | { |
1225 1227 | } |
1226 1228 | |
1227 1229 | |