Skip to content

Commit

Permalink
Move rads.deps-info into babashka.bbin.deps
Browse files Browse the repository at this point in the history
  • Loading branch information
rads committed Apr 26, 2024
1 parent 6ea3f3a commit 39ea43d
Show file tree
Hide file tree
Showing 6 changed files with 305 additions and 26 deletions.
25 changes: 12 additions & 13 deletions bbin
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
org.babashka/cli {:mvn/version "0.6.43"},
com.taoensso/timbre {:mvn/version "5.2.1"},
babashka/process {:mvn/version "0.4.14"},
io.github.rads/deps-info {:git/tag "v0.1.3", :git/sha "a591645"},
org.clojure/tools.gitlibs {:mvn/version "2.4.181"},
org.babashka/http-client {:mvn/version "0.1.8"},
version-clj/version-clj {:mvn/version "2.0.2"},
babashka/fs {:mvn/version "0.3.17"},
Expand Down Expand Up @@ -457,13 +457,12 @@ WARNING: (We won't make any changes without asking you first.)
(ns babashka.bbin.scripts.common
(:require [babashka.fs :as fs]
[babashka.deps :as deps]
[babashka.bbin.deps :as bbin-deps]
[babashka.bbin.dirs :as dirs]
[babashka.bbin.util :as util :refer [sh]]
[clojure.edn :as edn]
[clojure.main :as main]
[clojure.string :as str]
[rads.deps-info.infer :as deps-info-infer]
[rads.deps-info.summary :as deps-info-summary]
[selmer.parser :as selmer]
[selmer.util :as selmer-util])
(:import (java.util.jar JarFile)))
Expand Down Expand Up @@ -739,15 +738,15 @@ WARNING: (We won't make any changes without asking you first.)
(and (#{:local} procurer) (not (:local/root cli-opts)))
{::no-lib {:local/root (str (fs/canonicalize (:script/lib cli-opts) {:-links true}))}}

(deps-info-summary/git-repo-url? (:script/lib cli-opts))
(deps-info-infer/infer
(bbin-deps/git-repo-url? (:script/lib cli-opts))
(bbin-deps/infer
(cond-> (assoc cli-opts :lib (str (generate-deps-lib-name (:script/lib cli-opts)))
:git/url (:script/lib cli-opts))
(not (some cli-opts [:latest-tag :latest-sha :git/sha :git/tag]))
(assoc :latest-sha true)))

:else
(deps-info-infer/infer (assoc cli-opts :lib (:script/lib cli-opts))))
(bbin-deps/infer (assoc cli-opts :lib (:script/lib cli-opts))))
lib (key (first script-deps))
coords (val (first script-deps))
header (merge {:coords coords} (when-not (#{::no-lib} lib) {:lib lib}))
Expand Down Expand Up @@ -1179,6 +1178,7 @@ WARNING: (We won't make any changes without asking you first.)
(:require
[babashka.bbin.scripts.common :as common]
[babashka.bbin.util :as util]
[babashka.bbin.deps :as bbin-deps]
[babashka.bbin.dirs :as dirs]
[babashka.bbin.protocols :as p]
[babashka.bbin.scripts.git-dir :refer [map->GitDir]]
Expand All @@ -1192,7 +1192,6 @@ WARNING: (We won't make any changes without asking you first.)
[clojure.edn :as edn]
[clojure.java.io :as io]
[clojure.string :as str]
[rads.deps-info.summary :as deps-info-summary]
[selmer.filters :as filters]))

;; selmer filter for clojure escaping for e.g. files
Expand Down Expand Up @@ -1244,7 +1243,7 @@ WARNING: (We won't make any changes without asking you first.)
:artifact artifact}))))

(defn- new-script [cli-opts]
(let [summary (deps-info-summary/summary cli-opts)
(let [summary (bbin-deps/summary cli-opts)
{:keys [procurer artifact]} summary]
(case [procurer artifact]
[:git :dir] (map->GitDir {:cli-opts cli-opts :summary summary})
Expand Down Expand Up @@ -1283,7 +1282,7 @@ WARNING: (We won't make any changes without asking you first.)
parsed (parse-script (read-header script-file))]
(cond
(-> parsed :coords :bbin/url)
(let [summary (deps-info-summary/summary {:script/lib (-> parsed :coords :bbin/url)})
(let [summary (bbin-deps/summary {:script/lib (-> parsed :coords :bbin/url)})
{:keys [procurer artifact]} summary]
(case [procurer artifact]
[:git :dir] (map->GitDir {:cli-opts cli-opts :summary summary :coords (:coords parsed)})
Expand All @@ -1298,13 +1297,13 @@ WARNING: (We won't make any changes without asking you first.)
(map->MavenJar {:cli-opts cli-opts :lib (:lib parsed)})

(-> parsed :coords :git/tag)
(let [summary (deps-info-summary/summary {:script/lib (:lib parsed)
:git/tag (-> parsed :coords :git/tag)})]
(let [summary (bbin-deps/summary {:script/lib (:lib parsed)
:git/tag (-> parsed :coords :git/tag)})]
(map->GitDir {:cli-opts cli-opts :summary summary :coords (:coords parsed)}))

(-> parsed :coords :git/sha)
(let [summary (deps-info-summary/summary {:script/lib (:lib parsed)
:git/sha (-> parsed :coords :git/sha)})]
(let [summary (bbin-deps/summary {:script/lib (:lib parsed)
:git/sha (-> parsed :coords :git/sha)})]
(map->GitDir {:cli-opts cli-opts :summary summary :coords (:coords parsed)}))

:else (default-script cli-opts))))
Expand Down
2 changes: 1 addition & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
com.taoensso/timbre {:mvn/version "5.2.1"}
expound/expound {:mvn/version "0.9.0"}
fipp/fipp {:mvn/version "0.6.26"}
io.github.rads/deps-info {:git/tag "v0.1.3" :git/sha "a591645"}
org.babashka/cli {:mvn/version "0.6.43"}
org.babashka/http-client {:mvn/version "0.1.8"}
org.babashka/json {:mvn/version "0.1.1"}
org.clojure/tools.gitlibs {:mvn/version "2.4.181"}
selmer/selmer {:mvn/version "1.12.55"}
version-clj/version-clj {:mvn/version "2.0.2"}}
:aliases {:neil {:project {:name babashka/bbin
Expand Down
194 changes: 194 additions & 0 deletions src/babashka/bbin/deps.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
(ns babashka.bbin.deps
(:require [babashka.fs :as fs]
[clojure.edn :as edn]
[clojure.set :as set]
[clojure.tools.gitlibs.impl :as gitlibs-impl]
[babashka.bbin.git :as git]))

(def lib-opts->template-deps-fn
"A map to define valid CLI options.
- Each key is a sequence of valid combinations of CLI opts.
- Each value is a function which returns a tools.deps lib map."
{[#{:local/root}]
(fn [_ lib-sym lib-opts]
{lib-sym (select-keys lib-opts [:local/root])})

[#{} #{:git/url}]
(fn [client lib-sym lib-opts]
(let [url (or (:git/url lib-opts) (git/git-repo-url client lib-sym))
tag (git/latest-git-tag client url)]
(if tag
{lib-sym {:git/url url
:git/tag (:name tag)
:git/sha (-> tag :commit :sha)}}
(let [sha (git/latest-git-sha client url)]
{lib-sym {:git/url url
:git/sha sha}}))))

[#{:git/tag} #{:git/url :git/tag}]
(fn [client lib-sym lib-opts]
(let [url (or (:git/url lib-opts) (git/git-repo-url client lib-sym))
tag (:git/tag lib-opts)
{:keys [commit]} (git/find-git-tag client url tag)]
{lib-sym {:git/url url
:git/tag tag
:git/sha (:sha commit)}}))

[#{:git/sha} #{:git/url :git/sha}]
(fn [client lib-sym lib-opts]
(let [url (or (:git/url lib-opts) (git/git-repo-url client lib-sym))
sha (:git/sha lib-opts)]
{lib-sym {:git/url url
:git/sha sha}}))

[#{:latest-sha} #{:git/url :latest-sha}]
(fn [client lib-sym lib-opts]
(let [url (or (:git/url lib-opts) (git/git-repo-url client lib-sym))
sha (git/latest-git-sha client url)]
{lib-sym {:git/url url
:git/sha sha}}))

[#{:git/url :git/tag :git/sha}]
(fn [_ lib-sym lib-opts]
{lib-sym (select-keys lib-opts [:git/url :git/tag :git/sha])})})

(def valid-lib-opts
"The set of all valid combinations of CLI opts."
(into #{} cat (keys lib-opts->template-deps-fn)))

(defn- cli-opts->lib-opts
"Returns parsed lib opts from raw CLI opts."
[cli-opts]
(-> cli-opts
(set/rename-keys {:sha :git/sha})
(select-keys (into #{} cat valid-lib-opts))))

(defn- find-template-deps-fn
"Returns a template-deps-fn given lib-opts parsed from raw CLI opts."
[lib-opts]
(some (fn [[k v]] (and (contains? (set k) (set (keys lib-opts))) v))
lib-opts->template-deps-fn))

(defn- invalid-lib-opts-error [provided-lib-opts]
(ex-info (str "Provided invalid combination of CLI options")
{:provided-opts (set (keys provided-lib-opts))
:valid-combinations valid-lib-opts}))

(def ^:private default-deps-info-client
{:ensure-git-dir gitlibs-impl/ensure-git-dir
:git-fetch gitlibs-impl/git-fetch})

(defn infer
"Returns a tools.deps lib map for the given CLI opts."
([cli-opts] (infer nil cli-opts))
([client cli-opts]
(let [client (merge default-deps-info-client client)
lib-opts (cli-opts->lib-opts cli-opts)
lib-sym (edn/read-string (:lib cli-opts))
template-deps-fn (find-template-deps-fn lib-opts)]
(if-not template-deps-fn
(throw (invalid-lib-opts-error lib-opts))
(template-deps-fn client lib-sym lib-opts)))))

(def ^:private symbol-regex
(re-pattern
(str "(?i)^"
"(?:((?:[a-z0-9-]+\\.)*[a-z0-9-]+)/)?"
"((?:[a-z0-9-]+\\.)*[a-z0-9-]+)"
"$")))

(defn- lib-str? [x]
(boolean (and (string? x) (re-seq symbol-regex x))))

(defn- local-script-path? [x]
(boolean (and (string? x) (fs/exists? x))))

(defn- http-url? [x]
(boolean (and (string? x) (re-seq #"^https?:https://" x))))

(defn- git-ssh-url? [x]
(boolean (and (string? x) (re-seq #"^.+@.+:.+\.git$" x))))

(defn- git-http-url? [x]
(boolean (and (string? x) (re-seq #"^https?:https://.+\.git$" x))))

(defn git-repo-url? [s]
(or (git-http-url? s) (git-ssh-url? s)))

(def ^:private deps-types
[{:lib lib-str?
:coords #{:local/root}
:procurer :local}

{:lib lib-str?
:coords #{:mvn/version}
:procurer :maven}

{:lib local-script-path?
:coords #{:bbin/url}
:procurer :local}

{:lib #(or (git-http-url? %) (git-ssh-url? %))
:coords #{:bbin/url}
:procurer :git}

{:lib http-url?
:coords #{:bbin/url}
:procurer :http}

{:lib lib-str?
:coords #{:git/sha :git/url :git/tag}
:procurer :git}

{:lib local-script-path?
:coords #{}
:procurer :local}

{:lib #(or (git-http-url? %) (git-ssh-url? %) (lib-str? %))
:coords #{}
:procurer :git}

{:lib http-url?
:coords #{}
:procurer :http}])


(defn- deps-type-match? [cli-opts deps-type]
(and ((:lib deps-type) (:script/lib cli-opts))
(or (empty? (:coords deps-type))
(seq (set/intersection (:coords deps-type) (set (keys cli-opts)))))
deps-type))

(defn- match-deps-type [cli-opts]
(or (some #(deps-type-match? cli-opts %) deps-types)
{:procurer :unknown-procurer}))

(defn- match-artifact [cli-opts procurer]
(cond
(or (#{:maven} procurer)
(and (#{:local} procurer)
(or (and (:script/lib cli-opts) (re-seq #"\.jar$" (:script/lib cli-opts)))
(and (:local/root cli-opts) (re-seq #"\.jar$" (:local/root cli-opts)))))
(and (#{:http} procurer) (re-seq #"\.jar$" (:script/lib cli-opts))))
:jar

(or (#{:git} procurer)
(and (#{:local} procurer)
(or (and (:script/lib cli-opts) (fs/directory? (:script/lib cli-opts)))
(and (:local/root cli-opts) (fs/directory? (:local/root cli-opts)))))
(and (#{:http} procurer) (re-seq #"\.git$" (:script/lib cli-opts))))
:dir

(or (and (#{:local} procurer) (and (:script/lib cli-opts)
(fs/regular-file? (:script/lib cli-opts))))
(and (#{:http} procurer) (re-seq #"\.(cljc?|bb)$" (:script/lib cli-opts))))
:file

:else :unknown-artifact))

(defn summary [cli-opts]
(let [{:keys [procurer]} (match-deps-type cli-opts)
artifact (match-artifact cli-opts procurer)]
{:procurer procurer
:artifact artifact}))
87 changes: 87 additions & 0 deletions src/babashka/bbin/git.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
(ns babashka.bbin.git
(:require [clojure.string :as str]
[babashka.fs :as fs]
[babashka.process :refer [sh]]))

(defn- ensure-git-dir [client git-url]
(binding [*err* (java.io.StringWriter.)]
(let [path ((:ensure-git-dir client) git-url)]
((:git-fetch client) (fs/file path))
path)))

(defn default-branch [client git-url]
(let [lib-dir (ensure-git-dir client git-url)
remote-info (sh "git remote show origin" {:dir lib-dir
:extra-env {"LC_ALL" "C"}})
[[_ branch]] (->> (:out remote-info)
str/split-lines
(some #(re-seq #"HEAD branch: (\w+)" %)))]
branch))

(defn latest-git-sha [client git-url]
(let [lib-dir (ensure-git-dir client git-url)
branch (default-branch client git-url)
log-result (sh ["git" "log" "-n" "1" branch "--pretty=format:%H"]
{:dir lib-dir})]
(str/trim-newline (:out log-result))))

(defn find-git-tag [client git-url tag]
(let [lib-dir (ensure-git-dir client git-url)
log-result (sh ["git" "log" "-n" "1" tag "--pretty=format:%H"]
{:dir lib-dir})
sha (str/trim-newline (:out log-result))]
{:name (str tag)
:commit {:sha sha}}))

(defn latest-git-tag [client git-url]
(let [lib-dir (ensure-git-dir client git-url)
describe-result (sh "git describe --tags --abbrev=0" {:dir lib-dir})
tag (str/trim-newline (:out describe-result))]
(when-not (str/blank? tag)
(find-git-tag client git-url tag))))

(def providers
{#"^(com|io)\.github\." :github
#"^(com|io)\.gitlab\." :gitlab
#"^(org|io)\.bitbucket\." :bitbucket
#"^(com|io)\.beanstalkapp\." :beanstalk
#"^ht\.sr\." :sourcehut})

(defn- clean-lib-str [lib]
(->> (reduce #(str/replace %1 %2 "") lib (keys providers))
symbol))

(defn git-http-url [lib]
(let [provider (some #(when (re-seq (key %) (str lib)) %) providers)
s (clean-lib-str (str lib))]
(case (val provider)
:github (str "https://github.com/" s ".git")
:gitlab (str "https://gitlab.com/" s ".git")
:bitbucket (let [[u] (str/split (str s) #"/")]
(str "https://" u "@bitbucket.org/" s ".git"))
:beanstalk (let [[u] (str/split (str s) #"/")]
(str "https://" u ".git.beanstalkapp.com/" (name lib) ".git"))
:sourcehut (str "https://git.sr.ht/~" s))))

(defn git-ssh-url [lib]
(let [provider (some #(when (re-seq (key %) (str lib)) %) providers)
s (clean-lib-str (str lib))]
(case (val provider)
:github (str "[email protected]:" s ".git")
:gitlab (str "[email protected]:" s ".git")
:bitbucket (str "[email protected]:" s ".git")
:beanstalk (let [[u] (str/split (str s) #"/")]
(str "git@" u ".git.beanstalkapp.com:/" s ".git"))
:sourcehut (str "[email protected]:~" s))))

(defn git-repo-url [client lib]
(try
(let [url (git-http-url lib)]
(ensure-git-dir client url)
url)
(catch Exception e
(if (re-seq #"^Unable to clone " (ex-message e))
(let [url (git-ssh-url lib)]
(ensure-git-dir client url)
url)
(throw e)))))
Loading

0 comments on commit 39ea43d

Please sign in to comment.