Skip to content

Commit

Permalink
Merge pull request #130 from jonas/release
Browse files Browse the repository at this point in the history
Configure publishing of the sbt plugin and tools library
  • Loading branch information
jonas authored Jul 24, 2018
2 parents ce84116 + 927eef6 commit 942598b
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 22 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ This tool generates Scala Native bindings from C headers. It's built upon clang

[Documentation](https://kornilova-l.github.io/scala-native-bindgen/)

## Releasing

To release version `x.y.z` run:

> sbt -Dproject.version=x.y.z release

Then build the `scala-native-bindgen` executable for both macOS and
Linux and upload them to the GitHub release page with the suffix
`-darwin` and `-linux`, respectively.

## License

This project is distributed under the Scala license.
Expand Down
77 changes: 70 additions & 7 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ val Versions = new {

inThisBuild(
Def.settings(
organization := "org.scalanative.bindgen",
version := "0.2-SNAPSHOT",
organization := "org.scala-native.bindgen",
licenses := Seq(
"BSD 3-Clause" -> url("https://www.scala-lang.org/license/")),
homepage := Some(url("https://kornilova-l.github.io/scala-native-bindgen")),
scalacOptions ++= Seq(
"-deprecation",
"-unchecked",
Expand All @@ -24,7 +26,20 @@ inThisBuild(
scmInfo := Some(
ScmInfo(url("https://github.com/kornilova-l/scala-native-bindgen"),
"scm:git:[email protected]:kornilova-l/scala-native-bindgen.git")),
git.remoteRepo := scmInfo.value.get.connection.replace("scm:git:", "")
developers := List(
Developer(
id = "kornilova-l",
name = "Liudmila Kornilova",
email = "[email protected]",
url = url("https://github.com/kornilova-l")
),
Developer(
id = "jonas",
name = "Jonas Fonseca",
email = "[email protected]",
url = url("https://github.com/jonas")
)
)
))

val root = project("scala-native-bindgen")
Expand All @@ -36,12 +51,33 @@ val root = project("scala-native-bindgen")
sbtPlugin,
docs
)
.enablePlugins(ReleasePlugin)
.settings(
publish / skip := true,
releaseCrossBuild := false,
releaseVersionFile := target.value / "unused-version.sbt",
releaseProcess := {
import ReleaseTransformations._
Seq[ReleaseStep](
checkSnapshotDependencies,
setReleaseVersions(version.value),
runClean,
releaseStepCommandAndRemaining("verify"),
setReleaseVersion,
tagRelease,
releaseStepCommandAndRemaining("^publish"),
pushChanges,
releaseStepTask(docs / ghpagesPushSite)
)
}
)

lazy val tests = project("tests")
.dependsOn(tools)
.settings(
fork in Test := true,
javaOptions in Test += {
publish / skip := true,
Test / fork := true,
Test / javaOptions += {
val rootDir = (ThisBuild / baseDirectory).value
s"-Dbindgen.path=$rootDir/bindgen/target/scala-native-bindgen"
},
Expand All @@ -57,6 +93,7 @@ lazy val samples = project("samples")
.in(file("tests/samples"))
.enablePlugins(ScalaNativePlugin)
.settings(
publish / skip := true,
scalaVersion := Versions.scala211,
libraryDependencies += "com.lihaoyi" %%% "utest" % "0.6.3" % "test",
testFrameworks += new TestFramework("utest.runner.Framework"),
Expand Down Expand Up @@ -108,20 +145,30 @@ lazy val tools = project("tools")

lazy val sbtPlugin = project("sbt-scala-native-bindgen", ScriptedPlugin)
.dependsOn(tools)
.enablePlugins(BuildInfoPlugin)
.settings(
Keys.sbtPlugin := true,
scriptedLaunchOpts += s"-Dplugin.version=${version.value}",
scriptedLaunchOpts += {
val rootDir = (ThisBuild / baseDirectory).value
s"-Dbindgen.path=$rootDir/bindgen/target/scala-native-bindgen"
},
buildInfoPackage := "org.scalanative.bindgen.sbt",
buildInfoKeys := Seq[BuildInfoKey](
version,
organization,
BuildInfoKey.map(scmInfo) {
case (k, v) => "projectUrl" -> v.get.browseUrl
}
),
publishLocal := publishLocal.dependsOn(tools / publishLocal).value
)

lazy val docs = project("docs")
.enablePlugins(GhpagesPlugin, ParadoxSitePlugin, ParadoxMaterialThemePlugin)
.settings(
paradoxProperties in Paradox ++= Map(
publish / skip := true,
Paradox / paradoxProperties ++= Map(
"github.base_url" -> scmInfo.value.get.browseUrl.toString
),
ParadoxMaterialThemePlugin.paradoxMaterialThemeSettings(Paradox),
Expand All @@ -134,15 +181,31 @@ lazy val docs = project("docs")

def project(name: String, plugged: AutoPlugin*) = {
val unplugged = Seq(ScriptedPlugin).filterNot(plugged.toSet)

Project(id = name, base = file(name))
.disablePlugins(unplugged: _*)
.enablePlugins(GitPlugin)
.enablePlugins(GitVersioning)
.settings(
versionWithGit,
git.useGitDescribe := true,
git.remoteRepo := scmInfo.value.get.connection.replace("scm:git:", ""),
crossSbtVersions := List(Versions.sbt013, Versions.sbt1),
scalaVersion := {
(pluginCrossBuild / sbtBinaryVersion).value match {
case "0.13" => Versions.scala210
case _ => Versions.scala212
}
}
},
bintrayOrganization := Some("scala-native-bindgen"),
bintrayRepository := {
if (Keys.sbtPlugin.value) "sbt-plugins"
else "maven"
},
publishMavenStyle := Keys.sbtPlugin.value == false,
Test / publishArtifact := false
)
}

lazy val setReleaseVersions: String => State => State =
v => _.put(ReleaseKeys.versions, (v, v))
3 changes: 3 additions & 0 deletions docs/src/paradox/obtaining-bindgen/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

@@@ index

* [Use the sbt plugin](sbt-plugin.md)
* [Use Docker Container](docker-container.md)
* [Build Binary with CMake](cmake.md)
* [Build Binary with docker-compose](docker-compose.md)
Expand All @@ -10,6 +11,8 @@

There are 3 ways to obtain bindgen:

* @ref:[Use the sbt plugin](sbt-plugin.md)

* @ref:[Use docker container](docker-container.md)

* @ref:[Build binary with CMake](cmake.md)
Expand Down
61 changes: 61 additions & 0 deletions docs/src/paradox/obtaining-bindgen/sbt-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Using the sbt plugin

To add the sbt plugin to your project add the following lines in `project/plugins.sbt`:

@@@ vars
```sbt
addSbtPlugin("org.scala-native.bindgen" % "sbt-scala-native-bindgen" % "$project.version$")

resolvers += Resolver.bintrayIvyRepo("scala-native-bindgen", "sbt-plugin")
resolvers += Resolver.bintrayRepo("scala-native-bindgen", "maven")
```
@@@

Next configure the plugin using the settings scoped to either `Compile` or `Test`:

|---------------------------|-------------------|
|`nativeBindgenHeader` | The C header file to read.
|`nativeBindgenPackage` | Package of the enclosing object. No package by default.
|`name in nativeBindgen` | Name of the enclosing object.
|`nativeBindgenLink` | Name of library to be linked.

@@@ note

By default the `scala-native-bindgen` executable is downloaded automatically for supported platforms. Set `version in nativeBindgen` (unscoped) to configure the version of the `scala-native-bindgen` to use if you want a version different from the version of the sbt plugin.

In case your platform is not supported, you must compile `scala-native-bindgen` yourself and configure the path to the executable using `nativeBindgenPath`, e.g.:

```sbt
nativeBindgenPath := file("/path/to/scala-native-bindgen")
```

@@@

Example settings:

```sbt
enablePlugins(ScalaNativeBindgenPlugin)
inConfig(Compile)(
Def.settings(
nativeBindgenHeader := (resourceDirectory in Compile).value / "header.h",
nativeBindgenPackage := Some("org.example.mylib"),
nativeBindgenLink := Some("mylib"), // Will pass `-lmylib` to the linker
nativeBindgenExclude := Some("__"),
name in nativeBindgen := "MyLib"
))
```

Running `nativeBindgen` will generate a file named `target/scala-2.x/src_managed/main/sbt-scala-native-bindgen//ScalaNativeBindgen.scala` containing something along the following lines:

```scala
package org.example.mylib

import scala.scalanative._
import scala.scalanative.native._

@native.link("mylib")
@native.extern
object MyLib {
// ... left out for brevity ...
}
```
12 changes: 8 additions & 4 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.3.8")
addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.3.2")
addSbtPlugin("io.github.jonas" % "sbt-paradox-material-theme" % "0.4.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.2")
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.3.8")
addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.3.2")
addSbtPlugin("io.github.jonas" % "sbt-paradox-material-theme" % "0.4.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.2")
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0")
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.9")
addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.4")
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.9.0")

libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package org.scalanative.bindgen.sbt
import sbt._
import sbt.Keys._

import java.nio.file.Files
import java.nio.file.attribute.{PosixFileAttributeView, PosixFilePermission}

import org.scalanative.bindgen.Bindgen

/**
Expand All @@ -25,13 +28,21 @@ import org.scalanative.bindgen.Bindgen
*
* Keys are defined in [[ScalaNativeBindgenPlugin.autoImport]].
*
* - `nativeBindgenPath`: Path to the `scala-native-bindgen` executable.
* - `nativeBindgenHeader`: The C header file to read.
*
* - `nativeBindgenPackage`: Package of the enclosing object.
* No package by default.
*
* - `name in nativeBindgen`: Name of the enclosing object.
*
* - `version in nativeBindgen`: Version of the `scala-native-bindgen`
* to use when automatically downloading the executable.
*
* - `nativeBindgenLink`: Name of library to be linked.
*
* - `nativeBindgen`: Generate Scala Native bindings.
*
* @example
* {{{
* nativeBindgenHeader in Compile := file("/usr/include/ctype.h")
Expand All @@ -42,8 +53,9 @@ import org.scalanative.bindgen.Bindgen
object ScalaNativeBindgenPlugin extends AutoPlugin {

object autoImport {
val ScalaNativeBindgen = config("scala-native-bindgen").hide
val nativeBindgenPath =
taskKey[Option[File]]("Path to the scala-native-bindgen executable")
taskKey[File]("Path to the scala-native-bindgen executable")
val nativeBindgenHeader = taskKey[File]("C header file")
val nativeBindgenPackage =
settingKey[Option[String]]("Package for the generated code")
Expand All @@ -57,7 +69,46 @@ object ScalaNativeBindgenPlugin extends AutoPlugin {
override def requires = plugins.JvmPlugin

override def projectSettings: Seq[Setting[_]] =
nativeBindgenScopedSettings(Compile)
inConfig(ScalaNativeBindgen)(Defaults.configSettings) ++
nativeBindgenScopedSettings(Compile) ++
Def.settings(
ivyConfigurations += ScalaNativeBindgen,
version in nativeBindgen := BuildInfo.version,
libraryDependencies ++= {
artifactName.map { name =>
val bindgenVersion = (version in nativeBindgen).value
val url =
s"${BuildInfo.projectUrl}/releases/download/v$bindgenVersion/$name"

BuildInfo.organization % name % bindgenVersion % ScalaNativeBindgen from (url)
}.toSeq
},
nativeBindgenPath := {
val scalaNativeBindgenUpdate = (update in ScalaNativeBindgen).value

val artifactFile = artifactName match {
case None =>
sys.error(
"No downloadable binaries available for your OS, " +
"please provide path via `nativeBindgenPath`")
case Some(name) =>
scalaNativeBindgenUpdate
.select(artifact = artifactFilter(name = name))
.head
}

// Set the executable bit on the expected path to fail if it doesn't exist
for (view <- Option(
Files.getFileAttributeView(artifactFile.toPath,
classOf[PosixFileAttributeView]))) {
val permissions = view.readAttributes.permissions
if (permissions.add(PosixFilePermission.OWNER_EXECUTE))
view.setPermissions(permissions)
}

artifactFile
}
)

private implicit class BindgenOps(val bindgen: Bindgen) extends AnyVal {
def maybe[T](opt: Option[T], f: Bindgen => T => Bindgen): Bindgen =
Expand All @@ -67,23 +118,27 @@ object ScalaNativeBindgenPlugin extends AutoPlugin {
}
}

private val artifactName =
Option(System.getProperty("os.name")).collect {
case "Mac OS X" => "scala-native-bindgen-darwin"
case "Linux" => "scala-native-bindgen-linux"
}

def nativeBindgenScopedSettings(conf: Configuration): Seq[Setting[_]] =
inConfig(conf)(
Seq(
Def.settings(
nativeBindgenHeader := {
sys.error("nativeBindgenHeader not configured")
},
nativeBindgenPath := None,
nativeBindgenPackage := None,
nativeBindgenExclude := None,
resourceDirectories in nativeBindgen := resourceDirectories.value,
sourceGenerators += Def.task { Seq(nativeBindgen.value) },
name in nativeBindgen := "ScalaNativeBindgen",
nativeBindgen := {
val output = sourceManaged.value / "sbt-scala-native-bindgen" / "nativeBindgen.scala"
val output = sourceManaged.value / "sbt-scala-native-bindgen" / "ScalaNativeBindgen.scala"

Bindgen()
.bindgenExecutable(nativeBindgenPath.value.get)
.bindgenExecutable(nativeBindgenPath.value)
.header(nativeBindgenHeader.value)
.name((name in nativeBindgen).value)
.maybe(nativeBindgenLink.value, _.link)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
name := "test"
organization := "org.scalanative.bindgen.sbt.test"
organization := "org.scala-native.bindgen.sbt.test"
enablePlugins(ScalaNativeBindgenPlugin)
scalaVersion := "2.11.12"

inConfig(Compile)(
Def.settings(
nativeBindgenPath := Option(System.getProperty("bindgen.path")).map(file),
nativeBindgenPath := file(System.getProperty("bindgen.path")),
nativeBindgenHeader := (resourceDirectory in Compile).value / "header.h",
nativeBindgenPackage := Some("org.example.app"),
nativeBindgenLink := Some("app"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
addSbtPlugin(
"org.scalanative.bindgen" % "sbt-scala-native-bindgen" % sys.props(
"org.scala-native.bindgen" % "sbt-scala-native-bindgen" % sys.props(
"plugin.version"))
Loading

0 comments on commit 942598b

Please sign in to comment.