Adding in/out file validation
This commit is contained in:
@@ -11,5 +11,7 @@ lazy val root = project
|
|||||||
|
|
||||||
libraryDependencies += "org.rogach" %% "scallop" % "5.2.0",
|
libraryDependencies += "org.rogach" %% "scallop" % "5.2.0",
|
||||||
libraryDependencies += "com.lihaoyi" %% "os-lib" % "0.11.5",
|
libraryDependencies += "com.lihaoyi" %% "os-lib" % "0.11.5",
|
||||||
|
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.6",
|
||||||
|
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.5.19",
|
||||||
libraryDependencies += "org.scalameta" %% "munit" % "1.2.0" % Test
|
libraryDependencies += "org.scalameta" %% "munit" % "1.2.0" % Test
|
||||||
)
|
)
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package com.minres.tgc.hammer
|
package com.minres.tgc.hammer
|
||||||
|
|
||||||
import org.rogach.scallop.{ValueConverter, listArgConverter, singleArgConverter}
|
import org.rogach.scallop.{ScallopOption, Util, ValueConverter, listArgConverter, singleArgConverter}
|
||||||
import os.*
|
import os.*
|
||||||
import Global.*
|
import Global.*
|
||||||
|
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
package com.minres.tgc.hammer
|
package com.minres.tgc.hammer
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level
|
||||||
import com.minres.tgc.hammer.cli.{HammerConf, MySubcommand}
|
import com.minres.tgc.hammer.cli.{HammerConf, MySubcommand}
|
||||||
|
import com.typesafe.scalalogging.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
import scala.compiletime.uninitialized
|
import scala.compiletime.uninitialized
|
||||||
|
|
||||||
@@ -8,8 +11,19 @@ object Main {
|
|||||||
var conf: HammerConf = uninitialized
|
var conf: HammerConf = uninitialized
|
||||||
|
|
||||||
def main(args: Array[String]): Unit = {
|
def main(args: Array[String]): Unit = {
|
||||||
|
var logger = Logger("TGCHammer")
|
||||||
conf = new HammerConf(args.toIndexedSeq)
|
conf = new HammerConf(args.toIndexedSeq)
|
||||||
|
|
||||||
|
val logLevel = conf.verbose() match {
|
||||||
|
case 0 => Level.WARN
|
||||||
|
case 1 => Level.INFO
|
||||||
|
case 2 => Level.DEBUG
|
||||||
|
case _ => Level.TRACE
|
||||||
|
}
|
||||||
|
LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME).asInstanceOf[ch.qos.logback.classic.Logger].setLevel(logLevel)
|
||||||
|
|
||||||
|
os.makeDir(Global.OUT_DIR)
|
||||||
|
os.makeDir(Global.TMP_DIR)
|
||||||
conf.subcommand match {
|
conf.subcommand match {
|
||||||
case Some(c: MySubcommand) =>
|
case Some(c: MySubcommand) =>
|
||||||
val tasks = c.getRequiredTasks
|
val tasks = c.getRequiredTasks
|
||||||
|
@@ -6,9 +6,12 @@ import com.minres.tgc.hammer.FileUtils.*
|
|||||||
|
|
||||||
class HammerConf(arguments: Seq[String]) extends ScallopConf(arguments) {
|
class HammerConf(arguments: Seq[String]) extends ScallopConf(arguments) {
|
||||||
val outputDirectory: ScallopOption[Path] = opt[Path](default = Some("output".path()), descr = "The base output directory")
|
val outputDirectory: ScallopOption[Path] = opt[Path](default = Some("output".path()), descr = "The base output directory")
|
||||||
|
val verbose: ScallopOption[Int] = tally()
|
||||||
addSubcommand(new LongnailCommand)
|
addSubcommand(new LongnailCommand)
|
||||||
addSubcommand(new TreenailCommand)
|
addSubcommand(new TreenailCommand)
|
||||||
addSubcommand(new LongnailSchedCommand)
|
addSubcommand(new LongnailSchedCommand)
|
||||||
|
|
||||||
|
requireSubcommand()
|
||||||
|
|
||||||
verify()
|
verify()
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,10 @@ import com.minres.tgc.hammer.tasks.longnail.LongnailMergeTask
|
|||||||
class LongnailMergeCommand extends MySubcommand("mergeISAX") {
|
class LongnailMergeCommand extends MySubcommand("mergeISAX") {
|
||||||
val inputFiles: ScallopOption[List[Path]] = trailArg[List[Path]]("inputFiles", group = mainGroup, descr = "One or multiple input files; Both .core_desc as well as .mlir are supported (also mixed)")
|
val inputFiles: ScallopOption[List[Path]] = trailArg[List[Path]]("inputFiles", group = mainGroup, descr = "One or multiple input files; Both .core_desc as well as .mlir are supported (also mixed)")
|
||||||
val output: ScallopOption[Path] = opt[Path](short = 'o', default = Some("merged.mlir".path()), descr = "The .mlir file containing the merged ISAXes")
|
val output: ScallopOption[Path] = opt[Path](short = 'o', default = Some("merged.mlir".path()), descr = "The .mlir file containing the merged ISAXes")
|
||||||
|
val overwrite: ScallopOption[Boolean] = toggle()
|
||||||
|
|
||||||
|
check(inputFiles)(checkPathsIsFile)
|
||||||
|
checkNotIf(overwrite)(output)(checkPathDoesNotExist)
|
||||||
|
|
||||||
override def getRequiredTasks: Seq[Task] = {
|
override def getRequiredTasks: Seq[Task] = {
|
||||||
val (coreDSLFiles, mlirFiles) = inputFiles().partition(_.ext == "core_desc")
|
val (coreDSLFiles, mlirFiles) = inputFiles().partition(_.ext == "core_desc")
|
||||||
|
@@ -4,7 +4,7 @@ import com.minres.tgc.hammer.options.ConfigElement
|
|||||||
import com.minres.tgc.hammer.tasks.Task
|
import com.minres.tgc.hammer.tasks.Task
|
||||||
import org.rogach.scallop.{ScallopOption, ScallopOptionGroup, Subcommand, Util}
|
import org.rogach.scallop.{ScallopOption, ScallopOptionGroup, Subcommand, Util}
|
||||||
|
|
||||||
import java.nio.file.Files
|
type Checker[T] = ScallopOption[T] => Either[String,Unit]
|
||||||
|
|
||||||
abstract class MySubcommand(name: String) extends Subcommand(name) {
|
abstract class MySubcommand(name: String) extends Subcommand(name) {
|
||||||
protected val mainGroup: ScallopOptionGroup = group()
|
protected val mainGroup: ScallopOptionGroup = group()
|
||||||
@@ -16,12 +16,42 @@ abstract class MySubcommand(name: String) extends Subcommand(name) {
|
|||||||
elem
|
elem
|
||||||
}
|
}
|
||||||
|
|
||||||
def validateOSPathIsDirectory(pathOption: ScallopOption[os.Path]): Unit = addValidation {
|
def checkPred[T](option: ScallopOption[T], predicate: T => Boolean, format: String): Either[String,Unit] = {
|
||||||
pathOption.toOption
|
option.toOption.map {
|
||||||
.map {
|
case o if predicate(o) => (Right(()))
|
||||||
case path if Files.isDirectory(path.toNIO) => Right(())
|
case o => Left(Util.format(format, o))
|
||||||
case path => Left(Util.format("File '%s' is not a directory", path))
|
}.getOrElse(Right(()))
|
||||||
}
|
}
|
||||||
.getOrElse(Right(()))
|
|
||||||
|
def checkPredIt[T, CC <: Iterable](option: ScallopOption[CC[T]], predicate: T => Boolean, format: String): Either[String,Unit] = {
|
||||||
|
option.toOption.map(options => {
|
||||||
|
val problems = options.filterNot(predicate)
|
||||||
|
problems match {
|
||||||
|
case Nil => Right(())
|
||||||
|
case problem :: Nil => Left(Util.format(format, problem))
|
||||||
|
case _ => Left(s"Multiple: ${Util.format(format, problems.mkString(", "))}")
|
||||||
|
}
|
||||||
|
}).getOrElse(Right(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
def checkPathExists: Checker[os.Path] = path => checkPred(path, os.exists, "File '%s' does not exist")
|
||||||
|
def checkPathDoesNotExist: Checker[os.Path] = path => checkPred(path, !os.exists(_), "File '%s' already exists")
|
||||||
|
def checkPathIsFile: Checker[os.Path] = path => checkPred(path, os.isFile, "File '%s' is not a file")
|
||||||
|
def checkPathIsDir: Checker[os.Path] = path => checkPred(path, os.isDir, "File '%s' is not a directory")
|
||||||
|
|
||||||
|
|
||||||
|
def checkPathsExists: Checker[List[os.Path]] = path => checkPredIt(path, os.exists, "File(s) '%s' do not exist")
|
||||||
|
def checkPathsDoesNotExists: Checker[List[os.Path]] = path => checkPredIt(path, !os.exists(_), "File(s) '%s' already exist")
|
||||||
|
def checkPathsIsFile: Checker[List[os.Path]] = path => checkPredIt(path, os.isFile, "File(s) '%s' are not files")
|
||||||
|
def checkPathsIsDir: Checker[List[os.Path]] = path => checkPredIt(path, os.isDir, "File(s) '%s' are not directories")
|
||||||
|
|
||||||
|
def check[T](option: ScallopOption[T])(check: Checker[T]): Unit = addValidation(check(option))
|
||||||
|
def checkPred[T, U](condOpt: ScallopOption[U], cond: U => Boolean)(option: ScallopOption[T])(check: Checker[T]): Unit = addValidation {
|
||||||
|
condOpt.toOption match {
|
||||||
|
case Some(value) if cond(value) => check(option)
|
||||||
|
case _ => Right(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
def checkIf[T](condOpt: ScallopOption[Boolean])(option: ScallopOption[T])(check: Checker[T]): Unit = checkPred(condOpt, identity)(option)(check)
|
||||||
|
def checkNotIf[T](condOpt: ScallopOption[Boolean])(option: ScallopOption[T])(check: Checker[T]): Unit = checkPred(condOpt, !_)(option)(check)
|
||||||
|
}
|
||||||
|
@@ -8,6 +8,10 @@ import os.Path
|
|||||||
class TreenailCommand extends MySubcommand("parseCoreDSL") {
|
class TreenailCommand extends MySubcommand("parseCoreDSL") {
|
||||||
val coreDSL: ScallopOption[Path] = trailArg[Path]("coreDSL", descr = "The .core_desc input file to be converted")
|
val coreDSL: ScallopOption[Path] = trailArg[Path]("coreDSL", descr = "The .core_desc input file to be converted")
|
||||||
val output: ScallopOption[Path] = opt[Path](short = 'o', default = Some("isax.mlir".path()), descr = "The .mlir file containing the converted ISAX")
|
val output: ScallopOption[Path] = opt[Path](short = 'o', default = Some("isax.mlir".path()), descr = "The .mlir file containing the converted ISAX")
|
||||||
|
val overwrite: ScallopOption[Boolean] = toggle()
|
||||||
|
|
||||||
|
check(coreDSL)(checkPathIsFile)
|
||||||
|
checkNotIf(overwrite)(output)(checkPathDoesNotExist)
|
||||||
|
|
||||||
banner(
|
banner(
|
||||||
"""Parse a CoreDSL input using Treenail into the MLIR representation
|
"""Parse a CoreDSL input using Treenail into the MLIR representation
|
||||||
|
Reference in New Issue
Block a user