forked from technomancy/leiningen
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvcs.clj
More file actions
102 lines (74 loc) · 3.48 KB
/
Copy pathvcs.clj
File metadata and controls
102 lines (74 loc) · 3.48 KB
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
(ns leiningen.vcs
"Interact with the version control system."
(:require [clojure.java.io :as io]
[bultitude.core :as b]
[leiningen.core.eval :as eval]
[leiningen.core.main :as main]))
;; TODO: make pom task use this ns by adding a few more methods
(def supported-systems (atom [:git]))
(defn uses-vcs [project vcs]
(let [vcs-dir (io/file (:root project) (str "." (name vcs)))]
(and (.exists vcs-dir) vcs)))
(defn which-vcs [project & _]
(or (:vcs project) (some (partial uses-vcs project) @supported-systems)))
(defn parse-tag-args [args]
(loop [parsed-args {:sign? true}
args args]
(case (first args)
("--sign" "-s") (recur (assoc parsed-args :sign? true) (rest args))
"--no-sign" (recur (assoc parsed-args :sign? false) (rest args))
nil parsed-args ;; We're finished and can exit
(recur (assoc parsed-args :prefix (first args)) (rest args)))))
;;; Methods
(defmulti push "Push to your remote repository."
which-vcs :default :none)
(defmulti commit "Commit changes to current repository."
which-vcs :default :none)
(defmulti tag "Apply a version control tag. Takes an optional tag prefix."
which-vcs :default :none)
(defmulti assert-committed "Abort if uncommitted changes exist."
which-vcs :default :none)
;;; VCS not found
(defn- unknown-vcs [task]
(binding [*out* *err*]
(println (str "Unknown VCS detected for 'vcs " task "'")))
(System/exit 1))
(defmethod push :none [project & [args]] (unknown-vcs "push"))
(defmethod commit :none [project] (unknown-vcs "commit"))
(defmethod tag :none [project] (unknown-vcs "tag"))
(defmethod assert-committed :none [project] (unknown-vcs "assert-committed"))
;;; Git
(defmethod push :git [project & args]
(binding [eval/*dir* (:root project)]
(apply eval/sh-with-exit-code "Couldn't push to the remote" "git" "push" args)
(apply eval/sh-with-exit-code "Couldn't push tags to the remote" "git" "push" "--tags" args)))
(defmethod commit :git [project]
(binding [eval/*dir* (:root project)]
(eval/sh-with-exit-code "Couldn't commit" "git" "commit" "-a" "-m" (str "Version " (:version project)))))
(defmethod tag :git [{:keys [root version]} & args]
(binding [eval/*dir* root]
(let [{:keys [sign? prefix]} (parse-tag-args args)
tag (if prefix
(str prefix version)
version)
cmd (->> ["git" "tag" (when sign? "--sign") tag "-m" (str "Release " version)]
(filter some?))]
(apply eval/sh-with-exit-code "Couldn't tag" cmd))))
(defmethod assert-committed :git [project]
(binding [eval/*dir* (:root project)]
(when (re-find #"Changes (not staged for commit|to be committed)"
(with-out-str (eval/sh-with-exit-code "Couldn't get status" "git" "status")))
(main/abort "Uncommitted changes in" (:root project) "directory."))))
(defn- not-found [subtask]
(partial #'main/task-not-found (str "vcs " subtask)))
(defn- load-methods []
(doseq [n (b/namespaces-on-classpath :prefix "leiningen.vcs.")]
(swap! supported-systems conj (keyword (last (.split (name n) "\\."))))
(require n)))
(defn ^{:subtasks [#'push #'commit #'tag #'assert-committed]} vcs
"Interact with the version control system."
[project subtask & args]
(load-methods)
(let [subtasks (:subtasks (meta #'vcs) {})
[subtask-var] (filter #(= subtask (name (:name (meta %)))) subtasks)]
(apply (or subtask-var (not-found subtask)) project args)))