Skip to content

Instantly share code, notes, and snippets.

@DanielThomas
Last active October 23, 2018 00:09
Show Gist options
  • Save DanielThomas/e10b97c8d3dc98ca46fb150f535dc8d8 to your computer and use it in GitHub Desktop.
Save DanielThomas/e10b97c8d3dc98ca46fb150f535dc8d8 to your computer and use it in GitHub Desktop.
package com.netflix.lint.rule.nebula
import com.netflix.nebula.lint.FileMode
import com.netflix.nebula.lint.rule.GradleLintRule
import com.netflix.nebula.lint.rule.GradleModelAware
import org.codehaus.groovy.ast.ClassNode
import java.security.MessageDigest
import static java.nio.file.Files.isSymbolicLink
class UpdateNebulaWrapperRule extends GradleLintRule implements GradleModelAware {
static WRAPPER_DIRS = ['gradle', 'gradle/wrapper']
static WRAPPER_FILES = ['gradlew', 'gradlew.bat', 'gradle/wrapper/gradle-wrapper.properties', 'gradle/wrapper/gradle-wrapper.jar']
static ALL_WRAPPER_FILES = WRAPPER_FILES + WRAPPER_DIRS
static downloadLatestNebula(File toDir) {
def tempDir = new File(toDir, "latestNebula-${new Date().time}")
WRAPPER_DIRS.each { new File(tempDir, it).mkdirs() }
WRAPPER_FILES.each {
def out = new File(tempDir, it)
def url = new URL("<raw-scm-request-url>/$it?raw")
out << url.openStream()
if (it.contains('gradlew')) out.setExecutable(true)
}
return tempDir
}
static md5(File file) {
if (!file.exists()) {
return null
}
return MessageDigest.getInstance("MD5").digest(file.bytes).encodeHex().toString()
}
static pathContainsSymbolicLink(File baseDir, File file) {
File curr = file.parentFile
while (curr != baseDir) {
if (isSymbolicLink(curr.toPath())) return true
curr = curr.parentFile
}
return false
}
@Override
protected void visitClassComplete(ClassNode node) {
if (!project.rootDir.equals(project.projectDir)) {
return // only execute for the root project
}
def rootDir = project.rootDir
def gitIgnore = new File(rootDir, '.gitignore')
if (gitIgnore.exists()) {
gitIgnore.readLines().eachWithIndex { String ignoreEntry, Integer index ->
if (ALL_WRAPPER_FILES.contains(ignoreEntry)) {
def lineToDelete = index + 1
addLintViolation("Nebula wrapper file is ignored using '$ignoreEntry' in .gitignore", gitIgnore, index)
.deleteLines(gitIgnore, lineToDelete..lineToDelete)
}
}
}
def latestNebulaRoot = downloadLatestNebula(project.buildDir)
WRAPPER_DIRS.each { dir ->
def examinedDir = new File(rootDir, dir)
if (examinedDir.exists()) {
if (examinedDir.isFile()) {
addLintViolation("Nebula wrapper directory '$dir' is a regular file", examinedDir, 0).deleteFile(examinedDir)
} else if (isSymbolicLink(examinedDir.toPath())) {
addLintViolation("Nebula wrapper directory '$dir' must not be a symbolic link", examinedDir, 0).deleteFile(examinedDir)
}
}
}
WRAPPER_FILES.each { file ->
def examinedFile = new File(rootDir, file)
def targetFile = new File(latestNebulaRoot, file)
def fileType = file.contains('gradlew') ? FileMode.Executable : FileMode.Regular
if (!examinedFile.exists() || pathContainsSymbolicLink(rootDir, examinedFile)) {
addLintViolation("Nebula wrapper file '$file' does not exist", examinedFile, 0).createFile(examinedFile, targetFile.text, fileType)
} else if (isSymbolicLink(examinedFile.toPath())) {
addLintViolation("Nebula wrapper file '$file' must not be a symbolic link", examinedFile, 0).deleteFile(examinedFile).createFile(examinedFile, targetFile.text, fileType)
} else if (md5(examinedFile) != md5(targetFile)) {
addLintViolation("Nebula wrapper file '$file' is out-of-date", examinedFile, 0).deleteFile(examinedFile).createFile(examinedFile, targetFile.text, fileType)
} else if (fileType == FileMode.Executable && !examinedFile.canExecute()) {
addLintViolation("Nebula wrapper file '$file' is not executable", examinedFile, 0).deleteFile(examinedFile).createFile(examinedFile, targetFile.text, fileType)
}
}
}
@Override
String getDescription() {
return 'ensure the latest Nebula wrapper is being used'
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment