Merge branch 'wip/graft' of sbt/sbt-launcher-package into wip/graft

This commit is contained in:
Eugene Yokota 2021-04-19 10:47:09 -04:00
commit 2523f0f349
39 changed files with 4396 additions and 0 deletions

View File

@ -0,0 +1,28 @@
Steps to publish
================
```
$ sbt -Dsbt.build.version=1.0.3 -Dsbt.build.offline=true
> universal:publish
> debian:publish
> rpm:publish
> universal:bintrayReleaseAllStaged
> debian:releaseAllStaged
> rpm:releaseAllStaged
```
## Notes on batch
### Testing if a variable is blank
```
if not defined _JAVACMD set _JAVACMD=java
```
### Testing if an argument %0 is blank
```
if "%~0" == "" goto echolist_end
```
The above would work in case `%0` contains either double quote (`"`) or whitespace.

202
launcher-package/LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

45
launcher-package/NOTICE Normal file
View File

@ -0,0 +1,45 @@
sbt
https://www.scala-sbt.org/
Copyright 2011 - 2019, Lightbend, Inc.
Copyright 2008 - 2010, Mark Harrah
Licensed under Apache v2 license (see LICENSE)
Portions based on code from the Scala compiler. Portions of the Scala
library are distributed with the launcher.
Copyright 2002-2008 EPFL, Lausanne
JLine is distributed with the launcher.
It is licensed under a BSD-style license
Portions based on code from sbt launcher script
Copyright 2011 - 2012, Paul Phillips, and other contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Apache Ivy, licensed under the Apache License, Version 2.0
This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).
Portions of Ivy were originally developed by
Jayasoft SARL (http://www.jayasoft.fr/)
and are licensed to the Apache Software Foundation under the
"Software Grant License Agreement"
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,60 @@
sbt: the launcher script
========================
This is a launcher script for running [sbt](https://github.com/sbt/sbt).
Current -help output:
```bash
Usage: sbt [options]
-h | -help print this message
-v | -verbose this runner is chattier
-V | -version print the version of mothership sbt
-d | -debug set sbt log level to debug
-no-colors disable ANSI color codes
-sbt-create start sbt even if current directory contains no sbt project
-sbt-dir <path> path to global settings/plugins directory (default: ~/.sbt)
-sbt-boot <path> path to shared boot directory (default: ~/.sbt/boot in 0.11 series)
-ivy <path> path to local Ivy repository (default: ~/.ivy2)
-mem <integer> set memory options (default: 1024, which is -Xms1024m -Xmx1024m -XX:ReservedCodeCacheSize=128m)
-no-share use all local caches; no sharing
-no-global uses global caches, but does not use global ~/.sbt directory.
-jvm-debug <port> Turn on JVM debugging, open at the given port.
-batch Disable interactive mode
# sbt version (default: from project/build.properties if present, else latest release)
-sbt-version <version> use the specified version of sbt
-sbt-jar <path> use the specified jar as the sbt launcher
# java version (default: java from PATH, currently openjdk version "1.8.0_172")
-java-home <path> alternate JAVA_HOME
# jvm options and output control
JAVA_OPTS environment variable, if unset uses ""
.jvmopts if this file exists in the current directory, its contents
are appended to JAVA_OPTS
SBT_OPTS environment variable, if unset uses ""
.sbtopts if this file exists in the current directory, its contents
are prepended to the runner args
/etc/sbt/sbtopts if this file exists, it is prepended to the runner args
-Dkey=val pass -Dkey=val directly to the java runtime
-J-X pass option -X directly to the java runtime
(-J is stripped)
-S-X add -X to sbt's scalacOptions (-S is stripped)
```
### Native packages
This project also includes native packages to run sbt for
* Windows
* RedHat (rpm)
* Debian (deb)
Locations for download to be available soon.
### Build status
[![Build Status](https://travis-ci.org/sbt/sbt-launcher-package.svg?branch=master)](https://travis-ci.org/sbt/sbt-launcher-package)
[![Build Status](https://ci.appveyor.com/api/projects/status/github/sbt/sbt-launcher-package?branch=master&svg=true&retina=true)](https://ci.appveyor.com/project/sbt/sbt-launcher-package)

BIN
launcher-package/bin/coursier Executable file

Binary file not shown.

View File

@ -0,0 +1,95 @@
@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 JAR_PATH=%~dp0\%~n0
SET PROG_DIR=%~dp0
SET PSEP=;
@REM Start Java program
:runm2
SET CMDLINE=%JAVA_EXE% -noverify %JAVA_OPTS% -Dprog.dir="%PROG_DIR:\=\\%" -jar "%JAR_PATH%" %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%

470
launcher-package/build.sbt Executable file
View File

@ -0,0 +1,470 @@
import scala.util.control.Exception.catching
import _root_.bintray.InternalBintrayKeys._
import _root_.bintray.{BintrayRepo, Bintray}
import NativePackagerHelper._
import com.typesafe.sbt.packager.SettingsHelper._
import DebianConstants._
lazy val sbtOfflineInstall =
sys.props.getOrElse("sbt.build.offline", sys.env.getOrElse("sbt.build.offline", "true")) match {
case "true" | "1" => true
case "false" | "0" => false
case _ => false
}
lazy val sbtIncludeSbtn =
sys.props.getOrElse("sbt.build.includesbtn", sys.env.getOrElse("sbt.build.includesbtn", "true")) match {
case "true" | "1" => true
case "false" | "0" => false
case _ => false
}
lazy val sbtVersionToRelease = sys.props.getOrElse("sbt.build.version", sys.env.getOrElse("sbt.build.version", {
sys.error("-Dsbt.build.version must be set")
}))
lazy val scala210 = "2.10.7"
lazy val scala212 = "2.12.10"
lazy val scala210Jline = "org.scala-lang" % "jline" % scala210
lazy val jansi = {
if (sbtVersionToRelease startsWith "1.") "org.fusesource.jansi" % "jansi" % "1.12"
else "org.fusesource.jansi" % "jansi" % "1.4"
}
lazy val scala212Compiler = "org.scala-lang" % "scala-compiler" % scala212
lazy val scala212Jline = "jline" % "jline" % "2.14.6"
// use the scala-xml version used by the compiler not the latest: https://github.com/scala/scala/blob/v2.12.10/versions.properties#L22
lazy val scala212Xml = "org.scala-lang.modules" % "scala-xml_2.12" % "1.0.6"
lazy val sbtActual = "org.scala-sbt" % "sbt" % sbtVersionToRelease
lazy val sbt013ExtraDeps = {
if (sbtVersionToRelease startsWith "0.13.") Seq(scala210Jline)
else Seq()
}
lazy val isWindows: Boolean = sys.props("os.name").toLowerCase(java.util.Locale.ENGLISH).contains("windows")
lazy val isExperimental = (sbtVersionToRelease contains "RC") || (sbtVersionToRelease contains "M")
val sbtLaunchJarUrl = SettingKey[String]("sbt-launch-jar-url")
val sbtLaunchJarLocation = SettingKey[File]("sbt-launch-jar-location")
val sbtLaunchJar = TaskKey[File]("sbt-launch-jar", "Resolves SBT launch jar")
val moduleID = (organization) apply { (o) => ModuleID(o, "sbt", sbtVersionToRelease) }
val sbtnVersion = SettingKey[String]("sbtn-version")
val sbtnJarsMappings = TaskKey[Seq[(File, String)]]("sbtn-jars-mappings", "Resolves sbtn JARs")
val sbtnJarsBaseUrl = SettingKey[String]("sbtn-jars-base-url")
lazy val bintrayDebianUrl = settingKey[String]("API point for Debian packages")
lazy val bintrayDebianExperimentalUrl = settingKey[String]("API point for Debian experimental packages")
lazy val bintrayRpmUrl = settingKey[String]("API point for RPM packages")
lazy val bintrayRpmExperimentalUrl = settingKey[String]("API point for RPM experimental packages")
lazy val bintrayGenericPackagesUrl = settingKey[String]("API point for generic packages")
lazy val bintrayTripple = settingKey[(String, String, String)]("id, url, and pattern")
val bintrayLinuxPattern = "[module]/[revision]/[module]-[revision].[ext]"
val bintrayGenericPattern = "[module]/[revision]/[module]/[revision]/[module]-[revision].[ext]"
val bintrayReleaseAllStaged = TaskKey[Unit]("bintray-release-all-staged", "Release all staged artifacts on bintray.")
val windowsBuildId = settingKey[Int]("build id for Windows installer")
val debianBuildId = settingKey[Int]("build id for Debian")
val exportRepoUsingCoursier = taskKey[File]("export Maven style repository")
val exportRepoCsrDirectory = settingKey[File]("")
val x86MacPlatform = "x86_64-apple-darwin"
val x86LinuxPlatform = "x86_64-pc-linux"
val x86WindowsPlatform = "x86_64-pc-win32"
val x86MacImageName = s"sbtn-$x86MacPlatform"
val x86LinuxImageName = s"sbtn-$x86LinuxPlatform"
val x86WindowsImageName = s"sbtn-$x86WindowsPlatform.exe"
// This build creates a SBT plugin with handy features *and* bundles the SBT script for distribution.
val root = (project in file(".")).
enablePlugins(UniversalPlugin, LinuxPlugin, DebianPlugin, RpmPlugin, WindowsPlugin,
UniversalDeployPlugin, DebianDeployPlugin, RpmDeployPlugin, WindowsDeployPlugin).
settings(
organization := "org.scala-sbt",
name := "sbt-launcher-packaging",
packageName := "sbt",
version := "0.1.0",
crossTarget := target.value,
clean := {
val _ = (clean in dist).value
clean.value
},
credentials ++= {
(sys.env.get("BINTRAY_USER"), sys.env.get("BINTRAY_PASS")) match {
case (Some(u), Some(p)) => Seq(Credentials("Bintray API Realm", "api.bintray.com", u, p))
case _ => Nil
}
},
useGpg := true,
usePgpKeyHex("642AC823"),
pgpSecretRing := file(s"""${sys.props("user.home")}""") / ".ssh" / "scalasbt.key",
pgpPublicRing := file(s"""${sys.props("user.home")}""") / ".ssh" / "scalasbt.pub",
publishToSettings,
sbtLaunchJarUrl := downloadUrlForVersion(sbtVersionToRelease),
sbtLaunchJarLocation := { target.value / "sbt-launch.jar" },
sbtLaunchJar := {
val uri = sbtLaunchJarUrl.value
val file = sbtLaunchJarLocation.value
import dispatch.classic._
if(!file.exists) {
// oddly, some places require us to create the file before writing...
IO.touch(file)
val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(file))
try Http(url(uri) >>> writer)
finally writer.close()
}
// TODO - GPG Trust validation.
file
},
sbtnVersion := "1.4.7",
sbtnJarsBaseUrl := "https://github.com/sbt/sbtn-dist/releases/download",
sbtnJarsMappings := {
val baseUrl = sbtnJarsBaseUrl.value
val v = sbtnVersion.value
val macosImageTar = s"sbtn-$x86MacPlatform-$v.tar.gz"
val linuxImageTar = s"sbtn-$x86LinuxPlatform-$v.tar.gz"
val windowsImageZip = s"sbtn-$x86WindowsPlatform-$v.zip"
val t = target.value
val macosTar = t / macosImageTar
val linuxTar = t / linuxImageTar
val windowsZip = t / windowsImageZip
import dispatch.classic._
if(!macosTar.exists && !isWindows && sbtIncludeSbtn) {
IO.touch(macosTar)
val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(macosTar))
try Http(url(s"$baseUrl/v$v/$macosImageTar") >>> writer)
finally writer.close()
val platformDir = t / x86MacPlatform
IO.createDirectory(platformDir)
s"tar zxvf $macosTar --directory $platformDir".!
IO.move(platformDir / "sbtn", t / x86MacImageName)
}
if(!linuxTar.exists && !isWindows && sbtIncludeSbtn) {
IO.touch(linuxTar)
val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(linuxTar))
try Http(url(s"$baseUrl/v$v/$linuxImageTar") >>> writer)
finally writer.close()
val platformDir = t / x86LinuxPlatform
IO.createDirectory(platformDir)
s"""tar zxvf $linuxTar --directory $platformDir""".!
IO.move(platformDir / "sbtn", t / x86LinuxImageName)
}
if(!windowsZip.exists && sbtIncludeSbtn) {
IO.touch(windowsZip)
val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(windowsZip))
try Http(url(s"$baseUrl/v$v/$windowsImageZip") >>> writer)
finally writer.close()
val platformDir = t / x86WindowsPlatform
IO.unzip(windowsZip, platformDir)
IO.move(platformDir / "sbtn.exe", t / x86WindowsImageName)
}
if (!sbtIncludeSbtn) Seq()
else if (isWindows) Seq(t / x86WindowsImageName -> s"bin/$x86WindowsImageName")
else
Seq(t / x86MacImageName -> s"bin/$x86MacImageName",
t / x86LinuxImageName -> s"bin/$x86LinuxImageName",
t / x86WindowsImageName -> s"bin/$x86WindowsImageName")
},
// GENERAL LINUX PACKAGING STUFFS
maintainer := "Eugene Yokota <eugene.yokota@lightbend.com>",
packageSummary := "sbt, the interactive build tool",
packageDescription := """This script provides a native way to run sbt,
a build tool for Scala and more.""",
// Here we remove the jar file and launch lib from the symlinks:
linuxPackageSymlinks := {
val links = linuxPackageSymlinks.value
for {
link <- links
if !(link.destination endsWith "sbt-launch.jar")
} yield link
},
// DEBIAN SPECIFIC
debianBuildId := sys.props.getOrElse("sbt.build.patch", sys.env.getOrElse("DIST_PATCHVER", "0")).toInt,
version in Debian := {
if (debianBuildId.value == 0) sbtVersionToRelease
else sbtVersionToRelease + "." + debianBuildId.value
},
// Used to have "openjdk-8-jdk" but that doesn't work on Ubuntu 14.04 https://github.com/sbt/sbt/issues/3105
// before that we had java6-runtime-headless" and that was pulling in JDK9 on Ubuntu 16.04 https://github.com/sbt/sbt/issues/2931
debianPackageDependencies in Debian ++= Seq("bash (>= 3.2)"),
debianPackageRecommends in Debian += "git",
linuxPackageMappings in Debian += {
val bd = sourceDirectory.value
(packageMapping(
(bd / "debian" / "changelog") -> "/usr/share/doc/sbt/changelog.gz"
) withUser "root" withGroup "root" withPerms "0644" gzipped) asDocs()
},
debianChangelog in Debian := { Some(sourceDirectory.value / "debian" / "changelog") },
addPackage(Debian, packageBin in Debian, "deb"),
debianNativeBuildOptions in Debian := Seq("-Zgzip", "-z3"),
// RPM SPECIFIC
rpmRelease := debianBuildId.value.toString,
version in Rpm := {
val stable0 = (sbtVersionToRelease split "[^\\d]" filterNot (_.isEmpty) mkString ".")
val stable = if (rpmRelease.value == "0") stable0
else stable0 + "." + rpmRelease.value
if (isExperimental) ((sbtVersionToRelease split "[^\\d]" filterNot (_.isEmpty)).toList match {
case List(a, b, c, d) => List(0, 99, c, d).mkString(".")
})
else stable
},
// remove sbtn from RPM because it complains about it being noarch
linuxPackageMappings in Rpm := {
val orig = (linuxPackageMappings in Rpm).value
val nativeMappings = sbtnJarsMappings.value
orig.map(o => o.copy(mappings = o.mappings.toList filterNot {
case (x, p) => p.contains("sbtn-x86_64")
}))
},
rpmVendor := "lightbend",
rpmUrl := Some("http://github.com/sbt/sbt-launcher-package"),
rpmLicense := Some("BSD"),
// This is intentionally empty. java-devel could bring in JDK 9-ea on Fedora,
// and java-1.8.0-devel doesn't work on CentOS 6 and 7.
// https://github.com/sbt/sbt-launcher-package/issues/151
// https://github.com/elastic/logstash/issues/6275#issuecomment-261359933
rpmRequirements := Seq(),
rpmProvides := Seq("sbt"),
// WINDOWS SPECIFIC
windowsBuildId := 0,
version in Windows := {
val bid = windowsBuildId.value
val sv = sbtVersionToRelease
(sv split "[^\\d]" filterNot (_.isEmpty)) match {
case Array(major,minor,bugfix, _*) if bid == 0 => Seq(major, minor, bugfix) mkString "."
case Array(major,minor,bugfix, _*) => Seq(major, minor, bugfix, bid.toString) mkString "."
case Array(major,minor) => Seq(major, minor, "0", bid.toString) mkString "."
case Array(major) => Seq(major, "0", "0", bid.toString) mkString "."
}
},
maintainer in Windows := "Lightbend, Inc.",
packageSummary in Windows := "sbt " + (version in Windows).value,
packageDescription in Windows := "The interactive build tool.",
wixProductId := "ce07be71-510d-414a-92d4-dff47631848a",
wixProductUpgradeId := Hash.toHex(Hash((version in Windows).value)).take(32),
javacOptions := Seq("-source", "1.8", "-target", "1.8"),
// Universal ZIP download install.
packageName in Universal := packageName.value, // needs to be set explicitly due to a bug in native-packager
version in Universal := sbtVersionToRelease,
mappings in Universal := {
val t = (target in Universal).value
val prev = (mappings in Universal).value
val BinSbt = "bin" + java.io.File.separator + "sbt"
val BinBat = BinSbt + ".bat"
prev.toList map {
case (k, BinSbt) =>
import java.nio.file.{Files, FileSystems}
val x = IO.read(k)
IO.write(t / "sbt", x.replaceAllLiterally(
"declare init_sbt_version=_to_be_replaced",
s"declare init_sbt_version=$sbtVersionToRelease"))
if (FileSystems.getDefault.supportedFileAttributeViews.contains("posix")) {
val perms = Files.getPosixFilePermissions(k.toPath)
Files.setPosixFilePermissions(t / "sbt" toPath, perms)
}
(t / "sbt", BinSbt)
case (k, BinBat) =>
val x = IO.read(k)
IO.write(t / "sbt.bat", x.replaceAllLiterally(
"set init_sbt_version=_to_be_replaced",
s"set init_sbt_version=$sbtVersionToRelease"))
(t / "sbt.bat", BinBat)
case (k, v) => (k, v)
}
},
mappings in Universal ++= {
val launchJar = sbtLaunchJar.value
Seq(
launchJar -> "bin/sbt-launch.jar"
) ++ sbtnJarsMappings.value
},
mappings in Universal ++= (Def.taskDyn {
if (sbtOfflineInstall && sbtVersionToRelease.startsWith("1."))
Def.task {
val _ = (exportRepoUsingCoursier in dist).value
directory((target in dist).value / "lib")
}
else if (sbtOfflineInstall)
Def.task {
val _ = (exportRepo in dist).value
directory((target in dist).value / "lib")
}
else Def.task { Seq[(File, String)]() }
}).value,
mappings in Universal ++= {
val base = baseDirectory.value
if (sbtVersionToRelease startsWith "0.13.") Nil
else Seq[(File, String)](base / "LICENSE" -> "LICENSE", base / "NOTICE" -> "NOTICE")
},
// Misccelaneous publishing stuff...
projectID in Debian := {
val m = moduleID.value
m.copy(revision = (version in Debian).value)
},
projectID in Windows := {
val m = moduleID.value
m.copy(revision = (version in Windows).value)
},
projectID in Rpm := {
val m = moduleID.value
m.copy(revision = (version in Rpm).value)
},
projectID in Universal := {
val m = moduleID.value
m.copy(revision = (version in Universal).value)
}
)
lazy val integrationTest = (project in file("integration-test"))
.settings(
name := "integration-test",
scalaVersion := scala212,
libraryDependencies ++= Seq(
"io.monix" %% "minitest" % "2.3.2" % Test,
"com.eed3si9n.expecty" %% "expecty" % "0.11.0" % Test,
"org.scala-sbt" %% "io" % "1.3.1" % Test
),
testFrameworks += new TestFramework("minitest.runner.Framework")
)
def downloadUrlForVersion(v: String) = (v split "[^\\d]" flatMap (i => catching(classOf[Exception]) opt (i.toInt))) match {
case Array(0, 11, 3, _*) => "https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/sbt-launch/0.11.3-2/sbt-launch.jar"
case Array(0, 11, x, _*) if x >= 3 => "https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/sbt-launch/"+v+"/sbt-launch.jar"
case Array(0, y, _*) if y >= 12 => "https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/sbt-launch/"+v+"/sbt-launch.jar"
case Array(1, _, _*) if v contains ("-20") => "https://repo.scala-sbt.org/scalasbt/maven-snapshots/org/scala-sbt/sbt-launch/"+v+"/sbt-launch.jar"
case _ => "https://repo1.maven.org/maven2/org/scala-sbt/sbt-launch/"+v+"/sbt-launch-"+v+".jar"
}
def makePublishToForConfig(config: Configuration) = {
val v = sbtVersionToRelease
// Add the publish to and ensure global resolvers has the resolver we just configured.
inConfig(config)(Seq(
name := "sbt",
bintrayOrganization := {
// offline installation exceeds 50MB file limit for OSS organization
if (sbtOfflineInstall) Some("sbt")
else Some("sbt")
},
bintrayRepository := bintrayTripple.value._1,
bintrayRepo := Bintray.cachedRepo(bintrayEnsureCredentials.value,
bintrayOrganization.value,
bintrayRepository.value),
bintrayPackage := "sbt",
bintrayDebianUrl := s"https://api.bintray.com/content/${bintrayOrganization.value.get}/debian/",
bintrayDebianExperimentalUrl := s"https://api.bintray.com/content/${bintrayOrganization.value.get}/debian-experimental/",
bintrayRpmUrl := s"https://api.bintray.com/content/${bintrayOrganization.value.get}/rpm/",
bintrayRpmExperimentalUrl := s"https://api.bintray.com/content/${bintrayOrganization.value.get}/rpm-experimental/",
bintrayGenericPackagesUrl := s"https://api.bintray.com/content/${bintrayOrganization.value.get}/native-packages/",
bintrayTripple := {
config.name match {
case Debian.name if isExperimental => ("debian-experimental", bintrayDebianExperimentalUrl.value, bintrayLinuxPattern)
case Debian.name => ("debian", bintrayDebianUrl.value, bintrayLinuxPattern)
case Rpm.name if isExperimental => ("rpm-experimental", bintrayRpmExperimentalUrl.value, bintrayLinuxPattern)
case Rpm.name => ("rpm", bintrayRpmUrl.value, bintrayLinuxPattern)
case _ => ("native-packages", bintrayGenericPackagesUrl.value, bintrayGenericPattern)
}
},
publishTo := {
val (id, url, pattern) = bintrayTripple.value
val resolver = Resolver.url(id, new URL(url))(Patterns(pattern))
Some(resolver)
},
bintrayReleaseAllStaged := bintrayRelease(bintrayRepo.value, bintrayPackage.value, version.value, sLog.value)
// Uncomment to release right after publishing
// publish <<= (publish, bintrayRepo, bintrayPackage, version, sLog) apply { (publish, bintrayRepo, bintrayPackage, version, sLog) =>
// for {
// pub <- publish
// repo <- bintrayRepo
// } yield bintrayRelease(repo, bintrayPackage, version, sLog)
// }
)) ++ Seq(
resolvers ++= ((publishTo in config) apply (_.toSeq)).value
)
}
def publishToSettings =
Seq[Configuration](Debian, Universal, Windows, Rpm) flatMap makePublishToForConfig
def bintrayRelease(repo: BintrayRepo, pkg: String, version: String, log: Logger): Unit =
repo.release(pkg, version, log)
def downloadUrl(uri: URI, out: File): Unit =
{
import dispatch.classic._
if(!out.exists) {
IO.touch(out)
val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(out))
try Http(url(uri.toString) >>> writer)
finally writer.close()
}
}
def colonName(m: ModuleID): String = s"${m.organization}:${m.name}:${m.revision}"
lazy val dist = (project in file("dist"))
.enablePlugins(ExportRepoPlugin)
.settings(
name := "dist",
scalaVersion := {
if (sbtVersionToRelease startsWith "0.13.") scala210
else scala212
},
libraryDependencies ++= Seq(sbtActual, jansi, scala212Compiler, scala212Jline, scala212Xml) ++ sbt013ExtraDeps,
exportRepo := {
val old = exportRepo.value
sbtVersionToRelease match {
case v if v.startsWith("1.") =>
sys.error("sbt 1.x should use coursier")
case v if v.startsWith("0.13.") =>
val outbase = exportRepoDirectory.value / "org.scala-sbt" / "compiler-interface" / v
val uribase = s"https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/compiler-interface/$v/"
downloadUrl(uri(uribase + "ivys/ivy.xml"), outbase / "ivys" / "ivy.xml")
downloadUrl(uri(uribase + "jars/compiler-interface.jar"), outbase / "jars" / "compiler-interface.jar")
downloadUrl(uri(uribase + "srcs/compiler-interface-sources.jar"), outbase / "srcs" / "compiler-interface-sources.jar")
case _ =>
}
old
},
exportRepoDirectory := target.value / "lib" / "local-preloaded",
exportRepoCsrDirectory := exportRepoDirectory.value,
exportRepoUsingCoursier := {
val outDirectory = exportRepoCsrDirectory.value
val csr =
if (isWindows) (baseDirectory in LocalRootProject).value / "bin" / "coursier.bat"
else (baseDirectory in LocalRootProject).value / "bin" / "coursier"
val cache = target.value / "coursier"
IO.delete(cache)
val v = sbtVersionToRelease
s"$csr fetch --cache $cache org.scala-sbt:sbt:$v".!
s"$csr fetch --cache $cache ${colonName(jansi)}".!
s"$csr fetch --cache $cache ${colonName(scala212Compiler)}".!
s"$csr fetch --cache $cache ${colonName(scala212Xml)}".!
val mavenCache = cache / "https" / "repo1.maven.org" / "maven2"
val compilerBridgeVer = IO.listFiles(mavenCache / "org" / "scala-sbt" / "compiler-bridge_2.12", DirectoryFilter).toList.headOption
compilerBridgeVer match {
case Some(bridgeDir) =>
val bridgeVer = bridgeDir.getName
s"$csr fetch --cache $cache --sources org.scala-sbt:compiler-bridge_2.10:$bridgeVer".!
s"$csr fetch --cache $cache --sources org.scala-sbt:compiler-bridge_2.11:$bridgeVer".!
s"$csr fetch --cache $cache --sources org.scala-sbt:compiler-bridge_2.12:$bridgeVer".!
s"$csr fetch --cache $cache --sources org.scala-sbt:compiler-bridge_2.13:$bridgeVer".!
case _ =>
sys.error("bridge not found")
}
IO.copyDirectory(mavenCache, outDirectory, true, true)
outDirectory
},
conflictWarning := ConflictWarning.disable,
publish := (),
publishLocal := (),
resolvers += Resolver.typesafeIvyRepo("releases")
)

View File

@ -0,0 +1,5 @@
package foo
object Hello extends App {
println("hello")
}

View File

@ -0,0 +1,22 @@
lazy val check = taskKey[Unit]("")
lazy val check2 = taskKey[Unit]("")
lazy val root = (project in file("."))
.settings(
scalaVersion := "2.12.4",
name := "Hello",
libraryDependencies += "com.eed3si9n.verify" %% "verify" % "0.2.0" % Test,
testFrameworks += new TestFramework("verify.runner.Framework"),
check := {
val xs = IO.readLines(file("output.txt")).toVector
println(xs)
assert(xs(0) contains "welcome to sbt")
assert(xs(1) contains "loading project definition")
assert(xs(2) contains "loading settings")
val ys = IO.readLines(file("err.txt")).toVector.distinct
assert(ys.isEmpty, s"there's an stderr: $ys")
}
)

View File

@ -0,0 +1 @@
sbt.version=1.3.13

View File

@ -0,0 +1,7 @@
import verify._
object HelloTest extends BasicTestSuite {
test("addition") {
assert(2 == 1 + 1)
}
}

View File

@ -0,0 +1,31 @@
@echo on
cd "%~dp0"
mkdir freshly-baked
unzip ..\target\universal\sbt.zip -d freshly-baked
SETLOCAL
"freshly-baked\sbt\bin\sbt" about
SET JAVA_HOME=C:\jdk11
SET PATH=C:\jdk11\bin;%PATH%
SET SBT_OPTS=-Xmx4g -Dfile.encoding=UTF8
"freshly-baked\sbt\bin\sbt" -Dsbt.no.format=true about
"freshly-baked\sbt\bin\sbt" -Dsbt.no.format=true about 1> output.txt 2> err.txt
"freshly-baked\sbt\bin\sbt" -Dsbt.no.format=true check
"freshly-baked\sbt\bin\sbt" -Dsbt.no.format=true --numeric-version > numericVersion.txt
"freshly-baked\sbt\bin\sbt" -Dsbt.no.format=true checkNumericVersion
"freshly-baked\sbt\bin\sbt" -Dsbt.no.format=true --script-version > scriptVersion.txt
"freshly-baked\sbt\bin\sbt" -Dsbt.no.format=true checkScriptVersion
"freshly-baked\sbt\bin\sbt" -Dsbt.no.format=true --version > version.txt
"freshly-baked\sbt\bin\sbt" -Dsbt.no.format=true checkVersion
ENDLOCAL

39
launcher-package/citest/test.sh Executable file
View File

@ -0,0 +1,39 @@
#!/bin/bash
# exit when something fails
set -e
## https://github.com/travis-ci/travis-ci/issues/8408
unset _JAVA_OPTIONS
unset SBT_OPTS
java -version
## end of Java switching
mkdir -p freshly-baked
unzip -qo ../target/universal/sbt.zip -d ./freshly-baked
./freshly-baked/sbt/bin/sbt -Dsbt.no.format=true about
./freshly-baked/sbt/bin/sbt -Dsbt.no.format=true about 1> output.txt 2> err.txt
./freshly-baked/sbt/bin/sbt check
./freshly-baked/sbt/bin/sbt about run -v
./freshly-baked/sbt/bin/sbt about run
fail() {
echo "$@" >&2
exit 1
}
env HOME=./target/home1 ./freshly-baked/sbt/bin/sbt about
test -d ./target/home1/.sbt/preloaded/org/scala-sbt || fail "expected to find preloaded in ./target/home1/.sbt"
env HOME=./target/home2 ./freshly-baked/sbt/bin/sbt -sbt-dir ./target/home2/alternate-sbt about
test -d ./target/home2/alternate-sbt/preloaded/org/scala-sbt || fail "expected to find preloaded in ./target/home2/alternate-sbt"
env HOME=./target/home3 ./freshly-baked/sbt/bin/sbt -J-Dsbt.preloaded=./target/home3/alternate-preloaded about
test -d ./target/home3/alternate-preloaded/org/scala-sbt || fail "expected to find preloaded in ./target/home3/alternate-preloaded"
env HOME=./target/home4 ./freshly-baked/sbt/bin/sbt -J-Dsbt.global.base=./target/home4/global-base about
test -d ./target/home4/global-base/preloaded/org/scala-sbt || fail "expected to find preloaded in ./target/home4/global-base"

View File

@ -0,0 +1,3 @@
-XX:+CMSClassUnloadingEnabled
#-XX:ReservedCodeCacheSize=192m
#-Duser.timezone=GMT

View File

@ -0,0 +1,52 @@
lazy val check = taskKey[Unit]("")
lazy val checkNumericVersion = taskKey[Unit]("")
lazy val checkScriptVersion = taskKey[Unit]("")
lazy val checkVersion = taskKey[Unit]("")
// 1.3.0, 1.3.0-M4
lazy val versionRegEx = "\\d(\\.\\d+){2}(-\\w+)?"
lazy val root = (project in file("."))
.settings(
scalaVersion := "2.12.4",
name := "Hello",
check := {
val xs = IO.readLines(file("output.txt")).toVector
println(xs)
assert(xs(0) startsWith "[info] Loading project definition")
assert(xs(1) startsWith "[info] Loading settings from build.sbt")
assert(xs(2) startsWith "[info] Set current project to Hello")
assert(xs(3) startsWith "[info] This is sbt")
assert(xs(4) startsWith "[info] The current project")
assert(xs(5) startsWith "[info] The current project is built against Scala 2.12.4")
val ys = IO.readLines(file("err.txt")).toVector.distinct
assert(ys.size == 1, s"ys has more than one item: $ys")
assert(ys(0) startsWith "Java HotSpot(TM) 64-Bit Server VM warning")
},
checkNumericVersion = {
val xs = IO.readLines(file("numericVersion.txt")).toVector
val expectedVersion = "^"+versionRegEx+"$"
assert(xs(0).matches(expectedVersion))
},
checkScriptVersion = {
val xs = IO.readLines(file("scriptVersion.txt")).toVector
val expectedVersion = "^"+versionRegEx+"$"
assert(xs(0).matches(expectedVersion))
},
checkVersion = {
val out = IO.readLines(file("version.txt")).toVector.mkString("\n")
val expectedVersion =
s"""|(?m)^sbt version in this project: $versionRegEx
|sbt script version: $versionRegEx$$
|""".stripMargin.trim.replace("\n", "\\n")
assert(out.matches(expectedVersion))
}
)

View File

@ -0,0 +1,17 @@
@echo on
SETLOCAL
SET JAVA_HOME=C:\jdk11
SET PATH=C:\jdk11\bin;%PATH%
SET SBT_OPTS=-Xmx4g -Dfile.encoding=UTF8
SET BASE_DIR=%CD%
SET SCRIPT_DIR=%~dp0
CD %SCRIPT_DIR%
"%BASE_DIR%freshly-baked\sbt\bin\sbt" about 1> output.txt 2> err.txt
"%BASE_DIR%freshly-baked\sbt\bin\sbt" check
CD %BASE_DIR%
ENDLOCAL

View File

@ -0,0 +1,9 @@
#!/usr/bin/env python3
import sys
if '--version' in sys.argv or '-version' in sys.argv:
print('openjdk version "1.8.0_212"')
else:
for arg in sys.argv[1:]:
print(repr(arg)[1:-1])

View File

@ -0,0 +1 @@
@python "%~dp0%~n0" %*

View File

@ -0,0 +1,17 @@
package sbt.internal
import java.lang.{ ProcessBuilder => JProcessBuilder }
private[sbt] object InheritInput {
def apply(p: JProcessBuilder): Boolean = (redirectInput, inherit) match {
case (Some(m), Some(f)) =>
m.invoke(p, f); true
case _ => false
}
private[this] val pbClass = Class.forName("java.lang.ProcessBuilder")
private[this] val redirectClass = pbClass.getClasses find (_.getSimpleName == "Redirect")
private[this] val redirectInput = redirectClass map (pbClass.getMethod("redirectInput", _))
private[this] val inherit = redirectClass map (_ getField "INHERIT" get null)
}

View File

@ -0,0 +1,7 @@
package example.test
import com.eed3si9n.expecty.Expecty
trait PowerAssertions {
lazy val assert: Expecty = new Expecty()
}

View File

@ -0,0 +1,216 @@
package sbt.internal
import java.lang.{ Process => JProcess, ProcessBuilder => JProcessBuilder }
import java.io.{ Closeable, File, IOException }
import java.io.{ BufferedReader, InputStream, InputStreamReader, OutputStream, PipedInputStream, PipedOutputStream }
import java.net.URL
trait ProcessExtra {
import Process._
implicit def builderToProcess(builder: JProcessBuilder): ProcessBuilder = apply(builder)
implicit def fileToProcess(file: File): FilePartialBuilder = apply(file)
implicit def urlToProcess(url: URL): URLPartialBuilder = apply(url)
implicit def buildersToProcess[T](builders: Seq[T])(implicit convert: T => SourcePartialBuilder): Seq[SourcePartialBuilder] = applySeq(builders)
implicit def stringToProcess(command: String): ProcessBuilder = apply(command)
implicit def stringSeqToProcess(command: Seq[String]): ProcessBuilder = apply(command)
}
/** Methods for constructing simple commands that can then be combined. */
object Process extends ProcessExtra {
def apply(command: String): ProcessBuilder = apply(command, None)
def apply(command: Seq[String]): ProcessBuilder = apply(command.toArray, None)
def apply(command: String, arguments: Seq[String]): ProcessBuilder = apply(command :: arguments.toList, None)
/** create ProcessBuilder with working dir set to File and extra environment variables */
def apply(command: String, cwd: File, extraEnv: (String, String)*): ProcessBuilder =
apply(command, Some(cwd), extraEnv: _*)
/** create ProcessBuilder with working dir set to File and extra environment variables */
def apply(command: Seq[String], cwd: File, extraEnv: (String, String)*): ProcessBuilder =
apply(command, Some(cwd), extraEnv: _*)
/** create ProcessBuilder with working dir optionally set to File and extra environment variables */
def apply(command: String, cwd: Option[File], extraEnv: (String, String)*): ProcessBuilder = {
apply(command.split("""\s+"""), cwd, extraEnv: _*)
// not smart to use this on windows, because CommandParser uses \ to escape ".
/*CommandParser.parse(command) match {
case Left(errorMsg) => error(errorMsg)
case Right((cmd, args)) => apply(cmd :: args, cwd, extraEnv : _*)
}*/
}
/** create ProcessBuilder with working dir optionally set to File and extra environment variables */
def apply(command: Seq[String], cwd: Option[File], extraEnv: (String, String)*): ProcessBuilder = {
val jpb = new JProcessBuilder(command.toArray: _*)
cwd.foreach(jpb directory _)
extraEnv.foreach { case (k, v) => jpb.environment.put(k, v) }
apply(jpb)
}
def apply(builder: JProcessBuilder): ProcessBuilder = new SimpleProcessBuilder(builder)
def apply(file: File): FilePartialBuilder = new FileBuilder(file)
def apply(url: URL): URLPartialBuilder = new URLBuilder(url)
def applySeq[T](builders: Seq[T])(implicit convert: T => SourcePartialBuilder): Seq[SourcePartialBuilder] = builders.map(convert)
def apply(value: Boolean): ProcessBuilder = apply(value.toString, if (value) 0 else 1)
def apply(name: String, exitValue: => Int): ProcessBuilder = new DummyProcessBuilder(name, exitValue)
def cat(file: SourcePartialBuilder, files: SourcePartialBuilder*): ProcessBuilder = cat(file :: files.toList)
def cat(files: Seq[SourcePartialBuilder]): ProcessBuilder =
{
require(files.nonEmpty)
files.map(_.cat).reduceLeft(_ #&& _)
}
}
trait SourcePartialBuilder extends NotNull {
/** Writes the output stream of this process to the given file. */
def #>(f: File): ProcessBuilder = toFile(f, false)
/** Appends the output stream of this process to the given file. */
def #>>(f: File): ProcessBuilder = toFile(f, true)
/**
* Writes the output stream of this process to the given OutputStream. The
* argument is call-by-name, so the stream is recreated, written, and closed each
* time this process is executed.
*/
def #>(out: => OutputStream): ProcessBuilder = #>(new OutputStreamBuilder(out))
def #>(b: ProcessBuilder): ProcessBuilder = new PipedProcessBuilder(toSource, b, false, ExitCodes.firstIfNonzero)
private def toFile(f: File, append: Boolean) = #>(new FileOutput(f, append))
def cat = toSource
protected def toSource: ProcessBuilder
}
trait SinkPartialBuilder extends NotNull {
/** Reads the given file into the input stream of this process. */
def #<(f: File): ProcessBuilder = #<(new FileInput(f))
/** Reads the given URL into the input stream of this process. */
def #<(f: URL): ProcessBuilder = #<(new URLInput(f))
/**
* Reads the given InputStream into the input stream of this process. The
* argument is call-by-name, so the stream is recreated, read, and closed each
* time this process is executed.
*/
def #<(in: => InputStream): ProcessBuilder = #<(new InputStreamBuilder(in))
def #<(b: ProcessBuilder): ProcessBuilder = new PipedProcessBuilder(b, toSink, false, ExitCodes.firstIfNonzero)
protected def toSink: ProcessBuilder
}
trait URLPartialBuilder extends SourcePartialBuilder
trait FilePartialBuilder extends SinkPartialBuilder with SourcePartialBuilder {
def #<<(f: File): ProcessBuilder
def #<<(u: URL): ProcessBuilder
def #<<(i: => InputStream): ProcessBuilder
def #<<(p: ProcessBuilder): ProcessBuilder
}
/**
* Represents a process that is running or has finished running.
* It may be a compound process with several underlying native processes (such as 'a #&& b`).
*/
trait Process extends NotNull {
/** Blocks until this process exits and returns the exit code.*/
def exitValue(): Int
/** Destroys this process. */
def destroy(): Unit
}
/** Represents a runnable process. */
trait ProcessBuilder extends SourcePartialBuilder with SinkPartialBuilder {
/**
* Starts the process represented by this builder, blocks until it exits, and returns the output as a String. Standard error is
* sent to the console. If the exit code is non-zero, an exception is thrown.
*/
def !! : String
/**
* Starts the process represented by this builder, blocks until it exits, and returns the output as a String. Standard error is
* sent to the provided ProcessLogger. If the exit code is non-zero, an exception is thrown.
*/
def !!(log: ProcessLogger): String
/**
* Starts the process represented by this builder. The output is returned as a Stream that blocks when lines are not available
* but the process has not completed. Standard error is sent to the console. If the process exits with a non-zero value,
* the Stream will provide all lines up to termination and then throw an exception.
*/
def lines: Stream[String]
/**
* Starts the process represented by this builder. The output is returned as a Stream that blocks when lines are not available
* but the process has not completed. Standard error is sent to the provided ProcessLogger. If the process exits with a non-zero value,
* the Stream will provide all lines up to termination but will not throw an exception.
*/
def lines(log: ProcessLogger): Stream[String]
/**
* Starts the process represented by this builder. The output is returned as a Stream that blocks when lines are not available
* but the process has not completed. Standard error is sent to the console. If the process exits with a non-zero value,
* the Stream will provide all lines up to termination but will not throw an exception.
*/
def lines_! : Stream[String]
/**
* Starts the process represented by this builder. The output is returned as a Stream that blocks when lines are not available
* but the process has not completed. Standard error is sent to the provided ProcessLogger. If the process exits with a non-zero value,
* the Stream will provide all lines up to termination but will not throw an exception.
*/
def lines_!(log: ProcessLogger): Stream[String]
/**
* Starts the process represented by this builder, blocks until it exits, and returns the exit code. Standard output and error are
* sent to the console.
*/
def ! : Int
/**
* Starts the process represented by this builder, blocks until it exits, and returns the exit code. Standard output and error are
* sent to the given ProcessLogger.
*/
def !(log: ProcessLogger): Int
/**
* Starts the process represented by this builder, blocks until it exits, and returns the exit code. Standard output and error are
* sent to the console. The newly started process reads from standard input of the current process.
*/
def !< : Int
/**
* Starts the process represented by this builder, blocks until it exits, and returns the exit code. Standard output and error are
* sent to the given ProcessLogger. The newly started process reads from standard input of the current process.
*/
def !<(log: ProcessLogger): Int
/** Starts the process represented by this builder. Standard output and error are sent to the console.*/
def run(): Process
/** Starts the process represented by this builder. Standard output and error are sent to the given ProcessLogger.*/
def run(log: ProcessLogger): Process
/** Starts the process represented by this builder. I/O is handled by the given ProcessIO instance.*/
def run(io: ProcessIO): Process
/**
* Starts the process represented by this builder. Standard output and error are sent to the console.
* The newly started process reads from standard input of the current process if `connectInput` is true.
*/
def run(connectInput: Boolean): Process
/**
* Starts the process represented by this builder, blocks until it exits, and returns the exit code. Standard output and error are
* sent to the given ProcessLogger.
* The newly started process reads from standard input of the current process if `connectInput` is true.
*/
def run(log: ProcessLogger, connectInput: Boolean): Process
def runBuffered(log: ProcessLogger, connectInput: Boolean): Process
/** Constructs a command that runs this command first and then `other` if this command succeeds.*/
def #&&(other: ProcessBuilder): ProcessBuilder
/** Constructs a command that runs this command first and then `other` if this command does not succeed.*/
def #||(other: ProcessBuilder): ProcessBuilder
/**
* Constructs a command that will run this command and pipes the output to `other`.
* `other` must be a simple command.
* The exit code will be that of `other` regardless of whether this command succeeds.
*/
def #|(other: ProcessBuilder): ProcessBuilder
/** Constructs a command that will run this command and then `other`. The exit code will be the exit code of `other`.*/
def ###(other: ProcessBuilder): ProcessBuilder
def canPipeTo: Boolean
}
/** Each method will be called in a separate thread.*/
final class ProcessIO(val writeInput: OutputStream => Unit, val processOutput: InputStream => Unit, val processError: InputStream => Unit, val inheritInput: JProcessBuilder => Boolean) extends NotNull {
def withOutput(process: InputStream => Unit): ProcessIO = new ProcessIO(writeInput, process, processError, inheritInput)
def withError(process: InputStream => Unit): ProcessIO = new ProcessIO(writeInput, processOutput, process, inheritInput)
def withInput(write: OutputStream => Unit): ProcessIO = new ProcessIO(write, processOutput, processError, inheritInput)
}
trait ProcessLogger {
def info(s: => String): Unit
def error(s: => String): Unit
def buffer[T](f: => T): T
}

View File

@ -0,0 +1,433 @@
package sbt.internal
import java.lang.{ Process => JProcess, ProcessBuilder => JProcessBuilder }
import java.io.{ BufferedReader, Closeable, InputStream, InputStreamReader, IOException, OutputStream, PrintStream }
import java.io.{ FilterInputStream, FilterOutputStream, PipedInputStream, PipedOutputStream }
import java.io.{ File, FileInputStream, FileOutputStream }
import java.net.URL
/** Runs provided code in a new Thread and returns the Thread instance. */
private object Spawn {
def apply(f: => Unit): Thread = apply(f, false)
def apply(f: => Unit, daemon: Boolean): Thread =
{
val thread = new Thread() { override def run() = { f } }
thread.setDaemon(daemon)
thread.start()
thread
}
}
private object Future {
def apply[T](f: => T): () => T =
{
val result = new SyncVar[Either[Throwable, T]]
def run(): Unit =
try { result.set(Right(f)) }
catch { case e: Exception => result.set(Left(e)) }
Spawn(run)
() =>
result.get match {
case Right(value) => value
case Left(exception) => throw exception
}
}
}
object BasicIO {
def apply(buffer: StringBuffer, log: Option[ProcessLogger], withIn: Boolean) = new ProcessIO(input(withIn), processFully(buffer), getErr(log), inheritInput(withIn))
def apply(log: ProcessLogger, withIn: Boolean) = new ProcessIO(input(withIn), processInfoFully(log), processErrFully(log), inheritInput(withIn))
def getErr(log: Option[ProcessLogger]) = log match { case Some(lg) => processErrFully(lg); case None => toStdErr }
private def processErrFully(log: ProcessLogger) = processFully(s => log.error(s))
private def processInfoFully(log: ProcessLogger) = processFully(s => log.info(s))
def closeOut = (_: OutputStream).close()
final val BufferSize = 8192
final val Newline = System.getProperty("line.separator")
def close(c: java.io.Closeable) = try { c.close() } catch { case _: java.io.IOException => () }
def processFully(buffer: Appendable): InputStream => Unit = processFully(appendLine(buffer))
def processFully(processLine: String => Unit): InputStream => Unit =
in =>
{
val reader = new BufferedReader(new InputStreamReader(in))
processLinesFully(processLine)(reader.readLine)
reader.close()
}
def processLinesFully(processLine: String => Unit)(readLine: () => String): Unit = {
def readFully(): Unit = {
val line = readLine()
if (line != null) {
processLine(line)
readFully()
}
}
readFully()
}
def connectToIn(o: OutputStream): Unit = transferFully(Uncloseable protect System.in, o)
def input(connect: Boolean): OutputStream => Unit = if (connect) connectToIn else closeOut
def standard(connectInput: Boolean): ProcessIO = standard(input(connectInput), inheritInput(connectInput))
def standard(in: OutputStream => Unit, inheritIn: JProcessBuilder => Boolean): ProcessIO = new ProcessIO(in, toStdOut, toStdErr, inheritIn)
def toStdErr = (in: InputStream) => transferFully(in, System.err)
def toStdOut = (in: InputStream) => transferFully(in, System.out)
def transferFully(in: InputStream, out: OutputStream): Unit =
try { transferFullyImpl(in, out) }
catch { case _: InterruptedException => () }
private[this] def appendLine(buffer: Appendable): String => Unit =
line =>
{
buffer.append(line)
buffer.append(Newline)
}
private[this] def transferFullyImpl(in: InputStream, out: OutputStream): Unit = {
val continueCount = 1 //if(in.isInstanceOf[PipedInputStream]) 1 else 0
val buffer = new Array[Byte](BufferSize)
def read(): Unit = {
val byteCount = in.read(buffer)
if (byteCount >= continueCount) {
out.write(buffer, 0, byteCount)
out.flush()
read
}
}
read
in.close()
}
def inheritInput(connect: Boolean) = { p: JProcessBuilder => if (connect) InheritInput(p) else false }
}
private[sbt] object ExitCodes {
def ignoreFirst: (Int, Int) => Int = (a, b) => b
def firstIfNonzero: (Int, Int) => Int = (a, b) => if (a != 0) a else b
}
private[sbt] abstract class AbstractProcessBuilder extends ProcessBuilder with SinkPartialBuilder with SourcePartialBuilder {
def #&&(other: ProcessBuilder): ProcessBuilder = new AndProcessBuilder(this, other)
def #||(other: ProcessBuilder): ProcessBuilder = new OrProcessBuilder(this, other)
def #|(other: ProcessBuilder): ProcessBuilder =
{
require(other.canPipeTo, "Piping to multiple processes is not supported.")
new PipedProcessBuilder(this, other, false, exitCode = ExitCodes.ignoreFirst)
}
def ###(other: ProcessBuilder): ProcessBuilder = new SequenceProcessBuilder(this, other)
protected def toSource = this
protected def toSink = this
def run(): Process = run(false)
def run(connectInput: Boolean): Process = run(BasicIO.standard(connectInput))
def run(log: ProcessLogger): Process = run(log, false)
def run(log: ProcessLogger, connectInput: Boolean): Process = run(BasicIO(log, connectInput))
private[this] def getString(log: Option[ProcessLogger], withIn: Boolean): String =
{
val buffer = new StringBuffer
val code = this ! BasicIO(buffer, log, withIn)
if (code == 0) buffer.toString else sys.error("Nonzero exit value: " + code)
}
def !! = getString(None, false)
def !!(log: ProcessLogger) = getString(Some(log), false)
def !!< = getString(None, true)
def !!<(log: ProcessLogger) = getString(Some(log), true)
def lines: Stream[String] = lines(false, true, None)
def lines(log: ProcessLogger): Stream[String] = lines(false, true, Some(log))
def lines_! : Stream[String] = lines(false, false, None)
def lines_!(log: ProcessLogger): Stream[String] = lines(false, false, Some(log))
private[this] def lines(withInput: Boolean, nonZeroException: Boolean, log: Option[ProcessLogger]): Stream[String] =
{
val streamed = Streamed[String](nonZeroException)
val process = run(new ProcessIO(BasicIO.input(withInput), BasicIO.processFully(streamed.process), BasicIO.getErr(log), BasicIO.inheritInput(withInput)))
Spawn { streamed.done(process.exitValue()) }
streamed.stream()
}
def ! = run(false).exitValue()
def !< = run(true).exitValue()
def !(log: ProcessLogger) = runBuffered(log, false).exitValue()
def !<(log: ProcessLogger) = runBuffered(log, true).exitValue()
def runBuffered(log: ProcessLogger, connectInput: Boolean) =
log.buffer { run(log, connectInput) }
def !(io: ProcessIO) = run(io).exitValue()
def canPipeTo = false
}
private[sbt] class URLBuilder(url: URL) extends URLPartialBuilder with SourcePartialBuilder {
protected def toSource = new URLInput(url)
}
private[sbt] class FileBuilder(base: File) extends FilePartialBuilder with SinkPartialBuilder with SourcePartialBuilder {
protected def toSource = new FileInput(base)
protected def toSink = new FileOutput(base, false)
def #<<(f: File): ProcessBuilder = #<<(new FileInput(f))
def #<<(u: URL): ProcessBuilder = #<<(new URLInput(u))
def #<<(s: => InputStream): ProcessBuilder = #<<(new InputStreamBuilder(s))
def #<<(b: ProcessBuilder): ProcessBuilder = new PipedProcessBuilder(b, new FileOutput(base, true), false, ExitCodes.firstIfNonzero)
}
private abstract class BasicBuilder extends AbstractProcessBuilder {
protected[this] def checkNotThis(a: ProcessBuilder) = require(a != this, "Compound process '" + a + "' cannot contain itself.")
final def run(io: ProcessIO): Process =
{
val p = createProcess(io)
p.start()
p
}
protected[this] def createProcess(io: ProcessIO): BasicProcess
}
private abstract class BasicProcess extends Process {
def start(): Unit
}
private abstract class CompoundProcess extends BasicProcess {
def destroy(): Unit = destroyer()
def exitValue() = getExitValue().getOrElse(sys.error("No exit code: process destroyed."))
def start() = getExitValue
protected lazy val (getExitValue, destroyer) =
{
val code = new SyncVar[Option[Int]]()
code.set(None)
val thread = Spawn(code.set(runAndExitValue()))
(
Future { thread.join(); code.get },
() => thread.interrupt()
)
}
/** Start and block until the exit value is available and then return it in Some. Return None if destroyed (use 'run')*/
protected[this] def runAndExitValue(): Option[Int]
protected[this] def runInterruptible[T](action: => T)(destroyImpl: => Unit): Option[T] =
{
try { Some(action) }
catch { case _: InterruptedException => destroyImpl; None }
}
}
private abstract class SequentialProcessBuilder(a: ProcessBuilder, b: ProcessBuilder, operatorString: String) extends BasicBuilder {
checkNotThis(a)
checkNotThis(b)
override def toString = " ( " + a + " " + operatorString + " " + b + " ) "
}
private class PipedProcessBuilder(first: ProcessBuilder, second: ProcessBuilder, toError: Boolean, exitCode: (Int, Int) => Int) extends SequentialProcessBuilder(first, second, if (toError) "#|!" else "#|") {
override def createProcess(io: ProcessIO) = new PipedProcesses(first, second, io, toError, exitCode)
}
private class AndProcessBuilder(first: ProcessBuilder, second: ProcessBuilder) extends SequentialProcessBuilder(first, second, "#&&") {
override def createProcess(io: ProcessIO) = new AndProcess(first, second, io)
}
private class OrProcessBuilder(first: ProcessBuilder, second: ProcessBuilder) extends SequentialProcessBuilder(first, second, "#||") {
override def createProcess(io: ProcessIO) = new OrProcess(first, second, io)
}
private class SequenceProcessBuilder(first: ProcessBuilder, second: ProcessBuilder) extends SequentialProcessBuilder(first, second, "###") {
override def createProcess(io: ProcessIO) = new ProcessSequence(first, second, io)
}
private class SequentialProcess(a: ProcessBuilder, b: ProcessBuilder, io: ProcessIO, evaluateSecondProcess: Int => Boolean) extends CompoundProcess {
protected[this] override def runAndExitValue() =
{
val first = a.run(io)
runInterruptible(first.exitValue)(first.destroy()) flatMap
{ codeA =>
if (evaluateSecondProcess(codeA)) {
val second = b.run(io)
runInterruptible(second.exitValue)(second.destroy())
} else
Some(codeA)
}
}
}
private class AndProcess(a: ProcessBuilder, b: ProcessBuilder, io: ProcessIO) extends SequentialProcess(a, b, io, _ == 0)
private class OrProcess(a: ProcessBuilder, b: ProcessBuilder, io: ProcessIO) extends SequentialProcess(a, b, io, _ != 0)
private class ProcessSequence(a: ProcessBuilder, b: ProcessBuilder, io: ProcessIO) extends SequentialProcess(a, b, io, ignore => true)
private class PipedProcesses(a: ProcessBuilder, b: ProcessBuilder, defaultIO: ProcessIO, toError: Boolean, exitCode: (Int, Int) => Int) extends CompoundProcess {
protected[this] override def runAndExitValue() =
{
val currentSource = new SyncVar[Option[InputStream]]
val pipeOut = new PipedOutputStream
val source = new PipeSource(currentSource, pipeOut, a.toString)
source.start()
val pipeIn = new PipedInputStream(pipeOut)
val currentSink = new SyncVar[Option[OutputStream]]
val sink = new PipeSink(pipeIn, currentSink, b.toString)
sink.start()
def handleOutOrError(fromOutput: InputStream) = currentSource.put(Some(fromOutput))
val firstIO =
if (toError)
defaultIO.withError(handleOutOrError)
else
defaultIO.withOutput(handleOutOrError)
val secondIO = defaultIO.withInput(toInput => currentSink.put(Some(toInput)))
val second = b.run(secondIO)
val first = a.run(firstIO)
try {
runInterruptible {
val firstResult = first.exitValue
currentSource.put(None)
currentSink.put(None)
val secondResult = second.exitValue
exitCode(firstResult, secondResult)
} {
first.destroy()
second.destroy()
}
} finally {
BasicIO.close(pipeIn)
BasicIO.close(pipeOut)
}
}
}
private class PipeSource(currentSource: SyncVar[Option[InputStream]], pipe: PipedOutputStream, label: => String) extends Thread {
final override def run(): Unit = {
currentSource.get match {
case Some(source) =>
try { BasicIO.transferFully(source, pipe) }
catch { case e: IOException => println("I/O error " + e.getMessage + " for process: " + label); e.printStackTrace() }
finally {
BasicIO.close(source)
currentSource.unset()
}
run()
case None =>
currentSource.unset()
BasicIO.close(pipe)
}
}
}
private class PipeSink(pipe: PipedInputStream, currentSink: SyncVar[Option[OutputStream]], label: => String) extends Thread {
final override def run(): Unit = {
currentSink.get match {
case Some(sink) =>
try { BasicIO.transferFully(pipe, sink) }
catch { case e: IOException => println("I/O error " + e.getMessage + " for process: " + label); e.printStackTrace() }
finally {
BasicIO.close(sink)
currentSink.unset()
}
run()
case None =>
currentSink.unset()
}
}
}
private[sbt] class DummyProcessBuilder(override val toString: String, exitValue: => Int) extends AbstractProcessBuilder {
override def run(io: ProcessIO): Process = new DummyProcess(exitValue)
override def canPipeTo = true
}
/**
* A thin wrapper around a java.lang.Process. `ioThreads` are the Threads created to do I/O.
* The implementation of `exitValue` waits until these threads die before returning.
*/
private class DummyProcess(action: => Int) extends Process {
private[this] val exitCode = Future(action)
override def exitValue() = exitCode()
override def destroy(): Unit = ()
}
/** Represents a simple command without any redirection or combination. */
private[sbt] class SimpleProcessBuilder(p: JProcessBuilder) extends AbstractProcessBuilder {
override def run(io: ProcessIO): Process =
{
import io._
val inherited = inheritInput(p)
val process = p.start()
// spawn threads that process the output and error streams, and also write input if not inherited.
if (!inherited)
Spawn(writeInput(process.getOutputStream))
val outThread = Spawn(processOutput(process.getInputStream))
val errorThread =
if (!p.redirectErrorStream)
Spawn(processError(process.getErrorStream)) :: Nil
else
Nil
new SimpleProcess(process, outThread :: errorThread)
}
override def toString = p.command.toString
override def canPipeTo = true
}
/**
* A thin wrapper around a java.lang.Process. `outputThreads` are the Threads created to read from the
* output and error streams of the process.
* The implementation of `exitValue` wait for the process to finish and then waits until the threads reading output and error streams die before
* returning. Note that the thread that reads the input stream cannot be interrupted, see https://github.com/sbt/sbt/issues/327 and
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4514257
*/
private class SimpleProcess(p: JProcess, outputThreads: List[Thread]) extends Process {
override def exitValue() =
{
try {
p.waitFor()
} catch {
case _: InterruptedException => p.destroy()
}
outputThreads.foreach(_.join()) // this ensures that all output is complete before returning (waitFor does not ensure this)
p.exitValue()
}
override def destroy() = p.destroy()
}
private[sbt] class FileOutput(file: File, append: Boolean) extends OutputStreamBuilder(new FileOutputStream(file, append), file.getAbsolutePath)
private[sbt] class URLInput(url: URL) extends InputStreamBuilder(url.openStream, url.toString)
private[sbt] class FileInput(file: File) extends InputStreamBuilder(new FileInputStream(file), file.getAbsolutePath)
import Uncloseable.protect
private[sbt] class OutputStreamBuilder(stream: => OutputStream, label: String) extends ThreadProcessBuilder(label, _.writeInput(protect(stream))) {
def this(stream: => OutputStream) = this(stream, "<output stream>")
}
private[sbt] class InputStreamBuilder(stream: => InputStream, label: String) extends ThreadProcessBuilder(label, _.processOutput(protect(stream))) {
def this(stream: => InputStream) = this(stream, "<input stream>")
}
private[sbt] abstract class ThreadProcessBuilder(override val toString: String, runImpl: ProcessIO => Unit) extends AbstractProcessBuilder {
override def run(io: ProcessIO): Process =
{
val success = new SyncVar[Boolean]
success.put(false)
new ThreadProcess(Spawn { runImpl(io); success.set(true) }, success)
}
}
private[sbt] final class ThreadProcess(thread: Thread, success: SyncVar[Boolean]) extends Process {
override def exitValue() =
{
thread.join()
if (success.get) 0 else 1
}
override def destroy(): Unit = thread.interrupt()
}
object Uncloseable {
def apply(in: InputStream): InputStream = new FilterInputStream(in) { override def close(): Unit = () }
def apply(out: OutputStream): OutputStream = new FilterOutputStream(out) { override def close(): Unit = () }
def protect(in: InputStream): InputStream = if (in eq System.in) Uncloseable(in) else in
def protect(out: OutputStream): OutputStream = if ((out eq System.out) || (out eq System.err)) Uncloseable(out) else out
}
private[sbt] object Streamed {
def apply[T](nonzeroException: Boolean): Streamed[T] =
{
val q = new java.util.concurrent.LinkedBlockingQueue[Either[Int, T]]
def next(): Stream[T] =
q.take match {
case Left(0) => Stream.empty
case Left(code) => if (nonzeroException) sys.error("Nonzero exit code: " + code) else Stream.empty
case Right(s) => Stream.cons(s, next)
}
new Streamed((s: T) => q.put(Right(s)), code => q.put(Left(code)), () => next())
}
}
private[sbt] final class Streamed[T](val process: T => Unit, val done: Int => Unit, val stream: () => Stream[T]) extends NotNull

View File

@ -0,0 +1,90 @@
package example.test
import minitest._
import scala.sys.process._
import java.io.File
object SbtRunnerTest extends SimpleTestSuite with PowerAssertions {
// 1.3.0, 1.3.0-M4
private val versionRegEx = "\\d(\\.\\d+){2}(-\\w+)?"
lazy val isWindows: Boolean = sys.props("os.name").toLowerCase(java.util.Locale.ENGLISH).contains("windows")
lazy val sbtScript =
if (isWindows) new File("target/universal/stage/bin/sbt.bat")
else new File("target/universal/stage/bin/sbt")
def sbtProcess(args: String*) = sbtProcessWithOpts(args: _*)("", "")
def sbtProcessWithOpts(args: String*)(javaOpts: String, sbtOpts: String) =
sbt.internal.Process(Seq(sbtScript.getAbsolutePath) ++ args, new File("citest"),
"JAVA_OPTS" -> javaOpts,
"SBT_OPTS" -> sbtOpts)
test("sbt runs") {
assert(sbtScript.exists)
val out = sbtProcess("compile", "-v").!
assert(out == 0)
()
}
test("sbt -V|-version|--version should print sbtVersion") {
val out = sbtProcess("-version").!!.trim
val expectedVersion =
s"""|(?m)^sbt version in this project: $versionRegEx(\\r)?
|sbt script version: $versionRegEx$$
|""".stripMargin.trim.replace("\n", "\\n")
assert(out.matches(expectedVersion))
val out2 = sbtProcess("--version").!!.trim
assert(out2.matches(expectedVersion))
val out3 = sbtProcess("-V").!!.trim
assert(out3.matches(expectedVersion))
()
}
test("sbt --numeric-version should print sbt script version") {
val out = sbtProcess("--numeric-version").!!.trim
val expectedVersion = "^"+versionRegEx+"$"
assert(out.matches(expectedVersion))
()
}
test("sbt --script-version should print sbtVersion") {
val out = sbtProcess("--script-version").!!.trim
val expectedVersion = "^"+versionRegEx+"$"
assert(out.matches(expectedVersion))
()
}
test("sbt --sbt-jar should run") {
val out = sbtProcess("compile", "-v", "--sbt-jar", "../target/universal/stage/bin/sbt-launch.jar").!!.linesIterator.toList
assert(out.contains[String]("../target/universal/stage/bin/sbt-launch.jar") ||
out.contains[String]("\"../target/universal/stage/bin/sbt-launch.jar\"")
)
()
}
test("sbt \"testOnly *\"") {
val out = sbtProcess("testOnly *", "--no-colors", "-v").!!.linesIterator.toList
assert(out.contains[String]("[info] HelloTest"))
()
}
/*
test("sbt --client") {
val out = sbtProcess("--client", "--no-colors", "compile").!!.linesIterator.toList
if (isWindows) {
println(out)
} else {
assert(out exists { _.contains("server was not detected") })
}
val out2 = sbtProcess("--client", "--no-colors", "shutdown").!!.linesIterator.toList
if (isWindows) {
println(out)
} else {
assert(out2 exists { _.contains("disconnected") })
}
()
}
*/
}

View File

@ -0,0 +1,172 @@
package example.test
import minitest._
import java.io.File
object SbtScriptTest extends SimpleTestSuite with PowerAssertions {
lazy val isWindows: Boolean = sys.props("os.name").toLowerCase(java.util.Locale.ENGLISH).contains("windows")
lazy val sbtScript =
if (isWindows) new File("target/universal/stage/bin/sbt.bat")
else new File("target/universal/stage/bin/sbt")
private val javaBinDir = new File("integration-test", "bin").getAbsolutePath
private def makeTest(
name: String,
javaOpts: String = "",
sbtOpts: String = "",
)(args: String*)(f: List[String] => Any) = {
test(name) {
val out = sbtProcessWithOpts(args: _*)(javaOpts = javaOpts, sbtOpts = sbtOpts).!!.linesIterator.toList
f(out)
()
}
}
def sbtProcess(args: String*) = sbtProcessWithOpts(args: _*)("", "")
def sbtProcessWithOpts(args: String*)(javaOpts: String, sbtOpts: String) = {
val path = sys.env("PATH")
sbt.internal.Process(Seq(sbtScript.getAbsolutePath) ++ args, new File("citest"),
"JAVA_OPTS" -> javaOpts,
"SBT_OPTS" -> sbtOpts,
if (isWindows)
"JAVACMD" -> new File(javaBinDir, "java.cmd").getAbsolutePath()
else
"PATH" -> (javaBinDir + File.pathSeparator + path)
)
}
makeTest("sbt -no-colors")("compile", "-no-colors", "-v") { out: List[String] =>
assert(out.contains[String]("-Dsbt.log.noformat=true"))
}
makeTest("sbt --no-colors")("compile", "--no-colors", "-v") { out: List[String] =>
assert(out.contains[String]("-Dsbt.log.noformat=true"))
}
makeTest("sbt --color=false")("compile", "--color=false", "-v") { out: List[String] =>
assert(out.contains[String]("-Dsbt.color=false"))
}
makeTest("sbt --no-colors in SBT_OPTS", sbtOpts = "--no-colors")("compile", "-v") { out: List[String] =>
if (isWindows) cancel("Test not supported on windows")
assert(out.contains[String]("-Dsbt.log.noformat=true"))
}
makeTest("sbt --debug-inc")("compile", "--debug-inc", "-v") { out: List[String] =>
assert(out.contains[String]("-Dxsbt.inc.debug=true"))
}
makeTest("sbt --supershell=never")("compile", "--supershell=never", "-v") { out: List[String] =>
assert(out.contains[String]("-Dsbt.supershell=never"))
}
makeTest("sbt --timings")("compile", "--timings", "-v") { out: List[String] =>
assert(out.contains[String]("-Dsbt.task.timings=true"))
}
makeTest("sbt -D arguments")("-Dsbt.supershell=false", "compile", "-v") { out: List[String] =>
assert(out.contains[String]("-Dsbt.supershell=false"))
}
makeTest("sbt --sbt-version")("--sbt-version", "1.3.13", "-v") { out: List[String] =>
assert(out.contains[String]("-Dsbt.version=1.3.13"))
}
makeTest("sbt -mem 503")("-mem", "503", "-v") { out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
}
makeTest("sbt with -mem 503, -Xmx in JAVA_OPTS", javaOpts = "-Xmx1024m")("-mem", "503", "-v") { out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xmx1024m"))
}
makeTest("sbt with -mem 503, -Xmx in SBT_OPTS", sbtOpts = "-Xmx1024m")("-mem", "503", "-v") { out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xmx1024m"))
}
makeTest("sbt with -mem 503, -Xss in JAVA_OPTS", javaOpts = "-Xss6m")("-mem", "503", "-v") { out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xss6m"))
}
makeTest("sbt with -mem 503, -Xss in SBT_OPTS", sbtOpts = "-Xss6m")("-mem", "503", "-v") { out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xss6m"))
}
makeTest("sbt with -Xms2048M -Xmx2048M -Xss6M in JAVA_OPTS", javaOpts = "-Xms2048M -Xmx2048M -Xss6M")("-v") { out: List[String] =>
assert(out.contains[String]("-Xms2048M"))
assert(out.contains[String]("-Xmx2048M"))
assert(out.contains[String]("-Xss6M"))
}
makeTest("sbt with -Xms2048M -Xmx2048M -Xss6M in SBT_OPTS", sbtOpts = "-Xms2048M -Xmx2048M -Xss6M")( "-v") { out: List[String] =>
assert(out.contains[String]("-Xms2048M"))
assert(out.contains[String]("-Xmx2048M"))
assert(out.contains[String]("-Xss6M"))
}
makeTest(
name = "sbt with -Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080 in SBT_OPTS",
sbtOpts = "-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080",
)("-v") { out: List[String] =>
assert(out.contains[String]("-Dhttp.proxyHost=proxy"))
assert(out.contains[String]("-Dhttp.proxyPort=8080"))
}
makeTest(
name = "sbt with -XX:ParallelGCThreads=16 -XX:PermSize=128M in SBT_OPTS",
sbtOpts = "-XX:ParallelGCThreads=16 -XX:PermSize=128M",
)("-v") { out: List[String] =>
assert(out.contains[String]("-XX:ParallelGCThreads=16"))
assert(out.contains[String]("-XX:PermSize=128M"))
}
makeTest("sbt with -XX:+UseG1GC -XX:+PrintGC in JAVA_OPTS", javaOpts = "-XX:+UseG1GC -XX:+PrintGC")("-v") { out: List[String] =>
assert(out.contains[String]("-XX:+UseG1GC"))
assert(out.contains[String]("-XX:+PrintGC"))
assert(!out.contains[String]("-XX:+UseG1GC=-XX:+PrintGC"))
}
makeTest("sbt with -XX:-UseG1GC -XX:-PrintGC in SBT_OPTS", sbtOpts = "-XX:+UseG1GC -XX:+PrintGC")( "-v") { out: List[String] =>
assert(out.contains[String]("-XX:+UseG1GC"))
assert(out.contains[String]("-XX:+PrintGC"))
assert(!out.contains[String]("-XX:+UseG1GC=-XX:+PrintGC"))
}
test("sbt with -debug in SBT_OPTS appears in sbt commands") {
if (isWindows) cancel("Test not supported on windows")
val out: List[String] = sbtProcessWithOpts("compile", "-v")(javaOpts = "", sbtOpts = "-debug").!!.linesIterator.toList
// Debug argument must appear in the 'commands' section (after the sbt-launch.jar argument) to work
val sbtLaunchMatcher = """^.+sbt-launch.jar["]{0,1}$""".r
val locationOfSbtLaunchJarArg = out.zipWithIndex.collectFirst {
case (arg, index) if sbtLaunchMatcher.findFirstIn(arg).nonEmpty => index
}
assert(locationOfSbtLaunchJarArg.nonEmpty)
val argsAfterSbtLaunch = out.drop(locationOfSbtLaunchJarArg.get)
assert(argsAfterSbtLaunch.contains("-debug"))
()
}
makeTest("sbt --jvm-debug <port>")("--jvm-debug", "12345", "-v") { out: List[String] =>
assert(out.contains[String]("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=12345"))
}
makeTest("sbt --no-share adds three system properties")("--no-share") { out: List[String] =>
assert(out.contains[String]("-Dsbt.global.base=project/.sbtboot"))
assert(out.contains[String]("-Dsbt.boot.directory=project/.boot"))
assert(out.contains[String]("-Dsbt.ivy.home=project/.ivy"))
}
makeTest("accept `--ivy` in `SBT_OPTS`", sbtOpts = "--ivy /ivy/dir")("-v") { out: List[String] =>
if (isWindows) cancel("Test not supported on windows")
assert(out.contains[String]("-Dsbt.ivy.home=/ivy/dir"))
}
}

View File

@ -0,0 +1,38 @@
package sbt.internal
// minimal copy of scala.concurrent.SyncVar since that version deprecated put and unset
private[sbt] final class SyncVar[A] {
private[this] var isDefined: Boolean = false
private[this] var value: Option[A] = None
/** Waits until a value is set and then gets it. Does not clear the value */
def get: A = synchronized {
while (!isDefined) wait()
value.get
}
/** Waits until a value is set, gets it, and finally clears the value. */
def take(): A = synchronized {
try get finally unset()
}
/** Sets the value, whether or not it is currently defined. */
def set(x: A): Unit = synchronized {
isDefined = true
value = Some(x)
notifyAll()
}
/** Sets the value, first waiting until it is undefined if it is currently defined. */
def put(x: A): Unit = synchronized {
while (isDefined) wait()
set(x)
}
/** Clears the value, whether or not it is current defined. */
def unset(): Unit = synchronized {
isDefined = false
value = None
notifyAll()
}
}

View File

@ -0,0 +1,60 @@
import sbt._
import Keys._
import com.typesafe.sbt.SbtPgp
import com.typesafe.sbt.packager.universal.{ UniversalPlugin, UniversalDeployPlugin }
import com.typesafe.sbt.packager.debian.{ DebianPlugin, DebianDeployPlugin }
import com.typesafe.sbt.packager.rpm.{ RpmPlugin, RpmDeployPlugin }
import com.typesafe.sbt.pgp.gpgExtension
object PackageSignerPlugin extends sbt.AutoPlugin {
override def trigger = allRequirements
override def requires = SbtPgp && UniversalDeployPlugin && DebianDeployPlugin && RpmDeployPlugin
import com.typesafe.sbt.pgp.PgpKeys._
import UniversalPlugin.autoImport._
import DebianPlugin.autoImport._
import RpmPlugin.autoImport._
override def projectSettings: Seq[Setting[_]] =
inConfig(Universal)(packageSignerSettings) ++
inConfig(Debian)(packageSignerSettings) ++
inConfig(Rpm)(packageSignerSettings)
def subExtension(art: Artifact, ext: String): Artifact =
art.copy(extension = ext)
def packageSignerSettings: Seq[Setting[_]] = Seq(
signedArtifacts := {
val artifacts = packagedArtifacts.value
val r = pgpSigner.value
val skipZ = (skip in pgpSigner).value
val s = streams.value
if (!skipZ) {
artifacts flatMap { case (art, f) =>
Seq(art -> f,
subExtension(art, art.extension + gpgExtension) ->
r.sign(f, file(f.getAbsolutePath + gpgExtension), s))
}
}
else artifacts
},
publishSignedConfiguration := Classpaths.publishConfig(
signedArtifacts.value,
None,
resolverName = Classpaths.getPublishTo(publishTo.value).name,
checksums = (checksums in publish).value,
logging = ivyLoggingLevel.value,
overwrite = isSnapshot.value),
publishLocalSignedConfiguration := Classpaths.publishConfig(
signedArtifacts.value,
None,
resolverName = "local",
checksums = (checksums in publish).value,
logging = ivyLoggingLevel.value,
overwrite = isSnapshot.value),
publishSigned := Classpaths.publishTask(publishSignedConfiguration, deliver).value,
publishLocalSigned := Classpaths.publishTask(publishLocalSignedConfiguration, deliver).value
)
}

View File

@ -0,0 +1 @@
sbt.version=0.13.17

View File

@ -0,0 +1,5 @@
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.2.0-M9")
libraryDependencies += "net.databinder" %% "dispatch-http" % "0.8.10"
addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.1")
addSbtPlugin("com.eed3si9n" % "sbt-export-repo" % "0.1.1")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.1")

View File

@ -0,0 +1,49 @@
sbt (1.0.0) stable; urgency=low
* sbt 1.0 uses Scala 2.12 for build definitions and plugins. This also requires JDK 8.
* See http://www.scala-sbt.org/1.x/docs/sbt-1.0-Release-Notes.html for the full list of changes.
-- Eugene Yokota <eed3si9n@gmail.com> Fri, 11 Aug 2017 00:00:00 +0000
sbt (0.13.15) stable; urgency=low
* sbt 0.13.15 removes the Maven version range when possible.
* Adds preliminary compatibility with JDK 9. Using this requires 0.13.15+ launcher. #2951 by @retronym
* Adds "local-preloaded" repository for offline installation
-- Eugene Yokota <eed3si9n@gmail.com> Mon, 10 Apr 2017 00:00:00 +0000
sbt (0.13.13) stable; urgency=low
* The `new` command, which helps creating new build definitions.
This is extensible via `templateResolverInfos` setting.
sbt 0.13.13 will ship with Giter8 template resolver out of the box.
#2705 by @eed3si9n
* Auto plugins can add synthetic subprojects. #2717 by @eed3si9n
* The no-longer-documented sbt 0.12 DSL `<<=`, `<+=`, and `<++=`
operators and tuple enrichment are now marked deprecated.
(These are removed in 1.0.x branch.) @eed3si9n and @dwijnand
* The `.value` method is deprecated for input tasks since `.evaluated`
is normally what's needed.
(Also removed in 1.0.x branch) #2709 by @eed3si9n
* sbt 0.13.13 will display deprecation warning for build.sbt.
#2784 by @eed3si9n
* Renames the early command `--<command>` that was added in 0.13.1 to
`early(<command>)`. `--error` will work, but we encourage you to
migrate to single hyphen version: `-error`, `-warn`, `-info`, and
`-debug`. #2742 by @eed3si9n
-- Dale Wijnand <dale.wijnand@gmail.com> Fri, 28 Oct 2016 14:30:00 +0000
sbt (0.12.0-build-0100)
* No need for different launcher jar files now
-- Joshua Suereth <joshua.suereth@typesafe.com> 2012-07-2012
sbt (0.11.2-build-0100)
* First debian package release
-- Joshua Suereth <joshua.suereth@typesafe.com> 2011-11-29

View File

@ -0,0 +1,22 @@
sbt
Copyright: Paul Phillips, Lightbend, and other contributors.
2011-11-28
The home page of sbt package is at:
https://github.com/sbt/sbt-launcher-package
The entire code base may be distributed under the terms of the BSD license, which appears immediately below.
Copyright (c) 2011 - 2018, Paul Phillips, Lightbend, and other contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,22 @@
sbt
Copyright: Paul Phillips, Lightbend, and other contributors.
2011-11-28
The home page of sbt package is at:
https://github.com/sbt/sbt-launcher-package
The entire code base may be distributed under the terms of the BSD license, which appears immediately below.
Copyright (c) 2011 - 2018, Paul Phillips, Lightbend, and other contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,98 @@
.\" Process this file with
.\" groff -man -Tascii sbt.1
.\"
.TH SBT 1 "NOVEMBER 2011" Linux "User Manuals"
.SH NAME
sbt \- An interactive build tool for Scala, Java, and more.
.SH SYNOPSIS
.B sbt [-h]
.I <commands>
.B ...
.SH DESCRIPTION
SBT is a build tool for Scala, Java, and more. It requires Java 1.8 or later.
The current directory is assumed to be the project.
.SH OPTIONS
.IP "-h, --help"
Show help options.
.IP "-v, --verbose"
turn up the noise
.IP "-V, --version"
print sbt version information
.IP "--numeric-version"
print the numeric sbt version (sbt sbtVersion)
.IP "--script-version"
print the version of sbt script
.IP "-d, --debug"
set sbt log level to debug
.IP --no-colors
disable ANSI color codes
.IP "--color=auto|always|true|false|never"
enable or disable ANSI color codes (sbt 1.3 and above)
.IP "--supershell=auto|always|true|false|never"
enable or disable supershell (sbt 1.3 and above)
.IP --traces
generate Trace Event report on shutdown (sbt 1.3 and above)
.IP --timings
display task timings report on shutdown
.IP --sbt-create
start sbt even if current directory contains no sbt project
.IP "--sbt-dir <path>"
path to global settings/plugins directory (default: ~/.sbt)
.IP "--sbt-boot <path>"
path to shared boot directory (default: ~/.sbt/boot in 0.11 series)
.IP "--ivy <path>"
path to local Ivy repository (default: ~/.ivy2)
.IP "--mem <integer>"
set memory options (default: 1024)
.IP "--no-share"
use all local caches; no sharing
.IP "--no-global"
uses global caches, but does not use global ~/.sbt directory.
.IP "--jvm-debug <port>"
Turn on JVM debugging, open at the given port.
.IP --batch
Disable interactive mode
.SH SBT Version Options
.IP "--sbt-version <version>"
Use the alternate system wide
.IP "--sbt-jar <path>"
use the specified jar as the sbt launcher
.SH Java Options
.IP "--java-home <path>"
alternate JAVA_HOME
.IP "-Dkey=val"
pass -Dkey=val directly to the java runtime
.IP -J-X
pass option -X directly to the java runtime (-J is stripped)
.IP -S-X
add -X to sbt's scalacOptions (-S is stripped)
.SH FILES
.I ~/.sbt
.RS
The user configuration directory.
.RE
.I ".jvmopts"
.RS
if this file exists in the current directory, its contents are appended
to the JAVA_OPTS.
.RE
.I ".sbtopts"
.RS
if this file exists in the current directory, its contents are prepended
to the runner args.
.RE
.I "/etc/sbt/sbtopts"
.RS
if this file exists, it is prepended to the runner args
.SH ENVIRONMENT
.IP JAVA_OPTS
If non-null a set of arguments passed to java.
.IP SBT_OPTS
environment variable, if unset uses "-Dfile.encoding=UTF-8".
.SH NOTES
In the case of duplicated or conflicting options, the order above
shows precedence: JAVA_OPTS lowest, command line options highest.
.SH EXAMPLES
Most users of this script will only have to call "sbt" on the command line.
.SH BUGS
https://github.com/sbt/sbt/issues

View File

@ -0,0 +1,678 @@
#!/usr/bin/env bash
set +e
declare -a residual_args
declare -a java_args
declare -a scalac_args
declare -a sbt_commands
declare -a sbt_options
declare -a print_version
declare -a print_sbt_version
declare -a print_sbt_script_version
declare -a original_args
declare java_cmd=java
declare java_version
declare init_sbt_version=_to_be_replaced
declare sbt_default_mem=1024
declare -r default_sbt_opts=""
declare -r default_java_opts="-Dfile.encoding=UTF-8"
declare sbt_verbose=
declare sbt_debug=
declare build_props_sbt_version=
declare use_sbtn=
declare sbtn_command="$SBTN_CMD"
### ------------------------------- ###
### Helper methods for BASH scripts ###
### ------------------------------- ###
# Bash reimplementation of realpath to return the absolute path
realpathish () {
(
TARGET_FILE="$1"
FIX_CYGPATH="$2"
cd "$(dirname "$TARGET_FILE")"
TARGET_FILE=$(basename "$TARGET_FILE")
COUNT=0
while [ -L "$TARGET_FILE" -a $COUNT -lt 100 ]
do
TARGET_FILE=$(readlink "$TARGET_FILE")
cd "$(dirname "$TARGET_FILE")"
TARGET_FILE=$(basename "$TARGET_FILE")
COUNT=$(($COUNT + 1))
done
# make sure we grab the actual windows path, instead of cygwin's path.
if [[ "x$FIX_CYGPATH" != "x" ]]; then
echo "$(cygwinpath "$(pwd -P)/$TARGET_FILE")"
else
echo "$(pwd -P)/$TARGET_FILE"
fi
)
}
# Uses uname to detect if we're in the odd cygwin environment.
is_cygwin() {
local os=$(uname -s)
case "$os" in
CYGWIN*) return 0 ;;
MINGW*) return 0 ;;
MSYS*) return 0 ;;
*) return 1 ;;
esac
}
# TODO - Use nicer bash-isms here.
CYGWIN_FLAG=$(if is_cygwin; then echo true; else echo false; fi)
# This can fix cygwin style /cygdrive paths so we get the
# windows style paths.
cygwinpath() {
local file="$1"
if [[ "$CYGWIN_FLAG" == "true" ]]; then #"
echo $(cygpath -w $file)
else
echo $file
fi
}
declare -r sbt_bin_dir="$(dirname "$(realpathish "$0")")"
declare -r sbt_home="$(dirname "$sbt_bin_dir")"
echoerr () {
echo 1>&2 "$@"
}
vlog () {
[[ $sbt_verbose || $sbt_debug ]] && echoerr "$@"
}
dlog () {
[[ $sbt_debug ]] && echoerr "$@"
}
jar_file () {
echo "$(cygwinpath "${sbt_home}/bin/sbt-launch.jar")"
}
acquire_sbt_jar () {
sbt_jar="$(jar_file)"
if [[ ! -f "$sbt_jar" ]]; then
echoerr "Could not find launcher jar: $sbt_jar"
exit 2
fi
}
# execRunner should be called only once to give up control to java
execRunner () {
# print the arguments one to a line, quoting any containing spaces
[[ $sbt_verbose || $sbt_debug ]] && echo "# Executing command line:" && {
for arg; do
if printf "%s\n" "$arg" | grep -q ' '; then
printf "\"%s\"\n" "$arg"
else
printf "%s\n" "$arg"
fi
done
echo ""
}
if [[ "$CYGWIN_FLAG" == "true" ]]; then
# In cygwin we loose the ability to re-hook stty if exec is used
# https://github.com/sbt/sbt-launcher-package/issues/53
"$@"
else
exec "$@"
fi
}
addJava () {
dlog "[addJava] arg = '$1'"
java_args=( "${java_args[@]}" "$1" )
}
addSbt () {
dlog "[addSbt] arg = '$1'"
sbt_commands=( "${sbt_commands[@]}" "$1" )
}
addResidual () {
dlog "[residual] arg = '$1'"
residual_args=( "${residual_args[@]}" "$1" )
}
addDebugger () {
addJava "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$1"
}
addMemory () {
dlog "[addMemory] arg = '$1'"
# evict memory related options
local xs=("${java_args[@]}")
java_args=()
for i in "${xs[@]}"; do
if ! [[ "${i}" == *-Xmx* ]] && ! [[ "${i}" == *-Xms* ]] && ! [[ "${i}" == *-Xss* ]] && ! [[ "${i}" == *-XX:MaxPermSize* ]] && ! [[ "${i}" == *-XX:MaxMetaspaceSize* ]] && ! [[ "${i}" == *-XX:ReservedCodeCacheSize* ]]; then
java_args+=("${i}")
fi
done
local ys=("${sbt_options[@]}")
sbt_options=()
for i in "${ys[@]}"; do
if ! [[ "${i}" == *-Xmx* ]] && ! [[ "${i}" == *-Xms* ]] && ! [[ "${i}" == *-Xss* ]] && ! [[ "${i}" == *-XX:MaxPermSize* ]] && ! [[ "${i}" == *-XX:MaxMetaspaceSize* ]] && ! [[ "${i}" == *-XX:ReservedCodeCacheSize* ]]; then
sbt_options+=("${i}")
fi
done
# a ham-fisted attempt to move some memory settings in concert
local mem=$1
local codecache=$(( $mem / 8 ))
(( $codecache > 128 )) || codecache=128
(( $codecache < 512 )) || codecache=512
local class_metadata_size=$(( $codecache * 2 ))
if [[ -z $java_version ]]; then
java_version=$(jdk_version)
fi
addJava "-Xms${mem}m"
addJava "-Xmx${mem}m"
addJava "-Xss4M"
addJava "-XX:ReservedCodeCacheSize=${codecache}m"
(( $java_version >= 8 )) || addJava "-XX:MaxPermSize=${class_metadata_size}m"
}
addDefaultMemory() {
# if we detect any of these settings in ${JAVA_OPTS} or ${JAVA_TOOL_OPTIONS} we need to NOT output our settings.
# The reason is the Xms/Xmx, if they don't line up, cause errors.
if [[ "${java_args[@]}" == *-Xmx* ]] || \
[[ "${java_args[@]}" == *-Xms* ]] || \
[[ "${java_args[@]}" == *-Xss* ]] || \
[[ "${java_args[@]}" == *-XX:+UseCGroupMemoryLimitForHeap* ]] || \
[[ "${java_args[@]}" == *-XX:MaxRAM* ]] || \
[[ "${java_args[@]}" == *-XX:InitialRAMPercentage* ]] || \
[[ "${java_args[@]}" == *-XX:MaxRAMPercentage* ]] || \
[[ "${java_args[@]}" == *-XX:MinRAMPercentage* ]]; then
:
elif [[ "${JAVA_TOOL_OPTIONS}" == *-Xmx* ]] || \
[[ "${JAVA_TOOL_OPTIONS}" == *-Xms* ]] || \
[[ "${JAVA_TOOL_OPTIONS}" == *-Xss* ]] || \
[[ "${JAVA_TOOL_OPTIONS}" == *-XX:+UseCGroupMemoryLimitForHeap* ]] || \
[[ "${JAVA_TOOL_OPTIONS}" == *-XX:MaxRAM* ]] || \
[[ "${JAVA_TOOL_OPTIONS}" == *-XX:InitialRAMPercentage* ]] || \
[[ "${JAVA_TOOL_OPTIONS}" == *-XX:MaxRAMPercentage* ]] || \
[[ "${JAVA_TOOL_OPTIONS}" == *-XX:MinRAMPercentage* ]] ; then
:
elif [[ "${sbt_options[@]}" == *-Xmx* ]] || \
[[ "${sbt_options[@]}" == *-Xms* ]] || \
[[ "${sbt_options[@]}" == *-Xss* ]] || \
[[ "${sbt_options[@]}" == *-XX:+UseCGroupMemoryLimitForHeap* ]] || \
[[ "${sbt_options[@]}" == *-XX:MaxRAM* ]] || \
[[ "${sbt_options[@]}" == *-XX:InitialRAMPercentage* ]] || \
[[ "${sbt_options[@]}" == *-XX:MaxRAMPercentage* ]] || \
[[ "${sbt_options[@]}" == *-XX:MinRAMPercentage* ]] ; then
:
else
addMemory $sbt_default_mem
fi
}
require_arg () {
local type="$1"
local opt="$2"
local arg="$3"
if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then
echo "$opt requires <$type> argument"
exit 1
fi
}
is_function_defined() {
declare -f "$1" > /dev/null
}
# parses JDK version from the -version output line.
# 8 for 1.8.0_nn, 9 for 9-ea etc, and "no_java" for undetected
jdk_version() {
local result
local lines=$("$java_cmd" -Xms32M -Xmx32M -version 2>&1 | tr '\r' '\n')
local IFS=$'\n'
for line in $lines; do
if [[ (-z $result) && ($line = *"version \""*) ]]
then
local ver=$(echo $line | sed -e 's/.*version "\(.*\)"\(.*\)/\1/; 1q')
# on macOS sed doesn't support '?'
if [[ $ver = "1."* ]]
then
result=$(echo $ver | sed -e 's/1\.\([0-9]*\)\(.*\)/\1/; 1q')
else
result=$(echo $ver | sed -e 's/\([0-9]*\)\(.*\)/\1/; 1q')
fi
fi
done
if [[ -z $result ]]
then
result=no_java
fi
echo "$result"
}
# Extracts the preloaded directory from either -Dsbt.preloaded or -Dsbt.global.base
# properties by looking at:
# - _JAVA_OPTIONS environment variable,
# - SBT_OPTS environment variable,
# - JAVA_OPTS environment variable and
# - properties set by command-line options
# in that order. The last one will be chosen such that `sbt.preloaded` is
# always preferred over `sbt.global.base`.
getPreloaded() {
local -a _java_options_array
local -a sbt_opts_array
local -a java_opts_array
read -a _java_options_array <<< "$_JAVA_OPTIONS"
read -a sbt_opts_array <<< "$SBT_OPTS"
read -a java_opts_array <<< "$JAVA_OPTS"
local args_to_check=(
"${_java_options_array[@]}"
"${sbt_opts_array[@]}"
"${java_opts_array[@]}"
"${java_args[@]}")
local via_global_base="$HOME/.sbt/preloaded"
local via_explicit=""
for opt in "${args_to_check[@]}"; do
if [[ "$opt" == -Dsbt.preloaded=* ]]; then
via_explicit="${opt#-Dsbt.preloaded=}"
elif [[ "$opt" == -Dsbt.global.base=* ]]; then
via_global_base="${opt#-Dsbt.global.base=}/preloaded"
fi
done
echo "${via_explicit:-${via_global_base}}"
}
syncPreloaded() {
local source_preloaded="$sbt_home/lib/local-preloaded/"
local target_preloaded="$(getPreloaded)"
if [[ "$init_sbt_version" == "" ]]; then
# FIXME: better $init_sbt_version detection
init_sbt_version="$(ls -1 "$source_preloaded/org/scala-sbt/sbt/")"
fi
[[ -f "$target_preloaded/org/scala-sbt/sbt/$init_sbt_version/" ]] || {
# lib/local-preloaded exists (This is optional)
[[ -d "$source_preloaded" ]] && {
command -v rsync >/dev/null 2>&1 && {
mkdir -p "$target_preloaded"
rsync --recursive --links --perms --times --ignore-existing "$source_preloaded" "$target_preloaded" || true
}
}
}
}
# Detect that we have java installed.
checkJava() {
local required_version="$1"
# Now check to see if it's a good enough version
local good_enough="$(expr $java_version ">=" $required_version)"
if [[ "$java_version" == "" ]]; then
echo
echo "No Java Development Kit (JDK) installation was detected."
echo Please go to http://www.oracle.com/technetwork/java/javase/downloads/ and download.
echo
exit 1
elif [[ "$good_enough" != "1" ]]; then
echo
echo "The Java Development Kit (JDK) installation you have is not up to date."
echo $script_name requires at least version $required_version+, you have
echo version $java_version
echo
echo Please go to http://www.oracle.com/technetwork/java/javase/downloads/ and download
echo a valid JDK and install before running $script_name.
echo
exit 1
fi
}
copyRt() {
local at_least_9="$(expr $java_version ">=" 9)"
if [[ "$at_least_9" == "1" ]]; then
# The grep for java9-rt-ext- matches the filename prefix printed in Export.java
java9_ext=$("$java_cmd" "${sbt_options[@]}" "${java_args[@]}" \
-jar "$sbt_jar" --rt-ext-dir | grep java9-rt-ext- | tr -d '\r')
java9_rt=$(echo "$java9_ext/rt.jar")
vlog "[copyRt] java9_rt = '$java9_rt'"
if [[ ! -f "$java9_rt" ]]; then
echo copying runtime jar...
mkdir -p "$java9_ext"
"$java_cmd" \
"${sbt_options[@]}" \
"${java_args[@]}" \
-jar "$sbt_jar" \
--export-rt \
"${java9_rt}"
fi
addJava "-Dscala.ext.dirs=${java9_ext}"
fi
}
run() {
# Copy preloaded repo to user's preloaded directory
syncPreloaded
# no jar? download it.
[[ -f "$sbt_jar" ]] || acquire_sbt_jar "$sbt_version" || {
# still no jar? uh-oh.
echo "Download failed. Obtain the sbt-launch.jar manually and place it at $sbt_jar"
exit 1
}
# TODO - java check should be configurable...
checkJava "6"
# Java 9 support
copyRt
# If we're in cygwin, we should use the windows config, and terminal hacks
if [[ "$CYGWIN_FLAG" == "true" ]]; then #"
stty -icanon min 1 -echo > /dev/null 2>&1
addJava "-Djline.terminal=jline.UnixTerminal"
addJava "-Dsbt.cygwin=true"
fi
if [[ $print_sbt_version ]]; then
execRunner "$java_cmd" -jar "$sbt_jar" "sbtVersion" | tail -1 | sed -e 's/\[info\]//g'
elif [[ $print_sbt_script_version ]]; then
echo "$init_sbt_version"
elif [[ $print_version ]]; then
execRunner "$java_cmd" -jar "$sbt_jar" "sbtVersion" | tail -1 | sed -e 's/\[info\]/sbt version in this project:/g'
echo "sbt script version: $init_sbt_version"
else
# run sbt
execRunner "$java_cmd" \
"${java_args[@]}" \
"${sbt_options[@]}" \
-jar "$sbt_jar" \
"${sbt_commands[@]}" \
"${residual_args[@]}"
fi
exit_code=$?
# Clean up the terminal from cygwin hacks.
if [[ "$CYGWIN_FLAG" == "true" ]]; then #"
stty icanon echo > /dev/null 2>&1
fi
exit $exit_code
}
declare -ra noshare_opts=(-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy)
declare -r sbt_opts_file=".sbtopts"
declare -r build_props_file="$(pwd)/project/build.properties"
declare -r etc_sbt_opts_file="/etc/sbt/sbtopts"
# this allows /etc/sbt/sbtopts location to be changed
declare -r etc_file="${SBT_ETC_FILE:-$etc_sbt_opts_file}"
declare -r dist_sbt_opts_file="${sbt_home}/conf/sbtopts"
declare -r win_sbt_opts_file="${sbt_home}/conf/sbtconfig.txt"
usage() {
cat <<EOM
Usage: `basename "$0"` [options]
-h | --help print this message
-v | --verbose this runner is chattier
-V | --version print sbt version information
--numeric-version print the numeric sbt version (sbt sbtVersion)
--script-version print the version of sbt script
-d | --debug set sbt log level to debug
-debug-inc | --debug-inc
enable extra debugging for the incremental debugger
--no-colors disable ANSI color codes
--color=auto|always|true|false|never
enable or disable ANSI color codes (sbt 1.3 and above)
--supershell=auto|always|true|false|never
enable or disable supershell (sbt 1.3 and above)
--traces generate Trace Event report on shutdown (sbt 1.3 and above)
--timings display task timings report on shutdown
--sbt-create start sbt even if current directory contains no sbt project
--sbt-dir <path> path to global settings/plugins directory (default: ~/.sbt)
--sbt-boot <path> path to shared boot directory (default: ~/.sbt/boot in 0.11 series)
--ivy <path> path to local Ivy repository (default: ~/.ivy2)
--mem <integer> set memory options (default: $sbt_default_mem)
--no-share use all local caches; no sharing
--no-global uses global caches, but does not use global ~/.sbt directory.
--jvm-debug <port> Turn on JVM debugging, open at the given port.
--batch disable interactive mode
# sbt version (default: from project/build.properties if present, else latest release)
--sbt-version <version> use the specified version of sbt
--sbt-jar <path> use the specified jar as the sbt launcher
# java version (default: java from PATH, currently $(java -version 2>&1 | grep version))
--java-home <path> alternate JAVA_HOME
# jvm options and output control
JAVA_OPTS environment variable, if unset uses "$default_java_opts"
.jvmopts if this file exists in the current directory, its contents
are appended to JAVA_OPTS
SBT_OPTS environment variable, if unset uses "$default_sbt_opts"
.sbtopts if this file exists in the current directory, its contents
are prepended to the runner args
/etc/sbt/sbtopts if this file exists, it is prepended to the runner args
-Dkey=val pass -Dkey=val directly to the java runtime
-J-X pass option -X directly to the java runtime
(-J is stripped)
-S-X add -X to sbt's scalacOptions (-S is stripped)
In the case of duplicated or conflicting options, the order above
shows precedence: JAVA_OPTS lowest, command line options highest.
EOM
}
process_my_args () {
while [[ $# -gt 0 ]]; do
case "$1" in
-batch|--batch) exec </dev/null && shift ;; #>
-sbt-create|--sbt-create) sbt_create=true && shift ;;
new) sbt_new=true && addResidual "$1" && shift ;;
*) addResidual "$1" && shift ;;
esac
done
# Now, ensure sbt version is used.
[[ "${sbt_version}XXX" != "XXX" ]] && addJava "-Dsbt.version=$sbt_version"
# Confirm a user's intent if the current directory does not look like an sbt
# top-level directory and neither the -sbt-create option nor the "new"
# command was given.
[[ -f ./build.sbt || -d ./project || -n "$sbt_create" || -n "$sbt_new" ]] || {
echo "[warn] Neither build.sbt nor a 'project' directory in the current directory: $(pwd)"
while true; do
echo 'c) continue'
echo 'q) quit'
read -p '? ' || exit 1
case "$REPLY" in
c|C) break ;;
q|Q) exit 1 ;;
esac
done
}
}
## map over argument array. this is used to process both command line arguments and SBT_OPTS
map_args () {
local options=()
local commands=()
while [[ $# -gt 0 ]]; do
case "$1" in
-no-colors|--no-colors) options=( "${options[@]}" "-Dsbt.log.noformat=true" ) && shift ;;
-timings|--timings) options=( "${options[@]}" "-Dsbt.task.timings=true" "-Dsbt.task.timings.on.shutdown=true" ) && shift ;;
-traces|--traces) options=( "${options[@]}" "-Dsbt.traces=true" ) && shift ;;
--supershell=*) options=( "${options[@]}" "-Dsbt.supershell=${1:13}" ) && shift ;;
-supershell=*) options=( "${options[@]}" "-Dsbt.supershell=${1:12}" ) && shift ;;
--color=*) options=( "${options[@]}" "-Dsbt.color=${1:8}" ) && shift ;;
-color=*) options=( "${options[@]}" "-Dsbt.color=${1:7}" ) && shift ;;
-no-share|--no-share) options=( "${options[@]}" "${noshare_opts[@]}" ) && shift ;;
-no-global|--no-global) options=( "${options[@]}" "-Dsbt.global.base=$(pwd)/project/.sbtboot" ) && shift ;;
-ivy|--ivy) require_arg path "$1" "$2" && options=( "${options[@]}" "-Dsbt.ivy.home=$2" ) && shift 2 ;;
-sbt-boot|--sbt-boot) require_arg path "$1" "$2" && options=( "${options[@]}" "-Dsbt.boot.directory=$2" ) && shift 2 ;;
-sbt-dir|--sbt-dir) require_arg path "$1" "$2" && options=( "${options[@]}" "-Dsbt.global.base=$2" ) && shift 2 ;;
-debug|--debug) commands=( "${commands[@]}" "-debug" ) && shift ;;
-debug-inc|--debug-inc) options=( "${options[@]}" "-Dxsbt.inc.debug=true" ) && shift ;;
*) options=( "${options[@]}" "$1" ) && shift ;;
esac
done
declare -p options
declare -p commands
}
process_args () {
while [[ $# -gt 0 ]]; do
case "$1" in
-h|-help|--help) usage; exit 1 ;;
-v|-verbose|--verbose) sbt_verbose=1 && shift ;;
-V|-version|--version) print_version=1 && shift ;;
--numeric-version) print_sbt_version=1 && shift ;;
--script-version) print_sbt_script_version=1 && shift ;;
-d|-debug|--debug) sbt_debug=1 && addSbt "-debug" && shift ;;
--client) use_sbtn=1 && shift ;;
--server) use_sbtn=0 && shift ;;
-mem|--mem) require_arg integer "$1" "$2" && addMemory "$2" && shift 2 ;;
-jvm-debug|--jvm-debug) require_arg port "$1" "$2" && addDebugger $2 && shift 2 ;;
-batch|--batch) exec </dev/null && shift ;;
-sbt-jar|--sbt-jar) require_arg path "$1" "$2" && sbt_jar="$2" && shift 2 ;;
-sbt-version|--sbt-version) require_arg version "$1" "$2" && sbt_version="$2" && shift 2 ;;
-java-home|--java-home) require_arg path "$1" "$2" &&
java_cmd="$2/bin/java" &&
export JAVA_HOME="$2" &&
export JDK_HOME="$2" &&
export PATH="$2/bin:$PATH" &&
shift 2 ;;
"-D*"|-D*) addJava "$1" && shift ;;
-J*) addJava "${1:2}" && shift ;;
*) addResidual "$1" && shift ;;
esac
done
is_function_defined process_my_args && {
myargs=("${residual_args[@]}")
residual_args=()
process_my_args "${myargs[@]}"
}
}
loadConfigFile() {
# Make sure the last line is read even if it doesn't have a terminating \n
cat "$1" | sed $'/^\#/d;s/\r$//' | while read -r line || [[ -n "$line" ]]; do
eval echo $line
done
}
loadPropFile() {
while IFS='=' read -r k v; do
if [[ "$k" == "sbt.version" ]]; then
build_props_sbt_version="$v"
fi
done <<< "$(cat "$1" | sed $'/^\#/d;s/\r$//')"
}
detectNativeClient() {
if [[ "$sbtn_command" != "" ]]; then
:
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
[[ -f "${sbt_bin_dir}/sbtn-x86_64-pc-linux" ]] && sbtn_command="${sbt_bin_dir}/sbtn-x86_64-pc-linux"
elif [[ "$OSTYPE" == "darwin"* ]]; then
[[ -f "${sbt_bin_dir}/sbtn-x86_64-apple-darwin" ]] && sbtn_command="${sbt_bin_dir}/sbtn-x86_64-apple-darwin"
elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
[[ -f "${sbt_bin_dir}/sbtn-x86_64-pc-win32.exe" ]] && sbtn_command="${sbt_bin_dir}/sbtn-x86_64-pc-win32.exe"
elif [[ "$OSTYPE" == "freebsd"* ]]; then
:
else
:
fi
}
# Run native client if build.properties points to 1.4+ and has SBT_NATIVE_CLIENT
isRunNativeClient() {
sbtV="$build_props_sbt_version"
[[ "$sbtV" == "" ]] && sbtV="$init_sbt_version"
[[ "$sbtV" == "" ]] && sbtV="0.0.0"
sbtBinaryV_1=$(echo "$sbtV" | sed 's/^\([0-9]*\)\.\([0-9]*\).*$/\1/')
sbtBinaryV_2=$(echo "$sbtV" | sed 's/^\([0-9]*\)\.\([0-9]*\).*$/\2/')
if (( $sbtBinaryV_1 >= 2 )) || ( (( $sbtBinaryV_1 >= 1 )) && (( $sbtBinaryV_2 >= 4 )) ); then
if [[ "$use_sbtn" == "1" ]] && [[ "$sbtn_command" != "" ]]; then
echo "true"
else
echo "false"
fi
else
echo "false"
fi
}
runNativeClient() {
vlog "[debug] running native client"
for i in "${!original_args[@]}"; do
if [[ "${original_args[i]}" = "--client" ]]; then
unset 'original_args[i]'
fi
done
sbt_script=$0
sbt_script=${sbt_script/ /%20}
execRunner "$sbtn_command" "--sbt-script=$sbt_script" "${original_args[@]}"
}
original_args=("$@")
# Here we pull in the default settings configuration.
[[ -f "$dist_sbt_opts_file" ]] && set -- $(loadConfigFile "$dist_sbt_opts_file") "$@"
# Here we pull in the global settings configuration.
[[ -f "$etc_file" ]] && set -- $(loadConfigFile "$etc_file") "$@"
# Pull in the project-level config file, if it exists.
[[ -f "$sbt_opts_file" ]] && set -- $(loadConfigFile "$sbt_opts_file") "$@"
# Pull in the project-level java config, if it exists.
[[ -f ".jvmopts" ]] && export JAVA_OPTS="$JAVA_OPTS $(loadConfigFile .jvmopts)"
# Pull in default JAVA_OPTS
[[ -z "${JAVA_OPTS// }" ]] && export JAVA_OPTS="$default_java_opts"
[[ -f "$build_props_file" ]] && loadPropFile "$build_props_file"
detectNativeClient
java_args=($JAVA_OPTS)
sbt_options0=(${SBT_OPTS:-$default_sbt_opts})
if [[ "$SBT_NATIVE_CLIENT" == "true" ]]; then
use_sbtn=1
fi
# Split SBT_OPTS into options/commands
miniscript=$(map_args "${sbt_options0[@]}") && eval "${miniscript/options/sbt_options}" && \
eval "${miniscript/commands/sbt_additional_commands}"
# Combine command line options/commands and commands from SBT_OPTS
miniscript=$(map_args "$@") && eval "${miniscript/options/cli_options}" && eval "${miniscript/commands/cli_commands}"
args1=( "${cli_options[@]}" "${cli_commands[@]}" "${sbt_additional_commands[@]}" )
# process the combined args, then reset "$@" to the residuals
process_args "${args1[@]}"
vlog "[sbt_options] $(declare -p sbt_options)"
if [[ "$(isRunNativeClient)" == "true" ]]; then
set -- "${residual_args[@]}"
argumentCount=$#
runNativeClient
else
java_version="$(jdk_version)"
vlog "[process_args] java_version = '$java_version'"
addDefaultMemory
set -- "${residual_args[@]}"
argumentCount=$#
run
fi

View File

@ -0,0 +1,981 @@
@REM SBT launcher script
@REM
@REM Environment:
@REM JAVA_HOME - location of a JDK home dir (mandatory)
@REM SBT_OPTS - JVM options (optional)
@REM Configuration:
@REM sbtconfig.txt found in the SBT_HOME.
@REM ZOMG! We need delayed expansion to build up CFG_OPTS later
@setlocal enabledelayedexpansion
@echo off
set SBT_BIN_DIR=%~dp0
if not defined SBT_HOME for %%I in ("!SBT_BIN_DIR!\..") do set "SBT_HOME=%%~fI"
set SBT_ARGS=
set _JAVACMD=
set _SBT_OPTS=
set _JAVA_OPTS=
set init_sbt_version=_to_be_replaced
set sbt_default_mem=1024
set default_sbt_opts=
set default_java_opts=-Dfile.encoding=UTF-8
set sbt_jar=
set build_props_sbt_version=
set run_native_client=
set sbt_args_print_version=
set sbt_args_print_sbt_version=
set sbt_args_print_sbt_script_version=
set sbt_args_verbose=
set sbt_args_debug=
set sbt_args_debug_inc=
set sbt_args_batch=
set sbt_args_color=
set sbt_args_no_colors=
set sbt_args_no_global=
set sbt_args_no_share=
set sbt_args_sbt_jar=
set sbt_args_ivy=
set sbt_args_supershell=
set sbt_args_timings=
set sbt_args_traces=
set sbt_args_sbt_create=
set sbt_args_sbt_dir=
set sbt_args_sbt_version=
set sbt_args_mem=
set sbt_args_client=
rem users can set SBT_OPTS via .sbtopts
if exist .sbtopts for /F %%A in (.sbtopts) do (
set _sbtopts_line=%%A
if not "!_sbtopts_line:~0,1!" == "#" (
if "!_sbtopts_line:~0,2!" == "-J" (
set _sbtopts_line=!_sbtopts_line:~2,1000!
)
if defined _SBT_OPTS (
set _SBT_OPTS=!_SBT_OPTS! !_sbtopts_line!
) else (
set _SBT_OPTS=!_sbtopts_line!
)
)
)
rem TODO: remove/deprecate sbtconfig.txt and parse the sbtopts files
rem FIRST we load the config file of extra options.
set SBT_CONFIG=!SBT_HOME!\conf\sbtconfig.txt
set SBT_CFG_OPTS=
for /F "tokens=* eol=# usebackq delims=" %%i in ("!SBT_CONFIG!") do (
set DO_NOT_REUSE_ME=%%i
rem ZOMG (Part #2) WE use !! here to delay the expansion of
rem SBT_CFG_OPTS, otherwise it remains "" for this loop.
set SBT_CFG_OPTS=!SBT_CFG_OPTS! !DO_NOT_REUSE_ME!
)
rem poor man's jenv (which is not available on Windows)
if defined JAVA_HOMES (
if exist .java-version for /F %%A in (.java-version) do (
set JAVA_HOME=%JAVA_HOMES%\%%A
set JDK_HOME=%JAVA_HOMES%\%%A
)
)
if exist "project\build.properties" (
for /F "eol=# delims== tokens=1*" %%a in (project\build.properties) do (
if "%%a" == "sbt.version" if not "%%b" == "" (
set build_props_sbt_version=%%b
)
)
)
rem must set PATH or wrong javac is used for java projects
if defined JAVA_HOME set "PATH=%JAVA_HOME%\bin;%PATH%"
rem We use the value of the JAVACMD environment variable if defined
if defined JAVACMD set "_JAVACMD=%JAVACMD%"
rem remove quotes
if defined _JAVACMD set _JAVACMD=!_JAVACMD:"=!
if not defined _JAVACMD (
if not "%JAVA_HOME%" == "" (
if exist "%JAVA_HOME%\bin\java.exe" set "_JAVACMD=%JAVA_HOME%\bin\java.exe"
)
)
if not defined _JAVACMD set _JAVACMD=java
rem users can set JAVA_OPTS via .jvmopts (sbt-extras style)
if exist .jvmopts for /F %%A in (.jvmopts) do (
set _jvmopts_line=%%A
if not "!_jvmopts_line:~0,1!" == "#" (
if defined _JAVA_OPTS (
set _JAVA_OPTS=!_JAVA_OPTS! %%A
) else (
set _JAVA_OPTS=%%A
)
)
)
rem We use the value of the JAVA_OPTS environment variable if defined, rather than the config.
if not defined _JAVA_OPTS if defined JAVA_OPTS set _JAVA_OPTS=%JAVA_OPTS%
if not defined _JAVA_OPTS if defined default_java_opts set _JAVA_OPTS=!default_java_opts!
rem We use the value of the SBT_OPTS environment variable if defined, rather than the config.
if not defined _SBT_OPTS if defined SBT_OPTS set _SBT_OPTS=%SBT_OPTS%
if not defined _SBT_OPTS if defined SBT_CFG_OPTS set _SBT_OPTS=!SBT_CFG_OPTS!
if not defined _SBT_OPTS if defined default_sbt_opts set _SBT_OPTS=!default_sbt_opts!
if defined SBT_NATIVE_CLIENT (
if "%SBT_NATIVE_CLIENT%" == "true" (
set sbt_args_client=1
)
)
:args_loop
shift
if "%~0" == "" goto args_end
set g=%~0
rem make sure the sbt_args_debug gets set first incase any argument parsing uses :dlog
if "%~0" == "-d" set _debug_arg=true
if "%~0" == "--debug" set _debug_arg=true
if defined _debug_arg (
set _debug_arg=
set sbt_args_debug=1
set SBT_ARGS=-debug !SBT_ARGS!
goto args_loop
)
if "%~0" == "-h" goto usage
if "%~0" == "-help" goto usage
if "%~0" == "--help" goto usage
if "%~0" == "-v" set _verbose_arg=true
if "%~0" == "-verbose" set _verbose_arg=true
if "%~0" == "--verbose" set _verbose_arg=true
if defined _verbose_arg (
set _verbose_arg=
set sbt_args_verbose=1
goto args_loop
)
if "%~0" == "-V" set _version_arg=true
if "%~0" == "-version" set _version_arg=true
if "%~0" == "--version" set _version_arg=true
if defined _version_arg (
set _version_arg=
set sbt_args_print_version=1
goto args_loop
)
if "%~0" == "--client" set _client_arg=true
if defined _client_arg (
set _client_arg=
set sbt_args_client=1
goto args_loop
)
if "%~0" == "-batch" set _batch_arg=true
if "%~0" == "--batch" set _batch_arg=true
if defined _batch_arg (
set _batch_arg=
set sbt_args_batch=1
goto args_loop
)
if "%~0" == "-no-colors" set _no_colors_arg=true
if "%~0" == "--no-colors" set _no_colors_arg=true
if defined _no_colors_arg (
set _no_colors_arg=
set sbt_args_no_colors=1
goto args_loop
)
if "%~0" == "-no-global" set _no_global_arg=true
if "%~0" == "--no-global" set _no_global_arg=true
if defined _no_global_arg (
set _no_global_arg=
set sbt_args_no_global=1
goto args_loop
)
if "%~0" == "-traces" set _traces_arg=true
if "%~0" == "--traces" set _traces_arg=true
if defined _traces_arg (
set _traces_arg=
set sbt_args_traces=1
goto args_loop
)
if "%~0" == "-sbt-create" set _sbt_create_arg=true
if "%~0" == "--sbt-create" set _sbt_create_arg=true
if defined _sbt_create_arg (
set _sbt_create_arg=
set sbt_args_sbt_create=1
goto args_loop
)
if "%~0" == "-sbt-dir" set _sbt_dir_arg=true
if "%~0" == "--sbt-dir" set _sbt_dir_arg=true
if defined _sbt_dir_arg (
set _sbt_dir_arg=
if not "%~1" == "" (
set sbt_args_sbt_dir=%1
shift
goto args_loop
) else (
echo "%~0" is missing a value
goto error
)
)
if "%~0" == "-sbt-boot" set _sbt_boot_arg=true
if "%~0" == "--sbt-boot" set _sbt_boot_arg=true
if defined _sbt_boot_arg (
set _sbt_boot_arg=
if not "%~1" == "" (
set sbt_args_sbt_boot=%1
shift
goto args_loop
) else (
echo "%~0" is missing a value
goto error
)
)
if "%~0" == "-sbt-jar" set _sbt_jar=true
if "%~0" == "--sbt-jar" set _sbt_jar=true
if defined _sbt_jar (
set _sbt_jar=
if not "%~1" == "" (
if exist "%~1" (
set sbt_args_sbt_jar=%1
shift
goto args_loop
) else (
echo %~1 does not exist
goto error
)
) else (
echo "%~0" is missing a value
goto error
)
)
if "%~0" == "-ivy" set _sbt_ivy_arg=true
if "%~0" == "--ivy" set _sbt_ivy_arg=true
if defined _sbt_ivy_arg (
set _sbt_ivy_arg=
if not "%~1" == "" (
set sbt_args_ivy=%1
shift
goto args_loop
) else (
echo "%~0" is missing a value
goto error
)
)
if "%~0" == "-debug-inc" set _debug_inc_arg=true
if "%~0" == "--debug-inc" set _debug_inc_arg=true
if defined _debug_inc_arg (
set _debug_inc_arg=
set sbt_args_debug_inc=1
goto args_loop
)
if "%~0" == "--sbt-version" set _sbt_version_arg=true
if "%~0" == "-sbt-version" set _sbt_version_arg=true
if defined _sbt_version_arg (
set _sbt_version_arg=
if not "%~1" == "" (
set sbt_args_sbt_version=%~1
shift
goto args_loop
) else (
echo "%~0" is missing a value
goto error
)
)
if "%~0" == "--mem" set _sbt_mem_arg=true
if "%~0" == "-mem" set _sbt_mem_arg=true
if defined _sbt_mem_arg (
set _sbt_mem_arg=
if not "%~1" == "" (
set sbt_args_mem=%~1
shift
goto args_loop
) else (
echo "%~0" is missing a value
goto error
)
)
if "%~0" == "--supershell" set _supershell_arg=true
if "%~0" == "-supershell" set _supershell_arg=true
if defined _supershell_arg (
set _supershell_arg=
if not "%~1" == "" (
set sbt_args_supershell=%~1
shift
goto args_loop
) else (
echo "%~0" is missing a value
goto error
)
)
if "%~0" == "--color" set _color_arg=true
if "%~0" == "-color" set _color_arg=true
if defined _color_arg (
set _color_arg=
if not "%~1" == "" (
set sbt_args_color=%~1
shift
goto args_loop
) else (
echo "%~0" is missing a value
goto error
)
goto args_loop
)
if "%~0" == "--no-share" set _no_share_arg=true
if "%~0" == "-no-share" set _no_share_arg=true
if defined _no_share_arg (
set _no_share_arg=
set sbt_args_no_share=1
goto args_loop
)
if "%~0" == "--timings" set _timings_arg=true
if "%~0" == "-timings" set _timings_arg=true
if defined _timings_arg (
set _timings_arg=
set sbt_args_timings=1
goto args_loop
)
if "%~0" == "--script-version" (
set sbt_args_print_sbt_script_version=1
goto args_loop
)
if "%~0" == "--numeric-version" (
set sbt_args_print_sbt_version=1
goto args_loop
)
if "%~0" == "-jvm-debug" set _jvm_debug_arg=true
if "%~0" == "--jvm-debug" set _jvm_debug_arg=true
if defined _jvm_debug_arg (
set _jvm_debug_arg=
if not "%~1" == "" (
set /a JVM_DEBUG_PORT=%~1 2>nul >nul
if !JVM_DEBUG_PORT! EQU 0 (
rem next argument wasn't a port, set a default and process next arg
set /A JVM_DEBUG_PORT=5005
goto args_loop
) else (
shift
goto args_loop
)
)
)
if "%~0" == "-java-home" set _java_home_arg=true
if "%~0" == "--java-home" set _java_home_arg=true
if defined _java_home_arg (
set _java_home_arg=
if not "%~1" == "" (
if exist "%~1\bin\java.exe" (
set "_JAVACMD=%~1\bin\java.exe"
set "JAVA_HOME=%~1"
set "JDK_HOME=%~1"
shift
goto args_loop
) else (
echo Directory "%~1" for JAVA_HOME is not valid
goto error
)
) else (
echo Second argument for --java-home missing
goto error
)
)
if "%~0" == "new" (
if not defined SBT_ARGS (
set sbt_new=true
)
)
if "%g:~0,2%" == "-D" (
rem special handling for -D since '=' gets parsed away
for /F "tokens=1 delims==" %%a in ("%g%") do (
rem make sure it doesn't have the '=' already
if "%g%" == "%%a" (
if not "%~1" == "" (
call :dlog [args_loop] -D argument %~0=%~1
set "SBT_ARGS=!SBT_ARGS! %~0=%~1"
shift
goto args_loop
) else (
echo %g% is missing a value
goto error
)
) else (
call :dlog [args_loop] -D argument %~0
set "SBT_ARGS=!SBT_ARGS! %~0"
goto args_loop
)
)
)
if not "%g:~0,5%" == "-XX:+" if not "%g:~0,5%" == "-XX:-" if "%g:~0,3%" == "-XX" (
rem special handling for -XX since '=' gets parsed away
for /F "tokens=1 delims==" %%a in ("%g%") do (
rem make sure it doesn't have the '=' already
if "%g%" == "%%a" (
if not "%~1" == "" (
call :dlog [args_loop] -XX argument %~0=%~1
set "SBT_ARGS=!SBT_ARGS! %~0=%~1"
shift
goto args_loop
) else (
echo %g% is missing a value
goto error
)
) else (
call :dlog [args_loop] -XX argument %~0
set "SBT_ARGS=!SBT_ARGS! %~0"
goto args_loop
)
)
)
rem the %0 (instead of %~0) preserves original argument quoting
set SBT_ARGS=!SBT_ARGS! %0
goto args_loop
:args_end
rem Confirm a user's intent if the current directory does not look like an sbt
rem top-level directory and the "new" command was not given.
if not defined sbt_args_sbt_create if not defined sbt_args_print_version if not defined sbt_args_print_sbt_version if not defined sbt_args_print_sbt_script_version if not exist build.sbt (
if not exist project\ (
if not defined sbt_new (
echo [warn] Neither build.sbt nor a 'project' directory in the current directory: "%CD%"
setlocal
:confirm
echo c^) continue
echo q^) quit
set /P reply=^?
if /I "!reply!" == "c" (
goto confirm_end
) else if /I "!reply!" == "q" (
exit /B 1
)
goto confirm
:confirm_end
endlocal
)
)
)
call :process
rem avoid bootstrapping/java version check for script version
if !sbt_args_print_sbt_script_version! equ 1 (
echo !init_sbt_version!
goto :eof
)
if !run_native_client! equ 1 (
goto :runnative !SBT_ARGS!
goto :eof
)
call :checkjava
if defined sbt_args_sbt_jar (
set "sbt_jar=!sbt_args_sbt_jar!"
) else (
set "sbt_jar=!SBT_HOME!\bin\sbt-launch.jar"
)
set sbt_jar=!sbt_jar:"=!
call :copyrt
if defined JVM_DEBUG_PORT (
set _JAVA_OPTS=!_JAVA_OPTS! -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=!JVM_DEBUG_PORT!
)
call :sync_preloaded
call :run !SBT_ARGS!
if ERRORLEVEL 1 goto error
goto end
:run
rem set arguments
if defined sbt_args_debug_inc (
set _SBT_OPTS=-Dxsbt.inc.debug=true !_SBT_OPTS!
)
if defined sbt_args_no_colors (
set _SBT_OPTS=-Dsbt.log.noformat=true !_SBT_OPTS!
)
if defined sbt_args_no_global (
set _SBT_OPTS=-Dsbt.global.base=project/.sbtboot !_SBT_OPTS!
)
if defined sbt_args_no_share (
set _SBT_OPTS=-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy !_SBT_OPTS!
)
if defined sbt_args_supershell (
set _SBT_OPTS=-Dsbt.supershell=!sbt_args_supershell! !_SBT_OPTS!
)
if defined sbt_args_sbt_version (
set _SBT_OPTS=-Dsbt.version=!sbt_args_sbt_version! !_SBT_OPTS!
)
if defined sbt_args_sbt_dir (
set _SBT_OPTS=-Dsbt.global.base=!sbt_args_sbt_dir! !_SBT_OPTS!
)
if defined sbt_args_sbt_boot (
set _SBT_OPTS=-Dsbt.boot.directory=!sbt_args_sbt_boot! !_SBT_OPTS!
)
if defined sbt_args_ivy (
set _SBT_OPTS=-Dsbt.ivy.home=!sbt_args_ivy! !_SBT_OPTS!
)
if defined sbt_args_color (
set _SBT_OPTS=-Dsbt.color=!sbt_args_color! !_SBT_OPTS!
)
if defined sbt_args_mem (
call :addMemory !sbt_args_mem!
) else (
call :addDefaultMemory
)
if defined sbt_args_timings (
set _SBT_OPTS=-Dsbt.task.timings=true -Dsbt.task.timings.on.shutdown=true !_SBT_OPTS!
)
if defined sbt_args_traces (
set _SBT_OPTS=-Dsbt.traces=true !_SBT_OPTS!
)
rem TODO: _SBT_OPTS needs to be processed as args and diffed against SBT_ARGS
if !sbt_args_print_sbt_version! equ 1 (
call :set_sbt_version
echo !sbt_version!
goto :eof
)
if !sbt_args_print_version! equ 1 (
call :set_sbt_version
echo sbt version in this project: !sbt_version!
echo sbt script version: !init_sbt_version!
goto :eof
)
if defined sbt_args_verbose (
echo # Executing command line:
echo "!_JAVACMD!"
if defined _JAVA_OPTS ( call :echolist !_JAVA_OPTS! )
if defined _SBT_OPTS ( call :echolist !_SBT_OPTS! )
echo -cp
echo "!sbt_jar!"
echo xsbt.boot.Boot
if not "%~1" == "" ( call :echolist %* )
echo.
)
"!_JAVACMD!" !_JAVA_OPTS! !_SBT_OPTS! -cp "!sbt_jar!" xsbt.boot.Boot %*
goto :eof
:runnative
set "_SBTNCMD=!SBT_BIN_DIR!sbtn-x86_64-pc-win32.exe"
if defined sbt_args_verbose (
echo # running native client
if not "%~1" == "" ( call :echolist %* )
set "SBT_ARGS=-v !SBT_ARGS!"
)
set "SBT_SCRIPT=!SBT_BIN_DIR: =%%20!sbt.bat"
set "SBT_ARGS=--sbt-script=!SBT_SCRIPT! %SBT_ARGS%"
rem Microsoft Visual C++ 2010 SP1 Redistributable Package (x64) is required
rem https://www.microsoft.com/en-us/download/details.aspx?id=13523
"!_SBTNCMD!" %SBT_ARGS%
goto :eof
rem for expression tries to interpret files, so simply loop over %* instead
rem fixes dealing with quotes after = args: -Dscala.ext.dirs="C:\Users\First Last\.sbt\0.13\java9-rt-ext-adoptopenjdk_11_0_3"
:echolist
rem call method is in first call of %0
shift
if "%~0" == "" goto echolist_end
set "p=%~0"
if "%p:~0,2%" == "-D" (
rem special handling for -D since '=' gets parsed away
for /F "tokens=1 delims==" %%a in ("%p%") do (
rem make sure it doesn't have the '=' already
if "%p%" == "%%a" if not "%~1" == "" (
echo %0=%1
shift
goto echolist
)
)
)
if not "%p:~0,5%" == "-XX:+" if not "%p:~0,5%" == "-XX:-" if "%p:~0,3%" == "-XX" (
rem special handling for -XX since '=' gets parsed away
for /F "tokens=1 delims==" %%a in ("%p%") do (
rem make sure it doesn't have the '=' already
if "%p%" == "%%a" if not "%~1" == "" (
echo %0=%1
shift
goto echolist
)
)
)
if "%p:~0,14%" == "-agentlib:jdwp" (
rem special handling for --jvm-debug since '=' and ',' gets parsed away
for /F "tokens=1 delims==" %%a in ("%p%") do (
rem make sure it doesn't have the '=' already
if "%p%" == "%%a" if not "%~1" == "" if not "%~2" == "" if not "%~3" == "" if not "%~4" == "" if not "%~5" == "" if not "%~6" == "" if not "%~7" == "" if not "%~8" == "" (
echo %0=%1=%2,%3=%4,%5=%6,%7=%8
shift & shift & shift & shift & shift & shift & shift & shift
goto echolist
)
)
)
echo %0
goto echolist
:echolist_end
exit /B 0
:addJava
call :dlog [addJava] arg = '%*'
set "_JAVA_OPTS=!_JAVA_OPTS! %*"
exit /B 0
:addMemory
call :dlog [addMemory] arg = '%*'
rem evict memory related options
set _new_java_opts=
set _old_java_opts=!_JAVA_OPTS!
:next_java_opt
if "!_old_java_opts!" == "" goto :done_java_opt
for /F "tokens=1,*" %%g in ("!_old_java_opts!") do (
set "p=%%g"
if not "!p:~0,4!" == "-Xmx" if not "!p:~0,4!" == "-Xms" if not "!p:~0,4!" == "-Xss" if not "!p:~0,15!" == "-XX:MaxPermSize" if not "!p:~0,20!" == "-XX:MaxMetaspaceSize" if not "!p:~0,25!" == "-XX:ReservedCodeCacheSize" (
set _new_java_opts=!_new_java_opts! %%g
)
set "_old_java_opts=%%h"
)
goto :next_java_opt
:done_java_opt
set _JAVA_OPTS=!_new_java_opts!
set _new_sbt_opts=
set _old_sbt_opts=!_SBT_OPTS!
:next_sbt_opt
if "!_old_sbt_opts!" == "" goto :done_sbt_opt
for /F "tokens=1,*" %%g in ("!_old_sbt_opts!") do (
set "p=%%g"
if not "!p:~0,4!" == "-Xmx" if not "!p:~0,4!" == "-Xms" if not "!p:~0,4!" == "-Xss" if not "!p:~0,15!" == "-XX:MaxPermSize" if not "!p:~0,20!" == "-XX:MaxMetaspaceSize" if not "!p:~0,25!" == "-XX:ReservedCodeCacheSize" (
set _new_sbt_opts=!_new_sbt_opts! %%g
)
set "_old_sbt_opts=%%h"
)
goto :next_sbt_opt
:done_sbt_opt
set _SBT_OPTS=!_new_sbt_opts!
rem a ham-fisted attempt to move some memory settings in concert
set mem=%1
set /a codecache=!mem! / 8
if !codecache! GEQ 512 set /a codecache=512
if !codecache! LEQ 128 set /a codecache=128
set /a class_metadata_size=!codecache! * 2
call :addJava -Xms!mem!m
call :addJava -Xmx!mem!m
call :addJava -Xss4M
call :addJava -XX:ReservedCodeCacheSize=!codecache!m
if /I !JAVA_VERSION! LSS 8 (
call :addJava -XX:MaxPermSize=!class_metadata_size!m
)
exit /B 0
:addDefaultMemory
rem if we detect any of these settings in ${JAVA_OPTS} or ${JAVA_TOOL_OPTIONS} we need to NOT output our settings.
rem The reason is the Xms/Xmx, if they don't line up, cause errors.
set _has_memory_args=
if defined _JAVA_OPTS for /F %%g in ("!_JAVA_OPTS!") do (
set "p=%%g"
if "!p:~0,4!" == "-Xmx" set _has_memory_args=1
if "!p:~0,4!" == "-Xms" set _has_memory_args=1
if "!p:~0,4!" == "-Xss" set _has_memory_args=1
)
if defined JAVA_TOOL_OPTIONS for /F %%g in ("%JAVA_TOOL_OPTIONS%") do (
set "p=%%g"
if "!p:~0,4!" == "-Xmx" set _has_memory_args=1
if "!p:~0,4!" == "-Xms" set _has_memory_args=1
if "!p:~0,4!" == "-Xss" set _has_memory_args=1
)
if defined _SBT_OPTS for /F %%g in ("!_SBT_OPTS!") do (
set "p=%%g"
if "!p:~0,4!" == "-Xmx" set _has_memory_args=1
if "!p:~0,4!" == "-Xms" set _has_memory_args=1
if "!p:~0,4!" == "-Xss" set _has_memory_args=1
)
if not defined _has_memory_args (
call :addMemory !sbt_default_mem!
)
exit /B 0
:dlog
if defined sbt_args_debug (
echo %* 1>&2
)
exit /B 0
:process
rem Parses x out of 1.x; for example 8 out of java version 1.8.0_xx
rem Otherwise, parses the major version; 9 out of java version 9-ea
set JAVA_VERSION=0
for /f "tokens=3 usebackq" %%g in (`CALL "!_JAVACMD!" -Xms32M -Xmx32M -version 2^>^&1 ^| findstr /i version`) do (
set JAVA_VERSION=%%g
)
rem removes all quotes from JAVA_VERSION
set JAVA_VERSION=!JAVA_VERSION:"=!
for /f "delims=.-_ tokens=1-2" %%v in ("!JAVA_VERSION!") do (
if /I "%%v" EQU "1" (
set JAVA_VERSION=%%w
) else (
set JAVA_VERSION=%%v
)
)
rem parse the first two segments of sbt.version and set run_native_client to
rem 1 if the user has also indicated they want to use native client.
set sbtV=!build_props_sbt_version!
set sbtBinaryV_1=
set sbtBinaryV_2=
for /F "delims=.-_ tokens=1-2" %%v in ("!sbtV!") do (
set sbtBinaryV_1=%%v
set sbtBinaryV_2=%%w
)
set native_client_ready=
if !sbtBinaryV_1! geq 2 (
set native_client_ready=1
) else (
if !sbtBinaryV_1! geq 1 (
if !sbtBinaryV_2! geq 4 (
set native_client_ready=1
)
)
)
if !native_client_ready! equ 1 (
if !sbt_args_client! equ 1 (
set run_native_client=1
)
)
set native_client_ready=
exit /B 0
:checkjava
set /a required_version=6
if /I !JAVA_VERSION! GEQ !required_version! (
exit /B 0
)
echo.
echo The Java Development Kit ^(JDK^) installation you have is not up to date.
echo sbt requires at least version !required_version!+, you have
echo version "!JAVA_VERSION!"
echo.
echo Please go to http://www.oracle.com/technetwork/java/javase/downloads/ and download
echo a valid JDK and install before running sbt.
echo.
exit /B 1
:copyrt
if /I !JAVA_VERSION! GEQ 9 (
"!_JAVACMD!" !_JAVA_OPTS! !_SBT_OPTS! -jar "!sbt_jar!" --rt-ext-dir > "%TEMP%.\rtext.txt"
set /p java9_ext= < "%TEMP%.\rtext.txt"
set "java9_rt=!java9_ext!\rt.jar"
if not exist "!java9_rt!" (
mkdir "!java9_ext!"
"!_JAVACMD!" !_JAVA_OPTS! !_SBT_OPTS! -jar "!sbt_jar!" --export-rt "!java9_rt!"
)
set _JAVA_OPTS=!_JAVA_OPTS! -Dscala.ext.dirs="!java9_ext!"
)
exit /B 0
:sync_preloaded
if not defined init_sbt_version (
rem FIXME: better !init_sbt_version! detection
FOR /F "tokens=* usebackq" %%F IN (`dir /b "!SBT_HOME!\lib\local-preloaded\org\scala-sbt\sbt" /B`) DO (
SET init_sbt_version=%%F
)
)
set PRELOAD_SBT_JAR="%UserProfile%\.sbt\preloaded\org\scala-sbt\sbt\!init_sbt_version!\"
if /I !JAVA_VERSION! GEQ 8 (
where robocopy >nul 2>nul
if %ERRORLEVEL% EQU 0 (
if not exist !PRELOAD_SBT_JAR! (
if exist "!SBT_HOME!\lib\local-preloaded\" (
robocopy "!SBT_HOME!\lib\local-preloaded" "%UserProfile%\.sbt\preloaded" /E >nul 2>nul
)
)
)
)
exit /B 0
:usage
for /f "tokens=3 usebackq" %%g in (`CALL "!_JAVACMD!" -Xms32M -Xmx32M -version 2^>^&1 ^| findstr /i version`) do (
set FULL_JAVA_VERSION=%%g
)
echo.
echo Usage: %~n0 [options]
echo.
echo -h ^| --help print this message
echo -v ^| --verbose this runner is chattier
echo -V ^| --version print sbt version information
echo --numeric-version print the numeric sbt version (sbt sbtVersion)
echo --script-version print the version of sbt script
echo -d ^| --debug set sbt log level to debug
echo -debug-inc ^| --debug-inc
echo enable extra debugging for the incremental debugger
echo --no-colors disable ANSI color codes
echo --color=auto^|always^|true^|false^|never
echo enable or disable ANSI color codes ^(sbt 1.3 and above^)
echo --supershell=auto^|always^|true^|false^|never
echo enable or disable supershell ^(sbt 1.3 and above^)
echo --traces generate Trace Event report on shutdown ^(sbt 1.3 and above^)
echo --timings display task timings report on shutdown
echo --sbt-create start sbt even if current directory contains no sbt project
echo --sbt-dir ^<path^> path to global settings/plugins directory ^(default: ~/.sbt^)
echo --sbt-boot ^<path^> path to shared boot directory ^(default: ~/.sbt/boot in 0.11 series^)
echo --ivy ^<path^> path to local Ivy repository ^(default: ~/.ivy2^)
echo --mem ^<integer^> set memory options ^(default: %sbt_default_mem%^)
echo --no-share use all local caches; no sharing
echo --no-global uses global caches, but does not use global ~/.sbt directory.
echo --jvm-debug ^<port^> enable on JVM debugging, open at the given port.
rem echo --batch disable interactive mode
echo.
echo # sbt version ^(default: from project/build.properties if present, else latest release^)
echo --sbt-version ^<version^> use the specified version of sbt
echo --sbt-jar ^<path^> use the specified jar as the sbt launcher
echo.
echo # java version ^(default: java from PATH, currently !FULL_JAVA_VERSION!^)
echo --java-home ^<path^> alternate JAVA_HOME
echo.
echo # jvm options and output control
echo JAVA_OPTS environment variable, if unset uses "!default_java_opts!"
echo .jvmopts if this file exists in the current directory, its contents
echo are appended to JAVA_OPTS
echo SBT_OPTS environment variable, if unset uses "!default_sbt_opts!"
echo .sbtopts if this file exists in the current directory, its contents
echo are prepended to the runner args
echo !SBT_CONFIG!
echo if this file exists, it is prepended to the runner args
echo -Dkey=val pass -Dkey=val directly to the java runtime
rem echo -J-X pass option -X directly to the java runtime
rem echo ^(-J is stripped^)
rem echo -S-X add -X to sbt's scalacOptions ^(-S is stripped^)
echo.
echo In the case of duplicated or conflicting options, the order above
echo shows precedence: JAVA_OPTS lowest, command line options highest.
echo.
@endlocal
exit /B 1
:set_sbt_version
rem set project sbtVersion
for /F "usebackq tokens=2" %%G in (`CALL "!_JAVACMD!" -jar "!sbt_jar!" "sbtVersion" 2^>^&1`) do set "sbt_version=%%G"
exit /B 0
:error
@endlocal
exit /B 1
:end
@endlocal
exit /B 0

View File

@ -0,0 +1,14 @@
# sbt configuration file for Windows
# Set the java args
#-mem 1024 was added in sbt.bat as default
#-Xms1024m
#-Xmx1024m
#-Xss4M
#-XX:ReservedCodeCacheSize=128m
# Set the extra sbt options
# -Dsbt.log.format=true

View File

@ -0,0 +1,49 @@
# ------------------------------------------------ #
# The SBT Configuration file. #
# ------------------------------------------------ #
# Disable ANSI color codes
#
#-no-colors
# Starts sbt even if the current directory contains no sbt project.
#
-sbt-create
# Path to global settings/plugins directory (default: ~/.sbt)
#
#-sbt-dir /etc/sbt
# Path to shared boot directory (default: ~/.sbt/boot in 0.11 series)
#
#-sbt-boot ~/.sbt/boot
# Path to local Ivy repository (default: ~/.ivy2)
#
#-ivy ~/.ivy2
# set memory options
#
#-mem <integer>
# Use local caches for projects, no sharing.
#
#-no-share
# Put SBT in offline mode.
#
#-offline
# Sets the SBT version to use.
#-sbt-version 0.11.3
# Scala version (default: latest release)
#
#-scala-home <path>
#-scala-version <version>
# java version (default: java from PATH, currently $(java -version |& grep version))
#
#-java-home <path>

Binary file not shown.

View File

@ -0,0 +1,38 @@
#!/bin/sh
# sbt launcher script for Cygwin and MSYS
#
# Environment:
# JAVA_HOME - location of a JDK home dir (mandatory)
# SBT_OPTS - JVM options (optional)
# Configuration:
# sbtconfig.txt found in the SBT_HOME.
if [ -z "$JAVA_HOME" ]; then
JAVA_CMD=java
else
JAVA_CMD=$JAVA_HOME/bin/java
fi
UDIR=`dirname "$0"`
if [ -z "$MSYSTEM" ]; then
WDIR=`cygpath -alm "$UDIR"`
else
WDIR=`echo "$UDIR" | sed -e 's~^/\([^/]*\)/~\1:/~'`
fi
if [ -z "$JAVA_OPTS" ]; then
JAVA_OPTS=$(cat "$WDIR/sbtconfig.txt" | sed -e 's/\r//g' -e 's/^#.*$//g' | sed ':a;N;$!ba;s/\n/ /g')
fi
# TODO - this check should detect cygwin terminal, not just xterm.
if [ "_$TERM" = "_xterm" ]; then
# Let the terminal handle ANSI sequences
stty -icanon min 1 -echo > /dev/null 2>&1
"$JAVA_CMD" $JAVA_OPTS -Djline.terminal=jline.UnixTerminal -Dsbt.cygwin=true $SBT_OPTS -jar "$WDIR/sbt-launch.jar" "$@"
SCALA_STATUS=$?
stty icanon echo > /dev/null 2>&1
exit $SCALA_STATUS
else
# Use Jansi to intercept ANSI sequences
"$JAVA_CMD" -Dsbt.log.format=true $JAVA_OPTS $SBT_OPTS -cp "$WDIR/sbt-launch.jar" xsbt.boot.Boot "$@"
fi

View File

@ -0,0 +1,319 @@
#!/usr/bin/env bash
#
# This script will upload an sbt distribution (tar/tgz/msi and
# checksump files) to IBM Cloud Object Storage with the correct
# permissions, and prepare the shortened URLs on the "piccolo.link"
# Polr server.
#
#
# Required env vars:
#
# SBT_DEPLOY_S3KEY -- API Key for the sbt-distribution-archive bucket
# SBT_DEPLOY_S3SECRET -- Secret corresponding to the API Key
#
# POLR_USERNAME -- Username for the polr shortener
# POLR_PASSWORD -- Password for the polr shortener
#
# These environment vars can be either defined by the caller, or directly
# in the following lines, in place of the "your..." constants below.
#
SBT_DEPLOY_S3KEY="${SBT_DEPLOY_S3KEY:-yourSbtDeployS3key}"
SBT_DEPLOY_S3SECRET="${SBT_DEPLOY_S3SECRET:-yourSbtDeployS3secret}"
POLR_USERNAME="${POLR_USERNAME:-yourPolrUsername}"
POLR_PASSWORD="${POLR_PASSWORD:-yourPolrPassword}"
# Where to find the above information:
# - for SBT_DEPLOY_S3KEY/SBT_DEPLOY_S3SECRET, you need the API credentials for the
# 'sbt-downloads' buckets on IBM's COS. Please ask @cunei for
# details.
#
# Once you have SBT_DEPLOY_S3KEY/SBT_DEPLOY_S3SECRET, you can (and should) use those
# values also in your favorite S3 GUI browser (like CyberDuck
# or DragonDisk), in order to verify that the files are correctly
# uploaded, or to perform maintenance within the storage bucket.
#
# Note: do *not* use an S3 GUI to upload files, since that will set
# the permissions incorrectly, and the CDN will be unable to access
# the files.
#
# - for POLR_USERNAME/POLR_PASSWORD, you will need the credentials
# on "piccolo.link" for the user "lightbend-tools". Ask @cunei
# for details. Note: do not create a personal account to generate
# the short URLs: they are linked to the user that creates them
# and they would not appear in the "lightbend-tools" dashboard.
#
# Once you have set correctly the four vars above, please call
# this script as follows:
#
# If your files have this directory structure:
#
# here
# here/v0.13.15
# here/v0.13.15/sbt-0.13.15.msi
# here/v0.13.15/sbt-0.13.15.zip.asc
# here/v0.13.15/sbt-0.13.15.tgz.asc
# here/v0.13.15/sbt-0.13.15.tgz
# here/v0.13.15/sbt-0.13.15.zip
# here/v0.13.15/sbt-0.13.15.msi.asc
#
#
# then "cd here", then:
#
# $ .../sbt-upload.sh v0.13.15 [v0.13.16 ...]
#
# Where one or more directories are specified. Each directory name
# must be the letter 'v' plus a release version. The files within
# each directory can be named arbitrarily, and live in any
# subdirectory.
#
# Please note that the script will try to store temporary cookies
# and other info in a directory called "cookies", which will be
# created in the same directory as this script.
#
#--------------------------------------------------------------
#
set -o pipefail
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
usageAndExit() {
echo 'Usage: "'${0##*/}' <RELEASEDIR> [<RELEASEDIR> ...]"'
echo "where the final path component of each RELEASEDIR"
echo "must be 'v' plus"' a release number, for example: "v0.13.15".'
echo 'This script will leave some cookie files in a directory'
echo 'called "cookies", in the same location as the script.'
exit 1
}
if [[ "$#" < 1 ]]
then
usageAndExit
fi
RELEASE_DIRS=("${@:1}")
for RELEASE_DIR in "${RELEASE_DIRS[@]}"
do
RELEASE_TAG="$(basename "$RELEASE_DIR")"
if [[ "${RELEASE_TAG:0:1}" != 'v' || ! -d "${RELEASE_DIR}" ]]
then
usageAndExit
fi
done
POLR_DOMAIN_NAME="${POLR_DOMAIN_NAME:-piccolo.link}"
POLR_URL="https://$POLR_DOMAIN_NAME"
POLR_LOGIN_URL="$POLR_URL/login"
POLR_SHORTEN_URL="$POLR_URL/shorten"
# Let's try to login into Polr
# Prepare a work directory to store the cookies into
COOKIEDIR="${SCRIPTDIR}/cookies"
mkdir -p "${COOKIEDIR}"
HOME_COOKIES_PATH="${COOKIEDIR}/home-cookies"
LOGIN_COOKIES_PATH="${COOKIEDIR}/login-cookies"
CSRF_TOKEN_PATH="${COOKIEDIR}/csrf-token"
# Access home page to get tokens.
RESPONSE="$(
curl -si "$POLR_URL" \
--cookie-jar "$HOME_COOKIES_PATH"
)"
CODE="$(echo "$RESPONSE" | head -1 | awk '{print $2}')"
if [ -z "$CODE" -o "$CODE" -ne 200 ]
then
echo "ERROR: Could not load $POLR_URL; aborting."
echo -e "Response:\n$RESPONSE"
exit 1
fi
TOKEN="$(echo "$RESPONSE" | grep "_token" | \
sed -E "s/.+value='([a-zA-Z0-9]+)'.+/\1/")"
if [ -z "$TOKEN" ]
then
echo "ERROR: Could not find auth token; aborting."
exit 1
fi
# Save CSRF token.
CSRF_TOKEN="$(echo "$RESPONSE" | grep "csrf-token" | \
sed -E 's/.+content="([a-zA-Z0-9]+)".+/\1/')"
if [ -z "$CSRF_TOKEN" ]
then
echo "ERROR: Could not find CSRF token; aborting."
exit 1
fi
echo "$CSRF_TOKEN" > "$CSRF_TOKEN_PATH"
# Login and save cookie.
RESPONSE="$(
curl -siX POST "$POLR_LOGIN_URL" \
--cookie "$HOME_COOKIES_PATH" \
--cookie-jar "$LOGIN_COOKIES_PATH" \
-d "username=$POLR_USERNAME" \
-d "password=$POLR_PASSWORD" \
-d "_token=$TOKEN" \
-d "login='Sign In'"
)"
CODE="$(echo "$RESPONSE" | head -1 | awk '{print $2}')"
if [ -z "$CODE" -o "$CODE" -ne 302 ]
then
echo "ERROR: Login failed; aborting."
echo -e "Response:\n$RESPONSE"
exit 1
fi
#
# OK! Now, let's process the files
#
#
# Call this upload routine with:
# 1) relative path to the file from current dir. Do NOT use '..' or '.' in this path
# for example: uploadS3 "v1.1.4/sbt-1.1.4.tgz"
# assuming the file is in <current dir>/v1.1.4/sbt-1.1.4.tgz
#
# The file will be placed in the appropriate S3 bucket, and will be visible
# as: https://sbt-downloads.cdnedge.bluemix.net/releases/v1.1.4/sbt-1.1.4.tgz
#
uploadS3() {
S3FILEPATH="$1"
if [[ -z "$S3FILEPATH" ]]
then
echo "Internal error! Please report."
return 1
fi
S3BUCKET="sbt-distribution-archives"
S3HOST="s3-api.us-geo.objectstorage.softlayer.net"
S3RELATIVEPATH="/${S3BUCKET}/releases/${S3FILEPATH}"
S3CONTENTTYPE="$(file --brief --mime-type "$S3FILEPATH")"
S3NOWDATE="$(date -R)"
S3STRINGTOSIGN="PUT\n\n${S3CONTENTTYPE}\n${S3NOWDATE}\nx-amz-acl:public-read\n${S3RELATIVEPATH}"
S3SIGNATURE="$(echo -en ${S3STRINGTOSIGN} | openssl sha1 -hmac ${SBT_DEPLOY_S3SECRET} -binary | base64)"
echo "Uploading $S3FILEPATH"
curl -X PUT -T "${S3FILEPATH}" \
-H "Host: ${S3HOST}" \
-H "Date: ${S3NOWDATE}" \
-H "Content-Type: ${S3CONTENTTYPE}" \
-H "x-amz-acl: public-read" \
-H "Authorization: AWS ${SBT_DEPLOY_S3KEY}:${S3SIGNATURE}" \
"https://${S3HOST}${S3RELATIVEPATH}"
if [ $? -ne 0 ]
then
echo "Sorry, could not upload this file."
return 1
fi
}
shorten() {
# Arguments
URL="$1"
ENDING="$2"
TAGS=("${@:3}")
# echo "Short requested: ${ENDING} -- tags: ${TAGS[@]}"
# Retrieve the CSRF token
# CSRF_TOKEN="$(cat "$CSRF_TOKEN_PATH")"
TAG_LIST=""
if [ "${#TAGS[@]}" -gt 0 ]; then
for TAG in "${TAGS[@]}"; do # tag_list%5B%5D=$TAG
TAG_LIST="$TAG_LIST -d tag_list[]=$TAG"
done
fi
RESPONSE="$(
curl -siX POST "$POLR_SHORTEN_URL" \
--cookie "$LOGIN_COOKIES_PATH" \
-H "X-CSRF-TOKEN: $CSRF_TOKEN" \
--data-urlencode "link-url=$URL" \
-d "custom-ending=$ENDING" \
$TAG_LIST
)"
CODE="$(echo "$RESPONSE" | head -n 1 | awk '{print $2}')"
if [ "$CODE" -ne 200 ]
then
echo "Could not shorten to: '$ENDING', creating a different link."
return 1
fi
SHORT_URL="$(
echo "$RESPONSE" | \
egrep "value='http[s]?://$POLR_DOMAIN_NAME/" | \
sed -E "s@.+value='(http[s]?://$POLR_DOMAIN_NAME/[-_\.0-9a-zA-Z]+)'.+@\1@"
)"
echo "--> $SHORT_URL" | sed 's@http://@https://@'
}
for RELEASE_DIR in "${RELEASE_DIRS[@]}"
do
RELEASE_TAG="$(basename "$RELEASE_DIR")"
cd "$(dirname "$RELEASE_DIR")"
find "$RELEASE_TAG" -type f -print | while read
do
echo
uploadS3 "$REPLY"
if [ $? -eq 0 ]
then
URL="https://sbt-downloads.cdnedge.bluemix.net/releases/${REPLY}"
echo "--> $URL"
#
# let's calculate the Polr tags.
#
# In Polr the tags can only be combined with 'or', therefore
# we need to subdivide them according to the combinations that
# might be needed.
#
# We add these tags:
# - if it is an 'asc' checksum file, "${TAG}_asc", "asc"
# - if it is a tar/tgz/tar.gz/txz/tar.xz/zip/msi/deb/rpm/dmg, "${TAG}_bin", "bin"
# - if it is another file, "${TAG}_other", "other"
# In any case, we add "${TAG}"
#
# so that:
# 1) "${TAG}_asc" + "${TAG}_bin" + "${TAG}_other" are the statistics
# for the entire "${TAG}" release
# 2) "bin" are all of the archives downloads
# 3) "bin" + "asc" + "other" are all of the downloads
#
if [[ "${REPLY}" == *.asc ]]
then
KIND="asc"
elif [[ "${REPLY}" == *.tar || \
"${REPLY}" == *.tgz || \
"${REPLY}" == *.tar.gz || \
"${REPLY}" == *.txz || \
"${REPLY}" == *.tar.xz || \
"${REPLY}" == *.zip || \
"${REPLY}" == *.msi || \
"${REPLY}" == *.deb || \
"${REPLY}" == *.rpm || \
"${REPLY}" == *.dmg ]]
then
KIND="bin"
else
KIND="other"
fi
# First we try to shorten using just the file name.
# If that fails, we use an encoding of the entire path.
SHORT1="$(basename "$REPLY")"
shorten "$URL" "$SHORT1" "${RELEASE_TAG}_${KIND}" "${RELEASE_TAG}" "${KIND}"
if [[ $? != 0 ]]
then
SHORT2="${REPLY//\//_}"
shorten "$URL" "$SHORT2" "${RELEASE_TAG}_${KIND}" "${RELEASE_TAG}" "${KIND}"
if [[ $? != 0 ]]
then
echo "Sorry, could not create a short link."
fi
fi
fi
done
done