diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml index f22bd62b3..e0115d302 100644 --- a/.github/workflows/validate-pr.yml +++ b/.github/workflows/validate-pr.yml @@ -15,17 +15,34 @@ jobs: steps: - uses: actions/checkout@v1 + + - name: "Running shasum for cache invalidation" + run: | + shasum build.sbt \ + project/plugins.sbt \ + project/build.properties > gha.cache.tmp + - name: Loading ivy cache uses: actions/cache@v1 with: path: ~/.ivy2/cache - key: ${{ runner.os }}-ivy-${{ hashFiles('**/*.sbt') }} + key: ${{ runner.os }}-ivy-${{ hashFiles('gha.cache.tmp') }} restore-keys: | ${{ runner.os }}-ivy- + + - name: Loading coursier cache + uses: actions/cache@v1 + with: + path: ~/.cache/coursier + key: ${{ runner.os }}-coursier-${{ hashFiles('gha.cache.tmp') }} + restore-keys: | + ${{ runner.os }}-coursier- + - name: Set up Azul JDK 1.8 and SBT uses: olafurpg/setup-scala@v7 with: java-version: zulu@1.8 + - name: Validate run: sbt "^validate" diff --git a/build.sbt b/build.sbt index 79f465830..00ae86bd6 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,8 @@ name := "sbt-native-packager" organization := "com.typesafe.sbt" homepage := Some(url("https://github.com/sbt/sbt-native-packager")) -Global / scalaVersion := "2.12.7" +Global / onChangedBuildSource := ReloadOnSourceChanges +Global / scalaVersion := "2.12.12" // crossBuildingSettings crossSbtVersions := Vector("0.13.17", "1.1.6") @@ -58,42 +59,7 @@ mimaPreviousArtifacts := { val m = organization.value %% moduleName.value % "1.3.15" val sbtBinV = (sbtBinaryVersion in pluginCrossBuild).value val scalaBinV = (scalaBinaryVersion in update).value - Set(Defaults.sbtPluginExtra(m cross CrossVersion.Disabled(), sbtBinV, scalaBinV)) -} -mimaBinaryIssueFilters ++= { - import com.typesafe.tools.mima.core._ - List( - // added via #1179 - ProblemFilters.exclude[ReversedMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmKeys.rpmEpoch"), - ProblemFilters.exclude[ReversedMissingMethodProblem]( - "com.typesafe.sbt.packager.rpm.RpmKeys.com$typesafe$sbt$packager$rpm$RpmKeys$_setter_$rpmEpoch_=" - ), - ProblemFilters.exclude[MissingTypesProblem]("com.typesafe.sbt.packager.rpm.RpmMetadata$"), - ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmMetadata.apply"), - ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmMetadata.copy"), - ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmMetadata.this"), - // added via #1251 - ProblemFilters.exclude[ReversedMissingMethodProblem]( - "com.typesafe.sbt.packager.universal.UniversalKeys.com$typesafe$sbt$packager$universal$UniversalKeys$_setter_$containerBuildImage_=" - ), - ProblemFilters - .exclude[ReversedMissingMethodProblem]("com.typesafe.sbt.packager.universal.UniversalKeys.containerBuildImage"), - ProblemFilters.exclude[ReversedMissingMethodProblem]( - "com.typesafe.sbt.packager.graalvmnativeimage.GraalVMNativeImageKeys.graalVMNativeImageGraalVersion" - ), - ProblemFilters.exclude[ReversedMissingMethodProblem]( - "com.typesafe.sbt.packager.graalvmnativeimage.GraalVMNativeImageKeys.com$typesafe$sbt$packager$graalvmnativeimage$GraalVMNativeImageKeys$_setter_$graalVMNativeImageGraalVersion_=" - ), - // added via #1279 - ProblemFilters.exclude[ReversedMissingMethodProblem]( - "com.typesafe.sbt.packager.docker.DockerKeys.com$typesafe$sbt$packager$docker$DockerKeys$_setter_$dockerAutoremoveMultiStageIntermediateImages_=" - ), - ProblemFilters.exclude[ReversedMissingMethodProblem]( - "com.typesafe.sbt.packager.docker.DockerKeys.dockerAutoremoveMultiStageIntermediateImages" - ), - ProblemFilters - .exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.docker.DockerPlugin.publishLocalDocker") - ) + Set(Defaults.sbtPluginExtra(m cross CrossVersion.disabled, sbtBinV, scalaBinV)) } // Release configuration @@ -119,9 +85,9 @@ releaseProcess := Seq[ReleaseStep]( bintrayOrganization := Some("sbt") bintrayRepository := "sbt-plugin-releases" -addCommandAlias("scalafmtAll", "; scalafmt ; test:scalafmt ; sbt:scalafmt") +addCommandAlias("scalafmtFormatAll", "; ^scalafmtAll ; scalafmtSbt") // ci commands -addCommandAlias("validateFormatting", "; scalafmt::test ; test:scalafmt::test ; sbt:scalafmt::test") +addCommandAlias("validateFormatting", "; scalafmtCheckAll ; scalafmtSbtCheck") addCommandAlias("validate", "; clean ; update ; validateFormatting ; test ; mimaReportBinaryIssues") // List all scripted test separately to schedule them in different travis-ci jobs. diff --git a/project/ChangelogPlugin.scala b/project/ChangelogPlugin.scala index 5e658474d..06843c59e 100644 --- a/project/ChangelogPlugin.scala +++ b/project/ChangelogPlugin.scala @@ -62,19 +62,29 @@ object ChangelogPlugin extends AutoPlugin { private case class GithubChangeLogParameters(token: String) - private val githubChangeLogParser: Parser[GithubChangeLogParameters] = { + private val githubChangeLogParser: Parser[GithubChangeLogParameters] = (Space ~ token("--token") ~ Space ~> StringBasic).map(GithubChangeLogParameters) - } override def projectSettings: Seq[Setting[_]] = - Seq(generateChangelogToken := None, generateChangelog := { - val log = streams.value.log - val parameters = githubChangeLogParser.parsed - Seq("github_changelog_generator", "--user", "sbt", "--project", "sbt-native-packager", "--token", parameters.token) ! log match { - case 0 => log.success("CHANGELOG.md updated successfully") - case n => sys.error(s"Failed updating CHANGELOG.md. Process existed with status code $n") + Seq( + generateChangelogToken := None, + generateChangelog := { + val log = streams.value.log + val parameters = githubChangeLogParser.parsed + Seq( + "github_changelog_generator", + "--user", + "sbt", + "--project", + "sbt-native-packager", + "--token", + parameters.token + ) ! log match { + case 0 => log.success("CHANGELOG.md updated successfully") + case n => sys.error(s"Failed updating CHANGELOG.md. Process existed with status code $n") + } } - }) + ) private def generateChangelogStep(state: State): State = { val extracted = Project.extract(state) @@ -101,11 +111,10 @@ object ChangelogPlugin extends AutoPlugin { vcs(state).add(relativePath) !! log val vcsAddOutput = (vcs(state).status !!).trim - if (vcsAddOutput.isEmpty) { + if (vcsAddOutput.isEmpty) state.log.info("CHANGELOG.md hasn't been changed.") - } else { + else vcs(state).commit("Update changelog", sign, signOff) ! log - } state } @@ -130,13 +139,14 @@ object ChangelogPlugin extends AutoPlugin { * @param state * @return a process logger */ - private def toProcessLogger(state: State): ProcessLogger = new ProcessLogger { - override def err(s: => String): Unit = state.log.info(s) - override def out(s: => String): Unit = state.log.info(s) - override def buffer[T](f: => T): T = state.log.buffer(f) - } + private def toProcessLogger(state: State): ProcessLogger = + new ProcessLogger { + override def err(s: => String): Unit = state.log.info(s) + override def out(s: => String): Unit = state.log.info(s) + override def buffer[T](f: => T): T = state.log.buffer(f) + } - private def readToken(predefinedToken: Option[String]): String = + private def readToken(predefinedToken: Option[String]): String = predefinedToken // https://github.com/github-changelog-generator/github-changelog-generator#github-token .orElse(sys.env.get("CHANGELOG_GITHUB_TOKEN")) @@ -145,6 +155,6 @@ object ChangelogPlugin extends AutoPlugin { case Some(input) if input.trim.isEmpty => sys.error("No token provided") case Some(input) => input case None => sys.error("No token provided") - }) + }) } diff --git a/project/ReadmeReleasePlugin.scala b/project/ReadmeReleasePlugin.scala index 72ff7a81e..d946cb3d0 100644 --- a/project/ReadmeReleasePlugin.scala +++ b/project/ReadmeReleasePlugin.scala @@ -9,9 +9,8 @@ import scala.sys.process._ /** * == ReadmeRelease Plugin == - * + * * Changes the version in the README.md during a release. - * */ object ReadmeReleasePlugin extends AutoPlugin { @@ -33,7 +32,6 @@ object ReadmeReleasePlugin extends AutoPlugin { } - private def updateReadmeStep(state: State): State = { val extracted = Project.extract(state) val releaseVersion = extracted.get(version) @@ -41,14 +39,10 @@ object ReadmeReleasePlugin extends AutoPlugin { val readmeFile = base / "README.md" val versionRegex = """(\d{1,2}\.\d{1,2}\.\d{1,2})""".r - val updatedReadmeContent = versionRegex.replaceAllIn( - IO.read(readmeFile), - releaseVersion - ) + val updatedReadmeContent = versionRegex.replaceAllIn(IO.read(readmeFile), releaseVersion) IO.write(readmeFile, updatedReadmeContent) - state } @@ -67,11 +61,10 @@ object ReadmeReleasePlugin extends AutoPlugin { vcs(state).add(relativePath) !! log val vcsAddOutput = (vcs(state).status !!).trim - if (vcsAddOutput.isEmpty) { + if (vcsAddOutput.isEmpty) state.log.info("README.md hasn't been changed.") - } else { + else vcs(state).commit("Update release version in readme", sign, signOff) ! log - } state } @@ -96,11 +89,11 @@ object ReadmeReleasePlugin extends AutoPlugin { * @param state * @return a process logger */ - private def toProcessLogger(state: State): ProcessLogger = new ProcessLogger { - override def err(s: => String): Unit = state.log.info(s) - override def out(s: => String): Unit = state.log.info(s) - override def buffer[T](f: => T): T = state.log.buffer(f) - } - + private def toProcessLogger(state: State): ProcessLogger = + new ProcessLogger { + override def err(s: => String): Unit = state.log.info(s) + override def out(s: => String): Unit = state.log.info(s) + override def buffer[T](f: => T): T = state.log.buffer(f) + } } diff --git a/project/build.properties b/project/build.properties index c0bab0494..0837f7a13 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.2.8 +sbt.version=1.3.13 diff --git a/project/plugins.sbt b/project/plugins.sbt index 16546e5e4..2c1c06209 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -16,7 +16,7 @@ libraryDependencies += "jline" % "jline" % "2.11" addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.4") // For code formatting -addSbtPlugin("com.lucidchart" % "sbt-scalafmt" % "1.15") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2") // binary compatibility checks -addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.3.0") +addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.7.0") diff --git a/src/main/mima-filters/1.3.15.backward.excludes b/src/main/mima-filters/1.3.15.backward.excludes new file mode 100644 index 000000000..f427433bd --- /dev/null +++ b/src/main/mima-filters/1.3.15.backward.excludes @@ -0,0 +1,76 @@ +# added via #1179 +ProblemFilters.exclude[ReversedMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmKeys.rpmEpoch") +ProblemFilters.exclude[ReversedMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmKeys.com$typesafe$sbt$packager$rpm$RpmKeys$_setter_$rpmEpoch_=") +ProblemFilters.exclude[MissingTypesProblem]("com.typesafe.sbt.packager.rpm.RpmMetadata$") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmMetadata.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmMetadata.copy") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmMetadata.this") + +# added via #1251 +ProblemFilters.exclude[ReversedMissingMethodProblem]("com.typesafe.sbt.packager.universal.UniversalKeys.com$typesafe$sbt$packager$universal$UniversalKeys$_setter_$containerBuildImage_=") +ProblemFilters.exclude[ReversedMissingMethodProblem]("com.typesafe.sbt.packager.universal.UniversalKeys.containerBuildImage") +ProblemFilters.exclude[ReversedMissingMethodProblem]("com.typesafe.sbt.packager.graalvmnativeimage.GraalVMNativeImageKeys.graalVMNativeImageGraalVersion") +ProblemFilters.exclude[ReversedMissingMethodProblem]("com.typesafe.sbt.packager.graalvmnativeimage.GraalVMNativeImageKeys.com$typesafe$sbt$packager$graalvmnativeimage$GraalVMNativeImageKeys$_setter_$graalVMNativeImageGraalVersion_=") +# added via #1279 +ProblemFilters.exclude[ReversedMissingMethodProblem]("com.typesafe.sbt.packager.docker.DockerKeys.com$typesafe$sbt$packager$docker$DockerKeys$_setter_$dockerAutoremoveMultiStageIntermediateImages_=") +ProblemFilters.exclude[ReversedMissingMethodProblem]("com.typesafe.sbt.packager.docker.DockerKeys.dockerAutoremoveMultiStageIntermediateImages") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.docker.DockerPlugin.publishLocalDocker") + +# added via #1319 +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.universal.UniversalDeployPlugin.requires") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.universal.UniversalPlugin.requires") + +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.windows.WindowsDeployPlugin.requires") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.windows.WindowsProductInfo.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.windows.AddDirectoryToPath.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.windows.WindowsFeature.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.windows.AddShortCuts.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.windows.NamespaceDefinitions.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.windows.ComponentFile.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.windows.WindowsPlugin.requires") + +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.debian.PackageInfo.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.debian.DebianControlScriptReplacements.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.debian.DebianPlugin.requires") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.debian.DebianDeployPlugin.requires") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.debian.PackageMetaData.apply") + +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmDependencies.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmPlugin.requires") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmDeployPlugin.requires") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmSpec.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.rpm.RpmDescription.apply") + +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.JavaServerAppPackaging.requires") + +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.jar.ClasspathJarPlugin.requires") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.jar.LauncherJarPlugin.requires") + +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.systemloader.SystemdPlugin.requires") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.systemloader.SystemVPlugin.requires") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.systemloader.UpstartPlugin.requires") + +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.scripts.MultipleMains.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.scripts.BashStartScriptPlugin.trigger") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.scripts.BashStartScriptPlugin.requires") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.scripts.BashStartScriptPlugin.scriptTargetFolder") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.scripts.BatStartScriptPlugin.trigger") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.scripts.BatStartScriptPlugin.requires") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.scripts.BatStartScriptPlugin.scriptTargetFolder") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.scripts.ExplicitMainWithAdditional.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.archetypes.scripts.SingleMain.apply") + +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.validation.ValidationWarning.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.validation.ValidationError.apply") + +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.linux.LinuxFileMetaData.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.linux.LinuxPackageMapping.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.linux.LinuxPlugin.requires") + +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.jdkpackager.JDKPackagerDeployPlugin.requires") + +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.docker.DockerAlias.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.docker.Dockerfile.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.docker.ExecCmd.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.docker.CombinedCmd.apply") +ProblemFilters.exclude[DirectMissingMethodProblem]("com.typesafe.sbt.packager.docker.Cmd.apply") \ No newline at end of file diff --git a/src/main/scala-sbt-0.13/com/typesafe/sbt/packager/MappingsHelper.scala b/src/main/scala-sbt-0.13/com/typesafe/sbt/packager/MappingsHelper.scala index 769c21c49..5d23cbb67 100644 --- a/src/main/scala-sbt-0.13/com/typesafe/sbt/packager/MappingsHelper.scala +++ b/src/main/scala-sbt-0.13/com/typesafe/sbt/packager/MappingsHelper.scala @@ -68,7 +68,6 @@ object MappingsHelper { * Create mappings from your classpath. For example if you want to add additional * dependencies, like test or model. * - * * @example Add all test artifacts to a separated test folder * {{{ * mappings in Universal ++= fromClasspath((managedClasspath in Test).value, target = "test") @@ -95,16 +94,17 @@ object MappingsHelper { * ) * }}} * - * * @param entries from where mappings should be created from * @param target folder, e.g. `model`. Must not end with a slash * @param includeArtifact function to determine if an artifact should result in a mapping * @param includeOnNoArtifact default is false. When there's no Artifact meta data remove it */ - def fromClasspath(entries: Seq[Attributed[File]], - target: String, - includeArtifact: Artifact => Boolean, - includeOnNoArtifact: Boolean = false): Seq[(File, String)] = + def fromClasspath( + entries: Seq[Attributed[File]], + target: String, + includeArtifact: Artifact => Boolean, + includeOnNoArtifact: Boolean = false + ): Seq[(File, String)] = entries.filter(attr => attr.get(sbt.Keys.artifact.key) map includeArtifact getOrElse includeOnNoArtifact).map { attribute => val file = attribute.data @@ -114,8 +114,7 @@ object MappingsHelper { /** * Get the mappings for the given files relative to the given directories. */ - def relative(files: Seq[File], dirs: Seq[File]): Seq[(File, String)] = { + def relative(files: Seq[File], dirs: Seq[File]): Seq[(File, String)] = (files --- dirs) pair (relativeTo(dirs) | Path.flat) - } } diff --git a/src/main/scala-sbt-0.13/com/typesafe/sbt/packager/SettingsHelper.scala b/src/main/scala-sbt-0.13/com/typesafe/sbt/packager/SettingsHelper.scala index 0b0a2612f..de02a48b8 100644 --- a/src/main/scala-sbt-0.13/com/typesafe/sbt/packager/SettingsHelper.scala +++ b/src/main/scala-sbt-0.13/com/typesafe/sbt/packager/SettingsHelper.scala @@ -5,10 +5,12 @@ import sbt._ object SettingsHelper { - def addPackage(config: Configuration, - packageTask: TaskKey[File], - extension: String, - classifier: Option[String] = None): Seq[Setting[_]] = + def addPackage( + config: Configuration, + packageTask: TaskKey[File], + extension: String, + classifier: Option[String] = None + ): Seq[Setting[_]] = inConfig(config)( addArtifact( name apply (Artifact( @@ -24,10 +26,12 @@ object SettingsHelper { ) ) - def makeDeploymentSettings(config: Configuration, - packageTask: TaskKey[File], - extension: String, - classifier: Option[String] = None): Seq[Setting[_]] = + def makeDeploymentSettings( + config: Configuration, + packageTask: TaskKey[File], + extension: String, + classifier: Option[String] = None + ): Seq[Setting[_]] = inConfig(config)(Classpaths.ivyPublishSettings ++ Classpaths.jvmPublishSettings) ++ inConfig(config)( Seq( artifacts := Seq.empty, @@ -63,24 +67,23 @@ object SettingsHelper { checksums = checksums.value, logging = UpdateLogging.DownloadOnly, overwrite = isSnapshot.value - ) + ) ) ) ++ addPackage(config, packageTask, extension, classifier) ++ addResolver(config) /** - * SBT looks in the `otherResolvers` setting for resolvers defined in `publishTo`. - * If a user scopes a `publishTo`, e.g. - * - * {{{ - * // publish the rpm to the target folder - * publishTo in Rpm := Some(Resolver.file("target-resolver", target.value / "rpm-repo" )) - * }}} - * - * then the resolver must also be present in the `otherResolvers` - * - * @param config the ivy configuration to look for resolvers - */ - private def addResolver(config: Configuration): Seq[Setting[_]] = Seq( - otherResolvers ++= (publishTo in config).value.toSeq - ) + * SBT looks in the `otherResolvers` setting for resolvers defined in `publishTo`. + * If a user scopes a `publishTo`, e.g. + * + * {{{ + * // publish the rpm to the target folder + * publishTo in Rpm := Some(Resolver.file("target-resolver", target.value / "rpm-repo" )) + * }}} + * + * then the resolver must also be present in the `otherResolvers` + * + * @param config the ivy configuration to look for resolvers + */ + private def addResolver(config: Configuration): Seq[Setting[_]] = + Seq(otherResolvers ++= (publishTo in config).value.toSeq) } diff --git a/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/Compat.scala b/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/Compat.scala index 1cdc5ca1d..c7b493968 100644 --- a/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/Compat.scala +++ b/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/Compat.scala @@ -19,7 +19,6 @@ object Compat { type BuildDependencies = InternalBuildDependencies /** - * */ type Process = sys.process.Process diff --git a/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/MappingsHelper.scala b/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/MappingsHelper.scala index a81d80f51..b245c720b 100644 --- a/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/MappingsHelper.scala +++ b/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/MappingsHelper.scala @@ -38,7 +38,6 @@ object MappingsHelper extends Mapper { * Create mappings from your classpath. For example if you want to add additional * dependencies, like test or model. * - * * @example Add all test artifacts to a separated test folder * {{{ * mappings in Universal ++= fromClasspath((managedClasspath in Test).value, target = "test") @@ -65,26 +64,26 @@ object MappingsHelper extends Mapper { * ) * }}} * - * * @param entries from where mappings should be created from * @param target folder, e.g. `model`. Must not end with a slash * @param includeArtifact function to determine if an artifact should result in a mapping * @param includeOnNoArtifact default is false. When there's no Artifact meta data remove it */ - def fromClasspath(entries: Seq[Attributed[File]], - target: String, - includeArtifact: Artifact => Boolean, - includeOnNoArtifact: Boolean = false): Seq[(File, String)] = + def fromClasspath( + entries: Seq[Attributed[File]], + target: String, + includeArtifact: Artifact => Boolean, + includeOnNoArtifact: Boolean = false + ): Seq[(File, String)] = entries.filter(attr => attr.get(sbt.Keys.artifact.key) map includeArtifact getOrElse includeOnNoArtifact).map { attribute => - val file = attribute.data - file -> s"$target/${file.getName}" + val file = attribute.data + file -> s"$target/${file.getName}" } /** * Get the mappings for the given files relative to the given directories. */ - def relative(files: Seq[File], dirs: Seq[File]): Seq[(File, String)] = { + def relative(files: Seq[File], dirs: Seq[File]): Seq[(File, String)] = (files --- dirs) pair (relativeTo(dirs) | flat) - } } diff --git a/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/SettingsHelper.scala b/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/SettingsHelper.scala index fa5a581b8..370c5b3a2 100644 --- a/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/SettingsHelper.scala +++ b/src/main/scala-sbt-1.0/com/typesafe/sbt/packager/SettingsHelper.scala @@ -12,27 +12,32 @@ import com.typesafe.sbt.packager.Compat._ */ object SettingsHelper { - def addPackage(config: Configuration, - packageTask: TaskKey[File], - extension: String, - classifier: Option[String] = None): Seq[Setting[_]] = inConfig(config)( - addArtifact( - name apply (Artifact( - _, - extension, - extension, - classifier = classifier, - configurations = Vector.empty, - url = None - )), - packageTask + def addPackage( + config: Configuration, + packageTask: TaskKey[File], + extension: String, + classifier: Option[String] = None + ): Seq[Setting[_]] = + inConfig(config)( + addArtifact( + name apply (Artifact( + _, + extension, + extension, + classifier = classifier, + configurations = Vector.empty, + url = None + )), + packageTask + ) ) - ) - def makeDeploymentSettings(config: Configuration, - packageTask: TaskKey[File], - extension: String, - classifier: Option[String] = None): Seq[Setting[_]] = + def makeDeploymentSettings( + config: Configuration, + packageTask: TaskKey[File], + extension: String, + classifier: Option[String] = None + ): Seq[Setting[_]] = // Why do we need the ivyPublishSettings and jvmPublishSettings ? inConfig(config)(Classpaths.ivyPublishSettings ++ Classpaths.jvmPublishSettings) ++ inConfig(config)( Seq( @@ -73,19 +78,18 @@ object SettingsHelper { ) ++ addPackage(config, packageTask, extension, classifier) ++ addResolver(config) /** - * SBT looks in the `otherResolvers` setting for resolvers defined in `publishTo`. - * If a user scopes a `publishTo`, e.g. - * - * {{{ - * // publish the rpm to the target folder - * publishTo in Rpm := Some(Resolver.file("target-resolver", target.value / "rpm-repo" )) - * }}} - * - * then the resolver must also be present in the `otherResolvers` - * - * @param config the ivy configuration to look for resolvers - */ - private def addResolver(config: Configuration): Seq[Setting[_]] = Seq( - otherResolvers ++= (publishTo in config).value.toSeq - ) + * SBT looks in the `otherResolvers` setting for resolvers defined in `publishTo`. + * If a user scopes a `publishTo`, e.g. + * + * {{{ + * // publish the rpm to the target folder + * publishTo in Rpm := Some(Resolver.file("target-resolver", target.value / "rpm-repo" )) + * }}} + * + * then the resolver must also be present in the `otherResolvers` + * + * @param config the ivy configuration to look for resolvers + */ + private def addResolver(config: Configuration): Seq[Setting[_]] = + Seq(otherResolvers ++= (publishTo in config).value.toSeq) } diff --git a/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala b/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala index cc235c4d0..129c9351b 100644 --- a/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala @@ -38,7 +38,6 @@ import sbt.Keys.{name, normalizedName, packageBin, streams} * {{{ * enablePlugins(SbtNativePackager) * }}} - * */ object SbtNativePackager extends AutoPlugin { @@ -69,7 +68,6 @@ object SbtNativePackager extends AutoPlugin { * === NativePackagerHelper === * * This object contains a set of helper methods for working with mappings. - * */ object autoImport extends packager.NativePackagerKeys { diff --git a/src/main/scala/com/typesafe/sbt/packager/FileUtil.scala b/src/main/scala/com/typesafe/sbt/packager/FileUtil.scala index 4d264fd9d..b4743cbd3 100644 --- a/src/main/scala/com/typesafe/sbt/packager/FileUtil.scala +++ b/src/main/scala/com/typesafe/sbt/packager/FileUtil.scala @@ -63,16 +63,17 @@ object permissions { asString(user) + asString(group) + asString(other) } - private def asString(perm: Int): String = perm match { - case 0 => "---" - case 1 => "--x" - case 2 => "-w-" - case 3 => "-wx" - case 4 => "r--" - case 5 => "r-x" - case 6 => "rw-" - case 7 => "rwx" - } + private def asString(perm: Int): String = + perm match { + case 0 => "---" + case 1 => "--x" + case 2 => "-w-" + case 3 => "-wx" + case 4 => "r--" + case 5 => "r-x" + case 6 => "rw-" + case 7 => "rwx" + } /** Enriches string with `oct` interpolator, parsing string as base 8 integer. */ implicit class OctalString(val sc: StringContext) extends AnyVal { diff --git a/src/main/scala/com/typesafe/sbt/packager/Hashing.scala b/src/main/scala/com/typesafe/sbt/packager/Hashing.scala index 78a92b6c1..2111e6d86 100644 --- a/src/main/scala/com/typesafe/sbt/packager/Hashing.scala +++ b/src/main/scala/com/typesafe/sbt/packager/Hashing.scala @@ -17,10 +17,11 @@ object Hashing { val in = new java.io.FileInputStream(file); val buffer = new Array[Byte](8192) try { - def read(): Unit = in.read(buffer) match { - case x if x <= 0 => () - case size => md.update(buffer, 0, size); read() - } + def read(): Unit = + in.read(buffer) match { + case x if x <= 0 => () + case size => md.update(buffer, 0, size); read() + } read() } finally in.close() convertToHex(md.digest) @@ -33,8 +34,8 @@ object Hashing { if ((0 <= b) && (b <= 9)) ('0' + b).toChar else ('a' + (b - 10)).toChar for (i <- 0 until data.length) { - buf append byteToHex((data(i) >>> 4) & 0x0F) - buf append byteToHex(data(i) & 0x0F) + buf append byteToHex((data(i) >>> 4) & 0x0f) + buf append byteToHex(data(i) & 0x0f) } buf.toString } diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppPackaging.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppPackaging.scala index 15384420f..f512fcde6 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppPackaging.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppPackaging.scala @@ -41,58 +41,60 @@ object JavaAppPackaging extends AutoPlugin { override def requires: Plugins = debian.DebianPlugin && rpm.RpmPlugin && docker.DockerPlugin && windows.WindowsPlugin - override def projectSettings = Seq( - javaOptions in Universal := Nil, - // Here we record the classpath as it's added to the mappings separately, so - // we can use its order to generate the bash/bat scripts. - scriptClasspathOrdering := Nil, - // Note: This is sometimes on the classpath via dependencyClasspath in Runtime. - // We need to figure out why sometimes the Attributed[File] is correctly configured - // and sometimes not. - scriptClasspathOrdering += { - val jar = (packageBin in Compile).value - val id = projectID.value - val art = (artifact in Compile in packageBin).value - jar -> ("lib/" + makeJarName(id.organization, id.name, id.revision, art.name, art.classifier)) - }, - projectDependencyArtifacts := findProjectDependencyArtifacts.value, - scriptClasspathOrdering ++= universalDepMappings( - (dependencyClasspath in Runtime).value, - projectDependencyArtifacts.value - ), - scriptClasspathOrdering := scriptClasspathOrdering.value.distinct, - mappings in Universal ++= scriptClasspathOrdering.value, - scriptClasspath := makeRelativeClasspathNames(scriptClasspathOrdering.value), - linuxPackageMappings in Debian += { - val name = (packageName in Debian).value - val installLocation = defaultLinuxInstallLocation.value - val targetDir = (target in Debian).value - // create empty var/log directory - val d = targetDir / installLocation - d.mkdirs() - LinuxPackageMapping(Seq(d -> (installLocation + "/" + name)), LinuxFileMetaData()) - }, - bundledJvmLocation := (bundledJvmLocation ?? None).value - ) + override def projectSettings = + Seq( + javaOptions in Universal := Nil, + // Here we record the classpath as it's added to the mappings separately, so + // we can use its order to generate the bash/bat scripts. + scriptClasspathOrdering := Nil, + // Note: This is sometimes on the classpath via dependencyClasspath in Runtime. + // We need to figure out why sometimes the Attributed[File] is correctly configured + // and sometimes not. + scriptClasspathOrdering += { + val jar = (packageBin in Compile).value + val id = projectID.value + val art = (artifact in Compile in packageBin).value + jar -> ("lib/" + makeJarName(id.organization, id.name, id.revision, art.name, art.classifier)) + }, + projectDependencyArtifacts := findProjectDependencyArtifacts.value, + scriptClasspathOrdering ++= universalDepMappings( + (dependencyClasspath in Runtime).value, + projectDependencyArtifacts.value + ), + scriptClasspathOrdering := scriptClasspathOrdering.value.distinct, + mappings in Universal ++= scriptClasspathOrdering.value, + scriptClasspath := makeRelativeClasspathNames(scriptClasspathOrdering.value), + linuxPackageMappings in Debian += { + val name = (packageName in Debian).value + val installLocation = defaultLinuxInstallLocation.value + val targetDir = (target in Debian).value + // create empty var/log directory + val d = targetDir / installLocation + d.mkdirs() + LinuxPackageMapping(Seq(d -> (installLocation + "/" + name)), LinuxFileMetaData()) + }, + bundledJvmLocation := (bundledJvmLocation ?? None).value + ) private def makeRelativeClasspathNames(mappings: Seq[(File, String)]): Seq[String] = for { (_, name) <- mappings - } yield { - // Here we want the name relative to the lib/ folder... - // For now we just cheat... - if (name startsWith "lib/") name drop 4 - else "../" + name - } + } yield + // Here we want the name relative to the lib/ folder... + // For now we just cheat... + if (name startsWith "lib/") name drop 4 + else "../" + name /** * Constructs a jar name from components...(ModuleID/Artifact) */ - def makeJarName(org: String, - name: String, - revision: String, - artifactName: String, - artifactClassifier: Option[String]): String = + def makeJarName( + org: String, + name: String, + revision: String, + artifactName: String, + artifactClassifier: Option[String] + ): String = org + "." + name + "-" + Option(artifactName.replace(name, "")).filterNot(_.isEmpty).map(_ + "-").getOrElse("") + @@ -104,11 +106,12 @@ object JavaAppPackaging extends AutoPlugin { // ivy metadata if available. private def getJarFullFilename(dep: Attributed[File]): String = { val filename: Option[String] = for { - module <- dep.metadata - // sbt 0.13.x key - .get(AttributeKey[ModuleID]("module-id")) - // sbt 1.x key - .orElse(dep.metadata.get(AttributeKey[ModuleID]("moduleID"))) + module <- + dep.metadata + // sbt 0.13.x key + .get(AttributeKey[ModuleID]("module-id")) + // sbt 1.x key + .orElse(dep.metadata.get(AttributeKey[ModuleID]("moduleID"))) artifact <- dep.metadata.get(AttributeKey[Artifact]("artifact")) } yield makeJarName(module.organization, module.name, module.revision, artifact.name, artifact.classifier) filename.getOrElse(dep.data.getName) @@ -153,16 +156,14 @@ object JavaAppPackaging extends AutoPlugin { val artifactTask = extracted.get(packagedArtifacts in ref) for { arts <- artifactTask - } yield { - for { - (art, file) <- arts.toSeq // TODO -Filter! - } yield Attributed.blank(file).put(moduleID.key, module).put(artifact.key, art) - } + } yield for { + (art, file) <- arts.toSeq // TODO -Filter! + } yield Attributed.blank(file).put(moduleID.key, module).put(artifact.key, art) } private def findRealDep(dep: Attributed[File], projectArts: Seq[Attributed[File]]): Option[Attributed[File]] = if (dep.data.isFile) Some(dep) - else { + else projectArts.find { art => // TODO - Why is the module not showing up for project deps? //(art.get(sbt.Keys.moduleID.key) == dep.get(sbt.Keys.moduleID.key)) && @@ -174,11 +175,12 @@ object JavaAppPackaging extends AutoPlugin { case _ => false } } - } // Converts a managed classpath into a set of lib mappings. - private def universalDepMappings(deps: Seq[Attributed[File]], - projectArts: Seq[Attributed[File]]): Seq[(File, String)] = + private def universalDepMappings( + deps: Seq[Attributed[File]], + projectArts: Seq[Attributed[File]] + ): Seq[(File, String)] = for { dep <- deps realDep <- findRealDep(dep, projectArts) diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala index c551614ea..05411a884 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala @@ -36,7 +36,7 @@ object JavaServerAppPackaging extends AutoPlugin { val ENV_CONFIG_REPLACEMENT = "env_config" val ETC_DEFAULT = "etc-default" - /** These settings will be provided by this archetype*/ + /** These settings will be provided by this archetype */ def javaServerSettings: Seq[Setting[_]] = linuxSettings ++ debianSettings ++ rpmSettings @@ -47,27 +47,28 @@ object JavaServerAppPackaging extends AutoPlugin { * - logging directory * - config directory */ - def linuxSettings: Seq[Setting[_]] = Seq( - javaOptions in Linux := (javaOptions in Universal).value, - // === logging directory mapping === - linuxPackageMappings += { - packageTemplateMapping(defaultLinuxLogsLocation.value + "/" + (packageName in Linux).value)() - .withUser((daemonUser in Linux).value) - .withGroup((daemonGroup in Linux).value) - .withPerms("755") - }, - linuxPackageSymlinks += { - val name = (packageName in Linux).value - LinuxSymlink( - defaultLinuxInstallLocation.value + "/" + name + "/logs", - defaultLinuxLogsLocation.value + "/" + name - ) - }, - // === etc config mapping === - bashScriptEnvConfigLocation := Some("/etc/default/" + (packageName in Linux).value), - linuxStartScriptName := None, - daemonStdoutLogFile := None - ) + def linuxSettings: Seq[Setting[_]] = + Seq( + javaOptions in Linux := (javaOptions in Universal).value, + // === logging directory mapping === + linuxPackageMappings += { + packageTemplateMapping(defaultLinuxLogsLocation.value + "/" + (packageName in Linux).value)() + .withUser((daemonUser in Linux).value) + .withGroup((daemonGroup in Linux).value) + .withPerms("755") + }, + linuxPackageSymlinks += { + val name = (packageName in Linux).value + LinuxSymlink( + defaultLinuxInstallLocation.value + "/" + name + "/logs", + defaultLinuxLogsLocation.value + "/" + name + ) + }, + // === etc config mapping === + bashScriptEnvConfigLocation := Some("/etc/default/" + (packageName in Linux).value), + linuxStartScriptName := None, + daemonStdoutLogFile := None + ) /* etcDefaultConfig is dependent on serverLoading (systemd, systemv, etc.), * and is therefore distro specific. As such, these settings cannot be defined @@ -174,9 +175,12 @@ object JavaServerAppPackaging extends AutoPlugin { // Used to tell our packager to install our /etc/default/{{appName}} config file. protected def etcDefaultMapping(conf: Option[File], envLocation: Option[String]): Seq[LinuxPackageMapping] = { - val mapping = for (path <- envLocation; - c <- conf) - yield LinuxPackageMapping(Seq(c -> path), LinuxFileMetaData(Users.Root, Users.Root, "644")).withConfig() + val mapping = + for ( + path <- envLocation; + c <- conf + ) + yield LinuxPackageMapping(Seq(c -> path), LinuxFileMetaData(Users.Root, Users.Root, "644")).withConfig() mapping.toSeq } @@ -189,8 +193,9 @@ object JavaServerAppPackaging extends AutoPlugin { * @param scriptName that should be loaded * @return script lines */ - private[this] def getScriptContent(config: Configuration, - replacements: Seq[(String, String)])(scriptName: String): Seq[String] = + private[this] def getScriptContent(config: Configuration, replacements: Seq[(String, String)])( + scriptName: String + ): Seq[String] = JavaServerBashScript(scriptName, ARCHETYPE, config, replacements).toSeq /** @@ -204,10 +209,12 @@ object JavaServerAppPackaging extends AutoPlugin { * * @return Some(file: File) */ - protected def makeEtcDefaultScript(name: String, - tmpDir: File, - source: java.net.URL, - replacements: Seq[(String, String)]): Option[File] = { + protected def makeEtcDefaultScript( + name: String, + tmpDir: File, + source: java.net.URL, + replacements: Seq[(String, String)] + ): Option[File] = { val scriptBits = TemplateWriter.generateScript(source, replacements) val script = tmpDir / "tmp" / "etc" / "default" / name IO.write(script, scriptBits) @@ -215,15 +222,15 @@ object JavaServerAppPackaging extends AutoPlugin { } /** - * - * * @param scriptDirectory * @param scripts * @param replacements */ - protected def rpmScriptletContents(scriptDirectory: File, - scripts: Map[String, Seq[String]], - replacements: Seq[(String, String)]): Map[String, Seq[String]] = { + protected def rpmScriptletContents( + scriptDirectory: File, + scripts: Map[String, Seq[String]], + replacements: Seq[(String, String)] + ): Map[String, Seq[String]] = { import RpmConstants._ val predefined = List(Pre, Post, Preun, Postun) val predefinedScripts = predefined.foldLeft(scripts) { diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerBashScript.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerBashScript.scala index 780f98831..9889714ac 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerBashScript.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerBashScript.scala @@ -28,18 +28,19 @@ import com.typesafe.sbt.packager.archetypes.systemloader.ServerLoader._ object JavaServerBashScript { /** - * * @param script - script name * @param templateName - DebianPlugin.Names for maintainer scripts and "start" * @param loader - which startup system * @param replacements - default replacements * @param template - if specified, it will override the default one */ - def apply(script: String, - archetype: String, - config: Configuration, - replacements: Seq[(String, String)], - template: Option[URL] = None): Option[String] = { + def apply( + script: String, + archetype: String, + config: Configuration, + replacements: Seq[(String, String)], + template: Option[URL] = None + ): Option[String] = { // use template or else search for a default val url = template orElse { Option(getClass getResource s"$archetype/${config.name}/$script-template") @@ -73,9 +74,11 @@ object JavaServerLoaderScript { * @param script - default is "functions" * @return functions - addService/stopService with resolved variables */ - def loaderFunctionsReplacement(loader: ServerLoader, - archetype: String, - script: String = LOADER_FUNCTIONS): (String, String) = { + def loaderFunctionsReplacement( + loader: ServerLoader, + archetype: String, + script: String = LOADER_FUNCTIONS + ): (String, String) = { val source = getClass.getResource(templatePath(script, loader, archetype)) LOADER_FUNCTIONS -> TemplateWriter.generateScript(source, Nil) } diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/MaintainerScriptHelper.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/MaintainerScriptHelper.scala index 092c2644e..6319422b9 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/MaintainerScriptHelper.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/MaintainerScriptHelper.scala @@ -58,7 +58,6 @@ trait MaintainerScriptHelper { * ) * }}} * - * * @param current maintainer scripts * @param replacements (e.g. (linuxScriptReplacements in Debian).value) * @param scripts scriptName -> scriptContent pairs @@ -88,7 +87,6 @@ trait MaintainerScriptHelper { * ) * }}} * - * * @param current maintainer scripts * @param scripts scriptName -> scriptFile pairs * @return maintainerScripts with appended `scripts` diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/TemplateWriter.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/TemplateWriter.scala index f56decc02..2a5540612 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/TemplateWriter.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/TemplateWriter.scala @@ -39,10 +39,12 @@ object TemplateWriter { keySurround(key).r.replaceAllIn(line, java.util.regex.Matcher.quoteReplacement(value)) } - private def replaceValues(lines: Seq[String], - replacements: Seq[(String, String)], - eol: String, - keySurround: String => String): String = { + private def replaceValues( + lines: Seq[String], + replacements: Seq[(String, String)], + eol: String, + keySurround: String => String + ): String = { val sb = new StringBuilder for (line <- lines) { sb append replace(line, replacements, keySurround) @@ -51,25 +53,31 @@ object TemplateWriter { sb toString } - private[this] def replaceValues(lines: Seq[String], - replacements: Seq[(String, String)], - keySurround: String => String): Seq[String] = + private[this] def replaceValues( + lines: Seq[String], + replacements: Seq[(String, String)], + keySurround: String => String + ): Seq[String] = lines.map(line => replace(line, replacements, keySurround)) - def generateScript(source: java.net.URL, - replacements: Seq[(String, String)], - eol: String = "\n", - keySurround: String => String = bashFriendlyKeySurround, - charset: java.nio.charset.Charset = defaultCharset): String = { + def generateScript( + source: java.net.URL, + replacements: Seq[(String, String)], + eol: String = "\n", + keySurround: String => String = bashFriendlyKeySurround, + charset: java.nio.charset.Charset = defaultCharset + ): String = { val lines = sbt.IO.readLinesURL(source, charset) replaceValues(lines, replacements, eol, keySurround) } - def generateScriptFromString(source: String, - replacements: Seq[(String, String)], - eol: String = "\n", - keySurround: String => String = bashFriendlyKeySurround, - charset: java.nio.charset.Charset = defaultCharset): String = + def generateScriptFromString( + source: String, + replacements: Seq[(String, String)], + eol: String = "\n", + keySurround: String => String = bashFriendlyKeySurround, + charset: java.nio.charset.Charset = defaultCharset + ): String = replaceValues(source split eol, replacements, eol, keySurround) /** @@ -78,9 +86,11 @@ object TemplateWriter { * @param keySurround defaults to bashFriendlyKeySurround * @param charset defaults to UTF-8 */ - def generateScriptFromLines(lines: Seq[String], - replacements: Seq[(String, String)], - keySurround: String => String = bashFriendlyKeySurround, - charset: java.nio.charset.Charset = defaultCharset): Seq[String] = + def generateScriptFromLines( + lines: Seq[String], + replacements: Seq[(String, String)], + keySurround: String => String = bashFriendlyKeySurround, + charset: java.nio.charset.Charset = defaultCharset + ): Seq[String] = replaceValues(lines, replacements, keySurround) } diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/jlink/JlinkPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/jlink/JlinkPlugin.scala index 6ceeea2fc..5c34e2cc4 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/jlink/JlinkPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/jlink/JlinkPlugin.scala @@ -70,16 +70,17 @@ object JlinkPlugin extends AutoPlugin { } .getOrElse(sys.error("JAVA_VERSION not found in ${releaseFile.getAbsolutePath}")) - val modulePathOpts = if (modulePath.nonEmpty) { - Vector("--module-path", modulePath.mkString(":")) - } else Vector.empty + val modulePathOpts = + if (modulePath.nonEmpty) + Vector("--module-path", modulePath.mkString(":")) + else Vector.empty // Jdeps has a few convenient options (like --print-module-deps), but those // are not flexible enough - we need to parse the full output. val jdepsOutput = run("jdeps", "--multi-release" +: javaVersion +: modulePathOpts ++: "-R" +: paths) val deps = jdepsOutput.linesIterator - // There are headers in some of the lines - ignore those. + // There are headers in some of the lines - ignore those. .flatMap(PackageDependency.parse(_).iterator) .toSeq @@ -133,9 +134,8 @@ object JlinkPlugin extends AutoPlugin { jlinkOptions ++= { val modules = jlinkModules.value - if (modules.isEmpty) { + if (modules.isEmpty) sys.error("jlinkModules is empty") - } JlinkOptions( addModules = modules, @@ -238,17 +238,18 @@ object JlinkPlugin extends AutoPlugin { sealed trait Source object Source { - def parse(s: String): Source = s match { - case "not found" => NotFound - // We have no foolproof way to separate jars from modules here, so - // we have to do something flaky. - case name - if name.toLowerCase.endsWith(".jar") || - !name.contains('.') || - name.contains(' ') => - JarOrDir(name) - case name => Module(name) - } + def parse(s: String): Source = + s match { + case "not found" => NotFound + // We have no foolproof way to separate jars from modules here, so + // we have to do something flaky. + case name + if name.toLowerCase.endsWith(".jar") || + !name.contains('.') || + name.contains(' ') => + JarOrDir(name) + case name => Module(name) + } } case object NotFound extends Source @@ -273,11 +274,12 @@ object JlinkPlugin extends AutoPlugin { // foo.jar -> not found private val pattern = """^\s+([^\s]+)\s+->\s+([^\s]+)\s+([^\s].*?)\s*$""".r - def parse(s: String): Option[PackageDependency] = s match { - case pattern(dependent, dependee, source) => - Some(PackageDependency(dependent, dependee, Source.parse(source))) - case _ => None - } + def parse(s: String): Option[PackageDependency] = + s match { + case pattern(dependent, dependee, source) => + Some(PackageDependency(dependent, dependee, Source.parse(source))) + case _ => None + } } object Ignore { diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/ApplicationIniGenerator.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/ApplicationIniGenerator.scala index 39a025746..8bb7f1a44 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/ApplicationIniGenerator.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/ApplicationIniGenerator.scala @@ -10,11 +10,13 @@ trait ApplicationIniGenerator { * @return the existing mappings plus a generated application.ini * if custom javaOptions are specified */ - def generateApplicationIni(universalMappings: Seq[(File, String)], - javaOptions: Seq[String], - bashScriptConfigLocation: Option[String], - tmpDir: File, - log: Logger): Seq[(File, String)] = + def generateApplicationIni( + universalMappings: Seq[(File, String)], + javaOptions: Seq[String], + bashScriptConfigLocation: Option[String], + tmpDir: File, + log: Logger + ): Seq[(File, String)] = bashScriptConfigLocation .collect { case location if javaOptions.nonEmpty => diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/AshScriptPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/AshScriptPlugin.scala index fe6cf4f85..5987410bc 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/AshScriptPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/AshScriptPlugin.scala @@ -57,7 +57,6 @@ import sbt._ * * java -classpath $app_classpath $app_mainclass $@ * - * * == Configuration == * * This plugin adds new settings to configure your packaged application. @@ -75,15 +74,16 @@ object AshScriptPlugin extends AutoPlugin { val ashTemplate = "ash-template" - override def projectSettings = Seq( - bashScriptTemplateLocation := (sourceDirectory.value / "templates" / ashTemplate), - bashScriptDefines := Defines( - (scriptClasspath in bashScriptDefines).value, - bashScriptConfigLocation.value, - bundledJvmLocation.value - ), - bashScriptDefines ++= bashScriptExtraDefines.value - ) + override def projectSettings = + Seq( + bashScriptTemplateLocation := (sourceDirectory.value / "templates" / ashTemplate), + bashScriptDefines := Defines( + (scriptClasspath in bashScriptDefines).value, + bashScriptConfigLocation.value, + bundledJvmLocation.value + ), + bashScriptDefines ++= bashScriptExtraDefines.value + ) /** * Ash defines diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/BashStartScriptPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/BashStartScriptPlugin.scala index b45e312a6..cfcebcd21 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/BashStartScriptPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/BashStartScriptPlugin.scala @@ -13,7 +13,6 @@ import sbt._ * * This plugins creates a start bash script to run an application built with the * [[com.typesafe.sbt.packager.archetypes.JavaAppPackaging]]. - * */ object BashStartScriptPlugin extends AutoPlugin with ApplicationIniGenerator with CommonStartScriptGenerator { @@ -42,51 +41,53 @@ object BashStartScriptPlugin extends AutoPlugin with ApplicationIniGenerator wit object autoImport extends BashStartScriptKeys - protected[this] case class BashScriptConfig(override val executableScriptName: String, - override val scriptClasspath: Seq[String], - override val replacements: Seq[(String, String)], - override val templateLocation: File) - extends ScriptConfig { + protected[this] case class BashScriptConfig( + override val executableScriptName: String, + override val scriptClasspath: Seq[String], + override val replacements: Seq[(String, String)], + override val templateLocation: File + ) extends ScriptConfig { override def withScriptName(scriptName: String): BashScriptConfig = copy(executableScriptName = scriptName) } override protected[this] type SpecializedScriptConfig = BashScriptConfig - override def projectSettings: Seq[Setting[_]] = Seq( - bashScriptTemplateLocation := (sourceDirectory.value / "templates" / bashTemplate), - bashScriptExtraDefines := Nil, - bashScriptDefines := Defines( - (scriptClasspath in bashScriptDefines).value, - bashScriptConfigLocation.value, - bundledJvmLocation.value - ), - bashScriptDefines ++= bashScriptExtraDefines.value, - bashScriptReplacements := generateScriptReplacements(bashScriptDefines.value), - // Create a bashConfigLocation if options are set in build.sbt - bashScriptConfigLocation := (bashScriptConfigLocation ?? Some(appIniLocation)).value, - bashScriptEnvConfigLocation := (bashScriptEnvConfigLocation ?? None).value, - // Generating the application configuration - mappings in Universal := generateApplicationIni( - (mappings in Universal).value, - (javaOptions in Universal).value, - bashScriptConfigLocation.value, - (target in Universal).value, - streams.value.log - ), - makeBashScripts := generateStartScripts( - BashScriptConfig( - executableScriptName = executableScriptName.value, - scriptClasspath = (scriptClasspath in bashScriptDefines).value, - replacements = bashScriptReplacements.value, - templateLocation = bashScriptTemplateLocation.value + override def projectSettings: Seq[Setting[_]] = + Seq( + bashScriptTemplateLocation := (sourceDirectory.value / "templates" / bashTemplate), + bashScriptExtraDefines := Nil, + bashScriptDefines := Defines( + (scriptClasspath in bashScriptDefines).value, + bashScriptConfigLocation.value, + bundledJvmLocation.value + ), + bashScriptDefines ++= bashScriptExtraDefines.value, + bashScriptReplacements := generateScriptReplacements(bashScriptDefines.value), + // Create a bashConfigLocation if options are set in build.sbt + bashScriptConfigLocation := (bashScriptConfigLocation ?? Some(appIniLocation)).value, + bashScriptEnvConfigLocation := (bashScriptEnvConfigLocation ?? None).value, + // Generating the application configuration + mappings in Universal := generateApplicationIni( + (mappings in Universal).value, + (javaOptions in Universal).value, + bashScriptConfigLocation.value, + (target in Universal).value, + streams.value.log + ), + makeBashScripts := generateStartScripts( + BashScriptConfig( + executableScriptName = executableScriptName.value, + scriptClasspath = (scriptClasspath in bashScriptDefines).value, + replacements = bashScriptReplacements.value, + templateLocation = bashScriptTemplateLocation.value + ), + (mainClass in (Compile, bashScriptDefines)).value, + (discoveredMainClasses in Compile).value, + (target in Universal).value / "scripts", + streams.value.log ), - (mainClass in (Compile, bashScriptDefines)).value, - (discoveredMainClasses in Compile).value, - (target in Universal).value / "scripts", - streams.value.log - ), - mappings in Universal ++= makeBashScripts.value - ) + mappings in Universal ++= makeBashScripts.value + ) private[this] def generateScriptReplacements(defines: Seq[String]): Seq[(String, String)] = { val defineString = defines mkString "\n" @@ -142,8 +143,13 @@ object BashStartScriptPlugin extends AutoPlugin with ApplicationIniGenerator wit else "" - override protected[this] def createReplacementsForMainScript(mainClass: String, - mainClasses: Seq[String], - config: SpecializedScriptConfig): Seq[(String, String)] = - Seq("app_mainclass" -> mainClass, "available_main_classes" -> usageMainClassReplacement(mainClasses)) ++ config.replacements + override protected[this] def createReplacementsForMainScript( + mainClass: String, + mainClasses: Seq[String], + config: SpecializedScriptConfig + ): Seq[(String, String)] = + Seq( + "app_mainclass" -> mainClass, + "available_main_classes" -> usageMainClassReplacement(mainClasses) + ) ++ config.replacements } diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/BatStartScriptPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/BatStartScriptPlugin.scala index 916b7e611..7414cc7e9 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/BatStartScriptPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/BatStartScriptPlugin.scala @@ -14,7 +14,6 @@ import sbt._ * * This plugins creates a start bat script to run an application built with the * [[com.typesafe.sbt.packager.archetypes.JavaAppPackaging]]. - * */ object BatStartScriptPlugin extends AutoPlugin with ApplicationIniGenerator with CommonStartScriptGenerator { @@ -44,31 +43,36 @@ object BatStartScriptPlugin extends AutoPlugin with ApplicationIniGenerator with object autoImport extends BatStartScriptKeys import autoImport._ - protected[this] case class BatScriptConfig(override val executableScriptName: String, - override val scriptClasspath: Seq[String], - configLocation: Option[String], - extraDefines: Seq[String], - override val replacements: Seq[(String, String)], - override val templateLocation: File, - bundledJvmLocation: Option[String]) - extends ScriptConfig { + protected[this] case class BatScriptConfig( + override val executableScriptName: String, + override val scriptClasspath: Seq[String], + configLocation: Option[String], + extraDefines: Seq[String], + override val replacements: Seq[(String, String)], + override val templateLocation: File, + bundledJvmLocation: Option[String] + ) extends ScriptConfig { @deprecated("1.3.21", "") - def this(executableScriptName: String, - scriptClasspath: Seq[String], - configLocation: Option[String], - extraDefines: Seq[String], - replacements: Seq[(String, String)], - templateLocation: File) = + def this( + executableScriptName: String, + scriptClasspath: Seq[String], + configLocation: Option[String], + extraDefines: Seq[String], + replacements: Seq[(String, String)], + templateLocation: File + ) = this(executableScriptName, scriptClasspath, configLocation, extraDefines, replacements, templateLocation, None) @deprecated("1.3.21", "") - def copy(executableScriptName: String = executableScriptName, - scriptClasspath: Seq[String] = scriptClasspath, - configLocation: Option[String] = configLocation, - extraDefines: Seq[String] = extraDefines, - replacements: Seq[(String, String)] = replacements, - templateLocation: File = templateLocation): BatScriptConfig = + def copy( + executableScriptName: String = executableScriptName, + scriptClasspath: Seq[String] = scriptClasspath, + configLocation: Option[String] = configLocation, + extraDefines: Seq[String] = extraDefines, + replacements: Seq[(String, String)] = replacements, + templateLocation: File = templateLocation + ): BatScriptConfig = BatScriptConfig( executableScriptName, scriptClasspath, @@ -83,15 +87,19 @@ object BatStartScriptPlugin extends AutoPlugin with ApplicationIniGenerator with } object BatScriptConfig - extends scala.runtime.AbstractFunction6[String, Seq[String], Option[String], Seq[String], Seq[(String, String)], File, BatScriptConfig] { + extends scala.runtime.AbstractFunction6[String, Seq[String], Option[String], Seq[String], Seq[ + (String, String) + ], File, BatScriptConfig] { @deprecated("1.3.21", "") - def apply(executableScriptName: String, - scriptClasspath: Seq[String], - configLocation: Option[String], - extraDefines: Seq[String], - replacements: Seq[(String, String)], - templateLocation: File): BatScriptConfig = + def apply( + executableScriptName: String, + scriptClasspath: Seq[String], + configLocation: Option[String], + extraDefines: Seq[String], + replacements: Seq[(String, String)], + templateLocation: File + ): BatScriptConfig = BatScriptConfig( executableScriptName, scriptClasspath, @@ -106,36 +114,37 @@ object BatStartScriptPlugin extends AutoPlugin with ApplicationIniGenerator with override protected[this] type SpecializedScriptConfig = BatScriptConfig - override def projectSettings: Seq[Setting[_]] = Seq( - batScriptTemplateLocation := (sourceDirectory.value / "templates" / batTemplate), - batScriptConfigLocation := (batScriptConfigLocation ?? Some(appIniLocation)).value, - batScriptExtraDefines := Nil, - batScriptReplacements := Replacements(executableScriptName.value), - // Generating the application configuration - mappings in Universal := generateApplicationIni( - (mappings in Universal).value, - (javaOptions in Universal).value, - batScriptConfigLocation.value, - (target in Universal).value, - streams.value.log - ), - makeBatScripts := generateStartScripts( - BatScriptConfig( - executableScriptName = executableScriptName.value, - scriptClasspath = (scriptClasspath in batScriptReplacements).value, - configLocation = batScriptConfigLocation.value, - extraDefines = batScriptExtraDefines.value, - replacements = batScriptReplacements.value, - templateLocation = batScriptTemplateLocation.value, - bundledJvmLocation = bundledJvmLocation.value + override def projectSettings: Seq[Setting[_]] = + Seq( + batScriptTemplateLocation := (sourceDirectory.value / "templates" / batTemplate), + batScriptConfigLocation := (batScriptConfigLocation ?? Some(appIniLocation)).value, + batScriptExtraDefines := Nil, + batScriptReplacements := Replacements(executableScriptName.value), + // Generating the application configuration + mappings in Universal := generateApplicationIni( + (mappings in Universal).value, + (javaOptions in Universal).value, + batScriptConfigLocation.value, + (target in Universal).value, + streams.value.log + ), + makeBatScripts := generateStartScripts( + BatScriptConfig( + executableScriptName = executableScriptName.value, + scriptClasspath = (scriptClasspath in batScriptReplacements).value, + configLocation = batScriptConfigLocation.value, + extraDefines = batScriptExtraDefines.value, + replacements = batScriptReplacements.value, + templateLocation = batScriptTemplateLocation.value, + bundledJvmLocation = bundledJvmLocation.value + ), + (mainClass in (Compile, batScriptReplacements)).value, + (discoveredMainClasses in Compile).value, + (target in Universal).value / "scripts", + streams.value.log ), - (mainClass in (Compile, batScriptReplacements)).value, - (discoveredMainClasses in Compile).value, - (target in Universal).value / "scripts", - streams.value.log - ), - mappings in Universal ++= makeBatScripts.value - ) + mappings in Universal ++= makeBatScripts.value + ) /** * @param path that could be relative to APP_HOME @@ -152,9 +161,11 @@ object BatStartScriptPlugin extends AutoPlugin with ApplicationIniGenerator with def apply(name: String): Seq[(String, String)] = Seq("APP_NAME" -> name, "APP_ENV_NAME" -> NameHelper.makeEnvFriendlyName(name)) - def appDefines(mainClass: String, - config: BatScriptConfig, - replacements: Seq[(String, String)]): (String, String) = { + def appDefines( + mainClass: String, + config: BatScriptConfig, + replacements: Seq[(String, String)] + ): (String, String) = { val defines = Seq(makeWindowsRelativeClasspathDefine(config.scriptClasspath), Defines.mainClass(mainClass)) ++ config.configLocation.map(Defines.configFileDefine) ++ config.bundledJvmLocation.map(Defines.bundledJvmDefine) ++ @@ -196,9 +207,11 @@ object BatStartScriptPlugin extends AutoPlugin with ApplicationIniGenerator with } } - override protected[this] def createReplacementsForMainScript(mainClass: String, - mainClasses: Seq[String], - config: SpecializedScriptConfig): Seq[(String, String)] = + override protected[this] def createReplacementsForMainScript( + mainClass: String, + mainClasses: Seq[String], + config: SpecializedScriptConfig + ): Seq[(String, String)] = config.replacements :+ Replacements.appDefines(mainClass, config, config.replacements) } diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/CommonStartScriptGenerator.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/CommonStartScriptGenerator.scala index c55a58cc8..436d45de6 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/CommonStartScriptGenerator.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/CommonStartScriptGenerator.scala @@ -39,9 +39,11 @@ trait CommonStartScriptGenerator { */ protected[this] val executableBitValue: Boolean - protected[this] def createReplacementsForMainScript(mainClass: String, - mainClasses: Seq[String], - config: SpecializedScriptConfig): Seq[(String, String)] + protected[this] def createReplacementsForMainScript( + mainClass: String, + mainClasses: Seq[String], + config: SpecializedScriptConfig + ): Seq[(String, String)] protected[this] trait ScriptConfig { val executableScriptName: String @@ -59,11 +61,13 @@ trait CommonStartScriptGenerator { */ protected[this] type SpecializedScriptConfig <: ScriptConfig - protected[this] def generateStartScripts(config: SpecializedScriptConfig, - mainClass: Option[String], - discoveredMainClasses: Seq[String], - targetDir: File, - log: sbt.Logger): Seq[(File, String)] = + protected[this] def generateStartScripts( + config: SpecializedScriptConfig, + mainClass: Option[String], + discoveredMainClasses: Seq[String], + targetDir: File, + log: sbt.Logger + ): Seq[(File, String)] = StartScriptMainClassConfig.from(mainClass, discoveredMainClasses) match { case NoMain => log.warn("You have no main class in your project. No start script will be generated.") @@ -77,10 +81,12 @@ trait CommonStartScriptGenerator { createForwarderScripts(config.executableScriptName, additional, targetDir, config, log) } - private[this] def generateMainScripts(discoveredMainClasses: Seq[String], - config: SpecializedScriptConfig, - targetDir: File, - log: sbt.Logger): Seq[(File, String)] = { + private[this] def generateMainScripts( + discoveredMainClasses: Seq[String], + config: SpecializedScriptConfig, + targetDir: File, + log: sbt.Logger + ): Seq[(File, String)] = { val classAndScriptNames = ScriptUtils.createScriptNames(discoveredMainClasses) ScriptUtils.warnOnScriptNameCollision(classAndScriptNames, log) classAndScriptNames.map { @@ -94,16 +100,17 @@ trait CommonStartScriptGenerator { config.executableScriptName + scriptSuffix /** - * * @param mainClass - Main class added to the java command * @param config - Config data for this script * @param targetDir - Target directory for this script * @return File pointing to the created main script */ - private[this] def createMainScript(mainClass: String, - config: SpecializedScriptConfig, - targetDir: File, - mainClasses: Seq[String]): (File, String) = { + private[this] def createMainScript( + mainClass: String, + config: SpecializedScriptConfig, + targetDir: File, + mainClasses: Seq[String] + ): (File, String) = { val template = resolveTemplate(config.templateLocation) val replacements = createReplacementsForMainScript(mainClass, mainClasses, config) val scriptContent = TemplateWriter.generateScript(template, replacements, eol, keySurround) @@ -120,11 +127,13 @@ trait CommonStartScriptGenerator { if (defaultTemplateLocation.exists) defaultTemplateLocation.toURI.toURL else getClass.getResource(defaultTemplateLocation.getName) - private[this] def createForwarderScripts(executableScriptName: String, - discoveredMainClasses: Seq[String], - targetDir: File, - config: ScriptConfig, - log: sbt.Logger): Seq[(File, String)] = { + private[this] def createForwarderScripts( + executableScriptName: String, + discoveredMainClasses: Seq[String], + targetDir: File, + config: ScriptConfig, + log: sbt.Logger + ): Seq[(File, String)] = { val tmp = targetDir / scriptTargetFolder val forwarderTemplate = getClass.getResource(forwarderTemplateName) val classAndScriptNames = ScriptUtils.createScriptNames(discoveredMainClasses) diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/ScriptUtils.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/ScriptUtils.scala index 14ea90f99..f55f3316d 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/ScriptUtils.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/ScriptUtils.scala @@ -57,11 +57,10 @@ object ScriptUtils { def warnOnScriptNameCollision(classesAndScripts: Seq[(String, String)], log: sbt.Logger): Unit = { val duplicates = describeDuplicates(classesAndScripts) - if (duplicates.nonEmpty) { + if (duplicates.nonEmpty) log.warn( s"The resulting zip seems to contain duplicated script names for these classes: ${duplicates.mkString(", ")}" ) - } } /** @@ -74,30 +73,31 @@ object ScriptUtils { */ def toLowerCase(qualifiedClassName: String): String = { // suppose list is not very huge, so no need in tail recursion - def split(chars: List[Char]): List[Char] = chars match { - case c1 :: c2 :: cs if c1.isLower && c2.isUpper => - // aClass -> a-Class - // anUITest -> an-UITest - // ^ - c1 :: '-' :: split(c2 :: cs) - case c1 :: c2 :: c3 :: cs if c1.isUpper && c2.isUpper && c3.isLower => - // UITest -> UI-Test - // ^ - c1 :: '-' :: split(c2 :: c3 :: cs) - case c1 :: c2 :: cs if c1.isLetter && c2.isDigit => - // Test1 -> Test-1 - // ^ - c1 :: '-' :: split(c2 :: cs) - case c1 :: c2 :: cs if c1.isDigit && c2.isLetter => - // Test1Class -> Test-1-Class - // ^ ^ - // _not_ pkg1.Test - // ^ - c1 :: '-' :: split(c2 :: cs) - case c :: cs => - c :: split(cs) - case Nil => Nil - } + def split(chars: List[Char]): List[Char] = + chars match { + case c1 :: c2 :: cs if c1.isLower && c2.isUpper => + // aClass -> a-Class + // anUITest -> an-UITest + // ^ + c1 :: '-' :: split(c2 :: cs) + case c1 :: c2 :: c3 :: cs if c1.isUpper && c2.isUpper && c3.isLower => + // UITest -> UI-Test + // ^ + c1 :: '-' :: split(c2 :: c3 :: cs) + case c1 :: c2 :: cs if c1.isLetter && c2.isDigit => + // Test1 -> Test-1 + // ^ + c1 :: '-' :: split(c2 :: cs) + case c1 :: c2 :: cs if c1.isDigit && c2.isLetter => + // Test1Class -> Test-1-Class + // ^ ^ + // _not_ pkg1.Test + // ^ + c1 :: '-' :: split(c2 :: cs) + case c :: cs => + c :: split(cs) + case Nil => Nil + } val sb = new StringBuilder sb ++= split(qualifiedClassName.toList).map(_.toLower) sb.result() diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/StartScriptMainClassConfig.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/StartScriptMainClassConfig.scala index d917be4a7..f8cf50202 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/StartScriptMainClassConfig.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/StartScriptMainClassConfig.scala @@ -35,7 +35,6 @@ case class ExplicitMainWithAdditional(mainClass: String, additional: Seq[String] object StartScriptMainClassConfig { /** - * * @param mainClass optional main class, e.g. from (mainClass in Compile).value * @param discoveredMainClasses all discovered main classes, e.g. from (discoveredMainClasses in Compile).value * @return A start script configuration diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemVPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemVPlugin.scala index 232c0d2fc..a97536731 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemVPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemVPlugin.scala @@ -28,25 +28,26 @@ object SystemVPlugin extends AutoPlugin { inConfig(Debian)(systemVSettings) ++ debianSettings ++ inConfig(Rpm)(systemVSettings) ++ rpmSettings - def systemVSettings: Seq[Setting[_]] = Seq( - // used by other archetypes to define systemloader dependent behaviour - serverLoading := Some(ServerLoader.SystemV), - // Systemd settings - startRunlevels := Some("2 3 4 5"), - stopRunlevels := Some("0 1 6"), - requiredStartFacilities := Some("$remote_fs $syslog"), - requiredStopFacilities := Some("$remote_fs $syslog"), - defaultLinuxStartScriptLocation := "/etc/init.d", - termTimeout := 60, - killTimeout := 30, - // add systemloader to mappings and override the isConf setting - linuxPackageMappings ++= startScriptMapping( - linuxStartScriptName.value, - linuxMakeStartScript.value, - defaultLinuxStartScriptLocation.value, - isConf = false + def systemVSettings: Seq[Setting[_]] = + Seq( + // used by other archetypes to define systemloader dependent behaviour + serverLoading := Some(ServerLoader.SystemV), + // Systemd settings + startRunlevels := Some("2 3 4 5"), + stopRunlevels := Some("0 1 6"), + requiredStartFacilities := Some("$remote_fs $syslog"), + requiredStopFacilities := Some("$remote_fs $syslog"), + defaultLinuxStartScriptLocation := "/etc/init.d", + termTimeout := 60, + killTimeout := 30, + // add systemloader to mappings and override the isConf setting + linuxPackageMappings ++= startScriptMapping( + linuxStartScriptName.value, + linuxMakeStartScript.value, + defaultLinuxStartScriptLocation.value, + isConf = false + ) ) - ) def debianSettings: Seq[Setting[_]] = inConfig(Debian)( diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemdPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemdPlugin.scala index 8a060e25d..7a6a28307 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemdPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemdPlugin.scala @@ -43,28 +43,29 @@ object SystemdPlugin extends AutoPlugin { override def projectSettings: Seq[Setting[_]] = debianSettings ++ inConfig(Debian)(systemdSettings) ++ rpmSettings ++ inConfig(Rpm)(systemdSettings) - def systemdSettings: Seq[Setting[_]] = Seq( - // used by other archetypes to define systemloader dependent behaviour - serverLoading := Some(ServerLoader.Systemd), - // Systemd settings - startRunlevels := None, - stopRunlevels := None, - requiredStartFacilities := Some("network.target"), - requiredStopFacilities := Some("network.target"), - systemdSuccessExitStatus := Seq.empty, - linuxStartScriptName := Some(packageName.value + ".service"), - systemdIsServiceFileConfig := true, - // add systemloader to mappings - linuxPackageMappings ++= startScriptMapping( - linuxStartScriptName.value, - linuxMakeStartScript.value, - defaultLinuxStartScriptLocation.value, - systemdIsServiceFileConfig.value - ), - // add additional system configurations to script replacements - linuxScriptReplacements += ("SuccessExitStatus" -> systemdSuccessExitStatus.value.mkString(" ")), - linuxScriptReplacements += ("TimeoutStopSec" -> killTimeout.value.toString) - ) + def systemdSettings: Seq[Setting[_]] = + Seq( + // used by other archetypes to define systemloader dependent behaviour + serverLoading := Some(ServerLoader.Systemd), + // Systemd settings + startRunlevels := None, + stopRunlevels := None, + requiredStartFacilities := Some("network.target"), + requiredStopFacilities := Some("network.target"), + systemdSuccessExitStatus := Seq.empty, + linuxStartScriptName := Some(packageName.value + ".service"), + systemdIsServiceFileConfig := true, + // add systemloader to mappings + linuxPackageMappings ++= startScriptMapping( + linuxStartScriptName.value, + linuxMakeStartScript.value, + defaultLinuxStartScriptLocation.value, + systemdIsServiceFileConfig.value + ), + // add additional system configurations to script replacements + linuxScriptReplacements += ("SuccessExitStatus" -> systemdSuccessExitStatus.value.mkString(" ")), + linuxScriptReplacements += ("TimeoutStopSec" -> killTimeout.value.toString) + ) def debianSettings: Seq[Setting[_]] = inConfig(Debian)(defaultLinuxStartScriptLocation := "/lib/systemd/system") diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemloaderPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemloaderPlugin.scala index cf10b363f..b689ec5d8 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemloaderPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/SystemloaderPlugin.scala @@ -47,39 +47,40 @@ object SystemloaderPlugin extends AutoPlugin { inConfig(Debian)(systemloaderSettings) ++ debianSettings ++ inConfig(Rpm)(systemloaderSettings) ++ rpmSettings - def systemloaderSettings: Seq[Setting[_]] = Seq( - serverLoading := None, - serviceAutostart := true, - linuxStartScriptName := Some(packageName.value), - // defaults, may be override by concrete systemloader - retries := 0, - retryTimeout := 60, - killTimeout := 5, - termTimeout := 5, - // add loader-functions to script replacements - linuxScriptReplacements += loaderFunctionsReplacement(sourceDirectory.value, serverLoading.value), - linuxScriptReplacements ++= makeStartScriptReplacements( - requiredStartFacilities = requiredStartFacilities.value, - requiredStopFacilities = requiredStopFacilities.value, - startRunlevels = startRunlevels.value, - stopRunlevels = stopRunlevels.value, - termTimeout = termTimeout.value, - killTimeout = killTimeout.value, - retries = retries.value, - retryTimeout = retryTimeout.value, - loader = serverLoading.value - ), - // set the template - linuxStartScriptTemplate := linuxStartScriptUrl(sourceDirectory.value, serverLoading.value), - // define task to generate the systemloader script - linuxMakeStartScript := makeStartScript( - linuxStartScriptTemplate.value, - linuxScriptReplacements.value, - (target in Universal).value, - defaultLinuxStartScriptLocation.value, - linuxStartScriptName.value.getOrElse(sys.error("`linuxStartScriptName` is not defined")) + def systemloaderSettings: Seq[Setting[_]] = + Seq( + serverLoading := None, + serviceAutostart := true, + linuxStartScriptName := Some(packageName.value), + // defaults, may be override by concrete systemloader + retries := 0, + retryTimeout := 60, + killTimeout := 5, + termTimeout := 5, + // add loader-functions to script replacements + linuxScriptReplacements += loaderFunctionsReplacement(sourceDirectory.value, serverLoading.value), + linuxScriptReplacements ++= makeStartScriptReplacements( + requiredStartFacilities = requiredStartFacilities.value, + requiredStopFacilities = requiredStopFacilities.value, + startRunlevels = startRunlevels.value, + stopRunlevels = stopRunlevels.value, + termTimeout = termTimeout.value, + killTimeout = killTimeout.value, + retries = retries.value, + retryTimeout = retryTimeout.value, + loader = serverLoading.value + ), + // set the template + linuxStartScriptTemplate := linuxStartScriptUrl(sourceDirectory.value, serverLoading.value), + // define task to generate the systemloader script + linuxMakeStartScript := makeStartScript( + linuxStartScriptTemplate.value, + linuxScriptReplacements.value, + (target in Universal).value, + defaultLinuxStartScriptLocation.value, + linuxStartScriptName.value.getOrElse(sys.error("`linuxStartScriptName` is not defined")) + ) ) - ) def addAndStartService(autostart: Boolean, pad: String = ""): String = { val addService = @@ -138,15 +139,17 @@ object SystemloaderPlugin extends AutoPlugin { ) ) - private[this] def makeStartScriptReplacements(requiredStartFacilities: Option[String], - requiredStopFacilities: Option[String], - startRunlevels: Option[String], - stopRunlevels: Option[String], - termTimeout: Int, - killTimeout: Int, - retries: Int, - retryTimeout: Int, - loader: Option[ServerLoader]): Seq[(String, String)] = { + private[this] def makeStartScriptReplacements( + requiredStartFacilities: Option[String], + requiredStopFacilities: Option[String], + startRunlevels: Option[String], + stopRunlevels: Option[String], + termTimeout: Int, + killTimeout: Int, + retries: Int, + retryTimeout: Int, + loader: Option[ServerLoader] + ): Seq[(String, String)] = { // Upstart cannot handle empty values val (startOn, stopOn) = loader match { diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/UpstartPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/UpstartPlugin.scala index 4deeb7f33..258bfc1c3 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/UpstartPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/UpstartPlugin.scala @@ -30,24 +30,25 @@ object UpstartPlugin extends AutoPlugin { override def projectSettings: Seq[Setting[_]] = inConfig(Debian)(upstartSettings) ++ inConfig(Rpm)(upstartSettings) - def upstartSettings: Seq[Setting[_]] = Seq( - // used by other archetypes to define systemloader dependent behaviour - serverLoading := Some(ServerLoader.Upstart), - // Upstart settings - startRunlevels := Some("[2345]"), - stopRunlevels := Some("[016]"), - requiredStartFacilities := None, - requiredStopFacilities := None, - defaultLinuxStartScriptLocation := "/etc/init", - killTimeout := 5, - linuxStartScriptName := Some(packageName.value + ".conf"), - // add systemloader to mappings - linuxPackageMappings ++= startScriptMapping( - linuxStartScriptName.value, - linuxMakeStartScript.value, - defaultLinuxStartScriptLocation.value, - isConf = true + def upstartSettings: Seq[Setting[_]] = + Seq( + // used by other archetypes to define systemloader dependent behaviour + serverLoading := Some(ServerLoader.Upstart), + // Upstart settings + startRunlevels := Some("[2345]"), + stopRunlevels := Some("[016]"), + requiredStartFacilities := None, + requiredStopFacilities := None, + defaultLinuxStartScriptLocation := "/etc/init", + killTimeout := 5, + linuxStartScriptName := Some(packageName.value + ".conf"), + // add systemloader to mappings + linuxPackageMappings ++= startScriptMapping( + linuxStartScriptName.value, + linuxMakeStartScript.value, + defaultLinuxStartScriptLocation.value, + isConf = true + ) ) - ) } diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/package.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/package.scala index bfe56b64a..1d04e274e 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/package.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/systemloader/package.scala @@ -13,9 +13,11 @@ package object systemloader { private val LOADER_FUNCTIONS = "loader-functions" - def linuxStartScriptUrl(sourceDirectory: File, - loaderOpt: Option[ServerLoader], - name: String = "start-template"): URL = { + def linuxStartScriptUrl( + sourceDirectory: File, + loaderOpt: Option[ServerLoader], + name: String = "start-template" + ): URL = { val loader = loaderOpt.getOrElse( sys.error("No serverLoader defined. Enable a systemloader, e.g. with `enablePlugins(UpstartPlugin)`") ) @@ -33,11 +35,13 @@ package object systemloader { replacement.getOrElse(sys.error(s"Loader functions could not be loaded for ${loaderOpt}")) } - def makeStartScript(template: URL, - replacements: Seq[(String, String)], - target: File, - path: String, - name: String): Option[File] = { + def makeStartScript( + template: URL, + replacements: Seq[(String, String)], + target: File, + path: String, + name: String + ): Option[File] = { val scriptBits = TemplateWriter generateScript (template, replacements) val script = target / "tmp" / path / name IO.write(script, scriptBits) @@ -51,10 +55,12 @@ package object systemloader { * @param location - target destination from `defaultLinuxStartScriptLocation.value` * @param isConf - if the start script should be registered as a config file */ - def startScriptMapping(scriptName: Option[String], - script: Option[File], - location: String, - isConf: Boolean): Seq[LinuxPackageMapping] = { + def startScriptMapping( + scriptName: Option[String], + script: Option[File], + location: String, + isConf: Boolean + ): Seq[LinuxPackageMapping] = { val name = scriptName.getOrElse( sys.error( """No linuxStartScriptName defined. Add `linuxStartScriptName in := Some("name.service")""" diff --git a/src/main/scala/com/typesafe/sbt/packager/debian/DebianMetadata.scala b/src/main/scala/com/typesafe/sbt/packager/debian/DebianMetadata.scala index bb73b56ea..ab02bffe8 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/DebianMetadata.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/DebianMetadata.scala @@ -3,14 +3,16 @@ package com.typesafe.sbt.packager.debian case class PackageInfo(name: String, version: String, maintainer: String, summary: String, description: String) /** Represents package meta used by debian when constructing packages. */ -case class PackageMetaData(info: PackageInfo, - priority: String = "optional", - architecture: String = "all", - section: String = "java", - conflicts: Seq[String] = Seq.empty, - depends: Seq[String] = Seq.empty, - provides: Seq[String] = Seq.empty, - recommends: Seq[String] = Seq.empty) { +case class PackageMetaData( + info: PackageInfo, + priority: String = "optional", + architecture: String = "all", + section: String = "java", + conflicts: Seq[String] = Seq.empty, + depends: Seq[String] = Seq.empty, + provides: Seq[String] = Seq.empty, + recommends: Seq[String] = Seq.empty +) { def makeContent(installSizeEstimate: Long = 0L): String = { // TODO: Pretty print with line wrap. val sb = new StringBuilder diff --git a/src/main/scala/com/typesafe/sbt/packager/debian/DebianNativePackaging.scala b/src/main/scala/com/typesafe/sbt/packager/debian/DebianNativePackaging.scala index 495a97fc7..0c54558cd 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/DebianNativePackaging.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/DebianNativePackaging.scala @@ -21,12 +21,10 @@ import sbt._ *
  • dpkg-genchanges
  • * * - * * @example Enable the plugin in the `build.sbt` * {{{ * enablePlugins(DebianNativePackaging) * }}} - * */ trait DebianNativePackaging extends DebianPluginLike { @@ -61,7 +59,7 @@ trait DebianNativePackaging extends DebianPluginLike { val file = packageBin.value sys.process.Process(Seq("lintian", "-c", "-v", file.getName), Some(file.getParentFile)).! }, - /** Implementation of the actual packaging */ + /** Implementation of the actual packaging */ packageBin := buildPackage( name.value, version.value, @@ -100,12 +98,14 @@ trait DebianNativePackaging extends DebianPluginLike { } } - private[this] def buildPackage(name: String, - version: String, - arch: String, - stageDir: File, - buildOptions: Seq[String], - log: Logger) = { + private[this] def buildPackage( + name: String, + version: String, + arch: String, + stageDir: File, + buildOptions: Seq[String], + log: Logger + ) = { log.info("Building debian package with native implementation") // Make the package. We put this in fakeroot, so we can build the package with root owning files. val archive = archiveFilename(name, version, arch) diff --git a/src/main/scala/com/typesafe/sbt/packager/debian/DebianPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/debian/DebianPlugin.scala index c4597e144..f3a327073 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/DebianPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/DebianPlugin.scala @@ -27,7 +27,6 @@ import scala.util.matching.Regex * {{{ * enablePlugins(DebianPlugin) * }}} - * */ object DebianPlugin extends AutoPlugin with DebianNativePackaging { @@ -71,153 +70,154 @@ object DebianPlugin extends AutoPlugin with DebianNativePackaging { /** * the default debian settings for the debian namespaced settings */ - private def settings = Seq( - /* ==== Debian default settings ==== */ - debianPriority := "optional", - debianSection := "java", - debianPackageConflicts := Seq.empty, - debianPackageDependencies := Seq.empty, - debianPackageProvides := Seq.empty, - debianPackageRecommends := Seq.empty, - debianSignRole := "builder", - target in Debian := target.value / ((name in Debian).value + "-" + (version in Debian).value), - name in Debian := (name in Linux).value, - maintainerScripts in Debian := (maintainerScripts in Linux).value, - packageName in Debian := (packageName in Linux).value, - executableScriptName in Debian := (executableScriptName in Linux).value, - version in Debian := (version in Linux).value, - linuxPackageMappings in Debian := linuxPackageMappings.value, - packageDescription in Debian := (packageDescription in Linux).value, - packageSummary in Debian := (packageSummary in Linux).value, - maintainer in Debian := (maintainer in Linux).value, - validatePackageValidators in Debian := Seq( - nonEmptyMappings((linuxPackageMappings in Debian).value.flatMap(_.mappings)), - filesExist((linuxPackageMappings in Debian).value.flatMap(_.mappings)), - checkMaintainer((maintainer in Debian).value, asWarning = false) - ), - // override the linux sourceDirectory setting - sourceDirectory in Debian := sourceDirectory.value, - /* ==== Debian configuration settings ==== */ - debianControlScriptsDirectory := (sourceDirectory.value / "debian" / Names.DebianMaintainerScripts), - debianMaintainerScripts := Seq.empty, - debianMakePreinstScript := None, - debianMakePrermScript := None, - debianMakePostinstScript := None, - debianMakePostrmScript := None, - debianChangelog := None, - /* === new debian scripts implementation */ - maintainerScripts in Debian := { - val replacements = (linuxScriptReplacements in Debian).value - val scripts = Map( - Names.Prerm -> defaultMaintainerScript(Names.Prerm).toSeq.flatten, - Names.Preinst -> defaultMaintainerScript(Names.Preinst).toSeq.flatten, - Names.Postinst -> defaultMaintainerScript(Names.Postinst).toSeq.flatten, - Names.Postrm -> defaultMaintainerScript(Names.Postrm).toSeq.flatten - ) + private def settings = + Seq( + /* ==== Debian default settings ==== */ + debianPriority := "optional", + debianSection := "java", + debianPackageConflicts := Seq.empty, + debianPackageDependencies := Seq.empty, + debianPackageProvides := Seq.empty, + debianPackageRecommends := Seq.empty, + debianSignRole := "builder", + target in Debian := target.value / ((name in Debian).value + "-" + (version in Debian).value), + name in Debian := (name in Linux).value, + maintainerScripts in Debian := (maintainerScripts in Linux).value, + packageName in Debian := (packageName in Linux).value, + executableScriptName in Debian := (executableScriptName in Linux).value, + version in Debian := (version in Linux).value, + linuxPackageMappings in Debian := linuxPackageMappings.value, + packageDescription in Debian := (packageDescription in Linux).value, + packageSummary in Debian := (packageSummary in Linux).value, + maintainer in Debian := (maintainer in Linux).value, + validatePackageValidators in Debian := Seq( + nonEmptyMappings((linuxPackageMappings in Debian).value.flatMap(_.mappings)), + filesExist((linuxPackageMappings in Debian).value.flatMap(_.mappings)), + checkMaintainer((maintainer in Debian).value, asWarning = false) + ), + // override the linux sourceDirectory setting + sourceDirectory in Debian := sourceDirectory.value, + /* ==== Debian configuration settings ==== */ + debianControlScriptsDirectory := (sourceDirectory.value / "debian" / Names.DebianMaintainerScripts), + debianMaintainerScripts := Seq.empty, + debianMakePreinstScript := None, + debianMakePrermScript := None, + debianMakePostinstScript := None, + debianMakePostrmScript := None, + debianChangelog := None, + /* === new debian scripts implementation */ + maintainerScripts in Debian := { + val replacements = (linuxScriptReplacements in Debian).value + val scripts = Map( + Names.Prerm -> defaultMaintainerScript(Names.Prerm).toSeq.flatten, + Names.Preinst -> defaultMaintainerScript(Names.Preinst).toSeq.flatten, + Names.Postinst -> defaultMaintainerScript(Names.Postinst).toSeq.flatten, + Names.Postrm -> defaultMaintainerScript(Names.Postrm).toSeq.flatten + ) - // this is for legacy purposes to keep old behaviour - // --- legacy starts - def readContent(scriptFiles: Seq[(File, String)]): Map[String, Seq[String]] = - scriptFiles.map { - case (scriptFile, scriptName) => - scriptName -> IO.readLines(scriptFile) - }.toMap - - val userProvided = readContent( - Seq( - debianMakePreinstScript.value.map(script => script -> Names.Preinst), - debianMakePostinstScript.value.map(script => script -> Names.Postinst), - debianMakePrermScript.value.map(script => script -> Names.Prerm), - debianMakePostrmScript.value.map(script => script -> Names.Postrm) - ).flatten - ) + // this is for legacy purposes to keep old behaviour + // --- legacy starts + def readContent(scriptFiles: Seq[(File, String)]): Map[String, Seq[String]] = + scriptFiles.map { + case (scriptFile, scriptName) => + scriptName -> IO.readLines(scriptFile) + }.toMap + + val userProvided = readContent( + Seq( + debianMakePreinstScript.value.map(script => script -> Names.Preinst), + debianMakePostinstScript.value.map(script => script -> Names.Postinst), + debianMakePrermScript.value.map(script => script -> Names.Prerm), + debianMakePostrmScript.value.map(script => script -> Names.Postrm) + ).flatten + ) - // these things get appended. Don't check for nonexisting keys as they are already in the default scripts map - val appendedScripts = scripts.map { - case (scriptName, content) => - scriptName -> (content ++ userProvided.getOrElse(scriptName, Nil)) - } - // override and merge with the user defined scripts. Will change in the future - val controlScriptsDir = debianControlScriptsDirectory.value - val overridenScripts = scripts ++ readContent( - Seq( - scriptMapping(Names.Prerm, debianMakePrermScript.value, controlScriptsDir), - scriptMapping(Names.Preinst, debianMakePreinstScript.value, controlScriptsDir), - scriptMapping(Names.Postinst, debianMakePostinstScript.value, controlScriptsDir), - scriptMapping(Names.Postrm, debianMakePostrmScript.value, controlScriptsDir) - ).flatten - ) - // --- legacy ends + // these things get appended. Don't check for nonexisting keys as they are already in the default scripts map + val appendedScripts = scripts.map { + case (scriptName, content) => + scriptName -> (content ++ userProvided.getOrElse(scriptName, Nil)) + } + // override and merge with the user defined scripts. Will change in the future + val controlScriptsDir = debianControlScriptsDirectory.value + val overridenScripts = scripts ++ readContent( + Seq( + scriptMapping(Names.Prerm, debianMakePrermScript.value, controlScriptsDir), + scriptMapping(Names.Preinst, debianMakePreinstScript.value, controlScriptsDir), + scriptMapping(Names.Postinst, debianMakePostinstScript.value, controlScriptsDir), + scriptMapping(Names.Postrm, debianMakePostrmScript.value, controlScriptsDir) + ).flatten + ) + // --- legacy ends - // TODO remove the overridenScripts - val content = appendedScripts ++ overridenScripts + // TODO remove the overridenScripts + val content = appendedScripts ++ overridenScripts - // apply all replacements - content.mapValues { lines => - TemplateWriter.generateScriptFromLines(lines, replacements) - } - }, - debianMaintainerScripts := generateDebianMaintainerScripts( - (maintainerScripts in Debian).value, - (linuxScriptReplacements in Debian).value, - (target in Universal).value - ), - debianNativeBuildOptions := Nil - ) + // apply all replacements + content.mapValues { lines => + TemplateWriter.generateScriptFromLines(lines, replacements) + } + }, + debianMaintainerScripts := generateDebianMaintainerScripts( + (maintainerScripts in Debian).value, + (linuxScriptReplacements in Debian).value, + (target in Universal).value + ), + debianNativeBuildOptions := Nil + ) /** * == Debian scoped settings == * Everything used inside the debian scope - * */ - private def debianSettings: Seq[Setting[_]] = inConfig(Debian)( - Seq( - packageArchitecture := "all", - debianPackageInfo := PackageInfo( - packageName.value, - version.value, - maintainer.value, - packageSummary.value, - packageDescription.value - ), - debianPackageMetadata := PackageMetaData( - debianPackageInfo.value, - debianPriority.value, - packageArchitecture.value, - debianSection.value, - debianPackageConflicts.value, - debianPackageDependencies.value, - debianPackageProvides.value, - debianPackageRecommends.value - ), - debianPackageInstallSize := getPackageInstallSize(linuxPackageMappings.value), - debianControlFile := createConfFile(debianPackageMetadata.value, debianPackageInstallSize.value, target.value), - debianConffilesFile := createConffilesFile(linuxPackageMappings.value, target.value), - debianMD5sumsFile := createMD5SumFile(stage.value), - debianMakeChownReplacements := makeChownReplacements(linuxPackageMappings.value, streams.value), - stage := { - val debianTarget = target.value - - stageMappings(linuxPackageMappings.value, debianTarget) - - // Now generate relative symlinks - LinuxSymlink.makeSymLinks(linuxPackageSymlinks.value, debianTarget, relativeLinks = false) - - stageMaintainerScripts( - debianMaintainerScripts.value, - debianMakeChownReplacements.value +: linuxScriptReplacements.value, + private def debianSettings: Seq[Setting[_]] = + inConfig(Debian)( + Seq( + packageArchitecture := "all", + debianPackageInfo := PackageInfo( + packageName.value, + version.value, + maintainer.value, + packageSummary.value, + packageDescription.value + ), + debianPackageMetadata := PackageMetaData( + debianPackageInfo.value, + debianPriority.value, + packageArchitecture.value, + debianSection.value, + debianPackageConflicts.value, + debianPackageDependencies.value, + debianPackageProvides.value, + debianPackageRecommends.value + ), + debianPackageInstallSize := getPackageInstallSize(linuxPackageMappings.value), + debianControlFile := createConfFile(debianPackageMetadata.value, debianPackageInstallSize.value, target.value), + debianConffilesFile := createConffilesFile(linuxPackageMappings.value, target.value), + debianMD5sumsFile := createMD5SumFile(stage.value), + debianMakeChownReplacements := makeChownReplacements(linuxPackageMappings.value, streams.value), + stage := { + val debianTarget = target.value + + stageMappings(linuxPackageMappings.value, debianTarget) + + // Now generate relative symlinks + LinuxSymlink.makeSymLinks(linuxPackageSymlinks.value, debianTarget, relativeLinks = false) + + stageMaintainerScripts( + debianMaintainerScripts.value, + debianMakeChownReplacements.value +: linuxScriptReplacements.value, + debianTarget + ) debianTarget - ) - debianTarget - }, - // TODO remove in next major release - debianExplodedPackage := stage.value, - // Replacement for ${{header}} as debian control scripts are bash scripts - linuxScriptReplacements += ("header" -> "#!/bin/sh\nset -e"), - stage := (stage dependsOn debianControlFile).value, - stage := (stage dependsOn debianConffilesFile).value + }, + // TODO remove in next major release + debianExplodedPackage := stage.value, + // Replacement for ${{header}} as debian control scripts are bash scripts + linuxScriptReplacements += ("header" -> "#!/bin/sh\nset -e"), + stage := (stage dependsOn debianControlFile).value, + stage := (stage dependsOn debianConffilesFile).value + ) ) - ) private[this] def getPackageInstallSize(mappings: Seq[LinuxPackageMapping]): Long = (for { @@ -229,10 +229,9 @@ object DebianPlugin extends AutoPlugin with DebianNativePackaging { private[this] def createConfFile(meta: PackageMetaData, size: Long, targetDir: File): File = { val description = Option(meta.info.description).filterNot(_.isEmpty) - if (description.isEmpty) { + if (description.isEmpty) sys.error("""packageDescription in Debian cannot be empty. Use packageDescription in Debian := "My package Description"""") - } val cfile = targetDir / Names.DebianMaintainerScripts / Names.Control IO.write(cfile, meta.makeContent(size), java.nio.charset.Charset.defaultCharset) chmod(cfile, "0644") @@ -295,9 +294,11 @@ object DebianPlugin extends AutoPlugin with DebianNativePackaging { * @param targetDir * @param replacements */ - private[this] def stageMaintainerScripts(maintainerScripts: Seq[(File, String)], - replacements: Seq[(String, String)], - targetDir: File) = + private[this] def stageMaintainerScripts( + maintainerScripts: Seq[(File, String)], + replacements: Seq[(String, String)], + targetDir: File + ) = for ((file, name) <- maintainerScripts) { val targetFile = targetDir / Names.DebianMaintainerScripts / name copyAndFixPerms(file, targetFile, LinuxFileMetaData()) @@ -313,16 +314,17 @@ object DebianPlugin extends AutoPlugin with DebianNativePackaging { * * Most of the methods are for java 6 file permission handling and * debian script adjustements. - * */ trait DebianPluginLike { /** validate group and usernames for debian systems */ val UserNamePattern: Regex = "^[a-z][-a-z0-9_]*$".r - private[debian] final def generateDebianMaintainerScripts(scripts: Map[String, Seq[String]], - replacements: Seq[(String, String)], - tmpDir: File): Seq[(File, String)] = + private[debian] final def generateDebianMaintainerScripts( + scripts: Map[String, Seq[String]], + replacements: Seq[(String, String)], + tmpDir: File + ): Seq[(File, String)] = scripts.map { case (scriptName, content) => val scriptBits = @@ -337,26 +339,30 @@ trait DebianPluginLike { url.map(source => IO.readLinesURL(source)) } - private[debian] final def copyAndFixPerms(from: File, - to: File, - perms: LinuxFileMetaData, - zipped: Boolean = false): Unit = { - if (zipped) { + private[debian] final def copyAndFixPerms( + from: File, + to: File, + perms: LinuxFileMetaData, + zipped: Boolean = false + ): Unit = { + if (zipped) IO.withTemporaryDirectory { dir => val tmp = dir / from.getName IO.copyFile(from, tmp) val zipped = Archives.gzip(tmp) IO.copyFile(zipped, to, preserveLastModified = true) } - } else IO.copyFile(from, to, preserveLastModified = true) + else IO.copyFile(from, to, preserveLastModified = true) // If we have a directory, we need to alter the perms. chmod(to, perms.permissions) // TODO - Can we do anything about user/group ownership? } - private[debian] final def filterAndFixPerms(script: File, - replacements: Seq[(String, String)], - perms: LinuxFileMetaData): File = { + private[debian] final def filterAndFixPerms( + script: File, + replacements: Seq[(String, String)], + perms: LinuxFileMetaData + ): File = { val filtered = TemplateWriter.generateScript(script.toURI.toURL, replacements) IO.delete(script) @@ -387,20 +393,20 @@ trait DebianPluginLike { } private[debian] final def validateUserGroupNames(user: String, streams: TaskStreams): Unit = { - if ((UserNamePattern findFirstIn user).isEmpty) { + if ((UserNamePattern findFirstIn user).isEmpty) streams.log.warn("The user or group '" + user + "' may contain invalid characters for Debian based distributions") - } - if (user.length > 32) { + if (user.length > 32) streams.log.warn( "The length of '" + user + "' must be not be greater than 32 characters for Debian based distributions." ) - } } @deprecated("Will be removed", "1.0.3") - private[debian] def scriptMapping(scriptName: String, - script: Option[File], - controlDir: File): Option[(File, String)] = + private[debian] def scriptMapping( + scriptName: String, + script: Option[File], + controlDir: File + ): Option[(File, String)] = (script, controlDir) match { // check if user defined script exists case (_, dir) if (dir / scriptName).exists => @@ -421,8 +427,10 @@ trait DebianPluginLike { * @param streams - logging * @return (CHOWN_REPLACEMENT -> ".. list of chown commands") */ - private[debian] def makeChownReplacements(mappings: Seq[LinuxPackageMapping], - streams: TaskStreams): (String, String) = { + private[debian] def makeChownReplacements( + mappings: Seq[LinuxPackageMapping], + streams: TaskStreams + ): (String, String) = { // how to create the chownCmd. TODO maybe configurable? def chownCmd(user: String, group: String)(path: String): String = s"chown $user:$group '$path'" diff --git a/src/main/scala/com/typesafe/sbt/packager/debian/JDebPackaging.scala b/src/main/scala/com/typesafe/sbt/packager/debian/JDebPackaging.scala index 6c7fe85eb..1bb2f9dda 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/JDebPackaging.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/JDebPackaging.scala @@ -27,7 +27,6 @@ import DebianPlugin.autoImport._ * * @author Nepomuk Seiler * @see [[https://github.com/tcurdt/jdeb/blob/master/src/main/java/org/vafer/jdeb/maven/DebMojo.java#L503]] - * */ object JDebPackaging extends AutoPlugin with DebianPluginLike { @@ -35,72 +34,72 @@ object JDebPackaging extends AutoPlugin with DebianPluginLike { override lazy val projectSettings: Seq[Setting[_]] = inConfig(Debian)(jdebSettings) - def jdebSettings = Seq( - // FIXME do nothing. Java7 posix needed - debianConffilesFile := { - target.value / Names.DebianMaintainerScripts / Names.Conffiles - }, - // FIXME copied from the debian plugin. Java7 posix needed - debianControlFile := { - val data = debianPackageMetadata.value - val size = debianPackageInstallSize.value - if (data.info.description == null || data.info.description.isEmpty) { - sys.error("""packageDescription in Debian cannot be empty. Use + def jdebSettings = + Seq( + // FIXME do nothing. Java7 posix needed + debianConffilesFile := { + target.value / Names.DebianMaintainerScripts / Names.Conffiles + }, + // FIXME copied from the debian plugin. Java7 posix needed + debianControlFile := { + val data = debianPackageMetadata.value + val size = debianPackageInstallSize.value + if (data.info.description == null || data.info.description.isEmpty) + sys.error("""packageDescription in Debian cannot be empty. Use packageDescription in Debian := "My package Description"""") - } - val cfile = target.value / Names.DebianMaintainerScripts / Names.Control - IO.write(cfile, data.makeContent(size), java.nio.charset.Charset.defaultCharset) - cfile - }, - /** - * Depends on the 'debianExplodedPackage' task as this creates all the files - * which are defined in the mappings. - */ - packageBin := { - val targetDir = target.value - val log = streams.value.log - val mappings = linuxPackageMappings.value - val symlinks = linuxPackageSymlinks.value - - // unused, but needed as dependency - val controlDir = targetDir / Names.DebianMaintainerScripts - val _ = debianControlFile.value - val conffile = debianConffilesFile.value - val replacements = debianMakeChownReplacements.value +: linuxScriptReplacements.value - - val controlScripts = debianMaintainerScripts.value - for ((file, name) <- controlScripts) { - val targetFile = controlDir / name - copyFiles(file, targetFile, LinuxFileMetaData()) - filterFiles(targetFile, replacements, LinuxFileMetaData()) - } + val cfile = target.value / Names.DebianMaintainerScripts / Names.Control + IO.write(cfile, data.makeContent(size), java.nio.charset.Charset.defaultCharset) + cfile + }, + /** + * Depends on the 'debianExplodedPackage' task as this creates all the files + * which are defined in the mappings. + */ + packageBin := { + val targetDir = target.value + val log = streams.value.log + val mappings = linuxPackageMappings.value + val symlinks = linuxPackageSymlinks.value + + // unused, but needed as dependency + val controlDir = targetDir / Names.DebianMaintainerScripts + val _ = debianControlFile.value + val conffile = debianConffilesFile.value + val replacements = debianMakeChownReplacements.value +: linuxScriptReplacements.value + + val controlScripts = debianMaintainerScripts.value + for ((file, name) <- controlScripts) { + val targetFile = controlDir / name + copyFiles(file, targetFile, LinuxFileMetaData()) + filterFiles(targetFile, replacements, LinuxFileMetaData()) + } - log.info("Building debian package with java based implementation 'jdeb'") - val archive = archiveFilename(normalizedName.value, version.value, packageArchitecture.value) - val debianFile = targetDir.getParentFile / archive - val debMaker = new JDebPackagingTask() - debMaker.packageDebian(mappings, symlinks, debianFile, targetDir, log) - debianFile - }, - packageBin := (packageBin dependsOn debianControlFile).value, - packageBin := (packageBin dependsOn debianConffilesFile).value, - // workaround for sbt-coursier - classpathTypes += "maven-plugin" - ) + log.info("Building debian package with java based implementation 'jdeb'") + val archive = archiveFilename(normalizedName.value, version.value, packageArchitecture.value) + val debianFile = targetDir.getParentFile / archive + val debMaker = new JDebPackagingTask() + debMaker.packageDebian(mappings, symlinks, debianFile, targetDir, log) + debianFile + }, + packageBin := (packageBin dependsOn debianControlFile).value, + packageBin := (packageBin dependsOn debianConffilesFile).value, + // workaround for sbt-coursier + classpathTypes += "maven-plugin" + ) /** * The same as [[DebianPluginLike.copyAndFixPerms]] except chmod invocation (for windows compatibility). * Permissions will be handled by jDeb packager itself. */ private def copyFiles(from: File, to: File, perms: LinuxFileMetaData, zipped: Boolean = false): Unit = - if (zipped) { + if (zipped) IO.withTemporaryDirectory { dir => val tmp = dir / from.getName IO.copyFile(from, tmp) val zipped = Archives.gzip(tmp) IO.copyFile(zipped, to, preserveLastModified = true) } - } else IO.copyFile(from, to, preserveLastModified = true) + else IO.copyFile(from, to, preserveLastModified = true) /** * The same as [[DebianPluginLike.filterAndFixPerms]] except chmod invocation (for windows compatibility). @@ -142,11 +141,13 @@ private class JDebPackagingTask { import org.vafer.jdeb.mapping._ import org.vafer.jdeb.producers._ - def packageDebian(mappings: Seq[LinuxPackageMapping], - symlinks: Seq[LinuxSymlink], - debianFile: File, - targetDir: File, - log: Logger): Unit = { + def packageDebian( + mappings: Seq[LinuxPackageMapping], + symlinks: Seq[LinuxSymlink], + debianFile: File, + targetDir: File, + log: Logger + ): Unit = { val debMaker = new DebMaker( new JDebConsole(log), (fileAndDirectoryProducers(mappings, targetDir) ++ linkProducers(symlinks)).asJava, @@ -189,10 +190,11 @@ private class JDebPackagingTask { /** * Creating link producers for symlinks. */ - private[debian] def linkProducers(symlinks: Seq[LinuxSymlink]): Seq[DataProducer] = symlinks map { - case LinuxSymlink(link, destination) => - new DataProducerLink(link, destination, true, null, null, null) - } + private[debian] def linkProducers(symlinks: Seq[LinuxSymlink]): Seq[DataProducer] = + symlinks map { + case LinuxSymlink(link, destination) => + new DataProducerLink(link, destination, true, null, null, null) + } /** * Creating the files which should be added as conffiles. diff --git a/src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala index 39126180e..7403a31c7 100644 --- a/src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala @@ -120,15 +120,16 @@ object DockerPlugin extends AutoPlugin { }, dockerAliases := { val alias = dockerAlias.value - if (dockerUpdateLatest.value) { + if (dockerUpdateLatest.value) Seq(alias, alias.withTag(Option("latest"))) - } else { + else Seq(alias) - } }, dockerEntrypoint := Seq(s"${(defaultLinuxInstallLocation in Docker).value}/bin/${executableScriptName.value}"), dockerCmd := Seq(), - dockerVersion := Try(Process(dockerExecCommand.value ++ Seq("version", "--format", "'{{.Server.Version}}'")).!!).toOption + dockerVersion := Try( + Process(dockerExecCommand.value ++ Seq("version", "--format", "'{{.Server.Version}}'")).!! + ).toOption .map(_.trim) .flatMap(DockerVersion.parse), dockerApiVersion := Try( @@ -262,15 +263,16 @@ object DockerPlugin extends AutoPlugin { } } tag (Tags.Network, Tags.Publish) - def cleanTask = Def.task { - val alias = dockerAliases.value - val log = streams.value.log - val rmiCommand = dockerRmiCommand.value - // clean up images - alias.foreach { aliasValue => - rmiDocker(rmiCommand, aliasValue.toString, log) + def cleanTask = + Def.task { + val alias = dockerAliases.value + val log = streams.value.log + val rmiCommand = dockerRmiCommand.value + // clean up images + alias.foreach { aliasValue => + rmiDocker(rmiCommand, aliasValue.toString, log) + } } - } Seq( executableScriptName := executableScriptName.value, @@ -281,9 +283,13 @@ object DockerPlugin extends AutoPlugin { publish := publishTask.value, clean := cleanTask.value, sourceDirectory := sourceDirectory.value / "docker", - stage := Stager.stage(Docker.name)(streams.value, stagingDirectory.value, dockerLayerMappings.value.map { - case LayeredMapping(layerIdx, file, path) => (file, pathInLayer(path, layerIdx)) - }), + stage := Stager.stage(Docker.name)( + streams.value, + stagingDirectory.value, + dockerLayerMappings.value.map { + case LayeredMapping(layerIdx, file, path) => (file, pathInLayer(path, layerIdx)) + } + ), stage := (stage dependsOn dockerGenerateConfig).value, stagingDirectory := (target in Docker).value / "stage", dockerLayerMappings := { @@ -394,11 +400,13 @@ object DockerPlugin extends AutoPlugin { * @param daemonGroup * @return COPY command copying all files inside the directory from another build stage. */ - private final def makeCopyFrom(src: String, - dest: String, - stage: String, - daemonUser: String, - daemonGroup: String): CmdLike = + private final def makeCopyFrom( + src: String, + dest: String, + stage: String, + daemonUser: String, + daemonGroup: String + ): CmdLike = Cmd("COPY", s"--from=$stage --chown=$daemonUser:$daemonGroup $src $dest") /** @@ -407,10 +415,12 @@ object DockerPlugin extends AutoPlugin { * @param daemonGroup * @return COPY command copying all files inside the directory from another build stage. */ - private final def makeCopyChown(layerId: Option[Int], - dockerBaseDirectory: String, - daemonUser: String, - daemonGroup: String): CmdLike = { + private final def makeCopyChown( + layerId: Option[Int], + dockerBaseDirectory: String, + daemonUser: String, + daemonGroup: String + ): CmdLike = { /** * This is the file path of the file in the Docker image, and does not depend on the OS where the image @@ -450,20 +460,22 @@ object DockerPlugin extends AutoPlugin { * @return useradd to create the daemon user with the given uidOpt and gidOpt after invoking groupadd to * create the daemon group if the given gidOpt does not exists. */ - private final def makeUserAdd(daemonUser: String, - daemonGroup: String, - uidOpt: Option[String], - gidOpt: Option[String]): CmdLike = + private final def makeUserAdd( + daemonUser: String, + daemonGroup: String, + uidOpt: Option[String], + gidOpt: Option[String] + ): CmdLike = Cmd( "RUN", (List("id", "-u", daemonUser, "1>/dev/null", "2>&1", "||") ::: (gidOpt.fold[List[String]](Nil)( - gid => - List("((", "getent", "group", gid, "1>/dev/null", "2>&1", "||") ::: - List("(", "type", "groupadd", "1>/dev/null", "2>&1", "&&") ::: - List("groupadd", "-g", gid, daemonGroup, "||") ::: - List("addgroup", "-g", gid, "-S", daemonGroup, "))", "&&") - )) ::: + gid => + List("((", "getent", "group", gid, "1>/dev/null", "2>&1", "||") ::: + List("(", "type", "groupadd", "1>/dev/null", "2>&1", "&&") ::: + List("groupadd", "-g", gid, daemonGroup, "||") ::: + List("addgroup", "-g", gid, "-S", daemonGroup, "))", "&&") + )) ::: List("(", "type", "useradd", "1>/dev/null", "2>&1", "&&") ::: List("useradd", "--system", "--create-home") ::: (uidOpt.fold[List[String]](Nil)(List("--uid", _))) ::: @@ -580,20 +592,23 @@ object DockerPlugin extends AutoPlugin { case s => } - override def out(inf: => String): Unit = inf match { - case s if !s.trim.isEmpty => log.info(s) - case s => - } + override def out(inf: => String): Unit = + inf match { + case s if !s.trim.isEmpty => log.info(s) + case s => + } override def buffer[T](f: => T): T = f } - def publishLocalDocker(context: File, - buildCommand: Seq[String], - execCommand: Seq[String], - strategy: DockerPermissionStrategy, - removeIntermediateImages: Boolean, - log: Logger): Unit = { + def publishLocalDocker( + context: File, + buildCommand: Seq[String], + execCommand: Seq[String], + strategy: DockerPermissionStrategy, + removeIntermediateImages: Boolean, + log: Logger + ): Unit = { log.debug("Executing Native " + buildCommand.mkString(" ")) log.debug("Working directory " + context.toString) @@ -608,7 +623,7 @@ object DockerPlugin extends AutoPlugin { .find(_.startsWith(labelCmd)) .map(_.substring(labelCmd.size).stripPrefix("\"").stripSuffix("\"")) match { // No matter if the build process succeeded or failed, we try to remove the intermediate images - case Some(id) => { + case Some(id) => val label = s"${labelKey}=${id}" log.info(s"""Removing intermediate image(s) (labeled "${label}") """) val retImageClean = sys.process.Process( @@ -616,8 +631,9 @@ object DockerPlugin extends AutoPlugin { ) ! publishLocalLogger(log) // FYI: "docker image prune" returns 0 (success) no matter if images were removed or not if (retImageClean != 0) - log.err("Something went wrong while removing multi-stage intermediate image(s)") // no exception, just let the user know - } + log.err( + "Something went wrong while removing multi-stage intermediate image(s)" + ) // no exception, just let the user know case None => log.info( """Not removing multi-stage intermediate image(s) because id is missing in Dockerfile (Comment: "# id=...")""" @@ -632,16 +648,18 @@ object DockerPlugin extends AutoPlugin { } def rmiDocker(execCommand: Seq[String], tag: String, log: Logger): Unit = { - def rmiDockerLogger(log: Logger) = new sys.process.ProcessLogger { - override def err(err: => String): Unit = err match { - case s if !s.trim.isEmpty => log.error(s) - case s => - } + def rmiDockerLogger(log: Logger) = + new sys.process.ProcessLogger { + override def err(err: => String): Unit = + err match { + case s if !s.trim.isEmpty => log.error(s) + case s => + } - override def out(inf: => String): Unit = log.info(inf) + override def out(inf: => String): Unit = log.info(inf) - override def buffer[T](f: => T): T = f - } + override def buffer[T](f: => T): T = f + } log.debug(s"Removing ${tag}") @@ -660,10 +678,11 @@ object DockerPlugin extends AutoPlugin { def publishLogger(log: Logger) = new sys.process.ProcessLogger { - override def err(err: => String): Unit = err match { - case s if !s.trim.isEmpty => log.error(s) - case s => - } + override def err(err: => String): Unit = + err match { + case s if !s.trim.isEmpty => log.error(s) + case s => + } override def out(inf: => String): Unit = inf match { @@ -690,12 +709,13 @@ object DockerPlugin extends AutoPlugin { log.info("Published image " + tag) } - private[this] def validateExposedPorts(ports: Seq[Int], udpPorts: Seq[Int]): Validation.Validator = () => { - if (ports.isEmpty && udpPorts.isEmpty) { - List( - ValidationWarning( - description = "There are no exposed ports for your docker image", - howToFix = """| Configure the `dockerExposedPorts` or `dockerExposedUdpPorts` setting. E.g. + private[this] def validateExposedPorts(ports: Seq[Int], udpPorts: Seq[Int]): Validation.Validator = + () => { + if (ports.isEmpty && udpPorts.isEmpty) + List( + ValidationWarning( + description = "There are no exposed ports for your docker image", + howToFix = """| Configure the `dockerExposedPorts` or `dockerExposedUdpPorts` setting. E.g. | | // standard tcp ports | dockerExposedPorts ++= Seq(9000, 9001) @@ -703,22 +723,22 @@ object DockerPlugin extends AutoPlugin { | // for udp ports | dockerExposedUdpPorts += 4444 """.stripMargin + ) ) - ) - } else { - List.empty + else + List.empty } - } - private[this] def validateDockerVersion(dockerApiVersion: Option[DockerApiVersion]): Validation.Validator = () => { - dockerApiVersion match { - case Some(_) => List.empty - case None => - List( - ValidationWarning( - description = - "sbt-native-packager wasn't able to identify the docker version. Some features may not be enabled", - howToFix = """|sbt-native packager tries to parse the `docker version` output. This can fail if + private[this] def validateDockerVersion(dockerApiVersion: Option[DockerApiVersion]): Validation.Validator = + () => { + dockerApiVersion match { + case Some(_) => List.empty + case None => + List( + ValidationWarning( + description = + "sbt-native-packager wasn't able to identify the docker version. Some features may not be enabled", + howToFix = """|sbt-native packager tries to parse the `docker version` output. This can fail if | | - the output has changed: | $ docker version --format '{{.Server.APIVersion}}' @@ -737,14 +757,16 @@ object DockerPlugin extends AutoPlugin { | import com.typesafe.sbt.packager.docker.DockerApiVersion | dockerApiVersion := Some(DockerApiVersion(1, 40)) """.stripMargin + ) ) - ) + } } - } - private[this] def validateDockerPermissionStrategy(strategy: DockerPermissionStrategy, - dockerVersion: Option[DockerVersion], - dockerApiVersion: Option[DockerApiVersion]): Validation.Validator = + private[this] def validateDockerPermissionStrategy( + strategy: DockerPermissionStrategy, + dockerVersion: Option[DockerVersion], + dockerApiVersion: Option[DockerApiVersion] + ): Validation.Validator = () => { (strategy, dockerVersion, dockerApiVersion) match { case (DockerPermissionStrategy.MultiStage, Some(ver), Some(apiVer)) if !DockerSupport.multiStage(ver, apiVer) => @@ -752,8 +774,7 @@ object DockerPlugin extends AutoPlugin { ValidationError( description = s"The detected Docker version $ver is not compatible with DockerPermissionStrategy.MultiStage", - howToFix = - """|sbt-native packager tries to parse the `docker version` output. + howToFix = """|sbt-native packager tries to parse the `docker version` output. |To use multi-stage build, upgrade your Docker, pick another strategy, or override dockerApiVersion: | | import com.typesafe.sbt.packager.docker.DockerPermissionStrategy diff --git a/src/main/scala/com/typesafe/sbt/packager/docker/DockerSpotifyClientPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/docker/DockerSpotifyClientPlugin.scala index a5d406a55..5a0ed54b6 100644 --- a/src/main/scala/com/typesafe/sbt/packager/docker/DockerSpotifyClientPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/docker/DockerSpotifyClientPlugin.scala @@ -25,7 +25,6 @@ import sbt._ * docker version * }}} * - * * @note this plugin is not intended to build very customizable docker images, but turn your mappings * configuration in a docker image with almost no ''any'' configuration. * @@ -83,15 +82,17 @@ object DockerSpotifyClientPlugin extends AutoPlugin { docker.publishDocker(aliases, log) } tag (Tags.Network, Tags.Publish) - def dockerServerVersion: Def.Initialize[Task[Option[DockerVersion]]] = Def.task { - val docker = new DockerClientTask() - docker.dockerServerVersion() - } + def dockerServerVersion: Def.Initialize[Task[Option[DockerVersion]]] = + Def.task { + val docker = new DockerClientTask() + docker.dockerServerVersion() + } - def dockerServerApiVersion: Def.Initialize[Task[Option[DockerApiVersion]]] = Def.task { - val docker = new DockerClientTask() - docker.dockerServerApiVersion() - } + def dockerServerApiVersion: Def.Initialize[Task[Option[DockerApiVersion]]] = + Def.task { + val docker = new DockerClientTask() + docker.dockerServerApiVersion() + } } @@ -108,10 +109,12 @@ private class DockerClientTask { import com.spotify.docker.client.messages.ProgressMessage import com.spotify.docker.client.{DefaultDockerClient, DockerClient, ProgressHandler} - def packageDocker(primaryAlias: DockerAlias, - aliases: Seq[DockerAlias], - dockerDirectory: String, - log: Logger): Unit = { + def packageDocker( + primaryAlias: DockerAlias, + aliases: Seq[DockerAlias], + dockerDirectory: String, + log: Logger + ): Unit = { val docker: DockerClient = DefaultDockerClient.fromEnv().build() log.info(s"PublishLocal using Docker API ${docker.version().apiVersion()}") @@ -143,11 +146,12 @@ private class DockerClientTask { DockerApiVersion.parse(docker.version().apiVersion()) } - private def progressHandler(log: Logger) = new ProgressHandler { - override def progress(message: ProgressMessage): Unit = - Option(message.error()) match { - case Some(error) if error.nonEmpty => log.error(message.error()) - case _ => Option(message.stream()) foreach (v => log.info(v)) - } - } + private def progressHandler(log: Logger) = + new ProgressHandler { + override def progress(message: ProgressMessage): Unit = + Option(message.error()) match { + case Some(error) if error.nonEmpty => log.error(message.error()) + case _ => Option(message.stream()) foreach (v => log.info(v)) + } + } } diff --git a/src/main/scala/com/typesafe/sbt/packager/docker/DockerVersion.scala b/src/main/scala/com/typesafe/sbt/packager/docker/DockerVersion.scala index 27356e036..820ddb679 100644 --- a/src/main/scala/com/typesafe/sbt/packager/docker/DockerVersion.scala +++ b/src/main/scala/com/typesafe/sbt/packager/docker/DockerVersion.scala @@ -10,9 +10,14 @@ object DockerVersion { def parse(version: String): Option[DockerVersion] = Option(version).collect { case DockerVersionPattern(major, minor, patch, _, release) => - new DockerVersion(major.toInt, minor.toInt, Option(patch) match { - case Some(p) => p.drop(1).toInt - case _ => 0 - }, Option(release)) + new DockerVersion( + major.toInt, + minor.toInt, + Option(patch) match { + case Some(p) => p.drop(1).toInt + case _ => 0 + }, + Option(release) + ) } } diff --git a/src/main/scala/com/typesafe/sbt/packager/docker/dockerfile.scala b/src/main/scala/com/typesafe/sbt/packager/docker/dockerfile.scala index 074e94439..14a2540f7 100644 --- a/src/main/scala/com/typesafe/sbt/packager/docker/dockerfile.scala +++ b/src/main/scala/com/typesafe/sbt/packager/docker/dockerfile.scala @@ -4,7 +4,6 @@ package docker /** * a single line in a dockerfile. See subclasses for more detail - * */ trait CmdLike { diff --git a/src/main/scala/com/typesafe/sbt/packager/graalvmnativeimage/GraalVMNativeImagePlugin.scala b/src/main/scala/com/typesafe/sbt/packager/graalvmnativeimage/GraalVMNativeImagePlugin.scala index db99a8c94..78d5f6523 100644 --- a/src/main/scala/com/typesafe/sbt/packager/graalvmnativeimage/GraalVMNativeImagePlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/graalvmnativeimage/GraalVMNativeImagePlugin.scala @@ -94,13 +94,15 @@ object GraalVMNativeImagePlugin extends AutoPlugin { } ) - private def buildLocal(targetDirectory: File, - binaryName: String, - nativeImageCommand: String, - className: String, - classpathJars: Seq[File], - extraOptions: Seq[String], - log: ProcessLogger): File = { + private def buildLocal( + targetDirectory: File, + binaryName: String, + nativeImageCommand: String, + className: String, + classpathJars: Seq[File], + extraOptions: Seq[String], + log: ProcessLogger + ): File = { targetDirectory.mkdirs() val command = { val nativeImageArguments = { @@ -116,15 +118,17 @@ object GraalVMNativeImagePlugin extends AutoPlugin { } } - private def buildInDockerContainer(targetDirectory: File, - binaryName: String, - className: String, - classpathJars: Seq[(File, String)], - extraOptions: Seq[String], - dockerCommand: Seq[String], - resources: Seq[(File, String)], - image: String, - streams: TaskStreams): File = { + private def buildInDockerContainer( + targetDirectory: File, + binaryName: String, + className: String, + classpathJars: Seq[(File, String)], + extraOptions: Seq[String], + dockerCommand: Seq[String], + resources: Seq[(File, String)], + image: String, + streams: TaskStreams + ): File = { stage(targetDirectory, classpathJars, resources, streams) @@ -154,47 +158,49 @@ object GraalVMNativeImagePlugin extends AutoPlugin { * * The passed in docker image must have GraalVM installed and on the PATH, including the gu utility. */ - def generateContainerBuildImage(baseImage: String): Def.Initialize[Task[Option[String]]] = Def.task { - val dockerCommand = (DockerPlugin.autoImport.dockerExecCommand in GraalVMNativeImage).value - val streams = Keys.streams.value + def generateContainerBuildImage(baseImage: String): Def.Initialize[Task[Option[String]]] = + Def.task { + val dockerCommand = (DockerPlugin.autoImport.dockerExecCommand in GraalVMNativeImage).value + val streams = Keys.streams.value - val (baseName, tag) = baseImage.split(":", 2) match { - case Array(n, t) => (n, t) - case Array(n) => (n, "latest") - } + val (baseName, tag) = baseImage.split(":", 2) match { + case Array(n, t) => (n, t) + case Array(n) => (n, "latest") + } - val imageName = s"${baseName.replace('/', '-')}-native-image:$tag" - import sys.process._ - if ((dockerCommand ++ Seq("image", "ls", imageName, "--quiet")).!!.trim.isEmpty) { - streams.log.info(s"Generating new GraalVM native-image image based on $baseImage: $imageName") + val imageName = s"${baseName.replace('/', '-')}-native-image:$tag" + import sys.process._ + if ((dockerCommand ++ Seq("image", "ls", imageName, "--quiet")).!!.trim.isEmpty) { + streams.log.info(s"Generating new GraalVM native-image image based on $baseImage: $imageName") - val dockerContent = Dockerfile( - Cmd("FROM", baseImage), - Cmd("WORKDIR", "/opt/graalvm"), - ExecCmd("RUN", "gu", "install", "native-image"), - ExecCmd("ENTRYPOINT", "native-image") - ).makeContent + val dockerContent = Dockerfile( + Cmd("FROM", baseImage), + Cmd("WORKDIR", "/opt/graalvm"), + ExecCmd("RUN", "gu", "install", "native-image"), + ExecCmd("ENTRYPOINT", "native-image") + ).makeContent - val command = dockerCommand ++ Seq("build", "-t", imageName, "-") + val command = dockerCommand ++ Seq("build", "-t", imageName, "-") - val ret = sys.process.Process(command) #< - new ByteArrayInputStream(dockerContent.getBytes()) ! - DockerPlugin.publishLocalLogger(streams.log) + val ret = sys.process.Process(command) #< + new ByteArrayInputStream(dockerContent.getBytes()) ! + DockerPlugin.publishLocalLogger(streams.log) - if (ret != 0) - throw new RuntimeException("Nonzero exit value when generating GraalVM container build image: " + ret) + if (ret != 0) + throw new RuntimeException("Nonzero exit value when generating GraalVM container build image: " + ret) - } else { - streams.log.info(s"Using existing GraalVM native-image image: $imageName") - } + } else + streams.log.info(s"Using existing GraalVM native-image image: $imageName") - Some(imageName) - } + Some(imageName) + } - private def stage(targetDirectory: File, - classpathJars: Seq[(File, String)], - resources: Seq[(File, String)], - streams: TaskStreams): File = { + private def stage( + targetDirectory: File, + classpathJars: Seq[(File, String)], + resources: Seq[(File, String)], + streams: TaskStreams + ): File = { val stageDir = targetDirectory / "stage" val mappings = classpathJars ++ resources.map { case (resource, path) => resource -> s"resources/$path" diff --git a/src/main/scala/com/typesafe/sbt/packager/jdkpackager/JDKPackagerAntHelper.scala b/src/main/scala/com/typesafe/sbt/packager/jdkpackager/JDKPackagerAntHelper.scala index 4e1e8ff7d..c19f683ec 100644 --- a/src/main/scala/com/typesafe/sbt/packager/jdkpackager/JDKPackagerAntHelper.scala +++ b/src/main/scala/com/typesafe/sbt/packager/jdkpackager/JDKPackagerAntHelper.scala @@ -82,11 +82,13 @@ object JDKPackagerAntHelper { type ApplicationDOM = Elem /** Create the `` definition. */ - private[jdkpackager] def applicationDOM(name: String, - version: String, - mainClass: Option[String], - toolkit: JDKPackagerToolkit, - appArgs: Seq[String]): ApplicationDOM = + private[jdkpackager] def applicationDOM( + name: String, + version: String, + mainClass: Option[String], + toolkit: JDKPackagerToolkit, + appArgs: Seq[String] + ): ApplicationDOM = // format: OFF ` definition. */ - private[jdkpackager] def infoDOM(name: String, - description: String, - maintainer: String, - iconPath: Option[File], - associations: Seq[FileAssociation]): InfoDOM = + private[jdkpackager] def infoDOM( + name: String, + description: String, + maintainer: String, + iconPath: Option[File], + associations: Seq[FileAssociation] + ): InfoDOM = // format: OFF { @@ -127,11 +131,13 @@ object JDKPackagerAntHelper { type DeployDOM = Elem /** Create the `` definition. */ - private[jdkpackager] def deployDOM(basename: String, - packageType: String, - mainJar: File, - outputDir: File, - infoDOM: InfoDOM): DeployDOM = + private[jdkpackager] def deployDOM( + basename: String, + packageType: String, + mainJar: File, + outputDir: File, + infoDOM: InfoDOM + ): DeployDOM = // format: OFF = 8 build 40. |Details: | http://docs.oracle.com/javase/8/docs/technotes/guides/deploy/javafx_ant_task_reference.html#CIAIDHBJ - """.stripMargin - ) + """.stripMargin) /** Config for scoping keys outside of Global . */ val JDKPackager: Configuration = config("jdkPackager") extend SbtNativePackager.Universal diff --git a/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPackageMapping.scala b/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPackageMapping.scala index 66ce1b0df..4f66e0545 100644 --- a/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPackageMapping.scala +++ b/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPackageMapping.scala @@ -5,11 +5,13 @@ package linux import sbt._ import LinuxPlugin.Users -case class LinuxFileMetaData(user: String = Users.Root, - group: String = Users.Root, - permissions: String = "755", - config: String = "false", - docs: Boolean = false) { +case class LinuxFileMetaData( + user: String = Users.Root, + group: String = Users.Root, + permissions: String = "755", + config: String = "false", + docs: Boolean = false +) { def withUser(u: String) = copy(user = u) def withGroup(g: String) = copy(group = g) @@ -18,9 +20,11 @@ case class LinuxFileMetaData(user: String = Users.Root, def asDocs() = copy(docs = true) } -case class LinuxPackageMapping(mappings: Traversable[(File, String)], - fileData: LinuxFileMetaData = LinuxFileMetaData(), - zipped: Boolean = false) { +case class LinuxPackageMapping( + mappings: Traversable[(File, String)], + fileData: LinuxFileMetaData = LinuxFileMetaData(), + zipped: Boolean = false +) { def withUser(user: String) = copy(fileData = fileData withUser user) def withGroup(group: String) = copy(fileData = fileData withGroup group) diff --git a/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPlugin.scala index 7638ff9a7..e0819bd87 100644 --- a/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPlugin.scala @@ -43,124 +43,127 @@ object LinuxPlugin extends AutoPlugin { /** * default linux settings */ - def linuxSettings: Seq[Setting[_]] = Seq( - linuxPackageMappings := Seq.empty, - linuxPackageSymlinks := Seq.empty, - sourceDirectory in Linux := sourceDirectory.value / "linux", - generateManPages := { - val log = streams.value.log - for (file <- ((sourceDirectory in Linux).value / "usr/share/man/man1" ** "*.1").get) { - val man = makeMan(file) - log.info("Generated man page for[" + file + "] =") - log.info(man) - } - }, - packageSummary in Linux := packageSummary.value, - packageDescription in Linux := packageDescription.value, - name in Linux := name.value, - packageName in Linux := packageName.value, - executableScriptName in Linux := executableScriptName.value, - daemonUser := (packageName in Linux).value, - daemonUser in Linux := daemonUser.value, - daemonUserUid in Linux := None, - daemonGroup := (daemonUser in Linux).value, - daemonGroup in Linux := daemonGroup.value, - daemonGroupGid in Linux := None, - daemonShell in Linux := "/bin/false", - defaultLinuxInstallLocation := "/usr/share", - defaultLinuxLogsLocation := "/var/log", - defaultLinuxConfigLocation := "/etc", - // Default settings for service configurations - startRunlevels := None, - stopRunlevels := None, - requiredStartFacilities := None, - requiredStopFacilities := None, - fileDescriptorLimit := Some("1024"), - termTimeout := 10, - killTimeout := 10, - // Default linux bashscript replacements - linuxScriptReplacements := makeReplacements( - author = (maintainer in Linux).value, - description = (packageSummary in Linux).value, - execScript = (executableScriptName in Linux).value, - chdir = chdir(defaultLinuxInstallLocation.value, (packageName in Linux).value), - logdir = defaultLinuxLogsLocation.value, - appName = (packageName in Linux).value, - version = sbt.Keys.version.value, - daemonUser = (daemonUser in Linux).value, - daemonUserUid = (daemonUserUid in Linux).value, - daemonGroup = (daemonGroup in Linux).value, - daemonGroupGid = (daemonGroupGid in Linux).value, - daemonShell = (daemonShell in Linux).value, - fileDescriptorLimit = (fileDescriptorLimit in Linux).value - ), - linuxScriptReplacements += controlScriptFunctionsReplacement( - /* Add key for control-functions */ ), - maintainerScripts in Linux := Map.empty - ) + def linuxSettings: Seq[Setting[_]] = + Seq( + linuxPackageMappings := Seq.empty, + linuxPackageSymlinks := Seq.empty, + sourceDirectory in Linux := sourceDirectory.value / "linux", + generateManPages := { + val log = streams.value.log + for (file <- ((sourceDirectory in Linux).value / "usr/share/man/man1" ** "*.1").get) { + val man = makeMan(file) + log.info("Generated man page for[" + file + "] =") + log.info(man) + } + }, + packageSummary in Linux := packageSummary.value, + packageDescription in Linux := packageDescription.value, + name in Linux := name.value, + packageName in Linux := packageName.value, + executableScriptName in Linux := executableScriptName.value, + daemonUser := (packageName in Linux).value, + daemonUser in Linux := daemonUser.value, + daemonUserUid in Linux := None, + daemonGroup := (daemonUser in Linux).value, + daemonGroup in Linux := daemonGroup.value, + daemonGroupGid in Linux := None, + daemonShell in Linux := "/bin/false", + defaultLinuxInstallLocation := "/usr/share", + defaultLinuxLogsLocation := "/var/log", + defaultLinuxConfigLocation := "/etc", + // Default settings for service configurations + startRunlevels := None, + stopRunlevels := None, + requiredStartFacilities := None, + requiredStopFacilities := None, + fileDescriptorLimit := Some("1024"), + termTimeout := 10, + killTimeout := 10, + // Default linux bashscript replacements + linuxScriptReplacements := makeReplacements( + author = (maintainer in Linux).value, + description = (packageSummary in Linux).value, + execScript = (executableScriptName in Linux).value, + chdir = chdir(defaultLinuxInstallLocation.value, (packageName in Linux).value), + logdir = defaultLinuxLogsLocation.value, + appName = (packageName in Linux).value, + version = sbt.Keys.version.value, + daemonUser = (daemonUser in Linux).value, + daemonUserUid = (daemonUserUid in Linux).value, + daemonGroup = (daemonGroup in Linux).value, + daemonGroupGid = (daemonGroupGid in Linux).value, + daemonShell = (daemonShell in Linux).value, + fileDescriptorLimit = (fileDescriptorLimit in Linux).value + ), + linuxScriptReplacements += controlScriptFunctionsReplacement( /* Add key for control-functions */ ), + maintainerScripts in Linux := Map.empty + ) /** * maps the `mappings` content into `linuxPackageMappings` and * `linuxPackageSymlinks`. */ - def mapGenericFilesToLinux: Seq[Setting[_]] = Seq( - // First we look at the src/linux files - linuxPackageMappings ++= { - val linuxContent = MappingsHelper.contentOf((sourceDirectory in Linux).value) - if (linuxContent.isEmpty) Seq.empty - else mapGenericMappingsToLinux(linuxContent, Users.Root, Users.Root)(identity) - }, - // Now we look at the src/universal files. - linuxPackageMappings ++= getUniversalFolderMappings( - (packageName in Linux).value, - defaultLinuxInstallLocation.value, - (mappings in Universal).value - ), - // Now we generate symlinks. - linuxPackageSymlinks ++= { - val installLocation = defaultLinuxInstallLocation.value - val linuxPackageName = (packageName in Linux).value - for { - (file, name) <- (mappings in Universal).value - if !file.isDirectory - if name startsWith "bin/" - if !(name endsWith ".bat") // IGNORE windows-y things. - } yield LinuxSymlink("/usr/" + name, installLocation + "/" + linuxPackageName + "/" + name) - }, - // Map configuration files - linuxPackageSymlinks ++= { - val linuxPackageName = (packageName in Linux).value - val installLocation = defaultLinuxInstallLocation.value - val configLocation = defaultLinuxConfigLocation.value - val needsConfLink = - (mappings in Universal).value exists { - case (file, destination) => - (destination startsWith "conf/") && !file.isDirectory - } - if (needsConfLink) - Seq( - LinuxSymlink( - link = configLocation + "/" + linuxPackageName, - destination = installLocation + "/" + linuxPackageName + "/conf" + def mapGenericFilesToLinux: Seq[Setting[_]] = + Seq( + // First we look at the src/linux files + linuxPackageMappings ++= { + val linuxContent = MappingsHelper.contentOf((sourceDirectory in Linux).value) + if (linuxContent.isEmpty) Seq.empty + else mapGenericMappingsToLinux(linuxContent, Users.Root, Users.Root)(identity) + }, + // Now we look at the src/universal files. + linuxPackageMappings ++= getUniversalFolderMappings( + (packageName in Linux).value, + defaultLinuxInstallLocation.value, + (mappings in Universal).value + ), + // Now we generate symlinks. + linuxPackageSymlinks ++= { + val installLocation = defaultLinuxInstallLocation.value + val linuxPackageName = (packageName in Linux).value + for { + (file, name) <- (mappings in Universal).value + if !file.isDirectory + if name startsWith "bin/" + if !(name endsWith ".bat") // IGNORE windows-y things. + } yield LinuxSymlink("/usr/" + name, installLocation + "/" + linuxPackageName + "/" + name) + }, + // Map configuration files + linuxPackageSymlinks ++= { + val linuxPackageName = (packageName in Linux).value + val installLocation = defaultLinuxInstallLocation.value + val configLocation = defaultLinuxConfigLocation.value + val needsConfLink = + (mappings in Universal).value exists { + case (file, destination) => + (destination startsWith "conf/") && !file.isDirectory + } + if (needsConfLink) + Seq( + LinuxSymlink( + link = configLocation + "/" + linuxPackageName, + destination = installLocation + "/" + linuxPackageName + "/conf" + ) ) - ) - else Seq.empty - } - ) + else Seq.empty + } + ) - def makeReplacements(author: String, - description: String, - execScript: String, - chdir: String, - logdir: String, - appName: String, - version: String, - daemonUser: String, - daemonUserUid: Option[String], - daemonGroup: String, - daemonGroupGid: Option[String], - daemonShell: String, - fileDescriptorLimit: Option[String]): Seq[(String, String)] = + def makeReplacements( + author: String, + description: String, + execScript: String, + chdir: String, + logdir: String, + appName: String, + version: String, + daemonUser: String, + daemonUserUid: Option[String], + daemonGroup: String, + daemonGroupGid: Option[String], + daemonShell: String, + fileDescriptorLimit: Option[String] + ): Seq[(String, String)] = Seq( "author" -> author, "descr" -> description, @@ -209,7 +212,6 @@ object LinuxPlugin extends AutoPlugin { * `/conf` directory is given a symlink to `/etc/` * Files in `conf/` or `etc/` directories are automatically marked as configuration. * `../man/...1` files are automatically compressed into .gz files. - * */ def mapGenericMappingsToLinux(mappings: Seq[(File, String)], user: String, group: String)( rename: String => String @@ -243,9 +245,11 @@ object LinuxPlugin extends AutoPlugin { final def chdir(installLocation: String, packageName: String): String = s"$installLocation/$packageName" - private[this] def getUniversalFolderMappings(pkg: String, - installLocation: String, - mappings: Seq[(File, String)]): Seq[LinuxPackageMapping] = { + private[this] def getUniversalFolderMappings( + pkg: String, + installLocation: String, + mappings: Seq[(File, String)] + ): Seq[LinuxPackageMapping] = { // TODO - More windows filters... def isWindowsFile(f: (File, String)): Boolean = f._2 endsWith ".bat" diff --git a/src/main/scala/com/typesafe/sbt/packager/rpm/Keys.scala b/src/main/scala/com/typesafe/sbt/packager/rpm/Keys.scala index fbfd7f003..a3d15e2be 100644 --- a/src/main/scala/com/typesafe/sbt/packager/rpm/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/rpm/Keys.scala @@ -78,11 +78,8 @@ trait RpmKeys { "Directory where all debian control scripts reside. Default is 'src/rpm/scriptlets'" ) - val rpmBrpJavaRepackJars = SettingKey[Boolean]( - "brp-java-repack-jars", - """Overrides the __os_post_install scriptlet - http://swaeku.github.io/blog/2013/08/05/how-to-disable-brp-java-repack-jars-during-rpm-build/ for details""" - ) + val rpmBrpJavaRepackJars = SettingKey[Boolean]("brp-java-repack-jars", """Overrides the __os_post_install scriptlet + http://swaeku.github.io/blog/2013/08/05/how-to-disable-brp-java-repack-jars-during-rpm-build/ for details""") // Building val rpmLint = TaskKey[Unit]("rpm-lint", "Runs rpmlint program against the generated RPM, if available.") diff --git a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmHelper.scala b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmHelper.scala index 224cc7d75..386196c16 100644 --- a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmHelper.scala +++ b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmHelper.scala @@ -113,9 +113,8 @@ object RpmHelper { // Workaround for #1246 - random tests fail with a NullPointerException in the sbt ConsoleLogger // I wasn't able to reproduce this locally and there aren't any user reports on this, so we catch // the NPE and log via println - try { - outputBuffer.foreach(log.info(_)) - } catch { + try outputBuffer.foreach(log.info(_)) + catch { case e: NullPointerException => outputBuffer.foreach(println(_)) } diff --git a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmMetadata.scala b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmMetadata.scala index 98261f52d..17951c8f9 100644 --- a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmMetadata.scala +++ b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmMetadata.scala @@ -8,35 +8,41 @@ import com.typesafe.sbt.packager.rpm.RpmPlugin.Names._ import com.typesafe.sbt.packager.archetypes.TemplateWriter import java.io.File -case class RpmMetadata(name: String, - version: String, - release: String, - prefix: Option[String] = None, - arch: String, - vendor: String, - os: String, - summary: String, - description: String, - autoprov: String, - autoreq: String, - epoch: Option[Int]) +case class RpmMetadata( + name: String, + version: String, + release: String, + prefix: Option[String] = None, + arch: String, + vendor: String, + os: String, + summary: String, + description: String, + autoprov: String, + autoreq: String, + epoch: Option[Int] +) /** * The Description used to generate an RPM */ -case class RpmDescription(license: Option[String] = None, - distribution: Option[String] = None, - url: Option[String] = None, - group: Option[String] = None, - packager: Option[String] = None, - icon: Option[String] = None, - changelogFile: Option[String] = None) - -case class RpmDependencies(provides: Seq[String] = Seq.empty, - requirements: Seq[String] = Seq.empty, - prereq: Seq[String] = Seq.empty, - obsoletes: Seq[String] = Seq.empty, - conflicts: Seq[String] = Seq.empty) { +case class RpmDescription( + license: Option[String] = None, + distribution: Option[String] = None, + url: Option[String] = None, + group: Option[String] = None, + packager: Option[String] = None, + icon: Option[String] = None, + changelogFile: Option[String] = None +) + +case class RpmDependencies( + provides: Seq[String] = Seq.empty, + requirements: Seq[String] = Seq.empty, + prereq: Seq[String] = Seq.empty, + obsoletes: Seq[String] = Seq.empty, + conflicts: Seq[String] = Seq.empty +) { def contents: String = { val sb = new StringBuilder def appendSetting(prefix: String, values: Seq[String]) = @@ -53,13 +59,15 @@ case class RpmDependencies(provides: Seq[String] = Seq.empty, /** * Parameters stay because of binary compatibility. */ -case class RpmScripts(pretrans: Option[String] = None, - pre: Option[String] = None, - post: Option[String] = None, - verifyscript: Option[String] = None, - posttrans: Option[String] = None, - preun: Option[String] = None, - postun: Option[String] = None) { +case class RpmScripts( + pretrans: Option[String] = None, + pre: Option[String] = None, + post: Option[String] = None, + verifyscript: Option[String] = None, + posttrans: Option[String] = None, + preun: Option[String] = None, + postun: Option[String] = None +) { def pretransContent(): String = buildScript("pretrans", pretrans) def preContent(): String = buildScript("pre", pre) @@ -94,8 +102,10 @@ case class RpmScripts(pretrans: Option[String] = None, object RpmScripts { - def fromMaintainerScripts(maintainerScripts: Map[String, Seq[String]], - replacements: Seq[(String, String)]): RpmScripts = { + def fromMaintainerScripts( + maintainerScripts: Map[String, Seq[String]], + replacements: Seq[(String, String)] + ): RpmScripts = { val toContent = toContentWith(replacements) _ RpmScripts( pretrans = maintainerScripts.get(Pretrans).map(toContent), @@ -114,14 +124,16 @@ object RpmScripts { } -case class RpmSpec(meta: RpmMetadata, - desc: RpmDescription = RpmDescription(), - deps: RpmDependencies = RpmDependencies(), - setarch: Option[String], - scriptlets: RpmScripts = RpmScripts(), - mappings: Seq[LinuxPackageMapping] = Seq.empty, - symlinks: Seq[LinuxSymlink] = Seq.empty, - installLocation: String) { +case class RpmSpec( + meta: RpmMetadata, + desc: RpmDescription = RpmDescription(), + deps: RpmDependencies = RpmDependencies(), + setarch: Option[String], + scriptlets: RpmScripts = RpmScripts(), + mappings: Seq[LinuxPackageMapping] = Seq.empty, + symlinks: Seq[LinuxSymlink] = Seq.empty, + installLocation: String +) { def installDir: String = LinuxPlugin.chdir(installLocation, meta.name) diff --git a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala index cffd3b63f..1e5f1596d 100644 --- a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala @@ -148,9 +148,8 @@ object RpmPlugin extends AutoPlugin { val pre = scripts.getOrElse(Names.Pre, Nil) val scriptBits = IO.readStream(RpmPlugin.osPostInstallMacro.openStream, Charset forName "UTF-8") scripts + (Names.Pre -> (pre :+ scriptBits)) - } else { + } else scripts - } }, rpmScripts := RpmScripts .fromMaintainerScripts((maintainerScripts in Rpm).value, (linuxScriptReplacements in Rpm).value), diff --git a/src/main/scala/com/typesafe/sbt/packager/universal/Archives.scala b/src/main/scala/com/typesafe/sbt/packager/universal/Archives.scala index 98409d2fa..cf0eabb8e 100644 --- a/src/main/scala/com/typesafe/sbt/packager/universal/Archives.scala +++ b/src/main/scala/com/typesafe/sbt/packager/universal/Archives.scala @@ -32,11 +32,13 @@ object Archives { * @param options NOT USED * @return zip file */ - def makeZip(target: File, - name: String, - mappings: Seq[(File, String)], - top: Option[String], - options: Seq[String]): File = { + def makeZip( + target: File, + name: String, + mappings: Seq[(File, String)], + top: Option[String], + options: Seq[String] + ): File = { val zip = target / (name + ".zip") // add top level directory if defined @@ -74,11 +76,13 @@ object Archives { * @param options NOT USED * @return zip file */ - def makeNativeZip(target: File, - name: String, - mappings: Seq[(File, String)], - top: Option[String], - options: Seq[String]): File = { + def makeNativeZip( + target: File, + name: String, + mappings: Seq[(File, String)], + top: Option[String], + options: Seq[String] + ): File = { val zip = target / (name + ".zip") // add top level directory if defined @@ -120,11 +124,13 @@ object Archives { * @param options NOT USED * @return dmg file */ - def makeDmg(target: File, - name: String, - mappings: Seq[(File, String)], - top: Option[String], - options: Seq[String]): File = { + def makeDmg( + target: File, + name: String, + mappings: Seq[(File, String)], + top: Option[String], + options: Seq[String] + ): File = { val t = target / "dmg" val dmg = target / (name + ".dmg") if (!t.isDirectory) IO.createDirectory(t) @@ -212,10 +218,11 @@ object Archives { * @param mappings included in the output * @param top level directory * @return tar file - * */ - def makeTarball(compressor: File => File, - ext: String)(target: File, name: String, mappings: Seq[(File, String)], top: Option[String]): File = + def makeTarball( + compressor: File => File, + ext: String + )(target: File, name: String, mappings: Seq[(File, String)], top: Option[String]): File = makeTarballWithOptions(compressor, ext)(target, name, mappings, top, options = Seq("--force-local", "-pcvf")) /** @@ -226,13 +233,14 @@ object Archives { * @param topDirectory level directory * @param options for tar command * @return tar file - * */ - def makeTarballWithOptions(compressor: File => File, ext: String)(target: File, - name: String, - mappings: Seq[(File, String)], - topDirectory: Option[String], - options: Seq[String]): File = { + def makeTarballWithOptions(compressor: File => File, ext: String)( + target: File, + name: String, + mappings: Seq[(File, String)], + topDirectory: Option[String], + options: Seq[String] + ): File = { val tarball = target / (name + ext) IO.withTemporaryDirectory { tempDirectory => val workingDirectory = tempDirectory / name diff --git a/src/main/scala/com/typesafe/sbt/packager/universal/UniversalPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/universal/UniversalPlugin.scala index ae2525f96..f13ef6199 100644 --- a/src/main/scala/com/typesafe/sbt/packager/universal/UniversalPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/universal/UniversalPlugin.scala @@ -93,14 +93,15 @@ object UniversalPlugin extends AutoPlugin { target in config := target.value / config.name ) - private[this] def defaultUniversalArchiveOptions: Seq[Setting[_]] = Seq( - universalArchiveOptions in (Universal, packageZipTarball) := Seq("-pcvf"), - universalArchiveOptions in (Universal, packageXzTarball) := Seq("-pcvf"), - universalArchiveOptions in (UniversalDocs, packageZipTarball) := Seq("-pcvf"), - universalArchiveOptions in (UniversalDocs, packageXzTarball) := Seq("-pcvf"), - universalArchiveOptions in (UniversalSrc, packageZipTarball) := Seq("-pcvf"), - universalArchiveOptions in (UniversalSrc, packageXzTarball) := Seq("-pcvf") - ) + private[this] def defaultUniversalArchiveOptions: Seq[Setting[_]] = + Seq( + universalArchiveOptions in (Universal, packageZipTarball) := Seq("-pcvf"), + universalArchiveOptions in (Universal, packageXzTarball) := Seq("-pcvf"), + universalArchiveOptions in (UniversalDocs, packageZipTarball) := Seq("-pcvf"), + universalArchiveOptions in (UniversalDocs, packageXzTarball) := Seq("-pcvf"), + universalArchiveOptions in (UniversalSrc, packageZipTarball) := Seq("-pcvf"), + universalArchiveOptions in (UniversalSrc, packageXzTarball) := Seq("-pcvf") + ) private[this] def printDist(dist: File, streams: TaskStreams): File = { streams.log.info("") @@ -112,8 +113,9 @@ object UniversalPlugin extends AutoPlugin { private type Packager = (File, String, Seq[(File, String)], Option[String], Seq[String]) => File /** Creates packaging settings for a given package key, configuration + archive type. */ - private[this] def makePackageSettings(packageKey: TaskKey[File], - config: Configuration)(packager: Packager): Seq[Setting[_]] = + private[this] def makePackageSettings(packageKey: TaskKey[File], config: Configuration)( + packager: Packager + ): Seq[Setting[_]] = inConfig(config)( Seq( universalArchiveOptions in packageKey := Nil, @@ -146,7 +148,7 @@ object UniversalDeployPlugin extends AutoPlugin { import UniversalPlugin.autoImport._ - override def requires = UniversalPlugin + override def requires: Plugins = UniversalPlugin override def projectSettings: Seq[Setting[_]] = SettingsHelper.makeDeploymentSettings(Universal, packageBin in Universal, "zip") ++ diff --git a/src/main/scala/com/typesafe/sbt/packager/universal/ZipHelper.scala b/src/main/scala/com/typesafe/sbt/packager/universal/ZipHelper.scala index 47c090d2b..fca0b4ed7 100644 --- a/src/main/scala/com/typesafe/sbt/packager/universal/ZipHelper.scala +++ b/src/main/scala/com/typesafe/sbt/packager/universal/ZipHelper.scala @@ -65,8 +65,9 @@ object ZipHelper { for { (file, name) <- sources.toSeq // TODO - Figure out if this is good enough.... - perm = if (file.isDirectory || file.canExecute) oct"0755" - else oct"0644" + perm = + if (file.isDirectory || file.canExecute) oct"0755" + else oct"0644" } yield FileMapping(file, name, Some(perm)) archive(mappings, outputZip) } @@ -114,16 +115,11 @@ object ZipHelper { mode foreach (entry.setUnixMode) output putArchiveEntry entry val fis = new java.io.FileInputStream(file) - try { - try { - // TODO - Write file into output? - IOUtils.copy(fis, output) - } finally { - output.closeArchiveEntry() - } - } finally { - fis.close() - } + try try + // TODO - Write file into output? + IOUtils.copy(fis, output) + finally output.closeArchiveEntry() + finally fis.close() } } } @@ -134,15 +130,12 @@ object ZipHelper { private def withZipOutput(file: File)(f: ZipArchiveOutputStream => Unit): Unit = { val zipOut = new ZipArchiveOutputStream(file) zipOut setLevel Deflater.BEST_COMPRESSION - try { - f(zipOut) - } catch { + try f(zipOut) + catch { case t: Throwable => IOUtils.closeQuietly(zipOut) throw t - } finally { - zipOut.close() - } + } finally zipOut.close() } /** @@ -173,11 +166,8 @@ object ZipHelper { val uri = new URI("jar", zipFile.toPath.toUri().toString(), null) val system = FileSystems.newFileSystem(uri, env) - try { - f(system) - } finally { - system.close() - } + try f(system) + finally system.close() } } diff --git a/src/main/scala/com/typesafe/sbt/packager/validation/Validation.scala b/src/main/scala/com/typesafe/sbt/packager/validation/Validation.scala index f25b7afae..3499423c9 100644 --- a/src/main/scala/com/typesafe/sbt/packager/validation/Validation.scala +++ b/src/main/scala/com/typesafe/sbt/packager/validation/Validation.scala @@ -15,7 +15,6 @@ object Validation { /** * A validator is a function that returns a list of validation results. * - * * @example Usually a validator is a function that captures some setting or task value, e.g. * {{{ * validatePackageValidators += { @@ -27,19 +26,18 @@ object Validation { * }}} * * The `validation` package object contains various standard validators. - * */ type Validator = () => List[ValidationResult] /** - * * @param validators a list of validators that produce a `Validation` result * @return aggregated result of all validator function */ - def apply(validators: Seq[Validator]): Validation = validators.flatMap(_.apply()).foldLeft(Validation(Nil, Nil)) { - case (validation, error: ValidationError) => validation.copy(errors = validation.errors :+ error) - case (validation, warning: ValidationWarning) => validation.copy(warnings = validation.warnings :+ warning) - } + def apply(validators: Seq[Validator]): Validation = + validators.flatMap(_.apply()).foldLeft(Validation(Nil, Nil)) { + case (validation, error: ValidationError) => validation.copy(errors = validation.errors :+ error) + case (validation, warning: ValidationWarning) => validation.copy(warnings = validation.warnings :+ warning) + } /** * Runs a list of validators and throws an exception after printing all @@ -63,9 +61,8 @@ object Validation { log.error(error.howToFix) } - if (errors.nonEmpty) { + if (errors.nonEmpty) sys.error(s"${errors.length} error(s) found") - } log.success("All package validations passed") } diff --git a/src/main/scala/com/typesafe/sbt/packager/validation/ValidationKeys.scala b/src/main/scala/com/typesafe/sbt/packager/validation/ValidationKeys.scala index d291a7018..93e97a9ca 100644 --- a/src/main/scala/com/typesafe/sbt/packager/validation/ValidationKeys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/validation/ValidationKeys.scala @@ -10,7 +10,6 @@ trait ValidationKeys { * - `sbt universal:packageBin::validatePackage` * - `sbt debian:packageBin::validatePackage` * - * * Each format should implement it's own validate. * Implemented in #1026 */ diff --git a/src/main/scala/com/typesafe/sbt/packager/validation/package.scala b/src/main/scala/com/typesafe/sbt/packager/validation/package.scala index b03aba8ed..b6a261fdc 100644 --- a/src/main/scala/com/typesafe/sbt/packager/validation/package.scala +++ b/src/main/scala/com/typesafe/sbt/packager/validation/package.scala @@ -6,7 +6,6 @@ import sbt._ * == validation == * * This package contains stanard validators that can be used by format and archetype plugins. - * */ package object validation { @@ -16,62 +15,62 @@ package object validation { * @param mappings the mappings that should be validated * @return a validator that checks if the mappins are empty */ - def nonEmptyMappings(mappings: Seq[(File, String)]): Validation.Validator = () => { - if (mappings.isEmpty) { - List( - ValidationError( - description = "You have no mappings defined! This will result in an empty package", - howToFix = "Try enabling an archetype, e.g. `enablePlugins(JavaAppPackaging)`" + def nonEmptyMappings(mappings: Seq[(File, String)]): Validation.Validator = + () => { + if (mappings.isEmpty) + List( + ValidationError( + description = "You have no mappings defined! This will result in an empty package", + howToFix = "Try enabling an archetype, e.g. `enablePlugins(JavaAppPackaging)`" + ) ) - ) - } else { - List.empty + else + List.empty } - } /** - * * @param mappings * @return */ - def filesExist(mappings: Seq[(File, String)]): Validation.Validator = () => { - // check that all files exist - mappings - .filter { - case (f, _) => !f.exists - } - .map { - case (file, dest) => - ValidationError( - description = s"Not found: ${file.getAbsolutePath} (mapped to $dest)", - howToFix = "Generate the file in the task/setting that adds it to the mappings task" - ) - } - .toList - } + def filesExist(mappings: Seq[(File, String)]): Validation.Validator = + () => { + // check that all files exist + mappings + .filter { + case (f, _) => !f.exists + } + .map { + case (file, dest) => + ValidationError( + description = s"Not found: ${file.getAbsolutePath} (mapped to $dest)", + howToFix = "Generate the file in the task/setting that adds it to the mappings task" + ) + } + .toList + } - def checkMaintainer(maintainer: String, asWarning: Boolean): Validation.Validator = () => { - if (maintainer.isEmpty) { - val description = "The maintainer is empty" - val howToFix = """|Add this to your build.sbt + def checkMaintainer(maintainer: String, asWarning: Boolean): Validation.Validator = + () => { + if (maintainer.isEmpty) { + val description = "The maintainer is empty" + val howToFix = """|Add this to your build.sbt | maintainer := "your.name@company.org"""".stripMargin - val result = if (asWarning) ValidationWarning(description, howToFix) else ValidationError(description, howToFix) - List(result) - } else { - List.empty + val result = if (asWarning) ValidationWarning(description, howToFix) else ValidationError(description, howToFix) + List(result) + } else + List.empty } - } - def epochIsNaturalNumber(epoch: Int): Validation.Validator = () => { - if (epoch < 0) { - ValidationError( - description = s"The Epoch cannot be a negative number (found $epoch)", - howToFix = "Change rpmEpoch to Some(n), where n >= 0" - ) :: Nil - } else { - Nil + def epochIsNaturalNumber(epoch: Int): Validation.Validator = + () => { + if (epoch < 0) + ValidationError( + description = s"The Epoch cannot be a negative number (found $epoch)", + howToFix = "Change rpmEpoch to Some(n), where n >= 0" + ) :: Nil + else + Nil } - } } diff --git a/src/main/scala/com/typesafe/sbt/packager/windows/WindowsPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/windows/WindowsPlugin.scala index d4470b59d..334055dbb 100644 --- a/src/main/scala/com/typesafe/sbt/packager/windows/WindowsPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/windows/WindowsPlugin.scala @@ -142,10 +142,11 @@ object WindowsPlugin extends AutoPlugin { /** * set the `mappings in Windows` and the `wixFeatures` */ - def mapGenericFilesToWindows: Seq[Setting[_]] = Seq( - mappings in Windows := (mappings in Universal).value, - wixFeatures := makeWindowsFeatures((packageName in Windows).value, (mappings in Windows).value) - ) + def mapGenericFilesToWindows: Seq[Setting[_]] = + Seq( + mappings in Windows := (mappings in Universal).value, + wixFeatures := makeWindowsFeatures((packageName in Windows).value, (mappings in Windows).value) + ) /** * Generates the wix configuration features diff --git a/src/main/scala/com/typesafe/sbt/packager/windows/WixHelper.scala b/src/main/scala/com/typesafe/sbt/packager/windows/WixHelper.scala index 15b2c5f12..e815d79fc 100644 --- a/src/main/scala/com/typesafe/sbt/packager/windows/WixHelper.scala +++ b/src/main/scala/com/typesafe/sbt/packager/windows/WixHelper.scala @@ -7,33 +7,36 @@ import sbt._ import collection.mutable.ArrayBuffer -case class WindowsProductInfo(id: String, // UUID of the package - title: String, // Human readable name of the package - version: String, // Windows version - maintainer: String, - description: String, - upgradeId: String, // UUID for upgrading - comments: String = "", - installScope: String = "perMachine", - installerVersion: String = "200", - compressed: Boolean = true) +case class WindowsProductInfo( + id: String, // UUID of the package + title: String, // Human readable name of the package + version: String, // Windows version + maintainer: String, + description: String, + upgradeId: String, // UUID for upgrading + comments: String = "", + installScope: String = "perMachine", + installerVersion: String = "200", + compressed: Boolean = true +) sealed trait FeatureComponent /** Define a new feature, that will be selectable in the default MSI. */ -case class WindowsFeature(id: String, - title: String, - desc: String, - absent: String = "allow", - level: String = "1", - display: String = "collapse", - components: Seq[FeatureComponent] = Seq.empty) - extends FeatureComponent +case class WindowsFeature( + id: String, + title: String, + desc: String, + absent: String = "allow", + level: String = "1", + display: String = "collapse", + components: Seq[FeatureComponent] = Seq.empty +) extends FeatureComponent /** Adds a file into a given windows feature. */ case class ComponentFile(source: String, editable: Boolean = false) extends FeatureComponent -/** Define wix namespace definitions, that depend on the major version of Wix tools **/ +/** Define wix namespace definitions, that depend on the major version of Wix tools * */ case class NamespaceDefinitions(majorVersionNumber: Int, namespace: String, utilExtension: String) /** @@ -52,10 +55,12 @@ object WixHelper { def makeGUID: String = java.util.UUID.randomUUID.toString // TODO - Fragment out this function a bit so it's not so ugly/random. - def makeWixProductConfig(name: String, - product: WindowsProductInfo, - features: Seq[WindowsFeature], - license: Option[File] = None): scala.xml.Node = { + def makeWixProductConfig( + name: String, + product: WindowsProductInfo, + features: Seq[WindowsFeature], + license: Option[File] = None + ): scala.xml.Node = { // TODO - First we find directories... // Adds all subdirectories... there was a bug when there were directories with only subdirs and no files in the tree, // so there was a gap and dirXml failed to create some directories @@ -82,7 +87,7 @@ object WixHelper { def dirXml(currentDir: String): scala.xml.Node = if (!currentDir.isEmpty) { val children = dirToChildren.getOrElse(currentDir, Seq.empty) - + { children map dirXml } @@ -91,72 +96,76 @@ object WixHelper { // We need component helpers... case class ComponentInfo(id: String, xml: scala.xml.Node) - def makeComponentInfo(c: FeatureComponent): ComponentInfo = c match { - case w: WindowsFeature => - sys.error("Nested windows features currently unsupported!") - case AddDirectoryToPath(dir) => - val dirRef = if (dir.isEmpty) "INSTALLDIR" else cleanStringForId(dir) - val homeEnvVar = NameHelper.makeEnvFriendlyName(name) + "_HOME" - val pathAddition = - if (dir.isEmpty) "%" + homeEnvVar + "%" - else "[INSTALLDIR]" + dir.replaceAll("\\/", "\\\\") - val id = cleanStringWithPostfix(dir, 64, "PathC") - val guid = makeGUID - val xml = - - + def makeComponentInfo(c: FeatureComponent): ComponentInfo = + c match { + case w: WindowsFeature => + sys.error("Nested windows features currently unsupported!") + case AddDirectoryToPath(dir) => + val dirRef = if (dir.isEmpty) "INSTALLDIR" else cleanStringForId(dir) + val homeEnvVar = NameHelper.makeEnvFriendlyName(name) + "_HOME" + val pathAddition = + if (dir.isEmpty) "%" + homeEnvVar + "%" + else "[INSTALLDIR]" + dir.replaceAll("\\/", "\\\\") + val id = cleanStringWithPostfix(dir, 64, "PathC") + val guid = makeGUID + val xml = + + - - + + - ComponentInfo(id, xml) - case ComponentFile(name, editable) => - val uname = name.replaceAll("\\\\", "/") - val dir = parentDir(uname).replaceAll("//", "/").stripSuffix("/").stripSuffix("/") - val dirRef = if (dir.isEmpty) "INSTALLDIR" else cleanStringForId(dir) - val fname = simpleName(uname) - val id = cleanStringWithPostfix(uname, 66, "") // Room for "fl_" - val xml = - - - + ComponentInfo(id, xml) + case ComponentFile(name, editable) => + val uname = name.replaceAll("\\\\", "/") + val dir = parentDir(uname).replaceAll("//", "/").stripSuffix("/").stripSuffix("/") + val dirRef = if (dir.isEmpty) "INSTALLDIR" else cleanStringForId(dir) + val fname = simpleName(uname) + val id = cleanStringWithPostfix(uname, 66, "") // Room for "fl_" + val xml = + + + { - if (editable) { - + if (editable) + - } else Seq.empty - } + else Seq.empty + } - ComponentInfo(id, xml) - // TODO - To have shortcuts, you MUST put something in the registry. Here, - // We should have shortcuts actually provide us with what they want in the registry, - // rather than forcing it to be something. - // Also, we need some mechanism to ensure the start menu folder is removed in the event - // that we remove all menu items. - case AddShortCuts(targets, workingDir) => - val targetSize = targets.size.toString.size - val id = cleanStringWithPostfix("shortcut_" + makeGUID, 67 - targetSize, "") // Room for "_SC"+incremental number - val xml = - - + ComponentInfo(id, xml) + // TODO - To have shortcuts, you MUST put something in the registry. Here, + // We should have shortcuts actually provide us with what they want in the registry, + // rather than forcing it to be something. + // Also, we need some mechanism to ensure the start menu folder is removed in the event + // that we remove all menu items. + case AddShortCuts(targets, workingDir) => + val targetSize = targets.size.toString.size + val id = + cleanStringWithPostfix("shortcut_" + makeGUID, 67 - targetSize, "") // Room for "_SC"+incremental number + val xml = + + { - for ((target, i) <- targets.zipWithIndex) yield { - val name = simpleName(target) - val desc = "Edit configuration file: " + name - val cleanName = name.replaceAll("[\\.-\\\\//]+", "_") - - } + for ((target, i) <- targets.zipWithIndex) yield { + val name = simpleName(target) + val desc = "Edit configuration file: " + name + val cleanName = name.replaceAll("[\\.-\\\\//]+", "_") + } - + } + - ComponentInfo(id, xml) - } + ComponentInfo(id, xml) + } val componentMap = (for (f <- features) yield { @@ -172,64 +181,72 @@ object WixHelper { - - + + - + - - { dirToChildren("") map dirXml } + + {dirToChildren("") map dirXml} { - for { - (fid, components) <- componentMap - ComponentInfo(cid, xml) <- components - } yield xml - } + for { + (fid, components) <- componentMap + ComponentInfo(cid, xml) <- components + } yield xml + } - + - + { - for (f <- features) - yield + for (f <- features) + yield { - for (ComponentInfo(id, _) <- componentMap.getOrElse(f.id, Seq.empty)) - yield - } + for (ComponentInfo(id, _) <- componentMap.getOrElse(f.id, Seq.empty)) + yield + } - } + } { - license.toSeq map { file => - - } + license.toSeq map { file => + } + } } - def makeWixConfig(name: String, // package name - product: WindowsProductInfo, - namespaceDefinitions: NamespaceDefinitions, - rest: xml.Node): xml.Node = - - - - - { rest } + def makeWixConfig( + name: String, // package name + product: WindowsProductInfo, + namespaceDefinitions: NamespaceDefinitions, + rest: xml.Node + ): xml.Node = + + + + + {rest} @@ -291,8 +308,10 @@ object WixHelper { def handleFile(f: File): (Seq[String], scala.xml.Node) = { val id = makeId(f) val xml = ( - - + + ) (Seq(id), xml) @@ -300,16 +319,16 @@ object WixHelper { def handleDirectory(dir: File): (Seq[String], scala.xml.Node) = { val buf: ArrayBuffer[String] = ArrayBuffer.empty val xml = ( - + { - for { - file <- IO.listFiles(dir) - (ids, xml) = recursiveHelper(file) - } yield { - buf.appendAll(ids) - xml - } + for { + file <- IO.listFiles(dir) + (ids, xml) = recursiveHelper(file) + } yield { + buf.appendAll(ids) + xml } + } ) (buf.toSeq, xml)