Add ExecutionOptionsManager

Taken from https://github.com/ucb-bar/firrtl
This commit is contained in:
Chick Markley
2016-10-24 21:00:14 -07:00
committed by Jack
parent 52e8b6b04a
commit a1c7742a57
5 changed files with 190 additions and 0 deletions

16
build.sbt Normal file
View File

@@ -0,0 +1,16 @@
// See LICENSE for license details.
import Dependencies._
lazy val commonSettings = Seq(
organization := "edu.berkeley.cs",
version := "0.1-SNAPSHOT",
scalaVersion := "2.11.8",
libraryDependencies ++= commonDependencies
)
lazy val executionoptions = (project in file("executionoptions"))
.settings(commonSettings)
.settings(
libraryDependencies ++= executionoptionsDependencies
)

View File

@@ -0,0 +1,126 @@
// See LICENSE for license details.
package bar.executionoptions
import scopt.OptionParser
/**
* Use this trait to define an options class that can add its private command line options to a externally
* declared parser
*/
trait ComposableOptions
/**
* Most of the chisel toolchain components require a topName which defines a circuit or a device under test.
* Much of the work that is done takes place in a directory.
* It would be simplest to require topName to be defined but in practice it is preferred to defer this.
* For example, in chisel, by deferring this it is possible for the execute there to first elaborate the
* circuit and then set the topName from that if it has not already been set.
*/
case class CommonOptions(topName: String = "", targetDirName: String = "test_run_dir") extends ComposableOptions
abstract class HasParser(applicationName: String) {
final val parser: OptionParser[Unit] = new OptionParser[Unit](applicationName) {}
}
trait HasCommonOptions {
self: ExecutionOptionsManager =>
var commonOptions = CommonOptions()
parser.note("common options")
parser.opt[String]("top-name")
.abbr("tn")
.valueName("<top-level-circuit-name>")
.foreach { x =>
commonOptions = commonOptions.copy(topName = x)
}
.text("This options defines the top level circuit, defaults to dut when possible")
parser.opt[String]("target-dir")
.abbr("td").valueName("<target-directory>")
.foreach { x =>
commonOptions = commonOptions.copy(targetDirName = x)
}
.text(s"This options defines a work directory for intermediate files, default is ${commonOptions.targetDirName}")
parser.help("help").text("prints this usage text")
}
/**
*
* @param applicationName The name shown in the usage
*/
class ExecutionOptionsManager(val applicationName: String) extends HasParser(applicationName) with HasCommonOptions {
def parse(args: Array[String]): Boolean = {
parser.parse(args)
}
def showUsageAsError(): Unit = parser.showUsageAsError()
/**
* make sure that all levels of targetDirName exist
*
* @return true if directory exists
*/
def makeTargetDir(): Boolean = {
(new java.io.File(commonOptions.targetDirName)).mkdirs()
}
def targetDirName: String = commonOptions.targetDirName
/**
* this function sets the topName in the commonOptions.
* It would be nicer to not need this but many chisel tools cannot determine
* the name of the device under test until other options have been parsed.
* Havin this function allows the code to set the TopName after it has been
* determined
*
* @param newTopName the topName to be used
*/
def setTopName(newTopName: String): Unit = {
commonOptions = commonOptions.copy(topName = newTopName)
}
def setTopNameIfNotSet(newTopName: String): Unit = {
if(commonOptions.topName.isEmpty) {
setTopName(newTopName)
}
}
def topName: String = commonOptions.topName
def setTargetDirName(newTargetDirName: String): Unit = {
commonOptions = commonOptions.copy(targetDirName = newTargetDirName)
}
/**
* return a file based on targetDir, topName and suffix
* Will not add the suffix if the topName already ends with that suffix
*
* @param suffix suffix to add, removes . if present
* @param fileNameOverride this will override the topName if nonEmpty, when using this targetDir is ignored
* @return
*/
def getBuildFileName(suffix: String, fileNameOverride: String = ""): String = {
makeTargetDir()
val baseName = if(fileNameOverride.nonEmpty) fileNameOverride else topName
val directoryName = {
if(fileNameOverride.nonEmpty) {
""
}
else if(baseName.startsWith("./") || baseName.startsWith("/")) {
""
}
else {
if(targetDirName.endsWith("/")) targetDirName else targetDirName + "/"
}
}
val normalizedSuffix = {
val dottedSuffix = if(suffix.startsWith(".")) suffix else s".$suffix"
if(baseName.endsWith(dottedSuffix)) "" else dottedSuffix
}
s"$directoryName$baseName$normalizedSuffix"
}
}

View File

@@ -0,0 +1,31 @@
// See LICENSE for license details.
package bar.executionoptions
import org.scalatest.{Matchers, FreeSpec}
class ExecutionOptionsManagerSpec extends FreeSpec with Matchers {
"ExecutionOptionsManager is a container for one more more ComposableOptions Block" - {
"It has a default CommonOptionsBlock" in {
val manager = new ExecutionOptionsManager("test")
manager.commonOptions.targetDirName should be ("test_run_dir")
}
"But can override defaults like this" in {
val manager = new ExecutionOptionsManager("test") { commonOptions = CommonOptions(topName = "dog") }
manager.commonOptions shouldBe a [CommonOptions]
manager.topName should be ("dog")
manager.commonOptions.topName should be ("dog")
}
"The add method should put a new version of a given type the manager" in {
val manager = new ExecutionOptionsManager("test") { commonOptions = CommonOptions(topName = "dog") }
val initialCommon = manager.commonOptions
initialCommon.topName should be ("dog")
manager.commonOptions = CommonOptions(topName = "cat")
val afterCommon = manager.commonOptions
afterCommon.topName should be ("cat")
initialCommon.topName should be ("dog")
}
}
}

1
project/build.properties Normal file
View File

@@ -0,0 +1 @@
sbt.version=0.13.12

View File

@@ -0,0 +1,16 @@
import sbt._
import Keys._
object Dependencies {
val scalatestVersion = "3.0.0"
val scalatest = "org.scalatest" %% "scalatest" % scalatestVersion % "test"
val scoptVersion = "3.4.0"
val scopt = "com.github.scopt" %% "scopt" % scoptVersion
val commonDependencies: Seq[ModuleID] = Seq(
scalatest
)
val executionoptionsDependencies: Seq[ModuleID] = Seq(
scopt
)
}