Skip to content

Commit 942598b

Browse files
authored
Merge pull request #130 from jonas/release
Configure publishing of the sbt plugin and tools library
2 parents ce84116 + 927eef6 commit 942598b

File tree

9 files changed

+218
-22
lines changed

9 files changed

+218
-22
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ This tool generates Scala Native bindings from C headers. It's built upon clang
66

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

9+
## Releasing
10+
11+
To release version `x.y.z` run:
12+
13+
> sbt -Dproject.version=x.y.z release
14+
15+
Then build the `scala-native-bindgen` executable for both macOS and
16+
Linux and upload them to the GitHub release page with the suffix
17+
`-darwin` and `-linux`, respectively.
18+
919
## License
1020

1121
This project is distributed under the Scala license.

build.sbt

+70-7
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ val Versions = new {
1212

1313
inThisBuild(
1414
Def.settings(
15-
organization := "org.scalanative.bindgen",
16-
version := "0.2-SNAPSHOT",
15+
organization := "org.scala-native.bindgen",
16+
licenses := Seq(
17+
"BSD 3-Clause" -> url("https://www.scala-lang.org/license/")),
18+
homepage := Some(url("https://kornilova-l.github.io/scala-native-bindgen")),
1719
scalacOptions ++= Seq(
1820
"-deprecation",
1921
"-unchecked",
@@ -24,7 +26,20 @@ inThisBuild(
2426
scmInfo := Some(
2527
ScmInfo(url("https://github.com/kornilova-l/scala-native-bindgen"),
2628
"scm:git:[email protected]:kornilova-l/scala-native-bindgen.git")),
27-
git.remoteRepo := scmInfo.value.get.connection.replace("scm:git:", "")
29+
developers := List(
30+
Developer(
31+
id = "kornilova-l",
32+
name = "Liudmila Kornilova",
33+
email = "[email protected]",
34+
url = url("https://github.com/kornilova-l")
35+
),
36+
Developer(
37+
id = "jonas",
38+
name = "Jonas Fonseca",
39+
email = "[email protected]",
40+
url = url("https://github.com/jonas")
41+
)
42+
)
2843
))
2944

3045
val root = project("scala-native-bindgen")
@@ -36,12 +51,33 @@ val root = project("scala-native-bindgen")
3651
sbtPlugin,
3752
docs
3853
)
54+
.enablePlugins(ReleasePlugin)
55+
.settings(
56+
publish / skip := true,
57+
releaseCrossBuild := false,
58+
releaseVersionFile := target.value / "unused-version.sbt",
59+
releaseProcess := {
60+
import ReleaseTransformations._
61+
Seq[ReleaseStep](
62+
checkSnapshotDependencies,
63+
setReleaseVersions(version.value),
64+
runClean,
65+
releaseStepCommandAndRemaining("verify"),
66+
setReleaseVersion,
67+
tagRelease,
68+
releaseStepCommandAndRemaining("^publish"),
69+
pushChanges,
70+
releaseStepTask(docs / ghpagesPushSite)
71+
)
72+
}
73+
)
3974

4075
lazy val tests = project("tests")
4176
.dependsOn(tools)
4277
.settings(
43-
fork in Test := true,
44-
javaOptions in Test += {
78+
publish / skip := true,
79+
Test / fork := true,
80+
Test / javaOptions += {
4581
val rootDir = (ThisBuild / baseDirectory).value
4682
s"-Dbindgen.path=$rootDir/bindgen/target/scala-native-bindgen"
4783
},
@@ -57,6 +93,7 @@ lazy val samples = project("samples")
5793
.in(file("tests/samples"))
5894
.enablePlugins(ScalaNativePlugin)
5995
.settings(
96+
publish / skip := true,
6097
scalaVersion := Versions.scala211,
6198
libraryDependencies += "com.lihaoyi" %%% "utest" % "0.6.3" % "test",
6299
testFrameworks += new TestFramework("utest.runner.Framework"),
@@ -108,20 +145,30 @@ lazy val tools = project("tools")
108145

109146
lazy val sbtPlugin = project("sbt-scala-native-bindgen", ScriptedPlugin)
110147
.dependsOn(tools)
148+
.enablePlugins(BuildInfoPlugin)
111149
.settings(
112150
Keys.sbtPlugin := true,
113151
scriptedLaunchOpts += s"-Dplugin.version=${version.value}",
114152
scriptedLaunchOpts += {
115153
val rootDir = (ThisBuild / baseDirectory).value
116154
s"-Dbindgen.path=$rootDir/bindgen/target/scala-native-bindgen"
117155
},
156+
buildInfoPackage := "org.scalanative.bindgen.sbt",
157+
buildInfoKeys := Seq[BuildInfoKey](
158+
version,
159+
organization,
160+
BuildInfoKey.map(scmInfo) {
161+
case (k, v) => "projectUrl" -> v.get.browseUrl
162+
}
163+
),
118164
publishLocal := publishLocal.dependsOn(tools / publishLocal).value
119165
)
120166

121167
lazy val docs = project("docs")
122168
.enablePlugins(GhpagesPlugin, ParadoxSitePlugin, ParadoxMaterialThemePlugin)
123169
.settings(
124-
paradoxProperties in Paradox ++= Map(
170+
publish / skip := true,
171+
Paradox / paradoxProperties ++= Map(
125172
"github.base_url" -> scmInfo.value.get.browseUrl.toString
126173
),
127174
ParadoxMaterialThemePlugin.paradoxMaterialThemeSettings(Paradox),
@@ -134,15 +181,31 @@ lazy val docs = project("docs")
134181

135182
def project(name: String, plugged: AutoPlugin*) = {
136183
val unplugged = Seq(ScriptedPlugin).filterNot(plugged.toSet)
184+
137185
Project(id = name, base = file(name))
138186
.disablePlugins(unplugged: _*)
187+
.enablePlugins(GitPlugin)
188+
.enablePlugins(GitVersioning)
139189
.settings(
190+
versionWithGit,
191+
git.useGitDescribe := true,
192+
git.remoteRepo := scmInfo.value.get.connection.replace("scm:git:", ""),
140193
crossSbtVersions := List(Versions.sbt013, Versions.sbt1),
141194
scalaVersion := {
142195
(pluginCrossBuild / sbtBinaryVersion).value match {
143196
case "0.13" => Versions.scala210
144197
case _ => Versions.scala212
145198
}
146-
}
199+
},
200+
bintrayOrganization := Some("scala-native-bindgen"),
201+
bintrayRepository := {
202+
if (Keys.sbtPlugin.value) "sbt-plugins"
203+
else "maven"
204+
},
205+
publishMavenStyle := Keys.sbtPlugin.value == false,
206+
Test / publishArtifact := false
147207
)
148208
}
209+
210+
lazy val setReleaseVersions: String => State => State =
211+
v => _.put(ReleaseKeys.versions, (v, v))

docs/src/paradox/obtaining-bindgen/index.md

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
@@@ index
44

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

1112
There are 3 ways to obtain bindgen:
1213

14+
* @ref:[Use the sbt plugin](sbt-plugin.md)
15+
1316
* @ref:[Use docker container](docker-container.md)
1417

1518
* @ref:[Build binary with CMake](cmake.md)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Using the sbt plugin
2+
3+
To add the sbt plugin to your project add the following lines in `project/plugins.sbt`:
4+
5+
@@@ vars
6+
```sbt
7+
addSbtPlugin("org.scala-native.bindgen" % "sbt-scala-native-bindgen" % "$project.version$")
8+
9+
resolvers += Resolver.bintrayIvyRepo("scala-native-bindgen", "sbt-plugin")
10+
resolvers += Resolver.bintrayRepo("scala-native-bindgen", "maven")
11+
```
12+
@@@
13+
14+
Next configure the plugin using the settings scoped to either `Compile` or `Test`:
15+
16+
|---------------------------|-------------------|
17+
|`nativeBindgenHeader` | The C header file to read.
18+
|`nativeBindgenPackage` | Package of the enclosing object. No package by default.
19+
|`name in nativeBindgen` | Name of the enclosing object.
20+
|`nativeBindgenLink` | Name of library to be linked.
21+
22+
@@@ note
23+
24+
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.
25+
26+
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.:
27+
28+
```sbt
29+
nativeBindgenPath := file("/path/to/scala-native-bindgen")
30+
```
31+
32+
@@@
33+
34+
Example settings:
35+
36+
```sbt
37+
enablePlugins(ScalaNativeBindgenPlugin)
38+
inConfig(Compile)(
39+
Def.settings(
40+
nativeBindgenHeader := (resourceDirectory in Compile).value / "header.h",
41+
nativeBindgenPackage := Some("org.example.mylib"),
42+
nativeBindgenLink := Some("mylib"), // Will pass `-lmylib` to the linker
43+
nativeBindgenExclude := Some("__"),
44+
name in nativeBindgen := "MyLib"
45+
))
46+
```
47+
48+
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:
49+
50+
```scala
51+
package org.example.mylib
52+
53+
import scala.scalanative._
54+
import scala.scalanative.native._
55+
56+
@native.link("mylib")
57+
@native.extern
58+
object MyLib {
59+
// ... left out for brevity ...
60+
}
61+
```

project/plugins.sbt

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.3.8")
2-
addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.3.2")
3-
addSbtPlugin("io.github.jonas" % "sbt-paradox-material-theme" % "0.4.0")
4-
addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.2")
1+
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.3.8")
2+
addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.3.2")
3+
addSbtPlugin("io.github.jonas" % "sbt-paradox-material-theme" % "0.4.0")
4+
addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.2")
5+
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0")
6+
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.9")
7+
addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.4")
8+
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.9.0")
59

610
libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value

sbt-scala-native-bindgen/src/main/scala/org/scalanative/bindgen/sbt/ScalaNativeBindgenPlugin.scala

+62-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package org.scalanative.bindgen.sbt
33
import sbt._
44
import sbt.Keys._
55

6+
import java.nio.file.Files
7+
import java.nio.file.attribute.{PosixFileAttributeView, PosixFilePermission}
8+
69
import org.scalanative.bindgen.Bindgen
710

811
/**
@@ -25,13 +28,21 @@ import org.scalanative.bindgen.Bindgen
2528
*
2629
* Keys are defined in [[ScalaNativeBindgenPlugin.autoImport]].
2730
*
31+
* - `nativeBindgenPath`: Path to the `scala-native-bindgen` executable.
2832
* - `nativeBindgenHeader`: The C header file to read.
2933
*
3034
* - `nativeBindgenPackage`: Package of the enclosing object.
3135
* No package by default.
3236
*
3337
* - `name in nativeBindgen`: Name of the enclosing object.
3438
*
39+
* - `version in nativeBindgen`: Version of the `scala-native-bindgen`
40+
* to use when automatically downloading the executable.
41+
*
42+
* - `nativeBindgenLink`: Name of library to be linked.
43+
*
44+
* - `nativeBindgen`: Generate Scala Native bindings.
45+
*
3546
* @example
3647
* {{{
3748
* nativeBindgenHeader in Compile := file("/usr/include/ctype.h")
@@ -42,8 +53,9 @@ import org.scalanative.bindgen.Bindgen
4253
object ScalaNativeBindgenPlugin extends AutoPlugin {
4354

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

5971
override def projectSettings: Seq[Setting[_]] =
60-
nativeBindgenScopedSettings(Compile)
72+
inConfig(ScalaNativeBindgen)(Defaults.configSettings) ++
73+
nativeBindgenScopedSettings(Compile) ++
74+
Def.settings(
75+
ivyConfigurations += ScalaNativeBindgen,
76+
version in nativeBindgen := BuildInfo.version,
77+
libraryDependencies ++= {
78+
artifactName.map { name =>
79+
val bindgenVersion = (version in nativeBindgen).value
80+
val url =
81+
s"${BuildInfo.projectUrl}/releases/download/v$bindgenVersion/$name"
82+
83+
BuildInfo.organization % name % bindgenVersion % ScalaNativeBindgen from (url)
84+
}.toSeq
85+
},
86+
nativeBindgenPath := {
87+
val scalaNativeBindgenUpdate = (update in ScalaNativeBindgen).value
88+
89+
val artifactFile = artifactName match {
90+
case None =>
91+
sys.error(
92+
"No downloadable binaries available for your OS, " +
93+
"please provide path via `nativeBindgenPath`")
94+
case Some(name) =>
95+
scalaNativeBindgenUpdate
96+
.select(artifact = artifactFilter(name = name))
97+
.head
98+
}
99+
100+
// Set the executable bit on the expected path to fail if it doesn't exist
101+
for (view <- Option(
102+
Files.getFileAttributeView(artifactFile.toPath,
103+
classOf[PosixFileAttributeView]))) {
104+
val permissions = view.readAttributes.permissions
105+
if (permissions.add(PosixFilePermission.OWNER_EXECUTE))
106+
view.setPermissions(permissions)
107+
}
108+
109+
artifactFile
110+
}
111+
)
61112

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

121+
private val artifactName =
122+
Option(System.getProperty("os.name")).collect {
123+
case "Mac OS X" => "scala-native-bindgen-darwin"
124+
case "Linux" => "scala-native-bindgen-linux"
125+
}
126+
70127
def nativeBindgenScopedSettings(conf: Configuration): Seq[Setting[_]] =
71128
inConfig(conf)(
72-
Seq(
129+
Def.settings(
73130
nativeBindgenHeader := {
74131
sys.error("nativeBindgenHeader not configured")
75132
},
76-
nativeBindgenPath := None,
77133
nativeBindgenPackage := None,
78134
nativeBindgenExclude := None,
79-
resourceDirectories in nativeBindgen := resourceDirectories.value,
80135
sourceGenerators += Def.task { Seq(nativeBindgen.value) },
81136
name in nativeBindgen := "ScalaNativeBindgen",
82137
nativeBindgen := {
83-
val output = sourceManaged.value / "sbt-scala-native-bindgen" / "nativeBindgen.scala"
138+
val output = sourceManaged.value / "sbt-scala-native-bindgen" / "ScalaNativeBindgen.scala"
84139

85140
Bindgen()
86-
.bindgenExecutable(nativeBindgenPath.value.get)
141+
.bindgenExecutable(nativeBindgenPath.value)
87142
.header(nativeBindgenHeader.value)
88143
.name((name in nativeBindgen).value)
89144
.maybe(nativeBindgenLink.value, _.link)

sbt-scala-native-bindgen/src/sbt-test/bindgen/generate/build.sbt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
name := "test"
2-
organization := "org.scalanative.bindgen.sbt.test"
2+
organization := "org.scala-native.bindgen.sbt.test"
33
enablePlugins(ScalaNativeBindgenPlugin)
44
scalaVersion := "2.11.12"
55

66
inConfig(Compile)(
77
Def.settings(
8-
nativeBindgenPath := Option(System.getProperty("bindgen.path")).map(file),
8+
nativeBindgenPath := file(System.getProperty("bindgen.path")),
99
nativeBindgenHeader := (resourceDirectory in Compile).value / "header.h",
1010
nativeBindgenPackage := Some("org.example.app"),
1111
nativeBindgenLink := Some("app"),
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
addSbtPlugin(
2-
"org.scalanative.bindgen" % "sbt-scala-native-bindgen" % sys.props(
2+
"org.scala-native.bindgen" % "sbt-scala-native-bindgen" % sys.props(
33
"plugin.version"))

0 commit comments

Comments
 (0)