Skip to content

Configure publishing of the sbt plugin and tools library #130

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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