Skip to content

Commit

Permalink
Merge branch 'release/0.4.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
xerial committed Jan 3, 2014
2 parents 3e95bed + a6d0aac commit 869a4ef
Show file tree
Hide file tree
Showing 24 changed files with 749 additions and 41 deletions.
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
language: scala
scala:
- 2.10.3

script: sbt ++$TRAVIS_SCALA_VERSION scripted

branches:
only:
- develop
- feature/sbt-0.12.x
50 changes: 36 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ A sbt plugin for creating distributable Scala packages that include dependent ja
- `sbt pack` creates a distributable package in `target/pack` folder.
- All dependent jars including scala-library.jar are collected in `target/pack/lib` folder. This process is much faster than creating a single-jar as in `sbt-assembly` or `proguard` plugins.
- Supporting multi-module projects.
- `sbt pack-archive` generates `tar.gz` archive of the distributable project.
- The archive is `target/{program name}-{version}.tar.gz`
- `sbt pack-archive` generates `tar.gz` archive that is ready to distribute.
- The archive name is `target/{project name}-{version}.tar.gz`
- `sbt pack` generates program launch scripts `target/pack/bin/{program name}`
- To run the program no need exists to install Scala, since it is included in the lib folder. Only java command needs to be found in the system.
- It also generates `.bat` launch scripts for Windows users.
- Generates a Makefile for program installation.
- Do `cd target/pack; make install`. Then you can run your program with `~/local/bin/{program name}`
- You can install multiple versions of your program in the system.
Expand All @@ -29,11 +30,25 @@ Add `sbt-pack` plugin to your sbt configuration:
**project/plugins.sbt**

```scala
addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.3.4") // for sbt-0.13.x or higher
addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.4.0") // for sbt-0.13.x or higher

addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.2.4") // for sbt-0.12.x (will not be maintained)
addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.2.5") // for sbt-0.12.x (New features will not be supported in this version.)
```

#### Minimum configuration

**build.sbt**
```scala
packSettings

// [Optional: Mappings from a program name to the corresponding Main class ]
packMain := Map("hello" -> "myprog.Hello")
```

Now you can use `sbt pack` command in your project.

#### Full build configuration

Import `xerial.sbt.Pack.packSettings` into your project settings. Then set `packMain` variable, a mapping from the your program names to their corresponding main classes. The main classes must be Scala objects that define `def main(args:Array[])` method:

**project/Build.scala**
Expand All @@ -48,16 +63,23 @@ object Build extends sbt.Build {
lazy val root = Project(
id = "myprog",
base = file("."),
settings = Defaults.defaultSettings ++ packSettings ++
Seq(
// Specify mappings from program name -> Main class (full package path)
packMain := Map("hello" -> "myprog.Hello"),
// Add custom settings here
// [Optional] JVM options of scripts (program name -> Seq(JVM option, ...))
packJvmOpts := Map("hello" -> Seq("-Xmx512m")),
// [Optional] Extra class paths to look when launching a program
packExtraClasspath := Map("hello" -> Seq("${PROG_HOME}/etc"))
)
settings = Defaults.defaultSettings
++ packSettings // This settings add pack and pack-archive commands to sbt
++ Seq(
// [Optional] Specify mappings from program name -> Main class (full package path)
packMain := Map("hello" -> "myprog.Hello"),
// Add custom settings here
// [Optional] JVM options of scripts (program name -> Seq(JVM option, ...))
packJvmOpts := Map("hello" -> Seq("-Xmx512m")),
// [Optional] Extra class paths to look when launching a program
packExtraClasspath := Map("hello" -> Seq("${PROG_HOME}/etc")),
// [Optional] (if you do not need to genrate .bat file for Windows. The default value is true)
packGenerateWindowsBatFile := false
)
// To publish tar.gz archive to the repository, add the following line (since 0.3.6)
// ++ publishPackArchive
// Before 0.3.6, use below:
// ++ addArtifact(Artifact("myprog", "arch", "tar.gz"), packArchive).settings
)
}
```
Expand Down
5 changes: 5 additions & 0 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
### Release Notes
- November 12, 2013 - 0.3.6 release
- Add publichPackArchive
- Add packArchivePrefix settings (packArchivePrefix:default=project name)-(version).tar.gz will be generated.
- October 30, 2013 - 0.3.5 release
- Fix prog.version JVM option generation
- October 24, 2013 - 0.3.4 release
- Fixes #15
- October 15, 2013 - 0.3.3 release
Expand Down
38 changes: 31 additions & 7 deletions src/main/scala/xerial/sbt/Pack.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@ object Pack extends sbt.Plugin {
val packDir = settingKey[String]("pack-dir")
val packUpdateReports = taskKey[Seq[sbt.UpdateReport]]("only for retrieving dependent module names")
val packArchive = TaskKey[File]("pack-archive", "create a tar.gz archive of the distributable package")
val packArchiveArtifact = SettingKey[Artifact]("tar.gz archive artifact")
val packArchivePrefix = SettingKey[String]("prefix of (prefix)-(version).tar.gz archive file name")
val packMain = settingKey[Map[String, String]]("prog_name -> main class table")
val packExclude = SettingKey[Seq[String]]("pack-exclude", "specify projects to exclude when packaging")
val packAllClasspaths = TaskKey[Seq[Classpath]]("pack-all-classpaths")
val packLibJars = TaskKey[Seq[File]]("pack-lib-jars")
val packGenerateWindowsBatFile = settingKey[Boolean]("Generate BAT file launch scripts for Windows")

val packMacIconFile = SettingKey[String]("pack-mac-icon-file", "icon file name for Mac")
val packResourceDir = SettingKey[String]("pack-resource-dir", "pack resource directory. default = src/pack")
Expand All @@ -69,6 +72,7 @@ object Pack extends sbt.Plugin {
packLibJars <<= (thisProjectRef, buildStructure, packExclude) flatMap getFromSelectedProjects(packageBin.task in Runtime),
packUpdateReports <<= (thisProjectRef, buildStructure, packExclude) flatMap getFromSelectedProjects(update.task),
packPreserveOriginalJarName := false,
packGenerateWindowsBatFile := true,
pack := {
val dependentJars = collection.immutable.SortedMap.empty[ModuleEntry, File] ++ (
for {
Expand Down Expand Up @@ -135,18 +139,29 @@ object Pack extends sbt.Plugin {
val pathSeparator = "${PSEP}"
// Render script via Scalate template
val engine = new TemplateEngine


for ((name, mainClass) <- mainTable) {
out.log.info("main class for %s: %s".format(name, mainClass))
def extraClasspath(sep:String) : String = packExtraClasspath.value.get(name).map(_.mkString("", sep, sep)).getOrElse("")
val m = Map(
"PROG_NAME" -> name,
"PROG_VERSION" -> progVersion,
"MAIN_CLASS" -> mainClass,
"MAC_ICON_FILE" -> packMacIconFile.value,
"JVM_OPTS" -> packJvmOpts.value.getOrElse(name, Nil).map("\"%s\"".format(_)).mkString(" "),
"EXTRA_CLASSPATH" -> packExtraClasspath.value.get(name).map(_.mkString("", pathSeparator, pathSeparator)).orElse(Some("")).get)
"EXTRA_CLASSPATH" -> extraClasspath(pathSeparator))
val launchScript = engine.layout("/xerial/sbt/template/launch.mustache", m)
val progName = m("PROG_NAME").replaceAll(" ", "") // remove white spaces
write("bin/%s".format(progName), launchScript)
write(s"bin/$progName", launchScript)

// Create BAT file
if(packGenerateWindowsBatFile.value) {
val extraPath = extraClasspath("%PSEP%").replaceAll("""\$\{PROG_HOME\}""", "%PROG_HOME%").replaceAll("/", """\\""")
val propForWin : Map[String, Any] = m + ("EXTRA_CLASSPATH" -> extraPath)
val batScript = engine.layout("/xerial/sbt/template/launch-bat.mustache", propForWin)
write(s"bin/${progName}.bat", batScript)
}
}

// Copy resources in src/pack folder
Expand Down Expand Up @@ -177,15 +192,17 @@ object Pack extends sbt.Plugin {
out.log.info("done.")
distDir
},
packArchiveArtifact := Artifact(packArchivePrefix.value, "arch", "tar.gz"),
packArchivePrefix := name.value,
packArchive := {
val out = streams.value
val targetDir: File = target.value
val distDir: File = pack.value
val binDir = distDir / "bin"
val archiveRoot = name.value + "-" + version.value
val archiveName = archiveRoot + ".tar.gz"
val archiveStem = s"${packArchivePrefix.value}-${version.value}"
val archiveName = s"${archiveStem}.tar.gz"
out.log.info("Generating " + rpath(baseDirectory.value, targetDir / archiveName))
val tarfile = new TarOutputStream(new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(targetDir / (archiveRoot + ".tar.gz"))) {
val tarfile = new TarOutputStream(new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(targetDir / archiveName)) {
`def`.setLevel(Deflater.BEST_COMPRESSION)
}))
def tarEntry(src: File, dst: String) {
Expand All @@ -197,13 +214,13 @@ object Pack extends sbt.Plugin {
tarEntry.getHeader.mode = Integer.parseInt("0755", 8)
tarfile.putNextEntry(tarEntry)
}
tarEntry(new File("."), archiveRoot)
tarEntry(new File("."), archiveStem)
val excludeFiles = Set("Makefile", "VERSION")
val buffer = Array.fill(1024 * 1024)(0: Byte)
def addFilesToTar(dir: File): Unit = dir.listFiles.
filterNot(f => excludeFiles.contains(rpath(distDir, f))).foreach {
file =>
tarEntry(file, archiveRoot ++ "/" ++ rpath(distDir, file))
tarEntry(file, archiveStem ++ "/" ++ rpath(distDir, file))
if (file.isDirectory) addFilesToTar(file)
else {
def copy(input: InputStream): Unit = input.read(buffer) match {
Expand All @@ -223,6 +240,13 @@ object Pack extends sbt.Plugin {
}
)


def publishPackArchive : SettingsDefinition = {
val pkgd = packagedArtifacts := packagedArtifacts.value updated (packArchiveArtifact.value, packArchive.value)
Seq( artifacts += packArchiveArtifact.value, pkgd )
}


private def getFromAllProjects[T](targetTask: SettingKey[Task[T]])(currentProject: ProjectRef, structure: BuildStructure): Task[Seq[T]] =
getFromSelectedProjects(targetTask)(currentProject, structure, Seq.empty)

Expand Down
118 changes: 118 additions & 0 deletions src/main/templates/launch-bat.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------

@REM ----------------------------------------------------------------------------
@REM sbt-pack launch script
@REM ----------------------------------------------------------------------------

@echo off

@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set HOME=%HOMEDRIVE%%HOMEPATH%)

set ERROR_CODE=0

@REM set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" @setlocal

@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome

for /f %%j in ("java.exe") do (
set JAVA_EXE=%%~$PATH:j
goto init
)

:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" (
SET JAVA_EXE="%JAVA_HOME%\bin\java.exe"
goto init
)

echo.
echo ERROR: JAVA_HOME is set to an invalid directory.
echo JAVA_HOME = %JAVA_HOME%
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation
echo.
goto error

:init
@REM Decide how to startup depending on the version of windows

@REM -- Win98ME
if NOT "%OS%"=="Windows_NT" goto Win9xArg

@REM -- 4NT shell
if "%@eval[2+2]" == "4" goto 4NTArgs

@REM -- Regular WinNT shell
set CMD_LINE_ARGS=%*
goto endInit

@REM The 4NT Shell from jp software
:4NTArgs
set CMD_LINE_ARGS=%$
goto endInit

:Win9xArg
@REM Slurp the command line arguments. This loop allows for an unlimited number
@REM of agruments (up to the command line limit, anyway).
set CMD_LINE_ARGS=
:Win9xApp
if %1a==a goto endInit
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto Win9xApp

@REM Reaching here means variables are defined and arguments have been captured
:endInit

SET PROG_HOME=%~dp0..
SET PSEP=;

@REM Start Java program
:runm2
SET CMDLINE=%JAVA_EXE% %JVM_OPT% {{{JVM_OPTS}}} -cp "{{{EXTRA_CLASSPATH}}}%PROG_HOME%\lib\*;" -Dprog.home="%PROG_HOME%" -Dprog.version="{{{PROG_VERSION}}}" {{{MAIN_CLASS}}} %CMD_LINE_ARGS%
%CMDLINE%
if ERRORLEVEL 1 goto error
goto end

:error
if "%OS%"=="Windows_NT" @endlocal
set ERROR_CODE=1

:end
@REM set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" goto endNT

@REM For old DOS remove the set variables from ENV - we assume they were not set
@REM before we started - at least we don't leave any baggage around
set JAVA_EXE=
set CMD_LINE_ARGS=
set CMDLINE=
set PSEP=
goto postExec

:endNT
@endlocal

:postExec
exit /B %ERROR_CODE%

2 changes: 1 addition & 1 deletion src/main/templates/launch.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ fi


PROG_NAME={{{PROG_NAME}}}
PROG_VERSION={{{PROG_VESRION}}}
PROG_VERSION={{{PROG_VERSION}}}

exec "$JAVACMD" \
${JVM_OPT} \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package sample

object Module1 {

def main(args:Array[String]) { println("hello module1") }

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package sample

object Module2 {
def main(args:Array[String]) { println("hello module2") }
}
53 changes: 53 additions & 0 deletions src/sbt-test/sbt-pack/archive-modules/project/Build.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import sbt._
import sbt.Keys._
import xerial.sbt.Pack._


object Build extends sbt.Build {

val commonSettings = Defaults.defaultSettings ++
// Add pack, pack-archive commands
packSettings ++
// publish tar.gz archive to the repository (since sbt-pack-0.3.6)
publishPackArchive ++
Seq(
scalaVersion := "2.10.3",
version := "0.1",
crossPaths := false
)

object ProgMap {
val m1 = Map("m1" -> "sample.Module1")
val m2 = Map("m2" -> "sample.Module2")
}

lazy val root = Project(
id = "archive-modules",
base = file("."),
settings = commonSettings ++
Seq(
packMain := ProgMap.m1 ++ ProgMap.m2
)
) aggregate(module1, module2)

lazy val module1 = Project(
id = "module1",
base = file("module1"),
settings = commonSettings ++
Seq(
packMain := ProgMap.m1,
libraryDependencies += "org.xerial" % "xerial-core" % "3.2.1"
)
)

lazy val module2 = Project(
id = "module2",
base = file("module2"),
settings = commonSettings ++
Seq(
packMain := ProgMap.m2,
libraryDependencies += "org.xerial.snappy" % "snappy-java" % "1.1.0"
)
)

}
Loading

0 comments on commit 869a4ef

Please sign in to comment.