Playのsbt-pluginに含まれる様々なtrait
ScalaのWebアプリケーションフレームワークであるPlay2、基板を支えるsbt-pluginに含まれる色々なtraitを見る。なおPlayのPluginとは別物なので注意。
PlayRun
, PlaySettings
あたり非常に興味深い。playのsbt設定や、run
を実行した時にどのような処理が行われるのかが分かる。
以下で触れるのは2.3.xブランチのこのcommit上の話、ただコードを読むだけ
trait PlayImport
jdbc, anormなどのcomponent
def component(id: String) = "com.typesafe.play" %% id % play.core.PlayVersion.current
saclaテンプレートでデフォルトで読み込まれるimport
val defaultScalaTemplateImports = Seq( "models._", "controllers._", "play.api.i18n._", "play.api.mvc._", "play.api.data._", "views.%format%._")
emojiLogs
...テストの結果を絵文字で表示してくれる
object PlayKeys
にて、以下のようなSettingKeyやTaskKeyなどの宣言
playVersion
, playDefaultPort
, playRunHooks
, playRoutesImports
, playGenerateReverseRouter
, playGenerateRefReverseRouter
, playNamespaceReverseRouter
, playMonitoredFiles
, playWatchService
PlaySettings
- self type annotation
this: PlayCommands with PlayPositionMapper with PlayRun with PlaySourceGenerators
PlayImportやsbtに宣言されたSettingKeyのPlay用実装が主な利用 PlayRunやPlayCommandsで定義された値とか使ってる
defaultScalaSettings
- TwirlのtemplateImports
defaultScalaTemplateImports
closureCompilerSettings
- JavascriptCompiler: minとかするやつ
- LessCompiler
- CoffeescriptCompiler
manageClasspath
defaultSettings
: 色々入ってる- Typesafe Releases Repositoryをresolverに追加
- target, source, conf, scalaSource, javaSourceなどのディレクトリ指定
TwirlCompileTemplates
時のsourceDirectories
をCompile時とTest時で別にしてる- javaOptionに
-encoding utf8
追加 - libraryDependenciesに以下のものを追加
"com.typesafe.play" %% "play" % play.core.PlayVersion.current
"com.typesafe.play" %% "play-test" % play.core.PlayVersion.current
"com.typesafe.play" %% "play-docs" % play.core.PlayVersion.current
parallelExection in Text := false
: sbtタスクの並列実行fork in Test := true
: テストconfiguration時にはJVMを別に起動- Specs2とJUnit別に
testOptions
を追加- Specs2:
sequential=true
,junitxml=console
- JUnit:
--ignore-runners=org.specs2.runner.JUnitRunner
- Specs2:
- ReverseRouterを生成させるフラグなどの設定
watchSources
(監視対象)にconfディレクトリやapp(ただしapp/assetsは除く)など追加- Compileコンフィギュレーションの
run
にplayDefaultRunTask
を追加val playDefaultRunTask = playRunTask(playRunHooks, playDependencyClasspath, playDependencyClassLoader, playReloaderClasspath, playReloaderClassLoader, playAssetsClassLoader)
shellPrompt
にplayPrompt
(プロジェクト名など出す)を設定- Compile/Testコンフィギュレーションの
compile
にPlayCommands.PostCompile
っての入れてる- この中でテンプレート云々とかしてたりする?(後で見る)
playRunHooks := Nil
playInteractionMode := play.PlayConsoleInteractionMode
assetsPrefix := "public/"
devSettings := Nil
TwirlKeys.templateImports ++= defaultTemplateImports
mainClass in (Compile, run) := Some("play.core.server.NettyServer")
- 知らんかった...
PlayCommands
- 継承
- extends PlayAssetsCompiler with PlayEclipse with PlayInternalKeys
- self type annotation
- PlayReloader
色んなコマンドやタスクの実装がある
PostCompile
- timestampはcacheDir/play_instrumentation(target/scala-x.x.x/cache/root/compile/play_instructionとか)
- javaクラスやテンプレートクラスのenhanceが必要かを編集時刻などを見て取得
analysis.apis.internal(sourceFile).compilation.startTime
でコンパイルもしてる気がする?(ここのanalysis
はcompile in scope
でsourceFile
が*.java
や*.template.scala
)- javaクラスのenhance
PropertiesEnhancer.generateAccessors
,PropertiesEnhancerrewriteAccess
- テンプレートクラスのenhance
PropertiesEnhancer.rewriteAccess
ebeanEnhancement
compile
時にはtarget/scala_2.x.x/*_managed以下にrouteなどの自動生成されたクラスなどをコピーする- enhanceされたクラスは編集時刻などの更新を行う
idea
,playPrompt
,h2-browser
,classpath
,sh
(Processに与えてJvmIOで処理してる),playCommoClassloaderTask
(普通にclasspassをURLClassLoaderに渡して作ってる,/* important here, don't depend of the sbt classLoader! */
),playMonitoredFilesTask
,computeDependencies
(libraryDependencies間違えるとよく出るエラーはこのへん), ``- RequireJsの処理とかある(使ってないしあまり興味無い)
enhanceって何してんの(play.core.enhancers.PropertiesEnhancer
)
PropertiesEnhancer.generateAccessors
- getDeclaredFiledsで取り出した定数などでない、publicなproperty field全てにpublicなgetter/setter生やしてく
PropertiesEnhancerrewriteAccess
- アクセッサーを利用している箇所のgetter/setterの名前をgetとsetの後に続く1文字目のみ大文字となるような表記に書き換えてる?
PlayRun
- 継承
- extends PlayInternalKeys
- self type annotation
- PlayReloader
playDefaultRunTask
、twiddleRunMonitor
とplayStartCommand
がメイン
val playDefaultRunTask = playRunTask(playRunHooks, playDependencyClasspath, playDependencyClassLoader,
playReloaderClasspath, playReloaderClassLoader, playAssetsClassLoader)
playRunTask
(run in Compile <<= playDefaultRunTask
)- devModeServerを以下の
startDevMode
から用意 startDevMode
: 評価された時に中身が順に実行される- 引数を踏まえてportやpropertiesを取得
/* We need to do a bit of classloader magic to run the Play application. There are seven classloaders: */
runHooks.run(_.beforeStarted())
- serverとして
mainClass(play.core.server.NettyServer)
のmainDevHttpMode/mainDevOnlyHttpsMode
からServerWithStop
が起動 runHooks.run(_.afterStarted(server.mainAddress))
- reloaderを持って、
close()
時に先ほどのserverが停止したりrunHooks.run(_.afterStopped())
が実行されるPlayDevServer
が返却される
~
のあるなしで分岐し、Console実行の場合:~
->PlayInteractionMode.doWithoutEcho
による入力待ち、~
なし ->PlayInteractionMode.waitForCancel
による入力待ち、非同期実行の場合は何もしないか引数の関数を実行するか
- devModeServerを以下の
twiddleRunMonitor
:~run
みたいなチルダ付けた時の動作SourceModificationWatch.watch
によるファイルの変更監視Thread.sleep
とかしつつ状態の変化を見てProject.runTask(compile in Compile, newState)
を実行する
playStartCommand
:start
コマンド実行時の動作- 引数を踏まえてportやpropertiesを取得
Project.runTask(stage, state)
を実行- 正しく動作した場合、実行バイナリをstadingDirectory以下から取得
- 新しいThreadを立てて、その中で先ほどのバイナリを実行
- その他playのasset関連の設定
PlayPositionMapper
コンパイルエラー時にソースの行番号を表示するためのマッパー
PlayReloader
- self type
- PlayCommands with PlayPositionMapper
PlayRunの開発サーバを支えるreloaderを提供
reloaderはplay.core.BuildLink
にclose
とgetClassLoader
を実装したもので、play.core.ReloadableApplication
の引数などに利用される*1
play.core.BuildLink
って?
Interface used by the Play build plugin to communicate with an embedded Play server.
- PlayWatchServiceに監視対象となるファイルを与えて、変更したかどうかのフラグを持つ
reload
は同期的に行われ、ファイルの変更があるなどを事前条件に以下の順に実行される(sbt run
の場合を基に)TaskKey[sbt.inc.Analysis]("play-reload")
が実行 ((PlayCommandsのval playReloadTask = Def.task(playCompileEverything.value.reduceLeft(_ ++ _))
))- 成功すれば、
TaskKey[Classpath]("play-reloader-classpath")
- 成功した時、クラスパス内のファイルに変更がある場合のみ
classloader
を入れ替える (ファイルの変更はSourceModificationWatch
内にてファイルの編集時刻の違いを見るなどして判定) (runTask
では、sbtのAct.scopedKeyparer
を利用して指定されたタスクを実行)
close
時には、classloaderを破棄し上記で挙げたファイルの変更を監視するwatcherを止める
PlayInternalKeys
classpath関連のタスク、playCommonClassLoader
、playStop
、playReload
、play-all-assets
PlayEclipse
- self type
- PlayCommands
com.typesafe.sbteclipse.coreのラッパー
PlayAssetsCompiler
AssetsCompiler
- ファイルの最終編集時刻見て、変更のある場合に、変更のあるファイルのみコンパイルしてpublic以下に置く
- ファイルの変更とかは、
sbt.Sync
使って管理してる
LessCompiler
JavascriptCompiler
CoffeescriptCompiler
PlaySourceGenerators
- RoutesCompier使ってrouteファイルを生成
- compileエラー表示
JvmIO, JvmLogger
別スレッドで何らかのプロセスを実行するためのラッパー
複数のJVM立ち上げてなんかするためのPlayJvm
がコメントアウトされて存在してた
*1:TODO NettyServerとか含めて後で見る