Last active
December 22, 2015 04:39
-
-
Save Jared314/6418917 to your computer and use it in GitHub Desktop.
Improving the Clojure-Git Interface with a Nice Facade
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns gitter.core | |
(:require [clj-jgit.porcelain :as c] | |
[clj-jgit.querying :as q] | |
[clj-jgit.internal :as i] | |
[clojure.string :as string] | |
[gitter.clj-jgit.porcelain :as helpers]) | |
(:import [clojure.lang ISeq Associative IFn MapEntry IObj] | |
[org.eclipse.jgit.api Git] | |
[org.eclipse.jgit.revwalk RevWalk])) | |
(defn gen-metadata [^Git repo] | |
(let [path (-> repo .getRepository .getDirectory .getParent) | |
branch (c/git-branch-current repo) | |
branch-names (map #(string/replace (.getName %) #"^refs/heads/" "") (c/git-branch-list repo)) | |
attached (c/git-branch-attached? repo)] | |
{::path path | |
::branch branch | |
::branches branch-names | |
::attached-head attached})) | |
(deftype Repository [^Git repo ^RevWalk walker metadata] | |
Associative | |
(count [this] -1) ;; TODO: Not yet | |
(seq [this] (seq walker)) | |
(cons [this o] | |
;; TODO: if walker first is not the current HEAD, create branch from current first | |
(helpers/git-add-commit repo o) | |
(Repository. repo (i/new-rev-walk repo) metadata)) | |
(empty [_] nil) ;; TODO: Not applicable or branch? | |
(equiv [_ o] | |
(and (instance? Repository o) | |
(= repo (.repo o)))) | |
(containsKey [_ key] (not (nil? (i/resolve-object key repo)))) | |
(entryAt [this k] (MapEntry. k (.valAt this k))) | |
(assoc [this _ _] this) ;; Not applicable | |
(valAt [this key] (.valAt this key nil)) | |
(valAt [this key notFound] (if (.containsKey this key) | |
(q/find-rev-commit repo walker key) | |
notFound)) | |
IFn | |
(invoke [this arg1] (.valAt this arg1 nil)) | |
(invoke [this arg1 arg2] (.valAt this arg1 arg2)) | |
IObj | |
(withMeta [_ meta] (Repository. repo walker (merge metadata meta))) | |
(meta [_] (merge (gen-metadata repo) metadata)) | |
Object | |
(toString [this] (let [m (.meta this)] (str "Path: " (::path m) " Branch: " (::branch m))))) | |
(defn get-repo [path] | |
(c/with-repo path (Repository. repo rev-walk nil))) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns gitter.core-test | |
(:require [clojure.test :refer :all] | |
[gitter.core :refer :all] | |
[gitter.clj-jgit.porcelain :refer :all]) | |
(:import [java.util Date])) | |
(def test-repo-path "/Users/user1/Desktop/tester1") | |
(deftest read-repo-test | |
(let [x (get-repo test-repo-path)] | |
(testing "Reading from the repository" | |
;; Checking for a commit by id | |
(is (contains? x "44cf78fa233d4ef44314099762ab77543471720a")) | |
(is (contains? x "HEAD")) | |
;; Fetching a commit | |
(is (= (get x "44cf78fa233d4ef443") | |
(x "44cf78fa233d4ef443"))) | |
(is (= (get x "HEAD") | |
(x "HEAD"))) | |
;; Fetching a commit with a notFound parameter | |
(is (= :fail | |
(get x "" :fail) | |
(x "" :fail))) | |
;; The repository has the following default metadata | |
(is (= {:gitter.core/path test-repo-path, :gitter.core/branches '("master"), :gitter.core/branch "master" :gitter.core/attached-head true} | |
(meta x))) | |
;; Assoc does nothing, and returns the repository | |
(is (= x | |
(assoc x "" 1))) | |
;;(seq? x) ;; TODO: | |
;;(first x) ;; TODO: | |
))) | |
(deftest write-repo-test | |
(testing "Writing to the repository" | |
(let [x (get-repo test-repo-path) | |
c {:message "test commit" | |
:author {:name "guy 1234" :email "[email protected]"} | |
:changes {"stuff.txt" (str "stuff contents " (Date.)) | |
"stuff4.txt" (str "stuff4 contents " (Date.))}}] | |
(is (= x | |
(conj x c)))))) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns gitter.clj-jgit.porcelain | |
(:require [clj-jgit.util :as util] | |
[clj-jgit.internal :refer :all] | |
[clj-jgit.porcelain :as c]) | |
(:import [org.eclipse.jgit.api Git StatusCommand Status StashCreateCommand StashApplyCommand] | |
[org.eclipse.jgit.lib ObjectId] | |
[gitter TreeIterator])) | |
(defn git-create-stash [^Git repo] | |
(-> repo | |
.stashCreate | |
.call)) | |
(defn git-apply-stash [^Git repo ^String key] | |
(-> repo | |
.stashApply | |
(.setStashRef key) | |
.call)) | |
(defn git-list-stash [^Git repo] | |
(-> repo | |
.stashList | |
.call)) | |
(defn git-drop-stash [^Git repo ^String key] | |
(let [stashes (git-list-stash repo) | |
target (first (filter #(= key (second %)) | |
(map-indexed #(vector %1 (.getName %2)) stashes)))] ;; TODO: cleanup | |
(when-not (nil? target) | |
(-> repo | |
.stashDrop | |
(.setStashRef (first target)) | |
.call)))) | |
(defn git-pop-stash [^Git repo ^String key] | |
(git-apply-stash repo key) | |
(git-drop-stash repo key)) | |
(defn head? [^Git repo k] | |
(let [r (.getRepository repo) | |
head (.getRef r "HEAD")] | |
(and (not (nil? head)) | |
(not (nil? (.getObjectId head))) | |
(= head | |
(.getRef r k))))) | |
;; TODO: There has to be a better way! | |
(defn with-preserved-staging [repo f] | |
(let [has-staged-changes (not-every? empty? (vals (c/git-status repo :added :changed :removed))) | |
stashid (if has-staged-changes (ObjectId/toString (.getId (git-create-stash repo)))) | |
result (f)] | |
(when has-staged-changes (git-pop-stash repo stashid)) | |
result)) | |
(defn git-add-commit [repo {:keys [message author committer changes] | |
:or {message "" author {:name "" :email ""} committer nil changes {}}}] | |
(let [prefixed-author {:author-name (:name author) :author-email (:email author)} | |
c (merge author committer) | |
prefixed-committer {:committer-name (:name c) :committer-email (:email c)}] | |
(with-preserved-staging repo | |
#(doto repo | |
(c/git-add "." false (TreeIterator. (.getRepository repo) changes)) | |
(c/git-commit message prefixed-author prefixed-committer))))) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defproject gitter "0.1.0-SNAPSHOT" | |
:description "FIXME: write description" | |
:url "http://example.com/FIXME" | |
:license {:name "Eclipse Public License" | |
:url "http://www.eclipse.org/legal/epl-v10.html"} | |
:dependencies [[org.clojure/clojure "1.5.1"] | |
[clj-jgit "0.3.9"]] | |
:aot [gitter.TreeIterator]) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns gitter.TreeIterator | |
(:import [org.eclipse.jgit.lib Repository FileMode] | |
[org.eclipse.jgit.treewalk WorkingTreeIterator WorkingTreeIterator$Entry WorkingTreeOptions] | |
[java.io ByteArrayInputStream]) | |
(:gen-class :extends org.eclipse.jgit.treewalk.WorkingTreeIterator | |
:init init2 | |
:post-init postinit | |
:state state | |
:constructors {[org.eclipse.jgit.lib.Repository Object] [org.eclipse.jgit.treewalk.WorkingTreeOptions] | |
[org.eclipse.jgit.lib.Repository Object org.eclipse.jgit.treewalk.WorkingTreeIterator] [org.eclipse.jgit.treewalk.WorkingTreeIterator]})) | |
(gen-interface :name gittree.IHasValue | |
:methods [[getValue [] Object]]) | |
(defn toEntry | |
([[k v]] (toEntry k v)) | |
([k v] | |
(let [node-name (if (keyword? k) (name k) (str k)) | |
node-mode (if (coll? v) FileMode/TREE FileMode/REGULAR_FILE) | |
node-modified 0 | |
node-value (if (string? v) (.getBytes v) (byte-array 0)) | |
node-length (count node-value)] | |
(proxy [WorkingTreeIterator$Entry gittree.IHasValue] [] | |
(getMode [] node-mode) | |
(getName [] node-name) | |
(getLength [] node-length) | |
(getLastModified [] node-modified) | |
(openInputStream [] (ByteArrayInputStream. node-value)) | |
(getValue [] v))))) | |
(defn -init2 | |
([^Repository repo data] | |
(let [options (-> repo (.getConfig) (.get WorkingTreeOptions/KEY))] | |
[[options] {:repo repo}])) | |
([^Repository repo data ^WorkingTreeIterator itr] | |
[[itr] {:repo repo}])) | |
(defn -postinit | |
([this repo data] (-postinit this repo data nil)) | |
([this repo data _] | |
(let [entries (if (map? data) (map toEntry data) (map-indexed toEntry data))] | |
(.initRootIterator this repo) | |
(.init this (into-array WorkingTreeIterator$Entry entries))))) | |
(defn -createSubtreeIterator [this reader idBuffer] | |
(let [repo (:repo (.state this))] | |
(gitter.TreeIterator. repo (.getValue (.current this)) this))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment