From 4273de5699d59b9e4943342ba9e18c4d15fbee3b Mon Sep 17 00:00:00 2001 From: Eugene Yokota <eed3si9n@gmail.com> Date: Sat, 21 Sep 2019 19:17:58 -0400 Subject: [PATCH 1/3] drop build loader build loader is no longer available. Fixes https://github.com/sbt/website/issues/571 --- .../10-DevGuide-Notes/04-Build-Loaders.md | 283 ------------------ 1 file changed, 283 deletions(-) delete mode 100644 src/reference/90-Developers-Guide/10-DevGuide-Notes/04-Build-Loaders.md diff --git a/src/reference/90-Developers-Guide/10-DevGuide-Notes/04-Build-Loaders.md b/src/reference/90-Developers-Guide/10-DevGuide-Notes/04-Build-Loaders.md deleted file mode 100644 index 897022534..000000000 --- a/src/reference/90-Developers-Guide/10-DevGuide-Notes/04-Build-Loaders.md +++ /dev/null @@ -1,283 +0,0 @@ ---- -out: Build-Loaders.html ---- - -Build Loaders -------------- - -Build loaders are the means by which sbt resolves, builds, and -transforms build definitions. Each aspect of loading may be customized -for special applications. Customizations are specified by overriding the -*buildLoaders* methods of your build definition's Build object. These -customizations apply to external projects loaded by the build, but not -the (already loaded) Build in which they are defined. Also documented on -this page is how to manipulate inter-project dependencies from a -setting. - -### Custom Resolver - -The first type of customization introduces a new resolver. A resolver -provides support for taking a build URI and retrieving it to a local -directory on the filesystem. For example, the built-in resolver can -checkout a build using git based on a git URI, use a build in an -existing local directory, or download and extract a build packaged in a -jar file. A resolver has type: - -```scala -ResolveInfo => Option[() => File] -``` - -The resolver should return None if it cannot handle the URI or Some -containing a function that will retrieve the build. The ResolveInfo -provides a staging directory that can be used or the resolver can -determine its own target directory. Whichever is used, it should be -returned by the loading function. A resolver is registered by passing it -to *BuildLoader.resolve* and overriding *Build.buildLoaders* with the -result: - -```scala -... -object Demo extends Build { - ... - override def buildLoaders = - BuildLoader.resolve(demoResolver) :: - Nil - - def demoResolver: BuildLoader.ResolveInfo => Option[() => File] = ... - -} -``` - -#### API Documentation - -Relevant API documentation for custom resolvers: - -- [ResolveInfo](../api/sbt/internal/BuildLoader\$\$ResolveInfo.html) -- [BuildLoader](../api/sbt/internal/BuildLoader\$.html) - -#### Full Example - -```scala -import sbt._ -import Keys._ - -object Demo extends Build -{ - // Define a project that depends on an external project with a custom URI - lazy val root = Project("root", file(".")).dependsOn( - uri("demo:a") - ) - - // Register the custom resolver - override def buildLoaders = - BuildLoader.resolve(demoResolver) :: - Nil - - // Define the custom resolver, which handles the 'demo' scheme. - // The resolver's job is to produce a directory containing the project to load. - // A subdirectory of info.staging can be used to create new local - // directories, such as when doing 'git clone ...' - def demoResolver(info: BuildLoader.ResolveInfo): Option[() => File] = - if(info.uri.getScheme != "demo") - None - else - { - // Use a subdirectory of the staging directory for the new local build. - // The subdirectory name is derived from a hash of the URI, - // and so identical URIs will resolve to the same directory (as desired). - val base = RetrieveUnit.temporary(info.staging, info.uri) - - // Return a closure that will do the actual resolution when requested. - Some(() => resolveDemo(base, info.uri.getSchemeSpecificPart)) - } - - // Construct a sample project on the fly with the name specified in the URI. - def resolveDemo(base: File, ssp: String): File = - { - // Only create the project if it hasn't already been created. - if(!base.exists) - IO.write(base / "build.sbt", template.format(ssp)) - base - } - - def template = """ -name := "%s" - -version := "1.0" -""" -} -``` - -### Custom Builder - -Once a project is resolved, it needs to be built and then presented to -sbt as an instance of `sbt.BuildUnit`. A custom builder has type: - -```scala -BuildInfo => Option[() => BuildUnit] -``` - -A builder returns None if it does not want to handle the build -identified by the `BuildInfo`. Otherwise, it provides a function that -will load the build when evaluated. Register a builder by passing it to -*BuildLoader.build* and overriding *Build.buildLoaders* with the result: - -```scala -... -object Demo extends Build { - ... - override def buildLoaders = - BuildLoader.build(demoBuilder) :: - Nil - - def demoBuilder: BuildLoader.BuildInfo => Option[() => BuildUnit] = ... - -} -``` - -#### API Documentation - -Relevant API documentation for custom builders: - -- [BuildInfo](../api/sbt/internal/BuildLoader\$\$BuildInfo.html) -- [BuildLoader](../api/sbt/internal/BuildLoader\$.html) -- [BuildUnit](../api/sbt/internal/BuildUnit.html) - -#### Example - -This example demonstrates the structure of how a custom builder could -read configuration from a pom.xml instead of the standard .sbt files and -project/ directory. - -```scala -... imports ... - -object Demo extends Build -{ - lazy val root = Project("root", file(".")) dependsOn( file("basic-pom-project") ) - - override def buildLoaders = - BuildLoader.build(demoBuilder) :: - Nil - - def demoBuilder: BuildInfo => Option[() => BuildUnit] = info => - if(pomFile(info).exists) - Some(() => pomBuild(info)) - else - None - - def pomBuild(info: BuildInfo): BuildUnit = - { - val pom = pomFile(info) - val model = readPom(pom) - - val n = Project.normalizeProjectID(model.getName) - val base = Option(model.getProjectDirectory) getOrElse info.base - val root = Project(n, base) settings( pomSettings(model) ) - val build = new Build { override def projects = Seq(root) } - val loader = this.getClass.getClassLoader - val definitions = new LoadedDefinitions(info.base, Nil, loader, build :: Nil, Nil) - val plugins = new LoadedPlugins(info.base / "project", Nil, loader, Nil, Nil) - new BuildUnit(info.uri, info.base, definitions, plugins) - } - - def readPom(file: File): Model = ... - def pomSettings(m: Model): Seq[Setting[_]] = ... - def pomFile(info: BuildInfo): File = info.base / "pom.xml" -``` - -### Custom Transformer - -Once a project has been loaded into an `sbt.BuildUnit`, it is -transformed by all registered transformers. A custom transformer has -type: - -```scala -TransformInfo => BuildUnit -``` - -A transformer is registered by passing it to *BuildLoader.transform* and -overriding *Build.buildLoaders* with the result: - -```scala -... -object Demo extends Build { - ... - override def buildLoaders = - BuildLoader.transform(demoTransformer) :: - Nil - - def demoTransformer: BuildLoader.TransformInfo => BuildUnit = ... - -} -``` - -#### API Documentation - -Relevant API documentation for custom transformers: - -- [TransformInfo](../api/sbt/internal/BuildLoader\$\$TransformInfo.html) -- [BuildLoader](../api/sbt/internal/BuildLoader\$.html) -- [BuildUnit](../api/sbt/internal/BuildUnit.html) - -##### Manipulating Project Dependencies in Settings - -The `buildDependencies` setting, in the Global scope, defines the -aggregation and classpath dependencies between projects. By default, -this information comes from the dependencies defined by `Project` -instances by the `aggregate` and `dependsOn` methods. Because -`buildDependencies` is a setting and is used everywhere dependencies -need to be known (once all projects are loaded), plugins and build -definitions can transform it to manipulate inter-project dependencies at -setting evaluation time. The only requirement is that no new projects -are introduced because all projects are loaded before settings get -evaluated. That is, all Projects must have been declared directly in a -Build or referenced as the argument to `Project.aggregate` or -`Project.dependsOn`. - -### The BuildDependencies type - -The type of the `buildDependencies` setting is -[BuildDependencies](../api/sbt/internal/BuildDependencies.html). -`BuildDependencies` provides mappings from a project to its aggregate or -classpath dependencies. For classpath dependencies, a dependency has -type `ClasspathDep[ProjectRef]`, which combines a `ProjectRef` with a -configuration (see [ClasspathDep](../api/sbt/ClasspathDep.html) -and [ProjectRef](../api/sbt/ProjectRef.html)). For aggregate -dependencies, the type of a dependency is just `ProjectRef`. - -The API for `BuildDependencies` is not extensive, covering only a little -more than the minimum required, and related APIs have more of an -internal, unpolished feel. Most manipulations consist of modifying the -relevant map (classpath or aggregate) manually and creating a new -`BuildDependencies` instance. - -#### Example - -As an example, the following replaces a reference to a specific build -URI with a new URI. This could be used to translate all references to a -certain git repository to a different one or to a different mechanism, -like a local directory. - -```scala -buildDependencies in Global := { - val deps = (buildDependencies in Global).value - val oldURI = uri("...") // the URI to replace - val newURI = uri("...") // the URI replacing oldURI - def substitute(dep: ClasspathDep[ProjectRef]): ClasspathDep[ProjectRef] = - if(dep.project.build == oldURI) - ResolvedClasspathDependency(ProjectRef(newURI, dep.project.project), dep.configuration) - else - dep - val newcp = - for( (proj, deps) <- deps.cp) yield - (proj, deps map substitute) - BuildDependencies(newcp, deps.aggregate) -} -``` - -It is not limited to such basic translations, however. The configuration -a dependency is defined in may be modified and dependencies may be added -or removed. Modifying `buildDependencies` can be combined with modifying -`libraryDependencies` to convert binary dependencies to and from source -dependencies, for example. From 1de2a0b6924459f9a97c617751253c315fbe91fa Mon Sep 17 00:00:00 2001 From: Eugene Yokota <eed3si9n@gmail.com> Date: Sat, 21 Sep 2019 19:21:19 -0400 Subject: [PATCH 2/3] Fix link Fixes https://github.com/sbt/website/issues/815 --- .../02-DetailTopics/04-Tasks-and-Commands/01a-Caching.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reference/02-DetailTopics/04-Tasks-and-Commands/01a-Caching.md b/src/reference/02-DetailTopics/04-Tasks-and-Commands/01a-Caching.md index 22c9865a3..e18b0fc3c 100644 --- a/src/reference/02-DetailTopics/04-Tasks-and-Commands/01a-Caching.md +++ b/src/reference/02-DetailTopics/04-Tasks-and-Commands/01a-Caching.md @@ -3,7 +3,7 @@ out: Caching.html --- [Basic-Def]: Basic-Def.html - [Task]: Task.html + [Tasks]: Tasks.html Caching ------- From a239e75183f7cfd81c4918d232de52e4a31777f7 Mon Sep 17 00:00:00 2001 From: Eugene Yokota <eed3si9n@gmail.com> Date: Sat, 21 Sep 2019 20:23:54 -0400 Subject: [PATCH 3/3] Update Linux installaiton steps Fixes https://github.com/sbt/sbt/issues/4261 Fixes https://github.com/sbt/website/issues/799 Ideally ``` sudo apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823 ``` should just work. but Ubuntu Bionic (18.04) uses gpg 2.2.4 that does not contain the fix mentioned in https://github.com/microsoft/WSL/issues/3286, and thus end up with ``` gpg: connecting dirmngr at '/tmp/apt-key-gpghome.BG01sRSmD5/S.dirmngr' failed: IPC connect call failed gpg: keyserver receive failed: No dirmngr ``` --- src/nanoc/content/download.html | 2 +- .../00-Getting-Started/01-Setup/c.md | 26 ++++++++++++++----- .../es/00-Getting-Started/01-Setup/c.md | 23 ++++++++++++---- .../ja/00-Getting-Started/01-Setup/c.md | 24 ++++++++++++----- .../zh-cn/00-Getting-Started/01-Setup/c.md | 16 +++++++++++- 5 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/nanoc/content/download.html b/src/nanoc/content/download.html index 87a559623..e4f15b555 100644 --- a/src/nanoc/content/download.html +++ b/src/nanoc/content/download.html @@ -34,7 +34,7 @@ <h3>Scoop</h3> <h2>Linux (deb)</h2> <pre> echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list -sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823 +curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add sudo apt-get update sudo apt-get install sbt </pre> diff --git a/src/reference/00-Getting-Started/01-Setup/c.md b/src/reference/00-Getting-Started/01-Setup/c.md index 0bd71fc2c..ce7ff5a0a 100644 --- a/src/reference/00-Getting-Started/01-Setup/c.md +++ b/src/reference/00-Getting-Started/01-Setup/c.md @@ -13,17 +13,29 @@ out: Installing-sbt-on-Linux.html Installing sbt on Linux ----------------------- -### Installing from a universal package +### Installing from SDKMAN -Download [ZIP][ZIP] or [TGZ][TGZ] package and expand it. +To install both JDK and sbt, consider using [SDKMAN](https://sdkman.io/). + +``` +\$ sdk list java +\$ sdk install java 11.0.4.hs-adpt +\$ sdk install sbt +``` + +This has two advantages. +1. It will install the official packaging by AdoptOpenJDK, as opposed to the ["mystery meat OpenJDK builds"](https://mail.openjdk.java.net/pipermail/jdk8u-dev/2019-May/009330.html). +2. It will install `tgz` packaging of sbt that contains all JAR files. (DEB and RPM packages do not to save bandwidth) ### Install JDK -You must first install a JDK. We recommend AdoptOpenJDK JDK 8 or JDK 11. The details around the package names differ from one distribution to another. +You must first install a JDK. We recommend **AdoptOpenJDK JDK 8** or **JDK 11**. -For example, Ubuntu xenial (16.04LTS) has [openjdk-8-jdk](https://packages.ubuntu.com/hu/xenial/openjdk-8-jdk). +The details around the package names differ from one distribution to another. For example, Ubuntu xenial (16.04LTS) has [openjdk-8-jdk](https://packages.ubuntu.com/hu/xenial/openjdk-8-jdk). Redhat family calls it [java-1.8.0-openjdk-devel](https://apps.fedoraproject.org/packages/java-1.8.0-openjdk-devel). -Redhat family calls it [java-1.8.0-openjdk-devel](https://apps.fedoraproject.org/packages/java-1.8.0-openjdk-devel). +### Installing from a universal package + +Download [ZIP][ZIP] or [TGZ][TGZ] package and expand it. ### Ubuntu and other Debian-based distributions @@ -33,7 +45,7 @@ Ubuntu and other Debian-based distributions use the DEB format, but usually you Run the following from the terminal to install `sbt` (You'll need superuser privileges to do so, hence the `sudo`). echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list - sudo apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823 + curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add sudo apt-get update sudo apt-get install sbt @@ -45,6 +57,8 @@ Once `sbt` is installed, you'll be able to manage the package in `aptitude` or S **Note**: There's been reports about SSL error using Ubuntu: `Server access Error: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty url=https://repo1.maven.org/maven2/org/scala-sbt/sbt/1.1.0/sbt-1.1.0.pom`, which apparently stems from OpenJDK 9 using PKCS12 format for `/etc/ssl/certs/java/cacerts` [cert-bug][cert-bug]. According to <https://stackoverflow.com/a/50103533/3827> it is fixed in Ubuntu Cosmic (18.10), but Ubuntu Bionic LTS (18.04) is still waiting for a release. See the answer for a woraround. +**Note**: `sudo apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823` may not work on Ubuntu Bionic LTS (18.04) since it's using a buggy GnuPG, so we are advising to use web API to download the public key in the above. + ### Red Hat Enterprise Linux and other RPM-based distributions [RPM][RPM] package is officially supported by sbt. diff --git a/src/reference/es/00-Getting-Started/01-Setup/c.md b/src/reference/es/00-Getting-Started/01-Setup/c.md index 83eb3954d..c5855920d 100644 --- a/src/reference/es/00-Getting-Started/01-Setup/c.md +++ b/src/reference/es/00-Getting-Started/01-Setup/c.md @@ -13,21 +13,34 @@ out: Installing-sbt-on-Linux.html Installing sbt on Linux ----------------------- -### Instalar desde un paquete universal +### Installing from SDKMAN -Descarga el paquete [ZIP][ZIP] o [TGZ][TGZ] y descomprímelo. +To install both JDK and sbt, consider using [SDKMAN](https://sdkman.io/). + +``` +\$ sdk list java +\$ sdk install java 11.0.4.hs-adpt +\$ sdk install sbt +``` + +This has two advantages. +1. It will install the official packaging by AdoptOpenJDK, as opposed to the ["mystery meat OpenJDK builds"](https://mail.openjdk.java.net/pipermail/jdk8u-dev/2019-May/009330.html). +2. It will install `tgz` packaging of sbt that contains all JAR files. (DEB and RPM packages do not to save bandwidth) ### Instalar JDK Primero desberás de instalar JDK. Recomendamos AdoptOpenJDK JDK 8 u AdoptOpenJDK JDK 11. -Los detalles sobre el nombre de los paquetes cambian de una distribución a otra. +Los detalles sobre el nombre de los paquetes cambian de una distribución a otra. Por ejemplo, Ubuntu xenial (16.04LTS) usa [openjdk-8-jdk](https://packages.ubuntu.com/hu/xenial/openjdk-8-jdk). - La familia Redhat lo llama [java-1.8.0-openjdk-devel](https://apps.fedoraproject.org/packages/java-1.8.0-openjdk-devel). +### Instalar desde un paquete universal + +Descarga el paquete [ZIP][ZIP] o [TGZ][TGZ] y descomprímelo. + ### Ubuntu y otras distribuciones basadas en Debian Los paquetes [DEB][DEB] son oficialmente soportados por sbt. @@ -41,7 +54,7 @@ Ejecuta lo siguiente desde el terminal para instalar `sbt` (necesitarás tener privilegios de administrador para hacerlo, de ahí el `sudo`). echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823 + curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add sudo apt-get update sudo apt-get install sbt diff --git a/src/reference/ja/00-Getting-Started/01-Setup/c.md b/src/reference/ja/00-Getting-Started/01-Setup/c.md index 980104849..68de311c7 100644 --- a/src/reference/ja/00-Getting-Started/01-Setup/c.md +++ b/src/reference/ja/00-Getting-Started/01-Setup/c.md @@ -13,13 +13,25 @@ out: Installing-sbt-on-Linux.html Linux への sbt のインストール -------------------------- -### JDK のインストール +### SDKMAN からのインストール + +JDK と sbt をするのに、[SDKMAN](https://sdkman.io/) の導入を検討してほしい。 + +``` +\$ sdk list java +\$ sdk install java 11.0.4.hs-adpt +\$ sdk install sbt +``` -まず JDK をインストールする必要がある。AdoptOpenJDK JDK 8 もしくは AdoptOpenJDK JDK 11 を推奨する。パッケージ名はディストリビューションによって異なる。 +この方法は 2つの利点がある。 +1. [「闇鍋 OpenJDK ビルド」](https://mail.openjdk.java.net/pipermail/jdk8u-dev/2019-May/009330.html)と揶揄されているディストロ管理の JDK ではなく、AdoptOpenJDK が出している公式のパッケージをインストールできる。 +2. sbt の全ての JAR ファイルを含んだ `tgz` パッケージをインストールできる (DEB と RPM版は帯域の節約のために JAR ファイルが含まれていない)。 -例えば、Ubuntu xenial (16.04LTS) には [openjdk-8-jdk](https://packages.ubuntu.com/hu/xenial/openjdk-8-jdk) がある。 +### JDK のインストール + +まず JDK をインストールする必要がある。AdoptOpenJDK JDK 8 もしくは AdoptOpenJDK JDK 11 を推奨する。 -Redhat 系は [java-1.8.0-openjdk-devel](https://apps.fedoraproject.org/packages/java-1.8.0-openjdk-devel) と呼んでいる。 +パッケージ名はディストリビューションによって異なる。例えば、Ubuntu xenial (16.04LTS) には [openjdk-8-jdk](https://packages.ubuntu.com/hu/xenial/openjdk-8-jdk) がある。Redhat 系は [java-1.8.0-openjdk-devel](https://apps.fedoraproject.org/packages/java-1.8.0-openjdk-devel) と呼んでいる。 ### ユニバーサルパッケージからのインストール @@ -36,7 +48,7 @@ Ubuntu 及びその他の Debian ベースのディストリビューション ターミナル上から以下を実行すると `sbt` をインストールできる (superuser 権限を必要とするため、`sudo` を使っている)。 echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823 + curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add sudo apt-get update sudo apt-get install sbt @@ -44,8 +56,6 @@ Ubuntu 及びその他の Debian ベースのディストリビューション sbt のバイナリは Bintray にて公開されており、都合の良いことに Bintray は APT リポジトリを提供している。 そのため、このリポジトリをパッケージ・マネージャに追加しさえすればよい。 ->**注意** [sbt/website#127][website127] で報告されている通り、https を使用するとセグメンテーション違反が発生する場合がある。 - `sbt` を最初にインストールした後は、このパッケージは `aptitude` や Synaptic 上から管理することができる (パッケージ・キャッシュの更新を忘れずに)。 追加された APT リポジトリは「システム設定 -> ソフトウェアとアップデート -> 他のソフトウェア」 の一番下に表示されているはずだ: diff --git a/src/reference/zh-cn/00-Getting-Started/01-Setup/c.md b/src/reference/zh-cn/00-Getting-Started/01-Setup/c.md index 152d7591d..f4f269ed8 100644 --- a/src/reference/zh-cn/00-Getting-Started/01-Setup/c.md +++ b/src/reference/zh-cn/00-Getting-Started/01-Setup/c.md @@ -10,6 +10,20 @@ out: Installing-sbt-on-Linux.html 在 Linux 上安装 sbt ----------------------- +### Installing from SDKMAN + +To install both JDK and sbt, consider using [SDKMAN](https://sdkman.io/). + +``` +\$ sdk list java +\$ sdk install java 11.0.4.hs-adpt +\$ sdk install sbt +``` + +This has two advantages. +1. It will install the official packaging by AdoptOpenJDK, as opposed to the ["mystery meat OpenJDK builds"](https://mail.openjdk.java.net/pipermail/jdk8u-dev/2019-May/009330.html). +2. It will install `tgz` packaging of sbt that contains all JAR files. (DEB and RPM packages do not to save bandwidth) + ### 通过通用的安装包安装 下载 [ZIP][ZIP] 或者 [TGZ][TGZ] 包并解压。 @@ -22,7 +36,7 @@ Ubuntu和其他基于Debian的发行版使用DEB格式,但通常你不从本 从终端运行下面的命令安装`sbt`(你需要超级用户权限,因此需要`sudo`)。 echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823 + curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add sudo apt-get update sudo apt-get install sbt