diff options
author | md_5 <git@md-5.net> | 2014-11-26 16:56:48 +1100 |
---|---|---|
committer | md_5 <git@md-5.net> | 2014-11-28 17:10:15 +1100 |
commit | 032e8ca0a3a2fd6059308ca43083df986467b99e (patch) | |
tree | 29a154dcfab98c5390ef6502c604509b884ea2d8 | |
download | buildtools-032e8ca0a3a2fd6059308ca43083df986467b99e.tar buildtools-032e8ca0a3a2fd6059308ca43083df986467b99e.tar.gz buildtools-032e8ca0a3a2fd6059308ca43083df986467b99e.tar.lz buildtools-032e8ca0a3a2fd6059308ca43083df986467b99e.tar.xz buildtools-032e8ca0a3a2fd6059308ca43083df986467b99e.zip |
Initial Commit
For more information please see http://www.spigotmc.org/
-rw-r--r-- | .gitignore | 35 | ||||
-rw-r--r-- | LICENSE | 26 | ||||
-rw-r--r-- | nb-configuration.xml | 31 | ||||
-rw-r--r-- | pom.xml | 107 | ||||
-rw-r--r-- | src/main/java/org/spigotmc/builder/Builder.java | 411 |
5 files changed, 610 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ae51bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Eclipse stuff +.classpath +.project +.settings/ + +# netbeans +nbproject/ +nbactions.xml + +# we use maven! +build.xml + +# maven +target/ +dependency-reduced-pom.xml + +# vim +.*.sw[a-p] + +# various other potential build files +build/ +bin/ +dist/ +manifest.mf + +# Mac filesystem dust +.DS_Store/ + +# intellij +*.iml +*.ipr +*.iws +.idea/ + +out
\ No newline at end of file @@ -0,0 +1,26 @@ +Copyright (c) 2014, SpigotMC. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +The name of the author may not be used to endorse or promote products derived +from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/nb-configuration.xml b/nb-configuration.xml new file mode 100644 index 0000000..7e46592 --- /dev/null +++ b/nb-configuration.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project-shared-configuration> + <!-- + This file contains additional configuration written by modules in the NetBeans IDE. + The configuration is intended to be shared among all the users of project and + therefore it is assumed to be part of version control checkout. + Without this configuration present, some functionality in the IDE may be limited or fail altogether. + --> + <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1"> + <!-- + Properties that influence various parts of the IDE, especially code formatting and the like. + You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up. + That way multiple projects can share the same settings (useful for formatting rules for example). + Any value defined here will override the pom.xml file value but is only applicable to the current project. + --> + <org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens> + <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens> + </properties> +</project-shared-configuration> @@ -0,0 +1,107 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <groupId>org.spigotmc</groupId> + <artifactId>builder</artifactId> + <packaging>jar</packaging> + <version>1.0-SNAPSHOT</version> + + <name>BuildTools</name> + <description></description> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>com.custardsource.dybdob</groupId> + <artifactId>java-diff-utils-copy</artifactId> + <version>1.0.1</version> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>18.0</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>net.sf.jopt-simple</groupId> + <artifactId>jopt-simple</artifactId> + <version>4.7</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jgit</groupId> + <artifactId>org.eclipse.jgit</artifactId> + <version>3.3.2.201404171909-r</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.14.8</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + </dependency> + </dependencies> + + <build> + <finalName>${project.name}</finalName> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.6</source> + <target>1.6</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>2.5</version> + <configuration> + <archive> + <manifestEntries> + <Main-Class>org.spigotmc.builder.Builder</Main-Class> + </manifestEntries> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>2.3</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + </execution> + </executions> + <configuration> + <filters> + <filter> + <artifact>*:*</artifact> + <excludes> + <exclude>**/*.java</exclude> + <exclude>**/*.SF</exclude> + <exclude>**/*.DSA</exclude> + </excludes> + </filter> + </filters> + <minimizeJar>true</minimizeJar> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/src/main/java/org/spigotmc/builder/Builder.java b/src/main/java/org/spigotmc/builder/Builder.java new file mode 100644 index 0000000..c8248b4 --- /dev/null +++ b/src/main/java/org/spigotmc/builder/Builder.java @@ -0,0 +1,411 @@ +package org.spigotmc.builder; + +import com.google.common.base.Charsets; +import com.google.common.base.Predicate; +import com.google.common.base.Throwables; +import com.google.common.collect.Iterables; +import com.google.common.hash.Hasher; +import com.google.common.hash.Hashing; +import com.google.common.io.ByteStreams; +import com.google.common.io.Files; +import com.google.common.io.Resources; +import difflib.DiffUtils; +import difflib.Patch; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +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; +import java.net.URL; +import java.util.Date; +import java.util.Enumeration; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import lombok.RequiredArgsConstructor; +import org.apache.commons.io.FileUtils; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.ResetCommand; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.revwalk.RevCommit; + +public class Builder +{ + + public static final boolean IS_WINDOWS = System.getProperty( "os.name" ).startsWith( "Windows" ); + public static final boolean IS_MAC = System.getProperty( "os.name" ).startsWith( "Mac" ); + public static final File CWD = new File( "." ); + public static final String MC_VERSION = "1.8"; + + public static void main(String[] args) throws Exception + { + if ( IS_MAC ) + { + System.out.println( "Sorry, but Macintosh is not currently a supported platform for compilation at this time." ); + System.out.println( "Please run this script on a Windows or Linux PC and then copy the jars to this computer." ); + return; + } + + try + { + runProcess( "bash -c exit", CWD ); + } catch ( Exception ex ) + { + System.out.println( "You must run this jar through bash (msysgit)" ); + return; + } + + try + { + runProcess( "git config --global user.name", CWD ); + } catch ( Exception ex ) + { + System.out.println( "Git name not set, setting it to default value." ); + runProcess( "git config --global user.name BuildTools", CWD ); + } + try + { + runProcess( "git config --global user.email", CWD ); + } catch ( Exception ex ) + { + System.out.println( "Git email not set, setting it to default value." ); + runProcess( "git config --global user.email unconfigured@null.spigotmc.org", CWD ); + } + + File workDir = new File( "work" ); + workDir.mkdir(); + + File bukkit = new File( "Bukkit" ); + if ( !bukkit.exists() ) + { + clone( "https://hub.spigotmc.org/stash/scm/spigot/bukkit.git", bukkit ); + } + + File craftBukkit = new File( "CraftBukkit" ); + if ( !craftBukkit.exists() ) + { + clone( "https://hub.spigotmc.org/stash/scm/spigot/craftbukkit.git", craftBukkit ); + } + + File spigot = new File( "Spigot" ); + if ( !spigot.exists() ) + { + clone( "https://hub.spigotmc.org/stash/scm/spigot/spigot.git", spigot ); + } + + File buildData = new File( "BuildData" ); + if ( !buildData.exists() ) + { + clone( "https://hub.spigotmc.org/stash/scm/spigot/builddata.git", buildData ); + } + + File maven = new File( "apache-maven-3.2.3" ); + if ( !maven.exists() ) + { + System.out.println( "Maven does not exist, downloading. Please wait." ); + + File mvnTemp = new File( "mvn.zip" ); + mvnTemp.deleteOnExit(); + + download( "http://static.spigotmc.org/maven/apache-maven-3.2.3-bin.zip", mvnTemp ); + unzip( mvnTemp, new File( "." ) ); + } + + String mvnCmd = maven.getAbsolutePath() + "/bin/mvn"; + if ( IS_WINDOWS ) + { + mvnCmd += ".bat"; + } else + { + mvnCmd = "/bin/sh " + mvnCmd; + } + + Git bukkitGit = Git.open( bukkit ); + Git craftBukkitGit = Git.open( craftBukkit ); + Git spigotGit = Git.open( spigot ); + Git buildGit = Git.open( buildData ); + + pull( bukkitGit ); + pull( craftBukkitGit ); + pull( spigotGit ); + pull( buildGit ); + + File vanillaJar = new File( workDir, "minecraft_server." + MC_VERSION + ".jar" ); + if ( !vanillaJar.exists() ) + { + download( String.format( "https://s3.amazonaws.com/Minecraft.Download/versions/%1$s/minecraft_server.%1$s.jar", MC_VERSION ), vanillaJar ); + } + + Iterable<RevCommit> mappings = buildGit.log() + .addPath( "mappings/bukkit-1.8.at" ) + .addPath( "mappings/bukkit-1.8-cl.csrg" ) + .addPath( "mappings/bukkit-1.8-members.csrg" ) + .addPath( "mappings/package.srg" ) + .setMaxCount( 1 ).call(); + + Hasher mappingsHash = Hashing.md5().newHasher(); + for ( RevCommit rev : mappings ) + { + mappingsHash.putString( rev.getName(), Charsets.UTF_8 ); + } + String mappingsVersion = mappingsHash.hash().toString().substring( 24 ); // Last 8 chars + + File finalMappedJar = new File( workDir, "mapped." + mappingsVersion + ".jar" ); + if ( !finalMappedJar.exists() ) + { + System.out.println( "Final mapped jar: " + finalMappedJar + " does not exist, creating!" ); + + File clMappedJar = new File( finalMappedJar + "-cl" ); + File mMappedJar = new File( finalMappedJar + "-m" ); + + runProcess( "java -jar BuildData/bin/SpecialSource.jar -i " + vanillaJar + " -m BuildData/mappings/bukkit-1.8-cl.csrg -o " + clMappedJar, CWD ); + runProcess( "java -jar BuildData/bin/SpecialSource-2.jar map -i " + clMappedJar + " -m " + "BuildData/mappings/bukkit-1.8-members.csrg -o " + mMappedJar, CWD ); + runProcess( "java -jar BuildData/bin/SpecialSource.jar -i " + mMappedJar + " --access-transformer BuildData/mappings/bukkit-1.8.at " + + "-m BuildData/mappings/package.srg -o " + finalMappedJar, CWD ); + } + + runProcess( mvnCmd + " install:install-file -Dfile=" + finalMappedJar + " -Dpackaging=jar -DgroupId=org.spigotmc -DartifactId=minecraft-server -Dversion=1.8-SNAPSHOT", CWD ); + + File decompileDir = new File( workDir, "decompile-" + mappingsVersion ); + if ( !decompileDir.exists() ) + { + decompileDir.mkdir(); + + File clazzDir = new File( decompileDir, "classes" ); + unzip( finalMappedJar, clazzDir, new Predicate<String>() + { + + @Override + public boolean apply(String input) + { + return input.startsWith( "net/minecraft/server" ); + } + } ); + + runProcess( "java -jar BuildData/bin/fernflower.jar -dgs=1 -hdc=0 -rbr=0 -asc=1 " + clazzDir + " " + decompileDir, CWD ); + + String jacobePath = "BuildData/bin/jacobe"; + if ( IS_WINDOWS ) + { + jacobePath += ".exe"; + } + runProcess( jacobePath + " -cfg=BuildData/bin/jacobe.cfg -nobackup -overwrite -outext=java " + decompileDir + "/net/minecraft/server", CWD ); + } + + 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() ) ); + } + File patchDir = new File( craftBukkit, "nms-patches" ); + for ( File file : patchDir.listFiles() ) + { + String targetFile = "net/minecraft/server/" + file.getName().replaceAll( ".patch", ".java" ); + + File clean = new File( decompileDir, targetFile ); + File t = new File( nmsDir.getParentFile(), targetFile ); + t.getParentFile().mkdirs(); + + System.out.println( "Patching with " + file.getName() ); + + Patch parsedPatch = DiffUtils.parseUnifiedDiff( Files.readLines( file, Charsets.UTF_8 ) ); + List<?> modifiedLines = DiffUtils.patch( Files.readLines( clean, Charsets.UTF_8 ), parsedPatch ); + + BufferedWriter bw = new BufferedWriter( new FileWriter( t ) ); + for ( String line : (List<String>) modifiedLines ) + { + bw.write( line ); + bw.newLine(); + } + bw.close(); + } + File tmpNms = new File( craftBukkit, "tmp-nms" ); + FileUtils.copyDirectory( nmsDir, tmpNms ); + + craftBukkitGit.branchDelete().setBranchNames( "patched" ).setForce( true ).call(); + craftBukkitGit.checkout().setCreateBranch( true ).setForce( true ).setName( "patched" ).call(); + craftBukkitGit.add().addFilepattern( "src/main/java/net/" ).call(); + craftBukkitGit.commit().setMessage( "CraftBukkit $ " + new Date() ).call(); + craftBukkitGit.checkout().setName( "master" ).call(); + + FileUtils.moveDirectory( tmpNms, nmsDir ); + + 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 ); + } + + // Git spigotApiGit = Git.open( spigotApi ); + // Git spigotServerGit = Git.open( spigotServer ); + System.out.println( "Compiling Bukkit" ); + runProcess( mvnCmd + " clean install", bukkit ); + + System.out.println( "Compiling CraftBukkit" ); + runProcess( mvnCmd + " clean install", craftBukkit ); + + try + { + runProcess( "bash applyPatches.sh", spigot ); + System.out.println( "*** Spigot patches applied!" ); + System.out.println( "Compiling Spigot & Spigot-API" ); + runProcess( mvnCmd + " clean install", spigot ); + } catch ( Exception ex ) + { + System.err.println( "Error compiling Spigot, are you running this jar via msysgit?" ); + ex.printStackTrace(); + } + } + + public static void pull(Git repo) throws Exception + { + System.out.println( "Pulling updates for " + repo.getRepository().getDirectory() ); + + repo.reset().setRef( "origin/master" ).setMode( ResetCommand.ResetType.HARD ).call(); + boolean result = repo.pull().call().isSuccessful(); + + if ( !result ) + { + throw new RuntimeException( "Could not pull updates!" ); + } + + System.out.println( "Successfully pulled updates!" ); + } + + public static int runProcess(String command, File workDir) throws Exception + { + final Process ps = new ProcessBuilder( command.split( " " ) ).directory( workDir ).start(); + + new Thread( new StreamRedirector( ps.getInputStream(), System.out ) ).start(); + new Thread( new StreamRedirector( ps.getErrorStream(), System.err ) ).start(); + + int status = ps.waitFor(); + + if ( status != 0 ) + { + throw new RuntimeException( "Error running command, return status !=0: " + command ); + } + + return status; + } + + @RequiredArgsConstructor + private static class StreamRedirector implements Runnable + { + + private final InputStream in; + private final PrintStream out; + + @Override + public void run() + { + BufferedReader br = new BufferedReader( new InputStreamReader( in ) ); + try + { + String line; + while ( ( line = br.readLine() ) != null ) + { + out.println( line ); + } + } catch ( IOException ex ) + { + throw Throwables.propagate( ex ); + } + } + } + + 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(); + ZipFile zip = new ZipFile( zipFile ); + + for ( Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements(); ) + { + ZipEntry entry = entries.nextElement(); + + if ( filter != null ) + { + if ( !filter.apply( entry.getName() ) ) + { + continue; + } + } + + File outFile = new File( targetFolder, entry.getName() ); + + if ( entry.isDirectory() ) + { + outFile.mkdirs(); + continue; + } + if ( outFile.getParentFile() != null ) + { + outFile.getParentFile().mkdirs(); + } + + InputStream is = zip.getInputStream( entry ); + OutputStream os = new FileOutputStream( outFile ); + try + { + ByteStreams.copy( is, os ); + } finally + { + is.close(); + os.close(); + } + + System.out.println( "Extracted: " + outFile ); + } + } + + public static void clone(String url, File target) throws GitAPIException + { + System.out.println( "Starting clone of " + url + " to " + target ); + + Git result = Git.cloneRepository().setURI( url ).setDirectory( target ).call(); + + try + { + System.out.println( "Cloned git repository " + url + " to " + url + ". Current HEAD: " + commitHash( result ) ); + + } finally + { + result.close(); + } + } + + public static String commitHash(Git repo) throws GitAPIException + { + return Iterables.getOnlyElement( repo.log().setMaxCount( 1 ).call() ).getName(); + } + + public static File download(String url, File target) throws IOException + { + System.out.println( "Starting download of " + url ); + + byte[] bytes = Resources.toByteArray( new URL( url ) ); + + System.out.println( "Downloaded file: " + target + " with md5: " + Hashing.md5().hashBytes( bytes ).toString() ); + + Files.write( bytes, target ); + + return target; + } +} |