aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/git.clj71
1 files changed, 71 insertions, 0 deletions
diff --git a/scripts/git.clj b/scripts/git.clj
new file mode 100755
index 0000000..c1e450b
--- /dev/null
+++ b/scripts/git.clj
@@ -0,0 +1,71 @@
+#!/usr/bin/env bb
+
+(require '[clojure.java.shell :refer [sh]])
+(require '[clojure.string :as str])
+(require '[clojure.java.io :as io])
+
+(defn dirname [path] (.getParent (io/file path)))
+
+(defn git [dir & args]
+ (let [proc (apply sh "git" "-C" (or dir ".") args)]
+ (when (= (:exit proc) 0)
+ (str/trim (:out proc)))))
+
+(defn git-remote-origin [dir]
+ (not-empty (git dir "remote" "get-url" "origin")))
+
+(defn git-first-remote [dir]
+ (some->> (git dir "remote" "-v")
+ str/split-lines
+ (keep #(re-matches #"^\w+\s+(.*)\s+\(fetch\)" %))
+ first
+ second))
+
+(defn prepare-link [remote-url rev file-path & [line-start line-end]]
+ (let [parse-path #(some->> (re-matches % remote-url) second)
+ line-hash (cond
+ (nil? line-start) nil
+ (= line-start line-end) (str "#L" line-start)
+ (some? line-end) (str "#L" line-start "-L" line-end)
+ (nil? line-end) (str "#L" line-start))]
+ (some->>
+ (cond
+ (empty? remote-url) nil
+ (.contains remote-url "github.com:") ["https://github.com" (parse-path #".*github.com:(.*)\.git$") "blob" rev (str file-path line-hash)]
+ (.contains remote-url "github.com/") ["https://github.com" (parse-path #".*github.com/(.*)(\.git)?$") "blob" rev (str file-path line-hash)]
+ (.contains remote-url "gitlab.com:") ["https://gitlab.com" (parse-path #".*gitlab.com:(.*)\.git$") "-/blob" rev (str file-path line-hash)]
+ (.contains remote-url "gitlab.com/") ["https://gitlab.com" (parse-path #".*gitlab.com/(.*)(\.git)?$") "-/blob" rev (str file-path line-hash)]
+ (.contains remote-url "git.sr.ht:") ["https://git.sr.ht" (parse-path #".*git.sr.ht:(.*)\.git$") "tree" rev (str file-path line-hash)]
+ (.contains remote-url "git.sr.ht/") ["https://git.sr.ht" (parse-path #".*git.sr.ht/(.*)(\.git)?$") "tree" rev (str file-path line-hash)]
+ :else nil)
+ (remove nil?)
+ (str/join "/"))))
+
+(defn git-current-rev [dir] (git dir "rev-parse" "--short" "HEAD"))
+
+(defn git-remote-url [dir file-path revision line-start line-end]
+ (some-> (or (git-remote-origin dir) (git-first-remote dir))
+ (prepare-link revision file-path line-start line-end)))
+
+(defn git-root [path]
+ (let [file-dir (if (empty? path) "." (dirname path))]
+ (some->> (git file-dir "rev-parse" "--absolute-git-dir")
+ dirname)))
+
+(defn cmd-link [[file-path line-start line-end rev]]
+ (let [dir (git-root file-path)
+ revision (or rev (git-current-rev dir) "main")
+ relative-file-path (str/trim (:out (sh "realpath" "--relative-to" dir file-path)))
+ remote-url (git-remote-url dir relative-file-path revision line-start line-end)]
+ (println remote-url)))
+
+(def commands
+ {"link" cmd-link})
+
+(let [[cmd & args] *command-line-args*]
+ (if-let [command-fn (commands cmd)]
+ (command-fn args)
+ (binding [*out* *err*]
+ (println (str "invalid command: " (or cmd "")))
+ (println (str "Valid commands: " (keys commands))))))
+