decadence

個人のメモ帳

sbt起動時、xsbt.bootの話

sbtの起動時の話

手元の更新し忘れて、3ヶ月前の0.13ブランチの見てた。変わってたら悲しい。

xsbt.boot

sbtって打つと何が起こるか。

xsbt.boot.Boot

  • main
    • CheckProxy
    • run(config)
    • runImple -> xsbt.boot.Launch map exit

xsbt.boot.Launch

  • apply: currentDirectory指定して起動 -> 返り値は exit code で: Option[Int]
    • --locate で起動ディレクトリ変更
    • 引数パースしたりで、設定のロケーションURLを探す
      • @load:で始まるもの: serialized-file -> LaunchConfiguration.restore(指定されたURLを基に、設定を読み直す)
      • @で始まるもの: properties-file -> parseAndInitializeConfig(指定されたpathを基に、設定を読み直す)
      • -Dで始まるもの: System.setProperty
      • 引数でコンフィグロケーションの指定がなければ
        • sbt.boot.propertiesがある時: そのへんから探す
        • 無い時: クラスパスから探す
          • userConfiguration: "/sbt.boot.properties"
          • defaultConfigurationPath: "/sbt/sbt.boot.properties"
    • 設定ファイルから、xsbt.boot.ConigurationParser.get*で設定を読みまくってる
    • 設定を入れて、launch(run(Launcher(config)))(makeRunConfig...)...
  • run(launcher: xsbti.Launcher)(config: RunConfiguration): xsbti.MainResult

    • 良く分からんけど設定にあるappのrun関数を実行してる -> 結果的にsbt.xMain.runらへんを呼び出す(sbt.ScriptMain, sbt.ConsoleMainもある)
    • JAnsi.installとかなんだ...
    • Class.forName("org.fusesource.jansi.AnsiConsole", true, loader)???????
    • config.appの情報を基にlauncherからAppProviderを生成
      • こういうのを基にしてる: config.app.toID(def toID = AppID(groupID, name, getVersion, main, toArray(components), crossVersioned, classpathExtra))
    • 生成されたAppProviderのmainを実行
      • 新たなClassLoader(AppProviderの持つやつ)を現在のスレッドにセットしなおして、mainを実行する
  • launch(run: RunConfiguration => xsbti.MainResult)(config: RunConfiguration): Option[Int]

    • runを実行して、MainResultの直和のいずれかにより、exit codeを含むOption[Int]を返す
      • xsbti.Exit => Some(e.code) : 終了時(state.failとか)
      • xsbti.Continue => None : 普通に継続
      • xsbti.Reboot => launch(run)(...) : 実行後の状態を引き継いで再帰

Transform

起動されるrunを含むconfigの内容、以下の場所にあった。

どうやって選ばれてるのかとか、全く理解してないけどスルー。

  • /src/main/conscript/sbt/launchconfig
  • /src/main/conscript/scalas/launchconfig
  • /src/main/conscript/screpl/launchconfig
val pairs = Seq(
  "sbt.xMain" -> "sbt",
  "sbt.ScriptMain" -> "scalas",
  "sbt.ConsoleMain" -> "screpl"
)
for ((main, dir) <- pairs) yield {
  val file = conscriptBase / dir / "launchconfig"
  copyPropertiesFile(source, main, file)
  file
}

次回

まだ普通に触る分な所は出てこない。完全に別のとこに移動したし、次はsbt.xMainとか見る。

コメント

JavaJVM詳しくないから分からないんだけど、普通にxMainとか呼び出したら良いのに何でClassLoaderとか使ってるのか誰か教えて欲しい。 設定ファイルから文字列でクラス指定してるから?別に指定した時だけClassLoader使って呼び出したら良いわけだし、なんで最初から全部ClassLoader使って呼び出したりしてんの。

違うClassLoader使って実行して、try~catchで囲んで制御とかしたいそういうやつ?

Java仮想マシンの配下では、多くのクラスが複雑に(かつ密接に)絡み合い、Javaアプリケーションの動作を支えています。しかし、複数のアプリケーションを利用しているうちに、相互のアプリケーション間で、同名でバージョンだけが異なるクラス(ライブラリ)が必要になったとしたらどうなるでしょう? しかも、そのクラスライブラリには、バージョン間の上位/下位互換性がないとしたら、どうしたらよいでしょうか。

 このように、バージョンアップしなければアプリケーションBが動かない、バージョンアップすればアプリケーションAが正常に動かなくなってしまうというケースは、多くのアプリケーションが並存するサーバ上においては、大いにあり得ることです。 ...(略)...

 これによって、複数のアプリケーション間で異なるバージョンのライブラリが並存していたとしても、相互に影響することなく正しい動作を行うことが可能になるのです。コンテナに対して、クラスライブラリを追加導入する場合、このクラスローダの階層関係と有効範囲を知っておくことは、ライブラリの競合による不具合を未然に防ぐために重要な知識であるといえるでしょう。 @IT:Java TIPS -- クラスローダの仕組みを知る

同じインタフェースがあれば問題無いんじゃないの?