heroku / heroku-sbt-plugin

An sbt plugin for deploying Heroku Scala applications
MIT License
0 stars 0 forks source link

Cyclic dependencies error on extraLoggers when used with lihaoyi/workbench #30

Closed tel closed 4 years ago

tel commented 8 years ago

I'm getting an error as soon as I declare the sbt-heroku plugin (version 1.0.1)

info] Loading project definition from /Users/tel/Dropbox/proj/qubit/project
Cyclic reference involving
   {file:/Users/tel/Dropbox/proj/qubit/}ui/*:extraLoggers
   {file:/Users/tel/Dropbox/proj/qubit/}/*:extraLoggers
    at sbt.Dag$Cyclic.$colon$colon(Dag.scala:67)
    at sbt.Dag$.sbt$Dag$$visit$1(Dag.scala:27)
    at sbt.Dag$$anonfun$visitAll$1$1.apply(Dag.scala:23)
    at sbt.Dag$$anonfun$visitAll$1$1.apply(Dag.scala:23)
    at scala.collection.Iterator$class.foreach(Iterator.scala:727)
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1157)
    at scala.collection.MapLike$DefaultValuesIterable.foreach(MapLike.scala:206)
    at sbt.Dag$.visitAll$1(Dag.scala:23)
    at sbt.Dag$.topologicalSort(Dag.scala:33)
    at sbt.Init$class.sort(Settings.scala:152)
    at sbt.Def$.sort(Def.scala:10)
    at sbt.Init$class.make(Settings.scala:146)
    at sbt.Def$.make(Def.scala:10)
    at sbt.Load$.apply(Load.scala:145)
    at sbt.Load$.defaultLoad(Load.scala:36)
    at sbt.BuiltinCommands$.liftedTree1$1(Main.scala:492)
    at sbt.BuiltinCommands$.doLoadProject(Main.scala:492)
    at sbt.BuiltinCommands$$anonfun$loadProjectImpl$2.apply(Main.scala:484)
    at sbt.BuiltinCommands$$anonfun$loadProjectImpl$2.apply(Main.scala:484)
    at sbt.Command$$anonfun$applyEffect$1$$anonfun$apply$2.apply(Command.scala:59)
    at sbt.Command$$anonfun$applyEffect$1$$anonfun$apply$2.apply(Command.scala:59)
    at sbt.Command$$anonfun$applyEffect$2$$anonfun$apply$3.apply(Command.scala:61)
    at sbt.Command$$anonfun$applyEffect$2$$anonfun$apply$3.apply(Command.scala:61)
    at sbt.Command$.process(Command.scala:93)
    at sbt.MainLoop$$anonfun$1$$anonfun$apply$1.apply(MainLoop.scala:96)
    at sbt.MainLoop$$anonfun$1$$anonfun$apply$1.apply(MainLoop.scala:96)
    at sbt.State$$anon$1.process(State.scala:184)
    at sbt.MainLoop$$anonfun$1.apply(MainLoop.scala:96)
    at sbt.MainLoop$$anonfun$1.apply(MainLoop.scala:96)
    at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
    at sbt.MainLoop$.next(MainLoop.scala:96)
    at sbt.MainLoop$.run(MainLoop.scala:89)
    at sbt.MainLoop$$anonfun$runWithNewLog$1.apply(MainLoop.scala:68)
    at sbt.MainLoop$$anonfun$runWithNewLog$1.apply(MainLoop.scala:63)
    at sbt.Using.apply(Using.scala:24)
    at sbt.MainLoop$.runWithNewLog(MainLoop.scala:63)
    at sbt.MainLoop$.runAndClearLast(MainLoop.scala:46)
    at sbt.MainLoop$.runLoggedLoop(MainLoop.scala:30)
    at sbt.MainLoop$.runLogged(MainLoop.scala:22)
    at sbt.StandardMain$.runManaged(Main.scala:54)
    at sbt.xMain.run(Main.scala:29)
    at xsbt.boot.Launch$$anonfun$run$1.apply(Launch.scala:109)
    at xsbt.boot.Launch$.withContextLoader(Launch.scala:128)
    at xsbt.boot.Launch$.run(Launch.scala:109)
    at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:35)
    at xsbt.boot.Launch$.launch(Launch.scala:117)
    at xsbt.boot.Launch$.apply(Launch.scala:18)
    at xsbt.boot.Boot$.runImpl(Boot.scala:41)
    at xsbt.boot.Boot$.main(Boot.scala:17)
    at xsbt.boot.Boot.main(Boot.scala)
[error] Cyclic reference involving
[error]    {file:/Users/tel/Dropbox/proj/qubit/}ui/*:extraLoggers
[error]    {file:/Users/tel/Dropbox/proj/qubit/}/*:extraLoggers
[error] Use 'last' for the full log.

My build.sbt looks like

lazy val commonSettings = Seq(
  organization := "jspha",
  scalaVersion := "2.11.8",
  version := "1.0-SNAPSHOT",
  resolvers += Resolver.sonatypeRepo("snapshots")
)

lazy val http4sVersion = "0.14.0-SNAPSHOT"
lazy val doobieVersion = "0.2.3"

lazy val server = project.in(file("server"))
  .settings(commonSettings: _*)
  .dependsOn(sharedJvm)
  .settings(
    libraryDependencies ++= Seq(
      "org.http4s" %% "http4s-dsl" % http4sVersion,
      "org.http4s" %% "http4s-blaze-server" % http4sVersion,

      "org.tpolecat" %% "doobie-core" % doobieVersion,
      "org.tpolecat" %% "doobie-contrib-postgresql" % doobieVersion,
      "org.tpolecat" %% "doobie-contrib-specs2" % doobieVersion,

      "org.slf4j" % "slf4j-simple" % "1.6.4"
    )
  )
  .settings(
    (resources in Compile) <+= Def.task {
      (artifactPath in (ui, Compile, fullOptJS)).value
    } dependsOn (fullOptJS in (ui, Compile))
  )
  .enablePlugins(JavaServerAppPackaging)

lazy val shared = crossProject.crossType(CrossType.Pure).in(file("shared"))
  .settings(commonSettings: _*)

lazy val sharedJvm = shared.jvm.settings(name := "sharedJvm")
lazy val sharedJs = shared.js.settings(name := "sharedJs")

lazy val ui = project.in(file("ui"))
  .settings(commonSettings: _*)
  .dependsOn(sharedJs)
  .enablePlugins(ScalaJSPlugin)
  .settings(workbenchSettings)
  .settings(
    bootSnippet := "jspha.qubit.ui.Runtime().main();",
    refreshBrowsers <<= refreshBrowsers.triggeredBy(fastOptJS in Compile)
  )
jkutner commented 8 years ago

Can you share the list of other plugins you are including? I think it most likely related to a conflict with one of them, rather than some configuration in your build.

tel commented 8 years ago

Sure, here's plugins.sbt


resolvers += "spray repo" at "http://repo.spray.io"
resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"

addSbtPlugin("io.spray" % "sbt-revolver" % "0.8.0")
addSbtPlugin("com.lihaoyi" % "workbench" % "0.2.3")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.9")
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.1.0-RC1")
addSbtPlugin("com.heroku" % "sbt-heroku" % "1.0.1")

logLevel := Level.Warn
tel commented 8 years ago

Based on a quick review, it's the workbench plugin which is causing the issues. I'll investigate further.

tel commented 8 years ago

Here's a relevant part of the definition of workbenchSettings:

    (extraLoggers in ThisBuild) := {
      val clientLogger = FullLogger{
        new Logger {
          def log(level: Level.Value, message: => String) =
            if(level >= Level.Info) server.value.Wire[Api].print(level.toString, message).call()
          def success(message: => String) = server.value.Wire[Api].print("info", message).call()
          def trace(t: => Throwable) = server.value.Wire[Api].print("error", t.toString).call()
        }
      }
      clientLogger.setSuccessEnabled(true)
      val currentFunction = extraLoggers.value
      (key: ScopedKey[_]) => clientLogger +: currentFunction(key)
    },

I'm not right now aware enough of how sbt works to understand why this would be causing the looping issues. For completeness, here's the similar line in sbt-heroku

      extraLoggers := {
        val currentFunction = extraLoggers.value
        (key: ScopedKey[_]) => {
          val taskOption = key.scope.task.toOption
          val loggers = currentFunction(key)
          if (taskOption.map(_.label) == Some("deployHeroku") || taskOption.map(_.label) == Some("deployHerokuSlug"))
            new HerokuLogger(target.value / "heroku" / "diagnostics.log") +: loggers
          else
            loggers
        }
      }
tel commented 8 years ago

I was able to get it working locally by filtering out the extraLoggers key from workbenchSettings.

  .settings(workbenchSettings.filterNot(p => p.key.key == extraLoggers.scopedKey.key))

but this is fairly blunt and unsatisfactory.

jkutner commented 8 years ago

Yes, that's not a good long term solution. Thank you for providing so much excellent detail on the problem. I will look into fixing it, but the what's causing the cycle is not immediately obvious to me (so I may have to enlist some help from the SBT folks).

tel commented 8 years ago

Np! I've also cross-posted this to lihaoyi/workbench as I'm honestly not sure where a fix ought to happen. Thank you for looking into it!

Malax commented 4 years ago

I'm closing this due to inactivity. Feel free to comment in case this issue still be relevant for you and I'll reopen it.