This is an automated email from the ASF dual-hosted git repository.

slawrence pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil.git


The following commit(s) were added to refs/heads/main by this push:
     new 0029591  Move where runtime2 stores the daffodil version
0029591 is described below

commit 0029591b643c191ea0156dd830e848e7f8a3e728
Author: Steve Lawrence <[email protected]>
AuthorDate: Tue Nov 30 09:03:00 2021 -0500

    Move where runtime2 stores the daffodil version
    
    Currently, runtime2 writes the daffodil version to generated_code.c. We
    store some example generated_code.c files in the repo as examples, which
    means when we bump the Daffodil version number we must also remember to
    update these examples. That's not hard and we do have github checks to
    ensure they are updated, but it's one more thing to think about during
    the release process.
    
    To avoid this extra work, this adds a new libcli/version.h file and
    overwrites it with the actual version number when generating code. Since
    this file is not stored along with the generated example code, we don't
    have to worry about updating generated code stored in the repo during
    version bumps.
    
    This also adds a new ForkCaptureLogger to make it easier to capture
    stderr/stdout from our forked processes in sbt and handle it
    appropriately. This way we can get a list of generated files from std
    out and log errors from stderr.
    
    DAFFODIL-2592
---
 build.sbt                                          | 24 +++++-------
 .../daffodil/runtime2/c/libcli/daffodil_getopt.c   |  1 +
 .../apache/daffodil/runtime2/c/libcli/version.h    | 28 ++++++++++++++
 .../apache/daffodil/runtime2/CodeGenerator.scala   |  3 ++
 .../runtime2/generators/CodeGeneratorState.scala   | 20 +++++++---
 .../test/c/examples/NestedUnion/generated_code.c   |  4 --
 .../src/test/c/examples/ex_nums/generated_code.c   |  4 --
 project/ForkCaptureLogger.scala                    | 43 ++++++++++++++++++++++
 8 files changed, 98 insertions(+), 29 deletions(-)

diff --git a/build.sbt b/build.sbt
index 917ae7a..be286e2 100644
--- a/build.sbt
+++ b/build.sbt
@@ -289,19 +289,16 @@ lazy val libManagedSettings = Seq(
     val args = Seq(mainClass, outdir.toString)
     val filesToWatch = (inSrc ++ inRSrc).toSet
     val cachedFun = FileFunction.cached(stream.cacheDirectory / "propgen") { _ 
=>
-      val out = new java.io.ByteArrayOutputStream()
+      val forkCaptureLogger = ForkCaptureLogger()
       val forkOpts = ForkOptions()
-                       .withOutputStrategy(Some(CustomOutput(out)))
+                       
.withOutputStrategy(Some(LoggedOutput(forkCaptureLogger)))
                        .withBootJars(cp.files.toVector)
       val ret = Fork.java(forkOpts, args)
+      forkCaptureLogger.stderr.foreach { stream.log.error(_) }
       if (ret != 0) {
         sys.error("Failed to generate code")
       }
-      val bis = new java.io.ByteArrayInputStream(out.toByteArray)
-      val isr = new java.io.InputStreamReader(bis)
-      val br = new java.io.BufferedReader(isr)
-      val iterator = Iterator.continually(br.readLine()).takeWhile(_ != null)
-      val files = iterator.map { f =>
+      val files = forkCaptureLogger.stdout.map { f =>
         new File(f)
       }.toSet
       stream.log.info(s"generated ${files.size} Scala sources to ${outdir}")
@@ -369,22 +366,19 @@ lazy val genExamplesSettings = Seq(
     val stream = (runtime2 / streams).value
     val filesToWatch = (inSrc ++ inRSrc).toSet
     val cachedFun = FileFunction.cached(stream.cacheDirectory / "genExamples") 
{ _ =>
-      val out = new java.io.ByteArrayOutputStream()
+      val forkCaptureLogger = ForkCaptureLogger()
       val forkOpts = ForkOptions()
-                       .withOutputStrategy(Some(CustomOutput(out)))
+                       
.withOutputStrategy(Some(LoggedOutput(forkCaptureLogger)))
                        .withBootJars(cp.files.toVector)
       val mainClass = "org.apache.daffodil.runtime2.CodeGenerator"
       val outdir = (runtime2 / Test / sourceDirectory).value / "c" / "examples"
       val args = Seq(mainClass, outdir.toString)
       val ret = Fork.java(forkOpts, args)
+      forkCaptureLogger.stderr.foreach { stream.log.error(_) }
       if (ret != 0) {
-        stream.log.error(s"failed to generate example files")
+        sys.error("failed to generate example files")
       }
-      val bis = new java.io.ByteArrayInputStream(out.toByteArray)
-      val isr = new java.io.InputStreamReader(bis)
-      val br = new java.io.BufferedReader(isr)
-      val iterator = Iterator.continually(br.readLine()).takeWhile(_ != 
null).filterNot(_.startsWith("WARN"))
-      val files = iterator.map { f =>
+      val files = 
forkCaptureLogger.stdout.filterNot(_.startsWith("WARNING")).map { f =>
         new File(f)
       }.toSet
       stream.log.info(s"generated ${files.size} runtime2 example files to 
${outdir}")
diff --git 
a/daffodil-runtime2/src/main/resources/org/apache/daffodil/runtime2/c/libcli/daffodil_getopt.c
 
b/daffodil-runtime2/src/main/resources/org/apache/daffodil/runtime2/c/libcli/daffodil_getopt.c
index ad979d2..dabb2d6 100644
--- 
a/daffodil-runtime2/src/main/resources/org/apache/daffodil/runtime2/c/libcli/daffodil_getopt.c
+++ 
b/daffodil-runtime2/src/main/resources/org/apache/daffodil/runtime2/c/libcli/daffodil_getopt.c
@@ -20,6 +20,7 @@
 #include <string.h>      // for strcmp, strrchr
 #include <unistd.h>      // for optarg, getopt, optopt, optind
 #include "cli_errors.h"  // for CLI_UNEXPECTED_ARGUMENT, CLI_HELP_USAGE, 
CLI_INVALID_COMMAND, CLI_INVALID_INFOSET, CLI_INVALID_OPTION, 
CLI_MISSING_COMMAND, CLI_MISSING_VALUE, CLI_PROGRAM_ERROR, CLI_PROGRAM_VERSION
+#include "version.h"
 // clang-format on
 
 // Initialize our "daffodil" CLI options
diff --git 
a/daffodil-runtime2/src/main/resources/org/apache/daffodil/runtime2/c/libcli/version.h
 
b/daffodil-runtime2/src/main/resources/org/apache/daffodil/runtime2/c/libcli/version.h
new file mode 100644
index 0000000..23a9a88
--- /dev/null
+++ 
b/daffodil-runtime2/src/main/resources/org/apache/daffodil/runtime2/c/libcli/version.h
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VERSION_H
+#define VERSION_H
+
+// This file will be overwritten with the correct program version information
+// when code is generated. This file exists here to support compiling the other
+// C files without generated code during Daffodil builds to ensure there are no
+// compilation errors in these C files.
+
+const char *daffodil_program_version = "DAFFODIL_PROGRAM_VERSION";
+
+#endif // VERSION_H
diff --git 
a/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/CodeGenerator.scala
 
b/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/CodeGenerator.scala
index e88c632..06b15e3 100644
--- 
a/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/CodeGenerator.scala
+++ 
b/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/CodeGenerator.scala
@@ -92,12 +92,15 @@ class CodeGenerator(root: Root) extends DFDL.CodeGenerator {
     diagnostics = diagnostics ++ root.warnings
     val codeHeaderText = codeGeneratorState.generateCodeHeader
     val codeFileText = codeGeneratorState.generateCodeFile(rootElementName)
+    val versionHeaderText = codeGeneratorState.generateVersionHeader
 
     // Write the generated C code into our code subdirectory
     val generatedCodeHeader = codeDir/"libruntime"/"generated_code.h"
     val generatedCodeFile = codeDir/"libruntime"/"generated_code.c"
+    val generatedVersionHeader = codeDir/"libcli"/"version.h"
     os.write(generatedCodeHeader, codeHeaderText)
     os.write(generatedCodeFile, codeFileText)
+    os.write.over(generatedVersionHeader, versionHeaderText)
 
     // Return our code directory in case caller wants to call compileCode next
     codeDir
diff --git 
a/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala
 
b/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala
index be8b3be..1ae4c94 100644
--- 
a/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala
+++ 
b/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala
@@ -608,6 +608,20 @@ class CodeGeneratorState {
     }
   }
 
+  def generateVersionHeader: String = {
+    val program = this.getClass.getPackage.getImplementationTitle
+    val version = this.getClass.getPackage.getImplementationVersion
+    val versionHeader =
+      s"""#ifndef VERSION_H
+         |#define VERSION_H
+         |
+         |const char *daffodil_program_version = "$program $version";
+         |
+         |#endif // VERSION_H
+         |""".stripMargin
+    versionHeader.replace("\r\n", "\n").replace("\n", System.lineSeparator)
+  }
+
   def generateCodeHeader: String = {
     val structs = finalStructs.mkString("\n")
     val header =
@@ -630,8 +644,6 @@ class CodeGeneratorState {
   }
 
   def generateCodeFile(rootElementName: String): String = {
-    val program = this.getClass.getPackage.getImplementationTitle
-    val version = this.getClass.getPackage.getImplementationVersion
     val prototypes = this.prototypes.mkString("\n")
     val erds = this.erds.mkString("\n")
     val finalImplementation = this.finalImplementation.mkString("\n")
@@ -647,10 +659,6 @@ class CodeGeneratorState {
          |#include "unparsers.h"  // for unparse_hexBinary, unparse_be_float, 
unparse_be_int16, unparse_validate_fixed, unparse_be_bool32, unparse_be_bool16, 
unparse_be_int32, unparse_be_uint16, unparse_be_uint32, unparse_le_bool32, 
unparse_le_int64, unparse_le_uint16, unparse_le_uint8, unparse_be_bool8, 
unparse_be_double, unparse_be_int64, unparse_be_int8, unparse_be_uint64, 
unparse_be_uint8, unparse_le_bool16, unparse_le_bool8, unparse_le_double, 
unparse_le_float, unparse_le_int16, unp [...]
          |// clang-format on
          |
-         |// Initialize our program's name and version
-         |
-         |const char *daffodil_program_version = "$program $version";
-         |
          |// Declare prototypes for easier compilation
          |
          |$prototypes
diff --git a/daffodil-runtime2/src/test/c/examples/NestedUnion/generated_code.c 
b/daffodil-runtime2/src/test/c/examples/NestedUnion/generated_code.c
index 071439b..add3f62 100644
--- a/daffodil-runtime2/src/test/c/examples/NestedUnion/generated_code.c
+++ b/daffodil-runtime2/src/test/c/examples/NestedUnion/generated_code.c
@@ -9,10 +9,6 @@
 #include "unparsers.h"  // for unparse_hexBinary, unparse_be_float, 
unparse_be_int16, unparse_validate_fixed, unparse_be_bool32, unparse_be_bool16, 
unparse_be_int32, unparse_be_uint16, unparse_be_uint32, unparse_le_bool32, 
unparse_le_int64, unparse_le_uint16, unparse_le_uint8, unparse_be_bool8, 
unparse_be_double, unparse_be_int64, unparse_be_int8, unparse_be_uint64, 
unparse_be_uint8, unparse_le_bool16, unparse_le_bool8, unparse_le_double, 
unparse_le_float, unparse_le_int16, unparse_le_in [...]
 // clang-format on
 
-// Initialize our program's name and version
-
-const char *daffodil_program_version = "daffodil-runtime2 3.2.0";
-
 // Declare prototypes for easier compilation
 
 static void foo_initSelf(foo *instance);
diff --git a/daffodil-runtime2/src/test/c/examples/ex_nums/generated_code.c 
b/daffodil-runtime2/src/test/c/examples/ex_nums/generated_code.c
index fd1642d..0a81fec 100644
--- a/daffodil-runtime2/src/test/c/examples/ex_nums/generated_code.c
+++ b/daffodil-runtime2/src/test/c/examples/ex_nums/generated_code.c
@@ -9,10 +9,6 @@
 #include "unparsers.h"  // for unparse_hexBinary, unparse_be_float, 
unparse_be_int16, unparse_validate_fixed, unparse_be_bool32, unparse_be_bool16, 
unparse_be_int32, unparse_be_uint16, unparse_be_uint32, unparse_le_bool32, 
unparse_le_int64, unparse_le_uint16, unparse_le_uint8, unparse_be_bool8, 
unparse_be_double, unparse_be_int64, unparse_be_int8, unparse_be_uint64, 
unparse_be_uint8, unparse_le_bool16, unparse_le_bool8, unparse_le_double, 
unparse_le_float, unparse_le_int16, unparse_le_in [...]
 // clang-format on
 
-// Initialize our program's name and version
-
-const char *daffodil_program_version = "daffodil-runtime2 3.2.0";
-
 // Declare prototypes for easier compilation
 
 static void array_initSelf(array *instance);
diff --git a/project/ForkCaptureLogger.scala b/project/ForkCaptureLogger.scala
new file mode 100644
index 0000000..73e3fae
--- /dev/null
+++ b/project/ForkCaptureLogger.scala
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import sbt.util.Level
+import sbt.util.Logger
+import scala.collection.mutable.ArrayBuffer
+
+/**
+ * Logger only to be used in ForkOptions to capture stderr and stdout. Anything
+ * logged to info is captured as stdout, anything logged to error is captured
+ * as stderr. When used in ForkOptions, all other levels or logging functions
+ * should never be used.
+ */
+case class ForkCaptureLogger() extends Logger {
+
+  val stderr = ArrayBuffer[String]()
+  val stdout = ArrayBuffer[String]()
+
+  override def log(level: Level.Value, message: => String): Unit = {
+    level match {
+      case Level.Info => stdout.append(message)
+      case Level.Error => stderr.append(message)
+      case _ => sys.error("Should not be possible")
+    }
+  }
+  override def success(message: => String): Unit = sys.error("Should not be 
possible")
+  override def trace(t: => Throwable): Unit = sys.error("Should not be 
possible")
+
+}

Reply via email to