Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Noel Welsh committed Feb 6, 2020
0 parents commit 65c5ede
Show file tree
Hide file tree
Showing 18 changed files with 578 additions and 0 deletions.
139 changes: 139 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Created by https://www.gitignore.io/api/scala,intellij,eclipse,sbt

### Scala ###
*.class
*.log

# sbt specific
.cache
.cache-main
.history
.lib/
dist/*
target/
lib_managed/
src_managed/
project/boot/
project/plugins/project/
project/target
project/project

# Scala-IDE specific
.scala_dependencies
.worksheet

# Documentation intermediate files
docs/src/main/paradox
docs/src/main/mdoc/api


### SublimeText ###
# cache files for sublime text
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache

# workspace files are user-specific
*.sublime-workspace

# project files should be checked into the repository, unless a significant
# proportion of contributors will probably not be using SublimeText
# *.sublime-project

# sftp configuration file
sftp-config.json


### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio

*.iml

## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:

# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries

# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml

# Gradle:
# .idea/gradle.xml
# .idea/libraries

# Mongo Explorer plugin:
# .idea/mongoSettings.xml

## File-based project format:
*.ipr
*.iws

## Plugin-specific files:

# IntelliJ
/out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties


### Eclipse ###
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath

# Eclipse Core
.project

# External tool builders
.externalToolBuilders/

# Locally stored "Eclipse launch configurations"
*.launch

# CDT-specific
.cproject

# JDT-specific (Eclipse Java Development Tools)
.classpath

# Java annotation processor (APT)
.factorypath

# PDT-specific
.buildpath

# sbteclipse plugin
.target

# TeXlipse plugin
.texlipse

# Metals and Bloop
.metals
.bloop
1 change: 1 addition & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
version = "2.3.2"
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# http4s Executable via GraalVM Native Image

This repository demonstrates how to compile an http4s application to a native executable using GraalVM's Native Image. The accompanying blog post (link pending) has all the details.

To quickly get going:

1. Build the Docker image in the `docker` directory

``` sh
cd docker
docker build -t inner-product/graalvm-native-image .
```

2. Run the `nativeImage` task from sbt.

The result will be a Linux executable.


## Building Without Docker

If you want to build an executable on your machine without using Docker you should:

1. Install GraalVM and Native Image
2. Build the fat JAR using the `assembly` task in sbt
3. Run `native-image -jar tar/scala-2.13/http4s-native-image-assembly-0.1.0-SNAPSHOT.jar `


## License

Distributed under the MIT license.

Copyright 2020 Inner Product LLC

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
70 changes: 70 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2020 Noel Welsh
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import sbt._
import scala.sys.process._
import java.io.File

ThisBuild / organization := "co.innerproduct"
ThisBuild / name := "ping"
ThisBuild / scalaVersion := "2.13.1"
ThisBuild / useSuperShell := false

libraryDependencies ++= Seq(
Dependencies.catsCore.value,
Dependencies.catsEffect.value,
Dependencies.miniTest.value,
Dependencies.miniTestLaws.value,
Dependencies.http4sBlazeServer.value,
Dependencies.http4sBlazeClient.value,
Dependencies.http4sCirce.value,
Dependencies.http4sDsl.value,
Dependencies.logback.value,
Dependencies.janino.value
)

testFrameworks += new TestFramework("minitest.runner.Framework")

lazy val nativeImage =
taskKey[File]("Build a standalone executable using GraalVM Native Image")

nativeImage := {
import sbt.Keys.streams
val assemblyFatJar = assembly.value
val assemblyFatJarPath = assemblyFatJar.getParent()
val assemblyFatJarName = assemblyFatJar.getName()
val outputPath = (baseDirectory.value / "out").getAbsolutePath()
val outputName = "ping-server"
val nativeImageDocker = "inner-product/graalvm-native-image"

val cmd = s"""docker run
| --volume ${assemblyFatJarPath}:/opt/assembly
| --volume ${outputPath}:/opt/native-image
| ${nativeImageDocker}
| --static
| -jar /opt/assembly/${assemblyFatJarName}
| ${outputName}""".stripMargin.filter(_ != '\n')

val log = streams.value.log
log.info(s"Building native image from ${assemblyFatJarName}")
log.debug(cmd)
val result = (cmd.!(log))

if (result == 0) file(s"${outputPath}/${outputName}")
else {
log.error(s"Native image command failed:\n ${cmd}")
throw new Exception("Native image command failed")
}
}
14 changes: 14 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Dockerfile to build an image that runs the GraalVM native-image compiler. We
# need to do this because native-image only builds on the platform on which it
# runs. Hence if we want to build Linux binaries on a different machine we need
# to create a Linux VM that does this. This is what we are doing here.
#
# To build this image, run:
#
# docker build -t inner-product/graalvm-native-image .
#
ARG GRAAL_VERSION=19.3.1-java11
FROM oracle/graalvm-ce:${GRAAL_VERSION}
WORKDIR /opt/native-image
RUN gu install native-image
ENTRYPOINT ["native-image"]
35 changes: 35 additions & 0 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import sbt._


object Dependencies {
// Library Versions
val catsVersion = "2.1.0"
val catsEffectVersion = "2.0.0"
val circeVersion = "0.12.3"

val http4sVersion = "0.21.0-RC2"

val logbackVersion = "1.2.3"
val janinoVersion = "3.1.0"

val miniTestVersion = "2.7.0"
val scalaCheckVersion = "1.14.1"


// Libraries
val catsEffect = Def.setting("org.typelevel" %% "cats-effect" % catsEffectVersion)
val catsCore = Def.setting("org.typelevel" %% "cats-core" % catsVersion)

val miniTest = Def.setting("io.monix" %% "minitest" % miniTestVersion % "test")
val miniTestLaws = Def.setting("io.monix" %% "minitest-laws" % miniTestVersion % "test")

val http4sBlazeServer = Def.setting("org.http4s" %% "http4s-blaze-server" % http4sVersion)
val http4sBlazeClient = Def.setting("org.http4s" %% "http4s-blaze-client" % http4sVersion)
val http4sCirce = Def.setting("org.http4s" %% "http4s-circe" % http4sVersion)
val http4sDsl = Def.setting("org.http4s" %% "http4s-dsl" % http4sVersion)

val logback = Def.setting("ch.qos.logback" % "logback-classic" % logbackVersion)
val janino = Def.setting("org.codehaus.janino" % "janino" % janinoVersion)

val circe = Def.setting("io.circe" %% "circe-generic" % circeVersion)
}
1 change: 1 addition & 0 deletions project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=1.3.3
4 changes: 4 additions & 0 deletions project/metals.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// DO NOT EDIT! This file is auto-generated.
// This file enables sbt-bloop to create bloop config files.

addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.4.0-RC1")
5 changes: 5 additions & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.3.4")
addSbtPlugin("io.github.davidgregory084" % "sbt-tpolecat" % "0.1.10")
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.5.1")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10")
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.6.1")
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Args = -H:+ReportExceptionStackTraces --allow-incomplete-classpath --no-fallback
Loading

0 comments on commit 65c5ede

Please sign in to comment.