Commits
9 9 | import com.google.common.io.ByteStreams; |
10 10 | import com.google.common.io.CharStreams; |
11 11 | import com.google.common.io.Files; |
12 12 | import com.google.common.io.Resources; |
13 13 | import com.google.gson.Gson; |
14 14 | import difflib.DiffUtils; |
15 15 | import difflib.Patch; |
16 16 | import java.io.BufferedOutputStream; |
17 17 | import java.io.BufferedReader; |
18 18 | import java.io.BufferedWriter; |
19 + | import java.io.ByteArrayInputStream; |
19 20 | import java.io.File; |
20 21 | import java.io.FileDescriptor; |
21 22 | import java.io.FileNotFoundException; |
22 23 | import java.io.FileOutputStream; |
23 24 | import java.io.FileWriter; |
24 25 | import java.io.FilenameFilter; |
25 26 | import java.io.IOException; |
26 27 | import java.io.InputStream; |
27 28 | import java.io.InputStreamReader; |
28 29 | import java.io.OutputStream; |
45 46 | import javax.net.ssl.SSLSession; |
46 47 | import javax.net.ssl.TrustManager; |
47 48 | import javax.net.ssl.X509TrustManager; |
48 49 | |
49 50 | import joptsimple.OptionParser; |
50 51 | import joptsimple.OptionSet; |
51 52 | import joptsimple.OptionSpec; |
52 53 | import lombok.RequiredArgsConstructor; |
53 54 | import org.apache.commons.io.FileUtils; |
54 55 | import org.apache.commons.io.output.TeeOutputStream; |
56 + | import org.eclipse.jgit.api.AddCommand; |
57 + | import org.eclipse.jgit.api.FetchCommand; |
55 58 | import org.eclipse.jgit.api.Git; |
56 59 | import org.eclipse.jgit.api.ResetCommand; |
57 60 | import org.eclipse.jgit.api.errors.GitAPIException; |
61 + | import org.eclipse.jgit.lib.CoreConfig; |
62 + | import org.eclipse.jgit.lib.Repository; |
63 + | import org.eclipse.jgit.lib.StoredConfig; |
58 64 | import org.eclipse.jgit.revwalk.RevCommit; |
65 + | import org.eclipse.jgit.transport.RefSpec; |
66 + | import org.eclipse.jgit.transport.RemoteConfig; |
67 + | import org.eclipse.jgit.transport.TagOpt; |
68 + | import org.eclipse.jgit.transport.URIish; |
59 69 | |
60 70 | public class Builder |
61 71 | { |
62 72 | |
63 73 | public static final String LOG_FILE = "BuildTools.log.txt"; |
64 74 | public static final boolean IS_WINDOWS = System.getProperty( "os.name" ).startsWith( "Windows" ); |
65 75 | public static final File CWD = new File( "." ); |
66 76 | private static boolean dontUpdate; |
67 77 | private static boolean skipCompile; |
68 78 | private static boolean generateSource; |
69 79 | private static boolean generateDocs; |
70 80 | private static boolean dev; |
81 + | private static boolean bash; |
71 82 | |
72 83 | public static void main(String[] args) throws Exception |
73 84 | { |
74 85 | // May be null |
75 86 | String buildVersion = Builder.class.getPackage().getImplementationVersion(); |
76 87 | int buildNumber = -1; |
77 88 | if ( buildVersion != null ) |
78 89 | { |
79 90 | String[] split = buildVersion.split( "-" ); |
80 91 | if ( split.length == 4 ) |
90 101 | System.out.println( "Loading BuildTools version: " + buildVersion + " (#" + buildNumber + ")" ); |
91 102 | |
92 103 | OptionParser parser = new OptionParser(); |
93 104 | OptionSpec<Void> disableCertFlag = parser.accepts( "disable-certificate-check" ); |
94 105 | OptionSpec<Void> dontUpdateFlag = parser.accepts( "dont-update" ); |
95 106 | OptionSpec<Void> skipCompileFlag = parser.accepts( "skip-compile" ); |
96 107 | OptionSpec<Void> generateSourceFlag = parser.accepts( "generate-source" ); |
97 108 | OptionSpec<Void> generateDocsFlag = parser.accepts( "generate-docs" ); |
98 109 | OptionSpec<Void> devFlag = parser.accepts( "dev" ); |
99 110 | OptionSpec<String> jenkinsVersion = parser.accepts( "rev" ).withRequiredArg().defaultsTo( "latest" ); |
111 + | OptionSpec<Void> bashFlag = parser.accepts( "bash" ); |
100 112 | |
101 113 | OptionSet options = parser.parse( args ); |
102 114 | |
103 115 | if ( options.has( disableCertFlag ) ) |
104 116 | { |
105 117 | disableHttpsCertificateCheck(); |
106 118 | } |
107 119 | dontUpdate = options.has( dontUpdateFlag ); |
108 120 | skipCompile = options.has( skipCompileFlag ); |
109 121 | generateSource = options.has( generateSourceFlag ); |
110 122 | generateDocs = options.has( generateDocsFlag ); |
111 123 | dev = options.has( devFlag ); |
124 + | bash = options.has( bashFlag ); |
112 125 | |
113 126 | logOutput(); |
114 127 | |
115 128 | if ( Float.parseFloat( System.getProperty( "java.class.version" ) ) < 51.0 ) |
116 129 | { |
117 130 | System.err.println( "*** WARNING *** You are not using Java 7 or above. Although this will work, it is highly discouraged due to the security issues present." ); |
118 131 | System.err.println( "*** WARNING *** Use java -version to check your version and update as soon as possible." ); |
119 132 | } |
120 133 | |
121 - | try |
122 - | { |
123 - | runProcess( CWD, "bash", "-c", "exit" ); |
124 - | } catch ( Exception ex ) |
125 - | { |
126 - | System.out.println( "You must run this jar through bash (msysgit)" ); |
127 - | System.exit( 1 ); |
128 - | } |
129 - | |
130 - | try |
131 - | { |
132 - | runProcess( CWD, "git", "config", "--global", "user.name" ); |
133 - | } catch ( Exception ex ) |
134 - | { |
135 - | System.out.println( "Git name not set, setting it to default value." ); |
136 - | runProcess( CWD, "git", "config", "--global", "user.name", "BuildTools" ); |
137 - | } |
138 - | try |
139 - | { |
140 - | runProcess( CWD, "git", "config", "--global", "user.email" ); |
141 - | } catch ( Exception ex ) |
142 - | { |
143 - | System.out.println( "Git email not set, setting it to default value." ); |
144 - | runProcess( CWD, "git", "config", "--global", "user.email", "unconfigured@null.spigotmc.org" ); |
145 - | } |
146 134 | |
147 135 | File workDir = new File( "work" ); |
148 136 | workDir.mkdir(); |
149 137 | |
150 138 | File bukkit = new File( "Bukkit" ); |
151 139 | if ( !bukkit.exists() ) |
152 140 | { |
153 141 | clone( "https://hub.spigotmc.org/stash/scm/spigot/bukkit.git", bukkit ); |
154 142 | } |
155 143 | |
164 152 | { |
165 153 | clone( "https://hub.spigotmc.org/stash/scm/spigot/spigot.git", spigot ); |
166 154 | } |
167 155 | |
168 156 | File buildData = new File( "BuildData" ); |
169 157 | if ( !buildData.exists() ) |
170 158 | { |
171 159 | clone( "https://hub.spigotmc.org/stash/scm/spigot/builddata.git", buildData ); |
172 160 | } |
173 161 | |
174 - | File maven = new File( "apache-maven-3.2.3" ); |
175 - | if ( !maven.exists() ) |
176 - | { |
177 - | System.out.println( "Maven does not exist, downloading. Please wait." ); |
178 - | |
179 - | File mvnTemp = new File( "mvn.zip" ); |
180 - | mvnTemp.deleteOnExit(); |
181 - | |
182 - | download( "http://static.spigotmc.org/maven/apache-maven-3.2.3-bin.zip", mvnTemp ); |
183 - | unzip( mvnTemp, new File( "." ) ); |
184 - | } |
185 - | |
186 - | String mvn = maven.getAbsolutePath() + "/bin/mvn"; |
187 - | |
188 162 | Git bukkitGit = Git.open( bukkit ); |
189 163 | Git craftBukkitGit = Git.open( craftBukkit ); |
190 164 | Git spigotGit = Git.open( spigot ); |
191 165 | Git buildGit = Git.open( buildData ); |
192 166 | |
193 167 | BuildInfo buildInfo = new BuildInfo( "Dev Build", "Development", 0, new BuildInfo.Refs( "master", "master", "master", "master" ) ); |
194 168 | |
195 169 | if ( !dontUpdate ) |
196 170 | { |
197 171 | if ( !dev ) |
268 242 | |
269 243 | runProcess( CWD, "java", "-jar", "BuildData/bin/SpecialSource-2.jar", "map", "-i", vanillaJar.getPath(), "-m", "BuildData/mappings/" + versionInfo.getClassMappings(), "-o", clMappedJar.getPath() ); |
270 244 | |
271 245 | runProcess( CWD, "java", "-jar", "BuildData/bin/SpecialSource-2.jar", "map", "-i", clMappedJar.getPath(), |
272 246 | "-m", "BuildData/mappings/" + versionInfo.getMemberMappings(), "-o", mMappedJar.getPath() ); |
273 247 | |
274 248 | runProcess( CWD, "java", "-jar", "BuildData/bin/SpecialSource.jar", "-i", mMappedJar.getPath(), "--access-transformer", "BuildData/mappings/" + versionInfo.getAccessTransforms(), |
275 249 | "-m", "BuildData/mappings/" + versionInfo.getPackageMappings(), "-o", finalMappedJar.getPath() ); |
276 250 | } |
277 251 | |
278 - | runProcess( CWD, "sh", mvn, "install:install-file", "-Dfile=" + finalMappedJar, "-Dpackaging=jar", "-DgroupId=org.spigotmc", |
252 + | maven( CWD, "install:install-file", "-Dfile=" + finalMappedJar, "-Dpackaging=jar", "-DgroupId=org.spigotmc", |
279 253 | "-DartifactId=minecraft-server", "-Dversion=" + versionInfo.getMinecraftVersion() + "-SNAPSHOT" ); |
280 254 | |
281 255 | File decompileDir = new File( workDir, "decompile-" + mappingsVersion ); |
282 256 | if ( !decompileDir.exists() ) |
283 257 | { |
284 258 | decompileDir.mkdir(); |
285 259 | |
286 260 | File clazzDir = new File( decompileDir, "classes" ); |
287 261 | unzip( finalMappedJar, clazzDir, new Predicate<String>() |
288 262 | { |
289 263 | |
290 264 | |
291 265 | public boolean apply(String input) |
292 266 | { |
293 267 | return input.startsWith( "net/minecraft/server" ); |
294 268 | } |
295 269 | } ); |
296 270 | |
297 - | runProcess( CWD, "java", "-jar", "BuildData/bin/fernflower.jar", "-dgs=1", "-hdc=0", "-rbr=0", "-asc=1", "-udv=0", clazzDir.getPath(), decompileDir.getPath() ); |
271 + | runProcess( CWD, "java", "-jar", "BuildData/bin/fernflower.jar", "-dgs=1", "-hdc=0", "-rbr=0", "-asc=1", "-udv=0", "-nls=1", clazzDir.getPath(), decompileDir.getPath() ); |
298 272 | } |
299 273 | |
300 274 | System.out.println( "Applying CraftBukkit Patches" ); |
301 275 | File nmsDir = new File( craftBukkit, "src/main/java/net" ); |
302 276 | if ( nmsDir.exists() ) |
303 277 | { |
304 278 | System.out.println( "Backing up NMS dir" ); |
305 279 | FileUtils.moveDirectory( nmsDir, new File( workDir, "nms.old." + System.currentTimeMillis() ) ); |
306 280 | } |
281 + | System.setProperty( "line.separator", "\n" ); |
307 282 | File patchDir = new File( craftBukkit, "nms-patches" ); |
308 283 | for ( File file : patchDir.listFiles() ) |
309 284 | { |
310 285 | String targetFile = "net/minecraft/server/" + file.getName().replaceAll( ".patch", ".java" ); |
311 286 | |
312 287 | File clean = new File( decompileDir, targetFile ); |
313 288 | File t = new File( nmsDir.getParentFile(), targetFile ); |
314 289 | t.getParentFile().mkdirs(); |
315 290 | |
316 291 | System.out.println( "Patching with " + file.getName() ); |
363 338 | if ( !spigotServer.exists() ) |
364 339 | { |
365 340 | clone( "file://" + craftBukkit.getAbsolutePath(), spigotServer ); |
366 341 | } |
367 342 | |
368 343 | // Git spigotApiGit = Git.open( spigotApi ); |
369 344 | // Git spigotServerGit = Git.open( spigotServer ); |
370 345 | if ( !skipCompile ) |
371 346 | { |
372 347 | System.out.println( "Compiling Bukkit" ); |
373 - | runProcess( bukkit, "sh", mvn, "clean", "install" ); |
348 + | maven( bukkit, "clean", "install" ); |
374 349 | if ( generateDocs ) |
375 350 | { |
376 - | runProcess( bukkit, "sh", mvn, "javadoc:jar" ); |
351 + | maven( bukkit, "javadoc:jar" ); |
377 352 | } |
378 353 | if ( generateSource ) |
379 354 | { |
380 - | runProcess( bukkit, "sh", mvn, "source:jar" ); |
355 + | maven( bukkit, "source:jar" ); |
381 356 | } |
382 357 | |
383 358 | System.out.println( "Compiling CraftBukkit" ); |
384 - | runProcess( craftBukkit, "sh", mvn, "clean", "install" ); |
359 + | maven( craftBukkit, "clean", "install" ); |
385 360 | } |
386 361 | |
387 362 | try |
388 363 | { |
389 - | runProcess( spigot, "bash", "applyPatches.sh" ); |
364 + | if (!bash) |
365 + | { |
366 + | applyPatches( |
367 + | bukkit, |
368 + | spigotApi, |
369 + | new File( spigot, "Spigot-API" ), |
370 + | new File( spigot, "Bukkit-Patches" ), |
371 + | "master" |
372 + | ); |
373 + | applyPatches( |
374 + | craftBukkit, |
375 + | spigotServer, |
376 + | new File( spigot, "Spigot-Server" ), |
377 + | new File( spigot, "CraftBukkit-Patches" ), |
378 + | "patched" |
379 + | ); |
380 + | } else |
381 + | { |
382 + | runProcess( spigot, "bash", "applyPatches.sh" ); |
383 + | } |
390 384 | System.out.println( "*** Spigot patches applied!" ); |
391 385 | System.out.println( "Compiling Spigot & Spigot-API" ); |
392 386 | |
393 387 | if ( !skipCompile ) |
394 388 | { |
395 - | runProcess( spigot, "sh", mvn, "clean", "install" ); |
389 + | maven( spigot, "clean", "install" ); |
396 390 | } |
397 391 | } catch ( Exception ex ) |
398 392 | { |
399 393 | System.err.println( "Error compiling Spigot, are you running this jar via msysgit?" ); |
400 394 | ex.printStackTrace(); |
401 395 | System.exit( 1 ); |
402 396 | } |
403 397 | |
404 398 | for ( int i = 0; i < 35; i++ ) |
405 399 | { |
406 400 | System.out.println( " " ); |
407 401 | } |
408 402 | System.out.println( "Success! Everything compiled successfully. Copying final .jar files now." ); |
409 403 | copyJar( "CraftBukkit/target", "craftbukkit", "craftbukkit-" + versionInfo.getMinecraftVersion() + ".jar" ); |
410 404 | copyJar( "Spigot/Spigot-Server/target", "spigot", "spigot-" + versionInfo.getMinecraftVersion() + ".jar" ); |
411 405 | } |
412 406 | |
407 + | public static void applyPatches(File base, File orig, File target, File patches, String branch) throws Exception |
408 + | { |
409 + | System.out.println( "Applying patches to " + target ); |
410 + | Git gitOrig = Git.open( orig ); |
411 + | |
412 + | gitOrig.fetch() |
413 + | .setRemote( "file://" + base.getAbsolutePath() ) |
414 + | .setRefSpecs( new RefSpec( "refs/heads/*:refs/remotes/origin/*" ) ) |
415 + | .call(); |
416 + | gitOrig.reset() |
417 + | .setRef( "origin/" + branch ) |
418 + | .setMode( ResetCommand.ResetType.HARD ) |
419 + | .call(); |
420 + | gitOrig.branchCreate() |
421 + | .setName( "upstream" ) |
422 + | .setForce( true ) |
423 + | .call(); |
424 + | |
425 + | clone( orig.toURI().toString(), target ); |
426 + | Git git = Git.open( target ); |
427 + | |
428 + | StoredConfig config = git.getRepository().getConfig(); |
429 + | config.setString( "remote", "upstream", "url", "file://" + orig.getAbsolutePath() ); |
430 + | config.save(); |
431 + | |
432 + | git.branchCreate() |
433 + | .setName( "master" ) |
434 + | .setForce( true ) |
435 + | .call(); |
436 + | git.checkout() |
437 + | .setName( "master" ) |
438 + | .call(); |
439 + | git.fetch() |
440 + | .setRemote( "upstream" ) |
441 + | .setRefSpecs( new RefSpec( "refs/heads/*:refs/remotes/upstream/*" ) ) |
442 + | .call(); |
443 + | git.reset() |
444 + | .setRef( "refs/remotes/upstream/upstream" ) |
445 + | .setMode( ResetCommand.ResetType.HARD ) |
446 + | .call(); |
447 + | git.clean().setCleanDirectories( true ).call(); |
448 + | |
449 + | File[] ps = patches.listFiles(); |
450 + | Arrays.sort( ps ); |
451 + | for ( File patch : ps ) |
452 + | { |
453 + | if ( !patch.getName().endsWith( ".patch" ) ) continue; |
454 + | System.out.println( "Applying " + patch.getName() ); |
455 + | |
456 + | String patchTxt = Files.toString( patch, Charsets.UTF_8 ); |
457 + | patchTxt = patchTxt.replaceAll( "\r", "" ); |
458 + | byte[] bytes = patchTxt.getBytes( Charsets.UTF_8 ); |
459 + | List<File> files = git.apply() |
460 + | .setPatch( new ByteArrayInputStream( bytes ) ) |
461 + | .call().getUpdatedFiles(); |
462 + | AddCommand add = git.add(); |
463 + | for (File file : files) |
464 + | { |
465 + | add.addFilepattern( target.toURI().relativize( file.toURI() ).getPath() ); |
466 + | } |
467 + | add.call(); |
468 + | SpigotPatch spigotPatch = new SpigotPatch( patch ); |
469 + | git.commit() |
470 + | .setAuthor( spigotPatch.getAuthor() ) |
471 + | .setMessage( spigotPatch.getMessage() ) |
472 + | .call(); |
473 + | } |
474 + | } |
475 + | |
413 476 | public static final String get(String url) throws IOException |
414 477 | { |
415 478 | URLConnection con = new URL( url ).openConnection(); |
416 479 | con.setConnectTimeout( 5000 ); |
417 480 | con.setReadTimeout( 5000 ); |
418 481 | |
419 482 | InputStreamReader r = null; |
420 483 | try |
421 484 | { |
422 485 | r = new InputStreamReader( con.getInputStream() ); |
459 522 | System.out.println( "Successfully fetched updates!" ); |
460 523 | |
461 524 | repo.reset().setRef( ref ).setMode( ResetCommand.ResetType.HARD ).call(); |
462 525 | if ( ref.equals( "master" ) ) |
463 526 | { |
464 527 | repo.reset().setRef( "origin/master" ).setMode( ResetCommand.ResetType.HARD ).call(); |
465 528 | } |
466 529 | System.out.println( "Checked out: " + ref ); |
467 530 | } |
468 531 | |
532 + | public static int maven(File workDir, String... command) throws Exception |
533 + | { |
534 + | File maven = new File( "apache-maven-3.2.3" ); |
535 + | if ( !maven.exists() ) |
536 + | { |
537 + | System.out.println( "Maven does not exist, downloading. Please wait." ); |
538 + | |
539 + | File mvnTemp = new File( "mvn.zip" ); |
540 + | mvnTemp.deleteOnExit(); |
541 + | |
542 + | download( "http://static.spigotmc.org/maven/apache-maven-3.2.3-bin.zip", mvnTemp ); |
543 + | unzip( mvnTemp, new File( "." ) ); |
544 + | } |
545 + | |
546 + | String mvn = maven.getAbsolutePath() + "/bin/mvn"; |
547 + | |
548 + | int extra = 2; |
549 + | if ( IS_WINDOWS ) |
550 + | { |
551 + | extra = 1; |
552 + | } |
553 + | |
554 + | String[] args = new String[ extra + command.length ]; |
555 + | |
556 + | if ( IS_WINDOWS ) { |
557 + | args[ 0 ] = mvn + ".bat"; |
558 + | } else |
559 + | { |
560 + | args[ 0 ] = "sh"; |
561 + | args[ 1 ] = mvn; |
562 + | } |
563 + | System.arraycopy( command, 0, args, extra, command.length ); |
564 + | return runProcess( workDir, args ); |
565 + | } |
566 + | |
469 567 | public static int runProcess(File workDir, String... command) throws Exception |
470 568 | { |
471 569 | ProcessBuilder pb = new ProcessBuilder( command ); |
472 570 | pb.directory( workDir ); |
473 571 | pb.environment().put( "JAVA_HOME", System.getProperty( "java.home" ) ); |
474 572 | if ( !pb.environment().containsKey( "MAVEN_OPTS" ) ) |
475 573 | { |
476 574 | pb.environment().put( "MAVEN_OPTS", "-Xmx1024M" ); |
477 575 | } |
478 576 | |
558 656 | } finally |
559 657 | { |
560 658 | is.close(); |
561 659 | os.close(); |
562 660 | } |
563 661 | |
564 662 | System.out.println( "Extracted: " + outFile ); |
565 663 | } |
566 664 | } |
567 665 | |
568 - | public static void clone(String url, File target) throws GitAPIException |
666 + | public static void clone(String url, File target) throws Exception |
569 667 | { |
570 668 | System.out.println( "Starting clone of " + url + " to " + target ); |
571 669 | |
572 - | Git result = Git.cloneRepository().setURI( url ).setDirectory( target ).call(); |
670 + | // Git result = Git.cloneRepository().setURI( url ).setDirectory( target ).call(); |
671 + | Repository repo = Git.init().setDirectory( target ).call().getRepository(); |
672 + | StoredConfig c = repo.getConfig(); |
673 + | if (c.getString( "user", null, "name" ) == null) |
674 + | { |
675 + | c.setString( "user", null, "name", "BuildTools" ); |
676 + | } |
677 + | if (c.getString( "user", null, "email" ) == null) |
678 + | { |
679 + | c.setString( "user", null, "email", "unconfigured@null.spigotmc.org" ); |
680 + | } |
681 + | c.setEnum( "core", null, "autocrlf", CoreConfig.AutoCRLF.FALSE ); |
682 + | URIish u = new URIish( url ); |
683 + | RemoteConfig config = new RemoteConfig( repo.getConfig(), "origin" ); |
684 + | config.addURI( u ); |
685 + | String dst = "refs/remotes/" + config.getName() + "/*"; |
686 + | RefSpec spec = new RefSpec(); |
687 + | spec = spec.setForceUpdate( true ); |
688 + | spec = spec.setSourceDestination( "refs/heads/*", dst ); |
689 + | |
690 + | config.addFetchRefSpec( spec ); |
691 + | config.update( c ); |
692 + | c.save(); |
693 + | |
694 + | Git result = new Git( repo ); |
695 + | result.fetch() |
696 + | .setRemote( "origin" ) |
697 + | .setTagOpt( TagOpt.FETCH_TAGS ) |
698 + | .call(); |
699 + | |
700 + | result.branchCreate() |
701 + | .setForce( true ) |
702 + | .setStartPoint( "origin/master" ) |
703 + | .setName( "master" ) |
704 + | .call(); |
705 + | |
706 + | result.checkout() |
707 + | .setForce( true ) |
708 + | .setStartPoint( "origin/master" ) |
709 + | .setName( "master" ) |
710 + | .call(); |
573 711 | |
574 712 | try |
575 713 | { |
576 714 | System.out.println( "Cloned git repository " + url + " to " + target.getAbsolutePath() + ". Current HEAD: " + commitHash( result ) ); |
577 715 | |
578 716 | } finally |
579 717 | { |
580 718 | result.close(); |
581 719 | } |
582 720 | } |