Zarządzanie projektami Clojure z leiningen

Z Jacek Laskowski - Wiki Projektanta Java EE

Czara goryczy z ciągłym uaktualnianiem wersji Clojure i biblioteki rozszerzającej Clojure Contrib przelała się i w końcu zebrałem się w sobie (zmusiło mnie), aby poświęcić chwilę na spróbowanie się z leiningen (w skrócie lein od nazwy skryptu uruchomieniowego). Jest to narzędzie do zarządzania projektami, którego konfiguracja jest programem w Clojure. Jest to doskonały sposób, aby w projekcie nie wyjść poza ramy Clojure, jeśli jest on językiem podstawowym (jak często i sama jego znajomość). Innymi słowy jest to odpowiednik Gradle (dla języka Groovy), Apache Maven (tu niestety "walczymy" z XML) czy Apache Ant, Apache Buildr (JRuby) i temu podobne.

Już miałem z nim spotkanie przy tworzeniu aplikacji webowej z Compojure, Ring i Hiccup, ale nie stał się moim podstawowym narzędziem. Jak to bywa, znałem, ale nieużywałem (nie pytaj mnie dlaczego, bo padnie magiczne "Nie wiem". Zdziwiony?).

Jako pracujący na codzień z Javą, gdzie prym wiodą IDE, które wspierają zarządzanie projektami i rozwojem aplikacji, mam nieodparte wrażenie, że dopóty nie będzie wsparcia dla lein w popularnych IDE dla Javy, dopóty nie będzie większego zainteresowania nim. Mam również wrażenie, że jest to jedynie problem osób migrujących z języka Java i głównym powodem tego stanu rzeczy jest...przyzwyczajenie oraz brak chęci poświęcenia większego wysiłku na rzecz bardziej dopasowanego lub bogatszego funkcjonalnie narzędzia (co w przypadku lein nie jest dla mnie takie oczywiste). Obserwuję, że osoby ze świata języków spoza JVM mają ten problem poza nimi i IDE raczej odstraszają swoją ogromnością funkcji niż przyciągają nimi do siebie.

Instalacja Leiningen

Instalacja lein opisana jest na jego stronie domowej, (która jest równocześnie jego repozytorium!) i sprowadza się do wykonania kilku poleceń:

$ wget --no-check-certificate https://github.com/technomancy/leiningen/raw/master/bin/lein
 
$ chmod +x lein
 
$ lein self-install
 
$ lein version
Leiningen 1.6.0-SNAPSHOT on Java 1.6.0_24 Java HotSpot(TM) 64-Bit Server VM

Można również zainstalować wersję stabilną 1.5.2.

Później, każdorazowa aktualizacja będzie wymagała wykonanie polecenia lein upgrade.

$ lein help upgrade
Upgrade Leiningen to the latest stable release.
 
$ lein upgrade
The script at /Users/jacek/apps/bin/lein will be upgraded to the latest stable version.
Do you want to continue [Y/n]? Y
 
Upgrading...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  8270  100  8270    0     0   4349      0  0:00:01  0:00:01 --:--:-- 55133
 
Downloading Leiningen now...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 9161k  100 9161k    0     0   566k      0  0:00:16  0:00:16 --:--:--  620k
 
Now running Leiningen 1.6.1.1 on Java 1.6.0_26 Java HotSpot(TM) 64-Bit Server VM

Na uwagę zasługuje również fakt uzupełnienia konfiguracji lein o instalację rlwrap, który pozwala na pracę w Clojure REPL, podobnie do linuksowej linii poleceń - historia, wyszukiwanie, edycja, itp. Więcej informacji można znaleźć na stronie Enhancing Clojure REPL with rlwrap.

Umieść rlwrap w zmiennej PATH, a lein skorzysta z niego.

$ rlwrap -v
rlwrap 0.37
 
$ type rlwrap
rlwrap is hashed (/opt/local/bin/rlwrap)

lein pozwala nam na utworzenie projektu (lein new), przygotowanie importu do IDE (lein pom), w którym korzysta się ze wsparcia dla projektów mavenowych, czy wykonaniu testów (lein test), uruchomieniu Clojure REPL (lein repl) i instalacji (lein install) oraz zbudowaniu projektu (lein jar). Dostępne polecenia poznasz wykonując polecenie lein help.

$ lein help
Leiningen is a build tool for Clojure.
 
Several tasks are available:
classpath   Print the classpath of the current project.
clean       Remove compiled class files from project.
compile     Compile Clojure source into .class files.
deploy      Build and deploy jar to remote repository.
deps        Download all dependencies and put them in :library-path.
help        Display a list of tasks or help for a given task.
install     Install the current project or download the project specified.
interactive Enter interactive task shell.
jar         Package up all the project's files into a jar file.
javac       Compile Java source files.
new         Create a new project skeleton.
plugin      Manage user-level plugins.
pom         Write a pom.xml file to disk for Maven interop.
repl        Start a repl session either with the current project or standalone.
retest      Run only the test namespaces which failed last time around.
run         Run a -main function with optional command-line arguments.
search      Search remote repository contents.
test        Run the project's tests.
test!       Run a project's tests after cleaning and fetching dependencies.
uberjar     Package up the project files and deps into a jar file.
upgrade     Upgrade Leiningen to the latest stable release.
version     Print version for Leiningen and the current JVM.
 
Run lein help $TASK for details.
Also available: readme, tutorial, copying, sample, and news.

Tym samym mam narzędzie, które zniesie ze mnie konieczność zarządzania zależnościami projektowymi (a dokładniej zależnościami bezpośrednich zależności) i wystarczy zadeklarować wersję Clojure oraz Clojure Contrib, a reszta sprowadzi się do odpowiednich poleceń lein.

Przykładowa sesja z leiningen - utworzenie projektu i import do IDE

Rozpoczynamy projekt z lein przez wykonanie lein new z nazwą projektu, która opcjonalnie przyjmuje nazwę grupy, do której należy.

jacek:~/sandbox
$ lein new pl.jaceklaskowski.clojure/witaj-clojure-gui
Created new project in: /Users/jacek/sandbox/witaj-clojure-gui
 
jacek:~/sandbox
$ cd witaj-clojure-gui/
 
jacek:~/sandbox/witaj-clojure-gui
$ ls -l
total 24
-rw-r--r--  1 jacek  staff   176 May 14 18:05 README
drwxr-xr-x  2 jacek  staff    68 May 14 19:49 classes
drwxr-xr-x  5 jacek  staff   170 May 14 19:49 lib
-rw-r--r--  1 jacek  staff   358 May 14 20:02 project.clj
drwxr-xr-x  3 jacek  staff   102 May 14 18:05 src
drwxr-xr-x  3 jacek  staff   102 May 14 18:05 test

Plikiem konfiguracji lein jest project.clj (który jest de facto aplikacją w Clojure).

Tworzymy konfigurację mavenową (a dokładniej generujemy plik pom.xml), aby IDE ze wsparciem dla tego typu projektów mogło zaimportować projekt i udostępnić środowisko graficzne do dalszej pracy programistycznej.

jacek:~/sandbox/witaj-clojure-gui
$ lein pom
Wrote pom.xml

Import do IDE i podniesienie wersji Clojure z Clojure Contrib to już chleb powszedni dla wielu pracujących z podobnymi narzędziami. Pozostawiam temat jako zadanie domowe (znużonych wieloma pracami domowymi uprasza się o kontakt z autorem).

Warto pamiętać, że każdorazowa zmiana zależności w project.clj wymaga ponownego utworzenia pom.xml (za pomocą lein pom) i odświeżenia projektu w IDE, np. w Eclipse z Counterclockwise wymaga to wciśnięcia klawisza F5.

Przykładowa sesja z Clojure REPL w wersji 1.3

Domyślnie, lein tworzy projekt z Clojure 1.2.1. Podniesienie wersji to aktualizacja project.clj z właściwą wersją Clojure.

(defproject clojure-sandbox "1.0.0-SNAPSHOT"
  :description "FIXME: write description"
  :dependencies [[org.clojure/clojure "1.3.0"]
                 [org.clojure/clojure-contrib "1.3.0"]])

Pamiętaj, aby dodać 1.3.0, a nie 1.3.

Uruchomienie lein repl w tym projekcie będzie już wykonane z Clojure 1.3.

jacek:~/sandbox/clojure-sandbox
$ lein repl
Downloading: org/clojure/clojure/1.3.0/clojure-1.3.0.pom from central
Downloading: org/clojure/clojure/1.3.0/clojure-1.3.0.jar from central
Copying 1 file to /Users/jacek/sandbox/clojure-sandbox/lib
REPL started; server listening on localhost port 16122
user=> (clojure-version)
"1.3.0"

Jeśli odpowiednia wersja Clojure nie będzie dostępna w lokalnym repozytorium, zostanie ściągnięta - dostęp do Sieci będzie w takim wypadku konieczny.

Osobiste