git.cljs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. (ns frontend.git
  2. (:refer-clojure :exclude [clone merge])
  3. (:require [promesa.core :as p]
  4. [frontend.util :as util]
  5. [frontend.config :as config]
  6. [clojure.string :as string]
  7. [clojure.set :as set]
  8. [frontend.state :as state]
  9. [cljs-bean.core :as bean]))
  10. ;; only support GitHub now
  11. (defn get-username
  12. []
  13. (get-in @state/state [:me :name]))
  14. (defn get-cors-proxy
  15. #_:clj-kondo/ignore
  16. [repo-url]
  17. (or
  18. (when-not (string/blank? (:cors_proxy (state/get-me)))
  19. (:cors_proxy (state/get-me)))
  20. ;; Not working yet
  21. ;; "https://cors-proxy-logseq.vercel.app"
  22. "https://cors.logseq.com"))
  23. (defn set-username-email
  24. [dir username email]
  25. (-> (p/let [_ (js/window.workerThread.setConfig dir "user.name" username)]
  26. (js/window.workerThread.setConfig dir "user.email" email))
  27. (p/catch (fn [error]
  28. (prn "Git set config error:" error)))))
  29. (defn clone
  30. [repo-url token]
  31. (js/window.workerThread.clone (config/get-repo-dir repo-url)
  32. repo-url
  33. (get-cors-proxy repo-url)
  34. 1
  35. (state/get-default-branch repo-url)
  36. (get-username)
  37. token))
  38. (defn list-files
  39. [repo-url]
  40. (js/window.workerThread.listFiles (config/get-repo-dir repo-url)
  41. (state/get-default-branch repo-url)))
  42. (defn fetch
  43. [repo-url token]
  44. (js/window.workerThread.fetch (config/get-repo-dir repo-url)
  45. repo-url
  46. (get-cors-proxy repo-url)
  47. 100
  48. (state/get-default-branch repo-url)
  49. (get-username)
  50. token))
  51. (defn merge
  52. [repo-url]
  53. (js/window.workerThread.merge (config/get-repo-dir repo-url)
  54. (state/get-default-branch repo-url)))
  55. (defn checkout
  56. [repo-url]
  57. (js/window.workerThread.checkout (config/get-repo-dir repo-url)
  58. (state/get-default-branch repo-url)))
  59. (defn add
  60. [repo-url file]
  61. (when js/window.git
  62. (js/window.workerThread.add (config/get-repo-dir repo-url)
  63. file)))
  64. (defn remove-file
  65. [repo-url file]
  66. (js/window.workerThread.remove (config/get-repo-dir repo-url)
  67. file))
  68. (defn rename
  69. [repo-url old-file new-file]
  70. (util/p-handle
  71. (add repo-url new-file)
  72. (fn [_]
  73. (remove-file repo-url old-file))))
  74. (defn commit
  75. ([repo-url message]
  76. (commit repo-url message nil))
  77. ([repo-url message parent]
  78. (let [{:keys [name email]} (:me @state/state)]
  79. (js/window.workerThread.commit (config/get-repo-dir repo-url)
  80. message
  81. name
  82. email
  83. parent))))
  84. (defn add-all
  85. "Equivalent to `git add --all`. Returns changed files."
  86. [repo-url]
  87. (p/let [repo-dir (config/get-repo-dir repo-url)
  88. ; statusMatrix will return `[]` rather than raising an error if the repo directory does
  89. ; not exist. So checks whether repo-dir exists before proceeding.
  90. _ (-> (js/window.pfs.stat repo-dir)
  91. (p/catch #(p/rejected (str "Cannot find repo dir '"
  92. repo-dir
  93. "' in fs when `git add --all`"))))
  94. status-matrix (js/window.workerThread.statusMatrixChanged repo-dir)
  95. changed-files (for [[file head work-dir _stage] status-matrix
  96. :when (not= head work-dir)]
  97. file)
  98. unstaged-files (for [[file _head work-dir stage] status-matrix
  99. :when (not= work-dir stage)]
  100. file)
  101. _ (p/all (for [file unstaged-files]
  102. (add repo-url file)))]
  103. changed-files))
  104. (defn commit-non-empty
  105. "Equivalent to `git add --all` and then `git commit` without `--allow-empty`."
  106. ([repo-url message]
  107. (commit-non-empty repo-url message nil))
  108. ([repo-url message parent]
  109. (p/let [changed-files (add-all repo-url)]
  110. (if (not-empty changed-files)
  111. (commit repo-url message parent)
  112. (p/resolved nil)))))
  113. (defn read-commit
  114. [repo-url oid]
  115. (js/window.workerThread.readCommit (config/get-repo-dir repo-url)
  116. oid))
  117. ;; FIXME: not working
  118. ;; (defn descendent?
  119. ;; [repo-url oid ancestor]
  120. ;; (js/window.workerThread.isDescendent (config/get-repo-dir repo-url)
  121. ;; oid
  122. ;; ancestor))
  123. (defn descendent?
  124. [repo-url oid ancestor]
  125. (p/let [child (read-commit repo-url oid)
  126. child-data (bean/->clj child)
  127. parent (read-commit repo-url ancestor)
  128. parent-data (bean/->clj parent)
  129. child-time (get-in child-data [:commit :committer :timestamp])
  130. parent-time (get-in parent-data [:commit :committer :timestamp])]
  131. (> child-time parent-time)))
  132. (defn push
  133. ([repo-url token]
  134. (push repo-url token false))
  135. ([repo-url token force?]
  136. (js/window.workerThread.push (config/get-repo-dir repo-url)
  137. (get-cors-proxy repo-url)
  138. (state/get-default-branch repo-url)
  139. force?
  140. (get-username)
  141. token)))
  142. (defn add-commit
  143. [repo-url file message commit-ok-handler commit-error-handler]
  144. (util/p-handle
  145. (add repo-url file)
  146. (fn [_]
  147. (util/p-handle
  148. (commit repo-url message)
  149. (fn []
  150. (commit-ok-handler))
  151. (fn [error]
  152. (commit-error-handler error))))))
  153. (defn get-diffs
  154. [repo-url hash-1 hash-2]
  155. (and js/window.git
  156. (let [dir (config/get-repo-dir repo-url)]
  157. (p/let [diffs (js/window.workerThread.getFileStateChanges hash-1 hash-2 dir)
  158. diffs (cljs-bean.core/->clj diffs)
  159. diffs (remove #(= (:type %) "equal") diffs)
  160. diffs (map (fn [diff]
  161. (update diff :path #(subs % 1))) diffs)]
  162. diffs))))
  163. (defn find-common-base
  164. ([repo-url remote-id local-id]
  165. (find-common-base repo-url remote-id local-id (atom [local-id]) (atom [remote-id])))
  166. ([repo-url remote-id local-id local-commits remote-commits]
  167. ;; FIXME: p/plet not working
  168. (p/let
  169. [local-commit (read-commit repo-url local-id)]
  170. (p/let [remote-commit (read-commit repo-url remote-id)]
  171. (let [local-parent (first (get-in (bean/->clj local-commit) [:commit :parent]))
  172. remote-parent (first (get-in (bean/->clj remote-commit) [:commit :parent]))]
  173. (swap! local-commits conj local-parent)
  174. (swap! remote-commits conj remote-parent)
  175. (let [commons (set/intersection (set @local-commits)
  176. (set @remote-commits))]
  177. (if (seq commons)
  178. (first commons)
  179. (find-common-base repo-url local-parent remote-parent local-commits remote-commits))))))))
  180. (defn read-blob
  181. [repo-url oid path]
  182. (js/window.workerThread.readBlob (config/get-repo-dir repo-url)
  183. oid
  184. path))
  185. ;; (resolve-ref (state/get-current-repo) "refs/remotes/origin/master")
  186. (defn resolve-ref
  187. [repo-url ref]
  188. (js/window.workerThread.resolveRef (config/get-repo-dir repo-url) ref))
  189. (defn write-ref!
  190. [repo-url oid]
  191. (js/window.workerThread.writeRef (config/get-repo-dir repo-url)
  192. (state/get-default-branch repo-url)
  193. oid))