(added details about plugins) |
|||
(2 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
= Building packages that use <code>sbt</code> = | = Building packages that use <code>sbt</code> = | ||
This is a quick guide to getting Fedora packages built with <code>sbt</code>. Since <code>sbt</code> uses Ivy for dependency resolution, you'll either need to construct a local Ivy repository as part of the build (for F20) or rely on xmvn's improved support for Ivy metadata (in F21 and above after xmvn 2.0 lands). For now, this guide covers building packages on F20 with the [https://github.com/willb/climbing-nemesis/ climbing-nemesis] script. | This is a quick guide to getting Fedora packages built with <code>sbt</code>. Since <code>sbt</code> uses Ivy for dependency resolution, you'll either need to construct a local Ivy repository as part of the build (for F20) or rely on xmvn's improved support for Ivy metadata (in F21 and above after xmvn 2.0 lands). For now, this guide covers building packages on F20 with the [https://github.com/willb/climbing-nemesis/ climbing-nemesis] script. | ||
Line 9: | Line 7: | ||
== Differences with upstream <code>sbt</code> == | == Differences with upstream <code>sbt</code> == | ||
<code>sbt</code> | The Fedora <code>sbt</code> package is primarily intended to be used for packaging <code>sbt</code>-based projects in Fedora. While you'll be able to use it to do general Scala development as well, some features that <code>sbt</code> users expect to have available (most notably, cross-building for incompatible Scala versions and launching different versions of <code>sbt</code> for different projects) have been removed since it is difficult or impossible to support them while meeting Fedora packaging guidelines. | ||
How <code>sbt</code> resolves Ivy dependencies is specified [http://www.scala-sbt.org/0.13.1/docs/Detailed-Topics/Launcher.html by a properties file] (see also [http://www.scala-sbt.org/release/docs/Detailed-Topics/Resolvers.html <code>sbt</code> resolver specifications]). For the Fedora <code>sbt</code>, this defaults to <code>/etc/sbt/sbt.boot.properties</code>, but you can override this by setting <code>SBT_BOOT_PROPERTIES</code> in your environment. Without overriding the properties file, the <code>sbt</code> script shipping in Fedora will allow you to specify the path to a local Ivy repository (set <code>SBT_IVY_DIR</code>) and the path to a cache of resolved artifacts that <code>sbt</code> needs to run (set <code>SBT_BOOT_DIR</code>). We'll discuss these more later in this document. | How Fedora <code>sbt</code> resolves Ivy dependencies is specified [http://www.scala-sbt.org/0.13.1/docs/Detailed-Topics/Launcher.html by a properties file] (see also [http://www.scala-sbt.org/release/docs/Detailed-Topics/Resolvers.html <code>sbt</code> resolver specifications]). For the Fedora <code>sbt</code>, this defaults to <code>/etc/sbt/sbt.boot.properties</code>, but you can override this by setting <code>SBT_BOOT_PROPERTIES</code> in your environment. Without overriding the properties file, the <code>sbt</code> script shipping in Fedora will allow you to specify the path to a local Ivy repository (set <code>SBT_IVY_DIR</code>) and the path to a cache of resolved artifacts that <code>sbt</code> needs to run (set <code>SBT_BOOT_DIR</code>). We'll discuss these more later in this document. | ||
== General tips and tricks == | == General tips and tricks == | ||
<code>sbt</code> build files are either written in a domain-specific language (<code>*.sbt</code> files) or are general Scala code that incorporates <code>sbt</code> as a library, and they typically either live in the root directory of a project's source tree or in the <code>project</code> directory. Because they aren't XML files, patches against <code>sbt</code> builds are typically less brittle than patches against Ant build files, and it's more straightforward to carry Fedora-specific build patches as <code>sed</code> commands. | |||
<code>sbt</code> build files list dependencies in [http://www.scala-sbt.org/release/docs/Getting-Started/Library-Dependencies a particular format]: <code> GROUP % ARTIFACT % VERSION </code> or <code> GROUP % ARTIFACT % VERSION % CONFIG </code>. You will also occasionally see dependencies of the form <code> GROUP %% ARTIFACT % VERSION </code>; the double-percent sign indicates that the Scala version should be appended to the artifact name, as is common practice for Scala artifacts in Maven and Ivy repositories. | <code>sbt</code> build files list dependencies in [http://www.scala-sbt.org/release/docs/Getting-Started/Library-Dependencies a particular format]: <code> GROUP % ARTIFACT % VERSION </code> or <code> GROUP % ARTIFACT % VERSION % CONFIG </code>. You will also occasionally see dependencies of the form <code> GROUP %% ARTIFACT % VERSION </code>; the double-percent sign indicates that the Scala version should be appended to the artifact name, as is common practice for Scala artifacts in Maven and Ivy repositories. | ||
Line 21: | Line 19: | ||
You'll want to patch the <code>project/build.properties</code> file, if there is one, to make sure that the project expects the version of <code>sbt</code> that is packaged in Fedora. You'll also want to make sure that the Scala version expected by this project is exactly the same as the one available in Fedora. If the project expects Scala 2.10.2, you'll need to patch the build files to have it look for 2.10.3 instead. | You'll want to patch the <code>project/build.properties</code> file, if there is one, to make sure that the project expects the version of <code>sbt</code> that is packaged in Fedora. You'll also want to make sure that the Scala version expected by this project is exactly the same as the one available in Fedora. If the project expects Scala 2.10.2, you'll need to patch the build files to have it look for 2.10.3 instead. | ||
Any <code>sbt</code> plugins mentioned in your project's build are probably not available in Fedora. Fortunately, most builds will proceed just fine without them (at least if we're building for Fedora); a pattern that works for many projects is to remove the contents of <code>project/plugins.sbt</code> in <code>%prep</code> and then make a Fedora-specific patch eliminating any code from other build files that fails to compile once the plugins are removed. (Of course, [[SIGs/bigdata/packaging/Scala# | Any <code>sbt</code> plugins mentioned in your project's build are probably not available in Fedora. Fortunately, most builds will proceed just fine without them (at least if we're building for Fedora); a pattern that works for many projects is to remove the contents of <code>project/plugins.sbt</code> in <code>%prep</code> and then make a Fedora-specific patch eliminating any code from other build files that fails to compile once the plugins are removed. (Of course, [[SIGs/bigdata/packaging/Scala#Other_Scala_projects_to_package | packaging plugins is a great way to help out]]!) | ||
=== Helpful macros === | === Helpful macros === | ||
Line 38: | Line 36: | ||
== Using <code>climbing-nemesis</code> == | == Using <code>climbing-nemesis</code> == | ||
The <code>climbing-nemesis</code> script uses Fedora's Maven metadata to construct and populate a local Ivy repository with artifacts you select. To use it, you'll need the script itself to be accessible from your build directory and to have added BuildRequires on <code>python</code> and <code>maven-local</code>. It has many options, all of which are documented in its on-line help; we will cover some of the most common ones here. The most basic <code>climbing-nemesis</code> invocation consists simply of a group ID, an artifact ID, and a path to the local Ivy repository, like this: | |||
<pre> | |||
./climbing_nemesis.py com.h2database h2 ivy-local | |||
</pre> | |||
The above will install <code>com.h2database:h2</code> into <code>ivy-local</code>, creating Ivy metadata from Maven metadata and making a symbolic link from the Ivy repository to the local, RPM-managed artifact. If you'd like to override the version number that <code>xmvn-resolve</code> decides is appropriate for the artifact, you can do so with the <code>--version</code> flag. Since packages occasionally have broken Maven metadata, it can be convenient to override the version string by default; this macro is helpful in that case: | |||
<pre> | |||
# The first argument is a group ID, the second is an artifact ID | |||
# Wrap the whole invocation in curly braces if you need to pass additional arguments! | |||
%global climbing_nemesis() ./climbing-nemesis.py %{1} %{2} ivy-local --version $(rpm -q --qf "%%%%{version}" $(rpm -q --whatprovides "mvn(%{1}:%{2})" )) | |||
</pre> | |||
By default, <code>climbing-nemesis</code> will install all dependencies that aren't listed under <code>test</code> or <code>optional</code> configurations. Because we sometimes don't use every capability implied in a POM file and because Maven metadata sometimes has incorrect dependency information, you may wish to remove or override dependencies. You can remove dependencies with the <code>--ignore</code> flag, add extra dependencies with the <code>--extra-dep</code> flag, and override the required version of a dependency by doing both, like this: | |||
<pre> | |||
%{climbing_nemesis cglib cglib-full ivy-local} --ignore asm --extra-dep asm:asm:$(rpm -q --qf "%%{version}" $(rpm -q --whatprovides "mvn(asm:asm)" )) | |||
</pre> | |||
Some Fedora Java packages don't have Maven metadata at all. In those cases, we can explicitly specify where to find a JAR file and what version it is: | |||
<pre> | |||
./climbing-nemesis.py --jarfile %{_javadir}/foofactory.jar com.foobar foofactory ivy-local --version 42.1 | |||
</pre> | |||
You can also use the <code>--pomfile</code> and <code>--ivyfile</code> options to take metadata from descriptor files pulled down from upstreams. | |||
Some Scala packages use additional Ivy metadata. This will be supported in xmvn 2.0, but for now, we need to specify it explicitly using the <code>--meta</code> option to <code>climbing-nemesis</code>, for example <code>--meta e:scalaVersion=2.10</code>. You can also use the <code>--scala VERSION</code> option to append <code>_VERSION</code> to the artifact name. |
Latest revision as of 14:08, 19 March 2014
Building packages that use sbt
This is a quick guide to getting Fedora packages built with sbt
. Since sbt
uses Ivy for dependency resolution, you'll either need to construct a local Ivy repository as part of the build (for F20) or rely on xmvn's improved support for Ivy metadata (in F21 and above after xmvn 2.0 lands). For now, this guide covers building packages on F20 with the climbing-nemesis script.
Eventually, I hope that the best practices around building Scala projects will coalesce into official Scala packaging guidelines, but for now it's sort of the wild west. Your feedback is welcome!
Differences with upstream sbt
The Fedora sbt
package is primarily intended to be used for packaging sbt
-based projects in Fedora. While you'll be able to use it to do general Scala development as well, some features that sbt
users expect to have available (most notably, cross-building for incompatible Scala versions and launching different versions of sbt
for different projects) have been removed since it is difficult or impossible to support them while meeting Fedora packaging guidelines.
How Fedora sbt
resolves Ivy dependencies is specified by a properties file (see also sbt
resolver specifications). For the Fedora sbt
, this defaults to /etc/sbt/sbt.boot.properties
, but you can override this by setting SBT_BOOT_PROPERTIES
in your environment. Without overriding the properties file, the sbt
script shipping in Fedora will allow you to specify the path to a local Ivy repository (set SBT_IVY_DIR
) and the path to a cache of resolved artifacts that sbt
needs to run (set SBT_BOOT_DIR
). We'll discuss these more later in this document.
General tips and tricks
sbt
build files are either written in a domain-specific language (*.sbt
files) or are general Scala code that incorporates sbt
as a library, and they typically either live in the root directory of a project's source tree or in the project
directory. Because they aren't XML files, patches against sbt
builds are typically less brittle than patches against Ant build files, and it's more straightforward to carry Fedora-specific build patches as sed
commands.
sbt
build files list dependencies in a particular format: GROUP % ARTIFACT % VERSION
or GROUP % ARTIFACT % VERSION % CONFIG
. You will also occasionally see dependencies of the form GROUP %% ARTIFACT % VERSION
; the double-percent sign indicates that the Scala version should be appended to the artifact name, as is common practice for Scala artifacts in Maven and Ivy repositories.
You'll want to patch the project/build.properties
file, if there is one, to make sure that the project expects the version of sbt
that is packaged in Fedora. You'll also want to make sure that the Scala version expected by this project is exactly the same as the one available in Fedora. If the project expects Scala 2.10.2, you'll need to patch the build files to have it look for 2.10.3 instead.
Any sbt
plugins mentioned in your project's build are probably not available in Fedora. Fortunately, most builds will proceed just fine without them (at least if we're building for Fedora); a pattern that works for many projects is to remove the contents of project/plugins.sbt
in %prep
and then make a Fedora-specific patch eliminating any code from other build files that fails to compile once the plugins are removed. (Of course, packaging plugins is a great way to help out!)
Helpful macros
The first of these macros, remap_version
, takes a group ID, an artifact ID, a version string, and a sbt
build file and updates the file so that any dependency on the given artifact is for the version specified in the macro invocation and not on whatever version was in the build file.
%global remap_version() sed -i -e 's/"%{1}" %% "%{2}" %% "[^"]*"/"%{1}" %% "%{2}" %% "'%{3}'"/g' %{4}
remap_version_to_installed
takes a group ID, an artifact ID, and a sbt
build file and updates the file so that any dependency on the given artifact is for the version of that artifact installed on the build machine.
%global remap_version_to_installed() sed -i -e 's/"%{1}" %% "%{2}" %% "[^"]*"/"%{1}" %% "%{2}" %% "'$(rpm -q --qf "%%%%{version}" $(rpm -q --whatprovides "mvn(%{1}:%{2})" ))'"/g' %{3}
Using climbing-nemesis
The climbing-nemesis
script uses Fedora's Maven metadata to construct and populate a local Ivy repository with artifacts you select. To use it, you'll need the script itself to be accessible from your build directory and to have added BuildRequires on python
and maven-local
. It has many options, all of which are documented in its on-line help; we will cover some of the most common ones here. The most basic climbing-nemesis
invocation consists simply of a group ID, an artifact ID, and a path to the local Ivy repository, like this:
./climbing_nemesis.py com.h2database h2 ivy-local
The above will install com.h2database:h2
into ivy-local
, creating Ivy metadata from Maven metadata and making a symbolic link from the Ivy repository to the local, RPM-managed artifact. If you'd like to override the version number that xmvn-resolve
decides is appropriate for the artifact, you can do so with the --version
flag. Since packages occasionally have broken Maven metadata, it can be convenient to override the version string by default; this macro is helpful in that case:
# The first argument is a group ID, the second is an artifact ID # Wrap the whole invocation in curly braces if you need to pass additional arguments! %global climbing_nemesis() ./climbing-nemesis.py %{1} %{2} ivy-local --version $(rpm -q --qf "%%%%{version}" $(rpm -q --whatprovides "mvn(%{1}:%{2})" ))
By default, climbing-nemesis
will install all dependencies that aren't listed under test
or optional
configurations. Because we sometimes don't use every capability implied in a POM file and because Maven metadata sometimes has incorrect dependency information, you may wish to remove or override dependencies. You can remove dependencies with the --ignore
flag, add extra dependencies with the --extra-dep
flag, and override the required version of a dependency by doing both, like this:
%{climbing_nemesis cglib cglib-full ivy-local} --ignore asm --extra-dep asm:asm:$(rpm -q --qf "%%{version}" $(rpm -q --whatprovides "mvn(asm:asm)" ))
Some Fedora Java packages don't have Maven metadata at all. In those cases, we can explicitly specify where to find a JAR file and what version it is:
./climbing-nemesis.py --jarfile %{_javadir}/foofactory.jar com.foobar foofactory ivy-local --version 42.1
You can also use the --pomfile
and --ivyfile
options to take metadata from descriptor files pulled down from upstreams.
Some Scala packages use additional Ivy metadata. This will be supported in xmvn 2.0, but for now, we need to specify it explicitly using the --meta
option to climbing-nemesis
, for example --meta e:scalaVersion=2.10
. You can also use the --scala VERSION
option to append _VERSION
to the artifact name.