-
-
Notifications
You must be signed in to change notification settings - Fork 183
/
build.gradle
150 lines (135 loc) · 6.3 KB
/
build.gradle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import java.util.regex.Matcher
import java.util.regex.Pattern
plugins {
id 'net.neoforged.gradleutils' version '3.0.0'
id 'dev.lukebemish.immaculate' version '0.1.6' apply false
id 'net.neoforged.licenser' version '0.7.5'
id 'neoforge.formatting-conventions'
id 'neoforge.versioning'
}
ext.isPreReleaseVersion = project.minecraft_version.contains('w') || project.minecraft_version.contains('-')
if (isPreReleaseVersion) {
project.version = "${project.neoforge_snapshot_next_stable}.0-alpha.${project.minecraft_version}.${(new Date()).format('yyyyMMdd.HHmmss', TimeZone.getTimeZone('UTC'))}"
} else {
project.version = gradleutils.version.toString()
}
// Print version, generally useful to know - also appears on CI
System.out.println("NeoForge version ${project.version}")
allprojects {
version rootProject.version
group 'net.neoforged'
apply plugin: 'java'
java.toolchain.languageVersion.set(JavaLanguageVersion.of(project.java_version))
}
// Remove src/ sources from the root project. They are used in the neoforge subproject.
sourceSets {
main {
java {
srcDirs = []
}
resources {
srcDirs = []
}
}
}
// Put licenser here otherwise it tries to license all source sets including decompiled MC sources
license {
header = file('codeformat/HEADER.txt')
skipExistingHeaders = true
tasks {
neoforge {
// Add all NeoForge sources
files.from rootProject.fileTree("src", {
include "**/*.java"
})
}
}
}
// Put spotless here because it wants the files to live inside the project root
immaculate {
workflows.named("java") {
files.from rootProject.fileTree("src", {
include "**/*.java"
})
}
workflows.register("patches") {
files.from(rootProject.fileTree("patches"))
custom 'noImportChanges', { String fileContents ->
if (fileContents.contains('+import') || fileContents.contains('-import')) {
throw new GradleException("Import changes are not allowed in patches!")
}
return fileContents
}
def interfaceChange = Pattern.compile('[-+].*(implements|(interface.*extends))(.*)\\{')
custom 'noInterfaceModifications', { String fileContents ->
def interfaceChanges = fileContents.lines().filter { it.matches(interfaceChange) }.toList()
if (interfaceChanges.isEmpty()) return fileContents
String oldInterfaces = ""
// we expect interface additions/removals in pairs of - and then +
interfaceChanges.each { String change ->
final match = change =~ interfaceChange
match.find()
final values = match.group(3).trim()
if (change.startsWith('-')) {
oldInterfaces = values
} else if (oldInterfaces != values) {
throw new GradleException("Modification of interfaces via patches is not allowed!")
}
}
return fileContents
}
//Note: This doesn't detect changing access level to or from package private
//TODO: Eventually try and make this support checking package private access level changes?
def accessLevelChange = Pattern.compile('^[-+]\\s*(public|private|protected)\\s.*\$', Pattern.UNIX_LINES | Pattern.MULTILINE)
custom 'noAccessWidening', { String fileContents ->
def accessChanges = fileContents.findAll(accessLevelChange)
if (accessChanges.isEmpty()) return fileContents
Set<String> privateRemovals = new HashSet<>()
Set<String> protectedRemovals = new HashSet<>()
accessChanges.each { String change ->
//Get the type of match
String[] data = change.substring(1).trim().split(" ", 2)
String lineStart = data[1].substring(0, Math.min(10, data[1].length()))
if (change.startsWith('-')) {//Removal
if (data[0] == 'private') {
privateRemovals.add(lineStart)
} else if (data[0] == 'protected') {
protectedRemovals.add(lineStart)
}
} else if (!privateRemovals.isEmpty() || !protectedRemovals.isEmpty()) {//Addition and we know of at least one removal
if (data[0] == 'public') {
if (privateRemovals.remove(lineStart) || protectedRemovals.remove(lineStart)) {
throw new GradleException("Widening access level via patches is not allowed, use an AT! Changed line: " + change)
}
} else if (data[0] == 'protected') {
if (privateRemovals.remove(lineStart)) {
throw new GradleException("Widening access level via patches is not allowed, use an AT! Changed line: " + change)
}
//Remove any protected ones that we have a match for
protectedRemovals.remove(lineStart)
} else if (data[0] == 'private') {
//Remove any private ones that we have a match for
privateRemovals.remove(lineStart)
}
}
}
//Note: We allow mismatched counts in case we are removing a method entirely for some reason
return fileContents
}
//Trim any trailing whitespace from patch additions
def trailingWhitespace = Pattern.compile('^\\+.*[ \t]+\$', Pattern.UNIX_LINES | Pattern.MULTILINE)
custom 'trimTrailingWhitespacePatches', { String fileContents ->
Matcher matcher = trailingWhitespace.matcher(fileContents)
StringBuilder sb = new StringBuilder()
while (matcher.find()) {
matcher.appendReplacement(sb, matcher.group().trim())
}
matcher.appendTail(sb)
return sb.toString()
}
//Replace any FQN versions of javax.annotation.Nullable with the jetbrains variant
custom 'jetbrainsNullablePatches', { String fileContents ->
fileContents.replace('@javax.annotation.Nullable', '@org.jetbrains.annotations.Nullable')
}
}
}