2014-04-12 13 views
6

Chciałbym utworzyć wtyczkę sbt dla mojego projektu, zanim go otworzę.jak napisać wtyczkę sbt, aby uruchomić aplikację z agentem

Projekt dołącza agenta Java na początku uruchamiania aplikacji, aby przydzielić go do różnych typów profilowania. Agent wypisze pliki tekstowe do późniejszego przetworzenia.

Chciałbym móc napisać plugin SBT, które mogą

  • mieć alternatywę do run nazywa runWithProfiling który uruchamia nowy proces java, ze środkiem dodany do listy argumentów, a przechodząc przez cały polecenia użytkowników.
  • na wyjeździe, to potem chce powołać jakąś dowolnego kodu postprocessingu produkować raport HTML

Wiem mniej więcej, jak utworzyć nowe polecenie, ale nie wiem, jak najlepiej wdrożyć alternatywny do run ... Nie chcę ponownie wymyślać koła, kopiując cały kod, który robi run. Czy istnieje sposób, aby wywołać run, ale upewnij się, że moje parametry są przekazywane (jeden raz) i że jest to z pewnością nowy proces java?

Również możliwość wykonania tego samego testu byłaby świetna.

UPDATE: jest to kod, który obecnie mam, ale cierpi z powodu kilku problemów, oznaczony jako TODO s

import sbt._ 
import Keys._ 
import sbt.Attributed.data 

object LionPlugin extends Plugin { 

    val lion = TaskKey[Unit]("lion", "Run a main class with lions-share profiling.") 

    override val projectSettings = Seq(
    fork := true, 
    javaOptions ++= Seq(
     "-Xloggc:gc.log", "-XX:+PrintGCDetails", "-XX:+PrintGCDateStamps", 
     "-XX:+PrintTenuringDistribution", "-XX:+PrintHeapAtGC" 
     // TODO: need to get hold of the local jar file for a particular artifact 
     // IMPL: pass the jar as the agent 
    ), 
    lion <<= (
     runner, 
     fullClasspath in Runtime, 
     mainClass in Runtime, 
     streams in Runtime 
    ) map runLion 
) 

    // TODO: update to a task that can take parameters (e.g. number of repeats, profiling settings) 
    def runLion(runner: ScalaRun, cp: Classpath, main: Option[String], streams: TaskStreams): Unit = { 
    assert(runner.isInstanceOf[ForkRun], "didn't get a forked runner... SBT is b0rk3d") 
    println("RUNNING with " + runner.getClass) 

    // TODO: ask user if main is None, like 'run' does 
    val m = main.getOrElse("Scratch") 

    // TODO: get the user's arguments 
    val args = Nil 

    runner.run(m, data(cp), args, streams.log) 

    // IMPL: post-process and produce the report 

    println("FINISHED") 
    } 

} 

Odpowiedz

1

Autorzy wtyczek muszą przestrzegać niepisanej przysięgi Hipokratesa, która jest "pierwsza, nie szkodzić". Twoja implementacja obecnie zmusza się do każdego podprojektu i modyfikuje domyślne zachowanie domyślne, co moim zdaniem jest niebezpieczne. Myślę, że powinieneś zduplikować parametry z zakresu run do swojego zadania, aby ustawienia domyślne były nienaruszone.

// TODO: update to a task that can take parameters (e.g. number of repeats, profiling settings) 

Zobacz Plugins Best Practices i istniejących wtyczek jak sbt-appengine dla przykładu.

W sbt-appengine devServer to zadanie wejściowe, które można ustawić szereg parametrów.

gae.devServer  := { 
    val args = startArgsParser.parsed 
    val x = (products in Compile).value 
    AppEngine.restartDevServer(streams.value, (gae.reLogTag in gae.devServer).value, 
    thisProjectRef.value, (gae.reForkOptions in gae.devServer).value, 
    (mainClass in gae.devServer).value, (fullClasspath in gae.devServer).value, 
    (gae.reStartArgs in gae.devServer).value, args, 
    packageWar.value, 
    (gae.onStartHooks in gae.devServer).value, (gae.onStopHooks in gae.devServer).value) 
} 

Jak widać jelito kodu jest rzeczywiście realizowany w metodzie pod AppEngine obiektu, więc ktoś inny może ponownie wykorzystać swoje rzeczy potencjalnie. Wiele parametrów metody (w tym przypadku restartDevServer) obejmuje zakres do zadania gae.devServer, takiego jak (mainClass in gae.devServer).

W jaki sposób zamierzasz zainstalować wtyczkę przez użytkowników kompilacji? Czy zamierzają włączyć go raz jako globalną wtyczkę i używać tych samych ustawień wszędzie, czy też będą je włączać dla każdej kompilacji w project/lion.sbt?Zalecane jest podanie i baseLionSettings i lionSettings, aby użytkownik mógł wybrać i wybrać, które podprojekty będą miały włączone zadanie lion.

Jak na bieżący przebieg, powinieneś rzucić okiem na ponowne użycie kodu z sbt-revolver podobnego do tego, co zrobiłem w sbt-appengine.

+0

jest to bardzo przydatne, dzięki! Bardzo chciałbym umożliwić użytkownikom ustawienie tego na podstawie modułu i pozostawienie fork/javaOptions użytkownika nietkniętym. Obawiam się, że nadal nie jestem bliżej, aby wiedzieć, jak to zrobić, nawet po przeczytaniu źródła. Pierwotnie miałem np. 'fork in lion: = true', ale to było ignorowane. – fommil

+0

chociaż, ukradnę twoje podejście i użyję 'Fork.java' bezpośrednio ... to znaczy, że nigdy nie zmieniam żadnego z ustawień. – fommil

1

Patrz „Jak mogę utworzyć własne zadanie run, oprócz uruchomić? "pod adresem http://www.scala-sbt.org/0.13.0/docs/faq.html. W twoim niestandardowym zadaniu, ustawisz fork na true, aby uruchomić świeżą maszynę JVM.

+0

Wow, jest tam często zadawane pytanie. Teraz czuję się głupio :-) – fommil

+0

to był tylko wierzchołek góry lodowej ... Właściwie wywoływanie 'fullRunTask' jest trudne. Jest to "Ustawienie" i nie wiem jak to nazwać ... – fommil

+0

Przepraszam, odznaczam odpowiedź, dzięki czemu mogę zaktualizować o więcej szczegółów – fommil

Powiązane problemy