Skip to content

Commit

Permalink
Merge pull request #1910 from Gedochao/config-keys-reference
Browse files Browse the repository at this point in the history
Add a reference for available config keys in help & docs
  • Loading branch information
Gedochao authored Mar 8, 2023
2 parents 6df89de + e52f002 commit 864e1a5
Show file tree
Hide file tree
Showing 9 changed files with 287 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package scala.cli.commands.config

import caseapp.*

import scala.build.internal.util.ConsoleUtils.ScalaCliConsole
import scala.cli.ScalaCli.{fullRunnerName, progName}
import scala.cli.commands.pgp.PgpScalaSigningOptions
import scala.cli.commands.shared.{
Expand All @@ -13,6 +14,7 @@ import scala.cli.commands.shared.{
SharedJvmOptions
}
import scala.cli.commands.tags
import scala.cli.config.{Key, Keys}

// format: off
@HelpMessage(ConfigOptions.helpMessage, "", ConfigOptions.detailedHelpMessage)
Expand Down Expand Up @@ -86,19 +88,38 @@ object ConfigOptions {
implicit lazy val help: Help[ConfigOptions] = Help.derive
private val helpHeader: String = s"Configure global settings for $fullRunnerName."
private val cmdName = "config"
private val websiteSuffix = s"misc/$cmdName"
val helpMessage: String =
s"""$helpHeader
|
|Available keys:
| ${configKeyMessages(includeHidden = false).mkString(s"${System.lineSeparator} ")}
|
|${HelpMessages.commandFullHelpReference(cmdName)}
|${HelpMessages.commandDocWebsiteReference(websiteSuffix)}""".stripMargin
|${HelpMessages.commandDocWebsiteReference(cmdName)}""".stripMargin
private def configKeyMessages(includeHidden: Boolean): Seq[String] = {
val allKeys: Seq[Key[_]] = Keys.map.values.toSeq
val keys: Seq[Key[_]] = if includeHidden then allKeys else allKeys.filterNot(_.hidden)
val maxFullNameLength = keys.map(_.fullName.length).max
keys.sortBy(_.fullName)
.map { key =>
val currentKeyFullNameLength = maxFullNameLength - key.fullName.length
val extraSpaces =
if currentKeyFullNameLength > 0 then " " * currentKeyFullNameLength else ""
val hiddenString =
if key.hidden then s"${ScalaCliConsole.GRAY}(hidden)${Console.RESET} " else ""
s"${Console.YELLOW}${key.fullName}${Console.RESET}$extraSpaces $hiddenString${key.description}"
}
}
val detailedHelpMessage: String =
s"""$helpHeader
|
|Syntax:
| ${Console.BOLD}$progName $cmdName key value${Console.RESET}
|For example, to globally set the interactive mode:
| ${Console.BOLD}$progName $cmdName interactive true${Console.RESET}
|
|Available keys:
| ${configKeyMessages(includeHidden = true).mkString(s"${System.lineSeparator} ")}
|
|${HelpMessages.commandDocWebsiteReference(websiteSuffix)}""".stripMargin
|${HelpMessages.commandDocWebsiteReference(cmdName)}""".stripMargin
}
24 changes: 19 additions & 5 deletions modules/config/src/main/scala/scala/cli/config/Key.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,13 @@ abstract class Key[T] {
def fromString(values: Seq[String]): Either[Key.MalformedValue, T]

/** The fully qualified name of this key */
final def fullName = (prefix :+ name).mkString(".")
final def fullName: String = (prefix :+ name).mkString(".")

/** A short description of a particular key's purpose and syntax for its values. */
def description: String

/** A flag indicating whether the key should by default be hidden in help outputs or not. */
def hidden: Boolean = false

/** Whether this key corresponds to a password (see [[Key.PasswordEntry]]) */
def isPasswordOption: Boolean = false
Expand Down Expand Up @@ -76,7 +82,9 @@ object Key {

final class StringEntry(
val prefix: Seq[String],
val name: String
val name: String,
val description: String = "",
override val hidden: Boolean = false
) extends Key[String] {
def parse(json: Array[Byte]): Either[EntryError, String] =
try Right(readFromArray(json)(stringCodec))
Expand All @@ -97,7 +105,9 @@ object Key {

final class BooleanEntry(
val prefix: Seq[String],
val name: String
val name: String,
val description: String = "",
override val hidden: Boolean = false
) extends Key[Boolean] {
def parse(json: Array[Byte]): Either[EntryError, Boolean] =
try Right(readFromArray(json)(booleanCodec))
Expand All @@ -118,7 +128,9 @@ object Key {

final class PasswordEntry(
val prefix: Seq[String],
val name: String
val name: String,
val description: String = "",
override val hidden: Boolean = false
) extends Key[PasswordOption] {
def parse(json: Array[Byte]): Either[EntryError, PasswordOption] =
try {
Expand Down Expand Up @@ -150,7 +162,9 @@ object Key {

final class StringListEntry(
val prefix: Seq[String],
val name: String
val name: String,
val description: String = "",
override val hidden: Boolean = false
) extends Key[List[String]] {
def parse(json: Array[Byte]): Either[EntryError, List[String]] =
try Right(readFromArray(json)(stringListCodec))
Expand Down
130 changes: 112 additions & 18 deletions modules/config/src/main/scala/scala/cli/config/Keys.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,125 @@ import scala.collection.mutable.ListBuffer

object Keys {

val userName = new Key.StringEntry(Seq("publish", "user"), "name")
val userEmail = new Key.StringEntry(Seq("publish", "user"), "email")
val userUrl = new Key.StringEntry(Seq("publish", "user"), "url")
val userName = new Key.StringEntry(
prefix = Seq("publish", "user"),
name = "name",
description = "The 'name' user detail, used for publishing.",
hidden = true
)
val userEmail = new Key.StringEntry(
prefix = Seq("publish", "user"),
name = "email",
description = "The 'email' user detail, used for publishing.",
hidden = true
)
val userUrl = new Key.StringEntry(
prefix = Seq("publish", "user"),
name = "url",
description = "The 'url' user detail, used for publishing.",
hidden = true
)

val ghToken = new Key.PasswordEntry(Seq("github"), "token")
val ghToken = new Key.PasswordEntry(
prefix = Seq("github"),
name = "token",
description = "GitHub token.",
hidden = true
)

val pgpSecretKey = new Key.PasswordEntry(Seq("pgp"), "secret-key")
val pgpSecretKeyPassword = new Key.PasswordEntry(Seq("pgp"), "secret-key-password")
val pgpPublicKey = new Key.PasswordEntry(Seq("pgp"), "public-key")
val pgpSecretKey = new Key.PasswordEntry(
prefix = Seq("pgp"),
name = "secret-key",
description = "The PGP secret key, used for signing.",
hidden = true
)
val pgpSecretKeyPassword = new Key.PasswordEntry(
prefix = Seq("pgp"),
name = "secret-key-password",
description = "The PGP secret key password, used for signing.",
hidden = true
)
val pgpPublicKey = new Key.PasswordEntry(
prefix = Seq("pgp"),
name = "public-key",
description = "The PGP public key, used for signing.",
hidden = true
)

val actions = new Key.BooleanEntry(Seq.empty, "actions")
val interactive = new Key.BooleanEntry(Seq.empty, "interactive")
val power = new Key.BooleanEntry(Seq.empty, "power")
val actions = new Key.BooleanEntry(
prefix = Seq.empty,
name = "actions",
description = "Globally enables actionable diagnostics. Enabled by default."
)
val interactive = new Key.BooleanEntry(
prefix = Seq.empty,
name = "interactive",
description = "Globally enables interactive mode (the '--interactive' flag)."
)
val power = new Key.BooleanEntry(
prefix = Seq.empty,
name = "power",
description = "Globally enables power mode (the '--power' launcher flag)."
)

val suppressDirectivesInMultipleFilesWarning =
new Key.BooleanEntry(Seq("suppress-warning"), "directives-in-multiple-files")
new Key.BooleanEntry(
prefix = Seq("suppress-warning"),
name = "directives-in-multiple-files",
description =
"Globally suppresses warnings about directives declared in multiple source files."
)
val suppressOutdatedDependenciessWarning =
new Key.BooleanEntry(Seq("suppress-warning"), "outdated-dependencies-files")
new Key.BooleanEntry(
prefix = Seq("suppress-warning"),
name = "outdated-dependencies-files",
description = "Globally suppresses warnings about outdated dependencies."
)

val proxyAddress = new Key.StringEntry(Seq("httpProxy"), "address")
val proxyUser = new Key.PasswordEntry(Seq("httpProxy"), "user")
val proxyPassword = new Key.PasswordEntry(Seq("httpProxy"), "password")
val proxyAddress = new Key.StringEntry(
prefix = Seq("httpProxy"),
name = "address",
description = "HTTP proxy address.",
hidden = true
)
val proxyUser = new Key.PasswordEntry(
prefix = Seq("httpProxy"),
name = "user",
description = "HTTP proxy user (used for authentication).",
hidden = true
)
val proxyPassword = new Key.PasswordEntry(
prefix = Seq("httpProxy"),
name = "password",
description = "HTTP proxy password (used for authentication).",
hidden = true
)

val repositoryMirrors = new Key.StringListEntry(Seq("repositories"), "mirrors")
val defaultRepositories = new Key.StringListEntry(Seq("repositories"), "default")
val repositoryMirrors = new Key.StringListEntry(
prefix = Seq("repositories"),
name = "mirrors",
description =
s"Repository mirrors, syntax: repositories.mirrors maven:*=https://repository.company.com/maven",
hidden = true
)
val defaultRepositories = new Key.StringListEntry(
prefix = Seq("repositories"),
name = "default",
description =
"Default repository, syntax: https://first-repo.company.com https://second-repo.company.com",
hidden = true
)

// Kept for binary compatibility
val repositoriesMirrors = repositoryMirrors

// setting indicating if the global interactive mode was suggested
val globalInteractiveWasSuggested = new Key.BooleanEntry(Seq.empty, "interactive-was-suggested")
val globalInteractiveWasSuggested = new Key.BooleanEntry(
prefix = Seq.empty,
name = "interactive-was-suggested",
description = "Setting indicating if the global interactive mode was already suggested.",
hidden = true
)

def all: Seq[Key[_]] = Seq[Key[_]](
actions,
Expand All @@ -46,6 +134,7 @@ object Keys {
globalInteractiveWasSuggested,
interactive,
suppressDirectivesInMultipleFilesWarning,
suppressOutdatedDependenciessWarning,
pgpPublicKey,
pgpSecretKey,
pgpSecretKeyPassword,
Expand Down Expand Up @@ -120,6 +209,8 @@ object Keys {

val repositoryCredentials: Key[List[RepositoryCredentials]] =
new Key[List[RepositoryCredentials]] {
override val description: String = "Repository credentials, syntax: value:user value:password"
override val hidden: Boolean = true

private def asJson(credentials: RepositoryCredentials): RepositoryCredentialsAsJson =
RepositoryCredentialsAsJson(
Expand Down Expand Up @@ -242,6 +333,9 @@ object Keys {
}

val publishCredentials: Key[List[PublishCredentials]] = new Key[List[PublishCredentials]] {
override val description: String =
"Publishing credentials, syntax: s1.oss.sonatype.org value:user value:password"
override val hidden: Boolean = true

private def asJson(credentials: PublishCredentials): PublishCredentialsAsJson =
PublishCredentialsAsJson(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,57 @@ import caseapp.HelpMessage

import java.util.stream.IntStream

import scala.annotation.tailrec
import scala.build.internal.util.ConsoleUtils.*

object ReferenceDocUtils {
extension (s: String) {
def consoleToFence: String =
s
.linesIterator
.fold("") { (acc, line) =>
val maybeOpenFence =
if line.contains(Console.BOLD) then
"""```sh
|""".stripMargin
else if line.contains(ScalaCliConsole.GRAY) then
"""```scala
|""".stripMargin
else ""
val maybeCloseFence =
if line.contains(Console.RESET) then
"""
|```""".stripMargin
else ""
val newLine = s"$maybeOpenFence${line.noConsoleKeys}$maybeCloseFence"
if acc.isEmpty then newLine
else s"""$acc
|$newLine""".stripMargin
}
def consoleToFence: String = {
@tailrec
def consoleToFenceRec(
remainingLines: Seq[String],
fenceOpen: Boolean = false,
acc: String = ""
): String =
remainingLines.headOption match
case None => acc
case Some(line) =>
val openFenceString =
if line.contains(Console.BOLD) then
"""```sh
|""".stripMargin
else if line.contains(ScalaCliConsole.GRAY) then
"""```scala
|""".stripMargin
else ""
val currentFenceOpen = fenceOpen || openFenceString.nonEmpty
val closeFenceString =
if currentFenceOpen && line.contains(Console.RESET) then
"""
|```""".stripMargin
else ""
val newFenceOpen = currentFenceOpen && closeFenceString.isEmpty
val newLine = s"$openFenceString${line.noConsoleKeys}$closeFenceString"
val newAcc =
if acc.isEmpty then newLine
else
s"""$acc
|$newLine""".stripMargin
consoleToFenceRec(remainingLines.tail, newFenceOpen, newAcc)
consoleToFenceRec(s.linesIterator.toSeq)
}
def filterOutHiddenStrings: String =
s.replace(s"${ScalaCliConsole.GRAY}(hidden)${Console.RESET} ", "")
def consoleYellowToMdBullets: String = s.replace(Console.YELLOW, "- ")
def consoleToMarkdown: String = s.filterOutHiddenStrings.consoleYellowToMdBullets.consoleToFence
}
extension (helpMessage: HelpMessage) {
def referenceDocMessage: String = helpMessage.message.consoleToFence.noConsoleKeys
def referenceDocMessage: String = helpMessage.message.consoleToMarkdown
def referenceDocDetailedMessage: String = {
val msg =
if helpMessage.detailedMessage.nonEmpty then helpMessage.detailedMessage
else helpMessage.message
msg.consoleToFence
msg.consoleToMarkdown
}
}

Expand Down
Loading

0 comments on commit 864e1a5

Please sign in to comment.