如何使用 xsbt-proguard-plugin 排除/包含特定包?

Posted

技术标签:

【中文标题】如何使用 xsbt-proguard-plugin 排除/包含特定包?【英文标题】:How do I exclude/include specific packages using xsbt-proguard-plugin? 【发布时间】:2012-06-01 20:37:03 【问题描述】:

我正在使用xsbt-proguard-plugin,这是一个用于与 Proguard 配合使用的 SBT 插件。

我正在尝试为我编写的Hive Deserializer 提供 Proguard 配置,它具有以下依赖项:

// project/Dependencies.scala
val hadoop      = "org.apache.hadoop"          %  "hadoop-core"          % V.hadoop
val hive        = "org.apache.hive"            %  "hive-common"          % V.hive
val serde       = "org.apache.hive"            %  "hive-serde"           % V.hive
val httpClient  = "org.apache.httpcomponents"  %  "httpclient"           % V.http 
val logging     = "commons-logging"            %  "commons-logging"      % V.logging
val specs2      = "org.specs2"                 %% "specs2"               % V.specs2      % "test"

加上一个非托管依赖:

// lib/UserAgentUtils-1.6.jar

因为其中大多数要么用于本地单元测试,要么在 Hadoop/Hive 环境中可用,所以我希望我的缩小 jarfile 只包括:

Java 类 SnowPlowEventDeserializer.class 和 SnowPlowEventStruct.class org.apache.httpcomponents.httpclient commons-logging lib/UserAgentUtils-1.6.jar

但我真的很难让语法正确。我应该从我想要保留的类的白名单开始,还是明确过滤掉 Hadoop/Hive/Serde/Specs2 库?我知道this SO question,但它似乎不适用于这里。

如果我最初尝试白名单方法:

// Should be equivalent to sbt> package
import ProguardPlugin._
lazy val proguard = proguardSettings ++ Seq(
  proguardLibraryJars := Nil,
  proguardOptions := Seq(
    "-keepattributes *Annotation*,EnclosingMethod",
    "-dontskipnonpubliclibraryclassmembers",
    "-dontoptimize",
    "-dontshrink",
    "-keep class com.snowplowanalytics.snowplow.hadoop.hive.SnowPlowEventDeserializer",
    "-keep class com.snowplowanalytics.snowplow.hadoop.hive.SnowPlowEventStruct"
  )
)

然后我得到一个 Hadoop 处理错误,很明显 Proguard 仍在尝试捆绑 Hadoop:

proguard: java.lang.IllegalArgumentException: Can't find common super class of [[Lorg/apache/hadoop/fs/FileStatus;] and [[Lorg/apache/hadoop/fs/s3/Block;]

同时,如果我尝试 Proguard's filtering syntax 建立我不想包含的库的黑名单:

import ProguardPlugin._
lazy val proguard = proguardSettings ++ Seq(
  proguardLibraryJars := Nil,
  proguardOptions := Seq(
    "-keepattributes *Annotation*,EnclosingMethod",
    "-dontskipnonpubliclibraryclassmembers",
    "-dontoptimize",
    "-dontshrink",
    "-injars  !*hadoop*.jar"
  )
)

那么这似乎也不起作用:

proguard: java.io.IOException: Can't read [/home/dev/snowplow-log-deserializers/!*hadoop*.jar] (No such file or directory)

非常感谢任何帮助!

【问题讨论】:

【参考方案1】:

白名单是正确的方法:ProGuard 应该获得完整的上下文,这样它就可以正确地剔除不需要的类、字段和方法。

错误“找不到公共超类”表明输入中仍然缺少某些库。 ProGuard 可能警告过它,但配置似乎包含选项 -ignorewarnings 或 -dontwarn (应该避免)。您应该使用 -injars 或 -libraryjars 添加库。

如果 ProGuard 然后在输出中包含一些您不期望的类,您可以使用“-whyareyoukeeping class somepackage.SomeUnexpectedClass”获得解释。

从工作配置开始,您仍然可以尝试从输入中过滤掉类或整个 jar。过滤器被添加到类路径中的项目中,而不是单独添加,例如“-injars some.jar(!somepackage/**.class)”——cfr。手册。如果输入包含拖入其他不需要的类的测试类,这将很有用。

【讨论】:

感谢 Eric,感谢您的帮助。最后,我无法超越重复的类错误,更不用说排除特定的罐子了。当我在 SBT 中有一个简单的依赖项列表时,排除特定的 jar 似乎也有点笨拙,我宁愿使用/注释以包含/排除。最后我采用了 sbt-assembly 方法,见下文。【参考方案2】:

最后,我无法使用 Proguard 解决重复的类错误,更不用说如何弄清楚如何过滤掉相关的 jar,所以最终切换到更干净的 sbt-assembly 方法:

-1。根据README,将 sbt-assembly 插件添加到我的项目中

-2。使用 "provided" 标志更新了适当的项目依赖项,以阻止它们被添加到我的胖 jar 中:

val hadoop      = "org.apache.hadoop"          %  "hadoop-core"          % V.hadoop      % "provided"
val hive        = "org.apache.hive"            %  "hive-common"          % V.hive        % "provided"
val serde       = "org.apache.hive"            %  "hive-serde"           % V.hive        % "provided"
val httpClient  = "org.apache.httpcomponents"  %  "httpclient"           % V.http
val httpCore    = "org.apache.httpcomponents"  %  "httpcore"             % V.http  
val logging     = "commons-logging"            %  "commons-logging"      % V.logging     % "provided"
val specs2      = "org.specs2"                 %% "specs2"               % V.specs2      % "test"

-3。添加了一个 sbt-assembly 配置,如下所示:

import sbtassembly.Plugin._
import AssemblyKeys._
lazy val sbtAssemblySettings = assemblySettings ++ Seq(
  assembleArtifact in packageScala := false,
  jarName in assembly <<= (name, version)  (name, version) => name + "-" + version + ".jar" ,
  mergeStrategy in assembly <<= (mergeStrategy in assembly) 
    (old) => 
      case "META-INF/NOTICE.txt" => MergeStrategy.discard
      case "META-INF/LICENSE.txt" => MergeStrategy.discard
      case x => old(x)
    
  
)

然后输入 assembly 生成一个“胖 jar”,其中只包含我需要的包,包括非托管依赖项,不包括 Hadoop/Hive 等。

【讨论】:

以上是关于如何使用 xsbt-proguard-plugin 排除/包含特定包?的主要内容,如果未能解决你的问题,请参考以下文章

在 SBT 中将 unmanagedJars 添加到 proguardLibraryJars

[精选] Mysql分表与分库如何拆分,如何设计,如何使用

如果加入条件,我该如何解决。如果使用字符串连接,我如何使用

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?