Skip to content

Commit

Permalink
Merge pull request #23 from scalacenter/topic/add-case-app
Browse files Browse the repository at this point in the history
Add reproduced version of case-app inefficiency
  • Loading branch information
jvican authored May 31, 2018
2 parents 853a159 + 383a60d commit 5ee6ec9
Show file tree
Hide file tree
Showing 9 changed files with 368 additions and 13 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ lazy val integrations = project
.in(file("integrations"))
.dependsOn(Circe)
.settings(
libraryDependencies += "com.github.alexarchambault" %% "case-app" % "1.2.0",
scalaHome := BuildDefaults.setUpScalaHome.value,
parallelExecution in Test := false,
scalacOptions in Compile := (Def.taskDyn {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package profiling.integrations

import java.nio.file.Path

import caseapp.{ExtraName, HelpMessage, Recurse, ValueDescription}

case class CliOptions(
@ExtraName("c")
@HelpMessage("File path to the bloop config directory.")
@ValueDescription(".bloop")
configDir: Option[Path] = None,
@ExtraName("v")
@HelpMessage("If set, print the about section at the beginning of the execution.")
version: Boolean = false,
@HelpMessage("If set, print out debugging information to stderr.")
verbose: Boolean = false,
@Recurse common: CommonOptions = CommonOptions.default,
)

object CliOptions {
val default = CliOptions()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package profiling.integrations

import java.nio.file.Path

import caseapp.core.ArgParser
import caseapp.{ArgsName, CommandName, ExtraName, HelpMessage, Hidden, Recurse}
import caseapp.core.CommandMessages

object Commands {

/* sealed abstract class Mode(val name: String)
/** The kind of items that should be returned for autocompletion */
object Mode {
case object Commands extends Mode("commands")
case object Projects extends Mode("projects")
case object ProjectBoundCommands extends Mode("project-commands")
case object Flags extends Mode("flags")
case object Reporters extends Mode("reporters")
case object Protocols extends Mode("protocols")
case object TestsFQCN extends Mode("testsfqcn")
case object MainsFQCN extends Mode("mainsfqcn")
implicit val completionModeRead: ArgParser[Mode] = ???
}
sealed abstract class BspProtocol(val name: String)
object BspProtocol {
case object Local extends BspProtocol("local")
case object Tcp extends BspProtocol("tcp")
implicit val bspProtocolRead: ArgParser[BspProtocol] = ???
}
sealed abstract class ReporterKind(val name: String)
case object ScalacReporter extends ReporterKind("scalac")
case object BloopReporter extends ReporterKind("bloop")*/

sealed trait RawCommand {
def cliOptions: CliOptions
}

sealed trait CompilingCommand extends RawCommand {
//def project: String
//def reporter: ReporterKind
}

/* sealed trait Tree[A]
case class Leaf[A](value: A) extends Tree[A]
case class Branch[A](
left: Tree[A],
right: Tree[A]
) extends Tree[A]*/

case class Help(
@Recurse cliOptions: CliOptions = CliOptions.default
) extends RawCommand

case class Autocomplete(
@Recurse cliOptions: CliOptions = CliOptions.default,
//mode: Mode,
//format: Format,
/* command: Option[String],
project: Option[String]*/
) extends RawCommand

case class About(
@Recurse cliOptions: CliOptions = CliOptions.default
) extends RawCommand

case class Projects(
/* @ExtraName("dot")
@HelpMessage("Print out a dot graph you can pipe into `dot`. By default, false.")
dotGraph: Boolean = false,*/
@Recurse cliOptions: CliOptions = CliOptions.default
) extends RawCommand

case class Configure(
/* @ExtraName("parallelism")
@HelpMessage("Set the number of threads used for parallel compilation and test execution.")
threads: Int = 4,*/
@Recurse cliOptions: CliOptions = CliOptions.default
) extends RawCommand

case class Clean(
/* @ExtraName("p")
@HelpMessage("The projects to clean.")
project: List[String] = Nil,
@HelpMessage("Do not run clean for dependencies. By default, false.")
isolated: Boolean = false,*/
@Recurse cliOptions: CliOptions = CliOptions.default,
) extends RawCommand

@CommandName("bsp")
case class Bsp(
/*/* @ExtraName("p")
@HelpMessage("The connection protocol for the bsp server. By default, local.")
protocol: BspProtocol = BspProtocol.Local,*/
@ExtraName("h")
@HelpMessage("The server host for the bsp server (TCP only).")
host: String = "127.0.0.1",
@HelpMessage("The port for the bsp server (TCP only).")
port: Int = 5101,
@ExtraName("s")
@HelpMessage("A path to a socket file to communicate through Unix sockets (local only).")
socket: Option[Path] = None,
@ExtraName("pn")
@HelpMessage(
"A path to a new existing socket file to communicate through Unix sockets (local only)."
)
pipeName: Option[String] = None,*/
@Recurse cliOptions: CliOptions = CliOptions.default
) extends RawCommand

case class Compile(
/* @ExtraName("p")
@HelpMessage("The project to compile (will be inferred from remaining cli args).")
project: String = "",
@HelpMessage("Compile the project incrementally. By default, true.")
incremental: Boolean = true,
/* @HelpMessage("Pick reporter to show compilation messages. By default, bloop's used.")
reporter: ReporterKind = BloopReporter,*/
@ExtraName("w")
@HelpMessage("Run the command when projects' source files change. By default, false.")
watch: Boolean = false,*/
@Recurse cliOptions: CliOptions = CliOptions.default,
) extends CompilingCommand

case class Test(
/* @ExtraName("p")
@HelpMessage("The project to test (will be inferred from remaining cli args).")
project: String = "",
@HelpMessage("Do not run tests for dependencies. By default, false.")
isolated: Boolean = false,
@ExtraName("o")
@HelpMessage("The list of test suite filters to test for only.")
only: List[String] = Nil,
@HelpMessage("The arguments to pass in to the test framework.")
args: List[String] = Nil,
/* @HelpMessage("Pick reporter to show compilation messages. By default, bloop's used.")
reporter: ReporterKind = BloopReporter,*/
@ExtraName("w")
@HelpMessage("Run the command when projects' source files change. By default, false.")
watch: Boolean = false,*/
@Recurse cliOptions: CliOptions = CliOptions.default
) extends CompilingCommand

case class Console(
/* @ExtraName("p")
@HelpMessage("The project to run the console at (will be inferred from remaining cli args).")
project: String = "",
/* @HelpMessage("Pick reporter to show compilation messages. By default, bloop's used.")
reporter: ReporterKind = BloopReporter,*/
@HelpMessage("Start up the console compiling only the target project's dependencies.")
excludeRoot: Boolean = false,*/
@Recurse cliOptions: CliOptions = CliOptions.default
) extends CompilingCommand

case class Run(
/* @ExtraName("p")
@HelpMessage("The project to run (will be inferred from remaining cli args).")
project: String = "",
@ExtraName("m")
@HelpMessage("The main class to run. Leave unset to let bloop select automatically.")
main: Option[String] = None,
/* @HelpMessage("Pick reporter to show compilation messages. By default, bloop's used.")
reporter: ReporterKind = BloopReporter,*/
@HelpMessage("The arguments to pass in to the main class.")
args: List[String] = Nil,
@ExtraName("w")
@HelpMessage("If set, run the command whenever projects' source files change.")
watch: Boolean = false,*/
@Recurse cliOptions: CliOptions = CliOptions.default
) extends CompilingCommand
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package profiling.integrations

import java.io.{InputStream, PrintStream}
import java.util.Properties

import caseapp.Hidden

/**
* Describes the common options for any command or CLI operation.
*
* They exist for two purposes: testing and nailgun. In both cases we
* need a precise handling of these parameters because they change
* depending on the environment we're running on.
*
* They are hidden because they are optional.
*/
case class CommonOptions(
@Hidden workingDirectory: String = System.getProperty("user.dir"),
@Hidden out: PrintStream = System.out,
@Hidden in: InputStream = System.in,
@Hidden err: PrintStream = System.err,
@Hidden ngout: PrintStream = System.out,
@Hidden ngerr: PrintStream = System.err
)

object CommonOptions {
final val default = CommonOptions()

// Our own version of properties in which we override `toString`
final class PrettyProperties extends Properties {
override def toString: String = synchronized {
super.keySet().toArray.map(_.toString).mkString(", ")
}
}

object PrettyProperties {
def from(p: Properties): PrettyProperties = {
val pp = new PrettyProperties()
pp.putAll(p)
pp
}
}

final lazy val currentEnv: PrettyProperties = {
import scala.collection.JavaConverters._
System.getenv().asScala.foldLeft(new PrettyProperties()) {
case (props, (key, value)) => props.setProperty(key, value); props
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package profiling.integrations

import java.io.{InputStream, PrintStream}
import java.nio.file.{Path, Paths}

import CommonOptions.PrettyProperties
import caseapp.{CaseApp, CommandParser}
import caseapp.util.{Implicit, AnnotationList}
import caseapp.core.{ArgParser, DefaultBaseCommand, HListParser, Parser, Default}
import shapeless.{Annotations, Coproduct, LabelledGeneric, Strict, Generic, HList}
import caseapp.{Name, ValueDescription, HelpMessage, Hidden, Recurse}

import scala.util.Try

trait CachedImplicits {
implicit val inputStreamRead: ArgParser[InputStream] =
ArgParser.instance[InputStream]("stdin")(_ => Right(System.in))
implicit val printStreamRead: ArgParser[PrintStream] =
ArgParser.instance[PrintStream]("stdout")(_ => Right(System.out))

implicit val pathParser: ArgParser[Path] = ArgParser.instance("A filepath parser") {
case supposedPath: String =>
val toPath = Try(Paths.get(supposedPath)).toEither
toPath.left.map(t => s"The provided path ${supposedPath} is not valid: '${t.getMessage()}'.")
}

implicit val propertiesParser: ArgParser[PrettyProperties] = {
ArgParser.instance("A properties parser") {
case whatever => Left("You cannot pass in properties through the command line.")
}
}

import shapeless.{HNil, CNil, :+:, ::}
implicit val implicitHNil: Implicit[HNil] = Implicit.hnil
implicit val implicitNone: Implicit[None.type] = Implicit.instance(None)
implicit val implicitNoneCnil: Implicit[None.type :+: CNil] =
Implicit.instance(Coproduct(None))

implicit val implicitOptionDefaultString: Implicit[Option[Default[String]]] =
Implicit.instance(Some(caseapp.core.Defaults.string))

implicit val implicitOptionDefaultInt: Implicit[Option[Default[Int]]] =
Implicit.instance(Some(caseapp.core.Defaults.int))

implicit val implicitOptionDefaultBoolean: Implicit[Option[Default[Boolean]]] =
Implicit.instance(Some(caseapp.core.Defaults.boolean))

implicit val implicitDefaultBoolean: Implicit[Default[Boolean]] =
Implicit.instance(caseapp.core.Defaults.boolean)

implicit val implicitOptionDefaultOptionPath: Implicit[Option[Default[Option[Path]]]] =
Implicit.instance(None)

implicit val implicitOptionDefaultPrintStream: Implicit[Option[Default[PrintStream]]] =
Implicit.instance(Some(Default.instance[PrintStream](System.out)))

implicit val implicitOptionDefaultInputStream: Implicit[Option[Default[InputStream]]] =
Implicit.instance(Some(Default.instance[InputStream](System.in)))
}

object Parsers extends CachedImplicits {

import shapeless.{the, HNil, ::}

implicit val labelledGenericCommonOptions: LabelledGeneric.Aux[CommonOptions, _] = LabelledGeneric.materializeProduct
implicit val commonOptionsParser: Parser.Aux[CommonOptions, _] = Parser.generic
implicit val labelledGenericCliOptions: LabelledGeneric.Aux[CliOptions, _] = LabelledGeneric.materializeProduct
implicit val cliOptionsParser: Parser.Aux[CliOptions, _] = Parser.generic

implicit val strictAutocompleteParser: Parser.Aux[Commands.Autocomplete, _] = Parser.generic
implicit val strictAboutParser: Parser.Aux[Commands.About, _] = Parser.generic
implicit val strictBspParser: Parser.Aux[Commands.Bsp, _] = Parser.generic
implicit val strictCleanParser: Parser.Aux[Commands.Clean, _] = Parser.generic
implicit val strictCompileParser: Parser.Aux[Commands.Compile, _] = Parser.generic
implicit val strictConfigureParser: Parser.Aux[Commands.Configure, _] = Parser.generic
implicit val strictConsoleParser: Parser.Aux[Commands.Console, _] = Parser.generic
implicit val strictHelpParser: Parser.Aux[Commands.Help, _] = Parser.generic
implicit val strictProjectsParser: Parser.Aux[Commands.Projects, _] = Parser.generic
implicit val strictRunParser: Parser.Aux[Commands.Run, _] = Parser.generic
implicit val strictTestParser: Parser.Aux[Commands.Test, _] = Parser.generic

val BaseMessages: caseapp.core.Messages[DefaultBaseCommand] =
caseapp.core.Messages[DefaultBaseCommand]
val CommandsMessages: caseapp.core.CommandsMessages[Commands.RawCommand] =
implicitly[caseapp.core.CommandsMessages[Commands.RawCommand]]
val CommandsParser: CommandParser[Commands.RawCommand] =
implicitly[caseapp.core.CommandParser[Commands.RawCommand]]
}

object Main extends App {
import Parsers._
/* assert(CommandsParser != null)
assert(CommandsMessages != null)*/
println("Hello World!")
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import io.circe._
/*import io.circe._
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
Expand All @@ -16,4 +16,4 @@ object WebsiteExample extends App {
import io.circe.generic.semiauto._
implicit val fooDecoder: Decoder[Foo] = deriveDecoder[Foo]
implicit val fooEncoder: Encoder[Foo] = deriveEncoder[Foo]*/
}
}*/
1 change: 1 addition & 0 deletions plugin/src/main/scala/ch/epfl/scala/PluginConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ case class PluginConfig(
sourceRoot: Option[AbsolutePath],
printSearchIds: Set[Int],
generateMacroFlamegraph: Boolean,
printFailedMacroImplicits: Boolean,
concreteTypeParamsInImplicits: Boolean
)
2 changes: 2 additions & 0 deletions plugin/src/main/scala/ch/epfl/scala/ProfilingPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class ProfilingPlugin(val global: Global) extends Plugin {
private final lazy val SourceRoot = "sourceroot"
private final lazy val PrintSearchResult = "print-search-result"
private final lazy val GenerateMacroFlamegraph = "generate-macro-flamegraph"
private final lazy val PrintFailedMacroImplicits = "print-failed-implicit-macro-candidates"
private final lazy val NoProfileDb = "no-profiledb"
private final lazy val ShowConcreteImplicitTparams = "show-concrete-implicit-tparams"
private final lazy val PrintSearchRegex = s"$PrintSearchResult:(.*)".r
Expand All @@ -59,6 +60,7 @@ class ProfilingPlugin(val global: Global) extends Plugin {
findOption(SourceRoot, SourceRootRegex).map(AbsolutePath.apply),
findSearchIds(findOption(PrintSearchResult, PrintSearchRegex)),
super.options.contains(GenerateMacroFlamegraph),
super.options.contains(PrintFailedMacroImplicits),
super.options.contains(ShowConcreteImplicitTparams)
)

Expand Down
Loading

0 comments on commit 5ee6ec9

Please sign in to comment.