package gs import java.time.LocalDate import scala.collection.mutable.ListBuffer /** Representation of a rendered Calendar Version. * * @param value * The version string. * @param pattern * The pattern which rendered the version string. */ case class CalVer( value: String, pattern: CalVer.Pattern ) object CalVer { /** Render the given pattern to a Calendar Version. * * @param pattern * The pattern to render. * @return * The rendered CalVer value. */ def render(pattern: Pattern): CalVer = { val today = LocalDate.now() CalVer( value = pattern.items.map { case Left(component) => component match { case Component.YYYY => today.getYear().toString() case Component.MM => today.getMonthValue().toString() case Component.DD => today.getDayOfMonth().toString() case Component.Label(label) => label case Component.GitSha(length) => Git.getSha(length) } case Right(delimiter) => Delimiter.render(delimiter) }.mkString, pattern = pattern ) } object Defaults { /** Default pattern for release versions. */ val ReleasePattern: Pattern = Pattern .builder(Component.YYYY) .addDelimiter(Delimiter.Dot) .addComponent(Component.MM) .addDelimiter(Delimiter.Dot) .addComponent(Component.DD) .addDelimiter(Delimiter.Hyphen) .addComponent(Component.Label("v")) .addComponent(Component.GitSha(7)) .build() /** Default pattern for pre-release versions. */ val PreReleasePattern: Pattern = Pattern .builder(Component.YYYY) .addDelimiter(Delimiter.Dot) .addComponent(Component.MM) .addDelimiter(Delimiter.Dot) .addComponent(Component.DD) .addDelimiter(Delimiter.Hyphen) .addComponent(Component.GitSha(7)) .addDelimiter(Delimiter.Hyphen) .addComponent(Component.Label("SNAPSHOT")) .build() } sealed trait Component object Component { /** CalVer Component: Year. */ case object YYYY extends Component /** CalVer Component: Month (1-12), without a leading zero. */ case object MM extends Component /** CalVer Component: Day of Month, without a leading zero. */ case object DD extends Component /** CalVer Component: Label. * * This component contains an arbitrary string value. * * @param value * The value of the label. */ case class Label(value: String) extends Component /** CalVer Component. Git SHA. * * This component defines the length (first N characters) of the Git SHA to * take from the current branch of the current repository. An empty string * is used if lookup fails or no commits exist. * * @param length * The number of characters of the Git SHA to use. */ case class GitSha(length: Int) extends Component def describe(component: Component): String = component match { case YYYY => "YYYY" case MM => "MM" case DD => "DD" case Label(value) => value case GitSha(length) => s"SHA($length)" } } sealed abstract class Delimiter(val value: String) object Delimiter { case object Dot extends Delimiter(".") case object Hyphen extends Delimiter("-") case object Plus extends Delimiter("+") case object Underscore extends Delimiter("_") def render(delimiter: Delimiter): String = delimiter.value } final class Pattern private (val items: List[Pattern.Item]) { lazy val str: String = items.map { case Left(component) => Component.describe(component) case Right(delimiter) => Delimiter.render(delimiter) }.mkString override def toString(): String = str } object Pattern { private type Item = Either[Component, Delimiter] def builder(component: Component): Builder = Builder(component) final class Builder private () { private val buffer: ListBuffer[Item] = new ListBuffer() def addComponent(component: Component): Builder = { val _ = buffer.append(Left(component)) this } def addDelimiter(delimiter: Delimiter): Builder = { val _ = buffer.append(Right(delimiter)) this } def build(): Pattern = new Pattern(buffer.toList) } object Builder { def apply(component: Component): Builder = { val b = new Builder() b.addComponent(component) b } } } }