diff --git a/akka-docs/_sphinx/themes/akka/layout.html b/akka-docs/_sphinx/themes/akka/layout.html
index 0bd735c446..0d46ef708e 100644
--- a/akka-docs/_sphinx/themes/akka/layout.html
+++ b/akka-docs/_sphinx/themes/akka/layout.html
@@ -6,6 +6,7 @@
{% extends "basic/layout.html" %}
{% set script_files = script_files + ['_static/theme_extras.js'] %}
{% set css_files = css_files + ['_static/print.css'] %}
+{% set is_snapshot = version.endswith("-SNAPSHOT") %}
{# do not display relbars #}
{% block relbar1 %}{% endblock %}
@@ -37,7 +38,11 @@
{%- endif -%}
+ {%- if is_snapshot -%}
+ {%- else -%}
+
+ {%- endif -%}
{%- endblock %}
diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala
index bc596dc126..b92bd7a611 100644
--- a/project/AkkaBuild.scala
+++ b/project/AkkaBuild.scala
@@ -24,10 +24,10 @@ object AkkaBuild extends Build {
lazy val akka = Project(
id = "akka",
base = file("."),
- settings = parentSettings ++ Unidoc.settings ++ rstdocSettings ++ Seq(
+ settings = parentSettings ++ Release.settings ++ Unidoc.settings ++ Rstdoc.settings ++ Publish.versionSettings ++ Seq(
parallelExecution in GlobalScope := false,
- Unidoc.unidocExclude := Seq(samples.id, tutorials.id),
- rstdocDirectory <<= baseDirectory / "akka-docs"
+ Publish.defaultPublishTo in ThisBuild <<= crossTarget / "repository",
+ Unidoc.unidocExclude := Seq(samples.id, tutorials.id)
),
aggregate = Seq(actor, testkit, actorTests, stm, remote, slf4j, amqp, mailboxes, akkaSbtPlugin, samples, tutorials, docs)
)
@@ -266,7 +266,7 @@ object AkkaBuild extends Build {
// Settings
- override lazy val settings = super.settings ++ buildSettings ++ Publish.versionSettings
+ override lazy val settings = super.settings ++ buildSettings
lazy val baseSettings = Defaults.defaultSettings ++ Publish.settings
@@ -349,23 +349,6 @@ object AkkaBuild extends Build {
compileInputs in MultiJvm <<= (compileInputs in MultiJvm) dependsOn (ScalariformKeys.format in MultiJvm),
ScalariformKeys.preferences in MultiJvm := formattingPreferences
)
-
- // reStructuredText docs
-
- val rstdocDirectory = SettingKey[File]("rstdoc-directory")
- val rstdoc = TaskKey[File]("rstdoc", "Build the reStructuredText documentation.")
-
- lazy val rstdocSettings = Seq(rstdoc <<= rstdocTask)
-
- def rstdocTask = (rstdocDirectory, streams) map {
- (dir, s) => {
- s.log.info("Building reStructuredText documentation...")
- val exitCode = Process(List("make", "clean", "html", "pdf"), dir) ! s.log
- if (exitCode != 0) sys.error("Failed to build docs.")
- s.log.info("Done building docs.")
- dir
- }
- }
}
// Dependencies
diff --git a/project/Publish.scala b/project/Publish.scala
index 1fb9039faa..9cea85af3c 100644
--- a/project/Publish.scala
+++ b/project/Publish.scala
@@ -1,16 +1,19 @@
package akka
import sbt._
-import Keys._
+import sbt.Keys._
+import sbt.Project.Initialize
import java.io.File
object Publish {
final val Snapshot = "-SNAPSHOT"
+ val defaultPublishTo = SettingKey[File]("default-publish-to")
+
lazy val settings = Seq(
crossPaths := false,
pomExtra := akkaPomExtra,
- publishTo := akkaPublishTo,
+ publishTo <<= akkaPublishTo,
credentials ++= akkaCredentials,
organizationName := "Typesafe Inc.",
organizationHomepage := Some(url("http://www.typesafe.com"))
@@ -32,11 +35,12 @@ object Publish {
}
- def akkaPublishTo: Option[Resolver] = {
- val property = Option(System.getProperty("akka.publish.repository"))
- val repo = property map { "Akka Publish Repository" at _ }
- val m2repo = Path.userHome / ".m2" /"repository"
- repo orElse Some(Resolver.file("Local Maven Repository", m2repo))
+ def akkaPublishTo: Initialize[Option[Resolver]] = {
+ defaultPublishTo { default =>
+ val property = Option(System.getProperty("akka.publish.repository"))
+ val repo = property map { "Akka Publish Repository" at _ }
+ repo orElse Some(Resolver.file("Default Local Repository", default))
+ }
}
def akkaCredentials: Seq[Credentials] = {
@@ -44,17 +48,11 @@ object Publish {
property map (f => Credentials(new File(f))) toSeq
}
- def stampVersion = Command.command("stamp-version") { state =>
- append((version in ThisBuild ~= stamp) :: Nil, state)
- }
+ // timestamped versions
- // TODO: replace with extracted.append when updated to sbt 0.10.1
- def append(settings: Seq[Setting[_]], state: State): State = {
+ def stampVersion = Command.command("stamp-version") { state =>
val extracted = Project.extract(state)
- import extracted._
- val append = Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, settings)
- val newStructure = Load.reapply(session.original ++ append, structure)
- Project.setProject(session, newStructure, state)
+ extracted.append(List(version in ThisBuild ~= stamp), state)
}
def stamp(version: String): String = {
diff --git a/project/Release.scala b/project/Release.scala
new file mode 100644
index 0000000000..6b6f5643bc
--- /dev/null
+++ b/project/Release.scala
@@ -0,0 +1,34 @@
+package akka
+
+import sbt._
+import sbt.Keys._
+import java.io.File
+
+object Release {
+ val releaseDirectory = SettingKey[File]("release-directory")
+
+ lazy val settings: Seq[Setting[_]] = commandSettings ++ Seq(
+ releaseDirectory <<= crossTarget / "release"
+ )
+
+ lazy val commandSettings = Seq(
+ commands += buildReleaseCommand
+ )
+
+ def buildReleaseCommand = Command.command("build-release") { state =>
+ val extracted = Project.extract(state)
+ val release = extracted.get(releaseDirectory)
+ val releaseVersion = extracted.get(version)
+ val projectRef = extracted.get(thisProjectRef)
+ val repo = extracted.get(Publish.defaultPublishTo)
+ val state1 = extracted.runAggregated(publish in projectRef, state)
+ val (state2, api) = extracted.runTask(Unidoc.unidoc, state1)
+ val (state3, docs) = extracted.runTask(Rstdoc.rstdoc, state2)
+ IO.delete(release)
+ IO.createDirectory(release)
+ IO.copyDirectory(repo, release / "releases")
+ IO.copyDirectory(api, release / "api" / "akka" / releaseVersion)
+ IO.copyDirectory(docs, release / "docs" / "akka" / releaseVersion)
+ state3
+ }
+}
diff --git a/project/Rstdoc.scala b/project/Rstdoc.scala
new file mode 100644
index 0000000000..fb38f756ac
--- /dev/null
+++ b/project/Rstdoc.scala
@@ -0,0 +1,34 @@
+package akka
+
+import sbt._
+import sbt.Keys._
+import java.io.File
+
+object Rstdoc {
+ val rstdocDirectory = SettingKey[File]("rstdoc-directory")
+ val rstdocTarget = SettingKey[File]("rstdoc-target")
+ val rstdoc = TaskKey[File]("rstdoc", "Build the reStructuredText documentation.")
+
+ lazy val settings = Seq(
+ rstdocDirectory <<= baseDirectory / "akka-docs",
+ rstdocTarget <<= crossTarget / "rstdoc",
+ rstdoc <<= rstdocTask
+ )
+
+ def rstdocTask = (rstdocDirectory, rstdocTarget, streams) map {
+ (dir, target, s) => {
+ s.log.info("Building reStructuredText documentation...")
+ val logger = new ProcessLogger {
+ def info(o: => String): Unit = s.log.debug(o)
+ def error(e: => String): Unit = s.log.debug(e)
+ def buffer[T](f: => T): T = f
+ }
+ val exitCode = Process(List("make", "clean", "html", "pdf"), dir) ! logger
+ if (exitCode != 0) sys.error("Failed to build docs.")
+ s.log.info("Creating reStructuredText documentation successful.")
+ IO.copyDirectory(dir / "_build" / "html", target)
+ IO.copyFile(dir / "_build" / "latex" / "Akka.pdf", target / "Akka.pdf")
+ target
+ }
+ }
+}
diff --git a/project/Unidoc.scala b/project/Unidoc.scala
index 7fffd98a27..209fda53c7 100644
--- a/project/Unidoc.scala
+++ b/project/Unidoc.scala
@@ -1,8 +1,8 @@
package akka
import sbt._
-import Keys._
-import Project.Initialize
+import sbt.Keys._
+import sbt.Project.Initialize
object Unidoc {
val unidocDirectory = SettingKey[File]("unidoc-directory")
diff --git a/project/scripts/find-replace b/project/scripts/find-replace
new file mode 100755
index 0000000000..d0b6035032
--- /dev/null
+++ b/project/scripts/find-replace
@@ -0,0 +1,85 @@
+#!/usr/bin/env bash
+#
+# Find and replace across all source files.
+# This script will be called as part of the release script.
+
+# get the source location for this script; handles symlinks
+function get_script_path {
+ local source="${BASH_SOURCE[0]}"
+ while [ -h "${source}" ] ; do
+ source="$(readlink "${source}")";
+ done
+ echo ${source}
+}
+
+# path, name, and dir for this script
+declare -r script_path=$(get_script_path)
+declare -r script_name=$(basename "${script_path}")
+declare -r script_dir="$(cd -P "$(dirname "${script_path}")" && pwd)"
+
+# print usage info
+function usage {
+ echo "Usage: ${script_name} find_expr replace_expr"
+}
+
+function echolog {
+ echo "[${script_name}] $@"
+}
+
+declare -r find_expr=$1
+declare -r replace_expr=$2
+
+if [ -z "$find_expr" ]; then
+ usage
+ exit 1
+fi
+
+echolog "$find_expr --> $replace_expr"
+
+# exclude directories from search
+
+declare exclude_dirs=".git dist deploy embedded-repo lib_managed project/boot project/scripts src_managed target"
+
+echolog "excluding directories: $exclude_dirs"
+
+exclude_opts="\("
+op="-path"
+for dir in $exclude_dirs; do
+ exclude_opts="${exclude_opts} ${op} '*/${dir}/*'"
+ op="-or -path"
+done
+exclude_opts="${exclude_opts} \) -prune -o"
+
+# replace in files
+
+search="find . ${exclude_opts} -type f -print0 | xargs -0 grep -Il \"$find_expr\""
+
+files=$(eval "$search")
+
+simple_diff="diff --old-line-format='[$script_name] - %l
+' --new-line-format='[$script_name] + %l
+' --changed-group-format='%<%>' --unchanged-group-format=''"
+
+for file in $files; do
+ echolog $file
+ # escape / for sed
+ sedfind=$(echo $find_expr | sed 's/\//\\\//g')
+ sedreplace=$(echo $replace_expr | sed 's/\//\\\//g')
+ sed -i '.sed' "s/${sedfind}/${sedreplace}/g" $file
+ eval "$simple_diff $file.sed $file"
+ rm -f $file.sed
+done
+
+# replace in file names
+
+search="find . ${exclude_opts} -type f -name \"*${find_expr}*\" -print"
+
+files=$(eval "$search")
+
+for file in $files; do
+ dir=$(dirname $file)
+ name=$(basename $file)
+ newname=$(echo $name | sed "s/${find_expr}/${replace_expr}/g")
+ echolog "$file --> $newname"
+ mv $file $dir/$newname
+done
diff --git a/project/scripts/find-replace.sh b/project/scripts/find-replace.sh
deleted file mode 100644
index fc21a8aa9f..0000000000
--- a/project/scripts/find-replace.sh
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/bin/bash
-
-# Find and replace across all source files.
-#
-# Example usage:
-#
-# sh project/scripts/find-replace.sh 1.1-SNAPSHOT 1.1-RC1
-#
-# This script will be called as part of the sbt release script.
-
-FIND=$1
-REPLACE=$2
-
-if [ -z "$FIND" ]; then
- echo "Usage: find-replace.sh FIND REPLACE"
- exit 1
-fi
-
-echo
-echo "Find and replace: $FIND --> $REPLACE"
-
-
-# Exclude directories from search
-
-excludedirs=".git dist deploy embedded-repo lib_managed project/boot project/scripts src_managed target"
-
-echo "Excluding directories: $excludedirs"
-
-excludeopts="\("
-op="-path"
-for dir in $excludedirs; do
- excludeopts="${excludeopts} ${op} '*/${dir}/*'"
- op="-or -path"
-done
-excludeopts="${excludeopts} \) -prune -o"
-
-
-# Replace in files
-
-search="find . ${excludeopts} -type f -print0 | xargs -0 grep -Il \"${FIND}\""
-
-echo $search
-echo
-
-files=$(eval "$search")
-
-simplediff="diff --old-line-format='- %l
-' --new-line-format='+ %l
-' --changed-group-format='%<%>' --unchanged-group-format=''"
-
-for file in $files; do
- echo
- echo $file
- # escape / for sed
- sedfind=$(echo $FIND | sed 's/\//\\\//g')
- sedreplace=$(echo $REPLACE | sed 's/\//\\\//g')
- sed -i '.sed' "s/${sedfind}/${sedreplace}/g" $file
- eval "$simplediff $file.sed $file"
- rm -f $file.sed
-done
-
-echo
-
-
-# Replace in file names
-
-search="find . ${excludeopts} -type f -name \"*${FIND}*\" -print"
-
-echo $search
-echo
-
-files=$(eval "$search")
-
-for file in $files; do
- dir=$(dirname $file)
- name=$(basename $file)
- newname=$(echo $name | sed "s/${FIND}/${REPLACE}/g")
- echo "$file --> $newname"
- mv $file $dir/$newname
-done
-
-echo
diff --git a/project/scripts/push-release.sh b/project/scripts/push-release.sh
deleted file mode 100644
index c58282144f..0000000000
--- a/project/scripts/push-release.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/bash
-
-VERSION=$1
-
-if [ -z "$VERSION" ]; then
- echo "Usage: push-release.sh VERSION"
- exit 1
-fi
-
-source ~/.akka-release
-
-if [ -z "$AKKA_RELEASE_SERVER" ]; then
- echo "Need AKKA_RELEASE_SERVER to be specified"
- exit 1
-fi
-
-if [ -z "$AKKA_RELEASE_PATH" ]; then
- echo "Need AKKA_RELEASE_PATH to be specified"
- exit 1
-fi
-
-ref=$(git symbolic-ref HEAD 2> /dev/null)
-branch=${ref#refs/heads/}
-
-git push origin $branch
-git push origin --tags
-
-release="target/release/${VERSION}"
-tmp="/tmp/akka-release-${VERSION}"
-
-rsync -avz ${release}/ ${AKKA_RELEASE_SERVER}:${tmp}/
-echo "Verify sudo on $AKKA_RELEASE_SERVER"
-ssh -t ${AKKA_RELEASE_SERVER} sudo -v
-ssh -t ${AKKA_RELEASE_SERVER} sudo rsync -rpt ${tmp}/ ${AKKA_RELEASE_PATH}
-ssh -t ${AKKA_RELEASE_SERVER} rm -rf ${tmp}
diff --git a/project/scripts/release b/project/scripts/release
old mode 100644
new mode 100755
index 847e8c350a..1870102161
--- a/project/scripts/release
+++ b/project/scripts/release
@@ -1,10 +1,234 @@
-sh git checkout -b releasing-{{release.arg1}}
-set akka.release true
-clean
-script find-replace.sh {{project.version}} {{release.arg1}}
-script find-replace.sh //[[:space:]]*release:[[:space:]]*
-reload
-build-release
-sh git add .
-sh git commit -am 'Update version for release {{project.version}}'
-sh git tag -m 'Version {{project.version}}' v{{project.version}}
+#!/usr/bin/env bash
+#
+# Release script for Akka.
+
+# defaults
+declare -r default_server="akka.io"
+declare -r default_path="/akka/www"
+
+# settings
+declare -r release_dir="target/release"
+declare release_server=${default_server}
+declare release_path=${default_path}
+
+# flags
+unset run_tests
+
+# get the source location for this script; handles symlinks
+function get_script_path {
+ local source="${BASH_SOURCE[0]}"
+ while [ -h "${source}" ] ; do
+ source="$(readlink "${source}")";
+ done
+ echo ${source}
+}
+
+# path, name, and dir for this script
+declare -r script_path=$(get_script_path)
+declare -r script_name=$(basename "${script_path}")
+declare -r script_dir="$(cd -P "$(dirname "${script_path}")" && pwd)"
+
+# print usage info
+function usage {
+ cat <&2
+}
+
+# fail the script with an error message
+function fail {
+ echoerr "$@"
+ exit 1
+}
+
+# process options and set flags
+while true; do
+ case "$1" in
+ -h | --help ) usage; exit 1 ;;
+ -t | --run-tests ) run_tests=true; shift ;;
+ -s | --server ) release_server=$2; shift 2 ;;
+ -p | --path ) release_path=$2; shift 2 ;;
+ * ) break ;;
+ esac
+done
+
+if [ $# != "1" ]; then
+ usage
+ fail "A release version must be specified"
+fi
+
+declare -r version=$1
+declare -r publish_path="${release_server}:${release_path}"
+
+# check for a git command
+type -P git &> /dev/null || fail "git command not found"
+
+# check for an sbt command
+type -P sbt &> /dev/null || fail "sbt command not found"
+
+# get the current git branch
+function get_current_branch {
+ local ref=$(git symbolic-ref HEAD 2> /dev/null)
+ local branch=${ref#refs/heads/}
+ echo "${branch}"
+}
+
+# get the current project version from sbt
+# a little messy as the ansi escape codes are included
+function get_current_version {
+ local result=$(sbt version | tail -1 | cut -f2)
+ # remove ansi escape code from end
+ local code0=$(echo -e "\033[0m")
+ echo ${result%$code0}
+}
+
+# store the current git branch for cleaning up
+declare -r initial_branch=$(get_current_branch)
+
+# check we have an initial branch
+[[ "${initial_branch}" ]] || fail "Not on a git branch"
+
+# check that we have a clean status
+[[ -z "$(git status --porcelain)" ]] || {
+ git status
+ fail "There are uncommitted changes - please commit before releasing"
+}
+
+# the branch we'll release on
+declare -r release_branch="releasing-${version}"
+
+# try to run a cleanup command - these shouldn't actually fail
+function safely {
+ "$@" || fail "Failed to clean up release - please check current state"
+}
+
+# perform a clean up when a failure has occurred
+function git_cleanup {
+ echoerr "Cleaning up..."
+ local branch=$(get_current_branch)
+ safely git reset --hard
+ safely git clean -f
+ if [ "${branch}" == "${release_branch}" ]; then
+ safely git checkout ${initial_branch}
+ safely git branch -d ${release_branch}
+ local tags=$(git tag -l)
+ [[ "${tags}" == *v${version}* ]] && safely git tag -d v${version}
+ fi
+ echoerr "Cleaned up failed release"
+}
+
+# clean up and fail the script with an error message
+function bail_out {
+ echoerr "Bailing out!"
+ git_cleanup
+ fail "$@"
+}
+
+# bail out for signals
+function signal_bail_out {
+ echoerr "Interrupted by signal"
+ bail_out "Received signal to stop release"
+}
+
+# bail out on signals
+trap signal_bail_out SIGHUP SIGINT SIGTERM
+
+# try to run a command or otherwise bail out
+function try {
+ "$@" || bail_out "Failed to create release"
+}
+
+echolog "Creating release ${version} ..."
+echolog "Publishing to ${publish_path}"
+[[ $run_tests ]] && echolog "All tests will be run"
+
+# try ssh'ing to the release server
+echolog "Checking ssh connection to ${release_server}"
+try ssh -t ${release_server} echo "Successfully contacted release server."
+
+echolog "Getting current project version from sbt..."
+declare -r current_version=$(get_current_version)
+echolog "Current version is ${current_version}"
+
+# check out a release branch
+try git checkout -b ${release_branch}
+
+# find and replace the version
+try ${script_dir}/find-replace ${current_version} ${version}
+
+# start clean
+try sbt clean
+
+# run the tests if specified
+if [ $run_tests ]; then
+ echolog "Running all tests..."
+ try sbt test
+ echolog "All tests are green"
+fi
+
+# build the release
+echolog "Building the release..."
+try sbt build-release
+echolog "Successfully created local release"
+
+# commit and tag this release
+echolog "Committing and tagging..."
+try git add .
+try git commit -am "Update version for release ${version}"
+try git tag -m "Version ${version}" v${version}
+
+# the point of no return... we're now pushing out to servers
+
+# use a special failure from now on
+function arrgh {
+ cat 1>&2 <