diff --git a/src/babashka/pods/impl.clj b/src/babashka/pods/impl.clj index a0ee63a..d0cdcd9 100644 --- a/src/babashka/pods/impl.clj +++ b/src/babashka/pods/impl.clj @@ -1,7 +1,8 @@ (ns babashka.pods.impl {:no-doc true} (:refer-clojure :exclude [read]) - (:require [bencode.core :as bencode] + (:require [babashka.pods.impl.resolver :as resolver] + [bencode.core :as bencode] [cheshire.core :as cheshire] [clojure.edn :as edn] [clojure.java.io :as io] @@ -278,7 +279,9 @@ (defn load-pod ([pod-spec] (load-pod pod-spec nil)) ([pod-spec {:keys [:remove-ns :resolve :transport]}] - (let [pod-spec (if (string? pod-spec) [pod-spec] pod-spec) + (let [pod-spec (cond (string? pod-spec) [pod-spec] + (qualified-symbol? pod-spec) (resolver/resolve qualified-symbol?) + :else pod-spec) pb (ProcessBuilder. ^java.util.List pod-spec) socket? (identical? :socket transport) _ (if socket? diff --git a/src/babashka/pods/impl/resolver.clj b/src/babashka/pods/impl/resolver.clj new file mode 100644 index 0000000..3a3b9c1 --- /dev/null +++ b/src/babashka/pods/impl/resolver.clj @@ -0,0 +1,111 @@ +(ns babashka.pods.impl.resolver + {:no-doc true} + (:refer-clojure :exclude [resolve]) + (:require [clojure.edn :as edn] + [clojure.java.io :as io] + [clojure.java.shell :refer [sh]] + [clojure.string :as str]) + (:import [java.net URL HttpURLConnection] + [java.nio.file Files])) + +(set! *warn-on-reflection* true) + +(defn normalize-arch [arch] + (if (= "amd64" arch) + "x86_64" + arch)) + +(def os {:os/name (System/getProperty "os.name") + :os/arch (let [arch (System/getProperty "os.arch")] + (normalize-arch arch))}) + +(defn warn [& strs] + (binding [*out* *err*] + (apply println strs))) + +(defn match-artifacts [package] + (let [artifacts (:package/artifacts package)] + (filter (fn [{os-name :os/name + os-arch :os/arch}] + (let [os-arch (normalize-arch os-arch)] + (and (re-matches (re-pattern os-name) (:os/name os)) + (re-matches (re-pattern os-arch) + (:os/arch os))))) + artifacts))) + +(defn unzip [{:keys [^java.io.File zip-file + ^java.io.File destination-dir + verbose]}] + (when verbose (warn "Unzipping" (.getPath zip-file) "to" (.getPath destination-dir))) + (let [output-path (.toPath destination-dir) + zip-file (io/file zip-file) + _ (.mkdirs (io/file destination-dir))] + (with-open + [fis (Files/newInputStream (.toPath zip-file) (into-array java.nio.file.OpenOption [])) + zis (java.util.zip.ZipInputStream. fis)] + (loop [] + (let [entry (.getNextEntry zis)] + (when entry + (let [entry-name (.getName entry) + new-path (.resolve output-path entry-name)] + (if (.isDirectory entry) + (Files/createDirectories new-path (into-array [])) + (Files/copy ^java.io.InputStream zis + new-path + ^"[Ljava.nio.file.CopyOption;" + (into-array + [java.nio.file.StandardCopyOption/REPLACE_EXISTING])))) + (recur))))))) + +(defn un-tgz [^java.io.File zip-file ^java.io.File destination-dir verbose?] + (when verbose? (warn "Unzipping" (.getPath zip-file) "to" (.getPath destination-dir))) + (let [tmp-file (java.io.File/createTempFile "glam" ".tar") + output-path (.toPath tmp-file)] + (with-open + [fis (Files/newInputStream (.toPath zip-file) (into-array java.nio.file.OpenOption [])) + zis (java.util.zip.GZIPInputStream. fis)] + (Files/copy ^java.io.InputStream zis + output-path + ^"[Ljava.nio.file.CopyOption;" + (into-array + [java.nio.file.StandardCopyOption/REPLACE_EXISTING]))) + (sh "tar" "xf" (.getPath tmp-file) "--directory" (.getPath destination-dir)) + (.delete tmp-file))) + +(defn make-executable [dest-dir executables verbose?] + (doseq [e executables] + (let [f (io/file dest-dir e)] + (when verbose? (warn "Making" (.getPath f) "executable.")) + (.setExecutable f true)))) + +(defn download [source ^java.io.File dest verbose?] + (when verbose? (warn "Downloading" source "to" (.getPath dest))) + (let [source (URL. source) + dest (io/file dest) + conn ^HttpURLConnection (.openConnection ^URL source)] + (.setInstanceFollowRedirects conn true) + (.connect conn) + (io/make-parents dest) + (with-open [is (.getInputStream conn)] + (io/copy is dest)) + (when verbose? (warn "Download complete.")))) + +(def pod-data-dir + ;; wrapped in delay for GraalVM native-image + (delay (io/file (System/getProperty "user.home") + ".babashka" "pods" "data"))) + +(defn pod-meta + ([qsym] (pod-meta qsym nil)) + ([qsym version] + (let [version (or version "latest") + f (io/file @pod-data-dir qsym (str version ".edn"))] + (if (.exists f) f + ;; TODO: download from github? + )))) + + + +(defn resolve [qsym] ;; TODO: version + (if-let [m (pod-meta qsym)] + ))