jadams-tresys commented on code in PR #183:
URL: https://github.com/apache/daffodil-sbt/pull/183#discussion_r3260491394


##########
src/main/scala/org/apache/daffodil/DaffodilPlugin.scala:
##########
@@ -840,6 +854,215 @@ object DaffodilPlugin extends AutoPlugin {
     }
   }
 
+  def daffodilFlattenSettings: Seq[Setting[_]] = Seq(
+    daffodilFlattenTarget := target.value / 
s"${name.value}-${version.value}-flat.zip",
+
+    /**
+     * Whether or not to publish the flattened schemas zip. Defaults to false.
+     *
+     * If projects want to publish flattened schemas then they must explicitly 
enable it by
+     * setting 'daffodilFlattenSchemas / publishArtifact := true'.
+     *
+     * If false, flattened schemas will not be created unless you explicitly 
run the
+     * daffodilFlattenSchemas.
+     */
+    daffodilFlattenSchemas / publishArtifact := false,
+
+    daffodilFlattenSchemas / artifact := Artifact(
+      name.value,
+      "flat",
+      "zip",
+      Some("flat"),
+      Vector(),
+      None
+    ),
+
+    /**
+     * Only grab the file types that need to be flattened. These files are only
+     * grabbed from the root project. Any referenced files will be pulled in
+     * from the classpath. Note that XML files are commonly used in XSLT for
+     * settings.
+     */
+    daffodilFlattenSchemas / includeFilter := "*.xsd" | "*.xsl" | "*.xslt" | 
"*.xml",
+    daffodilFlattenSchemas / excludeFilter := HiddenFileFilter,
+
+    daffodilFlattenResourceReferencePatterns := List(
+      """(?<!xsi:)schemaLocation=\"([^\"]*)\"""".r,
+      "href=\"([^\"]*)\"".r,
+      "document[(]'([^']*)'[)]".r
+    ),
+
+    daffodilFlattenSchemas / products := {
+
+      val logger = streams.value.log
+      val filter =
+        (daffodilFlattenSchemas / includeFilter).value -- 
(daffodilFlattenSchemas / excludeFilter).value
+
+      val flatDir = target.value / "flatDir"
+      if (flatDir.exists())
+        IO.delete(flatDir)
+      IO.createDirectory(flatDir)
+
+      val projectURLs = (Compile / resourceDirectories).value.map { root =>
+        (root ** filter).get.map(_.toURI.toURL).toList
+      }.flatten
+
+      /**
+       * Create a URLClassLoader object with URLs to all resources used by the
+       * project. The class loader will be used to resolve references made
+       * within the flattened files.
+       */
+      val allClasspathURLs = (Test / 
externalDependencyClasspath).value.map(_.data.toURI.toURL)
+      val classLoader = new URLClassLoader((projectURLs ++ 
allClasspathURLs).toArray, null)
+
+      val referenceRegexes = daffodilFlattenResourceReferencePatterns.value
+      val jarRegex = "(.*)!(.*)".r
+
+      val seen = scala.collection.mutable.Set[URI]()
+      val unprocessed = scala.collection.mutable.Stack[URI]()
+      unprocessed.pushAll(projectURLs.map(_.toURI))
+      seen ++= projectURLs.map(_.toURI)
+      while (!unprocessed.isEmpty) {
+        val contextURI = unprocessed.pop
+        val bytes = contextURI.toURL.openStream().readAllBytes()
+        val (contextPath, flatPath) = contextURI.getScheme match {
+          case "jar" =>
+            contextURI.toString match {
+              case jarRegex(jarPath, path) => {
+                val fs = try {
+                  FileSystems.getFileSystem(contextURI)
+                } catch {
+                  case e: FileSystemNotFoundException =>
+                    FileSystems.newFileSystem(contextURI, new 
java.util.HashMap[String, Any]())
+                }
+                val cPath = fs.getPath(path)
+                (cPath, Paths.get(flatDir.toString, 
cPath.toString.tail.replaceAll("/", "__")))
+              }
+              case _ =>
+                throw new IllegalArgumentException(s"Unable to parse JAR URI: 
$contextURI")
+            }
+          case "file" => {
+            val path = Paths.get(contextURI)
+            val root = (Compile / resourceDirectories).value
+              .find(file => contextURI.toString.contains(file.toString))
+              .get
+              .toURI
+            (
+              path,
+              Paths.get(
+                flatDir.toString,
+                Paths.get(root).relativize(path).toString.replaceAll("/", "__")
+              )
+            )
+          }
+          case _ =>
+            throw new IllegalArgumentException(s"Unrecognized URI scheme: 
$contextURI")
+        }
+
+        val bw = Files.newBufferedWriter(flatPath)

Review Comment:
   I'll make that change.  Originally we did want it to overwrite as we were 
simply copying files in reverse classpath order, but now that we are properly 
resolving references we shouldn't ever need to overwrite.



-- 
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]

Reply via email to