Created
May 24, 2015 22:14
-
-
Save mattmess1221/873638de33e0c378043e to your computer and use it in GitHub Desktop.
Groovy port of ForgeGradle's BasePlugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.minecraftforge.groodle.common | |
import static net.minecraftforge.gradle.common.Constants.* | |
import java.lang.reflect.ParameterizedType | |
import net.minecraftforge.gradle.common.BaseExtension | |
import net.minecraftforge.gradle.common.Constants | |
import net.minecraftforge.gradle.tasks.CrowdinDownload | |
import net.minecraftforge.gradle.tasks.Download | |
import net.minecraftforge.gradle.tasks.DownloadAssetsTask | |
import net.minecraftforge.gradle.tasks.EtagDownloadTask | |
import net.minecraftforge.gradle.tasks.ExtractConfigTask | |
import net.minecraftforge.gradle.tasks.GenSrgs | |
import net.minecraftforge.gradle.tasks.JenkinsChangelog | |
import net.minecraftforge.gradle.tasks.MergeJars | |
import net.minecraftforge.gradle.tasks.ObtainFernFlowerTask | |
import net.minecraftforge.gradle.tasks.SignJar | |
import net.minecraftforge.gradle.util.FileLogListenner | |
import net.minecraftforge.gradle.util.GradleConfigurationException | |
import net.minecraftforge.gradle.util.delayed.DelayedFile | |
import net.minecraftforge.gradle.util.delayed.DelayedFileTree | |
import net.minecraftforge.gradle.util.delayed.DelayedString | |
import net.minecraftforge.gradle.util.delayed.TokenReplacer | |
import net.minecraftforge.gradle.util.json.JsonFactory | |
import net.minecraftforge.gradle.util.json.version.Library | |
import net.minecraftforge.gradle.util.json.version.Version | |
import org.gradle.api.DefaultTask | |
import org.gradle.api.Plugin | |
import org.gradle.api.Project | |
import org.gradle.api.Task | |
import org.gradle.api.artifacts.Configuration | |
import org.gradle.api.artifacts.repositories.FlatDirectoryArtifactRepository | |
import org.gradle.api.artifacts.repositories.MavenArtifactRepository | |
import org.gradle.api.tasks.Delete | |
import org.gradle.testfixtures.ProjectBuilder | |
import com.google.common.base.Throwables | |
import com.google.common.cache.CacheBuilder | |
import com.google.common.cache.LoadingCache | |
import com.google.gson.reflect.TypeToken | |
abstract class BasePlugin<K extends BaseExtension> implements Plugin<Project> { | |
public Project project | |
public BasePlugin otherPlugin | |
@Override | |
final void apply(Project arg) { | |
project = arg | |
// check for gradle version | |
def split = project.gradle.gradleVersion.split(/\./) | |
def major = split[0].toInteger() | |
def minor = split[1].toInteger() | |
if (major <= 1 || (major == 2 && minor < 3)) | |
throw new RuntimeException("ForgeGradle 2.0 requires Gradle 2.3 or above.") | |
// search for overlays... | |
project.plugins.findAll {it.is BasePlugin }.each { | |
if (!canOverlayPlugin()) | |
throw new GradleConfigurationException("Seems you are trying to apply 2 ForgeGradle plugins that are not designed to overlay... Fix your buildscripts."); | |
project.logger.info 'Applying Overlay' | |
// found another BasePlugin that's already applied. | |
// do only overlay stuff and return | |
otherPlugin = it.with { | |
replacerCache = this.replacerCache | |
stringCache = this.stringCache | |
fileCache = this.fileCache | |
} | |
applyOverlayPlugin() | |
return | |
} | |
// logging | |
def projectCacheDir = project.gradle.startParameter.projectCacheDir | |
if (projectCacheDir == null) | |
projectCacheDir = new File(project.projectDir, '.gradle') | |
def listener = new FileLogListenner(new File(projectCacheDir, 'gradle.log')); | |
project.with { | |
logging.with { | |
standardOutputCaptureLevel += listener | |
standardErrorCaptureLevel += listener | |
} | |
gradle.addBuildListener listener | |
} | |
if (project.buildDir.absolutePath.contains('!')) | |
{ | |
project.logger.error 'Build path has !, This will screw over a lot of java things as ! is used to denote archive paths, REMOVE IT if you want to continue' | |
throw new RuntimeException('Build path contains !') | |
} | |
// set the obvious replacements | |
TokenReplacer.replaceMap << [ | |
REPLACE_CACHE_DIR:cacheFile('').absolutePath, | |
REPLACE_BUILD_DIR:project.buildDir.absolutePath | |
] | |
// extension objects | |
project.extensions.create EXT_NAME_MC, ((ParameterizedType)getClass().genericSuperclass).actualTypeArguments[0], this | |
// add buildscript usable tasks | |
project.extensions.extraProperties.set ( | |
"SignJar":SignJar, | |
"Download":Download, | |
"EtagDownload":EtagDownloadTask, | |
"CrowdinDownload":CrowdinDownload, | |
"JenkinsChangelog":JenkinsChangelog) | |
// repos | |
// TODO: move to userdev | |
project.allprojects{ Project proj -> | |
addMavenRepo proj, 'forge', URL_FORGE_MAVEN | |
proj.getRepositories().mavenCentral() | |
addMavenRepo proj, 'minecraft', URL_LIBRARY | |
} | |
// do Mcp Snapshot Stuff | |
setVersionInfoJson() | |
project.configurations{ | |
CONFIG_MCP_DATA | |
CONFIG_MAPPINGS | |
// set other configs | |
CONFIG_MC_DEPS | |
CONFIG_NATIVES | |
} | |
project.afterEvaluate { Project project -> | |
if (project.state.failure != null) return | |
this.afterEvaluate() | |
} | |
// some default tasks | |
makeCommonTasks() | |
// at last, apply the chind plugins | |
applyPlugin() | |
} | |
abstract void applyPlugin() | |
protected abstract void applyOverlayPlugin() | |
abstract boolean canOverlayPlugin() | |
private static boolean displayBanner = true | |
private void setVersionInfoJson() { | |
def jsonCache = cacheFile('McpMappings.json') | |
def etagFile = new File("${jsonCache.absolutePath}.etag") | |
extension.mcpJson = JsonFactory.GSON.fromJson(getWithEtag(URL_MCP_JSON, jsonCache, etagFile), new TypeToken<Map<String, Map<String, int[]>>>(){}.type) | |
} | |
protected void afterEvaluate() { | |
def mcVersion = delayedString(REPLACE_MC_VERSION)() | |
project.getDependencies.with { | |
add CONFIG_MAPPINGS, [ | |
group:'de.oceanlabs.mcp', | |
name: delayedString("mcp_$REPLACE_MCP_CHANNEL")(), | |
version:delayedString("$REPLACE_MCP_VERSION-$mcVersion")(), | |
ext:'zip' | |
] | |
add CONFIG_MCP_DATA, [ | |
group:'de.oceanlabs.mcp', | |
name:'mcp', | |
version:mcVersion, | |
classifier:'srg', | |
ext:'zip' | |
] | |
} | |
if (!displayBanner) return | |
project.logger.lifecycle """ | |
**************************** | |
Powered By MCP: | |
http://mcp.ocean-labs.de/ | |
Searge, ProfMobius, Fesh0r, | |
R4wk, ZeuX, IngisKahn, bspkrs | |
MCP Data Version: $extension.mcpVersion | |
**************************** | |
""" | |
displayBanner = false | |
} | |
private void makeCommonTasks() { | |
def dlClient = makeTask(TASK_DL_CLIENT, Download).with { | |
output = delayedFile JAR_CLIENT_FRESH | |
url = delayedString URL_MC_CLIENT | |
} | |
def dlServer = makeTask(TASK_DL_SERVER, Download).with { | |
output = delayedFile JAR_SERVER_FRESH | |
url = delayedString URL_MC_SERVER | |
} | |
makeTask(TASK_MERGE_JARS, MergeJars).with { | |
client = delayedFile JAR_CLIENT_FRESH | |
server = delayedFile JAR_SERVER_FRESH | |
outJar = delayedFile JAR_MERGED | |
dontProcess << ['org/bouncycastle', 'org/apache', 'com/google', 'com/mojang/authlib', 'com/mojang/util', 'gnu/trove', 'io/netty', 'javax/annotation', 'argo'] | |
dependsOn dlClient, dlServer | |
} | |
def getVersionJson = makeTask(TASK_DL_VERSION_JSON, EtagDownloadTask).with { | |
url = delayedString URL_MC_JSON | |
file = delayedFile JSON_VERSION | |
dieWithError = false | |
doLast { | |
try { | |
// normalize the line endings... | |
def json = delayedFile(JSON_VERSION)() | |
if (!json.exists) { | |
return | |
} | |
def lines = json.readLines "UTF-8" | |
def buf = new StringBuilder() | |
lines.each { buf.append(it).append('\n') } | |
json.write buf.toString(), "UTF-8" | |
// grab the AssetIndex if it isnt already there | |
if (!TokenReplacer.hasReplacement(REPLACE_ASSET_INDEX)) | |
JsonFactory.loadVersion json, json.parentFile | |
} catch(Throwable t) { | |
Throwables.propagate t | |
} | |
} | |
} | |
makeTask(TASK_EXTRACT_NATIVES, ExtractConfigTask).with { | |
destinationDir = delayedFile DIR_NATIVES | |
config = CONFIG_NATIVES | |
excludes << ['META-INF/**', 'META-INF/**'] | |
doesCache() | |
dependsOn getVersionJson | |
} | |
def getAssetsIndex = makeTask(TASK_DL_ASSET_INDEX, EtagDownloadTask).with { | |
url = delayedString ASSETS_INDEX_URL | |
file = delayedFile JSON_ASSET_INDEX | |
dieWithError = false | |
dependsOn getVersionJson | |
} | |
makeTask(TASK_DL_ASSETS, DownloadAssetsTask).with { | |
assetsDir = delayedFile DIR_ASSETS | |
assetsIndex = JSON_ASSET_INDEX | |
dependsOn getAssetsIndex | |
} | |
def extractMcpData = makeTask(TASK_EXTRACT_MCP, ExtractConfigTask).with { | |
destinationDir = delayedFile DIR_MCP_DATA | |
config = CONFIG_MCP_DATA | |
doesCache = true | |
} | |
def extractMcpMappings = makeTask(TASK_EXTRACT_MAPPINGS, ExtractConfigTask).with { | |
destinationDir = delayedFile(DIR_MCP_MAPPINGS) | |
config = CONFIG_MAPPINGS | |
doesCache = true | |
} | |
makeTask(TASK_GENERATE_SRGS, GenSrgs).with { | |
inSrg = delayedFile MCP_DATA_SRG | |
inExc = delayedFile MCP_DATA_EXC | |
methodsCsv = delayedFile CSV_METHOD | |
fieldsCsv = delayedFile CSV_FIELD | |
notchToSrg = delayedFile SRG_NOTCH_TO_SRG | |
notchToMcp = delayedFile SRG_NOTCH_TO_MCP | |
mcpToSrg = delayedFile SRG_SRG_TO_MCP | |
mcpToNotch = delayedFile SRG_MCP_TO_NOTCH | |
srgExc = delayedFile EXC_SRG | |
mcpExc = delayedFile EXC_MCP | |
dependsOn extractMcpData, extractMcpMappings | |
} | |
makeTask(TASK_DL_FERNFLOWER, ObtainFernFlowerTask).with { | |
mcpUrl = delayedString URL_FF | |
ffJar = delayedFile JAR_FERNFLOWER | |
} | |
makeTask(TASK_CLEAN_CACHE, Delete).with { | |
delete delayedFile(REPLACE_CACHE_DIR) | |
group = GROUP_FG | |
description = 'Clears the ForgeGradle cache. DON\'T RUN THIS unless you want a fresh start, or the dev tell you to.' | |
} | |
} | |
def final K getExtension() { | |
otherPlugin != null && canOverlayPlugin() ? overlayExtension : project.extensions[EXT_NAME_MC] | |
} | |
def abstract K getOverlayExtension() | |
def DefaultTask makeTask(String name) { | |
makeTask name, DefaultTask | |
} | |
def maybeMakeTask(String name) { | |
maybeMakeTask name, DefaultTask | |
} | |
def <T extends Task> T makeTask(String name, Class<T> type) { | |
makeTask(project, name, type) | |
} | |
def <T extends Task> T maybeMakeTask(String name, Class<T> type) { | |
maybeMakeTask(project, name, type) | |
} | |
def static <T extends Task> T maybeMakeTask(Project proj, String name, Class<T> type) { | |
proj.tasks.maybCreate name, type | |
} | |
def static <T extends Task> T makeTask(Project proj, String name, Class<T> type) { | |
proj.tasks.create name, type | |
} | |
def static Project buildProject(File buildFile, Project proj) { | |
def builder = ProjectBuilder.builder() | |
builder.with { | |
if (buildFile != null) { | |
projectDir = buildFile.parentFile | |
name = buildFile.parentFile.name | |
} else { | |
projectDir = new File('.') | |
} | |
if (proj != null) | |
parent = proj | |
} | |
def project = builder.build | |
if (buildFile != null) | |
project.apply from:buildFile.absolutePath | |
project | |
} | |
def applyExternalPlugin(String plug) { | |
project.apply plugin:plug | |
} | |
public MavenArtifactRepository addMavenRepo(Project proj, String name, String url) { | |
proj.getRepositories().maven { MavenArtifactRepository repo -> | |
repo.name = name | |
repo.url = url | |
} | |
} | |
public FlatDirectoryArtifactRepository addFlatRepo(Project proj, String name, String dirs){ | |
proj.getRepositories().flatDir { FlatDirectoryArtifactRepository repo -> | |
repo.name = name | |
repo.dirs = dirs | |
} | |
} | |
protected getWithEtag(String strUrl, File cache, File etagFile) { | |
try { | |
if (project.gradle.startParameter.isOffline()){ | |
return cache.text('UTF-8') | |
} | |
// dude, it's been less than 1 minutes since the last time.. | |
if (cache.exists && cache.lastModified + 60000 >= System.currentTimeMillis) | |
return cache.text('UTF-8') | |
String etag | |
if (etagFile.exists()) { | |
etag = etagFile.text('UTF-8') | |
} else { | |
etagFile.parentFile.mkdirs() | |
etag = '' | |
} | |
def url = strUrl.toURL() | |
def con = url.openConnection() as HttpURLConnection | |
con.instanceFollowRedirects = true | |
con.requestProperties << ["User-Agent":USER_AGENT] | |
con.ifModifiedSince = cache.lastModified | |
if (etag != null && !etag.empty){ | |
con.requestProperties << ["If-None-Match":etag] | |
} | |
con.connect() | |
def out = null as String | |
if (con.responseCode == 304) { | |
cache.createNewFile() | |
out = cache.text 'UTF-8' | |
} else if (con.responseCode == 200) { | |
def data = con.inputStream.text 'UTF-8' | |
cache.write data, 'UTF-8' | |
etag = con.headerFields['ETag'] | |
if (etag != null && !etag.empty) { | |
etagFile.createNewFile() | |
} else { | |
etagFile.write etag, 'UTF-8' | |
} | |
out = data | |
} else { | |
project.logger.error "Etag download for $strUrl failed with code $con.responseCode" | |
} | |
con.disconnect() | |
out | |
} catch( Exception e) { | |
e.printStackTrace() | |
} | |
if (cache.exists) { | |
try { | |
cache.text "UTF-8" | |
}catch(IOException e) { | |
Throwables.propagate e | |
} | |
} | |
throw new RuntimeException("Unable to obtain url ($strUrl) with etag!") | |
} | |
protected Version parseAndStoreVersion(File file, File... inheritanceDirs) { | |
if (!file.exists) {null} | |
def version = null | |
try{ | |
version = JsonFactory.loadVersion file, delayedFile(Constants.DIR_JSONS)() | |
}catch(Exception e) { | |
project.logger.error "$file could not be parsed" | |
Throwables.propagate(e) | |
} | |
if (version == null) { | |
try { | |
version = JsonFactory.loadVersion file, delayedFile(Constants.DIR_JSONS)() | |
}catch(Exception e) { | |
project.logger.error "$file could not be parsed" | |
} | |
} | |
// apply the dep info | |
def handler = project.getDependencies() | |
def adder = { libs, config -> | |
if (project.getConfigurations()[config].state == Configuration.State.UNRESOLVED){ | |
libs | |
.findAll{Library lib -> lib.natives == null} | |
.each{Library lib -> handler << [config:lib.artifactName]} | |
} else project.logger.debug "RESOLVED $config" | |
} | |
// actual dependencies | |
adder version.libraries, CONFIG_MC_DEPS | |
// the natives | |
adder version.libraries, CONFIG_NATIVES | |
TokenReplacer.replaceMap << [REPLACE_ASSET_INDEX:version.assets] | |
version | |
} | |
protected Version parseAndStoreVersion(File file) { | |
parseAndStoreVersion file, delayedFile(DIR_JSONS)() | |
} | |
// DELAYED STUFF ONLY ------------------------------------------------------------------------ | |
private LoadingCache<String, TokenReplacer> replacerCache = CacheBuilder.newBuilder().weakValues().build{new TokenReplacer(it)}; | |
private LoadingCache<String, DelayedString> stringCache = CacheBuilder.newBuilder().weakValues().build{new DelayedString(replacerCache.getUnchecked(it))}; | |
private LoadingCache<String, DelayedFile> fileCache = CacheBuilder.newBuilder().weakValues().build{new DelayedFile(project, replacerCache.getUnchecked(it))} | |
protected DelayedString delayedString(String path) | |
{ | |
stringCache.getUnchecked path | |
} | |
protected DelayedFile delayedFile(String path) | |
{ | |
fileCache.getUnchecked path | |
} | |
protected DelayedFileTree delayedTree(String path) | |
{ | |
new DelayedFileTree(project, replacerCache.getUnchecked(path)) | |
} | |
protected File cacheFile(String path) | |
{ | |
new File(project.gradle.gradleUserHomeDir, "caches/minecraft/$path") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment