Skip to content

Commit

Permalink
Start of CLI integration [WIP] (#8)
Browse files Browse the repository at this point in the history
* Remove morganstanley from package  name #1

* Further work on the Value side of the IR #1

* Working on setup of building the proto files used for grpc for the daemon

* Wired up CLI

* Fix print out for cli commands

* Do server startup

* Got zio-grpc code generation working for proto files

* Get the Daemon service to run

* Get daemon launching the gateway

* Working on grpc integration

* Simplify

* Cli setup

* Ensure args are passed to the command line

* Read in an IR JSON file into a JSON object

* Add "fuzzer for name"
  • Loading branch information
DamianReeves authored Mar 13, 2020
1 parent 653914c commit fe856f2
Show file tree
Hide file tree
Showing 27 changed files with 958 additions and 111 deletions.
159 changes: 159 additions & 0 deletions ScalaPBSupport.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
object module {
import java.net.URI
import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.{
FileSystems,
Files,
Path,
SimpleFileVisitor,
StandardCopyOption
}

import coursier.MavenRepository
import coursier.core.Version
import mill.define.Sources
import mill.api.PathRef
import mill.scalalib.Lib.resolveDependencies
import mill.scalalib._
import mill.api.Loose
import contrib.scalapblib._
import workers._

trait ZScalaPBModule extends ScalaPBModule {

def scalaPBZio: T[Boolean] = T { false }

def scalaPBPluginArtifacts = T { Seq.empty[String] }

def scalaPBIncludePath = Seq(scalaPBUnpackProto())

def compileScalaPB: T[PathRef] = T.persistent {
ZScalaPBWorkerApi.scalaPBWorker
.compile(
scalaPBClasspath().map(_.path),
scalaPBProtocPath(),
scalaPBSources().map(_.path),
scalaPBOptions(),
T.dest,
scalaPBIncludePath().map(_.path),
scalaPBZio(),
scalaPBPluginArtifacts()
)
}
}

}

object workers {
import java.io.File
import java.lang.reflect.Method
import java.net.URLClassLoader

import mill.api.PathRef

class ZScalaPBWorker {

private var scalaPBInstanceCache = Option.empty[(Long, ZScalaPBWorkerApi)]

private def scalaPB(
scalaPBClasspath: Agg[os.Path],
protocPath: Option[String]
) = {
val classloaderSig =
scalaPBClasspath.map(p => p.toString().hashCode + os.mtime(p)).sum
scalaPBInstanceCache match {
case Some((sig, instance)) if sig == classloaderSig => instance
case _ =>
val cl = new URLClassLoader(
scalaPBClasspath.map(_.toIO.toURI.toURL).toArray
)
val scalaPBCompilerClass = cl.loadClass("scalapb.ScalaPBC")
val mainMethod = scalaPBCompilerClass.getMethod(
"main",
classOf[Array[java.lang.String]]
)

val instance = new ZScalaPBWorkerApi {
override def compileScalaPB(
source: File,
scalaPBOptions: String,
generatedDirectory: File,
includes: Seq[os.Path],
useZIO: Boolean,
pluginArtifacts: Seq[String]
) {
val opts =
if (scalaPBOptions.isEmpty) "" else scalaPBOptions + ":"
val args =
pluginArtifacts.map(art => s"--plugin-artifact=$art") ++
protocPath.map(path => s"--protoc=$path").toSeq ++
Seq(
"--throw",
s"--scala_out=${opts}${generatedDirectory.getCanonicalPath}",
s"--proto_path=${source.getParentFile.getCanonicalPath}"
) ++
(if (useZIO)
Seq(s"--zio_out=${generatedDirectory.getCanonicalPath}")
else Seq.empty) ++
includes.map(i => s"--proto_path=${i.toIO.getCanonicalPath}") :+
source.getCanonicalPath
mainMethod.invoke(null, args.toArray)
}
}
scalaPBInstanceCache = Some((classloaderSig, instance))
instance
}
}

def compile(
scalaPBClasspath: Agg[os.Path],
protocPath: Option[String],
scalaPBSources: Seq[os.Path],
scalaPBOptions: String,
dest: os.Path,
scalaPBIncludePath: Seq[os.Path],
useZIO: Boolean,
pluginArtifacts: Seq[String]
)(implicit ctx: mill.api.Ctx): mill.api.Result[PathRef] = {
val compiler = scalaPB(scalaPBClasspath, protocPath)

def compileScalaPBDir(inputDir: os.Path) {
// ls throws if the path doesn't exist
if (inputDir.toIO.exists) {
os.walk(inputDir)
.filter(_.last.matches(".*.proto"))
.foreach { proto =>
compiler.compileScalaPB(
proto.toIO,
scalaPBOptions,
dest.toIO,
scalaPBIncludePath,
useZIO,
pluginArtifacts
)
}
}
}

scalaPBSources.foreach(compileScalaPBDir)

mill.api.Result.Success(PathRef(dest))
}
}

trait ZScalaPBWorkerApi {
def compileScalaPB(
source: File,
scalaPBOptions: String,
generatedDirectory: File,
includes: Seq[os.Path],
useZIO: Boolean,
pluginArtifacts: Seq[String]
)
}

object ZScalaPBWorkerApi {

def scalaPBWorker = new ZScalaPBWorker()
}
}
139 changes: 129 additions & 10 deletions build.sc
Original file line number Diff line number Diff line change
@@ -1,27 +1,120 @@
import $ivy.`com.lihaoyi::mill-contrib-bloop:$MILL_VERSION`
import $ivy.`com.lihaoyi::mill-contrib-scalapblib:$MILL_VERSION`
import $file.ScalaPBSupport
import ScalaPBSupport.module._
import mill._
import mill.scalalib._
import publish._
import mill.scalalib.scalafmt._
import $ivy.`com.lihaoyi::mill-contrib-bloop:$MILL_VERSION`
import contrib.scalapblib._
import coursier.maven.MavenRepository
import ammonite.ops._, ImplicitWd._

val productVersion = "0.1.0"

object morphir extends Module {
object core extends Cross[CoreModule]("2.12.10", "2.13.1") {}

object cli extends Cross[CliModule]("2.12.10", "2.13.1") {}

object core extends Cross[CoreModule]("2.12.10", "2.13.1") {}
object scala extends Cross[ScalaBackendModule]("2.12.10", "2.13.1") {}

}

class CoreModule(val crossScalaVersion: String)
extends CrossScalaModule
with MorphirModule {
with MorphirCommonModule
with PublishModule {

def publishVersion = productVersion
def ivyDeps = Agg(
ivy"com.lihaoyi::upickle::1.0.0"
ivy"com.lihaoyi::upickle:1.0.0",
ivy"dev.zio::zio-nio:${Versions.`zio-nio`}",
ivy"dev.zio::zio-streams:${Versions.zio}",
ivy"dev.zio::zio-test:${Versions.zio}"
)

def pomSettings = PomSettings(
description = "Morphir core package",
organization = "morphir",
url = "https://github.com/MorganStanley/morphir-jvm",
licenses = Seq(License.`Apache-2.0`),
versionControl = VersionControl.github("MorganStanley", "morphir-jvm"),
developers = Seq(
Developer(
"DamianReeves",
"Damian Reeves",
"https://github.com/DamianReeves"
)
)
)

object test extends Tests with MorphirTestModule {}
}

trait MorphirModule extends ScalafmtModule with CrossScalaModule {
class CliModule(val crossScalaVersion: String)
extends CrossScalaModule
with MorphirCommonModule {

def mainClass = Some("morphir.Main")
def ivyDeps = Agg(
ivy"org.rogach::scallop:${Versions.scallop}",
ivy"dev.zio::zio-nio:${Versions.`zio-nio`}",
ivy"dev.zio::zio-process:${Versions.`zio-process`}",
ivy"com.github.alexarchambault::case-app-refined:${Versions.`case-app`}"
)

def moduleDeps = Seq(
morphir.core(crossScalaVersion)
)

def generatedSources = T {
Seq(PathRef(generateBuildInfoFile(productVersion)))
}

def compile = T {
generatedSources()
super.compile()
}

object test extends Tests with MorphirTestModule {}
}

class ScalaBackendModule(val crossScalaVersion: String)
extends CrossScalaModule
with MorphirCommonModule {

def ivyDeps = Agg(
ivy"dev.zio::zio-streams:${Versions.zio}",
ivy"dev.zio::zio-nio:${Versions.`zio-nio`}"
)
def moduleDeps = Seq(
morphir.core(crossScalaVersion)
)
}

trait MorphirCommonModule extends ScalafmtModule with ScalaModule {
def repositories = super.repositories ++ Seq(
MavenRepository("https://oss.sonatype.org/content/repositories/snapshots")
)
def scalacOptions =
Seq(
"-unchecked",
"-deprecation",
"-deprecation", // Emit warning and location for usages of deprecated APIs.
"-explaintypes",
"-feature",
"-language:implicitConversions"
) ++ Seq("-encoding", "utf8")
"-unchecked",
"-target:jvm-1.8",
"-language:reflectiveCalls",
"-language:existentials", // Existential types (besides wildcard types) can be written and inferred
"-language:higherKinds", // Allow higher-kinded types
"-language:implicitConversions", // Allow definition of implicit functions called views
"-unchecked", // Enable additional warnings where generated code depends on assumptions.
"-Xcheckinit", // Wrap field accessors to throw an exception on uninitialized access.
"-Xfatal-warnings", // Fail the compilation if there are any warnings.
"-Ywarn-extra-implicit", // Warn when more than one implicit parameter section is defined.
"-Ywarn-unused:privates", // Warn if a private member is unused.
"-Xlint:inaccessible" // Warn about inaccessible types in method signatures.
) ++ Seq("-encoding", "utf-8")
}

trait MorphirTestModule extends TestModule {
Expand All @@ -35,5 +128,31 @@ trait MorphirTestModule extends TestModule {
}

object Versions {
val zio = "1.0.0-RC18"
val `grpc-netty` = "1.27.2"
val scalaPB = "0.10.1"
val zio = "1.0.0-RC18-2"
val `zio-nio` = "1.0.0-RC4"
val `zio-process` = "0.0.1"
val `zio-config` = "1.0.0-RC12"
val `case-app` = "2.0.0-M13"
val `zio-grpc` = "0.1.0+4-629d4bbe-SNAPSHOT"
val `protoc-gen-zio` = "protoc-gen-zio"
val refined = "0.9.13"
val scallop = "3.4.0"
}

def generateBuildInfoFile(
productVersion: String = productVersion
)(implicit ctx: mill.api.Ctx.Dest, ctxLog: mill.api.Ctx.Log) = {
val filename = "BuildInfo.scala"
val content = s"""
package morphir
object BuildInfo {
val appName = "morphir"
val productVersion = "$productVersion"
}
"""
ctxLog.log.info(s"Writing $filename")
write(ctx.dest / filename, content)
ctx.dest / filename
}
21 changes: 0 additions & 21 deletions core/src/com/morganstanley/morphir/ir/advanced/Type.scala

This file was deleted.

39 changes: 0 additions & 39 deletions core/src/com/morganstanley/morphir/ir/advanced/Value.scala

This file was deleted.

Loading

0 comments on commit fe856f2

Please sign in to comment.