Skip to content

Instantly share code, notes, and snippets.

@bpsm
Created October 20, 2011 05:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bpsm/1300472 to your computer and use it in GitHub Desktop.
Save bpsm/1300472 to your computer and use it in GitHub Desktop.
(ns jardifference
(:import (java.util.jar JarFile JarEntry JarOutputStream))
(:require (clojure.java [io :as io])
(clojure [set :as set])))
(defn jar-entry-seq
[^JarFile jf]
(enumeration-seq (.entries jf)))
(defn jar-entry-map
[^JarFile jf]
(apply merge {}
(for [^JarEntry je (jar-entry-seq jf) :when (not (.isDirectory je))]
{(.getName je) je})))
(defn same-content?
[^JarFile jf1 ^JarEntry je1 ^JarFile jf2 ^JarEntry je2]
(with-open [in1 (.getInputStream jf1 je1)
in2 (.getInputStream jf2 je2)]
(loop [c1 (.read in1), c2 (.read in2)]
(if (or (= -1 c1) (= -1 c2))
(= c1 c2)
(recur (.read in1) (.read in2))))))
(defn same?
[^JarFile jf1 ^JarEntry je1 ^JarFile jf2 ^JarEntry je2]
(and (= (.getSize je1) (.getSize je2))
(= (.getCrc je1) (.getCrc je2))
(= (.getCompressedSize je1) (.getCompressedSize je2))
(same-content? jf1 je1 jf2 je2)))
(def noop (constantly nil))
(defn compare-jars
[jf-old jf-new &
{:keys [identical changed deleted created]
:or {identical noop, changed noop, deleted noop, created noop}}]
(let [m-old (jar-entry-map jf-old), m-new (jar-entry-map jf-new)]
(doseq [name (-> (concat (keys m-old) (keys m-new)) set sort)
:let [je-old (m-old name), je-new (m-new name)]]
(cond (not je-old) (created jf-new je-new)
(not je-new) (deleted jf-old je-old)
(same? jf-old je-old jf-new je-new) (identical jf-old je-old)
:else (changed jf-new je-new)))))
(defn copy-entry
[^JarOutputStream out ^JarFile jf ^JarEntry je]
(with-open [in (.getInputStream jf je)]
(.putNextEntry out je)
(io/copy in out)
(.closeEntry out)))
(defn open-jar
^JarFile [^String path]
(JarFile. path))
(defn make-diff-jar
[jf-diff-name & jf-names]
{:pre [(even? (count jf-names))]}
(with-open [jout-diff (JarOutputStream. (io/output-stream jf-diff-name))]
(let [copy (partial copy-entry jout-diff)]
(doseq [[jf-old-name jf-new-name] (partition 2 jf-names)]
(with-open [jf-old (open-jar jf-old-name)
jf-new (open-jar jf-new-name)]
(compare-jars jf-old jf-new :changed copy :created copy))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment