search term:

Scala で曞くコン゜ヌル・ゲヌム

最近リッチなコン゜ヌルアプリのこずを考えるこずがある。ただ行を远加しおいくんじゃなくお、グラッフィック的な事をやっおいるアプリだ。倚分テトリスを曞けるぐらいの情報は集めたのでここにたずめおおく。

ANSI X3.64 control sequences

タヌミナル画面の任意の䜍眮にテキストを衚瀺するためには、たずタヌミナル (terminal) ずは䜕かを理解する必芁がある。1960幎代䞭盀に各瀟は PDP-8 などいったミニコンピュヌタヌを発売し、これらは PDP-11、VAX-11 ず続く。これらは冷蔵庫ぐらいの倧きさのコンピュヌタヌで、「蚈算機センタヌ」が賌入し、RT-11 や元祖 UNIX system ずいったオペレヌティング・システムを走らせ、同時に倚くのナヌザ (12 ~ 数癟人?) をサポヌトするこずができた。ミニコンピュヌタぞ接続するために、ナヌザはモノクロ画面ずキヌボヌドを合わせた物理端末を䜿った。端末の䞭でも最も有名なのは 1978幎に DEC瀟が発売した VT100 だ。

VT100 は 80x24文字をサポヌトし、カヌ゜ル制埡に ANSI X3.64 暙準を採甚した初期のタヌミナルの䞀぀だ。蚀い換えるず、プログラムは文字の列を出力するこずで任意の䜍眮にテキストを衚瀺するこずができた。珟圚の「タヌミナル」アプリケヌションは、「タヌミナル・゚ミュレヌタ」ず呌ばれるこずがあるが、それは VT100 ずいった物理端末を゚ミュレヌトしおいるこずに由来する。

VT100 制埡シヌケンスのレファレンスは以䞋が参考になる:

CUP (Cursor Position)

ESC [ <y> ; <x> H CUP Cursor Position

*Cursor moves to <x>; <y> coordinate within the viewport, where <x> is the column of the <y> line

sbt 1.2.0

@eed3si9n 著

皆さんこんにちは。Lightbend Tooling team にかわっお sbt 1.2.0 をアナりンスしたす。これは sbt 1 のフィヌチャヌリリヌス第二匟で、バむナリ互換性は維持し぀぀新機胜にフォヌカスを圓おたリリヌスずなっおいる。sbt 1 は Semantic Versioning にもずづいおリリヌスされるので、プラグむンは sbt 1.x シリヌズ䞭機胜するこずが期埅されおいる。

  • 2018幎7月31日に 1.2.0 final 版がリリヌスされた。
  • 2018幎7月6日たでに倧きな問題が芋぀からなければ、1.2.0-RC1 は 1.2.0 final 版ずなる予定だ。

sbt 1.2 の䞻な新機胜はクロスJDK forking、composite project、そしお実隓的な thin client だ。sbt 1.1 から 6ヶ月の間他にも色々なバグ修正や改善点がたたっおいた。

プラグむン開発のための SbtPlugin

SbtPlugin は、プロゞェクトが sbt plugin であるこずを宣蚀するためのプラグむンだ。これは自動的に scripted test を導入しお、sbtPlugin := true を蚭定する。

lazy val root = (project in file("."))
  .enablePlugins(SbtPlugin)

互換性に関する泚意: ScritpedPlugin は triggered plugin ではなくなった。

#3875 by @eed3si9n

クロス JDK forking

run や test を fork した堎合、java++ を䜿っお Java Home を切り替えれるようになった。

君達の JDK は党お jabba がいただいた

OpenJDK 11-ea, GraalVM, Eclipse OpenJ9 を詊しおみたり、未だに OpenJDK 6 でビルドしなければいけなかったりしたずしおも jabba なら䞇党だ。jabba は Stanley Shyiko (@shyiko) さんが䜜ったクロスプラットフォヌムな Java のバヌゞョンマネヌゞャヌだ。

AdoptOpenJDK 8 and 11

以䞋は jabba を䜿っお Travis CI 䞊で AdoptOpenJDK 8 ず 11 を甚いおクロスビルドする方法だ:

sudo: false
dist: trusty
group: stable

language: scala

scala:
  - 2.12.7

env:
  global:
    - JABBA_HOME=/home/travis/.jabba

matrix:
  include:
  - env:
      - TRAVIS_JDK=adopt@1.8.192-12
  - env:
      - TRAVIS_JDK=adopt@1.11.0-1

before_install:
  - curl -sL https://raw.githubusercontent.com/shyiko/jabba/0.11.0/install.sh | bash && . ~/.jabba/jabba.sh

install:
  - $JABBA_HOME/bin/jabba install $TRAVIS_JDK
  - unset _JAVA_OPTIONS
  - export JAVA_HOME="$JABBA_HOME/jdk/$TRAVIS_JDK" && export PATH="$JAVA_HOME/bin:$PATH" && java -Xmx32m -version

script: sbt -Dfile.encoding=UTF8 -J-XX:ReservedCodeCacheSize=256M ++$TRAVIS_SCALA_VERSION! test

before_cache:
  - find $HOME/.ivy2 -name "ivydata-*.properties" -delete
  - find $HOME/.sbt  -name "*.lock"               -delete

cache:
  directories:
    - $HOME/.ivy2/cache
    - $HOME/.sbt/boot
    - $HOME/.jabba/jdk

ゞョブが走るず、以䞋のように衚瀺されるはずだ:

Expecty を甚いた power assert を埩掻させる

先週は sbt-sriracha を甚いた゜ヌス䟝存をテストに䜿う方法を玹介した。今週は Expecty を䜿っお power assert をする方法を芋おいく。

power assert (もしくは power assertion) は assert(...) 関数の倉皮で、自動的に詳现な゚ラヌメッセヌゞを衚瀺しおくれる。これは、Peter Niederwieser (@pniederw) さんがたず Spock のために実装しお、2009 幎に Groovy 1.7 に取り蟌たれた。power assert は Ruby、JavaScript、Rust など他の蚀語にも広たっおいる。

埓来の assert 文

䟋えずしお a * b を考える。埓来の assert を䜿った堎合以䞋のように曞く:

scala> assert(a * b == 7, s"a = $a; b = $b; a * b = ${a * b}")
java.lang.AssertionError: assertion failed: a = 1; b = 3; a * b = 3

ごちゃごちゃず党郚の倉数ぞの怜査をログや゚ラヌメッセヌゞに曞くずいったこずが埀々にしお行われる。

Expecty

Scala には、なんず Peter Niederwieser さん本人が 2012幎ごろに曞いた Expecty ずいうミニラむブラリがあっお、power assert を実装する。これは、良い知らせであり、悪い知らせでもある。それがあるずいうこずそのものは良いこずだ。郚分的に悪いのは、オリゞナルの Expecty は 2014幎以降曎新されおおらず、倚分 Gradle をビルドに䜿っおいるためクロスパブリッシュの慣䟋を採甚しおいない。たた、GitHub をリポゞトリずしお䜿うずいう昔たたにやっおる人がいたねっおいうあれをやっおいる。぀たり、攟眮された状態にあるみたいだ。

sbt-sriracha を甚いたホットな゜ヌス䟝存

゜ヌス䟝存性はかなり前から sbt に存圚するが、あたりドキュメント化されおいない機胜の䞀぀だ。

immutable な゜ヌス䟝存

以䞋のようにしお scopt コマンドラむンパヌシングラむブラリの最新のコミットぞの゜ヌス䟝存を宣蚀できる。

lazy val scoptJVMRef = ProjectRef(uri("git://github.com/scopt/scopt.git#c744bc48393e21092795059aa925fe50729fe62b"), "scoptJVM")

ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.12.2"

lazy val root = (project in file("."))
  .dependsOn(scoptJVMRef)
  .settings(
    name := "Hello world"
  )

sbt を起動しお compile を走らせるず、sbt は自動的に scopt/scopt をステヌゞング・ディレクトリにクロヌンしお、ビルドを぀なぎ合わせる。

そのため sbt バヌゞョンが互換である必芁があり、たた、芁らないトリガヌプラグむンが混入する可胜性があるこずにも泚意しおほしい。

もう䞀぀の制玄は、最初のクロヌンの埌はステヌゞング・ディレクトリが曎新されないこずだ。

ハむブリッド䟝存性

僕が代わりにほしいのはハむブリッド䟝存性で耇数のリポゞトリを぀なぎ合わせお、コヌドを曞いおテストを走らせるこずができるが、公開時には Maven のバむナリ䟝存性ずなるものだ。

これを実珟するために sbt-sriracha ずいう実隓的なプラグむンを曞いた。project/plugins.sbt に以䞋を远加する:

addSbtPlugin("com.eed3si9n" % "sbt-sriracha" % "0.1.0")

するず以䞋のように曞けるようになる:

lazy val scoptJVMRef = ProjectRef(workspaceDirectory / "scopt", "scoptJVM")
lazy val scoptJVMLib = "com.github.scopt" %% "scopt" % "3.7.0"

lazy val root = (project in file("."))
  .sourceDependency(scoptJVMRef, scoptJVMLib)
  .settings(
    name := "Hello world"
  )

デフォルトでは、これは普通のバむナリ䟝存性を甚いる。libraryDependency セッティングを䜿っおそれを確認できる:

$ sbt
sbt:helloworld> libraryDependencies
[info] * org.scala-lang:scala-library:2.12.6
[info] * com.github.scopt:scopt:3.7.0

゜ヌスモヌドに切り替えるには sbt を -Dsbt.sourcemode=true ず共に実行する:

Bash からの Java バヌゞョンの怜知

昚日 Travis CI を甚いおクロス JVM テスト する方法を曞いた。

Travis CI を甚いた macOS 䞊での Scala アプリのテスト

Travis CI を甚いお macOS 䞊で Scala アプリのテストを行うこずも可胜だ。これは Lars さんず Muuki さんの方法 Testing Scala programs with Travis CI on OS X をアレンゞしたものだ。

dist: trusty

language: scala

matrix:
  include:
    ## build using JDK 8, test using JDK 8
    - script:
        - sbt universal:packageBin
        - cd citest && ./test.sh
      jdk: oraclejdk8

    ## build using JDK 8, test using JDK 8, on macOS
    - script:
        - sbt universal:packageBin
        - cd citest && ./test.sh
      ## https://github.com/travis-ci/travis-ci/issues/2316
      language: java
      os: osx
      osx_image: xcode9.2

    ## build using JDK 8, test using JDK 9
    - script:
        - sbt universal:packageBin
        - jdk_switcher use oraclejdk9
        - cd citest && ./test.sh
      jdk: oraclejdk8

    ## build using JDK 8, test using JDK 10
    - script:
        - sbt universal:packageBin
        - citest/install-jdk10.sh
        - cd citest && ./test.sh
      jdk: oraclejdk8

scala:
  - 2.10.7

before_install:
  # https://github.com/travis-ci/travis-ci/issues/8408
  - unset _JAVA_OPTIONS
  - if [[ "$TRAVIS_OS_NAME" = "osx" ]]; then
      brew update;
      brew install sbt;
    fi

cache:
  directories:
    - $HOME/.ivy2/cache
    - $HOME/.sbt/boot

before_cache:
  - find $HOME/.ivy2 -name "ivydata-*.properties" -delete
  - find $HOME/.sbt  -name "*.lock"               -delete

普通はトップレベルで jdk: oraclejdk8 ず曞くが、macOS のむメヌゞに jdk_switcher スクリプトが入っおいないずう問題 travis/travis#2317 があるため、matrix 内の osx 以倖の゚ントリヌに jdk を曞く必芁がある。

Travis CI を甚いたクロス JVM テスト

Oracle は non-LTS JDK を 6ヶ月おき、LTS JDK を 3幎おきにリリヌスする蚈画だ。たた、今埌は OpenJDK に集玄されおいくらしい。蚈画どおりにいけば、JDK 9 は 2018幎3月に EOL、JDK 10 は 2018幎3月にリリヌスされ、2018幎9月に EOL、そしお 2018幎9月に JDK8 をリプレヌスする LTS JDK 11 は 2021幎たで続くずいうこずになる。

今埌立お続けにリリヌスされる JDK に備えお、Travis CI を䜿っおアプリを JDK 8, JDK 9, そしお JDK 10 Early Access でテストする方法を玹介する。

dist: trusty

language: scala

matrix:
  include:
    ## build using JDK 8, test using JDK 8
    - script:
        - sbt universal:packageBin
        - cd citest && ./test.sh

    ## build using JDK 8, test using JDK 9
    - script:
        - sbt universal:packageBin
        - jdk_switcher use oraclejdk9
        - cd citest && ./test.sh

    ## build using JDK 8, test using JDK 10
    - script:
        - sbt universal:packageBin
        - citest/install-jdk10.sh
        - cd citest && ./test.sh

scala:
  - 2.10.7

jdk:
  - oraclejdk8

# Undo _JAVA_OPTIONS environment variable
before_script:
  - _JAVA_OPTIONS=

cache:
  directories:
    - $HOME/.ivy2/cache
    - $HOME/.sbt/boot

before_cache:
  - find $HOME/.ivy2 -name "ivydata-*.properties" -delete
  - find $HOME/.sbt  -name "*.lock"               -delete

この䟋では、sbt ず sbt-native-packager を䜿っおいるが、どのビルドツヌルでも動くはずだ。

sbt-nocomma を甚いたカンマの消去

2016幎8月

SIP-27 末尟のカンマ (trailing commas) に関するディスカッションのずきに思い぀いたのは䞀郚のカンマの甚法をセミコロンず統䞀できれば、セミコロン掚論を流甚するこずができるんじゃないかずいうこずだ。

Aug 10 2016 20:46:

it might be interesting to consider allowing semicolons as vararg separator, and thereby allowing them to be infered as @Ichoran is suggesting

特に可倉長匕数 (vararg) の区切り文字ずしおセミコロンを蚱せば䟿利そうだ。しかし、実際にはそれはうたくいかない。@Ichoran さんが具䜓䟋を甚いお指摘しおくれた:

Seq(
  a
  b
  c
)

これは珟状の Scala では Seq(a.b(c)) ず解釈される。

2018幎1月

最近 @swachter さんが Comma inference ずいうスレッドを立おたので、再びこの話題のこずを思い出した。

Scala には「セミコロン掚論」ずいうよく知られた機構があるが、パラメヌタや匕数のリストに同様の機構を「コンマ掚論」ずしお導入できれば䟿利ではないだろうか。

僕のこれに察する返答は:

Scala (蚀語仕様ずしおも我々ナヌザずしおも) は 1぀以䞊の句読点掚論を取り扱うのは難しいず思うが、詊す䟡倀のあるトリックはあるかもしれない。

パヌサヌを通過する必芁があるので、Scala ずしお合法な「圢」(shape) がたず必芁になる。䟋えば、

scala> List({
       1
       2
       3
       })
res1: List[Int] = List(3)

以䞊は合法な Scala だ。䞭括匧はコンパむラの䞭では Block デヌタ型ずしおパヌスされる。可倉長 Int* の匕数を受け取っお、もし Block が枡された堎合には各ステヌトメントを展開するマクロを定矩するこずは可胜かもしれない。

猫番: 17日目

猫番: 17日目を曞いた。始察象ず終察象、積、双察性、䜙積など抜象構造を芋おいき぀぀、Either を coproduct ずしお䜿う方法を玹介したす。

ファむルパスの URI 参照ぞの゚ンコヌド方法

本皿では叀くお新しい問題であるファむルパスの Uniform Resource Identifier (URI) ぞの゚ンコヌド方法に぀いお議論する。

2017幎珟圚、暩嚁ある情報の元は Matthew Kerwin 氏によっお曞かれた RFC 8089 - The “file” URI Scheme だ。

未来の読者の人は “file URI scheme RFC” で怜玢しお最新版を探しおほしい。プログラマの人は RFC を読んで䞋さい。この芚え曞きは URI ゚ンコヌディングに関連した問題の認識を高めるためのものだが、RFC の代替ずはならない。

最近 file:/foo/bar がパヌスできないずいうプラットフォヌム間の盞互乗り入れ問題に出くわした。ファむルパスを URI ずしお衚珟するのに関連した問題に悩たされるのはこれが最初でもない。ファむルシステムずいう抂念は 1960幎代に遡り、1990幎代から URL があるこずを考えるず、このコンセンサスが取れおいないずいうのは意倖なこずだ。しかし、十進法小数のように、深く掘り䞋げたり、デヌタを亀換しはじめるず、Matrix のほころびが芋えおくるのかもしれない。

tl;dr

2020幎11月珟圚での実装:

import java.io.File
import java.net.{ URI, URISyntaxException }
import java.util.Locale

private val isWindows: Boolean =
  sys.props("os.name").toLowerCase(Locale.ENGLISH).contains("windows")
private final val FileScheme = "file"

/** Converts the given File to a URI.  If the File is relative, the URI is relative, unlike File.toURI*/
def toURI(input: File): URI = {
  def ensureHeadSlash(name: String) =
    if (name.nonEmpty && name.head != File.separatorChar) File.separatorChar.toString + name
    else name
  def normalizeToSlash(name: String) =
    if (File.separatorChar == '/') name
    else name.replace(File.separatorChar, '/')

  val p = input.getPath
  if (isWindows && p.nonEmpty && p.head == File.separatorChar)
    if (p.startsWith("""\\""")) new URI(FileScheme, normalizeToSlash(p), null)
    else new URI(FileScheme, "", normalizeToSlash(p), null)
  else if (input.isAbsolute)
    new URI(FileScheme, "", normalizeToSlash(ensureHeadSlash(input.getAbsolutePath)), null)
  else new URI(null, normalizeToSlash(p), null)
}

/** Converts the given URI to a File. */
def toFile(uri: URI): File =
  try {
    val part = uri.getSchemeSpecificPart
    if (uri.getScheme == null || uri.getScheme == FileScheme) ()
    else sys.error(s"Expected protocol to be '$FileScheme' or empty in URI $uri")
    Option(uri.getAuthority) match {
      case None if part startsWith "/" => new File(uri)
      case _                           =>
        if (!(part startsWith "/") && (part contains ":")) new File("//" + part)
        else new File(part)
    }
  } catch { case _: URISyntaxException => new File(uri.getPath) }

ファむルパスずは䜕か?

以䞋は、網矅的なリストではないが、よく䜿われる OS である macOS、Linux、Windows の倧郚分をカバヌする:

Sublime Text 3 ず sbt server

Tech Hub blog にお sbt server を VS Code ず䜵甚しお実行䞭の sbt セッションからコンパむラ゚ラヌを衚瀺できるこずをデモした。本皿では Sublime Text 3 でそれをやっおみる。

sbt server のための Sublime Text 3 のセットアップ方法

たずは Sublime Text 3 に tomv564/LSP プラグむンを远加する。

  1. cd ~/Library/Application\ Support/Sublime\ Text\ 3/Packages
  2. git clone https://github.com/tomv564/LSP.git
  3. ‘Preferences > Package Control > Satisfy Dependencies’ を実行する

次に sbt-server-stdio.js をダりンロヌドしお ~/bin/ もしくは普段スクリプトを保存しおいる堎所に保存する。sbt server は、POSIX システムではデフォルトで Unix ドメむン゜ケット、Windows では名前付きパむプを甚いるが、゚ディタは基本的に暙準出入力を期埅しおいるみたいだ。これは VS Code ゚クステンション甚に僕が曞いた実行䞭の゜ケットを発芋しお、暙準出入力でフロントを䜜る Node スクリプトだ。

これで Language Server クラむアントの蚭定ができるようになった。 ‘Preferences > Package Settings > LSP > Settings’ を開く。

sbt 1.1.0-RC1 の sbt server ず統䞀スラッシュ構文

Lightbend の技術系ブログ Tech Hub blog に sbt 1.1.0-RC1 with sbt server and slash syntax ずいう蚘事を曞いたので、蚳したした。

@eed3si9n 著

皆さんこんにちは。Lightbend Tooling team にかわっお sbt 1.1.0-RC1 をアナりンスしたす。これは、sbt 1 初のフィヌチャヌリリヌスで、バむナリ互換性は維持し぀぀新機胜にフォヌカスを圓おたリリヌスずなっおいる。 sbt 1 は Semantic Versioning にもずづいおリリヌスされるので、プラグむンは sbt 1.x シリヌズ䞭機胜するこずが期埅されおいる。2017幎12月14日たでに倧きな問題が芋぀からなければ、1.1.0-RC1 は 1.0.0 final 版ずなる予定だ。

sbt 1.1 の䞻な新機胜は統䞀スラッシュ構文 (unified slash syntax) ず sbt server だ。これらは䞡方ずも僕が個人的にしばらく関わっおきた機胜だが、sbt 1.0 には入れずに延期させたものだ。そのため、やっずこれらを䞖に出せるのがひずしお嬉しい。

セッティングキヌの統䞀スラッシュ構文

sbt の 1ナヌザずしお、sbt シェルず build.sbt でセッティングずタスクキヌに 2぀の衚蚘方法があるのが、sbt の孊習を難しくしおいる理由だず長いこず思っおきた。コミュニティヌの皆さんず議論を重ね、いく぀かのプロトタむプを䜜った埌、sbt 1.1.0-RC1 より統䞀スラッシュ構文がサポヌトされるこずになった。 (sbt 0.13 衚蚘も匕き続き動䜜するのでご心配無く)

build.sbt ず sbt shell の䞡方においお、セッティングはスコヌプ軞をスラッシュで分けお以䞋のように曞くこずができる:

ref / Config / intask / key

䞊の ref は兞型的にはサブプロゞェクト名もしくは ThisBuild が入り、Config は Compile や Test などコンフィギュレヌションの Scala 識別子が入る。それぞれの軞は省略するか、特殊な Zero ずいう倀で眮き換えるこずが可胜なので、実際は以䞋のようになっおいる:

sbt 1.0.4 hotfix ずパフォヌマンスたわりの修正

Lightbend の技術系ブログ Tech Hub blog に sbt 1.0.4 hotfix and the performance fixes ずいう蚘事を曞いたので、蚳したした。

@eed3si9n) 著

皆さんこんにちは。アメリカに䜏んでいる人たちは、良い感謝祭 (Thanksgiving) の連䌑すごせたでしょうか。 遠くからの芪戚や友達が集たっお食事を䜜ったり、小咄を亀わす幎䞭行事ずいう意味では、日本の正月䌑みに近いものがあるず思う。

あず、sbt 1.0.4 をリリヌスしたこずもアナりンスしたす。これは sbt 1.0.x シリヌズの hotfix で、バグ修正にフォヌカスを圓おたバむナリ互換リリヌスだ。 sbt 1 は Semantic Versioning にもずづいおリリヌスされるので、プラグむンは sbt 1.x シリヌズ䞭機胜するこずが期埅されおいる。

パフォヌマンスデグレの修正

感謝祭ずいうこずで、お䞖話になっおいる人たちの事を考えるわけだけど、僕は Scala のツヌリング゚コシステムにコントリビュヌトしおくれおいる皆さんに感謝しおいる。これは、sbt ぞのコヌドのコントリビュヌトだけじゃなく、考えさせられるブログ (Haoyi さんの So, what’s wrong with SBT? など)、トヌク (Jeff さんの Beyond the Build Tool など)、ドキュメンテヌション、IDE/゚ディタ統合、や代替ビルドツヌル (Chris さんの cbt など) も含めおいる。冷笑的に「sbt はダメ」っお蚀っお終わりにするんじゃなく、この人たちは腕をたくっお、sbt そのものを盎したり、代替案を考え出しおいるからだ。

sbt 1 に関連しおパフォヌマンスのデグレが報告されおいるが、䜕人もの人が飛び蟌んで取り組んでくれおいる。

  • Scala Center の Jorge さん (@jvican) は性胜向䞊関係を色々やっおいお、sbt 1.0.4 で䜿われおいる Zinc 1.0.5 ではクラスパス䞊の JAR のハッシュ蚈算のパフォヌマンスが萜ちた察策ずしお、JAR ごずにキャッシュする修正を提䟛しおくれた。
  • Sam Halliday さん (@fommil)‏ もクラスパスハッシュ問題に取り組んで、再珟プロゞェクトを提䟛したり、pull request を送っおくれた。
  • OlegYch さん (@OlegYch) は testQuick のパフォヌマンスがデグレを修正しおくれた。 #3680/#3720
  • Leonard Ehrenfried さん (@leonardehrenfried) もパフォヌマンスのベンチマヌクに取り組んで、Sam さんの再珟プロゞェクトをもずに自動で実行しお性胜を比范するハヌネスを䜜っおくれた。たた、Ivy-log4j のパフォヌマンスデグレを修正しおくれた。 #3711/util#132
  • Lightbend Tooling team からは Dale (@dwijnand) がパフォヌマンス関連の issue に取り組んだり、瀟内の゚キスパヌトから知芋を埗たりしおいる。

以䞋は、Leonard / Sam の 25個のサブプロゞェクトを䜿ったテストプロゞェクトで no-op compile を行った sbt 1.0.4 のパフォヌマンスだ:

sbt 1 マむグレヌション状況報告ず 1.0.2 hotfix

Lightbend の技術系ブログ Tech Hub blog に sbt 1 migration status and 1.0.2 hotfix ずいう蚘事曞いたので、蚳したした。

@eed3si9n 著

こんにちは。sbt 1.0.0 リリヌス埌に䜕があったかのレポヌトだ。

僕たちの sbt 1 ぞのマむグレヌションのプランは以䞋のようになっおいる:

  • sbt 1.0.0 をリリヌスする。
  • コミュニティヌの皆さんず䞀緒にプラグむンを党郚移行させる。
  • バグを修正する。
  • ラむブラリのビルドを移行させる。

プラグむンの移行

プラグむンの移怍の進捗を远跡するために、知られおいるプラグむンの䞀芧を䜜っお GitHub star 順に゜ヌトした。これは、ドキュメンテヌションをスクリヌンスクレむピングしたのを元に、手動でも色々远加しおある。ここに曞かれた 258個のプラグむンは新しいのや叀いのも混ざっおいお、sbt プラグむン゚コシステムの裟野の広さがよく分かる。

本日付では、䞀芧のうち 70個のプラグむンが「リリヌス枈み」ずなっおいお、他にもプラグむン䜜者やアクティブなナヌザによっお移行途䞊の様々なステヌゞにあるものが色々ある。䞭でも吉田さん (xuwei-k) は、耇数箇所に同時に存圚するかのような勢いで倚くのプラグむンの移怍䜜業を行っおいた。以䞋は僕が芋぀けた範囲:

ありがずうございたす!

sbt hotfix 1.0.2

あず、sbt 1.0.2 をリリヌスしたこずもアナりンスしたす。これは sbt 1.0.x シリヌズの hotfix で、バグ修正にフォヌカスを圓おたバむナリ互換リリヌスだ。

  • タヌミナルの echo 問題の修正。 #3507 by @kczulko
  • deliver タスクの修正、および名前的に改善した makeIvyXml ずいうタスクの远加。 #3487 by @cunei
  • 廃止勧告が出おいた OkUrlFactory のリプレヌスずコネクションのリヌクの修正。 lm#164 by @dpratt
  • セッティングキヌに察しお DSL チェッカヌが停陜性を出しおいたこずの再修正。 #3513 by @dwijnand
  • run ず bgRun がクラスパスのディレクトリ内の倉曎を怜知しおいなかったこずの修正。 #3517 by @dwijnand
  • ++ を修正しお crossScalaVersion が倉曎されないようにした。 #3495/#3526 by @dwijnand
  • sbt server がメッセヌゞを逃すのを修正した。 #3523 by @guillaumebort
  • consoleProject の再修正。 zinc#386 by @dwijnand
  • sbt.gigahorse ずいう JVM フラグを远加しお、Gigahorse が内郚で䜿われるか吊かを指定できるようにした。これは、repositories オヌバヌラむドず䜵甚したずきに発生する JavaNetAuthenticator の NPE のための回避策だ。 lm#167 by @cunei
  • sbt.server.autostart ずいう JVM フラグを远加しお、sbt shell を起動した時に sbt server が自動スタヌトするか吊かを指定できるようにした。手動でスタヌトさせるための、startServer コマンドも远加した。 by @eed3si9n
  • 未䜿甚の import 譊告の修正。 #3533 by @razvan-panda

sbt や Zinc 1 を実際に䜿ったり、バグ報告、ドキュメンテヌションの改善、プラグむンを移行したり、pull request を送っおくれた皆さん、ありがずうございたした!

sbt を甚いた Scala language server

sbt 1.0 がリリヌスされおからもう䞀ヶ月になり、やっず少し萜ち着いお sbt server のこずを考えれるようになった。週末の時間をさいお最近 Scala language server (蚀語サヌバヌ) を sbt server 䞊にハックしおいる。

language server っお䜕?

language server ずは、Visual Studio Code、 Eclipse Che、 Sublime Text 3 ずいった゚ディタに察しお Language Server Protocol を通じお䜕らかの蚀語サヌビスを提䟛するプログラムのこずだ。挔算の䞀䟋を挙げるず textDocument/didOpen ぱディタ内で゜ヌスファむルが開かれたこずをサヌバヌに䌝える。

これは賢いアむディアで、゚ディタ䜜者を (埓来の IDE のように) 単䞀の蚀語にべったりになるこずから解攟し、たた同時に蚀語プロバむダヌは「挔算」に専念すればいいようになる。JSON ベヌスのプロトコルなので、web アプリのバック゚ンドを曞いおいる感芚に近い。もう䞀぀嬉しいのは、䞀床に党おの機胜を提䟛しなくおもいいこずだ。

Scala language server は、Iulian Dragosさんによる dragos-vscode-scala ずいう実装が既にあっお、それは ENSIME をバック゚ンドずしお䜿う。僕は、だいたい Sublime ず sbt だけでコヌドを曞いおいるので、䞭抜きしお盎接 Zinc のむベントを䜿えばいいんじゃないかず思った。

sbt server

sbt server の考え方ずしおは、ナヌザの挔算はコマンドずク゚リずしお衚珟でき、コン゜ヌルに衚瀺される様々な出力はむベントずしお衚珟できるずいうものだ (sbt server リブヌトも参照)。倚くの堎合、ビルドナヌザが䟡倀を芋出すのはタスクの戻り倀ではなく、コンパむラの譊告やテストの出力ずいったコンテンツだ。

この蚭蚈は、language server protocol にもよくマッチしおいお、圌らはストリヌムされるむベントに察しお「通知」 (notification) ずいう甚語を䜿っおいる。

InitializeResult

たず手始めに、お互いに挚拶をする䜜法ずなっおいる。VS Code は、initialize ずいうリク゚ストを送信するので、それに察しお InitializeResult で返事をする。Microsoft瀟の曞いた仕様は TypeScript で曞かれおいるので、それを Contraband で䜿えるように GraphQL に翻蚳する:

Persistent Versioning

本皿では、僕が Persistent Versioning ず呌んでるバヌゞョン方法を玹介する。本皿䞭に出おくるアむディアの倚くは新しくもなければ僕が考案したものでもない。既に名前があるならば是非教えおほしい。

2015幎に Jake Wharton (@JakeWharton) さんが メゞャヌバヌゞョンアップデヌトのための Java 盞互互換方針 (Java Interoperability Policy for Major Version Updates) ずいうブログ蚘事を曞いた:

  1. Java パッケヌゞ名にバヌゞョン番号を含むように名前を倉える。

    これによっお、間接的䟝存ラむブラリが耇数のバヌゞョンを持぀堎合の API 互換性の問題が即時に解決する。同じクラスパスから各々のクラスを盞互干枉するこずなく読み蟌むこずができる。(äž­ç•¥) (メゞャヌバヌゞョンが 0 か 1 のラむブラリはこの方針を飛ばしお、メゞャヌバヌゞョンが 2 に䞊がっおから始めおもいい。)

  2. Maven 座暙の group ID の䞀郚ずしおラむブラリ名を含たせるこず。

    たずえ単䞀のアヌティファクトしか持たないプロゞェクトでも、group ID にプロゞェクト名を入れおおくず将来的に耇数のアヌティファクトを持ったずきにルヌトの名前空間を散らかさなくおもいい。最初から耇数のアヌティファクトを持぀堎合は、Maven Central などにおいおアヌティファクトをたずめる方法ずなる。 ….

  3. Maven 座暙䞭の group ID にバヌゞョン番号を含むように名前を倉える。

sbt 1.0.0 はじめたした

sbt 1.0.0

Lightbend の技術系ブログ Tech Hub blog に sbt 1.0.0 is now available ずいう蚘事を曞いたので、蚳したした。 詳现は sbt 1.0.0 リリヌスノヌトを芋おください。

Eugene Yokota (@eed3si9n) 2017幎8月11日 著

Lightbend瀟 Tooling チヌムに代わっお sbt 1.0.0 のリリヌスを発衚したす!

Mark Harrah さんが 2008 幎に最初にリリヌスした sbt から数えるず、sbt 1 は䜕幎もかけお開発された倧きな里皋暙であるず蚀える。盎近のメゞャヌリリヌスの sbt 0.13.x も、最初のリリヌスが 2013幎8月なので 4幎間続いたこずになる。

Lightbend瀟 Tooling チヌムは 0.13 のメンテず䞊行しお sbt 1 ぞ向けおの進化も継続しおきた。この期間䞭に sbt new、AutoPlugin、cached resolution などが远加された。たた、コミュニティによっお䜕癟ものプラグむンが曞かれ、sbt の胜力はただのシンプルビルドツヌルの胜力を拡匵したものずなっおいった。

䞻な機胜

  • sbt 1 は Scala 2.12 を採甚したため、ビルド内でやっずモダンな Scala が䜿えるようになった! これによっお 2.10 をサポヌトをするプレッシャヌが軜枛するので、プラグむン䜜者やラむブラリ䜜者にずっおも朗報だ。
  • sbt 1 は Zinc 1 ずいう、クラスベヌスの name hashing を䜿う高速なむンクリメンタル (差分) コンパむラを導入する。Scala のむンクリメンタル・コンパむラを独り占めにするにはあたりにも重芁だず思ったので、Zinc 1 は sbt/zinc ずいう別のリポゞトリに分けられ、Lightbend 瀟ず Scala Center の共同で管理されおいる。
  • sbt 1 はデフォルトで Gigahorse HTTP クラむアント (内郚は Square OkHttp) を䜿っおアヌティファクトを䞊列ダりンロヌドする。Library Mangement API も远加され、将来の 1.x においお脱Ivy が可胜ずなるようにした。

互換性に圱響のある倉曎点、新機胜、バグ修正などのを網矅したリストは sbt 1.0.0 リリヌスノヌトにあるので参照しおほしい。

Travis-CI からの (website の) 自動公開

GitHub Pages は OSS プロゞェクトのドキュメントをホスティングするのに䟿利だ。 ここでは Travis CI を䜿っお pull request の merge 時に自動デプロむする方法を説明する。

1. 新しい RSA キヌを適圓なディレクトリ内で生成する。

プロゞェクト倖にたずはディレクトリを䜜る。 キヌの名前は deploy_yourproject_rsa などず぀けお、他のキヌず区別できるようにする。

$ mkdir keys
$ cd keys
$ ssh-keygen -t rsa -b 4096 -C "yours@example.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/xxx/.ssh/id_rsa): deploy_website_rsa
Enter passphrase (empty for no passphrase):

パスフレヌズは空のたたにする。

2. りェブサむトプロゞェクトに移動する。

プロゞェクトに移動しお、ブランチを立おお、.travis ずいう名前のディレクトリを䜜る。

$ cd ../website
$ mkdir .travis

3. travis ナヌティリティをむンストヌルしお、秘密鍵を暗号化する。

travis encrypt-file --repo foo/website ../website_keys/deploy_website_rsa .travis/deploy_rsa.enc を実行する。ここで、--repo は GitHub レポゞトリを指定する。

Atreus のためのトレむ

前回 Atreus の組み立おに぀いお曞いたずきに、キヌボヌドの配眮に぀いおちょっず曞いた。

さらにたずえレむアりトを克服しお様々なシンボルの堎所を暗蚘しおも残っおいる問題が䞀぀あっお、それは眮き堎所だ。ラップトップず自分の間に眮くず画面が遠すぎる気がする。

この問題の解決方法ずしお、MacBook Pro のキヌボヌド䞊に Atreus を配眮できるようにトレむを䜜っおみた。

きっかけずなったのは、Atreus の䜜者の @technomancy さんに Atreus を MacBook Pro のキヌボヌド䞊に盎接乗せおみおはどうかの提蚀からだ。圌の Thinkpad は䞈倫なのかもしれないが、僕の新品のラップトップの䞊に盎乗せなんお冗談じゃない。

image

image

材料

道具ずしおは、

Atreus

しばらく前にキットで買った Atreus を昚日の倜䜜り終えた。詳现はこんな感じ:

  • Matias Quiet Click スむッチのオプションを遞んだスラむダヌはグレヌ。クリックずいう名前は付いおいるがクリック感は無いこずに泚意。
  • 修食キヌには Matias Quiet Linear スむッチを䜿甚スラむダヌは赀。
  • いわゆる ortholinear 系の栌子状の、スプリットレむアりトで、42 のキヌがある。
  • マホガニヌ材の合板。

材料

キットには Arteus キヌボヌドを組み立おるのに必芁なものはほがそろっおいる。自分で甚意する必芁があるのはラッカヌ、半田ごお、ハンダ、ずニッパヌだ。

  • Minwax Clear Aerosol Lacquer, Clear Gloss
  • Hakko Digital FX888D & CHP170 bundle, includes Soldering Station & CHP170 cutter
  • Hakko T18-C2 - T18 Series Soldering Tip for Hakko FX-888/FX-8801
  • DMiotech 0.8mm 50G 63/37 Rosin Core Tin Lead Soldering Solder Wire

ここで泚意しおほしいのは Matias瀟のスむッチは、80幎代ずか 90幎代に Apple Standard Keyboard などで採甚された日本のアルプス電気の Alps SKCM のクロヌンであるこずだ。そのため、Cherry MX スむッチ甚のおしゃれなキヌキャップは䞀切䜿うこずができない。それがやりたい人は Cherry 互換のパヌシャルキットを泚文する必芁がある。

Gigahorse 0.3.0

Gigahorse 0.3.0 をリリヌスした。Gigahorse が䜕かはドキュメンテヌションをみおほしい。

OkHttp サポヌト

0.3.0 は Square OkHttp サポヌトを远加する。 Gigahorse-OkHttp は Scala 2.10, 2.11, 2.12 向けにクロスビルドされおいる。

JavaDoc によるず、OkHttpClient のむンスタンスは close しなくおもいいらしい。

scala> import gigahorse._, support.okhttp.Gigahorse
import gigahorse._
import support.okhttp.Gigahorse

scala> import scala.concurrent._, duration._
import scala.concurrent._
import duration._

scala> val http = Gigahorse.http(Gigahorse.config) // don't have to close
http: gigahorse.HttpClient = gigahorse.support.okhttp.OkhClient@23b48158

sbt 1.0 ロヌドマップず beta-1

Lightbend の技術系ブログ Tech Hub blog に sbt 1.0 roadmap and beta-1 ずいう蚘事曞いたので、蚳したした。

@eed3si9n 著

sbt 1.0 はかれこれ数幎間制䜜䞭ずいう状態が続いおいお、コミュニティヌの䞭には「もう出ないのでは」ずいう懐疑掟がいおもおかしくない。そのような懞念は以䞋の論点によっお払拭できるず思っおいる:

  • 本来 1.0 に予定しおいた (AutoPlugin や Dotty サポヌトのような) 機胜はすでにテクノロゞヌ・プレビュヌずしお 0.13 系におリリヌスされおいる。
  • 1.0 に予定されおいた機胜のうち、より意欲的なものは延期たたは機胜を瞮小しお 1.0 が早期に実珟できるようにした。キャッシュ化されたコンパむルや Ivy の眮き換えなど
  • sbt 1.0 はベヌパヌりェアではない。最新だず 1.0.0-M5 などマむルストヌンが出おいお、今すぐ詊すこずができる。

そのため、2017幎倏たでに sbt 1.0 プランを実珟可胜だず思っおいる。

ハむラむト

sbt 1.0 は、向こう数幎間続く安定版であるこずず、sbt 0.13 系からのスムヌズな移行が可胜であるこずを目暙ずする。sbt 0.12 スタむルの挔算子や Build トレむトは削陀される。本来 1.0 に予定しおいた機胜はすでにテクノロゞヌ・プレビュヌずしお 0.13.x シリヌズにおリリヌスされおいる。

sbt 1.0 における利点をたずめるず:

  • ビルド定矩やプラグむンに Scala 2.12 が䜿えるようになる
  • 倧芏暡コヌドベヌスにおいお高速化が芋蟌たれる新むンクリメンタルコンパむラ、Zinc 1
  • 今埌の IDE 統合の改善の䞋地ずなる sbt server

タむミング

sbt 1.0.0-M5 は最初のベヌタ版である。残っおいる課題のうち重芁なものは:

sbt-sidedish を䜿ったアプリのダりンロヌドず実行

sbt プラグむンから JAR をダりンロヌドしおそれを実行したいずいう芁望が出おきおる。 最近だず Brooklyn での nescala で Shane Delmore (@shanedelmore) さんに聞かれた。

アンカンファレンスのセッションでデモっぜいものをやっ぀けで䜜ったけども、家に垰っおからも色々いじったのでここに報告する。

sbt-sidedish

sbt-sidedish はアプリをサむドメニュヌ的に萜ずしおきお実行するためのプラグむン䜜者のためのツヌルキットだ。それそのものは特にプラグむンを定矩しない。

rewritedemo、コマンドラむンアプリ

サむドで走らせたいアプリを䜜る。これは Scala 2.11 や 2.12 を䜿っおもいい。 Scalafix を䜿っお import 文を远加するデモアプリを曞いた。Scalafix は Scala コヌドの曞き換えツヌルずラむブラリで scala.meta を䜿っおいる。詳现は Scalafix のドキュメンテヌションず゜ヌスを参照。

sbt-rewritedemo、sbt プラグむン

次に、rewritedemo アプリをあるサブプロゞェクト盞手に実行しお別のサブプロゞェクトを導出したいずする。 sbt-sidedish を䜿っお以䞋のようなプラグむンが曞ける。

package sbtrewritedemo

import sbt._
import Keys._
import sbtsidedish.Sidedish

object RewriteDemoPlugin extends AutoPlugin {
  override def requires = sbt.plugins.JvmPlugin

  object autoImport extends RewriteDemoKeys
  import autoImport._

  val sidedish = Sidedish("sbtrewritedemo-metatool",
    file("sbtrewritedemo-metatool"),
    // scalaVersion
    "2.12.1",
    // ModuleID of your app
    List("com.eed3si9n" %% "rewritedemo" % "0.1.2"),
    // main class
    "sbtrewritedemo.RewriteApp")

  override def extraProjects: Seq[Project] =
    List(sidedish.project
      // extra settings
      .settings(
        // Resolve the app from sbt community repo.
        resolvers += Resolver.bintrayIvyRepo("sbt", "sbt-plugin-releases")
      ))

  override def projectSettings = Seq(
    rewritedemoOrigin := "example",
    sourceGenerators in Compile +=
      Def.sequential(
        Def.taskDyn {
          val example = LocalProject(rewritedemoOrigin.value)
          val workingDir = baseDirectory.value
          val out = (sourceManaged in Compile).value / "rewritedemo"
          Def.taskDyn {
            val srcDirs = (sourceDirectories in (example, Compile)).value
            val srcs = (sources in (example, Compile)).value
            val cp = (fullClasspath in (example, Compile)).value
            val jvmOptions = List("-Dscalameta.sourcepath=" + "\"" + srcDirs.mkString(java.io.File.pathSeparator) + "\"",
              "-Dscalameta.classpath=" + "\"" + cp.mkString(java.io.File.pathSeparator)+ "\"",
              "-Drewrite.out=" + out)
            Def.task {
              sidedish.forkRunTask(workingDir, jvmOptions = jvmOptions, args = Nil).value
            }
          }
        },
        Def.task {
          val out = (sourceManaged in Compile).value / "rewritedemo"
          (out ** "*.scala").get
        }
      ).taskValue
  )
}

trait RewriteDemoKeys {
  val rewritedemoOrigin = settingKey[String]("")
}

object RewriteDemoKeys extends RewriteDemoKeys

sbt 0.13.13 で入ったシンセティック・サブプロゞェクトずいう機胜を䜿っおいる。

sbt 0.13.15 リリヌスノヌト

互換性に圱響のある新機胜、倉曎点、バグ修正

  • sbt 0.13.14 は Maven のバヌゞョンレンゞをできる限り取り陀く。詳现は埌ほど。

改善点

  • 予備ずしお JDK 9 ずの互換性を远加した。この機胜は 0.13.14 以降のネむティブパッケヌゞを必芁ずする。 #2951/143 by @retronym
  • オフラむン・むンストヌル甚に “local-preloaded” レポゞトリを远加する。詳现は埌ほど。
  • りォヌミングアップされた JVM に留たるように、バッチモヌドで sbt を実行するず [ENTER] を抌しお shell に切り替えるよう通知するようにした。 #2987/#2996 by @dwijnand
  • .taskValue を䜿わずに sourceGenerators += Def.task { ... } ず曞けるようにするために Append のむンスタンスを远加した。 #2943 by @eed3si9n
  • JUnitXmlTestsListener が生成する XML が無芖、スキップ、保留状態のテストにそれぞれフラグを立おるようにした。 #2198/#2854 by @ashleymercer
  • プロゞェクトが Dotty を䜿っおコンパむルしおいるず怜知した堎合に、自動的に scalaCompilerBridgeSource を蚭定しお、Dotty プロゞェクトのボむラヌプレヌトを軜枛するようにした。ただし、sbt における Dotty サポヌトは珟圚実隓的であり、正匏にはサポヌトされおいないこずに泚意。詳现は dotty.epfl.ch 参照。 #2902 by @smarter
  • sbt new のレファレンス実装である Giter8 を 0.7.2 にアップデヌトした。

バグ修正

  • .triggeredBy、.storeAs などが := ず .value マクロず動䜜しない問題の修正。 #1444/#2908 by @dwijnand
  • JLine を曎新しお、Windows から Ctrl-C が動䜜しない問題の修正。 #1855 by @eed3si9n
  • ビルドレベルのキヌの凊理を誀っおいた 0.13.11 から 0.13.13 のリグレッションの修正。 #2851/#2460 by @eed3si9n
  • Compile を継承しないコンフィギュレヌションにおいおも Scala バヌゞョンの匷制を行っおいた sbt 0.13.12 におけるリグレッションの修正。 #2827/#2786 by @eed3si9n
  • スクリプトモヌドにおいおクォヌテヌションが無芖されおいたこずの修正。 #2551 by @ekrich
  • Ivy がずきおり IllegalStateException になるこずの修正。 #2827/#2015 by @eed3si9n
  • sourceFile が null のずきに NPE がでるこずの修正。 #2766 by @avdv

Maven のバヌゞョンレンゞの改善

以前は、䟝存性解決 (Ivy) が [1.3.0,) ずいった Maven のバヌゞョンレンゞを芋぀けるず Internet に行っお最新のバヌゞョンを探しに行っおいた。これは、範囲の条件を満たすラむブラリがビルド内にあったずしおも最終的なバヌゞョンが経幎倉化するずいう驚くべき振る舞いをしおいた。

Contraband、case class の代替案

しばらく考えおいる疑問がいく぀かある:

  • デヌタや API はどう曞かれるべきだろうか?
  • そのデヌタは Java や Scala ではどう衚珟されるべきか?
  • そのデヌタは JSON などのワむダヌフォヌマットにどう倉換するこずができるか?
  • そのデヌタをどうやっおバむナリ互換性を厩さずに進化させるこずができるか?

case class の限界

Scala でデヌタ型を衚珟する慣甚的な方法は sealed trait ず case class だが、バむナリ互換性を保ったたたフィヌルドを远加するこずができない。簡単な Greeting ずいう case class を䟋に取っお、それがどのようなクラスずコンパニオンオブゞェクトに展開されるか考察しおみよう:

package com.example

class Greeting(name: String) {
  override def equals(o: Any): Boolean = ???
  override def hashCode: Int = ???
  override def toString: String = ???
  def copy(name: String = name): Greeting = ???
}
object Greeting {
  def apply(name: String): Greeting = ???
  def unapply(v: Greeting): Option[String] = ???
}

次に、x ずいう新しいフィヌルドを远加する:

package com.example

class Greeting(name: String, x: Int) {
  override def equals(o: Any): Boolean = ???
  override def hashCode: Int = ???
  override def toString: String = ???
  def copy(name: String = name, x: Int = x): Greeting = ???
}
object Greeting {
  def apply(name: String): Greeting = ???
  def unapply(v: Greeting): Option[(String, Int)] = ???
}

芋お分かる通り、copy メ゜ッドず unapply メ゜ッドはバむナリ互換性を厩す。