This repository has been archived by the owner on Oct 1, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
/
licenses.clj
118 lines (98 loc) · 3.76 KB
/
licenses.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
(ns leiningen.licenses
(:require [leiningen.core.classpath :as classpath]
[leiningen.core.main :as main]
[cemerick.pomegranate.aether :as aether]
[clojure.java.io :as io]
[clojure.pprint :as pp]
[clojure.string :as string]
[clojure.xml :as xml]
[clojure.zip :as zip])
(:import (java.util.jar JarFile)))
;; This code is a mess; sorry! But it gets the job done.
(defn- tag [tag]
#(= (:tag %) tag))
(def ^:private tag-content (juxt :tag (comp first :content)))
(defn- fetch-pom [{:keys [groupId artifactId version]}]
(try
(let [dep (symbol groupId artifactId)
[file] (->> (aether/resolve-dependencies
:coordinates [[dep version :extension "pom"]])
(aether/dependency-files)
;; possible we could get the wrong one here?
(filter #(.endsWith (str %) ".pom")))]
(xml/parse file))
(catch Exception e
(binding [*out* *err*]
(println "# " (class e) (.getMessage e))))))
(defn- get-parent [pom]
(if-let [parent-tag (->> pom
:content
(filter (tag :parent))
first
:content)]
(if-let [parent-coords (->> parent-tag
(map tag-content)
(apply concat)
(apply hash-map))]
(fetch-pom parent-coords))))
(defn- pom-license [pom]
(->> pom :content (filter (tag :licenses))))
(defn- get-pom [dep file]
(let [group (or (namespace dep) (name dep))
artifact (name dep)
pom-path (format "META-INF/maven/%s/%s/pom.xml" group artifact)
jar (JarFile. file)
pom (.getEntry jar pom-path)]
(and pom (xml/parse (.getInputStream jar pom)))))
(def ^:private license-file-names #{"LICENSE" "LICENSE.txt" "META-INF/LICENSE"
"META-INF/LICENSE.txt" "license/LICENSE"})
(defn- get-entry [jar name]
(.getEntry jar name))
(defn- try-raw-license [file]
(try
(let [jar (JarFile. file)
entry (some #(.getEntry jar %) license-file-names)]
(with-open [rdr (io/reader (.getInputStream jar entry))]
(string/trim (first (remove string/blank? (line-seq rdr))))))
(catch Exception e
(binding [*out* *err*]
(println "# " (class e) (.getMessage e))))))
(defn- get-licenses [dep file]
(if-let [pom (get-pom dep file)]
(->> (iterate get-parent pom)
(take-while identity)
(map pom-license)
(apply concat)
;; TODO: this might be trimming additional licenses?
(map (comp first :content first :content))
(filter (tag :name))
first :content first)
(try-raw-license file)))
(def formatters
{":text"
(fn [line]
(string/join " - " line))
":csv"
(fn [line]
(let [quote-csv
(fn [text]
(str \" (clojure.string/replace text #"\"" "\"\"") \"))]
(string/join "," (map quote-csv line))))})
(defn licenses
"List the license of each of your dependencies.
USAGE: lein licenses [:text]
Show license information in the default text format
USAGE lein licenses :csv
Show licenses in CSV format"
([project]
(licenses project ":text"))
([project output-style]
(if-let [format-fn (formatters output-style)]
(let [deps (#'classpath/get-dependencies :dependencies project)
deps (zipmap (keys deps) (aether/dependency-files deps))]
(doseq [[[dep version] file] deps]
(let [line [(pr-str dep)
version
(or (get-licenses dep file) "Unknown")]]
(println (format-fn line)))))
(main/abort "unknown formatter"))))