fun checkForCopiedCode()

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."
      )
    }
  }