From bfdba8f5ca76aace12752446716c277e84527e3b Mon Sep 17 00:00:00 2001 From: Pawel Batko Date: Fri, 19 Nov 2021 13:39:27 +0100 Subject: [PATCH 1/7] [DPP-673][Self-service error-codes] Generate error code directory compatible with both pdf and html docs --- docs/BUILD.bazel | 12 ++ docs/configs/pdf/index.rst | 1 + docs/scripts/live-preview.sh | 4 + .../source/error-codes/self-service/index.rst | 13 +- ledger/error/generator/BUILD.bazel | 20 ++ .../app/ErrorCodeInventoryDocsGen_App.scala | 204 ++++++++++++++++++ .../com/daml/error/generator/app/Main.scala | 35 +-- .../ErrorCodeDocumentationGenerator.scala | 19 +- .../daml/error/generator/ErrorDocItem.scala | 20 +- .../daml/error/generator/GroupDocItem.scala | 10 +- .../ErrorCodeDocumentationGeneratorSpec.scala | 4 +- .../scala/com/daml/error/ErrorClass.scala | 26 --- .../main/scala/com/daml/error/ErrorCode.scala | 2 +- .../scala/com/daml/error/ErrorGroup.scala | 8 +- .../scala/com/daml/error/ErrorGroupPath.scala | 30 +++ .../daml/error/definitions/ErrorGroups.scala | 4 +- .../scala/com/daml/error/ErrorGroupSpec.scala | 26 +-- .../utils/testpackage/DeprecatedError.scala | 4 +- .../utils/testpackage/SeriousError.scala | 4 +- .../testpackage/subpackage/MildErrors.scala | 5 +- 20 files changed, 353 insertions(+), 98 deletions(-) create mode 100644 ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGen_App.scala delete mode 100644 ledger/error/src/main/scala/com/daml/error/ErrorClass.scala create mode 100644 ledger/error/src/main/scala/com/daml/error/ErrorGroupPath.scala diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 693da4fc947f..25ba0059f29f 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -100,11 +100,14 @@ genrule( "//ledger-api/grpc-definitions:docs", "//:LICENSE", "//:NOTICES", + ":generate-docs-error-code-inventory-into-rst-file", ], outs = ["source.tar.gz"], cmd = """ cp -rL docs/source source + mkdir -p -- source/error-codes/self-service + cp -- $(location //docs:generate-docs-error-code-inventory-into-rst-file) source/error-codes/self-service/error_codes_inventory.rst # Copy in Stdlib mkdir -p source/daml/stdlib tar xf $(location //compiler/damlc:daml-base-rst.tar.gz) \\ @@ -666,6 +669,15 @@ genrule( visibility = ["//visibility:public"], ) if scala_major_version == "2.13" else None +genrule( + name = "generate-docs-error-code-inventory-into-rst-file", + srcs = [], + outs = ["error_codes_inventory.rst"], + cmd = "$(location //ledger/error/generator:generate-docs-error-code-inventory-app) $(location error_codes_inventory.rst)", + tools = ["//ledger/error/generator:generate-docs-error-code-inventory-app"], + visibility = ["//visibility:public"], +) + exports_files([ "source/daml-script/template-root/src/ScriptExample.daml", ]) diff --git a/docs/configs/pdf/index.rst b/docs/configs/pdf/index.rst index 550ba3953a73..0d4452af62ba 100644 --- a/docs/configs/pdf/index.rst +++ b/docs/configs/pdf/index.rst @@ -45,6 +45,7 @@ Building applications upgrade/index app-dev/authorization app-dev/ledger-api + error-codes/self-service/index Deploying to Daml ledgers ------------------------- diff --git a/docs/scripts/live-preview.sh b/docs/scripts/live-preview.sh index 423824461b9b..98e23f92841e 100755 --- a/docs/scripts/live-preview.sh +++ b/docs/scripts/live-preview.sh @@ -63,6 +63,10 @@ do cp -L ../../bazel-bin/docs/DigitalAssetSDK.pdf $BUILD_DIR/gen/_downloads fi if [ "$arg" = "--gen" ]; then + + bazel build //docs:generate-docs-error-code-inventory-into-rst-file + cp -L ../../bazel-bin/docs/error_codes_inventory.rst $BUILD_DIR/source/error-codes/self-service/error_codes_inventory.rst + # Hoogle bazel build //compiler/damlc:daml-base-hoogle.txt mkdir -p $BUILD_DIR/gen/hoogle_db diff --git a/docs/source/error-codes/self-service/index.rst b/docs/source/error-codes/self-service/index.rst index cbfdf609f3be..055939dab4c3 100644 --- a/docs/source/error-codes/self-service/index.rst +++ b/docs/source/error-codes/self-service/index.rst @@ -358,11 +358,14 @@ but there is no guarantee given that additional information will be preserved ac Error Codes Inventory ********************** -.. list-all-error-codes:: + +.. This file is generated: +.. include:: error_codes_inventory.rst Error Codes Migration Guide ---------------------------- +***************************** + The Ledger API gRPC error codes change introduced in the Daml SDK 1.18 release involves breaking compatibility with previous releases for some service Ledger API endpoints. @@ -375,7 +378,7 @@ For example, a service endpoint previously returning gRPC status code ``CODE_A`` and only an entry for the change from ``CODE_A`` in ``CODE_B`` is included in the table below. Ledger API -^^^^^^^^^^ +--------------------------- The table below outlines generic gRPC status code changes pertaining to the Ledger API and apply to all ledger backends. For changes specific to a ledger backend, check the next subsections. @@ -481,7 +484,7 @@ and apply to all ledger backends. For changes specific to a ledger backend, chec +-----------------------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ Sandbox (classic) -^^^^^^^^^^^^^^^^^ +--------------------------- The following gRPC status codes have changed for submission rejections in Sandbox classic. @@ -507,7 +510,7 @@ The following gRPC status codes have changed for submission rejections in Sandbo Daml Sandbox and VMBC -^^^^^^^^^^^^^^^^^^^^^ +--------------------------- The following gRPC status codes have changed for submission rejections in the Ledger API backed by KV-based ledgers (Daml Sandbox and VMBC). diff --git a/ledger/error/generator/BUILD.bazel b/ledger/error/generator/BUILD.bazel index ebc52e6f4796..2bd1e715de19 100644 --- a/ledger/error/generator/BUILD.bazel +++ b/ledger/error/generator/BUILD.bazel @@ -29,6 +29,26 @@ da_scala_binary( ], ) +da_scala_binary( + name = "generate-docs-error-code-inventory-app", + srcs = glob(["app/src/main/scala/**/*.scala"]), + main_class = "com.daml.error.generator.app.ErrorCodeInventoryDocsGen_App", + resources = glob(["src/main/resources/**/*"]), + scala_deps = [ + "@maven//:io_circe_circe_core", + "@maven//:org_typelevel_cats_core", + ], + visibility = ["//visibility:public"], + runtime_deps = [ + # Add the KVErrors to the classpath so they can be picked up by the generator + "//ledger/participant-state/kvutils", + ], + deps = [ + "//ledger/error", + "//ledger/error/generator:lib", + ], +) + da_scala_library( name = "lib", srcs = glob(["lib/src/main/scala/**/*.scala"]), diff --git a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGen_App.scala b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGen_App.scala new file mode 100644 index 000000000000..6620c68ca906 --- /dev/null +++ b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGen_App.scala @@ -0,0 +1,204 @@ +// Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.daml.error.generator.app + +import java.nio.file.{Files, Paths, StandardOpenOption} + +import com.daml.error.{ErrorGroupPath, ErrorGroupSegment} +import com.daml.error.generator.{ErrorCodeDocumentationGenerator, ErrorDocItem, GroupDocItem} + +import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer + +/** Generates error codes inventory as a reStructuredText + */ +object ErrorCodeInventoryDocsGen_App { + + def main(args: Array[String]): Unit = { + val text = { + val (errorDocItems, groupDocItems): (Seq[ErrorDocItem], Seq[GroupDocItem]) = + new ErrorCodeDocumentationGenerator().getDocItems + + val groupSegmentsToExplanationMap: Map[List[ErrorGroupSegment], Option[String]] = + groupDocItems.map { groupDocItem: GroupDocItem => + groupDocItem.errorGroupPath.segments -> groupDocItem.explanation.map(_.explanation) + }.toMap + + val errorCodes: Seq[ErrorCodeValue] = errorDocItems.map { (errorDocItem: ErrorDocItem) => + ErrorCodeValue( + category = errorDocItem.category, + errorGroupPath = errorDocItem.errorGroupPath, + conveyance = errorDocItem.conveyance.getOrElse("").replace('\n', ' '), + code = errorDocItem.code, + deprecationO = errorDocItem.deprecation.map(_.deprecation.replace('\n', ' ')), + explanation = errorDocItem.explanation.fold("")(_.explanation).replace('\n', ' '), + resolution = errorDocItem.resolution.fold("")(_.resolution).replace('\n', ' '), + ) + } + + val root = ErrorGroupTree.empty() + + // Build trie like structure of error groups and error codes. + errorCodes.foreach(errorCode => + root.insertErrorCode(errorCode, groupSegmentsToExplanationMap) + ) + // Traverse the trie to emit error code text. + ErrorGroupTree + .collectErrorCodesAsReStructuredTextSubsections(root) + .mkString("\n\n") + } + + if (args.length >= 1) { + val outputFile = Paths.get(args(0)) + val _ = Files.write(outputFile, text.getBytes, StandardOpenOption.CREATE_NEW) + } else { + println(text) + } + + } + +} + +case class ErrorCodeValue( + code: String, + errorGroupPath: ErrorGroupPath, + category: String, + explanation: String, + resolution: String, + conveyance: String, + deprecationO: Option[String], +) + +class ErrorGroupTree( + val name: String, + val explanation: Option[String] = None, + children: mutable.Map[ErrorGroupSegment, ErrorGroupTree] = + new mutable.HashMap[ErrorGroupSegment, ErrorGroupTree](), + errorCodes: mutable.Map[String, ErrorCodeValue] = new mutable.HashMap[String, ErrorCodeValue](), +) { + + def sortedSubGroups(): List[ErrorGroupTree] = { + children.values.toList.sortBy(_.name) + } + + def sortedErrorCodes(): List[ErrorCodeValue] = { + errorCodes.values.toList.sortBy(_.code) + } + + def insertErrorCode( + errorCode: ErrorCodeValue, + getExplanation: (List[ErrorGroupSegment]) => Option[String], + ): Unit = { + insert( + remaining = errorCode.errorGroupPath.segments, + path = Nil, + errorCode = errorCode, + getExplanation = getExplanation, + ) + } + + private def insert( + remaining: List[ErrorGroupSegment], + errorCode: ErrorCodeValue, + path: List[ErrorGroupSegment], + getExplanation: (List[ErrorGroupSegment]) => Option[String], + ): Unit = { + + remaining match { + case Nil => + assert(!errorCodes.contains(errorCode.code), s"Code: ${errorCode.code} is already present!") + errorCodes.put(errorCode.code, errorCode): Unit + case headGroup :: tail => + val newPath = path :+ headGroup + if (!children.contains(headGroup)) { + children.put( + headGroup, + new ErrorGroupTree( + name = headGroup.docName, + explanation = getExplanation(newPath), + ), + ) + } + children(headGroup).insert( + remaining = tail, + errorCode = errorCode, + path = newPath, + getExplanation, + ) + } + } + +} + +object ErrorGroupTree { + def empty(): ErrorGroupTree = new ErrorGroupTree( + name = "", + explanation = None, + ) + + def collectErrorCodesAsReStructuredTextSubsections(root: ErrorGroupTree): List[String] = { + + // in-order tree traversal + def iter( + tree: ErrorGroupTree, + path: List[String], + groupHierarchicalIndex: List[Int], + ): List[String] = { + val newPath = path :+ tree.name + val textBuffer: mutable.ArrayBuffer[String] = new ArrayBuffer[String]() + + // Add group text + textBuffer.addOne(s"""${groupHierarchicalIndex.mkString(".")}. ${newPath.mkString(" / ")} + |------------------------------------------------------------------------------------------------------------------- + | + |${tree.explanation.getOrElse("")} + |""".stripMargin) + // Add error codes in this group + textBuffer.addAll( + tree + .sortedErrorCodes() + .map(handleErrorCode) + ) + // Recurse to sub-groups + textBuffer.addAll( + tree + .sortedSubGroups() + .zipWithIndex + .flatMap { case (subGroup: ErrorGroupTree, index: Int) => + iter( + subGroup, + newPath, + groupHierarchicalIndex = groupHierarchicalIndex :+ (index + 1), + ) + } + ) + textBuffer.toList + } + + root + .sortedSubGroups() + .zipWithIndex + .flatMap { case (subGroup, i) => + iter(subGroup, path = List(), groupHierarchicalIndex = List(i + 1)) + } + } + + private def handleErrorCode(e: ErrorCodeValue): String = { + val deprecationText = e.deprecationO.fold("")(d => s""" + | **Depreciation**: ${d} + | """.stripMargin) + s"""Error code: ${e.code} + |^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | $deprecationText + | **Explanation**: ${e.explanation} + | + | **Category**: ${e.category} + | + | **Conveyance**: ${e.conveyance} + | + | **Resolution**: ${e.resolution} + | + |""".stripMargin + } +} diff --git a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala index 9123f1617190..7891b0b62ca8 100644 --- a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala +++ b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala @@ -3,7 +3,7 @@ package com.daml.error.generator.app -import com.daml.error.Grouping +import com.daml.error.ErrorGroupSegment import com.daml.error.generator.{ErrorCodeDocumentationGenerator, ErrorDocItem, GroupDocItem} import io.circe.Encoder import io.circe.syntax._ @@ -16,14 +16,14 @@ object Main { case class Output(errorCodes: Seq[ErrorDocItem], groups: Seq[GroupDocItem]) - implicit val groupingEncode: Encoder[Grouping] = + implicit val groupingEncode: Encoder[ErrorGroupSegment] = Encoder.forProduct2( "docName", "className", - )(i => + )((grouping: ErrorGroupSegment) => ( - i.docName, - i.group.map(_.fullClassName), + grouping.docName, + grouping.fullClassName, ) ) @@ -39,14 +39,14 @@ object Main { "resolution", )(i => ( - i.className, + i.fullClassName, i.category, - i.hierarchicalGrouping, + i.errorGroupPath.segments, i.conveyance, i.code, - i.deprecation.deprecation, - i.explanation.explanation, - i.resolution.resolution, + i.deprecation.fold("")(_.deprecation), + i.explanation.fold("")(_.explanation), + i.resolution.fold("")(_.resolution), ) ) @@ -56,8 +56,8 @@ object Main { "explanation", )(i => ( - i.className, - i.explanation.explanation, + i.fullClassName, + i.explanation.fold("")(_.explanation), ) ) @@ -66,10 +66,15 @@ object Main { def main(args: Array[String]): Unit = { val (errorCodes, groups) = new ErrorCodeDocumentationGenerator().getDocItems - val outputFile = Paths.get(args(0)) val output = Output(errorCodes, groups) val outputText: String = output.asJson.spaces2 - val outputBytes = outputText.getBytes - val _ = Files.write(outputFile, outputBytes, StandardOpenOption.CREATE_NEW) + + if (args.length >= 1) { + val outputFile = Paths.get(args(0)) + Files.write(outputFile, outputText.getBytes, StandardOpenOption.CREATE_NEW): Unit + } else { + println(outputText) + } + } } diff --git a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala index ac286b4c724f..30c06ad7fc41 100644 --- a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala +++ b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala @@ -36,7 +36,7 @@ class ErrorCodeDocumentationGenerator(prefixes: Array[String] = Array("com.daml" } val groups = getInstances[ErrorGroup] - groups.view.map(_.errorClass).groupBy(identity).collect { + groups.view.map(_.errorGroupPath).groupBy(identity).collect { case (group, occurrences) if occurrences.size > 1 => sys.error( s"There are ${occurrences.size} groups named $group but we require each group class name to be unique! " + @@ -63,14 +63,14 @@ class ErrorCodeDocumentationGenerator(prefixes: Array[String] = Array("com.daml" getErrorDocumentationAnnotations(error) ErrorDocItem( - className = error.getClass.getName, + fullClassName = error.getClass.getName, category = simpleClassName(error.category), - hierarchicalGrouping = error.parent.groupings.filter(_.docName.nonEmpty), - conveyance = error.errorConveyanceDocString.getOrElse(""), + errorGroupPath = error.errorGroupPath, + conveyance = error.errorConveyanceDocString, code = error.id, - deprecation = deprecation.getOrElse(Deprecation("")), - explanation = explanation.getOrElse(Explanation("")), - resolution = resolution.getOrElse(Resolution("")), + deprecation = deprecation, + explanation = explanation, + resolution = resolution, ) } @@ -79,8 +79,9 @@ class ErrorCodeDocumentationGenerator(prefixes: Array[String] = Array("com.daml" getGroupDocumentationAnnotations(group) GroupDocItem( - className = group.getClass.getName, - explanation = explanation.getOrElse(Explanation("")), + errorGroupPath = group.errorGroupPath, + fullClassName = group.fullClassName, + explanation = explanation, ) } diff --git a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorDocItem.scala b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorDocItem.scala index b95641e36472..9d5f66913146 100644 --- a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorDocItem.scala +++ b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorDocItem.scala @@ -3,26 +3,26 @@ package com.daml.error.generator -import com.daml.error.{Deprecation, Explanation, Grouping, Resolution} +import com.daml.error.{Deprecation, ErrorGroupPath, Explanation, Resolution} /** Contains error presentation data to be used for documentation rendering on the website. * - * @param className The error class name (see [[com.daml.error.ErrorCode]]). + * @param fullClassName The error class name (see [[com.daml.error.ErrorCode]]). * @param category The error code category (see [[com.daml.error.ErrorCategory]]). - * @param hierarchicalGrouping The hierarchical code grouping - * (see [[com.daml.error.ErrorClass]] and [[com.daml.error.ErrorGroup]]). + * @param errorGroupPath The hierarchical code grouping + * (see [[com.daml.error.ErrorGroupPath]] and [[com.daml.error.ErrorGroup]]). * @param conveyance Provides a statement about the form this error will be returned to the user. * @param code The error identifier. * @param explanation The detailed error explanation. * @param resolution The suggested error resolution. */ case class ErrorDocItem( - className: String, // TODO error codes: Rename to `errorCodeName` or `errorCodeClassName` to prevent confusion + fullClassName: String, // TODO error codes: Rename to `errorCodeName` or `errorCodeClassName` to prevent confusion category: String, - hierarchicalGrouping: List[Grouping], - conveyance: String, + errorGroupPath: ErrorGroupPath, + conveyance: Option[String], code: String, - deprecation: Deprecation, - explanation: Explanation, - resolution: Resolution, + deprecation: Option[Deprecation], + explanation: Option[Explanation], + resolution: Option[Resolution], ) diff --git a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala index 00243ff43c12..78343ca1a1a8 100644 --- a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala +++ b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala @@ -3,14 +3,16 @@ package com.daml.error.generator -import com.daml.error.Explanation +import com.daml.error.{ErrorGroupPath, Explanation} /** Contains error presentation data to be used for documentation rendering on the website. * - * @param className The group class name (see [[com.daml.error.ErrorGroup]]). + * @param fullClassName The group class name (see [[com.daml.error.ErrorGroup]]). * @param explanation The detailed error explanation. + * @param errorGroupPath Hierarchical grouping of this error group. */ case class GroupDocItem( - className: String, - explanation: Explanation, + fullClassName: String, + explanation: Option[Explanation], + errorGroupPath: ErrorGroupPath, ) diff --git a/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala b/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala index f074e4eede53..939d064de3ae 100644 --- a/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala +++ b/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala @@ -6,7 +6,7 @@ package com.daml.error.generator import com.daml.error.utils.testpackage.subpackage.MildErrors import com.daml.error.utils.testpackage.subpackage.MildErrors.NotSoSeriousError import com.daml.error.utils.testpackage.{DeprecatedError, SeriousError} -import com.daml.error.{Deprecation, Explanation, Grouping, Resolution} +import com.daml.error.{Deprecation, Explanation, ErrorGroupSegment, Resolution} import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers @@ -51,7 +51,7 @@ class ErrorCodeDocumentationGeneratorSpec extends AnyFlatSpec with Matchers { className = NotSoSeriousError.getClass.getTypeName, category = "TransientServerFailure", hierarchicalGrouping = - List(Grouping("Some grouping", None), Grouping("MildErrors", Some(MildErrors))), + List(ErrorGroupSegment("Some grouping", None), Grouping("MildErrors", Some(MildErrors))), conveyance = "This error is logged with log-level INFO on the server side.\nThis error is exposed on the API with grpc-status UNAVAILABLE including a detailed error message", code = "TEST_ROUTINE_FAILURE_PLEASE_IGNORE", diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala b/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala deleted file mode 100644 index 64d06bf4555a..000000000000 --- a/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package com.daml.error - -/** A grouping of errors. - * - * @param docName The name that will appear in the generated documentation for the grouping. - * @param group If the grouping is defined by an [[ErrorGroup]], the associated instance. - */ -case class Grouping( - docName: String, - group: Option[ErrorGroup], -) - -/** The classes [[ErrorClass]] and [[ErrorGroup]] are used to hierarchically structure error codes (their - * hierarchical structure affects how they are displayed on the website) - */ -case class ErrorClass(groupings: List[Grouping]) { - def extend(grouping: Grouping): ErrorClass = - ErrorClass(groupings :+ grouping) -} - -object ErrorClass { - def root(): ErrorClass = ErrorClass(Nil) -} diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala b/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala index 46cb4d7a7f93..a3bcc3532194 100644 --- a/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala +++ b/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala @@ -41,7 +41,7 @@ import scala.util.matching.Regex * } */ abstract class ErrorCode(val id: String, val category: ErrorCategory)(implicit - val parent: ErrorClass + val errorGroupPath: ErrorGroupPath ) { require(id.nonEmpty, "error-id must be non empty") diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala b/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala index 3e6397d2a2da..059a2d2768a4 100644 --- a/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala +++ b/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala @@ -3,13 +3,13 @@ package com.daml.error -abstract class ErrorGroup()(implicit parent: ErrorClass) { +abstract class ErrorGroup()(implicit parent: ErrorGroupPath) { val fullClassName: String = getClass.getName // Hit https://github.com/scala/bug/issues/5425?orig=1 here: we cannot use .getSimpleName in deeply nested objects // TODO error codes: Switch to using .getSimpleName when switching to JDK 9+ - implicit val errorClass: ErrorClass = resolveErrorClass() + implicit val errorGroupPath: ErrorGroupPath = resolveErrorClass() - private def resolveErrorClass(): ErrorClass = { + private def resolveErrorClass(): ErrorGroupPath = { val name = fullClassName .replace("$", ".") .split("\\.") @@ -21,6 +21,6 @@ abstract class ErrorGroup()(implicit parent: ErrorClass) { s"Could not parse full class name: '${fullClassName}' for the error class name" ) ) - parent.extend(Grouping(name, Some(this))) + parent.extend(ErrorGroupSegment(docName = name, fullClassName = fullClassName)) } } diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorGroupPath.scala b/ledger/error/src/main/scala/com/daml/error/ErrorGroupPath.scala new file mode 100644 index 000000000000..5a48263238e2 --- /dev/null +++ b/ledger/error/src/main/scala/com/daml/error/ErrorGroupPath.scala @@ -0,0 +1,30 @@ +// Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.daml.error + +/** A component of [[ErrorGroupPath]] + * + * @param docName The name that will appear in the generated documentation for the grouping. + * @param fullClassName Full class name of the corresponding [[ErrorGroup]]. + */ +case class ErrorGroupSegment( + docName: String, + fullClassName: String, +) { + require( + docName.trim.nonEmpty, + s"ErrorGroupSegment.docName must be non mmpty and must contain not only whitespace characters, but was: |${docName}|!", + ) +} + +/** Used to hierarchically structure error codes in the official documentation. + */ +case class ErrorGroupPath(segments: List[ErrorGroupSegment]) { + def extend(last: ErrorGroupSegment): ErrorGroupPath = + ErrorGroupPath(segments :+ last) +} + +object ErrorGroupPath { + def root(): ErrorGroupPath = ErrorGroupPath(Nil) +} diff --git a/ledger/error/src/main/scala/com/daml/error/definitions/ErrorGroups.scala b/ledger/error/src/main/scala/com/daml/error/definitions/ErrorGroups.scala index c2fea7edc60f..f607f2a4fe89 100644 --- a/ledger/error/src/main/scala/com/daml/error/definitions/ErrorGroups.scala +++ b/ledger/error/src/main/scala/com/daml/error/definitions/ErrorGroups.scala @@ -3,10 +3,10 @@ package com.daml.error.definitions -import com.daml.error.{ErrorClass, ErrorGroup} +import com.daml.error.{ErrorGroupPath, ErrorGroup} object ErrorGroups { - val rootErrorClass: ErrorClass = ErrorClass.root() + val rootErrorClass: ErrorGroupPath = ErrorGroupPath.root() object ParticipantErrorGroup extends ErrorGroup()(rootErrorClass) { abstract class IndexErrorGroup extends ErrorGroup() { diff --git a/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala b/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala index fde395064f59..5596d01ba628 100644 --- a/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala +++ b/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala @@ -9,31 +9,27 @@ import org.scalatest.matchers.should.Matchers class ErrorGroupSpec extends AnyFlatSpec with Matchers with BeforeAndAfter { - object ErrorGroupBar extends ErrorGroup()(ErrorClass.root()) + object ErrorGroupBar extends ErrorGroup()(ErrorGroupPath.root()) - object ErrorGroupsFoo { - private implicit val errorClass: ErrorClass = ErrorClass.root() - - object ErrorGroupFoo1 extends ErrorGroup() { - object ErrorGroupFoo2 extends ErrorGroup() { - object ErrorGroupFoo3 extends ErrorGroup() - } + object ErrorGroupFoo1 extends ErrorGroup()(ErrorGroupPath.root()) { + object ErrorGroupFoo2 extends ErrorGroup() { + object ErrorGroupFoo3 extends ErrorGroup() } } it should "resolve correct error group names" in { - ErrorGroupsFoo.ErrorGroupFoo1.ErrorGroupFoo2.ErrorGroupFoo3.errorClass shouldBe ErrorClass( + ErrorGroupFoo1.ErrorGroupFoo2.ErrorGroupFoo3.errorGroupPath shouldBe ErrorGroupPath( List( - Grouping("ErrorGroupFoo1", Some(ErrorGroupsFoo.ErrorGroupFoo1)), - Grouping("ErrorGroupFoo2", Some(ErrorGroupsFoo.ErrorGroupFoo1.ErrorGroupFoo2)), - Grouping( + ErrorGroupSegment("ErrorGroupFoo1", ErrorGroupFoo1.fullClassName), + ErrorGroupSegment("ErrorGroupFoo2", ErrorGroupFoo1.ErrorGroupFoo2.fullClassName), + ErrorGroupSegment( "ErrorGroupFoo3", - Some(ErrorGroupsFoo.ErrorGroupFoo1.ErrorGroupFoo2.ErrorGroupFoo3), + ErrorGroupFoo1.ErrorGroupFoo2.ErrorGroupFoo3.fullClassName, ), ) ) - ErrorGroupBar.errorClass shouldBe ErrorClass( - List(Grouping("ErrorGroupBar", Some(ErrorGroupBar))) + ErrorGroupBar.errorGroupPath shouldBe ErrorGroupPath( + List(ErrorGroupSegment("ErrorGroupBar", ErrorGroupBar.fullClassName)) ) } diff --git a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/DeprecatedError.scala b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/DeprecatedError.scala index 1a90c49ed3fe..984b70bcc0d4 100644 --- a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/DeprecatedError.scala +++ b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/DeprecatedError.scala @@ -4,7 +4,7 @@ package com.daml.error.utils.testpackage import com.daml.error.{Explanation, Resolution} -import com.daml.error.{BaseError, ErrorCategory, ErrorClass, ErrorCode} +import com.daml.error.{BaseError, ErrorCategory, ErrorGroupPath, ErrorCode} import com.daml.logging.LoggingContext @deprecated("deprecated.") @@ -12,7 +12,7 @@ import com.daml.logging.LoggingContext @Explanation("Things happen.") case object DeprecatedError extends ErrorCode("DEPRECATED_ERROR", ErrorCategory.SystemInternalAssumptionViolated)( - ErrorClass.root() + ErrorGroupPath.root() ) { case class Error(cause: String)(implicit val loggingContext: LoggingContext) extends BaseError { diff --git a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/SeriousError.scala b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/SeriousError.scala index 36932f8bac30..c1e2dedc06b8 100644 --- a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/SeriousError.scala +++ b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/SeriousError.scala @@ -4,14 +4,14 @@ package com.daml.error.utils.testpackage import com.daml.error.{Explanation, Resolution} -import com.daml.error.{BaseError, ErrorCategory, ErrorClass, ErrorCode} +import com.daml.error.{BaseError, ErrorCategory, ErrorGroupPath, ErrorCode} import com.daml.logging.LoggingContext @Explanation("Things happen.") @Resolution("Turn it off and on again.") case object SeriousError extends ErrorCode("BLUE_SCREEN", ErrorCategory.SystemInternalAssumptionViolated)( - ErrorClass.root() + ErrorGroupPath.root() ) { case class Error(cause: String)(implicit val loggingContext: LoggingContext) extends BaseError { diff --git a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/subpackage/MildErrors.scala b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/subpackage/MildErrors.scala index 7f06ac737204..f57cc9f2c1c4 100644 --- a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/subpackage/MildErrors.scala +++ b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/subpackage/MildErrors.scala @@ -8,7 +8,10 @@ import com.daml.logging.LoggingContext @Explanation("Groups mild errors together") object MildErrors - extends ErrorGroup()(parent = ErrorClass.root().extend(Grouping("Some grouping", None))) { + extends ErrorGroup()( + parent = + ErrorGroupPath.root().extend(ErrorGroupSegment("Some grouping", "full.class.Name123")) + ) { @Explanation("Test: Things like this always happen.") @Resolution("Test: Why not ignore?") From e479d1ab07e6d21e73ffa3039384140f0c946c96 Mon Sep 17 00:00:00 2001 From: Pawel Batko Date: Fri, 19 Nov 2021 13:50:34 +0100 Subject: [PATCH 2/7] 1 CHANGELOG_BEGIN CHANGELOG_END --- docs/BUILD.bazel | 7 +- docs/configs/html/conf.py | 1 - docs/scripts/live-preview.sh | 3 - .../self_service_error_codes_extension.py | 216 ------------------ ledger/daml-on-sql/BUILD.bazel | 7 +- 5 files changed, 2 insertions(+), 232 deletions(-) delete mode 100644 docs/sphinx_ext/self_service_error_codes_extension.py diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 25ba0059f29f..c3c77cc97879 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -18,7 +18,6 @@ exports_files( "source/tools/export/output-root/Export.daml", "source/tools/export/output-root/args.json", "source/tools/export/output-root/daml.yaml", - "sphinx_ext/self_service_error_codes_extension.py", ], ) @@ -203,7 +202,6 @@ genrule( genrule( name = "docs-no-pdf", srcs = glob([ - "sphinx_ext/**", "configs/html/**", "configs/static/pygments_daml_lexer.py", "configs/static/typescript.py", @@ -211,7 +209,6 @@ genrule( ":sources", ":theme", ":hoogle_db.tar.gz", - "//docs:generate-error-codes-json", "//language-support/java:javadoc", "//language-support/ts/daml-react:docs", "//language-support/ts/daml-ledger:docs", @@ -222,7 +219,6 @@ genrule( "@daml-cheat-sheet//:site", ":scripts/check-closing-quotes.sh", ":scripts/check-closing-quotes.sh.allow", - "//docs:error_codes_export.json", ], outs = ["html-only.tar.gz"], cmd = (""" @@ -274,7 +270,7 @@ genrule( # the PDF documentation due to issues with the FreeSerif font in the # fontspec package. So, for now we ignore `FutureWarning`. SPHINX_BUILD_EXIT_CODE=0 - SPHINX_BUILD_OUTPUT=$$(../$(location @sphinx_nix//:bin/sphinx-build) -D error_codes_json_export=../$(location //docs:error_codes_export.json) -c docs/configs/html docs/source html 2>&1) || SPHINX_BUILD_EXIT_CODE=$$? + SPHINX_BUILD_OUTPUT=$$(../$(location @sphinx_nix//:bin/sphinx-build) -c docs/configs/html docs/source html 2>&1) || SPHINX_BUILD_EXIT_CODE=$$? if [ "$$SPHINX_BUILD_EXIT_CODE" -ne 0 ]; then >&2 echo "## SPHINX-BUILD OUTPUT:" >&2 echo "$$SPHINX_BUILD_OUTPUT" @@ -318,7 +314,6 @@ genrule( tools = [ "@sphinx_nix//:bin/sphinx-build", "//bazel_tools/sh:mktgz", - "//docs:generate-error-codes-json", ] + (["@glibc_locales//:locale-archive"] if is_linux else []), ) if scala_major_version == "2.13" and not is_windows else None diff --git a/docs/configs/html/conf.py b/docs/configs/html/conf.py index fc0f26ce10a3..41cf5a03afea 100644 --- a/docs/configs/html/conf.py +++ b/docs/configs/html/conf.py @@ -36,7 +36,6 @@ extensions = [ 'sphinx.ext.extlinks', 'sphinx_copybutton', - 'self_service_error_codes_extension', ] # Add any paths that contain templates here, relative to this directory. diff --git a/docs/scripts/live-preview.sh b/docs/scripts/live-preview.sh index 98e23f92841e..8cd099dfad9b 100755 --- a/docs/scripts/live-preview.sh +++ b/docs/scripts/live-preview.sh @@ -52,9 +52,6 @@ TEMPLATES_DIR=$BUILD_DIR/source/_templates mkdir -p $TEMPLATES_DIR tar -zxf $BAZEL_BIN/templates/templates-tarball.tar.gz -C $TEMPLATES_DIR --strip-components=1 -# Error codes: create JSON file with error codes information -bazel build //docs:generate-error-codes-json - for arg in "$@" do if [ "$arg" = "--pdf" ]; then diff --git a/docs/sphinx_ext/self_service_error_codes_extension.py b/docs/sphinx_ext/self_service_error_codes_extension.py deleted file mode 100644 index 259fc2f95768..000000000000 --- a/docs/sphinx_ext/self_service_error_codes_extension.py +++ /dev/null @@ -1,216 +0,0 @@ -# Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -from collections import defaultdict -from docutils import nodes -from docutils.parsers.rst import Directive -from sphinx.writers.html import HTMLTranslator -from typing import Dict, Any - -import json - -error_codes_data = {} -group_data = {} - -CONFIG_OPT = 'error_codes_json_export' - -def load_data(app, config): - global error_codes_data - global group_data - - if CONFIG_OPT in config: - file_name = config[CONFIG_OPT] - try: - with open(file_name) as f: - tmp = json.load(f) - error_codes_data = {error["code"]: error for error in tmp["errorCodes"]} - group_data = {group["className"]: group for group in tmp["groups"]} - except EnvironmentError: - print(f"Failed to open file: '{file_name}'") - raise - - -def setup(app): - app.add_config_value(CONFIG_OPT, '', 'env') - app.connect('config-inited', load_data) - app.add_node(error_code_node) - app.add_directive('list-all-error-codes', ListAllErrorCodesDirective) - # Callback functions for populating error code section after the doctree is resolved - app.connect('doctree-resolved', process_error_code_nodes) - # Overwriting standard Sphinx translator to allow linking of return types - app.set_translator('html', PatchedHTMLTranslator) - - -class error_code_node(nodes.General, nodes.Element): - def __init__(self, codes, expl="", res=""): - nodes.Element.__init__(self) - print("found error node codes: %s" % codes) - self.codes = codes - self.expl = expl - self.res = res - - -class ListAllErrorCodesDirective(Directive): - has_contents = True - required_arguments = 0 - final_argument_whitespace = True - def run(self): - return [error_code_node([], None, None)] - - -def text_node(n, txt): - # Doubling the parameter, as TextElements want the raw text and the text - return n(txt, txt) - - -def process_error_code_nodes(app, doctree, fromDocName): - def build_indented_bold_and_non_bold_node(bold_text: str, non_bold_text: str): - bold = text_node(n=nodes.strong, txt=bold_text) - non_bold = text_node(n=nodes.inline, txt=non_bold_text) - both = nodes.definition('', bold) - both += non_bold - return both - - def item_to_node(item: Dict[str, Any]) -> nodes.definition_list_item: - node = nodes.definition_list_item() - term_node = text_node(nodes.term, "%s" % (item["code"])) - definition_node = nodes.definition('', text_node(nodes.paragraph, '')) - if item["deprecation"]: - definition_node += build_indented_bold_and_non_bold_node( - bold_text="Deprecated: ", - non_bold_text=item['deprecation']) - if item["explanation"]: - definition_node += build_indented_bold_and_non_bold_node( - bold_text="Explanation: ", - non_bold_text=item['explanation']) - definition_node += build_indented_bold_and_non_bold_node( - bold_text="Category: ", - non_bold_text=item['category']) - if item["conveyance"]: - definition_node += build_indented_bold_and_non_bold_node( - bold_text="Conveyance: ", - non_bold_text=item['conveyance']) - if item["resolution"]: - definition_node += build_indented_bold_and_non_bold_node( - bold_text="Resolution: ", - non_bold_text=item['resolution']) - permalink_node = build_permalink( - app=app, - fromDocName=fromDocName, - term=item["code"], - # NOTE: This is the path to the docs file in Sphinx's source dir - docname='error-codes/self-service/index', - node_to_permalink_to=term_node) - node += [permalink_node, definition_node] - - return node - - def group_explanation_to_node(text: str) -> nodes.definition_list_item: - return text_node(nodes.paragraph, text) - - # A node of this tree is a dict that can contain - # 1. further nodes and/or - # 2. 'leaves' in the form of a list of error (code) data - # Thus, the resulting tree is very similar to a trie - def build_hierarchical_tree_of_error_data(data) -> defaultdict: - create_node = lambda: defaultdict(create_node) - root = defaultdict(create_node) - for error_data in data: - current = root - for grouping in error_data['hierarchicalGrouping']: - current = current[grouping['docName']] - current['explanation'] = group_data[grouping['className']]['explanation'] - if 'error-codes' in current: - current['error-codes'].append(error_data) - else: - current['error-codes'] = [error_data] - return root - - # DFS to traverse the error code data tree from `build_hierarchical_tree_of_error_data` - # While traversing the tree, the presentation of the error codes on the documentation is built - def dfs(tree, node, numeric_prefix: str, topic_prefix: str) -> None: - if 'explanation' in tree and tree['explanation']: - node += group_explanation_to_node(tree['explanation']) - if 'error-codes' in tree: - dlist = nodes.definition_list() - for code in tree['error-codes']: - dlist += item_to_node(item=code) - node += dlist - i = 1 - for subtopic, subtree in tree.items(): - if subtopic in ['error-codes', 'explanation']: - continue - subtree_node_numeric_prefix = f"{numeric_prefix}{i}." - i += 1 - topic = subtopic - if topic_prefix != "": - topic = topic_prefix + " / " + subtopic - subtree_node_header = subtree_node_numeric_prefix + " " + topic - subtree_node = text_node(n=nodes.rubric, txt = subtree_node_header) - dfs(tree=subtree, node=subtree_node, numeric_prefix=subtree_node_numeric_prefix, topic_prefix=topic) - node += subtree_node - - for node in doctree.traverse(error_code_node): - # Valid error codes given to the .. error-codes:: directive as argument - # given_error_codes = [error_codes_data[code] for code in node.codes if code in error_codes_data] - # Code for manually overwriting the explanation or resolution of an error code - - section = nodes.section() - root = nodes.rubric(rawsource = "", text = "") - section += root - tree = build_hierarchical_tree_of_error_data(data=error_codes_data.values()) - dfs(tree=tree, node=root, numeric_prefix="", topic_prefix="") - node.replace_self(new=[section]) - - -# Build a permalink/anchor to a specific command/metric -def build_permalink(app, fromDocName, term, docname, node_to_permalink_to): - reference_node = nodes.reference('', '') - reference_node['refuri'] = app.builder.get_relative_uri(fromDocName, docname) + '#' + term - - reference_node += node_to_permalink_to - - target_node = nodes.target('', '', ids=[term]) - node_to_permalink_to += target_node - return reference_node - - -class PatchedHTMLTranslator(HTMLTranslator): - # We overwrite this method as otherwise an assertion fails whenever we create a reference whose parent is - # not a TextElement. Concretely, this enables using method `build_return_type_node` for creating links from - # return types to the appropriate scaladocs - # Similar to solution from https://stackoverflow.com/a/61669375 - - def visit_reference(self, node): - # type: (nodes.Node) -> None - atts = {'class': 'reference'} - if node.get('internal') or 'refuri' not in node: - atts['class'] += ' internal' - else: - atts['class'] += ' external' - if 'refuri' in node: - atts['href'] = node['refuri'] or '#' - if self.settings.cloak_email_addresses and \ - atts['href'].startswith('mailto:'): - atts['href'] = self.cloak_mailto(atts['href']) - self.in_mailto = 1 - else: - assert 'refid' in node, \ - 'References must have "refuri" or "refid" attribute.' - atts['href'] = '#' + node['refid'] - if not isinstance(node.parent, nodes.TextElement): - # --------------------- - # Commenting out this assertion is the only change compared to Sphinx version 3.4.3 - # assert len(node) == 1 and isinstance(node[0], nodes.image) - # --------------------- - atts['class'] += ' image-reference' - if 'reftitle' in node: - atts['title'] = node['reftitle'] - if 'target' in node: - atts['target'] = node['target'] - self.body.append(self.starttag(node, 'a', '', **atts)) - - if node.get('secnumber'): - self.body.append(('%s' + self.secnumber_suffix) % - '.'.join(map(str, node['secnumber']))) - diff --git a/ledger/daml-on-sql/BUILD.bazel b/ledger/daml-on-sql/BUILD.bazel index 45e3abe59635..72a4362f4aa8 100644 --- a/ledger/daml-on-sql/BUILD.bazel +++ b/ledger/daml-on-sql/BUILD.bazel @@ -126,14 +126,11 @@ genrule( srcs = [ "README.rst", "//docs:theme", - "//docs:sphinx_ext/self_service_error_codes_extension.py", "//docs:configs/html/conf.py", "//docs:configs/static/pygments_daml_lexer.py", "//docs:configs/static/typescript.py", "//docs:scripts/check-closing-quotes.sh", "//docs:scripts/check-closing-quotes.sh.allow", - "//docs:generate-error-codes-json", - "//docs:error_codes_export.json", ], outs = ["html.tar.gz"], cmd = """ @@ -142,8 +139,6 @@ genrule( mkdir -p build/docs/configs/html cp $(location //docs:configs/html/conf.py) build/docs/configs/html/conf.py - mkdir -p build/docs/sphinx_ext - cp $(location //docs:sphinx_ext/self_service_error_codes_extension.py) build/docs/sphinx_ext/self_service_error_codes_extension.py mkdir -p build/docs/configs/static cp $(location //docs:configs/static/pygments_daml_lexer.py) build/docs/configs/static/pygments_daml_lexer.py cp $(location //docs:configs/static/typescript.py) build/docs/configs/static/typescript.py @@ -175,7 +170,7 @@ genrule( # the PDF documentation due to issues with the FreeSerif font in the # fontspec package. So, for now we ignore `FutureWarning`. SPHINX_BUILD_EXIT_CODE=0 - SPHINX_BUILD_OUTPUT=$$(../$(location @sphinx_nix//:bin/sphinx-build) -D error_codes_json_export=../$(location //docs:error_codes_export.json) -c docs/configs/html docs/source html 2>&1) || SPHINX_BUILD_EXIT_CODE=$$? + SPHINX_BUILD_OUTPUT=$$(../$(location @sphinx_nix//:bin/sphinx-build) -c docs/configs/html docs/source html 2>&1) || SPHINX_BUILD_EXIT_CODE=$$? if [ "$$SPHINX_BUILD_EXIT_CODE" -ne 0 ]; then >&2 echo "## SPHINX-BUILD OUTPUT:" >&2 echo "$$SPHINX_BUILD_OUTPUT" From 9452002f65ba5ad8a8022ad6debfbbe249afa2f4 Mon Sep 17 00:00:00 2001 From: Pawel Batko Date: Mon, 22 Nov 2021 17:10:58 +0100 Subject: [PATCH 3/7] Revert some renames --- ledger/error/generator/BUILD.bazel | 2 +- ...ala => ErrorCodeInventoryDocsGenApp.scala} | 22 +++++++++---------- .../com/daml/error/generator/app/Main.scala | 10 ++++----- .../ErrorCodeDocumentationGenerator.scala | 4 ++-- .../daml/error/generator/ErrorDocItem.scala | 12 +++++----- .../daml/error/generator/GroupDocItem.scala | 4 ++-- .../ErrorCodeDocumentationGeneratorSpec.scala | 2 +- ...{ErrorGroupPath.scala => ErrorClass.scala} | 14 ++++++------ .../main/scala/com/daml/error/ErrorCode.scala | 2 +- .../scala/com/daml/error/ErrorGroup.scala | 8 +++---- .../daml/error/definitions/ErrorGroups.scala | 4 ++-- .../scala/com/daml/error/ErrorGroupSpec.scala | 16 +++++++------- .../utils/testpackage/DeprecatedError.scala | 4 ++-- .../utils/testpackage/SeriousError.scala | 4 ++-- .../testpackage/subpackage/MildErrors.scala | 3 +-- 15 files changed, 55 insertions(+), 56 deletions(-) rename ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/{ErrorCodeInventoryDocsGen_App.scala => ErrorCodeInventoryDocsGenApp.scala} (90%) rename ledger/error/src/main/scala/com/daml/error/{ErrorGroupPath.scala => ErrorClass.scala} (68%) diff --git a/ledger/error/generator/BUILD.bazel b/ledger/error/generator/BUILD.bazel index 2bd1e715de19..98d76481f71f 100644 --- a/ledger/error/generator/BUILD.bazel +++ b/ledger/error/generator/BUILD.bazel @@ -32,7 +32,7 @@ da_scala_binary( da_scala_binary( name = "generate-docs-error-code-inventory-app", srcs = glob(["app/src/main/scala/**/*.scala"]), - main_class = "com.daml.error.generator.app.ErrorCodeInventoryDocsGen_App", + main_class = "com.daml.error.generator.app.ErrorCodeInventoryDocsGenApp", resources = glob(["src/main/resources/**/*"]), scala_deps = [ "@maven//:io_circe_circe_core", diff --git a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGen_App.scala b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala similarity index 90% rename from ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGen_App.scala rename to ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala index 6620c68ca906..12b98c575e1c 100644 --- a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGen_App.scala +++ b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala @@ -5,7 +5,7 @@ package com.daml.error.generator.app import java.nio.file.{Files, Paths, StandardOpenOption} -import com.daml.error.{ErrorGroupPath, ErrorGroupSegment} +import com.daml.error.{ErrorClass, Grouping} import com.daml.error.generator.{ErrorCodeDocumentationGenerator, ErrorDocItem, GroupDocItem} import scala.collection.mutable @@ -13,14 +13,14 @@ import scala.collection.mutable.ArrayBuffer /** Generates error codes inventory as a reStructuredText */ -object ErrorCodeInventoryDocsGen_App { +object ErrorCodeInventoryDocsGenApp { def main(args: Array[String]): Unit = { val text = { val (errorDocItems, groupDocItems): (Seq[ErrorDocItem], Seq[GroupDocItem]) = new ErrorCodeDocumentationGenerator().getDocItems - val groupSegmentsToExplanationMap: Map[List[ErrorGroupSegment], Option[String]] = + val groupSegmentsToExplanationMap: Map[List[Grouping], Option[String]] = groupDocItems.map { groupDocItem: GroupDocItem => groupDocItem.errorGroupPath.segments -> groupDocItem.explanation.map(_.explanation) }.toMap @@ -28,7 +28,7 @@ object ErrorCodeInventoryDocsGen_App { val errorCodes: Seq[ErrorCodeValue] = errorDocItems.map { (errorDocItem: ErrorDocItem) => ErrorCodeValue( category = errorDocItem.category, - errorGroupPath = errorDocItem.errorGroupPath, + errorGroupPath = errorDocItem.hierarchicalGrouping, conveyance = errorDocItem.conveyance.getOrElse("").replace('\n', ' '), code = errorDocItem.code, deprecationO = errorDocItem.deprecation.map(_.deprecation.replace('\n', ' ')), @@ -62,7 +62,7 @@ object ErrorCodeInventoryDocsGen_App { case class ErrorCodeValue( code: String, - errorGroupPath: ErrorGroupPath, + errorGroupPath: ErrorClass, category: String, explanation: String, resolution: String, @@ -73,8 +73,8 @@ case class ErrorCodeValue( class ErrorGroupTree( val name: String, val explanation: Option[String] = None, - children: mutable.Map[ErrorGroupSegment, ErrorGroupTree] = - new mutable.HashMap[ErrorGroupSegment, ErrorGroupTree](), + children: mutable.Map[Grouping, ErrorGroupTree] = + new mutable.HashMap[Grouping, ErrorGroupTree](), errorCodes: mutable.Map[String, ErrorCodeValue] = new mutable.HashMap[String, ErrorCodeValue](), ) { @@ -88,7 +88,7 @@ class ErrorGroupTree( def insertErrorCode( errorCode: ErrorCodeValue, - getExplanation: (List[ErrorGroupSegment]) => Option[String], + getExplanation: (List[Grouping]) => Option[String], ): Unit = { insert( remaining = errorCode.errorGroupPath.segments, @@ -99,10 +99,10 @@ class ErrorGroupTree( } private def insert( - remaining: List[ErrorGroupSegment], + remaining: List[Grouping], errorCode: ErrorCodeValue, - path: List[ErrorGroupSegment], - getExplanation: (List[ErrorGroupSegment]) => Option[String], + path: List[Grouping], + getExplanation: (List[Grouping]) => Option[String], ): Unit = { remaining match { diff --git a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala index 7891b0b62ca8..2e3ca0aa99cb 100644 --- a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala +++ b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala @@ -3,7 +3,7 @@ package com.daml.error.generator.app -import com.daml.error.ErrorGroupSegment +import com.daml.error.Grouping import com.daml.error.generator.{ErrorCodeDocumentationGenerator, ErrorDocItem, GroupDocItem} import io.circe.Encoder import io.circe.syntax._ @@ -16,11 +16,11 @@ object Main { case class Output(errorCodes: Seq[ErrorDocItem], groups: Seq[GroupDocItem]) - implicit val groupingEncode: Encoder[ErrorGroupSegment] = + implicit val groupingEncode: Encoder[Grouping] = Encoder.forProduct2( "docName", "className", - )((grouping: ErrorGroupSegment) => + )((grouping: Grouping) => ( grouping.docName, grouping.fullClassName, @@ -39,9 +39,9 @@ object Main { "resolution", )(i => ( - i.fullClassName, + i.className, i.category, - i.errorGroupPath.segments, + i.hierarchicalGrouping.segments, i.conveyance, i.code, i.deprecation.fold("")(_.deprecation), diff --git a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala index 30c06ad7fc41..1d5ab4cc04b6 100644 --- a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala +++ b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala @@ -63,9 +63,9 @@ class ErrorCodeDocumentationGenerator(prefixes: Array[String] = Array("com.daml" getErrorDocumentationAnnotations(error) ErrorDocItem( - fullClassName = error.getClass.getName, + className = error.getClass.getName, category = simpleClassName(error.category), - errorGroupPath = error.errorGroupPath, + hierarchicalGrouping = error.errorGroupPath, conveyance = error.errorConveyanceDocString, code = error.id, deprecation = deprecation, diff --git a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorDocItem.scala b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorDocItem.scala index 9d5f66913146..a977d591db14 100644 --- a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorDocItem.scala +++ b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorDocItem.scala @@ -3,23 +3,23 @@ package com.daml.error.generator -import com.daml.error.{Deprecation, ErrorGroupPath, Explanation, Resolution} +import com.daml.error.{Deprecation, ErrorClass, Explanation, Resolution} /** Contains error presentation data to be used for documentation rendering on the website. * - * @param fullClassName The error class name (see [[com.daml.error.ErrorCode]]). + * @param className The error class name (see [[com.daml.error.ErrorCode]]). * @param category The error code category (see [[com.daml.error.ErrorCategory]]). - * @param errorGroupPath The hierarchical code grouping - * (see [[com.daml.error.ErrorGroupPath]] and [[com.daml.error.ErrorGroup]]). + * @param hierarchicalGrouping The hierarchical code grouping + * (see [[com.daml.error.ErrorClass]] and [[com.daml.error.ErrorGroup]]). * @param conveyance Provides a statement about the form this error will be returned to the user. * @param code The error identifier. * @param explanation The detailed error explanation. * @param resolution The suggested error resolution. */ case class ErrorDocItem( - fullClassName: String, // TODO error codes: Rename to `errorCodeName` or `errorCodeClassName` to prevent confusion + className: String, // TODO error codes: Rename to `errorCodeName` or `errorCodeClassName` to prevent confusion category: String, - errorGroupPath: ErrorGroupPath, + hierarchicalGrouping: ErrorClass, conveyance: Option[String], code: String, deprecation: Option[Deprecation], diff --git a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala index 78343ca1a1a8..1501e717ab0e 100644 --- a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala +++ b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala @@ -3,7 +3,7 @@ package com.daml.error.generator -import com.daml.error.{ErrorGroupPath, Explanation} +import com.daml.error.{ErrorClass, Explanation} /** Contains error presentation data to be used for documentation rendering on the website. * @@ -14,5 +14,5 @@ import com.daml.error.{ErrorGroupPath, Explanation} case class GroupDocItem( fullClassName: String, explanation: Option[Explanation], - errorGroupPath: ErrorGroupPath, + errorGroupPath: ErrorClass, ) diff --git a/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala b/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala index 939d064de3ae..1d05ea6dac6f 100644 --- a/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala +++ b/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala @@ -6,7 +6,7 @@ package com.daml.error.generator import com.daml.error.utils.testpackage.subpackage.MildErrors import com.daml.error.utils.testpackage.subpackage.MildErrors.NotSoSeriousError import com.daml.error.utils.testpackage.{DeprecatedError, SeriousError} -import com.daml.error.{Deprecation, Explanation, ErrorGroupSegment, Resolution} +import com.daml.error.{Deprecation, Explanation, Grouping, Resolution} import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorGroupPath.scala b/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala similarity index 68% rename from ledger/error/src/main/scala/com/daml/error/ErrorGroupPath.scala rename to ledger/error/src/main/scala/com/daml/error/ErrorClass.scala index 5a48263238e2..45ef645ce911 100644 --- a/ledger/error/src/main/scala/com/daml/error/ErrorGroupPath.scala +++ b/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala @@ -3,12 +3,12 @@ package com.daml.error -/** A component of [[ErrorGroupPath]] +/** A component of [[ErrorClass]] * * @param docName The name that will appear in the generated documentation for the grouping. * @param fullClassName Full class name of the corresponding [[ErrorGroup]]. */ -case class ErrorGroupSegment( +case class Grouping( docName: String, fullClassName: String, ) { @@ -20,11 +20,11 @@ case class ErrorGroupSegment( /** Used to hierarchically structure error codes in the official documentation. */ -case class ErrorGroupPath(segments: List[ErrorGroupSegment]) { - def extend(last: ErrorGroupSegment): ErrorGroupPath = - ErrorGroupPath(segments :+ last) +case class ErrorClass(segments: List[Grouping]) { + def extend(last: Grouping): ErrorClass = + ErrorClass(segments :+ last) } -object ErrorGroupPath { - def root(): ErrorGroupPath = ErrorGroupPath(Nil) +object ErrorClass { + def root(): ErrorClass = ErrorClass(Nil) } diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala b/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala index a3bcc3532194..777be111f0b9 100644 --- a/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala +++ b/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala @@ -41,7 +41,7 @@ import scala.util.matching.Regex * } */ abstract class ErrorCode(val id: String, val category: ErrorCategory)(implicit - val errorGroupPath: ErrorGroupPath + val errorGroupPath: ErrorClass ) { require(id.nonEmpty, "error-id must be non empty") diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala b/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala index 059a2d2768a4..d8ccad68ff6d 100644 --- a/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala +++ b/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala @@ -3,13 +3,13 @@ package com.daml.error -abstract class ErrorGroup()(implicit parent: ErrorGroupPath) { +abstract class ErrorGroup()(implicit parent: ErrorClass) { val fullClassName: String = getClass.getName // Hit https://github.com/scala/bug/issues/5425?orig=1 here: we cannot use .getSimpleName in deeply nested objects // TODO error codes: Switch to using .getSimpleName when switching to JDK 9+ - implicit val errorGroupPath: ErrorGroupPath = resolveErrorClass() + implicit val errorGroupPath: ErrorClass = resolveErrorClass() - private def resolveErrorClass(): ErrorGroupPath = { + private def resolveErrorClass(): ErrorClass = { val name = fullClassName .replace("$", ".") .split("\\.") @@ -21,6 +21,6 @@ abstract class ErrorGroup()(implicit parent: ErrorGroupPath) { s"Could not parse full class name: '${fullClassName}' for the error class name" ) ) - parent.extend(ErrorGroupSegment(docName = name, fullClassName = fullClassName)) + parent.extend(Grouping(docName = name, fullClassName = fullClassName)) } } diff --git a/ledger/error/src/main/scala/com/daml/error/definitions/ErrorGroups.scala b/ledger/error/src/main/scala/com/daml/error/definitions/ErrorGroups.scala index f607f2a4fe89..c2fea7edc60f 100644 --- a/ledger/error/src/main/scala/com/daml/error/definitions/ErrorGroups.scala +++ b/ledger/error/src/main/scala/com/daml/error/definitions/ErrorGroups.scala @@ -3,10 +3,10 @@ package com.daml.error.definitions -import com.daml.error.{ErrorGroupPath, ErrorGroup} +import com.daml.error.{ErrorClass, ErrorGroup} object ErrorGroups { - val rootErrorClass: ErrorGroupPath = ErrorGroupPath.root() + val rootErrorClass: ErrorClass = ErrorClass.root() object ParticipantErrorGroup extends ErrorGroup()(rootErrorClass) { abstract class IndexErrorGroup extends ErrorGroup() { diff --git a/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala b/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala index 5596d01ba628..0c22c6db6198 100644 --- a/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala +++ b/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala @@ -9,27 +9,27 @@ import org.scalatest.matchers.should.Matchers class ErrorGroupSpec extends AnyFlatSpec with Matchers with BeforeAndAfter { - object ErrorGroupBar extends ErrorGroup()(ErrorGroupPath.root()) + object ErrorGroupBar extends ErrorGroup()(ErrorClass.root()) - object ErrorGroupFoo1 extends ErrorGroup()(ErrorGroupPath.root()) { + object ErrorGroupFoo1 extends ErrorGroup()(ErrorClass.root()) { object ErrorGroupFoo2 extends ErrorGroup() { object ErrorGroupFoo3 extends ErrorGroup() } } it should "resolve correct error group names" in { - ErrorGroupFoo1.ErrorGroupFoo2.ErrorGroupFoo3.errorGroupPath shouldBe ErrorGroupPath( + ErrorGroupFoo1.ErrorGroupFoo2.ErrorGroupFoo3.errorGroupPath shouldBe ErrorClass( List( - ErrorGroupSegment("ErrorGroupFoo1", ErrorGroupFoo1.fullClassName), - ErrorGroupSegment("ErrorGroupFoo2", ErrorGroupFoo1.ErrorGroupFoo2.fullClassName), - ErrorGroupSegment( + Grouping("ErrorGroupFoo1", ErrorGroupFoo1.fullClassName), + Grouping("ErrorGroupFoo2", ErrorGroupFoo1.ErrorGroupFoo2.fullClassName), + Grouping( "ErrorGroupFoo3", ErrorGroupFoo1.ErrorGroupFoo2.ErrorGroupFoo3.fullClassName, ), ) ) - ErrorGroupBar.errorGroupPath shouldBe ErrorGroupPath( - List(ErrorGroupSegment("ErrorGroupBar", ErrorGroupBar.fullClassName)) + ErrorGroupBar.errorGroupPath shouldBe ErrorClass( + List(Grouping("ErrorGroupBar", ErrorGroupBar.fullClassName)) ) } diff --git a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/DeprecatedError.scala b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/DeprecatedError.scala index 984b70bcc0d4..1a90c49ed3fe 100644 --- a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/DeprecatedError.scala +++ b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/DeprecatedError.scala @@ -4,7 +4,7 @@ package com.daml.error.utils.testpackage import com.daml.error.{Explanation, Resolution} -import com.daml.error.{BaseError, ErrorCategory, ErrorGroupPath, ErrorCode} +import com.daml.error.{BaseError, ErrorCategory, ErrorClass, ErrorCode} import com.daml.logging.LoggingContext @deprecated("deprecated.") @@ -12,7 +12,7 @@ import com.daml.logging.LoggingContext @Explanation("Things happen.") case object DeprecatedError extends ErrorCode("DEPRECATED_ERROR", ErrorCategory.SystemInternalAssumptionViolated)( - ErrorGroupPath.root() + ErrorClass.root() ) { case class Error(cause: String)(implicit val loggingContext: LoggingContext) extends BaseError { diff --git a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/SeriousError.scala b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/SeriousError.scala index c1e2dedc06b8..36932f8bac30 100644 --- a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/SeriousError.scala +++ b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/SeriousError.scala @@ -4,14 +4,14 @@ package com.daml.error.utils.testpackage import com.daml.error.{Explanation, Resolution} -import com.daml.error.{BaseError, ErrorCategory, ErrorGroupPath, ErrorCode} +import com.daml.error.{BaseError, ErrorCategory, ErrorClass, ErrorCode} import com.daml.logging.LoggingContext @Explanation("Things happen.") @Resolution("Turn it off and on again.") case object SeriousError extends ErrorCode("BLUE_SCREEN", ErrorCategory.SystemInternalAssumptionViolated)( - ErrorGroupPath.root() + ErrorClass.root() ) { case class Error(cause: String)(implicit val loggingContext: LoggingContext) extends BaseError { diff --git a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/subpackage/MildErrors.scala b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/subpackage/MildErrors.scala index f57cc9f2c1c4..b405bcec6349 100644 --- a/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/subpackage/MildErrors.scala +++ b/ledger/error/src/test/utils/scala/com/daml/error/utils/testpackage/subpackage/MildErrors.scala @@ -9,8 +9,7 @@ import com.daml.logging.LoggingContext @Explanation("Groups mild errors together") object MildErrors extends ErrorGroup()( - parent = - ErrorGroupPath.root().extend(ErrorGroupSegment("Some grouping", "full.class.Name123")) + parent = ErrorClass.root().extend(Grouping("Some grouping", "full.class.Name123")) ) { @Explanation("Test: Things like this always happen.") From 39cd20c8e01b07c486619d7854a855acd1345ed5 Mon Sep 17 00:00:00 2001 From: Pawel Batko Date: Mon, 22 Nov 2021 18:05:46 +0100 Subject: [PATCH 4/7] cont --- .../error/generator/app/ErrorCodeInventoryDocsGenApp.scala | 4 ++-- .../src/main/scala/com/daml/error/generator/app/Main.scala | 4 ++-- .../error/generator/ErrorCodeDocumentationGenerator.scala | 6 +++--- .../main/scala/com/daml/error/generator/GroupDocItem.scala | 4 ++-- .../generator/ErrorCodeDocumentationGeneratorSpec.scala | 2 +- ledger/error/src/main/scala/com/daml/error/ErrorClass.scala | 6 +++--- ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala | 2 +- .../test/suite/scala/com/daml/error/ErrorGroupSpec.scala | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala index 12b98c575e1c..87cc9bfba6fc 100644 --- a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala +++ b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala @@ -22,7 +22,7 @@ object ErrorCodeInventoryDocsGenApp { val groupSegmentsToExplanationMap: Map[List[Grouping], Option[String]] = groupDocItems.map { groupDocItem: GroupDocItem => - groupDocItem.errorGroupPath.segments -> groupDocItem.explanation.map(_.explanation) + groupDocItem.errorGroupPath.groupings -> groupDocItem.explanation.map(_.explanation) }.toMap val errorCodes: Seq[ErrorCodeValue] = errorDocItems.map { (errorDocItem: ErrorDocItem) => @@ -91,7 +91,7 @@ class ErrorGroupTree( getExplanation: (List[Grouping]) => Option[String], ): Unit = { insert( - remaining = errorCode.errorGroupPath.segments, + remaining = errorCode.errorGroupPath.groupings, path = Nil, errorCode = errorCode, getExplanation = getExplanation, diff --git a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala index 2e3ca0aa99cb..0d2404e2d579 100644 --- a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala +++ b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala @@ -41,7 +41,7 @@ object Main { ( i.className, i.category, - i.hierarchicalGrouping.segments, + i.hierarchicalGrouping.groupings, i.conveyance, i.code, i.deprecation.fold("")(_.deprecation), @@ -56,7 +56,7 @@ object Main { "explanation", )(i => ( - i.fullClassName, + i.className, i.explanation.fold("")(_.explanation), ) ) diff --git a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala index 1d5ab4cc04b6..ed19acf0b62a 100644 --- a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala +++ b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala @@ -36,7 +36,7 @@ class ErrorCodeDocumentationGenerator(prefixes: Array[String] = Array("com.daml" } val groups = getInstances[ErrorGroup] - groups.view.map(_.errorGroupPath).groupBy(identity).collect { + groups.view.map(_.errorClass).groupBy(identity).collect { case (group, occurrences) if occurrences.size > 1 => sys.error( s"There are ${occurrences.size} groups named $group but we require each group class name to be unique! " + @@ -79,8 +79,8 @@ class ErrorCodeDocumentationGenerator(prefixes: Array[String] = Array("com.daml" getGroupDocumentationAnnotations(group) GroupDocItem( - errorGroupPath = group.errorGroupPath, - fullClassName = group.fullClassName, + errorGroupPath = group.errorClass, + className = group.fullClassName, explanation = explanation, ) } diff --git a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala index 1501e717ab0e..18a6b9d623be 100644 --- a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala +++ b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala @@ -7,12 +7,12 @@ import com.daml.error.{ErrorClass, Explanation} /** Contains error presentation data to be used for documentation rendering on the website. * - * @param fullClassName The group class name (see [[com.daml.error.ErrorGroup]]). + * @param className The group class name (see [[com.daml.error.ErrorGroup]]). * @param explanation The detailed error explanation. * @param errorGroupPath Hierarchical grouping of this error group. */ case class GroupDocItem( - fullClassName: String, + className: String, explanation: Option[Explanation], errorGroupPath: ErrorClass, ) diff --git a/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala b/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala index 1d05ea6dac6f..f074e4eede53 100644 --- a/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala +++ b/ledger/error/generator/lib/src/test/scala/com/daml/error/generator/ErrorCodeDocumentationGeneratorSpec.scala @@ -51,7 +51,7 @@ class ErrorCodeDocumentationGeneratorSpec extends AnyFlatSpec with Matchers { className = NotSoSeriousError.getClass.getTypeName, category = "TransientServerFailure", hierarchicalGrouping = - List(ErrorGroupSegment("Some grouping", None), Grouping("MildErrors", Some(MildErrors))), + List(Grouping("Some grouping", None), Grouping("MildErrors", Some(MildErrors))), conveyance = "This error is logged with log-level INFO on the server side.\nThis error is exposed on the API with grpc-status UNAVAILABLE including a detailed error message", code = "TEST_ROUTINE_FAILURE_PLEASE_IGNORE", diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala b/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala index 45ef645ce911..2468e3237f00 100644 --- a/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala +++ b/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala @@ -14,15 +14,15 @@ case class Grouping( ) { require( docName.trim.nonEmpty, - s"ErrorGroupSegment.docName must be non mmpty and must contain not only whitespace characters, but was: |${docName}|!", + s"Grouping.docName must be non empty and must contain not only whitespace characters, but was: |${docName}|!", ) } /** Used to hierarchically structure error codes in the official documentation. */ -case class ErrorClass(segments: List[Grouping]) { +case class ErrorClass(groupings: List[Grouping]) { def extend(last: Grouping): ErrorClass = - ErrorClass(segments :+ last) + ErrorClass(groupings :+ last) } object ErrorClass { diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala b/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala index d8ccad68ff6d..9b6daafae778 100644 --- a/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala +++ b/ledger/error/src/main/scala/com/daml/error/ErrorGroup.scala @@ -7,7 +7,7 @@ abstract class ErrorGroup()(implicit parent: ErrorClass) { val fullClassName: String = getClass.getName // Hit https://github.com/scala/bug/issues/5425?orig=1 here: we cannot use .getSimpleName in deeply nested objects // TODO error codes: Switch to using .getSimpleName when switching to JDK 9+ - implicit val errorGroupPath: ErrorClass = resolveErrorClass() + implicit val errorClass: ErrorClass = resolveErrorClass() private def resolveErrorClass(): ErrorClass = { val name = fullClassName diff --git a/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala b/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala index 0c22c6db6198..b33cc70639e0 100644 --- a/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala +++ b/ledger/error/src/test/suite/scala/com/daml/error/ErrorGroupSpec.scala @@ -18,7 +18,7 @@ class ErrorGroupSpec extends AnyFlatSpec with Matchers with BeforeAndAfter { } it should "resolve correct error group names" in { - ErrorGroupFoo1.ErrorGroupFoo2.ErrorGroupFoo3.errorGroupPath shouldBe ErrorClass( + ErrorGroupFoo1.ErrorGroupFoo2.ErrorGroupFoo3.errorClass shouldBe ErrorClass( List( Grouping("ErrorGroupFoo1", ErrorGroupFoo1.fullClassName), Grouping("ErrorGroupFoo2", ErrorGroupFoo1.ErrorGroupFoo2.fullClassName), @@ -28,7 +28,7 @@ class ErrorGroupSpec extends AnyFlatSpec with Matchers with BeforeAndAfter { ), ) ) - ErrorGroupBar.errorGroupPath shouldBe ErrorClass( + ErrorGroupBar.errorClass shouldBe ErrorClass( List(Grouping("ErrorGroupBar", ErrorGroupBar.fullClassName)) ) } From 6676d552b885dbc9eda02e4ee96a60ce22577e0e Mon Sep 17 00:00:00 2001 From: Pawel Batko Date: Mon, 22 Nov 2021 18:09:36 +0100 Subject: [PATCH 5/7] cont --- .../error/generator/app/ErrorCodeInventoryDocsGenApp.scala | 2 +- .../src/main/scala/com/daml/error/generator/app/Main.scala | 6 +++--- .../error/generator/ErrorCodeDocumentationGenerator.scala | 4 ++-- .../main/scala/com/daml/error/generator/GroupDocItem.scala | 4 ++-- ledger/error/src/main/scala/com/daml/error/ErrorClass.scala | 4 ++-- ledger/error/src/main/scala/com/daml/error/ErrorCode.scala | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala index 87cc9bfba6fc..ed76dc660e7f 100644 --- a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala +++ b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala @@ -22,7 +22,7 @@ object ErrorCodeInventoryDocsGenApp { val groupSegmentsToExplanationMap: Map[List[Grouping], Option[String]] = groupDocItems.map { groupDocItem: GroupDocItem => - groupDocItem.errorGroupPath.groupings -> groupDocItem.explanation.map(_.explanation) + groupDocItem.errorClass.groupings -> groupDocItem.explanation.map(_.explanation) }.toMap val errorCodes: Seq[ErrorCodeValue] = errorDocItems.map { (errorDocItem: ErrorDocItem) => diff --git a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala index 0d2404e2d579..a0e7ff42f013 100644 --- a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala +++ b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/Main.scala @@ -20,10 +20,10 @@ object Main { Encoder.forProduct2( "docName", "className", - )((grouping: Grouping) => + )(i => ( - grouping.docName, - grouping.fullClassName, + i.docName, + i.fullClassName, ) ) diff --git a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala index ed19acf0b62a..28cddbec77b9 100644 --- a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala +++ b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/ErrorCodeDocumentationGenerator.scala @@ -65,7 +65,7 @@ class ErrorCodeDocumentationGenerator(prefixes: Array[String] = Array("com.daml" ErrorDocItem( className = error.getClass.getName, category = simpleClassName(error.category), - hierarchicalGrouping = error.errorGroupPath, + hierarchicalGrouping = error.parent, conveyance = error.errorConveyanceDocString, code = error.id, deprecation = deprecation, @@ -79,7 +79,7 @@ class ErrorCodeDocumentationGenerator(prefixes: Array[String] = Array("com.daml" getGroupDocumentationAnnotations(group) GroupDocItem( - errorGroupPath = group.errorClass, + errorClass = group.errorClass, className = group.fullClassName, explanation = explanation, ) diff --git a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala index 18a6b9d623be..50cc27bbfcb4 100644 --- a/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala +++ b/ledger/error/generator/lib/src/main/scala/com/daml/error/generator/GroupDocItem.scala @@ -9,10 +9,10 @@ import com.daml.error.{ErrorClass, Explanation} * * @param className The group class name (see [[com.daml.error.ErrorGroup]]). * @param explanation The detailed error explanation. - * @param errorGroupPath Hierarchical grouping of this error group. + * @param errorClass Hierarchical grouping of this error group. */ case class GroupDocItem( className: String, explanation: Option[Explanation], - errorGroupPath: ErrorClass, + errorClass: ErrorClass, ) diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala b/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala index 2468e3237f00..51b5f87ce5b6 100644 --- a/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala +++ b/ledger/error/src/main/scala/com/daml/error/ErrorClass.scala @@ -21,8 +21,8 @@ case class Grouping( /** Used to hierarchically structure error codes in the official documentation. */ case class ErrorClass(groupings: List[Grouping]) { - def extend(last: Grouping): ErrorClass = - ErrorClass(groupings :+ last) + def extend(grouping: Grouping): ErrorClass = + ErrorClass(groupings :+ grouping) } object ErrorClass { diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala b/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala index 777be111f0b9..46cb4d7a7f93 100644 --- a/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala +++ b/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala @@ -41,7 +41,7 @@ import scala.util.matching.Regex * } */ abstract class ErrorCode(val id: String, val category: ErrorCategory)(implicit - val errorGroupPath: ErrorClass + val parent: ErrorClass ) { require(id.nonEmpty, "error-id must be non empty") From bf522f769b98c28298a49c8b967a799963df0bd5 Mon Sep 17 00:00:00 2001 From: Pawel Batko Date: Tue, 23 Nov 2021 12:48:54 +0100 Subject: [PATCH 6/7] TV review --- docs/BUILD.bazel | 2 +- docs/configs/pdf/index.rst | 1 - docs/scripts/live-preview.sh | 2 +- .../error/generator/app/ErrorCodeInventoryDocsGenApp.scala | 4 ++-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 626380aa6764..be3d1825a0ca 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -106,7 +106,7 @@ genrule( cp -rL docs/source source mkdir -p -- source/error-codes/self-service - cp -- $(location //docs:generate-docs-error-code-inventory-into-rst-file) source/error-codes/self-service/error_codes_inventory.rst + cp -- $(location //docs:generate-docs-error-code-inventory-into-rst-file) source/app-dev/grpc/error_codes_inventory.rst # Copy in Stdlib mkdir -p source/daml/stdlib tar xf $(location //compiler/damlc:daml-base-rst.tar.gz) \\ diff --git a/docs/configs/pdf/index.rst b/docs/configs/pdf/index.rst index 0d4452af62ba..550ba3953a73 100644 --- a/docs/configs/pdf/index.rst +++ b/docs/configs/pdf/index.rst @@ -45,7 +45,6 @@ Building applications upgrade/index app-dev/authorization app-dev/ledger-api - error-codes/self-service/index Deploying to Daml ledgers ------------------------- diff --git a/docs/scripts/live-preview.sh b/docs/scripts/live-preview.sh index 8cd099dfad9b..d39d1686bd79 100755 --- a/docs/scripts/live-preview.sh +++ b/docs/scripts/live-preview.sh @@ -62,7 +62,7 @@ do if [ "$arg" = "--gen" ]; then bazel build //docs:generate-docs-error-code-inventory-into-rst-file - cp -L ../../bazel-bin/docs/error_codes_inventory.rst $BUILD_DIR/source/error-codes/self-service/error_codes_inventory.rst + cp -L ../../bazel-bin/docs/error_codes_inventory.rst $BUILD_DIR/source/app-dev/grpc/error_codes_inventory.rst # Hoogle bazel build //compiler/damlc:daml-base-hoogle.txt diff --git a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala index ed76dc660e7f..f307956f793d 100644 --- a/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala +++ b/ledger/error/generator/app/src/main/scala/com/daml/error/generator/app/ErrorCodeInventoryDocsGenApp.scala @@ -186,9 +186,9 @@ object ErrorGroupTree { private def handleErrorCode(e: ErrorCodeValue): String = { val deprecationText = e.deprecationO.fold("")(d => s""" - | **Depreciation**: ${d} + | **Deprecation**: ${d} | """.stripMargin) - s"""Error code: ${e.code} + s"""${e.code} |^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | $deprecationText | **Explanation**: ${e.explanation} From 84c10bc027e5d90de2df7c05be7244e8f58e9b2e Mon Sep 17 00:00:00 2001 From: Pawel Batko Date: Tue, 23 Nov 2021 13:05:28 +0100 Subject: [PATCH 7/7] Fix section order in pdf --- docs/source/app-dev/grpc/index.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/source/app-dev/grpc/index.rst b/docs/source/app-dev/grpc/index.rst index 5163e89bdee6..65641a37cd1b 100644 --- a/docs/source/app-dev/grpc/index.rst +++ b/docs/source/app-dev/grpc/index.rst @@ -7,11 +7,6 @@ gRPC #### -.. toctree:: - :hidden: - - error-codes - If you want to write an application for the ledger API in other languages, you'll need to use `gRPC `__ directly. If you're not familiar with gRPC and protobuf, we strongly recommend following the `gRPC quickstart `__ and `gRPC tutorials `__. This documentation is written assuming you already have an understanding of gRPC. @@ -100,3 +95,9 @@ INTERNAL, UNKNOWN (when returned by the Command Service) Aside from the standard gRPC status codes, the failures returned by the Ledger API are enriched with details meant to help the application or the application developer to handle the error autonomously (e.g. by retrying on a retryable error). For more details on the rich error details see the :doc:`error-codes` + + +.. toctree:: + :hidden: + + error-codes