blob: 9b47d43bce55fb07411f25ffd20df9a188da794d [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
import sbt._
import sbt.Keys._
import com.typesafe.sbt.packager.universal.UniversalPlugin.autoImport._
/**
* Generates per-module LICENSE files for jar META-INF and dist zip top level.
*
* Each jar's META-INF/LICENSE describes only what is in that specific jar:
* - Modules without vendored code get Apache 2.0 only.
* - workflow-operator gets Apache 2.0 plus the mbknor-jackson-jsonschema
* attribution and the full MIT license text.
*
* NOTICE and DISCLAIMER are copied as-is from the repo root.
*
* See https://github.com/apache/texera/issues/4131
*/
object AddMetaInfLicenseFiles {
private lazy val rootDir = LocalRootProject / baseDirectory
private val ThirdPartyHeader = "THIRD-PARTY DEPENDENCIES"
/** Extract the Apache 2.0 license text (before the THIRD-PARTY section) from root LICENSE. */
private def apacheLicenseText(rootDir: File): String = {
val lines = IO.readLines(rootDir / "LICENSE")
val headerIndex = lines.indexWhere(_.trim == ThirdPartyHeader)
val cutoffIndex =
if (headerIndex >= 0) {
// Cut at the "---" delimiter line preceding the header
val delimiterIndex = lines.lastIndexWhere(_.startsWith("---"), headerIndex - 1)
if (delimiterIndex >= 0) delimiterIndex else headerIndex
} else {
lines.length
}
lines.take(cutoffIndex).mkString("\n").trim + "\n"
}
/** The vendored code section for workflow-operator (mbknor-jackson-jsonschema). */
private def workflowOperatorVendoredSection(rootDir: File): String = {
val mitLicense = IO.read(rootDir / "licenses" / "LICENSE-MIT.txt")
s"""
|--------------------------------------------------------------------------------
|THIRD-PARTY DEPENDENCIES
|--------------------------------------------------------------------------------
|
|This jar bundles compiled code from the following third-party project.
|The full license text is included below.
|
|MIT License
|--------------------------------------
|
|This product bundles code derived from mbknor-jackson-jsonschema:
| - com/kjetland/jackson/jsonSchema/
| Copyright (c) 2016 Kjell Tore Eliassen (mbknor)
| Source: https://github.com/mbknor/mbknor-jackson-jsonschema
|
|--------------------------------------------------------------------------------
|Full text of the MIT License:
|--------------------------------------------------------------------------------
|
|${mitLicense.trim}
|""".stripMargin
}
private def writeToMetaInf(managed: File, fileName: String, content: String): File = {
val dest = managed / "META-INF" / fileName
IO.write(dest, content)
dest
}
private def copyToMetaInf(managed: File, src: File, fileName: String): File = {
val dest = managed / "META-INF" / fileName
IO.copyFile(src, dest)
dest
}
private def noticeAndDisclaimer(managed: File, rootDir: File): Seq[File] = {
val files = Seq(copyToMetaInf(managed, rootDir / "NOTICE", "NOTICE"))
val disclaimer = rootDir / "DISCLAIMER"
if (disclaimer.exists()) files :+ copyToMetaInf(managed, disclaimer, "DISCLAIMER")
else files
}
/** Settings for modules WITHOUT vendored third-party code.
* META-INF/LICENSE contains only the Apache 2.0 license text. */
lazy val defaultSettings: Seq[Setting[_]] = Seq(
Compile / resourceGenerators += Def.task {
val managed = (Compile / resourceManaged).value
val root = rootDir.value
val licenseContent = apacheLicenseText(root)
writeToMetaInf(managed, "LICENSE", licenseContent) +: noticeAndDisclaimer(managed, root)
}.taskValue
)
/** Settings for workflow-operator which contains vendored mbknor-jackson-jsonschema code.
* META-INF/LICENSE contains Apache 2.0 plus the mbknor attribution and MIT license text. */
lazy val workflowOperatorSettings: Seq[Setting[_]] = Seq(
Compile / resourceGenerators += Def.task {
val managed = (Compile / resourceManaged).value
val root = rootDir.value
val licenseContent = apacheLicenseText(root) + "\n" + workflowOperatorVendoredSection(root)
writeToMetaInf(managed, "LICENSE", licenseContent) +: noticeAndDisclaimer(managed, root)
}.taskValue
)
/** Ships the module's per-module LICENSE-binary, NOTICE-binary, DISCLAIMER
* (if present), and licenses/ at the Universal zip's top level. The
* per-module files describe only the third-party content actually
* bundled in this module's dist zip; the licenses/ directory at the
* repo root is shared by all dist zips. DISCLAIMER is optional (it
* will be removed at graduation). */
def distMappings(
existing: Seq[(File, String)],
rootDir: File,
licenseBinary: File,
noticeBinary: File
): Seq[(File, String)] = {
val disclaimerFile = rootDir / "DISCLAIMER"
val licensesDir = rootDir / "licenses"
require(licenseBinary.isFile,
s"LICENSE-binary not found at $licenseBinary; required for binary-distribution packaging.")
require(noticeBinary.isFile,
s"NOTICE-binary not found at $noticeBinary; required for binary-distribution packaging.")
require(licensesDir.isDirectory,
s"licenses/ directory not found at $licensesDir; required for binary-distribution packaging.")
val reserved = Set("LICENSE", "NOTICE", "DISCLAIMER")
val filtered = existing.filterNot {
case (_, path) => reserved.contains(path) || path.startsWith("licenses/")
}
val licenseTexts = (licensesDir ** "*.txt").get.map(f => f -> s"licenses/${f.getName}")
val base = Seq(licenseBinary -> "LICENSE", noticeBinary -> "NOTICE")
val disclaimer =
if (disclaimerFile.isFile) Seq(disclaimerFile -> "DISCLAIMER")
else Seq.empty
filtered ++ base ++ disclaimer ++ licenseTexts
}
}