-
Notifications
You must be signed in to change notification settings - Fork 445
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from sbt/wip/symlinks
Add a layer between universal + specific native packages
- Loading branch information
Showing
24 changed files
with
835 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ Add the following to your `project/plugins.sbt` or `~/.sbt/plugins.sbt` file: | |
|
||
resolvers += Resolver.url("scalasbt", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases"))(Resolver.ivyStylePatterns) | ||
|
||
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "0.5.4") | ||
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "0.6.0-symlink-3") | ||
|
||
Then, in the project you wish to use the plugin, add the following settings: | ||
|
||
|
@@ -25,51 +25,26 @@ or | |
Using the sbt-native-packger plugin requires a bit of understanding of the underlying packaging mechanisms for each operating system it supports. The [generated documentation](http://scala-sbt.org/sbt-native-packager) for the plugin is still a work in progress. | ||
|
||
|
||
Here's an example excerpt for the debian + rpm package of [sbt-extras](http://github.com/paulp/sbt-extras) project: | ||
Here's an example excerpt for the native packaging of [sbt-launcher-packge](http://github.com/sbt/sbt-launcher-package) project: | ||
|
||
// GENERAL LINUX PACKAGING STUFFS | ||
maintainer := "Josh Suereth <[email protected]>", | ||
packageSummary := "Simple Build Tool for Scala-driven builds", | ||
packageDescription := """This script provides a native way to run the Simple Build Tool, | ||
a build tool for Scala software, also called SBT.""", | ||
linuxPackageMappings <+= (baseDirectory) map { bd => | ||
(packageMapping((bd / "sbt") -> "/usr/bin/sbt") | ||
withUser "root" withGroup "root" withPerms "0755") | ||
a build tool for Scala software, also called SBT.""", | ||
// Here we remove the jar file and launch lib from the symlinks: | ||
linuxPackageSymlinks <<= linuxPackageSymlinks map { links => | ||
for { | ||
link <- links | ||
if !(link.destination endsWith "sbt-launch-lib.bash") | ||
if !(link.destination endsWith "sbt-launch.jar") | ||
} yield link | ||
}, | ||
linuxPackageMappings <+= (sourceDirectory) map { bd => | ||
(packageMapping( | ||
(bd / "linux" / "usr/share/man/man1/sbt.1") -> "/usr/share/man/man1/sbt.1.gz" | ||
) withPerms "0644" gzipped) asDocs() | ||
}, | ||
linuxPackageMappings <+= (sourceDirectory in Linux) map { bd => | ||
packageMapping( | ||
(bd / "usr/share/doc/sbt/copyright") -> "/usr/share/doc/sbt/copyright" | ||
) withPerms "0644" asDocs() | ||
}, | ||
linuxPackageMappings <+= (sourceDirectory in Linux) map { bd => | ||
packageMapping( | ||
(bd / "usr/share/doc/sbt") -> "/usr/share/doc/sbt" | ||
) asDocs() | ||
}, | ||
linuxPackageMappings <+= (sourceDirectory in Linux) map { bd => | ||
packageMapping( | ||
(bd / "etc/sbt") -> "/etc/sbt" | ||
) withConfig() | ||
}, | ||
linuxPackageMappings <+= (sourceDirectory in Linux) map { bd => | ||
packageMapping( | ||
(bd / "etc/sbt/sbtopts") -> "/etc/sbt/sbtopts" | ||
) withPerms "0644" withConfig("noreplace") | ||
}, | ||
linuxPackageMappings <+= (sbtLaunchJar, sourceDirectory in Linux, sbtVersion) map { (jar, dir, v) => | ||
packageMapping(dir -> "/usr/lib/sbt", | ||
dir -> ("/usr/lib/sbt/" + v), | ||
jar -> ("/usr/lib/sbt/"+v+"/sbt-launch.jar")) withPerms "0755" | ||
}, | ||
// DEBIAN SPECIFIC | ||
name in Debian := "sbt", | ||
// DEBIAN SPECIFIC | ||
name in Debian <<= (sbtVersion) apply { (sv) => "sbt" /* + "-" + (sv split "[^\\d]" take 3 mkString ".")*/ }, | ||
version in Debian <<= (version, sbtVersion) apply { (v, sv) => | ||
sv + "-build-" + (v split "\\." map (_.toInt) dropWhile (_ == 0) map ("%02d" format _) mkString "") | ||
val nums = (v split "[^\\d]") | ||
"%s-%s-build-%03d" format (sv, (nums.init mkString "."), nums.last.toInt + 1) | ||
}, | ||
debianPackageDependencies in Debian ++= Seq("curl", "java2-runtime", "bash (>= 2.05a-11)"), | ||
debianPackageRecommends in Debian += "git", | ||
|
@@ -81,11 +56,30 @@ Here's an example excerpt for the debian + rpm package of [sbt-extras](http://gi | |
|
||
// RPM SPECIFIC | ||
name in Rpm := "sbt", | ||
version in Rpm <<= sbtVersion.identity, | ||
version in Rpm <<= sbtVersion apply { sv => (sv split "[^\\d]" filterNot (_.isEmpty) mkString ".") }, | ||
rpmRelease := "1", | ||
rpmVendor := "typesafe", | ||
rpmUrl := Some("http://github.com/paulp/sbt-extras"), | ||
rpmLicense := Some("BSD"), | ||
|
||
|
||
|
||
// WINDOWS SPECIFIC | ||
name in Windows := "sbt", | ||
version in Windows <<= (sbtVersion) apply { sv => | ||
(sv split "[^\\d]" filterNot (_.isEmpty)) match { | ||
case Array(major,minor,bugfix, _*) => Seq(major,minor,bugfix, "1") mkString "." | ||
case Array(major,minor) => Seq(major,minor,"0","1") mkString "." | ||
case Array(major) => Seq(major,"0","0","1") mkString "." | ||
} | ||
}, | ||
maintainer in Windows := "Typesafe, Inc.", | ||
packageSummary in Windows := "Simple Build Tool", | ||
packageDescription in Windows := "THE reactive build tool.", | ||
wixProductId := "ce07be71-510d-414a-92d4-dff47631848a", | ||
wixProductUpgradeId := "4552fb0e-e257-4dbd-9ecb-dba9dbacf424", | ||
javacOptions := Seq("-source", "1.5", "-target", "1.5"), | ||
|
||
// Universal ZIP download install. | ||
name in Universal := "sbt" | ||
|
||
The full build, including windows MSI generation, can be found [here](https://github.com/sbt/sbt-launcher-package/blob/full-packaging/project/packaging.scala). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
sbt.version=0.12.1 | ||
sbt.version=0.12.4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
149 changes: 149 additions & 0 deletions
149
src/main/scala/com/typesafe/sbt/packager/GenericPackageSettings.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package com.typesafe.sbt | ||
package packager | ||
|
||
import Keys._ | ||
import sbt._ | ||
import sbt.Keys.{name, mappings, sourceDirectory} | ||
import linux.LinuxSymlink | ||
import linux.LinuxPackageMapping | ||
|
||
object GenericPackageSettings { | ||
val installLocation = "/usr/share" | ||
} | ||
trait GenericPackageSettings | ||
extends linux.LinuxPlugin | ||
with debian.DebianPlugin | ||
with rpm.RpmPlugin | ||
with windows.WindowsPlugin | ||
with universal.UniversalPlugin { | ||
import GenericPackageSettings._ | ||
|
||
// This method wires a lot of hand-coded generalities about how to map directories | ||
// into linux, and the conventions we expect. | ||
// It is by no means 100% accurate, but should be ok for the simplest cases. | ||
// For advanced users, use the underlying APIs. | ||
// Right now, it's also pretty focused on command line scripts packages. | ||
|
||
/** | ||
* Maps linux file format from the universal from the conventions: | ||
* | ||
* `<project>/src/linux` files are mapped directly into linux packages. | ||
* `<universal>` files are placed under `/usr/share/<package-name>` | ||
* `<universal>/bin` files are given symlinks in `/usr/bin` | ||
* `<universal>/conf` directory is given a symlink to `/etc/<package-name>` | ||
* Files in `conf/` or `etc/` directories are automatically marked as configuration. | ||
* `../man/...1` files are automatically compressed into .gz files. | ||
*/ | ||
def mapGenericMappingsToLinux(mappings: Seq[(File, String)])(rename: String => String): Seq[LinuxPackageMapping] = { | ||
val (directories, nondirectories) = mappings.partition(_._1.isDirectory) | ||
val (binaries, nonbinaries) = nondirectories.partition(_._1.canExecute) | ||
val (manPages, nonManPages) = nonbinaries partition { | ||
case (file, name) => (name contains "man/") && (name endsWith ".1") | ||
} | ||
val compressedManPages = | ||
for((file, name) <- manPages) | ||
yield file -> (name + ".gz") | ||
val (configFiles, remaining) = nonManPages partition { | ||
case (file, name) => (name contains "etc/") || (name contains "conf/") | ||
} | ||
def packageMappingWithRename(mappings: (File, String)*): LinuxPackageMapping = { | ||
val renamed = | ||
for((file, name) <- mappings) | ||
yield file -> rename(name) | ||
packageMapping(renamed:_*) | ||
} | ||
|
||
Seq( | ||
packageMappingWithRename((binaries ++ directories):_*) withUser "root" withGroup "root" withPerms "0755", | ||
packageMappingWithRename(compressedManPages:_*).gzipped withUser "root" withGroup "root" withPerms "0644", | ||
packageMappingWithRename(configFiles:_*) withConfig() withUser "root" withGroup "root" withPerms "0644", | ||
packageMappingWithRename(remaining:_*) withUser "root" withGroup "root" withPerms "0644" | ||
) | ||
} | ||
|
||
def mapGenericFilesToLinux: Seq[Setting[_]] = Seq( | ||
// First we look at the src/linux files | ||
linuxPackageMappings <++= (name in Universal, sourceDirectory in Linux) map { (pkg, dir) => | ||
mapGenericMappingsToLinux((dir.*** --- dir) x relativeTo(dir))(identity) | ||
}, | ||
// Now we look at the src/universal files. | ||
linuxPackageMappings <++= (name in Universal, mappings in Universal) map { (pkg, mappings) => | ||
// TODO - More windows filters... | ||
def isWindowsFile(f: (File, String)): Boolean = | ||
f._2 endsWith ".bat" | ||
|
||
mapGenericMappingsToLinux(mappings filterNot isWindowsFile) { name => | ||
installLocation + "/" + pkg + "/" + name | ||
} | ||
}, | ||
// Now we generate symlinks. | ||
linuxPackageSymlinks <++= (name in Universal, mappings in Universal) map { (pkg, mappings) => | ||
for { | ||
(file, name) <- mappings | ||
if !file.isDirectory | ||
if name startsWith "bin/" | ||
if !(name endsWith ".bat") // IGNORE windows-y things. | ||
} yield LinuxSymlink("/usr/" + name, installLocation+"/"+pkg+"/"+name) | ||
}, | ||
// Map configuration files | ||
linuxPackageSymlinks <++= (name in Universal, mappings in Universal) map { (pkg, mappings) => | ||
val needsConfLink = | ||
mappings exists { case (file, name) => | ||
(name startsWith "conf/") && !file.isDirectory | ||
} | ||
if(needsConfLink) Seq(LinuxSymlink( | ||
link="/etc/" + pkg, | ||
destination=installLocation+"/"+pkg+"/conf")) | ||
else Seq.empty | ||
} | ||
) | ||
|
||
def mapGenericFilesToWindows: Seq[Setting[_]] = Seq( | ||
mappings in Windows <<= mappings in Universal, | ||
wixFeatures <<= (name in Windows, mappings in Windows) map makeWindowsFeatures | ||
) | ||
// TODO select main script! Filter Config links! | ||
def makeWindowsFeatures(name: String, mappings: Seq[(File, String)]): Seq[windows.WindowsFeature] = { | ||
import windows._ | ||
|
||
val files = | ||
for { | ||
(file, name) <- mappings | ||
if !file.isDirectory | ||
} yield ComponentFile(name, editable = (name startsWith "conf")) | ||
val corePackage = | ||
WindowsFeature( | ||
id=name+"Core", | ||
title=name, | ||
desc="All core files.", | ||
absent="disallow", | ||
components = files | ||
) | ||
// TODO - Detect bat files to add paths... | ||
val homeEnvVar = name.toUpperCase +"_HOME" | ||
val addBinToPath = | ||
// TODO - we may have issues here... | ||
WindowsFeature( | ||
id="AddBinToPath", | ||
title="Update Enviornment Variables", | ||
desc="Update PATH environment variables (requires restart).", | ||
components = Seq(AddDirectoryToPath("bin")) | ||
) | ||
val configLinks = for { | ||
(file, name) <- mappings | ||
if !file.isDirectory | ||
if name startsWith "conf/" | ||
} yield name | ||
val menuLinks = | ||
WindowsFeature( | ||
id="AddConfigLinks", | ||
title="Configuration start menu links", | ||
desc="Adds start menu shortcuts to edit configuration files.", | ||
components = Seq(AddShortCuts(configLinks)) | ||
) | ||
// TODO - Add feature for shortcuts to binary scripts. | ||
Seq(corePackage, addBinToPath, menuLinks) | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.