<commit_before>package com.typesafe.sbt
package packager
package rpm

import sbt._
import com.typesafe.sbt.packager.linux.{LinuxFileMetaData, LinuxPackageMapping, LinuxPlugin, LinuxSymlink}
import com.typesafe.sbt.packager.rpm.RpmPlugin.Names._
import com.typesafe.sbt.packager.archetypes.TemplateWriter
import java.io.File

case class RpmMetadata(name: String,
                       version: String,
                       release: String,
                       prefix: Option[String] = None,
                       arch: String,
                       vendor: String,
                       os: String,
                       summary: String,
                       description: String,
                       autoprov: String,
                       autoreq: String)

/**
  * The Description used to generate an RPM
  */
case class RpmDescription(license: Option[String] = None,
                          distribution: Option[String] = None,
                          url: Option[String] = None,
                          group: Option[String] = None,
                          packager: Option[String] = None,
                          icon: Option[String] = None,
                          changelogFile: Option[String] = None)

case class RpmDependencies(provides: Seq[String] = Seq.empty,
                           requirements: Seq[String] = Seq.empty,
                           prereq: Seq[String] = Seq.empty,
                           obsoletes: Seq[String] = Seq.empty,
                           conflicts: Seq[String] = Seq.empty) {
  def contents: String = {
    val sb = new StringBuilder
    def appendSetting(prefix: String, values: Seq[String]) =
      values foreach (v => sb append (prefix + v + "\n"))
    appendSetting("Provides: ", provides)
    appendSetting("Requires: ", requirements)
    appendSetting("PreReq: ", prereq)
    appendSetting("Obsoletes: ", obsoletes)
    appendSetting("Conflicts: ", conflicts)
    sb.toString
  }
}

/**
  * Parameters stay because of binary compatibility.
  */
case class RpmScripts(pretrans: Option[String] = None,
                      pre: Option[String] = None,
                      post: Option[String] = None,
                      verifyscript: Option[String] = None,
                      posttrans: Option[String] = None,
                      preun: Option[String] = None,
                      postun: Option[String] = None) {

  def pretransContent(): String =
    pretrans.fold("")("\n%pretrans\n" + _ + "\n\n")

  def preContent(): String =
    pre.fold("")("\n%pre\n" + _ + "\n\n")

  def postContent(buildSymlinkScript: Option[String]): String = {
    val scripts = Seq(post, buildSymlinkScript).flatten
    if (scripts.isEmpty)
      ""
    else
      "\n%post\n" + scripts.mkString("\n") + "\n\n"
  }

  def posttransContent(): String =
    posttrans.fold("")("\n%posttrans\n" + _ + "\n\n")

  def verifyscriptContent(): String =
    verifyscript.fold("")("\n%verifyscript\n" + _ + "\n\n")

  def preunContent(): String =
    preun.fold("")("\n%preun\n" + _ + "\n\n")

  def postunContent(tearDownSymlinkScript: Option[String]): String = {
    val scripts = Seq(postun, tearDownSymlinkScript).flatten
    if (scripts.isEmpty)
      ""
    else
      "\n%postun\n" + scripts.mkString("\n") + "\n\n"
  }

  @deprecated(
    "Call individual scriptlet content method instead, e.g. pretransContent(). This is to allow managing symlink during %post and %postun so it can be relocated",
    since = "1.0.5-M4"
  )
  @deprecated("Use contents(maintainerScripts) until next major release", "1.1.x")
  def contents(): String = {
    val labelledScripts = Seq("%pretrans", "%pre", "%post", "%verifyscript", "%posttrans", "%preun", "%postun").zip(
      Seq(pretrans, pre, post, verifyscript, posttrans, preun, postun)
    )
    labelledScripts.collect { case (a, Some(b)) => a + "\n" + b }.mkString("\n\n")
  }

}

object RpmScripts {

  def fromMaintainerScripts(maintainerScripts: Map[String, Seq[String]],
                            replacements: Seq[(String, String)]): RpmScripts = {
    val toContent = toContentWith(replacements) _
    RpmScripts(
      pretrans = maintainerScripts.get(Pretrans).map(toContent),
      pre = maintainerScripts.get(Pre).map(toContent),
      post = maintainerScripts.get(Post).map(toContent),
      verifyscript = maintainerScripts.get(Verifyscript).map(toContent),
      posttrans = maintainerScripts.get(Posttrans).map(toContent),
      preun = maintainerScripts.get(Preun).map(toContent),
      postun = maintainerScripts.get(Postun).map(toContent)
    )
  }

  // insert replacements
  private def toContentWith(replacements: Seq[(String, String)])(lines: Seq[String]): String =
    TemplateWriter.generateScriptFromLines(lines, replacements).mkString("\n")

}

case class RpmSpec(meta: RpmMetadata,
                   desc: RpmDescription = RpmDescription(),
                   deps: RpmDependencies = RpmDependencies(),
                   setarch: Option[String],
                   scriptlets: RpmScripts = RpmScripts(),
                   mappings: Seq[LinuxPackageMapping] = Seq.empty,
                   symlinks: Seq[LinuxSymlink] = Seq.empty,
                   installLocation: String) {

  def installDir: String =
    LinuxPlugin.chdir(installLocation, meta.name)

  // TODO - here we want to validate that all the data we have is ok to place
  // in the RPM.  e.g. the Description/vendor etc. must meet specific requirements.
  // For now we just check existence.
  def validate(log: Logger): Unit = {
    def ensureOr[T](value: T, msg: String, validator: T => Boolean): Boolean =
      if (validator(value)) true
      else {
        log.error(msg)
        false
      }
    def isNonEmpty(s: String): Boolean = !s.isEmpty
    // format: off
    val emptyValidators =
      Seq(
        ensureOr(meta.name, "`name in Rpm` is empty.  Please provide one.", isNonEmpty),
        ensureOr(meta.version, "`version in Rpm` is empty.  Please provide a vaid version for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.release, "`rpmRelease in Rpm` is empty.  Please provide a valid release number for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.arch, "`packageArchitecture in Rpm` is empty.  Please provide a valid archiecture for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.vendor, "`rpmVendor in Rpm` is empty.  Please provide a valid vendor for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.os, "`rpmOs in Rpm` is empty.  Please provide a valid os vaue for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.summary, "`packageSummary in Rpm` is empty.  Please provide a valid summary for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.description, "`packageDescription in Rpm` is empty.  Please provide a valid description for the rpm SPEC.", isNonEmpty)
      )
    // format: on
    // TODO - Continue validating after this point?
    if (!emptyValidators.forall(identity))
      sys.error("There are issues with the rpm spec data.")
  }

  private[this] def fixFilename(n: String): String = {
    val tmp =
      if (n startsWith "/") n
      else "/" + n
    if (tmp.contains(' ')) "\"%s\"" format tmp
    else tmp
  }

  private[this] def makeFilesLine(target: String, meta: LinuxFileMetaData, isDir: Boolean): String = {<commit_msg>Small Typo Fix "vaid" changed back to "valid"<commit_after>package com.typesafe.sbt
package packager
package rpm

import sbt._
import com.typesafe.sbt.packager.linux.{LinuxFileMetaData, LinuxPackageMapping, LinuxPlugin, LinuxSymlink}
import com.typesafe.sbt.packager.rpm.RpmPlugin.Names._
import com.typesafe.sbt.packager.archetypes.TemplateWriter
import java.io.File

case class RpmMetadata(name: String,
                       version: String,
                       release: String,
                       prefix: Option[String] = None,
                       arch: String,
                       vendor: String,
                       os: String,
                       summary: String,
                       description: String,
                       autoprov: String,
                       autoreq: String)

/**
  * The Description used to generate an RPM
  */
case class RpmDescription(license: Option[String] = None,
                          distribution: Option[String] = None,
                          url: Option[String] = None,
                          group: Option[String] = None,
                          packager: Option[String] = None,
                          icon: Option[String] = None,
                          changelogFile: Option[String] = None)

case class RpmDependencies(provides: Seq[String] = Seq.empty,
                           requirements: Seq[String] = Seq.empty,
                           prereq: Seq[String] = Seq.empty,
                           obsoletes: Seq[String] = Seq.empty,
                           conflicts: Seq[String] = Seq.empty) {
  def contents: String = {
    val sb = new StringBuilder
    def appendSetting(prefix: String, values: Seq[String]) =
      values foreach (v => sb append (prefix + v + "\n"))
    appendSetting("Provides: ", provides)
    appendSetting("Requires: ", requirements)
    appendSetting("PreReq: ", prereq)
    appendSetting("Obsoletes: ", obsoletes)
    appendSetting("Conflicts: ", conflicts)
    sb.toString
  }
}

/**
  * Parameters stay because of binary compatibility.
  */
case class RpmScripts(pretrans: Option[String] = None,
                      pre: Option[String] = None,
                      post: Option[String] = None,
                      verifyscript: Option[String] = None,
                      posttrans: Option[String] = None,
                      preun: Option[String] = None,
                      postun: Option[String] = None) {

  def pretransContent(): String =
    pretrans.fold("")("\n%pretrans\n" + _ + "\n\n")

  def preContent(): String =
    pre.fold("")("\n%pre\n" + _ + "\n\n")

  def postContent(buildSymlinkScript: Option[String]): String = {
    val scripts = Seq(post, buildSymlinkScript).flatten
    if (scripts.isEmpty)
      ""
    else
      "\n%post\n" + scripts.mkString("\n") + "\n\n"
  }

  def posttransContent(): String =
    posttrans.fold("")("\n%posttrans\n" + _ + "\n\n")

  def verifyscriptContent(): String =
    verifyscript.fold("")("\n%verifyscript\n" + _ + "\n\n")

  def preunContent(): String =
    preun.fold("")("\n%preun\n" + _ + "\n\n")

  def postunContent(tearDownSymlinkScript: Option[String]): String = {
    val scripts = Seq(postun, tearDownSymlinkScript).flatten
    if (scripts.isEmpty)
      ""
    else
      "\n%postun\n" + scripts.mkString("\n") + "\n\n"
  }

  @deprecated(
    "Call individual scriptlet content method instead, e.g. pretransContent(). This is to allow managing symlink during %post and %postun so it can be relocated",
    since = "1.0.5-M4"
  )
  @deprecated("Use contents(maintainerScripts) until next major release", "1.1.x")
  def contents(): String = {
    val labelledScripts = Seq("%pretrans", "%pre", "%post", "%verifyscript", "%posttrans", "%preun", "%postun").zip(
      Seq(pretrans, pre, post, verifyscript, posttrans, preun, postun)
    )
    labelledScripts.collect { case (a, Some(b)) => a + "\n" + b }.mkString("\n\n")
  }

}

object RpmScripts {

  def fromMaintainerScripts(maintainerScripts: Map[String, Seq[String]],
                            replacements: Seq[(String, String)]): RpmScripts = {
    val toContent = toContentWith(replacements) _
    RpmScripts(
      pretrans = maintainerScripts.get(Pretrans).map(toContent),
      pre = maintainerScripts.get(Pre).map(toContent),
      post = maintainerScripts.get(Post).map(toContent),
      verifyscript = maintainerScripts.get(Verifyscript).map(toContent),
      posttrans = maintainerScripts.get(Posttrans).map(toContent),
      preun = maintainerScripts.get(Preun).map(toContent),
      postun = maintainerScripts.get(Postun).map(toContent)
    )
  }

  // insert replacements
  private def toContentWith(replacements: Seq[(String, String)])(lines: Seq[String]): String =
    TemplateWriter.generateScriptFromLines(lines, replacements).mkString("\n")

}

case class RpmSpec(meta: RpmMetadata,
                   desc: RpmDescription = RpmDescription(),
                   deps: RpmDependencies = RpmDependencies(),
                   setarch: Option[String],
                   scriptlets: RpmScripts = RpmScripts(),
                   mappings: Seq[LinuxPackageMapping] = Seq.empty,
                   symlinks: Seq[LinuxSymlink] = Seq.empty,
                   installLocation: String) {

  def installDir: String =
    LinuxPlugin.chdir(installLocation, meta.name)

  // TODO - here we want to validate that all the data we have is ok to place
  // in the RPM.  e.g. the Description/vendor etc. must meet specific requirements.
  // For now we just check existence.
  def validate(log: Logger): Unit = {
    def ensureOr[T](value: T, msg: String, validator: T => Boolean): Boolean =
      if (validator(value)) true
      else {
        log.error(msg)
        false
      }
    def isNonEmpty(s: String): Boolean = !s.isEmpty
    // format: off
    val emptyValidators =
      Seq(
        ensureOr(meta.name, "`name in Rpm` is empty.  Please provide one.", isNonEmpty),
        ensureOr(meta.version, "`version in Rpm` is empty.  Please provide a valid version for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.release, "`rpmRelease in Rpm` is empty.  Please provide a valid release number for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.arch, "`packageArchitecture in Rpm` is empty.  Please provide a valid archiecture for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.vendor, "`rpmVendor in Rpm` is empty.  Please provide a valid vendor for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.os, "`rpmOs in Rpm` is empty.  Please provide a valid os vaue for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.summary, "`packageSummary in Rpm` is empty.  Please provide a valid summary for the rpm SPEC.", isNonEmpty),
        ensureOr(meta.description, "`packageDescription in Rpm` is empty.  Please provide a valid description for the rpm SPEC.", isNonEmpty)
      )
    // format: on
    // TODO - Continue validating after this point?
    if (!emptyValidators.forall(identity))
      sys.error("There are issues with the rpm spec data.")
  }

  private[this] def fixFilename(n: String): String = {
    val tmp =
      if (n startsWith "/") n
      else "/" + n
    if (tmp.contains(' ')) "\"%s\"" format tmp
    else tmp
  }

  private[this] def makeFilesLine(target: String, meta: LinuxFileMetaData, isDir: Boolean): String = {
{'fraction_non_alphanumeric': 0.12081822535403981, 'fraction_numerical': 0.0008209618936854347, 'mean_word_length': 2.446016030174446, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7058540', 'n_tokens_mistral': 4405, 'n_tokens_neox': 4268, 'n_words': 1135}