in build-logic/src/main/kotlin/copiedcode/CopiedCodeCheckerPlugin.kt [193:315]
fun checkForCopiedCode() {
val extension = project.extensions.getByType(CopiedCodeCheckerExtension::class.java)
val licenseFile = extension.licenseFile.get().asFile
val licenseFileRelative = licenseFile.relativeTo(project.rootDir).toString()
logger.info("Running copied code check against root project's {} file", licenseFileRelative)
val namedDirectorySets = namedDirectorySets()
val includedPatterns = extension.includedContentTypePatterns.get().map { Pattern.compile(it) }
val excludedPatterns = extension.includedContentTypePatterns.get().map { Pattern.compile(it) }
val includeUnknown = extension.includeUnrecognizedContentType.get()
val magicWord = extension.magicWord.get()
val magicWordPattern = Pattern.compile(".*\\b${magicWord}\\b.*")
val mentionedFilesInLicense =
extension.licenseFile
.get()
.asFile
.readLines()
.filter { line -> line.startsWith("* ") && line.length > 2 }
.map { line -> line.substring(2) }
.toSet()
val buildDir = project.layout.buildDirectory.asFile.get()
val unmentionedFiles =
namedDirectorySets
.flatMap { pair ->
val name = pair.first
val sourceDirectorySet = pair.second
logger.info(
"Checking {} for files containing {} not mentioned in {}",
name,
magicWord,
licenseFileRelative,
)
sourceDirectorySet.asFileTree
.filter { file -> !file.startsWith(buildDir) }
.map { file ->
val projectRelativeFile = file.relativeTo(project.projectDir)
val fileType = Files.probeContentType(file.toPath())
logger.info(
"Checking file '{}' (probed content type: {})",
projectRelativeFile,
fileType,
)
var r: String? = null
var check = true
if (fileType == null) {
if (!includeUnknown) {
logger.info(" ... unknown content type, skipping")
check = false
}
} else {
val excluded =
excludedPatterns.any { pattern -> pattern.matcher(fileType).matches() }
if (excluded) {
val included =
includedPatterns.any { pattern -> pattern.matcher(fileType).matches() }
if (!included) {
logger.info(" ... excluded and not included content type, skipping")
check = false
}
}
}
if (check) {
if (!file.readLines().any { s -> magicWordPattern.matcher(s).matches() }) {
logger.info(
" ... no magic word, not expecting an entry in {}",
licenseFileRelative,
)
} else {
val relativeFilePath = file.relativeTo(project.rootProject.projectDir).toString()
if (mentionedFilesInLicense.contains(relativeFilePath)) {
logger.info(" ... has magic word & mentioned in {}", licenseFileRelative)
} else {
// error (summary) logged below
logger.info(
"The file '{}' has the {} marker, but is not mentioned in {}",
relativeFilePath,
magicWord,
licenseFileRelative,
)
r = relativeFilePath
}
}
}
r
}
.filter { r -> r != null }
.map { r -> r!! }
}
.sorted()
.toList()
if (!unmentionedFiles.isEmpty()) {
logger.error(
"""
The following {} files have the {} marker but are not mentioned in {}, add those in an appropriate section.
{}
"""
.trimIndent(),
unmentionedFiles.size,
magicWord,
licenseFileRelative,
unmentionedFiles.joinToString("\n* ", "* "),
)
throw GradleException(
"${unmentionedFiles.size} files with the $magicWord marker need to be mentioned in $licenseFileRelative. See the messages above."
)
}
}