mirror of https://github.com/sbt/sbt.git
Reorganized/commented proguard build configuration.
Review by @jsuereth.
This commit is contained in:
parent
8f22d7d580
commit
06deda06af
|
|
@ -6,80 +6,118 @@ object LaunchProguard
|
|||
{
|
||||
lazy val Proguard = config("proguard") hide ;
|
||||
|
||||
lazy val configurationFile = SettingKey[File]("configuration-file")
|
||||
lazy val proguard = TaskKey[File]("proguard", "Produces the final compacted jar that contains only the classes needed using proguard.")
|
||||
lazy val proguardConfiguration = TaskKey[File]("proguard-configuration", "Creates the configuration file to use with proguard.")
|
||||
lazy val options = TaskKey[Seq[String]]("options")
|
||||
lazy val optimizePasses = SettingKey[Int]("optimize-passes")
|
||||
lazy val keepFullClasses = SettingKey[Seq[String]]("keep-full-classes")
|
||||
lazy val keepClasses = SettingKey[Seq[String]]("keep-classes")
|
||||
lazy val inputJars = TaskKey[Seq[File]]("input-jars")
|
||||
lazy val configurationFile = settingKey[File]("Location of the generated proguard configuration file.")
|
||||
lazy val proguard = taskKey[File]("Produces the final compacted jar that contains only the classes needed using proguard.")
|
||||
lazy val proguardConfiguration = taskKey[File]("Creates the configuration file to use with proguard.")
|
||||
lazy val options = taskKey[Seq[String]]("Proguard options.")
|
||||
lazy val optimizePasses = settingKey[Int]("Number of optimization passes proguard performs.")
|
||||
lazy val keepFullClasses = settingKey[Seq[String]]("Fully qualified names of classes that proguard should preserve the non-private API of.")
|
||||
|
||||
lazy val settings: Seq[Setting[_]] =
|
||||
inScope(GlobalScope)(inConfig(Proguard)(globalSettings)) ++
|
||||
inConfig(Proguard)( baseSettings ) :+
|
||||
(libraryDependencies += "net.sf.proguard" % "proguard-base" % "4.8" % Proguard.name)
|
||||
|
||||
/** Defaults */
|
||||
def globalSettings = Seq(
|
||||
optimizePasses := 2,
|
||||
optimizePasses := 2, // more don't seem to help much and it increases proguard runtime
|
||||
keepFullClasses := Nil,
|
||||
keepClasses := Nil,
|
||||
options := basicOptions
|
||||
)
|
||||
def baseSettings = Seq(
|
||||
options <++= optimizePasses map { passes => if(passes <= 0) Seq("-dontoptimize") else Seq( "-optimizationpasses " + passes.toString, "-optimizations !code/allocation/variable") },
|
||||
options <++= keepFullClasses map { _ map ("-keep public class " + _ + " {\n\tpublic protected * ;\n}") },
|
||||
options <++= keepClasses map { _ map ("-keep class " + _ + " {}") },
|
||||
configurationFile <<= target / "proguard.pro",
|
||||
proguardConfiguration <<= writeProguardConfiguration,
|
||||
proguard <<= proguardTask
|
||||
optimizeSetting,
|
||||
options ++= keepFullClasses.value map ("-keep public class " + _ + " {\n\tpublic protected * ;\n}"),
|
||||
configurationFile := target.value / "proguard.pro",
|
||||
proguardConfiguration := writeProguardConfiguration.value,
|
||||
proguard := proguardTask.value
|
||||
)
|
||||
|
||||
|
||||
/** Options to set the number of optimization passes or to disable optimization altogether. */
|
||||
def optimizeSetting = options ++= {
|
||||
val passes = optimizePasses.value
|
||||
if(passes <= 0)
|
||||
Seq("-dontoptimize")
|
||||
else
|
||||
Seq(
|
||||
"-optimizationpasses " + passes.toString,
|
||||
// optimization is problematic without this option, possibly proguard can't handle certain scalac-generated bytecode
|
||||
"-optimizations !code/allocation/variable"
|
||||
)
|
||||
}
|
||||
|
||||
def specific(launchSub: Reference): Seq[Setting[_]] = inConfig(Proguard)(Seq(
|
||||
keepFullClasses ++= "xsbti.**" :: Nil,
|
||||
keepClasses ++= "org.apache.ivy.plugins.resolver.URLResolver" :: "org.apache.ivy.plugins.resolver.IBiblioResolver" :: Nil,
|
||||
artifactPath <<= (target, version) { (out,v) => out / ("sbt-launch-" + v + ".jar") },
|
||||
options <++= (dependencyClasspath in (launchSub, Compile), compile in (launchSub,Compile), streams) map { (cp, analysis, s) => mapJars(cp.files, analysis.relations.allBinaryDeps.toSeq, s.log) },
|
||||
options <+= packageBin map { f => "-injars " + mkpath(f) },
|
||||
artifactPath := target.value / ("sbt-launch-" + version.value + ".jar"),
|
||||
options ++= dependencyOptions(launchSub).value,
|
||||
options += "-injars " + mkpath(packageBin.value),
|
||||
packageBin := (packageBin in (launchSub, Compile)).value,
|
||||
options <++= mainClass in (launchSub, Compile) map { _.toList map(s => keepMain.format(s)) },
|
||||
options <+= artifactPath map { p => "-outjars " + mkpath(p) },
|
||||
fullClasspath <<= (configuration, classpathTypes, update) map Classpaths.managedJars
|
||||
options ++= mainClass.in(launchSub, Compile).value.toList map keepMain,
|
||||
options += "-outjars " + mkpath(artifactPath.value),
|
||||
fullClasspath := Classpaths.managedJars(configuration.value, classpathTypes.value, update.value)
|
||||
))
|
||||
|
||||
def basicOptions =
|
||||
Seq(
|
||||
"-keep,allowoptimization,allowshrinking class * { *; }", // no obfuscation
|
||||
"-keepattributes SourceFile,LineNumberTable", // preserve debugging information
|
||||
"-dontnote",
|
||||
"-dontwarn", // too many warnings generated for scalac-generated bytecode last time this was enabled
|
||||
"-ignorewarnings")
|
||||
|
||||
/** Option to preserve the main entry point. */
|
||||
private def keepMain(className: String) =
|
||||
s"""-keep public class $className {
|
||||
| public static void main(java.lang.String[]);
|
||||
|}""".stripMargin
|
||||
|
||||
|
||||
private def excludeIvyResources =
|
||||
"META-INF/**" ::
|
||||
"fr/**" ::
|
||||
"**/antlib.xml" ::
|
||||
"**/*.png" ::
|
||||
"org/apache/ivy/core/settings/ivyconf*.xml" ::
|
||||
"org/apache/ivy/core/settings/ivysettings-*.xml" ::
|
||||
"org/apache/ivy/plugins/resolver/packager/*" ::
|
||||
"**/ivy_vfs.xml" ::
|
||||
"org/apache/ivy/plugins/report/ivy-report-*" ::
|
||||
Nil
|
||||
|
||||
// libraryFilter and the Scala library-specific filtering in mapInJars can be removed for 2.11, since it is properly modularized
|
||||
private def libraryFilter = "(!META-INF/**,!*.properties,!scala/util/parsing/*.class,**.class)"
|
||||
private def generalFilter = "(!META-INF/**,!*.properties)"
|
||||
|
||||
|
||||
def dependencyOptions(launchSub: Reference) = Def.task {
|
||||
val cp = (dependencyClasspath in (launchSub, Compile)).value
|
||||
val analysis = (compile in (launchSub,Compile)).value
|
||||
mapJars(cp.files, analysis.relations.allBinaryDeps.toSeq, streams.value.log)
|
||||
}
|
||||
|
||||
def mapJars(in: Seq[File], all: Seq[File], log: Logger): Seq[String] =
|
||||
mapInJars(in, log) ++ mapLibraryJars(all filterNot in.toSet)
|
||||
def writeProguardConfiguration = (options, configurationFile, streams) map { (opts, conf, s) =>
|
||||
val content = opts.mkString("\n")
|
||||
def writeProguardConfiguration = Def.task {
|
||||
val content = options.value.mkString("\n")
|
||||
val conf = configurationFile.value
|
||||
if(!conf.exists || IO.read(conf) != content) {
|
||||
s.log.info("Proguard configuration written to " + conf)
|
||||
streams.value.log.info("Proguard configuration written to " + conf)
|
||||
IO.write(conf, content)
|
||||
}
|
||||
conf
|
||||
}
|
||||
|
||||
def basicOptions =
|
||||
Seq(
|
||||
"-keep,allowoptimization,allowshrinking class * { *; }",
|
||||
"-keepattributes SourceFile,LineNumberTable",
|
||||
"-dontnote",
|
||||
"-dontwarn",
|
||||
"-ignorewarnings")
|
||||
|
||||
private val keepMain =
|
||||
"""-keep public class %s {
|
||||
| public static void main(java.lang.String[]);
|
||||
|}""".stripMargin
|
||||
|
||||
def mapLibraryJars(libraryJars: Seq[File]): Seq[String] = libraryJars.map(f => "-libraryjars " + mkpath(f))
|
||||
def mapOutJar(outJar: File) = "-outjars " + mkpath(outJar)
|
||||
|
||||
def mkpath(f: File) : String = mkpath(f.getAbsolutePath, '\"')
|
||||
def mkpath(path: String, delimiter : Char) : String = delimiter + path + delimiter
|
||||
|
||||
def proguardTask = (cacheDirectory, artifactPath, proguardConfiguration, fullClasspath, packageBin, streams) map { (cache, outputJar, configFile, cp, inJar, s) =>
|
||||
val f = FileFunction.cached(cache / "proguard", FilesInfo.hash) { _ =>
|
||||
runProguard(outputJar, configFile, cp.files, s.log)
|
||||
def proguardTask = Def.task {
|
||||
val inJar = packageBin.value
|
||||
val outputJar = artifactPath.value
|
||||
val configFile = proguardConfiguration.value
|
||||
val f = FileFunction.cached(cacheDirectory.value / "proguard", FilesInfo.hash) { _ =>
|
||||
runProguard(outputJar, configFile, fullClasspath.value.files, streams.value.log)
|
||||
Set(outputJar)
|
||||
}
|
||||
f(Set(inJar, configFile)) // make the assumption that if the classpath changed, the outputJar would change
|
||||
|
|
@ -109,20 +147,6 @@ object LaunchProguard
|
|||
}
|
||||
|
||||
private def excludeString(s: List[String]) = s.map("!" + _).mkString("(",",",")")
|
||||
private def excludeIvyResources =
|
||||
"META-INF/**" ::
|
||||
"fr/**" ::
|
||||
"**/antlib.xml" ::
|
||||
"**/*.png" ::
|
||||
"org/apache/ivy/core/settings/ivyconf*.xml" ::
|
||||
"org/apache/ivy/core/settings/ivysettings-*.xml" ::
|
||||
"org/apache/ivy/plugins/resolver/packager/*" ::
|
||||
"**/ivy_vfs.xml" ::
|
||||
"org/apache/ivy/plugins/report/ivy-report-*" ::
|
||||
Nil
|
||||
|
||||
private def libraryFilter = "(!META-INF/**,!*.properties,!scala/actors/**,!scala/util/parsing/*.class,**.class)"
|
||||
private def generalFilter = "(!META-INF/**,!*.properties)"
|
||||
|
||||
private def withJar[T](files: Seq[File], name: String) = mkpath(files.headOption getOrElse error(name + " not present") )
|
||||
private def isJarX(x: String)(file: File) =
|
||||
|
|
|
|||
Loading…
Reference in New Issue