Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Scala をインタラクティブにデバッグする方法あれこれ

110416
October 13, 2023
1.2k

Scala をインタラクティブにデバッグする方法あれこれ

Tips for interactively debugging Scala libraries and applications.

- sbt console
- test
- publishLocal & import from local repository
- import from private maven repository

110416

October 13, 2023
Tweet

Transcript

  1. WHOAMI GitHub: i10416 X(Twitter): @by110416 Scala & Rust developer 最近の

    Scala OSS コントリビューション https://github.com/neotypes/neotypes/releases/tag/v1.0.0-M3
  2. 前提:次のようなパッケージをデバッグする想定で説明する. // src/main/scala/Lib.scala package com.example object Lib { def doSomething():

    Int = 42 } // build.sbt ThisBuild / organization := "com.example" val lib = project.in(file(".")) .settings( scalaVersion := "3.3.1", version := "0.1.0-SNAPSHOT", libraryDependencies ++= Seq( "org.scalameta" %% "munit" % "1.0.0-M7" % Test ) )
  3. Table of Contents sbt console test publishLocal & import from

    local repository import from private maven repository
  4. 予習: sbt shell と sbt console sbt shell: 通常のシェル(zsh、fish や bash)で

    sbt と入力したときに開始される sbt の インタラクティブなインターフェース. sbt console: sbt shell から呼び出せる Scala REPL 環境 以下の例ではコードブロックの行頭が sbt> と書かれている場合 sbt shell 内でのコマンド実 行を、scala> と書かれている場合は Scala REPL 内でのコマンド実行を意味する.
  5. sbt console でデバッグ 複数行の入力 scala>:paste // Entering paste mode (ctrl-D

    to finish) object DeepThought { val theAnswer = 42 } // ctrl-D
  6. sbt console でデバッグ: 初期化コマンドの設定 console/initialCommands を設定すれば sbt console の初期化処理を追加できる. 毎回特定のモジュールやライブラリやインポートする場合は設定しておくと楽.

    // build.sbt val lib = project.in(file(".")) .settings( scalaVersion := "3.3.1", version := "0.1.0-SNAPSHOT", console / initialCommands := "import java.nio.file._", libraryDependencies ++= Seq( "org.scalameta" %% "munit" % "1.0.0-M7" % Test ) )
  7. sbt console でデバッグ: multi modules 特定のサブプロジェクトのデバッグをしたい場合は sbt shell 内で projects

    コマンドを実行し サブプロジェクトの名前を確認し projectname/console(下の例では sbt contrib/console ) とすればいい. ├── build.sbt ├── contrib/src/main/scala/... └── core/src/main/scala/... // build.sbt lazy val core = project.in(file("core")) ... lazy val contrib = project.in(file("contrib")) ...
  8. sbt console でデバッグ: Pros & Cons Pros 楽. セットアップや(ローカル)リリースが必要ない. 期待する動作がそこまで定まっていなくてもいい.

    Cons パッケージやアプリケーション全体をデバッグするのには向かない. JS や Native ではデバッグできない. コンパイルが通っている必要がある(consoleQuick を使えば回避できる)
  9. test(& sbt testOnly) でデバッグ // src/test/scala/Test.scala package com.example class Test

    extends munit.FunSuite { test("Lib.doSomething returns 42") { assertEquals(Lib.doSomething, 42) } } test sbt>test testOnly sbt>testOnly com.example.Test
  10. test でデバッグ: Pros & Cons Pros JS や Native でも動作確認できる.

    console より IDE のサポートを活用できる. Cons コンパイルを通さないといけない. テストを書かないといけない. ユニットテストが書きにくいコードベースだと辛い. ある程度期待する動作が定まっている必要がある.
  11. import from Scala CLI Scala CLI では using dep でパッケージを読み込める.

    using dep はデフォルトで maven のレポジトリとローカルのレポジトリからパッケージを探す. //> using dep "com.example::lib:0.1.0-SNAPSHOT" import com.example.Lib @main def run = println(Lib.doSomething()) //=> 42
  12. import from ammonite REPL ammonite REPL では $ivy. のマジックインポートを使ってパッケージを読み込める. @

    import $ivy.`com.example::lib:0.1.0-SNAPSHOT` @ import com.example.Lib @ Lib.doSomething() res0: Int = 42 @
  13. sbt publishLocal でデバッグ: Pros & Cons Pros ライブラリ全体の動作確認をできる. Cons 配布+新しいプロジェクトを作成しないといけないのでやや手間.

    バージョンでキャッシュされるのでバージョンを上げるかコミットハッシュなどを付与 する必要がある.
  14. Private な Maven レポジトリに配布されたパッケージをデバッグする 代表的なのは社内レポジトリから private パッケージを取得するユースケース. ここでは GCP の

    asia-northeast1 の example-project プロジェクトに example という Artifact Registry がある想定で説明する. GCP を例にするが基本的なアイディアは同じ(...なはず)
  15. sbt project から GCP Artifact Registry にアクセスする sbt gcs resolver

    を利用する. この sbt plugin は GCS や Artifact Registry へのパッケージの配布・取得機能を提供する. // project/plugins.sbt addSbtPlugin("org.latestbit" % "sbt-gcs-plugin" % "1.8.0") デフォルトの認証情報を設定しておけば plugin がよしなに読み取ってくれる. gcloud auth application-default login
  16. sbt project から GCP Artifact Registry にアクセスする // build.sbt resolvers

    += "My Maven Artifact Registry" at "artifactregistry://asia-northeast1-maven.pkg.dev/example-project/example" libraryDependencies ++= Seq( "com.example::lib:0.1.0-SNAPSHOT" )
  17. Scala CLI から GCP Artifact Registry にアクセスする 認証情報を設定する. repository のホストが

    asia-northeast1-maven.pkg.dev の時に指定した 認証情報が使われる. scala-cli --power config \ repositories.credentials "asia-northeast1-maven.pkg.dev" \ value:_json_key_base64 value:eyXXInR5cXXiOiXXc2..... value::eyXXInR5cXXiOiXXc2..... の部分はサービスアカウント has-access-to-artifact- [email protected] のJSON鍵ファイルを base64 エンコ ードしたもの.
  18. Scala CLI から GCP Artifact Registry にアクセスする using repository で

    maven やローカル以外のレポジトリを追加できる. //> using repository "https://asia-northeast1-maven.pkg.dev/examle-project/example" //> using dep "com.example::lib:0.1.0-SNAPSHOT" import com.example._ @main def run = println(Lib.doSomething())
  19. Scala CLI から認証付きレポジトリにアクセスする scala-cli --power config \ repositories.credentials <HOST> \

    <USERNAME> <PASSWORD> GitHub Packages などの認証付きレポジトリも同様に利用できる. scala-cli --power config \ repositories.credentials "maven.pkg.github.com" \ value:PrivateToken env:GITHUB_TOKEN /> using repository "https://maven.pkg.github.com/<org>/_"
  20. Misc remove/unset scala-cli --power config --remove repositories.credentials coursier fetch cs

    fetch -r https://asia-northeast1-maven.pkg.dev/example-project/example \ --credentials "asia-northeast1-maven.pkg.dev _json_key_base64:eyXXInR5cXXiOiXXc2....." sbt help <cmd> sbt> help help