From 0ae7c539ff72a54bf107e07d14e88e8189f5d169 Mon Sep 17 00:00:00 2001 From: Adriaan Groenenboom Date: Thu, 10 Oct 2024 16:27:06 +0200 Subject: [PATCH] WIP: cross build with sbt 2.x --- .scalafmt.conf | 2 +- build.sbt | 16 +- .../com/typesafe/sbt/packager/Compat.scala | 54 +++++ .../sbt/packager/MappingsHelper.scala | 160 +++++++++++++ .../sbt/packager/SettingsHelper.scala | 110 +++++++++ .../com/typesafe/sbt/PackagerPlugin.scala | 38 +-- .../sbt/packager/archetypes/JavaAppKeys.scala | 7 +- .../archetypes/JavaAppPackaging.scala | 191 +++++++-------- .../packager/archetypes/TemplateWriter.scala | 2 +- .../archetypes/jlink/JlinkPlugin.scala | 11 +- .../debian/DebianNativePackaging.scala | 13 +- .../typesafe/sbt/packager/debian/Keys.scala | 5 +- .../sbt/packager/docker/dockerfile.scala | 2 +- .../GraalVMNativeImagePlugin.scala | 32 +-- .../jdkpackager/JDKPackagerAntHelper.scala | 24 +- .../typesafe/sbt/packager/rpm/RpmHelper.scala | 2 +- .../typesafe/sbt/packager/rpm/RpmPlugin.scala | 125 +++++----- .../sbt/packager/universal/Keys.scala | 7 +- .../sbt/packager/windows/WindowsPlugin.scala | 217 +++++++++--------- .../sbt/packager/windows/WixHelper.scala | 44 ++-- .../src/main/scala/ExampleApp.scala | 2 +- .../src/main/scala/ExampleApp.scala | 2 +- .../src/main/scala/ExampleApp.scala | 2 +- .../src/main/scala/ExampleApp.scala | 2 +- 24 files changed, 690 insertions(+), 380 deletions(-) create mode 100644 src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/Compat.scala create mode 100644 src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/MappingsHelper.scala create mode 100644 src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/SettingsHelper.scala diff --git a/.scalafmt.conf b/.scalafmt.conf index 84293359d..88905a4de 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,7 +1,7 @@ # Version https://scalameta.org/scalafmt/docs/configuration.html#version version = 3.8.3 # Dialect https://scalameta.org/scalafmt/docs/configuration.html#scala-dialects -runner.dialect = scala212 +runner.dialect = scala3 style = IntelliJ maxColumn = 120 diff --git a/build.sbt b/build.sbt index 3d81d0e1d..b4aa2c843 100644 --- a/build.sbt +++ b/build.sbt @@ -3,12 +3,18 @@ organization := "com.github.sbt" homepage := Some(url("https://github.com/sbt/sbt-native-packager")) Global / onChangedBuildSource := ReloadOnSourceChanges -Global / scalaVersion := "2.12.20" +Global / scalaVersion := "3.3.4" -// crossBuildingSettings -crossSbtVersions := Vector("1.1.6") +crossScalaVersions := Seq("2.12.20", "3.3.4") -Compile / scalacOptions ++= Seq("-deprecation") +(pluginCrossBuild / sbtVersion) := { + scalaBinaryVersion.value match { + case "2.12" => "1.1.6" + case _ => "2.0.0-M2" + } +} + +Compile / scalacOptions ++= Seq("-deprecation", "-rewrite", "-source", "3.0-migration") javacOptions ++= Seq("-source", "1.8", "-target", "1.8") // put jdeb on the classpath for scripted tests @@ -37,7 +43,7 @@ libraryDependencies ++= { // scala version depended libraries libraryDependencies ++= { scalaBinaryVersion.value match { - case "2.10" => Nil + case "2.10" | "3" => Nil case _ => Seq( // Do NOT upgrade these dependencies to 2.x or newer! sbt-native-packager is a sbt-plugin diff --git a/src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/Compat.scala b/src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/Compat.scala new file mode 100644 index 000000000..b0ef0a3a6 --- /dev/null +++ b/src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/Compat.scala @@ -0,0 +1,54 @@ +package com.typesafe.sbt.packager + +import sbt.{librarymanagement as lm, PathFinder, File} +import sbt.internal.{librarymanagement as ilm, BuildDependencies as InternalBuildDependencies} +import sbt.util.CacheStore + +import java.nio.file.Path + +object Compat { + val IvyActions = ilm.IvyActions + type IvySbt = ilm.IvySbt + type IvyScala = sbt.librarymanagement.ScalaModuleInfo + val IvyScala = sbt.librarymanagement.ScalaModuleInfo + + type UpdateConfiguration = lm.UpdateConfiguration + + /** + * Used in + * - [[com.typesafe.sbt.packager.archetypes.JavaAppPackaging]] + */ + type BuildDependencies = InternalBuildDependencies + + /** + */ + type Process = sys.process.Process + + /** + * Used in + * - [[com.typesafe.sbt.packager.docker.DockerPlugin]] + */ + type ProcessLogger = sys.process.ProcessLogger + + /** + * Used in + * - [[com.typesafe.sbt.packager.Stager]] + * @param file + * @return + * a CacheStore + */ + implicit def fileToCacheStore(file: java.io.File): CacheStore = CacheStore(file) + + type CompatFile = xsbti.HashedVirtualFileRef + + def fromFile(file: File, extracted: sbt.Extracted): CompatFile = { + extracted.get(sbt.Keys.fileConverter).toVirtualFile(Path.of(file.toURI)) + } + + def toFile(file: CompatFile, extracted: sbt.Extracted): File = { + extracted.get(sbt.Keys.fileConverter).toPath(file).toFile + } + + val moduleKey = sbt.Keys.moduleIDStr + val artifactKey = sbt.Keys.artifactStr +} diff --git a/src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/MappingsHelper.scala b/src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/MappingsHelper.scala new file mode 100644 index 000000000..780a2083c --- /dev/null +++ b/src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/MappingsHelper.scala @@ -0,0 +1,160 @@ +package com.typesafe.sbt.packager + +import sbt.* +import sbt.io.* +import sbt.librarymanagement.LibraryManagementCodec.* +import sjsonnew.support.scalajson.unsafe.* +import sjsonnew.JsonFormat +import Compat.* + + +/** A set of helper methods to simplify the writing of mappings */ +object MappingsHelper extends Mapper { + + /** + * It lightens the build file if one wants to give a string instead of file. + * + * @example + * {{{ + * mappings in Universal ++= directory("extra") + * }}} + * + * @param sourceDir + * @return + * mappings + */ + def directory(sourceDir: String): Seq[(File, String)] = + directory(file(sourceDir)) + + /** + * It lightens the build file if one wants to give a string instead of file. + * + * @example + * {{{ + * mappings in Universal ++= contentOf("extra") + * }}} + * + * @param sourceDir + * as string representation + * @return + * mappings + */ + def contentOf(sourceDir: String): Seq[(File, String)] = + contentOf(file(sourceDir)) + + /** + * 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") + * }}} + * + * @param entries + * @param target + * @return + * a list of mappings + */ + def fromClasspath(entries: Def.Classpath, target: String, extracted: Extracted): Seq[(File, String)] = + fromClasspath(entries, target, extracted, _ => true) + + /** + * Create mappings from your classpath. For example if you want to add additional dependencies, like test or model. + * You can also filter the artifacts that should be mapped to mappings. + * + * @example + * Filter all osgi bundles + * {{{ + * Universal / mappings ++= fromClasspath( + * (Runtime / managedClasspath).value, + * "osgi", + * artifact => artifact.`type` == "bundle" + * ) + * }}} + * + * @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: Def.Classpath, + target: String, + extracted: Extracted, + includeArtifact: Artifact => Boolean, + includeOnNoArtifact: Boolean = false + ): Seq[(File, String)] = + // TODO: test: https://github.com/sbt/sbt/blob/78ac6d38097dac7eed75e857edb2262d05ce219e/main/src/main/scala/sbt/Defaults.scala#L4566 + entries + .filter(attr => + attr + .get(sbt.Keys.artifactStr) + .map(artifactFromStr) + .map(includeArtifact) + .getOrElse(includeOnNoArtifact) + ) + .map { attribute => + val file = Compat.toFile(attribute.data, extracted) + file -> s"$target/${file.getName}" + } + + private def artifactFromStr(str: String): Artifact = { + val format: JsonFormat[Artifact] = summon[JsonFormat[Artifact]] + val json = Parser.parseFromString(str).get + Converter.fromJsonUnsafe(json)(format) + } + + private def artifactToStr(art: Artifact): String = { + val format: JsonFormat[Artifact] = summon[JsonFormat[Artifact]] + CompactPrinter(Converter.toJsonUnsafe(art)(format)) + } + + /** + * Get the mappings for the given files relative to the given directories. + */ + def relative(files: Seq[File], dirs: Seq[File]): Seq[(File, String)] = + (files --- dirs) pair (relativeTo(dirs) | flat) + + /** + * Constructs a jar name from components...(ModuleID/Artifact) + */ + def makeJarName( + org: String, + name: String, + revision: String, + artifactName: String, + artifactClassifier: Option[String] + ): String = + org + "." + + name + "-" + + Option(artifactName.replace(name, "")).filterNot(_.isEmpty).map(_ + "-").getOrElse("") + + revision + + artifactClassifier.filterNot(_.isEmpty).map("-" + _).getOrElse("") + + ".jar" + + // Determines a nicer filename for an attributed jar file, using the + // ivy metadata if available. + def getJarFullFilename(dep: Attributed[CompatFile], extracted: Extracted): String = { + val filename: Option[String] = for { + moduleStr <- dep.metadata.get(sbt.Keys.moduleIDStr) + artifactStr <- dep.metadata.get(sbt.Keys.artifactStr) + } yield { + val module = Classpaths.moduleIdJsonKeyFormat.read(moduleStr) + val artifact = artifactFromStr(artifactStr) + makeJarName(module.organization, module.name, module.revision, artifact.name, artifact.classifier) + } + filename.getOrElse(toFile(dep.data, extracted).getName) + } + + def getArtifact(file: Attributed[CompatFile]): Option[Artifact] = + file.get(sbt.Keys.artifactStr).map(artifactFromStr) + + def setArtifact(artifact: Artifact, attr: Attributed[CompatFile]): Attributed[CompatFile] = + attr.put(sbt.Keys.artifactStr, artifactToStr(artifact)) + +} diff --git a/src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/SettingsHelper.scala b/src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/SettingsHelper.scala new file mode 100644 index 000000000..b19bdb350 --- /dev/null +++ b/src/main/scala-sbt-2.0.0-M2/com/typesafe/sbt/packager/SettingsHelper.scala @@ -0,0 +1,110 @@ +package com.typesafe.sbt.packager + +import sbt.* +import sbt.Keys.* +import sbt.librarymanagement.{IvyFileConfiguration, PublishConfiguration} +import Compat.* + +/** + * - TODO write tests for the SettingsHelper + * - TODO document methods properly + * - TODO document the sbt internal stuff that is used + */ +object SettingsHelper { + def addPackage( + config: Configuration, + packageTask: TaskKey[CompatFile], + 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[CompatFile], + 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( + artifacts := Seq.empty, + packagedArtifacts := Map.empty, + projectID := ModuleID(organization.value, name.value, version.value), + // Custom module settings to skip the ivy XmlModuleDescriptorParser + moduleSettings := ModuleDescriptorConfiguration(projectID.value, projectInfo.value) + .withScalaModuleInfo(scalaModuleInfo.value), + ivyModule := { + val ivy = ivySbt.value + new ivy.Module(moduleSettings.value) + }, + // Where have these settings gone? + // ------------------------------- + // deliverLocalConfiguration := Classpaths.deliverConfig(crossTarget.value, logging = ivyLoggingLevel.value) + // deliverConfiguration := deliverLocalConfiguration.value, + // ------------------------------- + publishConfiguration := { + val converter = fileConverter.value + PublishConfiguration() + .withResolverName(Classpaths.getPublishTo(publishTo.value).name) + .withArtifacts(packagedArtifacts.value.toVector.map { + case (artifact, virtualFile) => artifact -> converter.toPath(virtualFile).toFile + }) + .withChecksums(checksums.value.toVector) + .withOverwrite(isSnapshot.value) + .withLogging(UpdateLogging.DownloadOnly) + }, + publishLocalConfiguration := { + val converter = fileConverter.value + PublishConfiguration() + .withResolverName("local") + .withArtifacts(packagedArtifacts.value.toVector.map { + case (artifact, virtualFile) => artifact -> converter.toPath(virtualFile).toFile + }) + .withChecksums(checksums.value.toVector) + .withOverwrite(isSnapshot.value) + .withLogging(UpdateLogging.DownloadOnly) + }, + publishM2Configuration := { + val converter = fileConverter.value + PublishConfiguration() + .withResolverName(Resolver.mavenLocal.name) + .withArtifacts(packagedArtifacts.value.toVector.map { + case (artifact, virtualFile) => artifact -> converter.toPath(virtualFile).toFile + }) + .withChecksums(checksums.value.toVector) + .withOverwrite(isSnapshot.value) + .withLogging(UpdateLogging.DownloadOnly) + } + ) + ) ++ 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 + * Rpm / publishTo := 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 ++= (config / publishTo).value.toSeq) +} diff --git a/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala b/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala index 9465504ca..c7d5fb82d 100644 --- a/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala @@ -1,10 +1,10 @@ package com.typesafe.sbt -import packager._ -import debian.DebianPlugin.autoImport.genChanges +import com.typesafe.sbt.packager.* import com.typesafe.sbt.packager.Keys.{packageXzTarball, packageZipTarball, validatePackage, validatePackageValidators} +import com.typesafe.sbt.packager.debian.DebianPlugin.autoImport.genChanges import com.typesafe.sbt.packager.validation.Validation -import sbt._ +import sbt.* import sbt.Keys.{name, normalizedName, packageBin, streams} /** @@ -68,26 +68,26 @@ object SbtNativePackager extends AutoPlugin { */ object autoImport extends packager.NativePackagerKeys { - val NativePackagerKeys = packager.Keys - val NativePackagerHelper = packager.MappingsHelper + private val NativePackagerKeys = packager.Keys + private val NativePackagerHelper = packager.MappingsHelper - import SettingsHelper._ + import SettingsHelper.* @deprecated("Use enablePlugins(xxxDeployPlugin)", "1.x") - def deploymentSettings = - makeDeploymentSettings(Debian, packageBin in Debian, "deb") ++ - makeDeploymentSettings(Rpm, packageBin in Rpm, "rpm") ++ - makeDeploymentSettings(Windows, packageBin in Windows, "msi") ++ - makeDeploymentSettings(Universal, packageBin in Universal, "zip") ++ - addPackage(Universal, packageZipTarball in Universal, "tgz") ++ - makeDeploymentSettings(UniversalDocs, packageBin in UniversalDocs, "zip") ++ - addPackage(UniversalDocs, packageXzTarball in UniversalDocs, "txz") ++ - makeDeploymentSettings(Debian, genChanges in Debian, "changes") + def deploymentSettings: Seq[Setting[?]] = + makeDeploymentSettings(Debian, Debian / packageBin, "deb") ++ + makeDeploymentSettings(Rpm, Rpm / packageBin, "rpm") ++ + makeDeploymentSettings(Windows, Windows / packageBin, "msi") ++ + makeDeploymentSettings(Universal, Universal / packageBin, "zip") ++ + addPackage(Universal, Universal / packageZipTarball, "tgz") ++ + makeDeploymentSettings(UniversalDocs, UniversalDocs / packageBin, "zip") ++ + addPackage(UniversalDocs, UniversalDocs / packageXzTarball, "txz") ++ + makeDeploymentSettings(Debian, Debian / genChanges, "changes") } - import autoImport._ + import autoImport.* - override lazy val projectSettings = Seq( + override lazy val projectSettings: Seq[Setting[?]] = Def.settings( // Bad defaults that let us at least not explode users who don't care about native packagers maintainer := "", packageDescription := name.value, @@ -110,7 +110,7 @@ object SbtNativePackager extends AutoPlugin { * }}} */ @deprecated("Use enablePlugins(JavaAppPackaging)", "1.x") - def java_application: Seq[Setting[_]] = + def java_application: Seq[Setting[?]] = projectSettings ++ universal.UniversalPlugin.projectSettings ++ linux.LinuxPlugin.projectSettings ++ @@ -126,7 +126,7 @@ object SbtNativePackager extends AutoPlugin { * }}} */ @deprecated("Use enablePlugins(JavaServerAppPackaging)", "1.x") - def java_server: Seq[Setting[_]] = + def java_server: Seq[Setting[?]] = java_application ++ archetypes.JavaServerAppPackaging.projectSettings } diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppKeys.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppKeys.scala index 22cd57a18..bf6c43377 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppKeys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppKeys.scala @@ -1,6 +1,7 @@ package com.typesafe.sbt.packager.archetypes -import sbt._ +import com.typesafe.sbt.packager.Compat.CompatFile +import sbt.* /** * Available settings/tasks for the [[com.typesafe.sbt.packager.archetypes.JavaAppPackaging]] and all depending @@ -14,11 +15,11 @@ trait JavaAppKeys { "bashScriptEnvConfigLocation", "The location of a bash script that will be sourced before running the app." ) - val scriptClasspathOrdering = TaskKey[Seq[(File, String)]]( + val scriptClasspathOrdering = TaskKey[Seq[(CompatFile, String)]]( "scriptClasspathOrdering", "The order of the classpath used at runtime for the bat/bash scripts." ) - val projectDependencyArtifacts = TaskKey[Seq[Attributed[File]]]( + val projectDependencyArtifacts = TaskKey[Def.Classpath]( "projectDependencyArtifacts", "The set of exported artifacts from our dependent projects." ) 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 0dcb13aea..adfcd6e21 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppPackaging.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppPackaging.scala @@ -1,13 +1,14 @@ package com.typesafe.sbt.packager.archetypes -import sbt._ -import sbt.Keys._ import com.typesafe.sbt.SbtNativePackager.{Debian, Universal} -import com.typesafe.sbt.packager._ +import com.typesafe.sbt.packager.* +import com.typesafe.sbt.packager.Compat.* import com.typesafe.sbt.packager.Keys.packageName -import com.typesafe.sbt.packager.linux.{LinuxFileMetaData, LinuxPackageMapping} import com.typesafe.sbt.packager.linux.LinuxPlugin.autoImport.{defaultLinuxInstallLocation, linuxPackageMappings} -import com.typesafe.sbt.packager.Compat._ +import com.typesafe.sbt.packager.linux.{LinuxFileMetaData, LinuxPackageMapping} +import sbt.* +import sbt.Keys.* +import Compat.* /** * ==Java Application== @@ -37,45 +38,51 @@ object JavaAppPackaging extends AutoPlugin { object autoImport extends JavaAppKeys with JavaAppKeys2 with MaintainerScriptHelper - import JavaAppPackaging.autoImport._ + import JavaAppPackaging.autoImport.* 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[Def.Setting[?]] = Def.settings( + Universal / javaOptions := 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 = (Compile / packageBin).value + val id = projectID.value + val art = (Compile / packageBin / artifact).value + jar -> ("lib/" + MappingsHelper.makeJarName(id.organization, id.name, id.revision, art.name, art.classifier)) + }, + projectDependencyArtifacts := findProjectDependencyArtifacts.value, + scriptClasspathOrdering ++= universalDepMappings( + (Runtime / dependencyClasspath).value, + projectDependencyArtifacts.value, + Project.extract(state.value) + ), + scriptClasspathOrdering := scriptClasspathOrdering.value.distinct, + Universal / mappings ++= scriptClasspathOrdering.value, + scriptClasspath := { + val extracted = Project.extract(state.value) + val ordering = scriptClasspathOrdering.value.map { case (file, s) => + toFile(file, extracted) -> s + } + makeRelativeClasspathNames(ordering) + }, + Debian / linuxPackageMappings += { + val name = (Debian / packageName).value + val installLocation = defaultLinuxInstallLocation.value + val targetDir = (Debian / target).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 { @@ -86,89 +93,60 @@ object JavaAppPackaging extends AutoPlugin { 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 = - org + "." + - name + "-" + - Option(artifactName.replace(name, "")).filterNot(_.isEmpty).map(_ + "-").getOrElse("") + - revision + - artifactClassifier.filterNot(_.isEmpty).map("-" + _).getOrElse("") + - ".jar" - - // Determines a nicer filename for an attributed jar file, using the - // 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"))) - artifact <- dep.metadata.get(AttributeKey[Artifact]("artifact")) - } yield makeJarName(module.organization, module.name, module.revision, artifact.name, artifact.classifier) - filename.getOrElse(dep.data.getName) - } - // Here we grab the dependencies... - private def dependencyProjectRefs(build: BuildDependencies, thisProject: ProjectRef): Seq[ProjectRef] = + private def dependencyProjectRefs(build: Compat.BuildDependencies, thisProject: ProjectRef): Seq[ProjectRef] = build.classpathTransitive.getOrElse(thisProject, Nil) // TODO - Should we pull in more than just JARs? How do native packages come in? - private def isRuntimeArtifact(dep: Attributed[File]): Boolean = - dep.get(sbt.Keys.artifact.key).map(_.`type` == "jar").getOrElse { - val name = dep.data.getName + private def isRuntimeArtifact(dep: Attributed[CompatFile], extracted: Extracted): Boolean = + MappingsHelper.getArtifact(dep).map(_.`type` == "jar").getOrElse { + val name = Compat.toFile(dep.data, extracted).getName !(name.endsWith(".jar") || name.endsWith("-sources.jar") || name.endsWith("-javadoc.jar")) } - private def findProjectDependencyArtifacts: Def.Initialize[Task[Seq[Attributed[File]]]] = - Def - .task { - val stateTask = state.taskValue - val refs = thisProjectRef.value +: dependencyProjectRefs(buildDependencies.value, thisProjectRef.value) - // Dynamic lookup of dependencies... - val artTasks = refs map { ref => - extractArtifacts(stateTask, ref) - } - val allArtifactsTask: Task[Seq[Attributed[File]]] = - artTasks.fold[Task[Seq[Attributed[File]]]](task(Nil)) { (previous, next) => - for { - p <- previous - n <- next - } yield p ++ n.filter(isRuntimeArtifact) - } - allArtifactsTask + private def findProjectDependencyArtifacts: Def.Initialize[Task[Def.Classpath]] = + Def.task { + val stateTask = state.taskValue + val refs = thisProjectRef.value +: dependencyProjectRefs(buildDependencies.value, thisProjectRef.value) + val extracted = Project.extract(state.value) + // Dynamic lookup of dependencies... + val artTasks = refs map { ref => + extractArtifacts(stateTask, ref) } - .flatMap(identity) + artTasks + .fold[Task[Def.Classpath]](task(Nil)) { (previous, next) => + for { + p <- previous + n <- next + } yield p ++ n.filter(isRuntimeArtifact(_, extracted)) + } + .value + } - private def extractArtifacts(stateTask: Task[State], ref: ProjectRef): Task[Seq[Attributed[File]]] = + private def extractArtifacts(stateTask: Task[State], ref: ProjectRef): Task[Def.Classpath] = stateTask.flatMap { state => val extracted = Project.extract(state) // TODO - Is this correct? - val module = extracted.get(projectID in ref) - val artifactTask = extracted.get(packagedArtifacts in ref) + val module = extracted.get(ref / projectID) + val artifactTask = extracted.get(ref / packagedArtifacts) for { arts <- artifactTask } yield for { (art, file) <- arts.toSeq // TODO -Filter! - } yield Attributed.blank(file).put(moduleID.key, module).put(artifact.key, art) + } yield MappingsHelper.setArtifact(art, Attributed.blank(file)) } - private def findRealDep(dep: Attributed[File], projectArts: Seq[Attributed[File]]): Option[Attributed[File]] = - if (dep.data.isFile) Some(dep) + private def findRealDep( + dep: Attributed[CompatFile], + projectArts: Seq[Attributed[CompatFile]], + extracted: Extracted + ): Option[Attributed[CompatFile]] = + if (toFile(dep.data, extracted).isFile) Some(dep) 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)) && - (art.get(sbt.Keys.artifact.key), dep.get(sbt.Keys.artifact.key)) match { + (MappingsHelper.getArtifact(art), MappingsHelper.getArtifact(dep)) match { case (Some(l), Some(r)) => // TODO - extra attributes and stuff for comparison? // seems to break stuff if we do... @@ -179,11 +157,12 @@ object JavaAppPackaging extends AutoPlugin { // Converts a managed classpath into a set of lib mappings. private def universalDepMappings( - deps: Seq[Attributed[File]], - projectArts: Seq[Attributed[File]] - ): Seq[(File, String)] = + deps: Def.Classpath, + projectArts: Def.Classpath, + extracted: Extracted + ): Seq[(CompatFile, String)] = for { dep <- deps - realDep <- findRealDep(dep, projectArts) - } yield realDep.data -> ("lib/" + getJarFullFilename(realDep)) + realDep <- findRealDep(dep, projectArts, extracted) + } yield realDep.data -> ("lib/" + MappingsHelper.getJarFullFilename(realDep, extracted)) } 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 6a05541af..d3c750a64 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/TemplateWriter.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/TemplateWriter.scala @@ -49,7 +49,7 @@ object TemplateWriter { sb append replace(line, replacements, keySurround) sb append eol } - sb toString + sb.toString } private[this] def replaceValues( 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 5efedd9ae..dff264b08 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 @@ -3,12 +3,11 @@ package jlink import scala.collection.immutable import scala.sys.process.{BasicIO, Process, ProcessBuilder} -import sbt._ -import sbt.Keys._ +import sbt.* +import sbt.Keys.* import com.typesafe.sbt.SbtNativePackager.{Debian, Universal} import com.typesafe.sbt.packager.Keys.{bundledJvmLocation, packageName} -import com.typesafe.sbt.packager.Compat._ -import com.typesafe.sbt.packager.archetypes.jlink._ +import com.typesafe.sbt.packager.archetypes.jlink.* import com.typesafe.sbt.packager.archetypes.scripts.BashStartScriptKeys import com.typesafe.sbt.packager.universal.UniversalPlugin import java.io.File @@ -36,11 +35,11 @@ object JlinkPlugin extends AutoPlugin { val JlinkIgnore: Ignore.type = JlinkPlugin.Ignore } - import autoImport._ + import autoImport.* override def requires: Plugins = JavaAppPackaging - override lazy val projectSettings: Seq[Setting[_]] = Seq( + override lazy val projectSettings: Seq[Setting[?]] = Def.settings( jlinkBuildImage / target := target.value / "jlink" / "output", jlinkBundledJvmLocation := "jre", bundledJvmLocation := Some(jlinkBundledJvmLocation.value), 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 5eb450fee..ac25ede04 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/DebianNativePackaging.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/DebianNativePackaging.scala @@ -1,11 +1,12 @@ package com.typesafe.sbt.packager.debian import com.typesafe.sbt.SbtNativePackager.Debian -import com.typesafe.sbt.packager.Keys._ +import com.typesafe.sbt.packager.Keys.* import com.typesafe.sbt.packager.linux.LinuxFileMetaData -import com.typesafe.sbt.packager.Compat._ -import sbt.Keys._ -import sbt._ +import sbt.* +import sbt.Keys.* + +import scala.compat.Platform.EOL /** * ==Native Packaging== @@ -32,7 +33,7 @@ trait DebianNativePackaging extends DebianPluginLike { /** * Using the native installed dpkg-build tools to build the debian package. */ - private[debian] def debianNativeSettings: Seq[Setting[_]] = + private[debian] def debianNativeSettings: Seq[Setting[?]] = inConfig(Debian)( Seq( debianNativeBuildOptions += "-Znone", // packages are largely JARs, which are already compressed @@ -90,7 +91,7 @@ trait DebianNativePackaging extends DebianPluginLike { IO.writeLines(changesFile, allChanges) } catch { case e: Exception => - sys.error("Failure generating changes file." + e.getStackTraceString) + sys.error("Failure generating changes file." + e.getStackTrace.mkString("", EOL, EOL)) } changesFile } diff --git a/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala b/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala index fb55453e0..df71d4165 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala @@ -2,7 +2,8 @@ package com.typesafe.sbt package packager package debian -import sbt._ +import Compat.* +import sbt.* import linux.LinuxPackageMapping /** DEB packaging specifc build targets. */ @@ -46,7 +47,7 @@ trait DebianKeys { val debianSign = TaskKey[File]("debian-sign", "runs the dpkg-sig command to sign the generated deb file.") val debianSignRole = SettingKey[String]("debian-sign-role", "The role to use when signing a debian file (defaults to 'builder').") - val genChanges = TaskKey[File]("gen-changes", "runs the dpkg-genchanges command to generate the .changes file.") + val genChanges = TaskKey[CompatFile]("gen-changes", "runs the dpkg-genchanges command to generate the .changes file.") // Debian control scripts val debianControlScriptsDirectory = SettingKey[File]( 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 87021d3a3..458a943c4 100644 --- a/src/main/scala/com/typesafe/sbt/packager/docker/dockerfile.scala +++ b/src/main/scala/com/typesafe/sbt/packager/docker/dockerfile.scala @@ -94,6 +94,6 @@ case class Dockerfile(commands: CmdLike*) { def makeContent: String = { val sb = new StringBuilder commands foreach { sb append _.makeContent } - sb toString + sb.toString } } 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 41f196c89..305cdc248 100644 --- a/src/main/scala/com/typesafe/sbt/packager/graalvmnativeimage/GraalVMNativeImagePlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/graalvmnativeimage/GraalVMNativeImagePlugin.scala @@ -2,11 +2,10 @@ package com.typesafe.sbt.packager.graalvmnativeimage import java.io.ByteArrayInputStream -import sbt._ -import sbt.Keys.{mainClass, name, _} +import sbt.* +import sbt.Keys.{mainClass, name, *} import com.typesafe.sbt.packager.{MappingsHelper, Stager} -import com.typesafe.sbt.packager.Keys._ -import com.typesafe.sbt.packager.Compat._ +import com.typesafe.sbt.packager.Keys.* import com.typesafe.sbt.packager.archetypes.JavaAppPackaging import com.typesafe.sbt.packager.docker.{Cmd, DockerPlugin, Dockerfile, ExecCmd} import com.typesafe.sbt.packager.universal.UniversalPlugin @@ -26,7 +25,7 @@ object GraalVMNativeImagePlugin extends AutoPlugin { val GraalVMNativeImage: Configuration = config("graalvm-native-image") } - import autoImport._ + import autoImport.* private val GraalVMBaseImage = "ghcr.io/graalvm/graalvm-ce" @@ -34,16 +33,19 @@ object GraalVMNativeImagePlugin extends AutoPlugin { override def projectConfigurations: Seq[Configuration] = Seq(GraalVMNativeImage) - override lazy val projectSettings: Seq[Setting[_]] = Seq( - target in GraalVMNativeImage := target.value / "graalvm-native-image", + override lazy val projectSettings: Seq[Setting[?]] = Def.settings( + inConfig(GraalVMNativeImage)(Def.settings( + scopedSettings, + resourceDirectory := sourceDirectory.value / "graal", + mainClass := (Compile / mainClass).value + )), + target := target.value / "graalvm-native-image", graalVMNativeImageOptions := Seq.empty, graalVMNativeImageGraalVersion := None, graalVMNativeImageCommand := (if (scala.util.Properties.isWin) "native-image.cmd" else "native-image"), - resourceDirectory in GraalVMNativeImage := sourceDirectory.value / "graal", - mainClass in GraalVMNativeImage := (mainClass in Compile).value - ) ++ inConfig(GraalVMNativeImage)(scopedSettings) + ) - private lazy val scopedSettings = Seq[Setting[_]]( + private lazy val scopedSettings = Seq[Setting[?]]( resourceDirectories := Seq(resourceDirectory.value), includeFilter := "*", resources := resourceDirectories.value.descendantsExcept(includeFilter.value, excludeFilter.value).get, @@ -166,15 +168,15 @@ object GraalVMNativeImagePlugin extends AutoPlugin { /** * This can be used to build a custom build image starting from a custom base image. Can be used like so: * - * ``` + * {{{ * (containerBuildImage in GraalVMNativeImage) := generateContainerBuildImage("my-docker-hub-username/my-graalvm").value - * ``` + * }}} * * 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 dockerCommand = (GraalVMNativeImage / DockerPlugin.autoImport.dockerExecCommand).value val streams = Keys.streams.value val (baseName, tag) = baseImage.split(":", 2) match { @@ -183,7 +185,7 @@ object GraalVMNativeImagePlugin extends AutoPlugin { } val imageName = s"${baseName.replace('/', '-')}-native-image:$tag" - import sys.process._ + 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") 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 9bdca3938..f4d77063e 100644 --- a/src/main/scala/com/typesafe/sbt/packager/jdkpackager/JDKPackagerAntHelper.scala +++ b/src/main/scala/com/typesafe/sbt/packager/jdkpackager/JDKPackagerAntHelper.scala @@ -39,11 +39,11 @@ object JDKPackagerAntHelper { // Unlift searchPoint `Option`-s, and for each base directory, add the parent variant to cover nested JREs on Unix. val entryPoints = - searchPoints.flatten.flatMap(f ⇒ Seq(f, f.getAbsoluteFile)) + searchPoints.flatten.flatMap(f => Seq(f, f.getAbsoluteFile)) // On Windows we're often running in the JRE and not the JDK. If JDK is installed, // it's likely to be in a parallel directory, with the "jre" prefix changed to "jdk" - val entryPointsSpecialCaseWindows = entryPoints.flatMap { f ⇒ + val entryPointsSpecialCaseWindows = entryPoints.flatMap { f => if (f.getName.startsWith("jre")) Seq(f, f.getParentFile / ("jdk" + f.getName.drop(3))) else Seq(f) @@ -52,11 +52,11 @@ object JDKPackagerAntHelper { // Now search for the tool entryPointsSpecialCaseWindows .map(_ / "lib" / jarname) - .find { f ⇒ + .find { f => logger.debug(s"Looking for '$jarname' in '${f.getParent}'"); f.exists() } - .map { f ⇒ + .map { f => logger.debug(s"Found '$f'!"); f } } @@ -234,7 +234,7 @@ object JDKPackagerAntHelper { Seq("*.dmg", "*.pkg", "*.app", "*.msi", "*.exe", "*.deb", "*.rpm") val finder = globs.foldLeft(PathFinder.empty)(_ +++ output ** _) val result = finder.getPaths.headOption - result.foreach(f ⇒ s.log.info("Wrote " + f)) + result.foreach(f => s.log.info("Wrote " + f)) result.map(file) } @@ -249,7 +249,7 @@ object JDKPackagerAntHelper { /** Build package via Ant build.xml definition. */ private[jdkpackager] def buildPackageWithAnt(buildXML: File, target: File, s: TaskStreams): File = { - import org.apache.tools.ant.{Project ⇒ AntProject} + import org.apache.tools.ant.{Project => AntProject} val ap = new AntProject ap.setUserProperty("ant.file", buildXML.getAbsolutePath) @@ -269,7 +269,7 @@ object JDKPackagerAntHelper { /** For piping Ant messages to sbt logger. */ private class AntLogAdapter(s: TaskStreams) extends BuildListener { - import org.apache.tools.ant.{Project ⇒ AntProject} + import org.apache.tools.ant.{Project => AntProject} def buildFinished(event: BuildEvent): Unit = () def buildStarted(event: BuildEvent): Unit = () def targetStarted(event: BuildEvent): Unit = () @@ -278,11 +278,11 @@ object JDKPackagerAntHelper { def taskStarted(event: BuildEvent): Unit = () def messageLogged(event: BuildEvent): Unit = event.getPriority match { - case AntProject.MSG_ERR ⇒ s.log.error(event.getMessage) - case AntProject.MSG_WARN ⇒ s.log.warn(event.getMessage) - case AntProject.MSG_INFO ⇒ s.log.info(event.getMessage) - case AntProject.MSG_VERBOSE ⇒ s.log.verbose(event.getMessage) - case _ ⇒ s.log.debug(event.getMessage) + case AntProject.MSG_ERR => s.log.error(event.getMessage) + case AntProject.MSG_WARN => s.log.warn(event.getMessage) + case AntProject.MSG_INFO => s.log.info(event.getMessage) + case AntProject.MSG_VERBOSE => s.log.verbose(event.getMessage) + case _ => s.log.debug(event.getMessage) } } } 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 00e58e599..31e862680 100644 --- a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmHelper.scala +++ b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmHelper.scala @@ -8,7 +8,7 @@ object RpmHelper { /** Returns the host vendor for an rpm. */ def hostVendor = - sys.process.Process(Seq("rpm", "-E", "%{_host_vendor}")) !! + sys.process.Process(Seq("rpm", "-E", "%{_host_vendor}")).!! /** * Prepares the staging directory for the rpm build command. 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 d5046d7f5..f746754d4 100644 --- a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala @@ -1,15 +1,14 @@ package com.typesafe.sbt.packager.rpm -import sbt._ -import sbt.Keys._ +import sbt.* +import sbt.Keys.* import java.nio.charset.Charset import com.typesafe.sbt.SbtNativePackager.Linux import com.typesafe.sbt.packager.SettingsHelper -import com.typesafe.sbt.packager.Keys._ -import com.typesafe.sbt.packager.linux._ -import com.typesafe.sbt.packager.Compat._ -import com.typesafe.sbt.packager.validation._ +import com.typesafe.sbt.packager.Keys.* +import com.typesafe.sbt.packager.linux.* +import com.typesafe.sbt.packager.validation.* /** * Plugin containing all generic values used for packaging rpms. @@ -22,14 +21,14 @@ import com.typesafe.sbt.packager.validation._ */ object RpmPlugin extends AutoPlugin { - override def requires = LinuxPlugin + override def requires: Plugins = LinuxPlugin object autoImport extends RpmKeys { val Rpm: Configuration = config("rpm") extend Linux - val RpmConstants = Names + val RpmConstants: Names.type = Names } - import autoImport._ + import autoImport.* private final def osPostInstallMacro: java.net.URL = getClass getResource "brpJavaRepackJar" @@ -64,7 +63,7 @@ object RpmPlugin extends AutoPlugin { override def projectConfigurations: Seq[Configuration] = Seq(Rpm) - override lazy val projectSettings = Seq( + override lazy val projectSettings: Seq[Setting[?]] = Def.settings( rpmOs := "Linux", // TODO - default to something else? rpmRelease := (if (isSnapshot.value) "SNAPSHOT" else "1"), rpmPrefix := None, @@ -94,35 +93,56 @@ object RpmPlugin extends AutoPlugin { rpmPreun := None, rpmPostun := None, rpmScriptsDirectory := sourceDirectory.value / "rpm" / Names.Scriptlets, - // Explicitly defer default settings to generic Linux Settings. - maintainerScripts in Rpm := (maintainerScripts in Linux).value, - packageSummary in Rpm := (packageSummary in Linux).value, - packageDescription in Rpm := (packageDescription in Linux).value, - target in Rpm := target.value / "rpm", - name in Rpm := (name in Linux).value, - packageName in Rpm := (packageName in Linux).value, - executableScriptName in Rpm := (executableScriptName in Linux).value, - rpmDaemonLogFile := s"${(packageName in Linux).value}.log", - daemonStdoutLogFile in Rpm := Some(rpmDaemonLogFile.value), - validatePackageValidators in Rpm := Seq( - nonEmptyMappings((linuxPackageMappings in Rpm).value.flatMap(_.mappings)), - filesExist((linuxPackageMappings in Rpm).value.flatMap(_.mappings)), - checkMaintainer((maintainer in Rpm).value, asWarning = false), - epochIsNaturalNumber((rpmEpoch in Rpm).value.getOrElse(0)) - ), - // override the linux sourceDirectory setting - sourceDirectory in Rpm := sourceDirectory.value, - packageArchitecture in Rpm := "noarch", + inConfig(Rpm)(Def.settings( + // Explicitly defer default settings to generic Linux Settings. + maintainerScripts := (Linux / maintainerScripts).value, + packageSummary := (Linux / packageSummary).value, + packageDescription := (Linux / packageDescription).value, + target := target.value / "rpm", + name := (Linux / name).value, + packageName := (Linux / packageName).value, + executableScriptName := (Linux / executableScriptName).value, + daemonStdoutLogFile := Some(rpmDaemonLogFile.value), + validatePackageValidators := Seq( + nonEmptyMappings((Rpm / linuxPackageMappings).value.flatMap(_.mappings)), + filesExist((Rpm / linuxPackageMappings).value.flatMap(_.mappings)), + checkMaintainer((Rpm / maintainer).value, asWarning = false), + epochIsNaturalNumber((Rpm / rpmEpoch).value.getOrElse(0)) + ), + // override the linux sourceDirectory setting + sourceDirectory := sourceDirectory.value, + packageArchitecture := "noarch", + maintainerScripts := { + val scripts = (Rpm / maintainerScripts).value + if (!rpmBrpJavaRepackJars.value) { + val pre = scripts.getOrElse(Names.Pre, Nil) + val scriptBits = IO.readStream(RpmPlugin.osPostInstallMacro.openStream, Charset forName "UTF-8") + scripts + (Names.Pre -> (pre :+ scriptBits)) + } else + scripts + }, + stage := RpmHelper.stage(rpmSpecConfig.value, (Rpm / target).value, streams.value.log), + packageBin := { + val defaultPath = RpmHelper.buildRpm(rpmSpecConfig.value, (Rpm / stage).value, streams.value.log) + // `file` points to where buildRpm created the rpm. However we want it to be at `artifactPath`. + // If `artifactPath` is not the default value then we need to copy the file. + val path = (artifactPath in (Rpm, packageBin)).value + if (path.getCanonicalFile != defaultPath.getCanonicalFile) IO.copyFile(defaultPath, path) + path + }, + )), + Rpm / packageBin / artifactPath := RpmHelper.defaultRpmArtifactPath((Rpm / target).value, rpmMetadata.value), + rpmDaemonLogFile := s"${(Linux / packageName).value}.log", rpmMetadata := RpmMetadata( - (packageName in Rpm).value, - (version in Rpm).value.stripSuffix("-SNAPSHOT"), + (Rpm / packageName).value, + (Rpm / version).value.stripSuffix("-SNAPSHOT"), rpmRelease.value, rpmPrefix.value, - (packageArchitecture in Rpm).value, + (Rpm / packageArchitecture).value, rpmVendor.value, rpmOs.value, - (packageSummary in Rpm).value, - (packageDescription in Rpm).value, + (Rpm / packageSummary).value, + (Rpm / packageDescription).value, rpmAutoprov.value, rpmAutoreq.value, rpmEpoch.value @@ -143,39 +163,20 @@ object RpmPlugin extends AutoPlugin { rpmObsoletes.value, rpmConflicts.value ), - maintainerScripts in Rpm := { - val scripts = (maintainerScripts in Rpm).value - if (!rpmBrpJavaRepackJars.value) { - val pre = scripts.getOrElse(Names.Pre, Nil) - val scriptBits = IO.readStream(RpmPlugin.osPostInstallMacro.openStream, Charset forName "UTF-8") - scripts + (Names.Pre -> (pre :+ scriptBits)) - } else - scripts - }, rpmScripts := RpmScripts - .fromMaintainerScripts((maintainerScripts in Rpm).value, (linuxScriptReplacements in Rpm).value), + .fromMaintainerScripts((Rpm / maintainerScripts).value, (Rpm / linuxScriptReplacements).value), rpmSpecConfig := RpmSpec( rpmMetadata.value, rpmDescription.value, rpmDependencies.value, rpmSetarch.value, rpmScripts.value, - (linuxPackageMappings in Rpm).value, - (linuxPackageSymlinks in Rpm).value, - (defaultLinuxInstallLocation in Rpm).value + (Rpm / linuxPackageMappings).value, + (Rpm / linuxPackageSymlinks).value, + (Rpm / defaultLinuxInstallLocation).value ), - stage in Rpm := RpmHelper.stage(rpmSpecConfig.value, (target in Rpm).value, streams.value.log), - artifactPath in (Rpm, packageBin) := RpmHelper.defaultRpmArtifactPath((target in Rpm).value, rpmMetadata.value), - packageBin in Rpm := { - val defaultPath = RpmHelper.buildRpm(rpmSpecConfig.value, (stage in Rpm).value, streams.value.log) - // `file` points to where buildRpm created the rpm. However we want it to be at `artifactPath`. - // If `artifactPath` is not the default value then we need to copy the file. - val path = (artifactPath in (Rpm, packageBin)).value - if (path.getCanonicalFile != defaultPath.getCanonicalFile) IO.copyFile(defaultPath, path) - path - }, rpmLint := { - sys.process.Process(Seq("rpmlint", "-v", (packageBin in Rpm).value.getAbsolutePath)) ! streams.value.log match { + sys.process.Process(Seq("rpmlint", "-v", (Rpm / packageBin).value.getAbsolutePath)) ! streams.value.log match { case 0 => () case x => sys.error("Failed to run rpmlint, exit status: " + x) } @@ -185,10 +186,10 @@ object RpmPlugin extends AutoPlugin { object RpmDeployPlugin extends AutoPlugin { - import RpmPlugin.autoImport._ + import RpmPlugin.autoImport.* - override def requires = RpmPlugin + override def requires : Plugins = RpmPlugin - override def projectSettings: Seq[Setting[_]] = - SettingsHelper.makeDeploymentSettings(Rpm, packageBin in Rpm, "rpm") + override def projectSettings: Seq[Setting[?]] = + SettingsHelper.makeDeploymentSettings(Rpm, Rpm / packageBin, "rpm") } diff --git a/src/main/scala/com/typesafe/sbt/packager/universal/Keys.scala b/src/main/scala/com/typesafe/sbt/packager/universal/Keys.scala index 8c2e91f79..cd39a84e5 100644 --- a/src/main/scala/com/typesafe/sbt/packager/universal/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/universal/Keys.scala @@ -2,13 +2,14 @@ package com.typesafe.sbt package packager package universal -import sbt._ +import sbt.* +import Compat.CompatFile trait UniversalKeys { val packageZipTarball = - TaskKey[File]("package-zip-tarball", "Creates a tgz package.") + TaskKey[CompatFile]("package-zip-tarball", "Creates a tgz package.") val packageXzTarball = - TaskKey[File]("package-xz-tarball", "Creates a txz package.") + TaskKey[CompatFile]("package-xz-tarball", "Creates a txz package.") val packageOsxDmg = TaskKey[File]("package-osx-dmg", "Creates a dmg package for macOS (only on macOS).") val stage = TaskKey[File]( "stage", 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 04de1dd08..e8b621004 100644 --- a/src/main/scala/com/typesafe/sbt/packager/windows/WindowsPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/windows/WindowsPlugin.scala @@ -1,11 +1,10 @@ package com.typesafe.sbt.packager.windows -import sbt._ +import sbt.* import sbt.Keys.{mappings, name, packageBin, sourceDirectory, streams, target, version} import com.typesafe.sbt.SbtNativePackager.Universal import com.typesafe.sbt.packager.Keys.{maintainer, packageDescription, packageName, packageSummary} import com.typesafe.sbt.packager.universal.UniversalPlugin -import com.typesafe.sbt.packager.Compat._ import com.typesafe.sbt.packager.SettingsHelper import com.typesafe.sbt.packager.sourceDateEpoch @@ -36,121 +35,121 @@ object WindowsPlugin extends AutoPlugin { val Windows: Configuration = config("windows") } - import autoImport._ + import autoImport.* - override lazy val projectSettings: Seq[Setting[_]] = windowsSettings ++ mapGenericFilesToWindows - override def requires = UniversalPlugin + override lazy val projectSettings: Seq[Setting[?]] = windowsSettings ++ mapGenericFilesToWindows + override def requires: Plugins = UniversalPlugin override def projectConfigurations: Seq[Configuration] = Seq(Windows) /** * default windows settings */ - def windowsSettings: Seq[Setting[_]] = - Seq( - sourceDirectory in Windows := sourceDirectory.value / "windows", - target in Windows := target.value / "windows", - // TODO - Should this use normalized name like the linux guys? - name in Windows := name.value, - packageName in Windows := packageName.value, - // Defaults so that our simplified building works - candleOptions := Seq("-ext", "WixUtilExtension"), - lightOptions := Seq("-ext", "WixUIExtension", "-ext", "WixUtilExtension", "-cultures:en-us"), - wixProductId := WixHelper.makeGUID((packageName in Windows).value + "_wixProductId"), - wixProductUpgradeId := WixHelper.makeGUID((packageName in Windows).value + "_wixProductUpgradeId"), - wixMajorVersion := 3, - maintainer in Windows := maintainer.value, - packageSummary in Windows := packageSummary.value, - packageDescription in Windows := packageDescription.value, - wixProductLicense := { - // TODO - document this default. - val default = (sourceDirectory in Windows).value / "License.rtf" - if (default.exists) Some(default) - else None - }, - wixPackageInfo := WindowsProductInfo( - id = wixProductId.value, - title = (packageSummary in Windows).value, - version = (version in Windows).value, - maintainer = (maintainer in Windows).value, - description = (packageDescription in Windows).value, - upgradeId = wixProductUpgradeId.value, - comments = "TODO - we need comments." // TODO - allow comments - ), - wixFeatures := Seq.empty, - wixProductConfig := WixHelper.makeWixProductConfig( - (name in Windows).value, - wixPackageInfo.value, - wixFeatures.value, - wixProductLicense.value - ), - wixConfig := WixHelper.makeWixConfig( - (name in Windows).value, - wixPackageInfo.value, - WixHelper.getNameSpaceDefinitions(wixMajorVersion.value), - wixProductConfig.value - ), - wixConfig in Windows := wixConfig.value, - wixProductConfig in Windows := wixProductConfig.value, - wixFile := { - val config = (wixConfig in Windows).value - val wixConfigFile = (target in Windows).value / ((name in Windows).value + ".wxs") - IO.write(wixConfigFile, config.toString) - wixConfigFile - }, - wixFiles := Seq(wixFile.value) - ) ++ inConfig(Windows)(Seq(packageBin := { - val wsxSources = wixFiles.value - val msi = target.value / (name.value + ".msi") - - // First we have to move everything (including the WIX scripts) - // to our target directory. - val targetFlat: Path.FileMap = Path.flat(target.value) - val wsxFiles = wsxSources.map(targetFlat(_).get) - val wsxCopyPairs = wsxSources.zip(wsxFiles).filter { case (src, dest) => - src.getAbsolutePath != dest.getAbsolutePath - } - IO.copy(wsxCopyPairs) - IO.copy(for ((f, to) <- mappings.value) yield (f, target.value / to)) - - // Now compile WIX - val candleCmd = findWixExecutable("candle") +: - wsxFiles.map(_.getAbsolutePath) ++: - candleOptions.value - val wixobjFiles = wsxFiles.map { wsx => - wsx.getParentFile / (wsx.base + ".wixobj") - } - - sourceDateEpoch(target.value) - - streams.value.log.debug(candleCmd mkString " ") - sys.process.Process(candleCmd, Some(target.value)) ! streams.value.log match { - case 0 => () - case exitCode => sys.error(s"Unable to run WIX compilation to wixobj. Exited with ${exitCode}") - } - - sourceDateEpoch(target.value) - - // Now create MSI - val lightCmd = List(findWixExecutable("light"), "-out", msi.getAbsolutePath) ++ wixobjFiles - .map(_.getAbsolutePath) ++ - lightOptions.value - - streams.value.log.debug(lightCmd mkString " ") - sys.process.Process(lightCmd, Some(target.value)) ! streams.value.log match { - case 0 => () - case exitCode => sys.error(s"Unable to run build msi. Exited with ${exitCode}") - } - msi - })) + def windowsSettings: Seq[Setting[?]] = Def.settings( + inConfig(Windows)( + Def.settings( + sourceDirectory := sourceDirectory.value / "windows", + target := target.value / "windows", + // TODO - Should this use normalized name like the linux guys? + name := name.value, + packageName := packageName.value, + maintainer := maintainer.value, + packageSummary := packageSummary.value, + packageDescription := packageDescription.value, + wixConfig := wixConfig.value, + wixProductConfig := wixProductConfig.value, + packageBin := { + val wsxSources = wixFiles.value + val msi = target.value / (name.value + ".msi") + + // First we have to move everything (including the WIX scripts) + // to our target directory. + val targetFlat: Path.FileMap = Path.flat(target.value) + val wsxFiles = wsxSources.map(targetFlat(_).get) + val wsxCopyPairs = wsxSources.zip(wsxFiles).filter { case (src, dest) => + src.getAbsolutePath != dest.getAbsolutePath + } + IO.copy(wsxCopyPairs) + IO.copy(for ((f, to) <- mappings.value) yield (f, target.value / to)) + + // Now compile WIX + val candleCmd = findWixExecutable("candle") +: + wsxFiles.map(_.getAbsolutePath) ++: + candleOptions.value + val wixobjFiles = wsxFiles.map { wsx => + wsx.getParentFile / (wsx.base + ".wixobj") + } + + sourceDateEpoch(target.value) + + streams.value.log.debug(candleCmd mkString " ") + sys.process.Process(candleCmd, Some(target.value)) ! streams.value.log match { + case 0 => () + case exitCode => sys.error(s"Unable to run WIX compilation to wixobj. Exited with $exitCode") + } + + sourceDateEpoch(target.value) + + // Now create MSI + val lightCmd = List(findWixExecutable("light"), "-out", msi.getAbsolutePath) ++ wixobjFiles + .map(_.getAbsolutePath) ++ + lightOptions.value + + streams.value.log.debug(lightCmd mkString " ") + sys.process.Process(lightCmd, Some(target.value)) ! streams.value.log match { + case 0 => () + case exitCode => sys.error(s"Unable to run build msi. Exited with $exitCode") + } + msi + } + ) + ), + // Defaults so that our simplified building works + candleOptions := Seq("-ext", "WixUtilExtension"), + lightOptions := Seq("-ext", "WixUIExtension", "-ext", "WixUtilExtension", "-cultures:en-us"), + wixProductId := WixHelper.makeGUID((Windows / packageName).value + "_wixProductId"), + wixProductUpgradeId := WixHelper.makeGUID((Windows / packageName).value + "_wixProductUpgradeId"), + wixMajorVersion := 3, + wixProductLicense := { + // TODO - document this default. + val default = (Windows / sourceDirectory).value / "License.rtf" + if (default.exists) Some(default) + else None + }, + wixPackageInfo := WindowsProductInfo( + id = wixProductId.value, + title = (Windows / packageSummary).value, + version = (Windows / version).value, + maintainer = (Windows / maintainer).value, + description = (Windows / packageDescription).value, + upgradeId = wixProductUpgradeId.value, + comments = "TODO - we need comments." // TODO - allow comments + ), + wixFeatures := Seq.empty, + wixProductConfig := WixHelper + .makeWixProductConfig((Windows / name).value, wixPackageInfo.value, wixFeatures.value, wixProductLicense.value), + wixConfig := WixHelper.makeWixConfig( + (Windows / name).value, + wixPackageInfo.value, + WixHelper.getNameSpaceDefinitions(wixMajorVersion.value), + wixProductConfig.value + ), + wixFile := { + val config = (Windows / wixConfig).value + val wixConfigFile = (Windows / target).value / ((Windows / name).value + ".wxs") + IO.write(wixConfigFile, config.toString) + wixConfigFile + }, + wixFiles := Seq(wixFile.value) + ) /** * set the `mappings in Windows` and the `wixFeatures` */ - def mapGenericFilesToWindows: Seq[Setting[_]] = + def mapGenericFilesToWindows: Seq[Setting[?]] = Seq( - mappings in Windows := (mappings in Universal).value, - wixFeatures := makeWindowsFeatures((packageName in Windows).value, (mappings in Windows).value) + Windows / mappings := (Universal / mappings).value, + wixFeatures := makeWindowsFeatures((Windows / packageName).value, (Windows / mappings).value) ) /** @@ -217,10 +216,10 @@ object WindowsPlugin extends AutoPlugin { object WindowsDeployPlugin extends AutoPlugin { - import WindowsPlugin.autoImport._ + import WindowsPlugin.autoImport.* - override def requires = WindowsPlugin + override def requires: Plugins = WindowsPlugin - override def projectSettings: Seq[Setting[_]] = - SettingsHelper.makeDeploymentSettings(Windows, packageBin in Windows, "msi") + override def projectSettings: Seq[Setting[?]] = + SettingsHelper.makeDeploymentSettings(Windows, Windows / packageBin, "msi") } 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 6af48ad9f..36f737b62 100644 --- a/src/main/scala/com/typesafe/sbt/packager/windows/WixHelper.scala +++ b/src/main/scala/com/typesafe/sbt/packager/windows/WixHelper.scala @@ -2,8 +2,7 @@ package com.typesafe.sbt package packager package windows -import Keys._ -import sbt._ +import sbt.* import collection.mutable.ArrayBuffer import scala.collection.mutable @@ -84,7 +83,7 @@ object WixHelper { val filenamesPrep = for { f <- features - ComponentFile(name, _) <- f.components + case ComponentFile(name, _) <- f.components } yield allParentDirs(file(name)) val filenames = filenamesPrep.flatten.map(_.toString.replaceAll("\\\\", "/")).filter(_ != "") // Now for directories... @@ -96,11 +95,12 @@ object WixHelper { else filename lastIndexOf '\\' filename drop (lastSlash + 1) } - val dirs = (filenames map parentDir).distinct; + val dirs = (filenames map parentDir).distinct // Now we need our directory tree xml? - val dirToChildren = dirs groupBy parentDir; + val dirToChildren = dirs groupBy parentDir + def dirXml(currentDir: String): scala.xml.Node = - if (!currentDir.isEmpty) { + if (currentDir.nonEmpty) { val children = dirToChildren.getOrElse(currentDir, Seq.empty) { @@ -113,7 +113,7 @@ object WixHelper { case class ComponentInfo(id: String, xml: scala.xml.Node) def makeComponentInfo(c: FeatureComponent): ComponentInfo = c match { - case w: WindowsFeature => + case _: WindowsFeature => sys.error("Nested windows features currently unsupported!") case AddDirectoryToPath(dir) => val dirRef = if (dir.isEmpty) "INSTALLDIR" else cleanStringForId(dir) @@ -158,8 +158,8 @@ object WixHelper { // 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 + case AddShortCuts(targets, _) => + val targetSize = targets.size.toString.length val id = cleanStringWithPostfix( "shortcut_" + makeGUID(targets.mkString), @@ -174,7 +174,7 @@ object WixHelper { val name = simpleName(target) val desc = "Edit configuration file: " + name val cleanName = name.replaceAll("[\\.-\\\\//]+", "_") - } @@ -186,12 +186,12 @@ object WixHelper { } val componentMap = mutable.LinkedHashMap[String, Seq[ComponentInfo]]() - (for (f <- features) { + for (f <- features) { // TODO - we need to support more than "Component File". val componentInfos = f.components map makeComponentInfo componentMap(f.id) = componentInfos - }) + } val removeId = cleanStringWithPostfix("ApplicationProgramsFolderRemove", 67, "") @@ -215,8 +215,8 @@ object WixHelper { { for { - (fid, components) <- componentMap - ComponentInfo(cid, xml) <- components + (_, components) <- componentMap + ComponentInfo(_, xml) <- components } yield xml } @@ -291,7 +291,7 @@ object WixHelper { * characters and replacing with _. Also limits the width to 70 (rather than * 72) so we can safely add a few later. */ - def cleanStringForId(n: String) = { + def cleanStringForId(n: String): String = { val x = n.replaceAll("[^0-9a-zA-Z_]", "_").takeRight(59) + (math.abs(n.hashCode).toString + "xxxxxxxxx") .substring(0, 9) if (x startsWith "_") x @@ -305,7 +305,7 @@ object WixHelper { } /** Cleans a file name for the Wix pre-processor. Every $ should be doubled. */ - def cleanFileName(n: String) = + def cleanFileName(n: String): String = n.replaceAll("\\$", "\\$\\$").replaceAll("\\/", "\\\\") /** Takes a file and generates an ID for it. */ @@ -322,22 +322,19 @@ object WixHelper { // reference: https://github.com/sbt/sbt-native-packager/issues/726 def generateComponentsAndDirectoryXml(dir: File, id_prefix: String = ""): (Seq[String], scala.xml.Node) = { def makeId(f: File) = - cleanStringForId(IO.relativize(dir, f) map (id_prefix +) getOrElse (id_prefix + f.getName)) + cleanStringForId(IO.relativize(dir, f) map id_prefix.+ getOrElse (id_prefix + f.getName)) def handleFile(f: File): (Seq[String], scala.xml.Node) = { val id = makeId(f) - val xml = ( - + val xml = - ) (Seq(id), xml) } def handleDirectory(dir: File): (Seq[String], scala.xml.Node) = { val buf: ArrayBuffer[String] = ArrayBuffer.empty - val xml = ( - + val xml = { for { file <- IO.listFiles(dir) @@ -348,8 +345,7 @@ object WixHelper { } } - ) - (buf.toSeq, xml) + (buf, xml) } def recursiveHelper(f: File): (Seq[String], scala.xml.Node) = if (f.isDirectory) handleDirectory(f) diff --git a/src/sbt-test/jdkpackager/test-package-image/src/main/scala/ExampleApp.scala b/src/sbt-test/jdkpackager/test-package-image/src/main/scala/ExampleApp.scala index 35be79af9..05a4ff1e5 100644 --- a/src/sbt-test/jdkpackager/test-package-image/src/main/scala/ExampleApp.scala +++ b/src/sbt-test/jdkpackager/test-package-image/src/main/scala/ExampleApp.scala @@ -26,7 +26,7 @@ class ExampleApp extends Application { win.initOwner(stage) val args = getParameters.getRaw.mkString("\n") - val props = sys.props.toSeq.sortBy(_._1).map(p ⇒ s"${p._1}=${p._2}").mkString("\n") + val props = sys.props.toSeq.sortBy(_._1).map(p => s"${p._1}=${p._2}").mkString("\n") val content = new TextArea(Seq("## Application Arguments", args, "## System Properties", props).mkString("\n")) content.setPrefHeight(400) diff --git a/src/sbt-test/jdkpackager/test-package-mappings/src/main/scala/ExampleApp.scala b/src/sbt-test/jdkpackager/test-package-mappings/src/main/scala/ExampleApp.scala index abd7c0eb4..17df4c6bc 100644 --- a/src/sbt-test/jdkpackager/test-package-mappings/src/main/scala/ExampleApp.scala +++ b/src/sbt-test/jdkpackager/test-package-mappings/src/main/scala/ExampleApp.scala @@ -23,7 +23,7 @@ class ExampleApp extends Application { val win = new Stage(StageStyle.UTILITY) win.initModality(Modality.APPLICATION_MODAL) win.initOwner(stage) - val content = new TextArea(sys.props.toSeq.sortBy(_._1).map(p ⇒ s"${p._1}=${p._2}").mkString("\n")) + val content = new TextArea(sys.props.toSeq.sortBy(_._1).map(p => s"${p._1}=${p._2}").mkString("\n")) content.setPrefHeight(400) win.setScene(new Scene(content)) win.sizeToScene() diff --git a/src/sbt-test/jdkpackager/test-package-minimal/src/main/scala/ExampleApp.scala b/src/sbt-test/jdkpackager/test-package-minimal/src/main/scala/ExampleApp.scala index abd7c0eb4..17df4c6bc 100644 --- a/src/sbt-test/jdkpackager/test-package-minimal/src/main/scala/ExampleApp.scala +++ b/src/sbt-test/jdkpackager/test-package-minimal/src/main/scala/ExampleApp.scala @@ -23,7 +23,7 @@ class ExampleApp extends Application { val win = new Stage(StageStyle.UTILITY) win.initModality(Modality.APPLICATION_MODAL) win.initOwner(stage) - val content = new TextArea(sys.props.toSeq.sortBy(_._1).map(p ⇒ s"${p._1}=${p._2}").mkString("\n")) + val content = new TextArea(sys.props.toSeq.sortBy(_._1).map(p => s"${p._1}=${p._2}").mkString("\n")) content.setPrefHeight(400) win.setScene(new Scene(content)) win.sizeToScene() diff --git a/test-project-jdkpackager/src/main/scala/ExampleApp.scala b/test-project-jdkpackager/src/main/scala/ExampleApp.scala index abd7c0eb4..17df4c6bc 100644 --- a/test-project-jdkpackager/src/main/scala/ExampleApp.scala +++ b/test-project-jdkpackager/src/main/scala/ExampleApp.scala @@ -23,7 +23,7 @@ class ExampleApp extends Application { val win = new Stage(StageStyle.UTILITY) win.initModality(Modality.APPLICATION_MODAL) win.initOwner(stage) - val content = new TextArea(sys.props.toSeq.sortBy(_._1).map(p ⇒ s"${p._1}=${p._2}").mkString("\n")) + val content = new TextArea(sys.props.toSeq.sortBy(_._1).map(p => s"${p._1}=${p._2}").mkString("\n")) content.setPrefHeight(400) win.setScene(new Scene(content)) win.sizeToScene()