增强的基于Groovy的JAR /清单差异工具

这篇简短的博客文章提供了另一个Groovy脚本,该脚本提供了两个JAR(或WAR或EAR)文件及其MANIFEST.MF文件的简单区别。 它代表了我之前 写过JAR比较脚本Rick 添加GroovyCliBuilder以允许关闭某些输出数据,我的MANIFEST.MF比较脚本以及使用命令行标志的能力的组合。使脚本能够输出其他清单比较数据。

jarDiff2.groovy

#!/usr/bin/env groovy

/**
 * jarDiff2.groovy
 *
 * jarDiff2.groovy -htsc <first_jar_file> <second_jar_file>
 *
 * Script that compares two JAR files, reporting basic characteristics of each
 * along with differences between the two JARs. This script is based on the
 * original jarrDiff.groovy script with enhancements provided by Rick and with
 * enhancements for seeing more detailed differences between two Manifest files.
 *
 * Note this script can be used on any files using the Java ARchive format,
 * including WAR and EAR files.
 */

if (args.length < 2)
{
   println "\nUSAGE: jarDiff2.groovy -htsc <first_jar_file> <second_jar_file>\n"
   System.exit(-1)
}

TOTAL_WIDTH = 180
COLUMN_WIDTH = TOTAL_WIDTH / 2 - 3
ROW_SEPARATOR = "-".multiply(TOTAL_WIDTH)

import java.util.jar.Attributes
import java.util.jar.JarFile

// Set up the CLI options
//
def cli = new CliBuilder( usage: 'jarDiff.groovy -h -tsc ')
cli.with
{
   h longOpt: 'help', 'usage information'
   t longOpt: 'ignoreTime', args: 0, required: false, type: Boolean, 'Ignore time differences'
   s longOpt: 'ignoreSize', args: 0, required: false, type: Boolean, 'Ignore size differences'
   c longOpt: 'ignoreCrc', args: 0, required: false, type: Boolean, 'Ignore CRC differences'
   m longOpt: 'displayManifestDetails', args: 0, required: false, type: Boolean, 'Display Manifest differences details'
}

def opt = cli.parse(args)
if (!opt) return
if (opt.h)
{
   cli.usage()
   System.exit(-1)
}

def ignoreTime = opt.t
def ignoreSize = opt.s
def ignoreCrc = opt.c
def displayManifestDiffDetails = opt.m

if (opt.arguments().size < 2)
{
   println "Two JAR files required\n"
   cli.usage()
   System.exit(-1)
}

def file1Name = opt.arguments()[0]
def jar1File = new JarFile(file1Name)
def jar1 = extractJarContents(jar1File)
def file2Name = opt.arguments()[1]
def jar2File = new JarFile(file2Name)
def jar2 = extractJarContents(jar2File)

def entriesInJar1ButNotInJar2 = jar1.keySet() - jar2.keySet()
def entriesInJar2ButNotInJar1 = jar2.keySet() - jar1.keySet()

println ROW_SEPARATOR
println "| ${file1Name.center(COLUMN_WIDTH)} |${file2Name.center(COLUMN_WIDTH)} |"
print "| ${(Integer.toString(jar1File.size()) + " bytes").center(COLUMN_WIDTH)} |"
println "${(Integer.toString(jar2File.size()) + " bytes").center(COLUMN_WIDTH)} |"
println ROW_SEPARATOR

if (jar1File.manifest != jar2File.manifest)
{
   if (displayManifestDiffDetails)
   {
      displayDetailedManifestFilesDifferences(jar1File.manifest.mainAttributes, jar2File.manifest.mainAttributes)
   }
   else
   {
      def manifestPreStr = "# Manifest Entries: "
      def manifest1Str = manifestPreStr + Integer.toString(jar1File.manifest.mainAttributes.size())
      print "| ${manifest1Str.center(COLUMN_WIDTH)} |"
      def manifest2Str = manifestPreStr + Integer.toString(jar2File.manifest.mainAttributes.size())
      println "${manifest2Str.center(COLUMN_WIDTH)} |"
      println ROW_SEPARATOR
   }
}

entriesInJar1ButNotInJar2.each
{ entry1 ->
   print "| ${entry1.center(COLUMN_WIDTH)} |"
   println "${" ".center(entry1.size() > COLUMN_WIDTH ? 2 * COLUMN_WIDTH - entry1.size() : COLUMN_WIDTH)} |"
   println ROW_SEPARATOR
}
entriesInJar2ButNotInJar1.each
{ entry2 ->
   print "| ${" ".center(entry2.size() > COLUMN_WIDTH ? 2 * COLUMN_WIDTH - entry2.size() : COLUMN_WIDTH)}"
   println "| ${entry2.center(COLUMN_WIDTH)} |"
   println ROW_SEPARATOR
}

jar1.each 
{ key, value ->
   if (!entriesInJar1ButNotInJar2.contains(key))
   {
      def jar2Entry = jar2.get(key)
      if (value != jar2Entry)
      {
         println "| ${key.center(COLUMN_WIDTH)} |${jar2Entry.name.center(COLUMN_WIDTH)} |"
         if (value.crc != jar2Entry.crc)
         {
            def crc1Str = "CRC: ${value.crc}"
            def crc2Str = "CRC: ${jar2Entry.crc}"
            print "| ${crc1Str.center(COLUMN_WIDTH)} |"
            println "${crc2Str.center(COLUMN_WIDTH)} |"
         }
         if (value.size != jar2Entry.size)
         {
            def size1Str = "${value.size} bytes"
            def size2Str = "${jar2Entry.size} bytes"
            print "| ${size1Str.center(COLUMN_WIDTH)} |"
            println "${size2Str.center(COLUMN_WIDTH)} |"
         }
         if (value.time != jar2Entry.time)
         {
            boolean crcDiff = (!ignoreCrc && value.crc != jar2Entry.crc)
            boolean sizeDiff = (!ignoreSize && value.size != jar2Entry.size)
            boolean timeDiff = (!ignoreTime && value.time != jar2Entry.time)

            if(crcDiff || sizeDiff || timeDiff)
            {
               println "| ${key.center(COLUMN_WIDTH)} |${jar2Entry.name.center(COLUMN_WIDTH)} |"
               if (crcDiff)
               {
                  def crc1Str = "CRC: ${value.crc}"
                  def crc2Str = "CRC: ${jar2Entry.crc}"
                  print "| ${crc1Str.center(COLUMN_WIDTH)} |"
                  println "${crc2Str.center(COLUMN_WIDTH)} |"
               }
               if (sizeDiff)
               {
                  def size1Str = "${value.size} bytes"
                  def size2Str = "${jar2Entry.size} bytes"
                  print "| ${size1Str.center(COLUMN_WIDTH)} |"
                  println "${size2Str.center(COLUMN_WIDTH)} |"
               }
               if (timeDiff)
               {
                  def time1Str = "${new Date(value.time)}"
                  def time2Str = "${new Date(jar2Entry.time)}"
                  print "| ${time1Str.center(COLUMN_WIDTH)} |"
                  println "${time2Str.center(COLUMN_WIDTH)} |"
               }
               println ROW_SEPARATOR
            }
         }
      }
   }
}

/**
 * Provide mapping of JAR entry names to characteristics about that JAR entry
 * for the JAR indicated by the provided JAR file name.
 *
 * @param jarFile JAR file from which to extract contents.
 * @return JAR entries and thir characteristics.
 */
def TreeMap<String, JarCharacteristics> extractJarContents(JarFile jarFile)
{
   def jarContents = new TreeMap<String, JarCharacteristics>()
   entries = jarFile.entries()
   entries.each
   { entry->
      jarContents.put(entry.name, new JarCharacteristics(entry.name, entry.crc, entry.size, entry.time));
   }
   return jarContents
}

/**
 * Add more detailed Manifest differences to output report.
 *
 * @param manifest1Attrs Main attributes of first JAR file's Manifest
 * @param manifest2Attrs Main attributes of second JAR file's Manifest.
 */
def displayDetailedManifestFilesDifferences(
   Attributes manifest1Attrs, Attributes manifest2Attrs)
{
   def attrsIn1ButNot2 = manifest1Attrs.keySet() - manifest2Attrs.keySet()
   def attrsIn2ButNot1 = manifest2Attrs.keySet() - manifest1Attrs.keySet()
   attrsIn1ButNot2.each
   {
      def attr1onlyStr = "${it}=${manifest1Attrs.get(it)}" 
      print "| ${attr1onlyStr.center(COLUMN_WIDTH)} |"
      println "${" ".center(attr1onlyStr.size() > COLUMN_WIDTH ? 2 * COLUMN_WIDTH - attr1onlyStr.size() : COLUMN_WIDTH)} |"
   }
   println ROW_SEPARATOR
   attrsIn2ButNot1.each
   {
      def attr2onlyStr = "${it}=${manifest2Attrs.get(it)}"
      print "| ${" ".center(attr2onlyStr.size() > COLUMN_WIDTH ? 2 * COLUMN_WIDTH - attr2onlyStr.size() : COLUMN_WIDTH)}|"
      println " ${attr2onlyStr.center(COLUMN_WIDTH)} |"
   }
   println ROW_SEPARATOR
   manifest1Attrs.each
   {
      def key = it.key
      if (it.value != manifest2Attrs.get(key) && !attrsIn1ButNot2.contains(it.key))
      {
         def attr1Str = "${key}=${manifest1Attrs.get(key)}"
         print "| ${attr1Str.center(COLUMN_WIDTH)}"
         def attr2Str = "${key}=${manifest2Attrs.get(key)}"
         println "| ${attr2Str.center(COLUMN_WIDTH)} |"
      }
   }
   println ROW_SEPARATOR
}

与该脚本的第一个版本一样,该脚本依赖于非常简单的JarCharacteristics.groovy类。 在Groovy 1.8或更高版本中,此类很简单(Groovy的早期版本需要实现一些其他代码,因为它们没有@Canonical ):

JarCharacteristics.groovy

@groovy.transform.Canonical
class JarCharacteristics
{
   String name
   long crc
   long size
   long time
}

这篇文章中显示的JAR差异脚本版本使用命令行参数来指定何时不显示由于CRC,大小或修改日期而引起的JAR条目差异。 指定该标志时,还会显示一个附加标志,以显示更详细的清单文件差异。 默认值是显示基于CRC,大小和修改日期的常规JAR条目差异,但不显示清单文件中的详细差异。 这些标志可用于禁用CRC,大小或修改日期的差异,或启用更详细的清单文件差异输出。


翻译自: https://www.javacodegeeks.com/2013/07/enhanced-groovy-based-jarmanifest-diff-tool.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值