stevedlawrence commented on code in PR #253:
URL: https://github.com/apache/daffodil-vscode/pull/253#discussion_r963831051
##########
.vscode/launch.json:
##########
@@ -48,6 +48,15 @@
],
"internalConsoleOptions": "openOnSessionStart",
"preLaunchTask": "npm: compile"
+ },
+ {
+ "type": "scala",
+ "request": "launch",
+ "name": "DAPodil",
Review Comment:
What does this actually launch? What is DAPodil?
##########
bindings.xjb:
##########
@@ -0,0 +1,58 @@
+<jxb:bindings version="2.1"
Review Comment:
This needs a license header.
Also, is this generated? Can this just be created as part of the build
process?
##########
bindings.xjb:
##########
@@ -0,0 +1,58 @@
+<jxb:bindings version="2.1"
+ xmlns:tdml="http://www.ibm.com/xmlns/dfdl/testData"
+ xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
+ xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <jxb:globalBindings>
+ <jxb:serializable uid="1" />
+ </jxb:globalBindings>
+ <jxb:bindings schemaLocation="resources/xsd/DFDL_part3_model.xsd"
version="1.0">
+ <jxb:bindings
node="//xs:attributeGroup[@name='SetVariableAG']/xs:attribute[@name='value']">
+ <jxb:property name="ValueAttribute"/>
+ </jxb:bindings>
+ <jxb:bindings node="//xs:element[@name='simpleType']">
+ <jxb:class name="simpleTypeClass"/>
+ </jxb:bindings>
+ <jxb:bindings node="//xs:element[@name='group']">
+ <jxb:class name="groupClass"/>
+ </jxb:bindings>
+ <jxb:bindings node="//xs:element[@name='choice']">
+ <jxb:class name="choiceClass"/>
+ </jxb:bindings>
+ <jxb:bindings node="//xs:element[@name='sequence']">
+ <jxb:class name="sequenceClass"/>
+ </jxb:bindings>
+ <jxb:bindings node="//xs:element[@name='element']">
+ <jxb:class name="elementClass"/>
+ </jxb:bindings>
+ </jxb:bindings>
+ <jxb:bindings schemaLocation="resources/xsd/DFDL_part2_attributes.xsd"
version="1.0">
+ <jxb:bindings
node="//xs:attributeGroup[@name='BaseAGQualified']/xs:attribute[@name='ref']">
+ <jxb:property name="RefAttribute"/>
+ </jxb:bindings>
+ </jxb:bindings>
+ <jxb:bindings schemaLocation="resources/xsd/DFDL_part1_simpletypes.xsd"
version="1.0">
+ <jxb:bindings node="//xs:simpleType[@name='ByteOrderEnum']">
+ <jxb:typesafeEnumClass name="ByteOrderEnumType"/>
+ </jxb:bindings>
+ <jxb:bindings node="//xs:simpleType[@name='BitOrderEnum']">
+ <jxb:typesafeEnumClass name="BitOrderEnumType"/>
+ </jxb:bindings>
+ </jxb:bindings>
+ <jxb:bindings schemaLocation="resources/xsd/dafext.xsd" version="1.0">
+ <jxb:bindings node="//xs:attribute[@name='parseUnparsePolicy']">
+ <jxb:property name="ParseUnparsePolicyExt"/>
+ </jxb:bindings>
+ <jxb:bindings node="//xs:simpleType[@name='PropertyNameType']">
+ <jxb:typesafeEnumClass name="PropertyNameTypeExt"/>
+ </jxb:bindings>
+ <jxb:bindings node="//xs:complexType[@name='PropertyType']">
+ <jxb:class name="PropertyTypeClass"/>
+ </jxb:bindings>
+ </jxb:bindings>
+ <jxb:bindings schemaLocation="resources/xsd/dfdlx.xsd" version="1.0">
+ <jxb:bindings node="//xs:simpleType[@name='PropertyNameType']">
+ <jxb:typesafeEnumClass name="PropertyNameTypeX"/>
+ </jxb:bindings>
+ </jxb:bindings>
+</jxb:bindings>
Review Comment:
What is the decision point for what bindings get included? There seems to be
very small subset of everything defined in the schemas?
##########
build.sbt:
##########
@@ -88,3 +89,180 @@ lazy val core = project
packageName := s"${name.value}-$daffodilVer"
)
.enablePlugins(commonPlugins: _*)
+ .dependsOn(sbtXjcProject)
+ .aggregate(sbtXjcProject)
+
+lazy val sbtXjcProject = project
+ .in(file("server/sbtXjc"))
+ .enablePlugins(SbtXjcPlugin)
+ .settings(
+ name := "daffodil-xjc",
+ libraryDependencies ++= Seq(
+ "javax.activation" % "activation" % "1.1.1",
+ "com.sun.xml.bind" % "jaxb-xjc" % "2.1.6"
+ ),
+ xjcCommandLine += "-nv",
+ xjcCommandLine += "-p",
+ xjcCommandLine += "org.apache.daffodil.tdml",
+ xjcBindings += "bindings.xjb",
+ xjcJvmOpts += "-classpath",
+ xjcJvmOpts += Seq(
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "javax",
+ "activation",
+ "activation",
+ "1.1.1",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "javax",
+ "activation",
+ "javax.activation-api",
+ "1.2.0",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "org",
+ "glassfish",
+ "jaxb",
+ "txw2",
+ "2.2.11",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "relaxngDatatype",
+ "relaxngDatatype",
+ "20020414",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "com",
+ "sun",
+ "xsom",
+ "xsom",
+ "20140925",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "com",
+ "sun",
+ "xml",
+ "bind",
+ "external",
+ "rngom",
+ "2.2.11",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "com",
+ "sun",
+ "istack",
+ "istack-commons-runtime",
+ "2.21",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "org",
+ "glassfish",
+ "jaxb",
+ "codemodel",
+ "2.2.11",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "org",
+ "glassfish",
+ "jaxb",
+ "jaxb-core",
+ "2.2.11",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "javax",
+ "xml",
+ "bind",
+ "jaxb-api",
+ "2.1",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "com",
+ "sun",
+ "istack",
+ "istack-commons-tools",
+ "2.21",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "org",
+ "glassfish",
+ "jaxb",
+ "jaxb-xjc",
+ "2.2.11",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "com",
+ "sun",
+ "xml",
+ "bind",
+ "jaxb-impl",
+ "2.2.11",
+ "*"
Review Comment:
Is adding all these paths manually really the expected usage of this? This
seems incredibly fragile and hard to maintain, especially with the verisions in
the. Isn't any version change going to break this? Does the sbt xjc plugin not
handle all of this?
##########
project/Rat.scala:
##########
@@ -34,7 +34,9 @@ object Rat {
file("images/daffodil.ico"),
// yarn and rpm generated files
file("yarn.lock"),
- file("package-lock.json")
+ file("package-lock.json"),
+ // JAXB Bindings files
+ file("bindings.xjb")
Review Comment:
If a file can have a license, it should have one. An xjb file is just XML
and so can have a license. This should be removed from the Rat excludes.
##########
build.sbt:
##########
@@ -88,3 +89,180 @@ lazy val core = project
packageName := s"${name.value}-$daffodilVer"
)
.enablePlugins(commonPlugins: _*)
+ .dependsOn(sbtXjcProject)
+ .aggregate(sbtXjcProject)
+
+lazy val sbtXjcProject = project
+ .in(file("server/sbtXjc"))
+ .enablePlugins(SbtXjcPlugin)
+ .settings(
+ name := "daffodil-xjc",
+ libraryDependencies ++= Seq(
+ "javax.activation" % "activation" % "1.1.1",
+ "com.sun.xml.bind" % "jaxb-xjc" % "2.1.6"
+ ),
+ xjcCommandLine += "-nv",
+ xjcCommandLine += "-p",
+ xjcCommandLine += "org.apache.daffodil.tdml",
+ xjcBindings += "bindings.xjb",
+ xjcJvmOpts += "-classpath",
+ xjcJvmOpts += Seq(
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "javax",
+ "activation",
+ "activation",
+ "1.1.1",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "javax",
+ "activation",
+ "javax.activation-api",
+ "1.2.0",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "org",
+ "glassfish",
+ "jaxb",
+ "txw2",
+ "2.2.11",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "relaxngDatatype",
+ "relaxngDatatype",
+ "20020414",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "com",
+ "sun",
+ "xsom",
+ "xsom",
+ "20140925",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "com",
+ "sun",
+ "xml",
+ "bind",
+ "external",
+ "rngom",
+ "2.2.11",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "com",
+ "sun",
+ "istack",
+ "istack-commons-runtime",
+ "2.21",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "org",
+ "glassfish",
+ "jaxb",
+ "codemodel",
+ "2.2.11",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "org",
+ "glassfish",
+ "jaxb",
+ "jaxb-core",
+ "2.2.11",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "javax",
+ "xml",
+ "bind",
+ "jaxb-api",
+ "2.1",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "com",
+ "sun",
+ "istack",
+ "istack-commons-tools",
+ "2.21",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "org",
+ "glassfish",
+ "jaxb",
+ "jaxb-xjc",
+ "2.2.11",
+ "*"
+ ).mkString(java.io.File.separator),
+ Seq(
+ s"${csrCacheDirectory.value}",
+ "https",
+ "repo1.maven.org",
+ "maven2",
+ "com",
+ "sun",
+ "xml",
+ "bind",
+ "jaxb-impl",
+ "2.2.11",
+ "*"
+ ).mkString(java.io.File.separator)
+ ).mkString(java.io.File.pathSeparator),
+ Compile / xjc / sources := Seq(file("resources/xsd")),
Review Comment:
Should these files be in the `server/sbtXjc` subproject? Though, maybe I'm
not sure what the sbtXjc subproject is for? That directory doesn't actually
exist?
##########
resources/xsd/xml.xsd:
##########
@@ -0,0 +1,155 @@
+<?xml version='1.0'?>
+<!--
+ Copyright © 2018 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, European Research Consortium for Informatics and
+ Mathematics, Keio University, Beihang). All Rights Reserved. This work is
+ distributed under the W3C® Software License [1] in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+-->
Review Comment:
Many of these files you've copied have different licenses. If they are going
to be copied like this (which I hope there is an alternative), then you need to
update the LICENSE/NOTICE files accordingly.
##########
server/core/src/main/scala/org.apache.daffodil.debugger.dap/Parse.scala:
##########
@@ -176,71 +180,333 @@ object Parse {
case class File(path: Path) extends InfosetOutput
}
+ sealed trait TDMLConfig extends LaunchArgs
+ object TDMLConfig {
+ case class Generate(
+ schemaPath: Path,
+ dataPath: Path,
+ stopOnEntry: Boolean,
+ infosetOutput: LaunchArgs.InfosetOutput,
+ name: String,
+ description: String,
+ path: String
+ ) extends TDMLConfig
+
+ case class Append(
+ schemaPath: Path,
+ dataPath: Path,
+ stopOnEntry: Boolean,
+ infosetOutput: LaunchArgs.InfosetOutput,
+ name: String,
+ description: String,
+ path: String
+ ) extends TDMLConfig
+
+ case class Execute(
+ stopOnEntry: Boolean,
+ infosetOutput: LaunchArgs.InfosetOutput,
+ name: String,
+ description: String,
+ path: String
+ ) extends TDMLConfig
+ }
+
def parse(arguments: JsonObject): EitherNel[String, LaunchArgs] =
+ // Determine, based on the presence of the tdmlConfig object in the
launch config, whether
+ // this is a "normal" DFDL operation or if we should attempt to
parse the values from
+ // the tdmlConfig object.
+ Option(arguments.getAsJsonObject("tdmlConfig")) match {
+ case None => parseManual(arguments)
+ case Some(tdmlConfig) => parseTDML(arguments, tdmlConfig)
+ }
+
+ // Parse a launch config that has been found to not have a tdmlConfig
object
+ def parseManual(arguments: JsonObject): EitherNel[String, LaunchArgs] =
(
- Option(arguments.getAsJsonPrimitive("program"))
- .toRight("missing 'program' field from launch request")
- .flatMap(path =>
- Either
- .catchNonFatal(Paths.get(path.getAsString))
- .leftMap(t => s"'program' field from launch request is not a
valid path: $t")
- .ensureOr(path => s"program file at $path doesn't
exist")(_.toFile().exists())
- )
- .toEitherNel,
- Option(arguments.getAsJsonPrimitive("data"))
- .toRight("missing 'data' field from launch request")
- .flatMap(path =>
- Either
- .catchNonFatal(Paths.get(path.getAsString))
- .leftMap(t => s"'data' field from launch request is not a
valid path: $t")
- .ensureOr(path => s"data file at $path doesn't
exist")(_.toFile().exists())
- )
- .toEitherNel,
- Option(arguments.getAsJsonPrimitive("stopOnEntry"))
- .map(_.getAsBoolean())
- .getOrElse(true)
- .asRight[String]
- .toEitherNel,
- Option(arguments.getAsJsonObject("infosetOutput")) match {
+ parseProgram(arguments),
+ parseData(arguments),
+ parseStopOnEntry(arguments),
+ parseInfosetOutput(arguments)
+ ).parMapN(LaunchArgs.Manual.apply)
+ }
+
+ // Parse a tdmlConfig object from the launch config
+ //
+ // tdmlConfig: {
+ // action: '',
+ // name: '',
+ // description: '',
+ // path: ''
+ // }
+ //
+ // The action field is parsed first.
+ // If it is a valid action ('generate' | 'append' | 'execute'), create a
LaunchArgs object of the appropriate type
+ // If it is 'none' or missing, create a LaunchArgs.Manual object. This
will ignore any other fields in the tdmlConfig object.
+ //
+ // arguments: Launch config
+ // tdmlConfig: tdmlConfig object from the launch config
+ def parseTDML(arguments: JsonObject, tdmlConfig: JsonObject):
EitherNel[String, LaunchArgs] =
+ Option(tdmlConfig.getAsJsonPrimitive("action")) match {
+ case None =>
+ (
+ parseProgram(arguments),
+ parseData(arguments),
+ parseStopOnEntry(arguments),
+ parseInfosetOutput(arguments)
+ ).parMapN(LaunchArgs.Manual.apply)
+ case Some(action) =>
+ action.getAsString() match {
+ case "generate" =>
+ (
+ parseProgram(arguments),
+ parseData(arguments),
+ parseStopOnEntry(arguments),
+ parseInfosetOutput(arguments, true),
+ parseTDMLName(tdmlConfig),
+ parseTDMLDescription(tdmlConfig),
+ parseTDMLPath(tdmlConfig)
+ ).parMapN(LaunchArgs.TDMLConfig.Generate.apply)
+ case "append" =>
+ (
+ parseProgram(arguments),
+ parseData(arguments),
+ parseStopOnEntry(arguments),
+ parseInfosetOutput(arguments, true),
+ parseTDMLName(tdmlConfig),
+ parseTDMLDescription(tdmlConfig),
+ parseTDMLPath(tdmlConfig)
+ ).parMapN(LaunchArgs.TDMLConfig.Append.apply)
+ case "execute" =>
+ (
+ parseStopOnEntry(arguments),
+ parseInfosetOutput(arguments),
+ parseTDMLName(tdmlConfig),
+ parseTDMLDescription(tdmlConfig),
+ parseTDMLPath(tdmlConfig)
+ ).parMapN(LaunchArgs.TDMLConfig.Execute.apply)
+ case "none" =>
+ (
+ parseProgram(arguments),
+ parseData(arguments),
+ parseStopOnEntry(arguments),
+ parseInfosetOutput(arguments)
+ ).parMapN(LaunchArgs.Manual.apply)
+ case invalidType =>
+ Left(
+ s"invalid 'tdmlConfig.action': '$invalidType', must be 'none',
'generate', 'append', or 'execute'"
+ ).toEitherNel
+ }
+ }
+
+ // Parse the program field from the launch config
+ // Returns an error if the program field is missing or is an invalid path
+ // A case where the user expects a new directory to be created is not a
valid path
+ // eg. /path/to/<existing>/<non-existing>/file.tdml
+ //
+ // arguments: Launch config
+ def parseProgram(arguments: JsonObject) =
+ Option(arguments.getAsJsonPrimitive("program"))
+ .toRight("missing 'program' field from launch request")
+ .flatMap(path =>
+ Either
+ .catchNonFatal(Paths.get(path.getAsString))
+ .leftMap(t => s"'program' field from launch request is not a valid
path: $t")
+ .ensureOr(path => s"program file at $path doesn't
exist")(_.toFile().exists())
+ )
+ .toEitherNel
+
+ // Parse the data field from the launch config
+ // Returns an error if the data field is missing or is an invalid path
+ // A case where the user expects a new directory to be created is not a
valid path
+ // eg. /path/to/<existing>/<non-existing>/file.tdml
+ //
+ // arguments: Launch config
+ def parseData(arguments: JsonObject) =
+ Option(arguments.getAsJsonPrimitive("data"))
+ .toRight("missing 'data' field from launch request")
+ .flatMap(path =>
+ Either
+ .catchNonFatal(Paths.get(path.getAsString))
+ .leftMap(t => s"'data' field from launch request is not a valid
path: $t")
+ .ensureOr(path => s"data file at $path doesn't
exist")(_.toFile().exists())
+ )
+ .toEitherNel
+
+ // Parse the stopOnEntry field from the launch config
+ // Defaults to true
+ //
+ // arguments: Launch config
+ def parseStopOnEntry(arguments: JsonObject) =
+ Option(arguments.getAsJsonPrimitive("stopOnEntry"))
+ .map(_.getAsBoolean())
+ .getOrElse(true)
+ .asRight[String]
+ .toEitherNel
+
+ // Parse the infosetOutput object from the launch config
+ //
+ // infosetOutput: {
+ // type: '',
+ // path: ''
+ // }
+ //
+ // Type must be 'none' | 'console' | 'file'
+ // If type is 'file', there must be a 'path' field that contains a valid
path
+ // for the resulting infoset to be written to
+ // A case where the user expects a new directory to be created is not a
valid path
+ // eg. /path/to/<existing>/<non-existing>/file.tdml
+ //
+ // arguments: Launch config
+ // requireFile: Whether or not the type field must be set to file. This is
a requirement
+ // for the TDML generate operation. Returns an error if this
boolean
+ // is set to True, and the type field is set to a value other
than file
+ def parseInfosetOutput(arguments: JsonObject, requireFile: Boolean =
false) =
+ Option(arguments.getAsJsonObject("infosetOutput")) match {
+ case None => Right(LaunchArgs.InfosetOutput.Console).toEitherNel
+ case Some(infosetOutput) =>
+ Option(infosetOutput.getAsJsonPrimitive("type")) match {
case None => Right(LaunchArgs.InfosetOutput.Console).toEitherNel
- case Some(infosetOutput) =>
- Option(infosetOutput.getAsJsonPrimitive("type")) match {
- case None =>
Right(LaunchArgs.InfosetOutput.Console).toEitherNel
- case Some(typ) =>
- typ.getAsString() match {
- case "none" =>
Right(LaunchArgs.InfosetOutput.None).toEitherNel
- case "console" =>
Right(LaunchArgs.InfosetOutput.Console).toEitherNel
- case "file" =>
- Option(infosetOutput.getAsJsonPrimitive("path"))
- .toRight("missing 'infosetOutput.path' field from
launch request")
- .flatMap(path =>
- Either
-
.catchNonFatal(LaunchArgs.InfosetOutput.File(Paths.get(path.getAsString)))
- .leftMap(t => s"'infosetOutput.path' field from
launch request is not a valid path: $t")
- .ensureOr(file => s"can't write to infoset output
file at ${file.path}") { f =>
- val file = f.path.toFile
- file.canWrite || (!file.exists &&
file.getParentFile.canWrite)
- }
- )
- .toEitherNel
- case invalidType =>
- Left(
- s"invalid 'infosetOutput.type': '$invalidType', must
be 'none', 'console', or 'file'"
- ).toEitherNel
- }
+ case Some(typ) =>
+ typ.getAsString() match {
+ case "none" =>
+ if (requireFile)
+ Left("'type' field in 'infosetOutput' must be set to
'file'").toEitherNel
+ else
+ Right(LaunchArgs.InfosetOutput.None).toEitherNel
+ case "console" =>
+ if (requireFile)
+ Left("'type' field in 'infosetOutput' must be set to
'file'").toEitherNel
+ else
+ Right(LaunchArgs.InfosetOutput.Console).toEitherNel
+ case "file" =>
+ Option(infosetOutput.getAsJsonPrimitive("path"))
+ .toRight("missing 'infosetOutput.path' field from launch
request")
+ .flatMap(path =>
+ Either
+
.catchNonFatal(LaunchArgs.InfosetOutput.File(Paths.get(path.getAsString)))
+ .leftMap(t => s"'infosetOutput.path' field from launch
request is not a valid path: $t")
+ .ensureOr(file => s"can't write to infoset output file
at ${file.path}") { f =>
+ val file = f.path.toFile
+ // If an empty string is passed in, it will be set
to the workspace directory by default
+ // This is inside the Java code, so we have to make
sure that the TDML file we
+ // are working with is not a directory
+ !file.isDirectory() && (file.canWrite ||
(!file.exists && file.getParentFile.canWrite))
+ }
+ )
+ .toEitherNel
+ case invalidType =>
+ Left(
+ s"invalid 'infosetOutput.type': '$invalidType', must be
'none', 'console', or 'file'"
+ ).toEitherNel
}
}
- ).parMapN(LaunchArgs.apply)
- }
+ }
+
+ // The following functions granularly parse the tdmlConfig object from the
launch config
+ //
+ // tdmlConfig: {
+ // action: '',
+ // name: '',
+ // description: '',
+ // path: ''
+ // }
+ //
+ // The action field is parsed elsewhere. If these functions are hit, a
valid action
+ // other than 'none' was found.
+
+ // Parse the name field from the tdmlConfig object from the launch config
+ // Returns an error if the field is missing or is an empty string
+ //
+ // tdmlConfig: tdmlConfig object from the launch config
+ def parseTDMLName(tdmlConfig: JsonObject) =
+ Option(tdmlConfig.getAsJsonPrimitive("name"))
+ .toRight("missing 'tdmlConfig.name' field from launch request")
+ .map(_.getAsString())
+ .flatMap(name => Either.cond(name.length() > 0, name, "'name' field
from 'tdmlConfig' object cannot be empty"))
+ .toEitherNel
+
+ // Parse the description field from the tdmlConfig object from the launch
config
+ // Returns an error if the field is missing or is an empty string
+ //
+ // tdmlConfig: tdmlConfig object from the launch config
+ def parseTDMLDescription(tdmlConfig: JsonObject) =
+ Option(tdmlConfig.getAsJsonPrimitive("description"))
+ .toRight("missing 'tdmlConfig.description' field from launch request")
+ .map(_.getAsString())
+ .flatMap(description =>
+ Either
+ .cond(description.length() > 0, description, "'description' field
from 'tdmlConfig' object cannot be empty")
+ )
+ .toEitherNel
+
+ // Parse the path field from the tdmlConfig object from the launch config
+ // Returns an error if the field is missing or is an invalid path
+ // A case where the user expects a new directory to be created is not a
valid path
+ // eg. /path/to/<existing>/<non-existing>/file.tdml
+ //
+ // tdmlConfig: tdmlConfig object from the launch config
+ def parseTDMLPath(tdmlConfig: JsonObject) =
+ Option(tdmlConfig.getAsJsonPrimitive("path"))
+ .toRight("missing 'tdmlConfig.path' field from launch request")
+ .flatMap(path =>
+ Either
+
.catchNonFatal(Paths.get(path.getAsString).toFile().getAbsolutePath())
+ .leftMap(t => s"'infosetOutput.path' field from launch request is
not a valid path: $t")
+ .ensureOr(file => s"can't write to infoset output file at
${file}") { f =>
+ val file = Paths.get(f).toFile()
+ // If an empty string is passed in, it will be set to the
workspace directory by default
+ // This is inside the Java code, so we have to make sure that
the TDML file we
+ // are working with is not a directory
+ !file.isDirectory() && (file.canWrite || (!file.exists &&
file.getParentFile.canWrite))
+ }
+ )
+ .toEitherNel
Review Comment:
I'm a little concerned that this duplicates a decent amount of logic from
the daffodil tdml library. And there's a lot of non trivial code in the TDML
library that isn't implemented that we definitely don't want to reimplement.
For example, input data can be defined in binary, hex, or characters, and even
more complicates like bitOrder, replaceDFDLEntitites, etc. And this is just the
data portion. There's a lot of complexity to TDML files that I would hate to
have duplicated.
##########
resources/xsd/DFDL_part3_model.xsd:
##########
@@ -0,0 +1,368 @@
+<?xml version="1.0" encoding="UTF-8"?>
Review Comment:
I assume all these files in `resources/xsd` have just been copied and
unmodified from Daffodil? Can they instead be pulled out of the the
daffodil-lib dependency?
Otherwise these files may start to drift from the ones in Daffodil when we
make changes and we'll have to remember (and most likely forget) to keep things
updated.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]