Most, hogy már van egy virtuális szerverünk, kellene kezdeni vele valami mókás dolgot. Lehetne mondjuk egy távolról is vezérelhető build rendszerünk (a "távolról" mondjuk ebben az esetben talán egy kicsit túlzás :)), amit a kedvenc szövegszerkesztőnk automatikusan tudna vezérelni. Az úgy kellőképp mókásan hangzik ahhoz, hogy belevágjunk. :)
Ahhoz, hogy legyen értelme a build rendszernek, nem árt, ha van mit build-elni. Tegyük fel mondjuk a példa kedvéért, hogy CSS helyett szeretnénk Sass-t, JavaScript helyett pedig CoffeeScript-et használni. Természetesen a rendszer képességei nem merülnek ki ennyiben, lehetne mondjuk olyat is csinálni, hogy a sablon fájlokat fordítsa le PHP-ra, vagy a konfigurációs XML-ekből gyártson tömböket, esetleg minden unit tesztet lefuttasson. A lehetőségek száma, ahogy mondani szokás, végtelen, de maradjunk az eredeti kettőnél, a többi a kedves olvasó fantáziájára van bízva. Kezdjük is rögtön a telepítéssel:
Sass
sudo apt-get install ruby rubygems sudo gem install sass
A Sass [Syntactically Awesome Stylesheets] nevezetű előfeldolgozó néhány hasznos kiegészítéssel segít ráncba szedni az elvadult CSS kóddzsungelt.
CoffeeScript
sudo apt-get install nodejs npm sudo npm install coffee-script
A CoffeeScript a funkcionális programozási nyelvekre és talán egy csöppet a Ruby-ra emlékeztető nyelv a JavaScript egy komolyabb újragondolása (a Sass-CSS viszonylathoz képest), de mentségére legyen mondva, hogy egy az egyben valid JavaScript-re fordul.
Építkezzünk
A build-elésben segítségünkre lesz a vicces nevű PHP-s build eszköz, a Phing. A következő módon érhetjük el, hogy feltelepüljön:
sudo apt-get install php-pear sudo pear channel-discover pear.phing.info sudo pear install phing/phing
A példához a következő minimális projekt könyvtárszerkezetet fogjuk használni:
-
assets/
- coffee/
- sass/
-
www/
- css/
- js/
- build.xml
Az assets/
könyvtárban vannak a nyers fájlok, a www/
könytárba mennek a generált fájlok, amiket nem árt kívülről is elérni. A kulcs pedig a build.xml
, ami a Phing számára tartalmaz utasításokat. Kezdetnek valami ilyesmi például megteszi:
<?xml version="1.0" encoding="UTF-8"?> <project name="MyProject" default="assets"> <property name="sass_dir" value="${project.basedir}/assets/sass/" /> <property name="coffee_dir" value="${project.basedir}/assets/coffee/" /> <property name="css_target" value="${project.basedir}/www/css/" /> <property name="js_target" value="${project.basedir}/www/js/" /> <target name="sass"> <exec command="sass --no-cache --update "${sass_dir}:${css_target}"" /> </target> <target name="coffee"> <exec command="coffee -o "${js_target}" "${coffee_dir}"" /> </target> <target name="assets"> <phingcall target="sass" /> <phingcall target="coffee" /> </target> </project>
A projekt könyvtárában (egy szinten a build.xml
-lel) állva ki tudjuk adni a következő három parancsot, amivel a Sass-t, CoffeeScript-et és mindkettőt egyszerre lefordíthatjuk (ha nem adunk meg semmit a phing
után, akkor a default assets
fog lefutni):
phing sass
phing coffee
phing assets
Az alkalmazás
Már csak azt kellene elérni, hogy a fájlok módosítása után a megfelelő parancs automatikusan lefusson. Bár mind a Sass, mind a CoffeeScript rendelkezik megoldással a problémára (--watch
), a későbbiekre is gondolva inkább valami általánosabb megoldásra lenne szükség. Mondjuk egy webes minialkalmazás, ami a kapott paraméterek függvényében meghívja a megfelelő parancsot. A kódszerkesztő alkalmazásunk pedig ezt a paraméterezett URL-t hívogathatná. Mondjuk valami ilyesmit:
http://builder.vbox/index.php?project=projektneve&target=target
Az a bizonyos index.php
pedig valami ilyen kis egyszerű dolog lenne (az egyszerűség ára az, hogy élünk azzal a feltételezéssel, hogy az egyes projektek a /var/www/projektneve.vbox/
könyvtárban vannak és eltekintünk az olyan dolgoktól, mint például a target
valódiságának az ellenőrzése):
$dir = '/var/www/' . get('project') . '.vbox/'; if (!file_exists($dir . 'build.xml')) { exit('invalid_project'); } $target = get('target'); if (!$target) { exit('no_target'); } chdir($dir); shell_exec('phing ' . escapeshellcmd($target)); exit('ok'); function get($name) { if (empty($_GET[$name])) { return ''; } return preg_replace('/[^a-z0-9\-\.]/i', '', $_GET[$name]); }
A plugin
Ezzel meg is van a távolról is vezérelhető egyszerű kis build rendszerünk. A kedvenc szerkesztőnkhöz írhatunk egy plugin-t, ami mentésre meghívja a megfelelő URL-t, hogy legenerálódjanak a CSS/JS fájlok (vagy akár tetszőleges billentyűkombinációra tetszőleges build parancsot meghívhatunk). Sublime Text 2 esetén valahogy így nézne ki a dolog:
import sublime, sublime_plugin import urllib, urllib2 import os, threading class BuilderThread(threading.Thread): def __init__(self, project, target): threading.Thread.__init__(self) self.project = project self.target = target def run(self): try: data = urllib.urlencode({ 'project': self.project, 'target': self.target, }) request = urllib2.Request('http://builder.vbox/index.php?' + data) response = urllib2.urlopen(request).read() return except (urllib2.HTTPError) as (e): err = '%s: HTTP error %s contacting API' % (__name__, str(e.code)) except (urllib2.URLError) as (e): err = '%s: URL error %s contacting API' % (__name__, str(e.reason)) sublime.error_message(err) class BuilderEventListener(sublime_plugin.EventListener): def __init__(self): sublime_plugin.EventListener.__init__(self) def on_post_save(self, view): name, ext = os.path.splitext(view.file_name()) project = view.settings().get('builder_project_name', False) if (False == project): return if (ext == '.coffee'): BuilderThread(project, 'coffee').start() elif (ext == '.scss' or ext == '.sass'): BuilderThread(project, 'sass').start()
A plugin használ egy builder_project_name
nevű beállítást, amit az éppen aktuális projekt .sublime-project
fájljában érdemes megadni:
{ "settings": { "builder_project_name": "test-project" } }
Ezzel meg is volnánk, kellemes építkezést.