【问题标题】:How do I exclude/include specific packages using xsbt-proguard-plugin?如何使用 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)

非常感谢任何帮助!

【问题讨论】:

    标签: scala sbt proguard


    【解决方案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 等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-17
      • 2012-06-11
      • 2014-04-14
      • 2011-01-27
      • 2013-09-03
      • 2012-08-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多