Obsah
1. Programovací jazyk Clojure a práce s Gitem
2. Instalace knihovny clj-jgit
3. První demonstrační příklad – naklonování Git repositáře a výpis seznamu větví
5. Třetí demonstrační příklad – využití makra with-repo
6. Čtvrtý demonstrační příklad – výpis logu ve zjednodušené podobě
7. Pátý demonstrační příklad – výpis vybraných informací z logu
8. Šestý demonstrační příklad – přidání a modifikace souborů v Git repositáři, provedení commitu
9. Repositář s demonstračními příklady
10. Odkazy na předchozí části seriálu
1. Programovací jazyk Clojure a práce s GITem
Systém Git pravděpodobně není nutné programátorům podrobně představovat, protože se v současnosti jedná o jeden z nejrozšířenějších a nejpopulárnějších distribuovaných systémů pro správu revizí (distributed revision control system). Git je možné používat z příkazové řádky, k dispozici jsou však taktéž nástroje s grafickým uživatelským rozhraním, popř. je Git součástí i několika integrovaných vývojových prostředí. V některých případech je však nutné s Gitem, resp. přesněji řečeno s gitovskými repositáři, pracovat přímo z vyvíjené aplikace (v mém konkrétním případě se jedná o systém zajišťující publikaci dosti rozsáhlých strukturovaných dokumentů na zákaznickém portálu). V případě využití programovacího jazyka Clojure je pro tento účel nejvhodnější použít knihovnu nazvanou clj-jgit. Jak již název této knihovny naznačuje, jedná se o funkcionálně pojaté rozhraní k javovské knihovně JGit (http://www.jgit.org/). V následujících kapitolách si ukážeme naprosté základy práce s touto knihovnou, složitější příklady budou uvedeny příště.
2. Instalace knihovny clj-jgit
Instalace knihovny clj-jgit je velmi jednoduchá, protože můžeme použít systém Leiningen popsaný v úvodních částech tohoto seriálu (viz desátou kapitolu s odkazy). Postačuje pouze vytvořit nový projekt příkazem:
lein new app dummyproject
Dále je nutné upravit projektový soubor project.clj takovým způsobem, aby se v něm nacházelo jméno a verze knihovny clj-jgit:
(defproject dummyproject "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.6.0"] [clj-jgit "0.8.0"]] :main ^:skip-aot dummyproject.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Posledním krokem je spuštění příkazu:
lein deps
Systém Leiningen by měl zajistit stažení knihovny clj-jgit i všech závislých knihoven:
Retrieving clj-jgit/clj-jgit/0.8.0/clj-jgit-0.8.0.pom from clojars Retrieving org/eclipse/jgit/org.eclipse.jgit.java7/3.5.0.201409260305-r/org.eclipse.jgit.java7-3.5.0.201409260305-r.pom from central Retrieving org/eclipse/jgit/org.eclipse.jgit-parent/3.5.0.201409260305-r/org.eclipse.jgit-parent-3.5.0.201409260305-r.pom from central Retrieving org/eclipse/jgit/org.eclipse.jgit/3.5.0.201409260305-r/org.eclipse.jgit-3.5.0.201409260305-r.pom from central Retrieving com/jcraft/jsch/0.1.50/jsch-0.1.50.pom from central Retrieving org/sonatype/oss/oss-parent/6/oss-parent-6.pom from central Retrieving com/googlecode/javaewah/JavaEWAH/0.7.9/JavaEWAH-0.7.9.pom from central Retrieving org/apache/httpcomponents/httpclient/4.1.3/httpclient-4.1.3.pom from central Retrieving org/apache/httpcomponents/httpcomponents-client/4.1.3/httpcomponents-client-4.1.3.pom from central Retrieving org/apache/httpcomponents/project/5/project-5.pom from central Retrieving org/apache/httpcomponents/httpcore/4.1.4/httpcore-4.1.4.pom from central Retrieving org/apache/httpcomponents/httpcomponents-core/4.1.4/httpcomponents-core-4.1.4.pom from central Retrieving commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.pom from central Retrieving org/apache/commons/commons-parent/5/commons-parent-5.pom from central Retrieving org/apache/apache/4/apache-4.pom from central Retrieving commons-codec/commons-codec/1.4/commons-codec-1.4.pom from central Retrieving org/apache/commons/commons-parent/11/commons-parent-11.pom from central Retrieving org/clojure/core.memoize/0.5.3/core.memoize-0.5.3.pom from central Retrieving org/clojure/pom.contrib/0.0.26/pom.contrib-0.0.26.pom from central Retrieving org/clojure/core.cache/0.6.3/core.cache-0.6.3.pom from central Retrieving org/clojure/data.priority-map/0.0.2/data.priority-map-0.0.2.pom from central Retrieving org/clojure/pom.contrib/0.0.25/pom.contrib-0.0.25.pom from central Retrieving org/clojure/clojure/1.3.0/clojure-1.3.0.pom from central Retrieving fs/fs/1.3.2/fs-1.3.2.pom from clojars Retrieving org/apache/commons/commons-compress/1.3/commons-compress-1.3.pom from central Retrieving org/apache/commons/commons-parent/22/commons-parent-22.pom from central Retrieving org/apache/apache/9/apache-9.pom from central Retrieving com/jcraft/jsch/0.1.50/jsch-0.1.50.jar from central Retrieving org/eclipse/jgit/org.eclipse.jgit.java7/3.5.0.201409260305-r/org.eclipse.jgit.java7-3.5.0.201409260305-r.jar from central Retrieving com/googlecode/javaewah/JavaEWAH/0.7.9/JavaEWAH-0.7.9.jar from central Retrieving org/eclipse/jgit/org.eclipse.jgit/3.5.0.201409260305-r/org.eclipse.jgit-3.5.0.201409260305-r.jar from central Retrieving org/apache/httpcomponents/httpcore/4.1.4/httpcore-4.1.4.jar from central Retrieving org/apache/httpcomponents/httpclient/4.1.3/httpclient-4.1.3.jar from central Retrieving commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar from central Retrieving org/clojure/core.memoize/0.5.3/core.memoize-0.5.3.jar from central Retrieving org/clojure/core.cache/0.6.3/core.cache-0.6.3.jar from central Retrieving commons-codec/commons-codec/1.4/commons-codec-1.4.jar from central Retrieving org/clojure/data.priority-map/0.0.2/data.priority-map-0.0.2.jar from central Retrieving org/apache/commons/commons-compress/1.3/commons-compress-1.3.jar from central Retrieving clj-jgit/clj-jgit/0.8.0/clj-jgit-0.8.0.jar from clojars Retrieving fs/fs/1.3.2/fs-1.3.2.jar from clojars
3. První demonstrační příklad – naklonování Git repositáře a výpis seznamu větví
V dnešním prvním demonstračním příkladu s názvem git-test1 jsou ukázány základy práce s knihovnou clj-jgit. Nejprve je vytvořena kostra příkladu, a to s využitím nám již známého příkazu:
lein new app git-test1
Po spuštění výše uvedeného příkazu by se měla vytvořit následující adresářová struktura:
├── doc │ └── intro.md ├── LICENSE ├── project.clj ├── README.md ├── resources ├── src │ └── git_test1 │ └── core.clj └── test └── git_test1 └── core_test.clj
Dále je nutné provést úpravu projektového souboru project.clj, a to tak, že se do sekce :dependencies přidá knihovna clj-jgit ve verzi 0.8.0. Navíc se v tomto demonstračním příkladu používá další miniknihovna se jménem clj-rm-rf. Název této knihovny napovídá, jakou funkci zde nalezneme – jedná se o funkci použitou pro smazání vybraného adresáře:
(defproject git-test1 "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.6.0"] [clj-jgit "0.8.0"] [clj-rm-rf "1.0.0-SNAPSHOT"]] :main ^:skip-aot git-test1.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Samotný zdrojový kód demonstračního příkladu, tj. konkrétně zdrojový soubor src/git_test1/core.clj, je poměrně jednoduchý. Nejprve musíme načíst modul clj-jgit.porcelain a taktéž hozumi.rm-rf, což zajistí dvojice řádků:
(require '[clj-jgit.porcelain :as jgit]) (require '[hozumi.rm-rf :as rm-rf])
Následuje deklarace dvojice konstant, kde první konstanta obsahuje adresu Git repositáře, který se bude klonovat. Druhá konstanta pak obsahuje jméno adresáře, do něhož se Git repositář naklonuje (tento adresář se na konci demonstračního příkladu smaže):
(def repository-url "Adresa Git repositare vcetne specifikace protokolu." "https://github.com/tisnik/testrepo.git") (def directory-name "Jmeno adresare, do ktereho se Git repositar naklonuje." "repo")
Následuje trojice pomocných funkcí. První funkce naklonuje Git repositář do specifikovaného adresáře s využitím volání clj-jgit.porcelain/git-clone, druhá funkce (volaná na konci příkladu) smaže adresář s naklonovaným repositářem s využitím hozumi.rm-rf/rm-r a konečně třetí funkce načte seznam všech vzdálených větví, na což je použita funkce clj-jgit.porcelain/git-branch-list. Vrácená sekvence obsahuje objekty, nikoli přímo jména větví, takže je nutné použít metodu getName (volanou v programové smyčce):
(defn clone-repository "Naklonovani Git repositare do specifikovaneho adresare." [url directory] (jgit/git-clone url directory)) (defn delete-directory "Smazani adresare vcetne podadresaru a souboru." [directory] (rm-rf/rm-r (java.io.File. directory))) (defn list-branches "Vypis vsech vzdalenych vetvi." [repository] (println "Remote branch list:") (doseq [branch (jgit/git-branch-list repository :remote)] (println (.getName branch))))
Další část demonstračního příkladu je již jednoduchá, protože následující funkce clone-and-list-branches naklonuje Git repositář, zobrazí stav repositáře (ten v tomto případě musí být čistý) a následně vypíše všechny vzdálené větve:
(defn clone-and-list-branches "Funkce naklonuje repositar a vypise vsechny vzdalene vetve." [repository-url directory-name] (let [repository (clone-repository repository-url directory-name)] ; navic jeste zjistime stav repositare (println "Repository status: " (jgit/git-status repository)) (list-branches repository)))
Za povšimnutí stojí použití formy try-finally zajišťující, že pracovní adresář se vždy smaže, nezávisle na tom, zda při klonování či při dalších manipulacích s repositářem dojde k vyhození výjimky:
(defn git-test-1 "Naklonovani repositare a vypis vzdalenych vetvi." [repository-url directory-name] (try (clone-and-list-branches repository-url directory-name) (finally ; vymazani adresare s naklonovanym repositarem (delete-directory directory-name))))
Podívejme se nyní na úplný výpis zdrojového kódu:
(ns git-test1.core (:gen-class)) (require '[clj-jgit.porcelain :as jgit]) (require '[hozumi.rm-rf :as rm-rf]) (def repository-url "Adresa Git repositare vcetne specifikace protokolu." "https://github.com/tisnik/testrepo.git") (def directory-name "Jmeno adresare, do ktereho se Git repositar naklonuje." "repo") (defn clone-repository "Naklonovani Git repositare do specifikovaneho adresare." [url directory] (jgit/git-clone url directory)) (defn delete-directory "Smazani adresare vcetne podadresaru a souboru." [directory] (rm-rf/rm-r (java.io.File. directory))) (defn list-branches "Vypis vsech vzdalenych vetvi." [repository] (println "Remote branch list:") (doseq [branch (jgit/git-branch-list repository :remote)] (println (.getName branch)))) (defn clone-and-list-branches "Funkce naklonuje repositar a vypise vsechny vzdalene vetve." [repository-url directory-name] (let [repository (clone-repository repository-url directory-name)] ; navic jeste zjistime stav repositare (println "Repository status: " (jgit/git-status repository)) (list-branches repository))) (defn git-test-1 "Naklonovani repositare a vypis vzdalenych vetvi." [repository-url directory-name] (try (clone-and-list-branches repository-url directory-name) (finally ; vymazani adresare s naklonovanym repositarem (delete-directory directory-name)))) (defn -main "Funkce zavolana po zadani prikazu 'lein run'." [& args] (git-test-1 repository-url directory-name))
Po spuštění příkladu by se na standardní výstup měly vypsat tyto řádky:
Repository status: {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{}, :added #{}} Remote branch list: refs/remotes/origin/branch-1 refs/remotes/origin/branch-2 refs/remotes/origin/master
4. Druhý demonstrační příklad – použití funkce load-repo pro načtení informací o Git repositáři z lokálního adresáře
V dnešním druhém demonstračním příkladu si ukážeme použití funkce nazvané load-repo pro načtení informací o Git repositáři, který již byl naklonován dříve (nebo se může jednat o lokální repositář). Opět si nejprve vytvoříme kostru projektu:
lein new app git-test2
Úprava projektového souboru project.clj je naprosto stejná, jako tomu bylo v prvním demonstračním příkladu:
(defproject git-test2 "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.6.0"] [clj-jgit "0.8.0"] [clj-rm-rf "1.0.0-SNAPSHOT"]] :main ^:skip-aot git-test2.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
I ve druhém demonstračním příkladu dojde k naklonování repositáře a následně k výpisu informace o jeho stavu i seznamu vzdálených větví. Zatímco však v prvním příkladu jsme si pamatovali hodnotu vrácenou funkcí clj-jgit.porcelain/git-clone, ve druhém příkladu tuto hodnotu „zapomeneme“ (nikam se neuloží). Namísto toho je použita funkce clj-jgit.porcelain/load-repo, které se předá adresář, v němž je klon repositáře. Tuto funkci tedy použijeme vždy ve chvíli, kdy existuje jeho lokální kopie, nezávisle na tom, v jakém je tato kopie stavu:
(defn git-test-2 "Naklonovani repositare, nacteni informaci z vytvoreneho adresare a vypis vzdalenych vetvi." [repository-url directory-name] ; naklonovani repositare do specifikovaneho adresare (clone-repository repository-url directory-name) ; nacteni informaci o repositari z lokalniho adresare (try (-> (jgit/load-repo directory-name) list-branches) (finally ; vymazani adresare s naklonovanym repositarem (delete-directory directory-name))))
Úplný zdrojový kód souboru src/git_test2/core.clj:
(ns git-test2.core (:gen-class)) (require '[clj-jgit.porcelain :as jgit]) (require '[hozumi.rm-rf :as rm-rf]) (def repository-url "Adresa Git repositare vcetne specifikace protokolu." "https://github.com/tisnik/testrepo.git") (def directory-name "Jmeno adresare, do ktereho se Git repositar naklonuje." "repo") (defn clone-repository "Naklonovani Git repositare do specifikovaneho adresare." [url directory] (jgit/git-clone url directory)) (defn delete-directory "Smazani adresare vcetne podadresaru a souboru." [directory] (rm-rf/rm-r (java.io.File. directory))) (defn list-branches "Vypis vsech vzdalenych vetvi." [repository] (println "Remote branch list:") (doseq [branch (jgit/git-branch-list repository :remote)] (println (.getName branch)))) (defn git-test-2 "Naklonovani repositare, nacteni informaci z vytvoreneho adresare a vypis vzdalenych vetvi." [repository-url directory-name] ; naklonovani repositare do specifikovaneho adresare (clone-repository repository-url directory-name) ; nacteni informaci o repositari z lokalniho adresare (try (-> (jgit/load-repo directory-name) list-branches) (finally ; vymazani adresare s naklonovanym repositarem (delete-directory directory-name)))) (defn -main "Funkce zavolana po zadani prikazu 'lein run'." [& args] (git-test-2 repository-url directory-name))
Po spuštění příkladu by se na standardní výstup měly vypsat tyto řádky:
Repository status: {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{}, :added #{}} Remote branch list: refs/remotes/origin/branch-1 refs/remotes/origin/branch-2 refs/remotes/origin/master
5. Třetí demonstrační příklad – využití makra with-repo
Třetí demonstrační příklad, který si dnes ukážeme, vysvětluje použití makra with-repo. S makry začínajícími prefixem with- se můžeme v knihovnách programovacího jazyka Clojure setkat poměrně často, protože se používají ve chvíli, kdy je zapotřebí pracovat s nějakým zdrojem (soubor, síťové připojení, standardní výstup přesměrovaný do řetězce), jenž se musí po dokončení práce nějakým způsobem „uzavřít“ či „finalizovat“. Všechny funkce volané uvnitř těchto maker mohou pracovat se specifikovaným zdrojem a nemusí se starat o jeho uvolnění. Makro with-repo není žádnou výjimkou – používá se ve chvíli, kdy se načte informace o repositáři a uloží se do implicitně nazvané lokální proměnné repo. Práce s touto proměnnou je ve skutečnosti velmi snadná, o čemž se lze snadno přesvědčit:
(defn git-test-3 "Naklonovani repositare, nacteni informaci z vytvoreneho adresare a vypis vzdalenych vetvi." [repository-url directory-name] ; naklonovani repositare do specifikovaneho adresare (clone-repository repository-url directory-name) ; nacteni informaci o repositari z lokalniho adresare ; povsimnete si pouziti "automagicky" vytvorene promenne, ; ktera se jmenuje 'repo' (try (jgit/with-repo directory-name (list-branches repo) ; libovolné množství funkcí používajících proměnnou repo ) (finally ; vymazani adresare s naklonovanym repositarem (delete-directory directory-name))))
Opět si nejprve vytvoříme kostru projektu:
lein new app git-test3
Úprava projektového souboru project.clj je naprosto stejná, jako tomu bylo v prvním i ve druhém demonstračním příkladu:
(defproject git-test3 "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.6.0"] [clj-jgit "0.8.0"] [clj-rm-rf "1.0.0-SNAPSHOT"]] :main ^:skip-aot git-test3.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Zdrojový kód souboru src/git_test3/core.clj:
(ns git-test3.core (:gen-class)) (require '[clj-jgit.porcelain :as jgit]) (require '[hozumi.rm-rf :as rm-rf]) (def repository-url "Adresa Git repositare vcetne specifikace protokolu." "https://github.com/tisnik/testrepo.git") (def directory-name "Jmeno adresare, do ktereho se Git repositar naklonuje." "repo") (defn clone-repository "Naklonovani Git repositare do specifikovaneho adresare." [url directory] (jgit/git-clone url directory)) (defn delete-directory "Smazani adresare vcetne podadresaru a souboru." [directory] (rm-rf/rm-r (java.io.File. directory))) (defn list-branches "Vypis vsech vzdalenych vetvi." [repository] (println "Remote branch list:") (doseq [branch (jgit/git-branch-list repository :remote)] (println (.getName branch)))) (defn git-test-3 "Naklonovani repositare, nacteni informaci z vytvoreneho adresare a vypis vzdalenych vetvi." [repository-url directory-name] ; naklonovani repositare do specifikovaneho adresare (clone-repository repository-url directory-name) ; nacteni informaci o repositari z lokalniho adresare ; povsimnete si pouziti "automagicky" vytvorene promenne, ; ktera se jmenuje 'repo' (try (jgit/with-repo directory-name (list-branches repo)) (finally ; vymazani adresare s naklonovanym repositarem (delete-directory directory-name)))) (defn -main "Funkce zavolana po zadani prikazu 'lein run'." [& args] (git-test-3 repository-url directory-name))
Po spuštění příkladu by se na standardní výstup měly opět vypsat stejné řádky:
Repository status: {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{}, :added #{}} Remote branch list: refs/remotes/origin/branch-1 refs/remotes/origin/branch-2 refs/remotes/origin/master
6. Čtvrtý demonstrační příklad – výpis logu ve zjednodušené podobě
Dnešní čtvrtý demonstrační příklad se již odlišuje od předchozích třech příkladů, protože se v něm bude pracovat s logy (resp. zjednodušeně řečeno se zprávami o jednotlivých commitech). Vytvoření kostry příkladu je snadné:
lein new app git-test4
Úprava projektového souboru project.clj je stále stejná:
(defproject git-test4 "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.6.0"] [clj-jgit "0.8.0"] [clj-rm-rf "1.0.0-SNAPSHOT"]] :main ^:skip-aot git-test4.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Základní kostra tohoto příkladu je prakticky shodná s příkladem předchozím, ovšem volá se odlišná funkce nazvaná print-simple-log, která je zde zvýrazněna tučným písmem:
(defn git-test-4 "Naklonovani repositare, nacteni informaci z vytvoreneho adresare a vypis logu." [repository-url directory-name] ; naklonovani repositare do specifikovaneho adresare (clone-repository repository-url directory-name) ; nacteni informaci o repositari z lokalniho adresare ; povsimnete si pouziti "automagicky" vytvorene promenne, ; ktera se jmenuje 'repo' (try (jgit/with-repo directory-name (print-simple-log repo)) (finally ; vymazani adresare s naklonovanym repositarem (delete-directory directory-name))))
Ve funkci print-simple-log je volání clj-jgit.porcelain/git-log vracející informace z logu. Pro převod na čitelné informace o commitech je nutné (uvnitř smyčky) zavolat funkci clj-jgit.querying/commit-info vracející pro každý log speciální javovský objekt typu RevCommit a další informace uložené do mapy:
(defn print-simple-log "Vypis logu ve zjednodusenem formatu." [repository] (doseq [log-entry (jgit/git-log repository)] (println (jgit-query/commit-info repository log-entry))))
Po spuštění příkladu by se na standardní výstup měly vypsat tyto (poměrně nečitelné) řádky:
{:email ptisnovs@redhat.com, :raw #<RevCommit commit 394ce42cb3bcf44ff4e9a94949814bacddcdfe9b 1434726521 ----sp>, :time #inst "2015-06-19T15:08:41.000-00:00", :branches (refs/heads/master), :changed_files ([garbage :add]), :merge false, :author Pavel Tisnovsky, :id 394ce42cb3bcf44ff4e9a94949814bacddcdfe9b, :repo #<Git Git[Repository[repo/.git]]>, :message Added garbage} {:email ptisnovs@redhat.com, :raw #<RevCommit commit 0fd398ab16e53ea0b783aef2413d75b75c6462cd 1434723899 ----sp>, :time #inst "2015-06-19T14:24:59.000-00:00", :branches (refs/heads/master), :changed_files ([README.md :edit]), :merge false, :author Pavel Tisnovsky, :id 0fd398ab16e53ea0b783aef2413d75b75c6462cd, :repo #<Git Git[Repository[repo/.git]]>, :message Updated README.md} {:email ptisnovs@redhat.com, :raw #<RevCommit commit badf2b12f9281a8581009bfa068a5147c4cbc87a 1434722046 ----sp>, :time #inst "2015-06-19T13:54:06.000-00:00", :branches (refs/heads/master), :changed_files [[README.md :add]], :merge false, :author Pavel Tišnovský, :id badf2b12f9281a8581009bfa068a5147c4cbc87a, :repo #<Git Git[Repository[repo/.git]]>, :message Initial commit}
Zdrojový kód souboru src/git_test4/core.clj:
(ns git-test4.core (:gen-class)) (require '[clj-jgit.porcelain :as jgit]) (require '[clj-jgit.querying :as jgit-query]) (require '[hozumi.rm-rf :as rm-rf]) (def repository-url "Adresa Git repositare vcetne specifikace protokolu." "https://github.com/tisnik/testrepo.git") (def directory-name "Jmeno adresare, do ktereho se Git repositar naklonuje." "repo") (defn clone-repository "Naklonovani Git repositare do specifikovaneho adresare." [url directory] (jgit/git-clone url directory)) (defn delete-directory "Smazani adresare vcetne podadresaru a souboru." [directory] (rm-rf/rm-r (java.io.File. directory))) (defn print-simple-log "Vypis logu ve zjednodusenem formatu." [repository] (doseq [log-entry (jgit/git-log repository)] (println (jgit-query/commit-info repository log-entry)))) (defn git-test-4 "Naklonovani repositare, nacteni informaci z vytvoreneho adresare a vypis logu." [repository-url directory-name] ; naklonovani repositare do specifikovaneho adresare (clone-repository repository-url directory-name) ; nacteni informaci o repositari z lokalniho adresare ; povsimnete si pouziti "automagicky" vytvorene promenne, ; ktera se jmenuje 'repo' (try (jgit/with-repo directory-name (print-simple-log repo)) (finally ; vymazani adresare s naklonovanym repositarem (delete-directory directory-name)))) (defn -main "Funkce zavolana po zadani prikazu 'lein run'." [& args] (git-test-4 repository-url directory-name))
7. Pátý demonstrační příklad – výpis vybraných informací z logu
Informace z logu, které byly vypsány v rámci předchozího příkladu byly poměrně nečitelné, ovšem ve skutečnosti je relativně snadné z vrácené sekvence objektů získat pouze potřebné informace. Jak se to dělá, si ukážeme v předposledním demonstračním příkladu. Vytvoření kostry příkladu je stále stejné:
lein new app git-test5
Úprava projektového souboru project.clj taktéž nepřináší žádné nové změny:
(defproject git-test5 "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.6.0"] [clj-jgit "0.8.0"] [clj-rm-rf "1.0.0-SNAPSHOT"]] :main ^:skip-aot git-test5.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Funkce print-simple-log z předchozího příkladu pouze bez dalších úprav převáděla obsah (atributy) datových struktur vracených funkcí commit-info na řetězec, který byl ihned poté vypsán na standardní výstup:
(defn print-simple-log "Vypis logu ve zjednodusenem formatu." [repository] (doseq [log-entry (jgit/git-log repository)] (println (jgit-query/commit-info repository log-entry))))
Pro vylepšení vypisovaných výsledků o commitech však můžeme výsledek funkce commit-info uložit do lokální proměnné a následně získat a vypsat pouze vybrané atributy. Vzhledem k tomu, že je vrácena mapa, je získání atributů snadné, a to buď funkcí get nebo ještě jednodušeji zápisem (:klíč mapa):
(defn print-customized-log "Vypis logovacich informaci ve zvolenem formatu." [repository] (doseq [log-entry (jgit/git-log repository)] (let [info (jgit-query/commit-info repository log-entry)] (println (:author info) ":" (:message info)))))
Informace vypsané funkcí print-customized-log jsou již bez problémů čitelné:
Pavel Tisnovsky : Added garbage Pavel Tisnovsky : Updated README.md Pavel Tišnovský : Initial commit
Podívejme se nyní na úplný zdrojový kód souboru src/git_test5/core.clj:
(ns git-test5.core (:gen-class)) (require '[clj-jgit.porcelain :as jgit]) (require '[clj-jgit.querying :as jgit-query]) (require '[hozumi.rm-rf :as rm-rf]) (def repository-url "Adresa Git repositare vcetne specifikace protokolu." "https://github.com/tisnik/testrepo.git") (def directory-name "Jmeno adresare, do ktereho se Git repositar naklonuje." "repo") (defn clone-repository "Naklonovani Git repositare do specifikovaneho adresare." [url directory] (jgit/git-clone url directory)) (defn delete-directory "Smazani adresare vcetne podadresaru a souboru." [directory] (rm-rf/rm-r (java.io.File. directory))) (defn print-customized-log "Vypis logovacich informaci ve zvolenem formatu." [repository] (doseq [log-entry (jgit/git-log repository)] (let [info (jgit-query/commit-info repository log-entry)] (println (:author info) ":" (:message info))))) (defn git-test-5 "Naklonovani repositare, nacteni informaci z vytvoreneho adresare a vypis podrobnejsiho logu." [repository-url directory-name] ; naklonovani repositare do specifikovaneho adresare (clone-repository repository-url directory-name) ; nacteni informaci o repositari z lokalniho adresare ; povsimnete si pouziti "automagicky" vytvorene promenne, ; ktera se jmenuje 'repo' (try (jgit/with-repo directory-name (print-customized-log repo)) (finally ; vymazani adresare s naklonovanym repositarem (delete-directory directory-name)))) (defn -main "Funkce zavolana po zadani prikazu 'lein run'." [& args] (git-test-5 repository-url directory-name))
8. Šestý demonstrační příklad – přidání a modifikace souborů v GIT repositáři, provedení commitu
Dnešní šestý a současně i poslední demonstrační příklad nazvaný git-test6 bude již zajímavější, než příklady předchozí. Ukážeme si totiž přidávání a modifikaci souborů v repositáři, provádění commitů a taktéž vliv těchto operací na stav repositáře. Opět si tedy vytvořme kostru příkladu:
lein new app git-test6
Úprava projektového souboru project.clj je stále stejná a spočívá v přidání dvou nových knihoven:
(defproject git-test6 "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.6.0"] [clj-jgit "0.8.0"] [clj-rm-rf "1.0.0-SNAPSHOT"]] :main ^:skip-aot git-test6.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
V hlavní části programu se používají tyto funkce a makra:
Funkce či makro | Význam |
---|---|
clj-jgit.porcelain/git-clone | naklonování repositáře (již známe) |
clj-jgit.porcelain/with-repo | blok, v němž se pracuje se specifikovaným repositářem |
clj-jgit.porcelain/git-add | přidání souboru či změny do stage area |
clj-jgit.porcelain/git-commit | provedení commitu (ze stage area do lokálního repa) |
clj-jgit.porcelain/git-status | získání stavu repositáře |
Stav repositáře má podobu mapy se šesticí prvků s klíči :untracked, :removed, :modified, :missing, :changed a :added. Hodnotami prvků jsou množiny (set) souborů.
Hlavní část demonstračního programu, kde se provádí změny v repositáři:
(defn git-test-6 "Naklonovani repositare a pridani noveho souboru." [repository-url directory-name] ; naklonovani repositare do specifikovaneho adresare (clone-repository repository-url directory-name) ; budeme pracova s repositarem, ktery je v nasledujicim bloku ; predstavovan symbolem 'repo' (jgit/with-repo directory-name ; stav repa na zacatku (println "Repository status: " (jgit/git-status repo)) ; vytvoreni noveho souboru (spit (str directory-name "/answer.txt") "*42*") ; modifikace stavajiciho souboru (spit (str directory-name "/README.md") "new text") ; novy stav repa (println "Repository status: " (jgit/git-status repo)) ; pridani zmen do stage area (jgit/git-add repo "answer.txt") (jgit/git-add repo "README.md") ; novy stav repa (println "Repository status: " (jgit/git-status repo)) ; provedeme commit vsech zmen (jgit/git-commit repo "The Answer to the Ultimate Question of Life, the Universe, and Everything") ; konecny stav repa (println "Repository status: " (jgit/git-status repo)) ) (delete-directory directory-name))
Po spuštění by se měla na standardní výstup vypsat pětice stavů repositáře:
Repository status: {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{}, :added #{}} Repository status: {:untracked #{answer.txt}, :removed #{}, :modified #{README.md}, :missing #{}, :changed #{}, :added #{}} Repository status: {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{README.md}, :added #{answer.txt}} Repository status: {:untracked #{}, :removed #{}, :modified #{}, :missing #{}, :changed #{}, :added #{}}
Význam jednotlivých řádků:
- Na začátku (ihned po naklonování) je repositář ve stavu clean, což je logické
- Po vytvoření souboru answer.txt (ten v repu neexistoval) je tento soubor ve stavu untracked
- Po modifikaci souboru README.md (ten již v repu existoval) je tento soubor ve stavu modified
- (jgit/git-add repo „answer.txt“) zajistí změnu stavu z untracked na added
- (jgit/git-add repo „README.md“) zajistí změnu stavu z modified na changed
- Po (jgit/git-commit repo zpráva) se repositář opět ocitne ve stavu clean
Zdrojový kód souboru src/git_test6/core.clj:
(ns git-test6.core (:gen-class)) (require '[clj-jgit.porcelain :as jgit]) (require '[hozumi.rm-rf :as rm-rf]) (def repository-url "Adresa Git repositare vcetne specifikace protokolu." "https://github.com/tisnik/testrepo.git") (def directory-name "Jmeno adresare, do ktereho se Git repositar naklonuje." "repo") (defn delete-directory "Smazani adresare vcetne podadresaru a souboru." [directory] (rm-rf/rm-r (java.io.File. directory))) (defn clone-repository "Naklonovani Git repositare do specifikovaneho adresare." [url directory] (jgit/git-clone url directory)) (defn git-test-6 "Naklonovani repositare a pridani noveho souboru." [repository-url directory-name] ; naklonovani repositare do specifikovaneho adresare (clone-repository repository-url directory-name) ; budeme pracova s repositarem, ktery je v nasledujicim bloku ; predstavovan symbolem 'repo' (jgit/with-repo directory-name ; stav repa na zacatku (println "Repository status: " (jgit/git-status repo)) ; vytvoreni noveho souboru (spit (str directory-name "/answer.txt") "*42*") ; modifikace stavajiciho souboru (spit (str directory-name "/README.md") "new text") ; novy stav repa (println "Repository status: " (jgit/git-status repo)) ; pridani zmen do stage area (jgit/git-add repo "answer.txt") (jgit/git-add repo "README.md") ; novy stav repa (println "Repository status: " (jgit/git-status repo)) ; provedeme commit vsech zmen (jgit/git-commit repo "The Answer to the Ultimate Question of Life, the Universe, and Everything") ; konecny stav repa (println "Repository status: " (jgit/git-status repo)) ) (delete-directory directory-name)) (defn -main "Funkce zavolana po zadani prikazu 'lein run'." [& args] (git-test-6 repository-url directory-name))
9. Repositář s demonstračními příklady
Všech šest dnes popsaných demonstračních příkladů bylo, podobně jako v předchozích částech tohoto seriálu, uloženo do Git repositáře dostupného na adrese https://github.com/tisnik/clojure-examples. V tabulce zobrazené pod tímto odstavcem naleznete na zdrojové kódy jednotlivých příkladů přímé odkazy:
Naklonování celého repositáře zajistí příkaz:
git clone http://github.com/tisnik/clojure-examples.git
Cloning into 'clojure-examples'... remote: Counting objects: 638, done. remote: Compressing objects: 100% (48/48), done. Receiving objects: 100% (638/638), 101.89 KiB | 141.00 KiB/s, done. remote: Total 638 (delta 30), reused 0 (delta 0), pack-reused 560 Resolving deltas: 100% (248/248), done. Checking connectivity... done.
10. Odkazy na předchozí části seriálu
Stalo se již zvykem uvést odkazy na všechny předchozí části tohoto seriálu. Tento zvyk samozřejmě dodržíme i dnes:
- Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - Pluginy pro Leiningen
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (2)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/
11. Odkazy na Internetu
- Seriál o Gitu: 1. díl – Git – Historie a principy
http://www.itnetwork.cz/git-tutorial-historie-a-principy - 2. díl – Git – Instalace a vytvoření repositáře
http://www.itnetwork.cz/git-tutorial-instalace-a-stazeni-repositare - 3. díl – Git – Základy
http://www.itnetwork.cz/git-tutorial-zaklady - 4. díl – Git – Zkoumání historie
http://www.itnetwork.cz/git-tutorial-historie - 5. díl – Git – Rozděluj a panuj
http://www.itnetwork.cz/git-tutorial-vetve - 6. díl – Git – práce se vzdáleným repositářem
http://www.itnetwork.cz/git-prace-se-vzdalenym-repositarem - Building User Interfaces with Seesaw (slajdy k přednášce)
http://darevay.com/talks/clojurewest2012/#/title-slide - Seesaw na GitHubu
https://github.com/daveray/seesaw - Seesaw API Documentation
http://daveray.github.io/seesaw/ - Seesaw wiki
https://github.com/daveray/seesaw/wiki - seesaw-repl-tutorial.clj
https://gist.github.com/daveray/1441520 - Témata o Seesaw na Google groups
https://groups.google.com/forum/#!forum/seesaw-clj - Threading macro (dokumentace k jazyku Clojure)
https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/-> - Understanding the Clojure → macro
http://blog.fogus.me/2009/09/04/understanding-the-clojure-macro/ - Clisk
https://github.com/mikera/clisk - clojars: net.mikera/clisk
https://clojars.org/net.mikera/clisk - clojure.inspector
http://clojure.github.io/clojure/clojure.inspector-api.html - Clisk: wiki
https://github.com/mikera/clisk/wiki - Dokumentace vygenerovaná pro knihovnu core.matrix
https://cloojure.github.io/doc/core.matrix/index.html - Size and Dimensionality
https://groups.google.com/forum/#!topic/numerical-clojure/zebBCa68eTw/discussion - Towards core.matrix for Clojure?
https://clojurefun.wordpress.com/2013/01/05/towards-core-matrix-for-clojure/ - The Clojure Toolbox
http://www.clojure-toolbox.com/ - Neanderthal
http://neanderthal.uncomplicate.org/ - Hello world project
https://github.com/uncomplicate/neanderthal/blob/master/examples/hello-world/project.clj - vectorz-clj
https://github.com/mikera/vectorz-clj - vectorz – Examples
https://github.com/mikera/vectorz-clj/wiki/Examples - gloss
https://github.com/ztellman/gloss - HTTP client/server for Clojure
http://www.http-kit.org/ - Array Programming
https://en.wikipedia.org/wiki/Array_programming - Discovering Array Languages
http://archive.vector.org.uk/art10008110 - no stinking loops – Kalothi
http://www.nsl.com/ - Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
http://www.vector.org.uk/ - APL Interpreters
http://www.vector.org.uk/?area=interpreters - APL_(programming_language
http://en.wikipedia.org/wiki/APL_(programming_language - APL FAQ
http://www.faqs.org/faqs/apl-faq/ - APL FAQ (nejnovější verze)
http://home.earthlink.net/~swsirlin/apl.faq.html - A+
http://www.aplusdev.org/ - APLX
http://www.microapl.co.uk/ - FreeAPL
http://www.pyr.fi/apl/index.htm - J: a modern, high-level, general-purpose, high-performance programming language
http://www.jsoftware.com/ - K, Kdb: an APL derivative for Solaris, Linux, Windows
http://www.kx.com - openAPL (GPL)
http://sourceforge.net/projects/openapl - Parrot APL (GPL)
http://www.parrotcode.org/ - Learning J (Roger Stokes)
http://www.jsoftware.com/help/learning/contents.htm - Rosetta Code
http://rosettacode.org/wiki/Main_Page - Why APL
http://www.acm.org/sigapl/whyapl.htm - java.jdbc API Reference
https://clojure.github.io/java.jdbc/ - Hiccup
https://github.com/weavejester/hiccup - Clojure Ring na GitHubu
https://github.com/ring-clojure/ring - A brief overview of the Clojure web stack
https://brehaut.net/blog/2011/ring_introduction - Getting Started with Ring
http://www.learningclojure.com/2013/01/getting-started-with-ring.html - Getting Started with Ring and Compojure – Clojure Web Programming
http://www.myclojureadventure.com/2011/03/getting-started-with-ring-and-compojure.html - Unit Testing in Clojure
http://nakkaya.com/2009/11/18/unit-testing-in-clojure/ - Testing in Clojure (Part-1: Unit testing)
http://blog.knoldus.com/2014/03/22/testing-in-clojure-part-1-unit-testing/ - API for clojure.test – Clojure v1.6 (stable)
https://clojure.github.io/clojure/clojure.test-api.html - Leiningen: úvodní stránka
http://leiningen.org/ - Leiningen: Git repository
https://github.com/technomancy/leiningen - leiningen-win-installer
http://leiningen-win-installer.djpowell.net/ - Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - Clojure 3: Funkcionální programování
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/ - Clojure 4: Kolekce, sekvence a lazy sekvence
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/ - Clojure 5: Sekvence, lazy sekvence a paralelní programy
http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - Clojure 8: Identity, stavy, neměnné hodnoty a reference
http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/ - Clojure 9: Validátory, pozorovatelé a kooperace s Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - Clojure 12: Překlad programů z Clojure do bajtkódu JVM I:
http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/ - Clojure 13: Překlad programů z Clojure do bajtkódu JVM II:
http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - Clojure 20: Vývojová prostředí pro Clojure (Vimu s REPL)
http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/