Skip to content

Commit

Permalink
Merge pull request #27 from Romastyi/issue-23.3
Browse files Browse the repository at this point in the history
#23 Etlas Configuration
  • Loading branch information
rahulmutt authored Apr 24, 2019
2 parents 1ac1a7f + 289a90e commit 1f8cb3f
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 114 deletions.
8 changes: 5 additions & 3 deletions example/build.sbt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
lazy val root = (project in file(".")).
settings(
inThisBuild(Seq(
scalaVersion := "2.12.8",
version := "0.1.0-SNAPSHOT"
etaVersion := "0.8.6b4",
etlasUseLocal := false,
etlasVersion := "1.5.0.0",
scalaVersion := "2.12.8",
version := "0.1.0-SNAPSHOT"
)),
name := "example",
etaVersion := "0.8.6b5",
exposedModules in EtaLib += "Example.Transform",
libraryDependencies in EtaLib ++= Seq(
eta("aeson"),
Expand Down
161 changes: 101 additions & 60 deletions src/main/scala/com/typelead/Etlas.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,65 +6,109 @@ import java.lang.{ProcessBuilder => JProcessBuilder}
import EtaDependency.EtaVersion
import sbt.Keys._
import sbt._
import sbt.io.Using

import scala.collection.mutable.ArrayBuffer
import scala.sys.process.{Process, ProcessLogger}
import scala.util.Try
import scala.util.{Properties, Try}

final case class Etlas(cwd: File, dist: File, etaVersion: EtaVersion) {
final case class Etlas(installPath: Option[File], workDir: File, dist: File, etaVersion: EtaVersion, sendMetrics: Boolean) {

import Etlas._

def changeWorkDir(workDir: File): Etlas = this.copy(workDir = workDir)

private def args(xs: String*): Seq[String] = {
xs.toIndexedSeq.withBuildDir(dist).withEtaVersion(etaVersion).addSendMetrics(sendMetrics)
}

def build(cabal: Cabal, log: Logger): Unit = {
etlas(Seq("build").withBuildDir(dist).withEtaVersion(etaVersion), cwd, log, filterLog = _ => true)
etlas(installPath, args("build"), workDir, log, filterLog = _ => true)
()
}

def buildArtifacts(cabal: Cabal, log: Logger, filter: Cabal.Artifact.Filter): Unit = {
cabal.getArtifacts(filter).foreach {
artifact => etlas(Seq("build", artifact.depsPackage).withBuildDir(dist).withEtaVersion(etaVersion), cwd, log, filterLog = _ => true)
artifact => etlas(installPath, args("build", artifact.depsPackage), workDir, log, filterLog = _ => true)
}
}

def clean(log: Logger): Unit = {
etlas(Seq("clean").withBuildDir(dist).withEtaVersion(etaVersion), cwd, log)
etlas(installPath, args("clean"), workDir, log)
()
}

def deps(cabal: Cabal, log: Logger, filter: Cabal.Artifact.Filter): Seq[String] = {
def filterDepsLog(s: String): Boolean = defaultFilterLog(s) || !(s.startsWith("dependency") || s.startsWith("maven-dependencies"))
cabal.getArtifacts(filter).flatMap { artifact =>
etlas(Seq("deps", artifact.depsPackage, "--keep-going").withBuildDir(dist).withEtaVersion(etaVersion), cwd, log, saveOutput = true, filterLog = filterDepsLog)
etlas(installPath, args("deps", artifact.depsPackage, "--keep-going"), workDir, log, saveOutput = true, filterLog = filterDepsLog)
}
}

def install(log: Logger): Unit = {
log.info("Installing dependencies...")
etlas(Seq("install", "--dependencies-only"), cwd, log)
etlas(installPath, args("install", "--dependencies-only"), workDir, log)
}

def freeze(log: Logger): Unit = {
etlas(Seq("freeze"), cwd, log)
etlas(installPath, args("freeze"), workDir, log)
}

def run(log: Logger): Unit = {
etlas(Seq("run").withBuildDir(dist).withEtaVersion(etaVersion), cwd, log)
etlas(installPath, args("run"), workDir, log)
()
}

def runArtifacts(cabal: Cabal, log: Logger, filter: Cabal.Artifact.Filter): Unit = {
cabal.getArtifacts(Cabal.Artifact.and(Cabal.Artifact.executable, filter)).foreach { artifact =>
etlas(Seq("run", artifact.name).withBuildDir(dist).withEtaVersion(etaVersion), cwd, log, filterLog = _ => true)
etlas(installPath, args("run", artifact.name), workDir, log, filterLog = _ => true)
}
}

def test(log: Logger): Unit = {
etlas(Seq("test").withBuildDir(dist).withEtaVersion(etaVersion), cwd, log, filterLog = _ => true)
etlas(installPath, args("test"), workDir, log, filterLog = _ => true)
}

def testArtifacts(cabal: Cabal, log: Logger, filter: Cabal.Artifact.Filter): Unit = {
cabal.getArtifacts(Cabal.Artifact.and(Cabal.Artifact.testSuite, filter)).foreach { artifact =>
etlas(Seq("test", artifact.name).withBuildDir(dist).withEtaVersion(etaVersion), cwd, log, filterLog = _ => true)
etlas(installPath, args("test", artifact.name), workDir, log, filterLog = _ => true)
}
}

def init(name: String,
description: String,
version: String,
developers: Seq[Developer],
homepage: Option[URL],
sourceDir: File,
log: Logger): Unit = {
log.info("Initialize project...")
etlas(installPath, Seq(
"init",
"--non-interactive",
"--is-executable",
s"--package-dir=${workDir.getCanonicalPath}",
s"--package-name=$name-eta",
s"--synopsis=$description",
s"--version=$version",
s"--source-dir=${IO.relativize(workDir, sourceDir).getOrElse(sourceDir.getCanonicalPath)}",
"--language=Haskell2010"
) ++ developers.headOption.toList.flatMap(
dev => Seq(s"--author=${dev.name}", s"--email=${dev.email}")
) ++ homepage.map(
url => s"--homepage=$url"
), workDir, log)
}

def repl(log: sbt.Logger): Try[Unit] = {
def console0(): Unit = {
log.info("Starting Eta interpreter...")
fork(installPath, args("repl"), workDir, log)
}
Run.executeTrapExit(console0(), log).recover {
case _: InterruptedException =>
log.info("Eta REPL was interrupted.")
()
}
}

Expand All @@ -85,7 +129,6 @@ final case class Etlas(cwd: File, dist: File, etaVersion: EtaVersion) {

def getEtaPackage(cabal: Cabal, log: Logger): Cabal.EtaPackage = {
log.info("Resolve package dependencies...")
buildArtifacts(cabal, log, Cabal.Artifact.library)
Cabal.EtaPackage(cabal.projectName, cabal.getArtifactsJars(dist, etaVersion, Cabal.Artifact.library), getPackageDd(dist, etaVersion))
}

Expand All @@ -111,8 +154,13 @@ object Etlas {
}
}

private def etlas(args: Seq[String],
cwd: File,
private def getEtlasBinary(installPath: Option[File]): String = {
installPath.map(_.getCanonicalPath).getOrElse("etlas")
}

private def etlas(installPath: Option[File],
args: Seq[String],
workDir: File,
log: Logger,
saveOutput: Boolean = false,
filterLog: String => Boolean = defaultFilterLog): Seq[String] = {
Expand All @@ -131,9 +179,10 @@ object Etlas {
override def buffer[T](s: => T): T = s
}

IO.createDirectory(cwd)
logCmd(s"Running `etlas ${args.mkString(" ")} in '$cwd'`...")(log)
val exitCode = synchronized(Process("etlas" +: args, cwd) ! logger)
IO.createDirectory(workDir)
val binary = getEtlasBinary(installPath)
logCmd(s"Running `$binary ${args.mkString(" ")} in '$workDir'`...")(log)
val exitCode = synchronized(Process(binary +: args, workDir) ! logger)

if (exitCode != 0) {
sys.error("\n\n[etlas] Exit Failure " ++ exitCode.toString)
Expand All @@ -143,12 +192,12 @@ object Etlas {

}

private def fork(args: Seq[String], cwd: File, log: sbt.Logger): Unit = {
private def fork(installPath: Option[File], args: Seq[String], workDir: File, log: sbt.Logger): Unit = {

logCmd(s"Running `etlas ${args.mkString(" ")} in '$cwd'`...")(Logger(log))

val jpb = new JProcessBuilder(("etlas" +: args).toArray: _ *)
jpb.directory(cwd)
val binary = getEtlasBinary(installPath)
logCmd(s"Running `$binary ${args.mkString(" ")} in '$workDir'`...")(Logger(log))
val jpb = new JProcessBuilder((binary +: args).toArray: _ *)
jpb.directory(workDir)
jpb.redirectInput(Redirect.INHERIT)
val exitCode = Process(jpb).run(SbtUtils.terminalIO).exitValue()

Expand All @@ -161,51 +210,43 @@ object Etlas {
private implicit class ArgsOps(val args: Seq[String]) extends AnyVal {
def withBuildDir(dist: File): Seq[String] = args ++ Seq("--builddir", dist.getCanonicalPath)
def withEtaVersion(etaVersion: EtaVersion): Seq[String] = s"--select-eta=${etaVersion.friendlyVersion}" +: args
def addSendMetrics(flag: Boolean): Seq[String] = (if (flag) "--enable-send-metrics" else "--disable-send-metrics") +: args
}

def etaVersion(cwd: File, log: Logger): EtaVersion = {
EtaVersion(etlas(Seq("exec", "eta", "--", "--numeric-version"), cwd, log, saveOutput = true).head)
def etaVersion(installPath: Option[File], workDir: File, log: Logger): EtaVersion = {
EtaVersion(etlas(installPath, Seq("exec", "eta", "--", "--numeric-version"), workDir, log, saveOutput = true).head)
}

def etlasVersion(cwd: File, log: Logger): String = {
etlas(Seq("--numeric-version"), cwd, log, saveOutput = true).head
def etlasVersion(installPath: Option[File], workDir: File, log: Logger): String = {
etlas(None, Seq("--numeric-version"), workDir, log, saveOutput = true).head
}

def init(cwd: File,
name: String,
description: String,
version: String,
developers: Seq[Developer],
homepage: Option[URL],
sourceDir: File,
log: Logger): Unit = {
log.info("Initialize project...")
etlas(Seq(
"init",
"--non-interactive",
"--is-executable",
s"--package-dir=${cwd.getCanonicalPath}",
s"--package-name=$name-eta",
s"--synopsis=$description",
s"--version=$version",
s"--source-dir=${IO.relativize(cwd, sourceDir).getOrElse(sourceDir.getCanonicalPath)}",
"--language=Haskell2010"
) ++ developers.headOption.toList.flatMap(
dev => Seq(s"--author=${dev.name}", s"--email=${dev.email}")
) ++ homepage.map(
url => s"--homepage=$url"
), cwd, log)
}
private[typelead] val DEFAULT_ETLAS_REPO = "http://cdnverify.eta-lang.org/eta-binaries"

def repl(cwd: File, dist: File, etaVersion: EtaVersion, log: sbt.Logger): Try[Unit] = {
def console0(): Unit = {
log.info("Starting Eta interpreter...")
fork(Seq("repl").withBuildDir(dist).withEtaVersion(etaVersion), cwd, log)
def download(repo: String, dest: File, version: String, log: Logger): Unit = {
val (arch, ext) = if (Properties.isWin)
("x86_64-windows", ".exe")
else if (Properties.isMac)
("x86_64-osx", "")
else
("x86_64-linux", "")
val binary = "etlas" + ext
if (dest.exists()) {
()
} else {
val url = new URL(repo + "/etlas-" + version + "/binaries/" + arch + "/" + binary)
log.info(s"Downloading Etlas binary from '$url' to '${dest.getCanonicalPath}' ...")
IO.createDirectory(dest.getParentFile)
Using.urlInputStream(url) { input =>
IO.transfer(input, dest)
}
}
Run.executeTrapExit(console0(), log).recover {
case _: InterruptedException =>
log.info("Eta REPL was interrupted.")
()
if (dest.setExecutable(true)) {
val version = etlas(Some(dest), Seq("--version"), dest.getParentFile, log, saveOutput = true).head
if (version.toLowerCase.contains("etlas")) ()
else sys.error(s"Executable '${dest.getCanonicalPath}' is not Etlas binary.")
} else {
sys.error("Could not set permissions for Eltas binary.")
}
}

Expand Down
Loading

0 comments on commit 1f8cb3f

Please sign in to comment.