Már egy ideje az íróasztal fiókom mélyén tanyázik egy MCP23017 chip, amivel például a Raspberry Pi GPIO portjait lehet bővíteni, szám szerint 16 darab új csatlakozással. A 16 darab csatlakozás pedig pont elég arra, hogy 16 darab LED segítségével megjelenítsünk egy bináris órát (bár sajnos csak 12 órás megjelenítéssel).

Hardver és összedrótozás

Először is talán ismerkedjünk meg egy kicsit közelebbről az MCP23017-tel. I²C buszon lehet vele kommunikálni, a hardver címét az A0-2 lábak határozzák meg.

A GPA0-7 és GPB0-7 lábakra fogjuk rákötni a ledeket (esetleg a LED-hez kellhet még egy ellenállás is, de én attól eltekintettem), A VSS-re és az A0-2 lábakra megy a föld (ez a 0x20-as hardvercímet fogja eredményezni), a VDD-re és a RESET-re a 3.3V, az SLC és SDA pedig a Raspberry Pi azonos nevű kivezetéseivel lesz összekötve.

Katt a nagyobb változatért.

Bónuszként a kábelrengeteg miatt még úgy is fog tűnni, mintha valami bonyolult dolog lenne. Ezen kívül, ami még érdekel minket, azok az MCP23017 regiszterei és azok címei. Legalábbis egy részük:

0x00 IODIRA A GPA0-7 lábak inputként vagy outputként működjenek
0x01 IODIRB A GPB0-7 lábak inputként vagy outputként működjenek
0x12 GPIOA Ennek a segítségével lehet a GPA0-7 lábakat elérni
0x13 GPIOB Ennek a segítségével lehet a GPB0-7 lábakat elérni

A chip dokumentációjában utána lehet nézni a többinek is, ha valakit esetleg részletesebben is érdekelne.

Konfigurálás

Ennyit a hardverről, végre rátérhetünk a dolog szoftveres részére. Mint azt már fentebb említettem, a chip I²C-t használ, ami alapból nincsen bekapcsolva az RPi-n. Először is a /etc/modules fájlba kell két új sor, mondjuk a végére:

i2c-bcm2708
i2c-dev

Aztán a /etc/modprobe.d/raspi-blacklist.conf fájlban a blacklist i2c-bcm2708 sort kell törölni (vagy kikommentelni). Szükség van ezen kívül még néhány csomagra telepítésére is:

$ sudo apt-get install python-smbus i2c-tools

Ha ez is végzett, akkor már csak egy újraindítás, és el is kezdhetjük használatba venni a szerkezetet.

Életre keltés

Először is szükségünk lesz a chip címére, amit az i2cdetect parancs segítségével tudunk kideríteni. A fenti drótozással elvileg ezt kell kapnunk:

$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Amiből kiderül, hogy 0x20 az eszköz címe (régebbi RPi-n előfordulhat, hogy sudo i2cdetect -y 0 a nyerő parancs), úgyhogy rá is térhetünk a kódra.

import time
import smbus

Az már a konfigurálás során kiderült, hogy a Python smbus modulját fogjuk használni (meg egy kis időt, ha már egyszer órát csinálunk).

i2c = 1
addr = 0x20

Néhány beállítás: az i2c értéke ugyanaz, mint amit az i2cdetect parancsban is használtunk -y paraméterként, az addr értéke pedig az i2cdetect válaszából kinyert hardver cím.

bus = smbus.SMBus(i2c)
bus.write_byte_data(addr, 0x00, 0x00)
bus.write_byte_data(addr, 0x01, 0x00)

Kezdődhet a kommunikáció. A chip 0x00-s és 0x01-es regisztereit is kinullázzuk, ami mindkét nyolcas csatlakozó csoportot output-ra állítja.

try:
  while True:
    now = time.localtime()
    h = now.tm_hour
    if h > 12:
      h = h - 12
    
    x = '{:04b}{:06b}{:06b}'.format(h, now.tm_min, now.tm_sec)
    
    bus.write_byte_data(addr, 0x12, int(x[8:], 2))
    bus.write_byte_data(addr, 0x13, int(x[:8], 2))
    time.sleep(0.01)
except KeyboardInterrupt:
    bus.write_byte_data(addr, 0x12, 0x00)
    bus.write_byte_data(addr, 0x13, 0x00)
    print

Először átvarázsoljuk az aktuális időt egy nekünk megfelelő bináris formátumba, aztán beírjuk az egyes byte-okat a 0x12-es és 0x13-as regiszterekbe. Aztán ez megy tovább a végtelenségig. Vagyis amíg Ctrl+C-t nem nyomunk, akkor kinullázzuk mindkét regisztert, ami az összes ledet lekapcsolja. A végeredmény pedig:

Korábban már volt róla szó, hogy hogyan lehetne közvetlenül Sublime-ból build-eket futtatni a virtuális gépünkön egy plugin és egy webalkalmazás segítségével. Most nézzünk meg egy másik megközelítést, ami a Sublime beépített build rendszer támogatását és a PuTTY parancssoros változatát használja.

Amire szükségünk lesz (Windows-os környezetben):

Linux-os környezetben a Plink helyett az ssh, PuTTYgen helyett pedig az ssh-keygen használható.

Elkészítés

Első lépésként, ha még nincs beállítva publikus kulcs autentikáció a hozzáférésünkhöz a szerveren, akkor indítsuk el a PuTTYgen-t és generáljunk egy kulcsot:

PuTTYgen

A bejegyzés írása során többször próbáltam kattintani, hogy eltűnjön a kijelölés.

Ahogy azt a PuTTYgen okosan írja is, a Generate gomb megnyomása után kijelölt szöveget be kell másolnunk a szerveren a ~/.ssh/authorized_keys fájlba. Aztán passphrase nélkül mentsük el a privát kulcsot, arra még a későbbiekben szükségünk lesz.

Jöhet a Sublime beállítása. Feltételezem, hogy éppen egy projektben vagyunk, ha nem, csináljunk egyet gyorsan. Ez után a Project > Edit Project menüre kattintva a megnyíló config fájlhoz hozzáadjuk a saját build rendszerünket (a nagy valószínűséggel már ott lévő "folders" kulccsal azonos szintre). Majd a Tools > Build Systems menüpontban ki is választjuk, hogy azt használja a Sublime.

"build_systems":
[
    {
        "name": "csudiszuper build rendszer",
        "working_dir": "c:\\path\\to\\plink\\",
        "cmd": [
            "plink",
            "-i", "c:\\path\\to\\private_key.ppk",
            "username@virtual.machine.host",
            "futtatandó parancsok"
        ]
    }
]

A "futtatandó parancsok" rész a fenti configban nagyban függ attól, hogy mit is szeretnénk pontosan build futtatása címszó alatt csinálni, de nagyjából annyiból áll, hogy belépünk a projektünk könyvtárába és meghívjuk a build rendszerünket (Phing, Grunt, Ant, make vagy bármi más, ami szimpatikus).
Ezek után a Ctrl+B billentyűkombinációval el is indíthatjuk a futtatást és láthatjuk a szerkesztőben a kimenetét.

SublimeText

A példa kedvéért a guzzle make test-jét futtattam. Katt a nagyobb változatért.

Ezen a ponton még belefuthatunk néhány hibába. Például, hogy ha még nem csatlakoztunk a szerverhez, akkor el kellene fogadnunk az RSA kulcsát, amit a build rendszeren keresztül nem tudunk megtenni, így érdemes pl. PuTTY-ból megejteni az első kapcsolódást. Egy másik gyakori probléma az lehet, hogy visszautasítja a szerver a kulcsot, aminek például az SSH szerver beállításaihoz (PubkeyAuthentication rész a /etc/ssh/sshd_config fájlban) vagy a home könyvtárunkban lévő .ssh könyvtár és a benne lévő fájlok jogosultságaihoz (minden csak a saját felhasználónk által legyen írható/olvasható) lehet köze.

Én egyébként mostanában hajlok arra, hogy make-et használjak build-elésre. Jó eséllyel nem kell hozzá semmit se telepíteni és a Phing-et elég lassúnak találtam, ami gyakori futtatás esetén nem egy vágyott tulajdonság. Mivel egyébként is csak konzolos parancsokat futtatok, egy egész egyszerű Makefile-lal meg lehet úszni például a coding standard-ek ellenőrzését és a unit tesztek futtatását:

PHPUNIT=@vendor/bin/phpunit
PHPCS=@vendor/bin/phpcs

all: test checkstyle

test:
	$(PHPUNIT) --bootstrap=vendor/autoload.php tests/

checkstyle:
	$(PHPCS) --report=full --standard=PSR2 src/ tests/

Már egy ideje beüzemeltem otthonra egy Raspberry Pi-t, de eddig nem használtam túl sok mindenre. A kamera modul megjelenésével gondoltam ideje lenne kezdeni vele valamit... Egy elég egyszerű dologról van szó, a kamera modullal való ismerkedéshez tökéletes kis projekt lehet. A beépített raspistill parancs támogatja is a time-lapse képek készítését a -tl és -t kapcsolók segítségével, de úgy vettem észre, hogy hosszabb futás esetén eléggé megakasztja a rendszert, így célravezetőbb lehet egy kis shell scriptet használni (nevezzük mondjuk timelapse.sh-nak), ami megfelelő időközönként futtatja a raspistill parancsot:

#!/bin/bash

for i in $(seq -f "%04g" 1 1440)
do
    raspistill -o "/path/to/images/IMG_${i}.jpg" -t 1000
    sleep 59
done

Ez a kód így nagyjából percenként fog egy képet csinálni, 1440-szer (tehát kb. egy napig fog futni). A raspistill paraméterezésével még érdemes lehet egy kicsit foglalkozni (például a képméretet beállítani a -w és -h kapcsolók segítségével). A sleep helyett használhatunk usleep-et is, ha pontosabban szeretnénk megadni a várakozási időt két futás között. Futtatni a következő módon ajánlott:

$ ./timelapse.sh &

Így háttérbe küldjük a folyamatot és nyugodtan kiléphetünk a shell-ből, a script tovább fog futni. Ha elkészültek a képek már csak össze kell őket fűzni egy videóvá. Ezt érdemesebb egy erősebb hardveren megtenni, ha nem akarunk a szükségesnél jóval többet várni. Parancssorból használhatjuk például az avconv parancsot:

$ avconv \
    -f image2 \
    -i /path/to/images/IMG_%04d.jpg \
    -r 24 \
    -qscale 2 \
    -s 640x480 \
    /path/to/output.avi

A különböző paraméterekkel itt is érdemes lehet eljátszogatni, hogy olyan kimenetet kapjunk, amit szeretnénk. Nálam ilyesmi lett a végeredmény egy délután alatt, percenként kb. 6 képet készítve:

Google Reader logo

Pár millió felhasználó nem volt elég az életben tartásához, úgyhogy sokan állhattunk neki az alternatív megoldások utáni kutatásnak, amikor a Google bejelentette a leállást. Aztán a mai nappal tényleg vége lett. Reggel még az olvasatlan elemek felén sikerült végigmennem, aztán egyszer csak kirántották alólam az alkalmazást. :) Nem is nagyon tudok mit hozzáfűzni a témához, csak gondoltam megérdemelne 8 év után egy megemlékezést.

Ha esetleg érdekelne, hogy kik tették lehetővé, hogy az elmúlt években kényelmesen olvashasd a kedvenc oldalaidon megjelenő tartalmakat, errefelé van egy post a Reader csapatról.

Amennyiben még nem találtál volna mást, én ezeken tartom rajta a szemem:

  • The Old Reader
    Egyelőre még nincs mobil alkalmazás, kicsit lassan frissülnek a feedek, néha újra feltűnnek már elolvasott postok, a webes mobil nézet nem túl használható, de a desktop böngészős változat hozza az elvárt működést.
  • Digg Reader
    Erősen béta, helyenként kifejezetten bugos, mobil alkalmazás egyelőre csak iKészülékekre. Jelen formájában számomra még használhatatlan, mert nem lehet csak az olvasatlanokat listázni, de a jövőben egy ígéretes utódja lehet a Reader-nek.

A minap eszembe jutott, hogy milyen jó is lenne, ha a Sublime jelezné, ha van valami elgépelés az éppen szerkesztett fájlba. És bár létezik elég sok megoldás a problémára, ami ráadásul még több nyelvet is (Python, CSS, JavaScript, stb.) támogat, de azért mégis csak sokkal mókásabb egy sajátot írni.

A megoldás lényege, hogy valahol a vinyón van egy PHP bináris, amit megfuttatunk a -l kapcsolóval, ami nem futtatja a fájlt, hanem csak szintaxisra ellenőriz. A válasz a PHP szokásos "parse error" szövege lesz, ami azt írja ki, hogy hol hasalt el a fordító, ami nem feltétlen esik egybe azzal, hogy hol van a hiba. A kódot többféleképpen meg lehetne valósítani (pl. parancsként, amit menüből, vagy billentyűkombinációra lehet futtatni), én azt választottam, hogy mentés eseményre automatikusan fusson le, ha megfelelő a fájl kiterjesztése:

import sublime, sublime_plugin, os, subprocess, re

class PhpLintEventListener(sublime_plugin.EventListener):
    key = "php_lint_syntax_error"
    
    def on_post_save(self, view):
        if not view.settings().has("php_lint"):
            return
        
        config = view.settings().get("php_lint")
        
        bin_path = config.get("binary", "")
        name, ext = os.path.splitext(view.file_name())
        
        if not bin_path or ext not in config.get("extensions", []):
            return
        
        view.erase_regions(self.key)
        view.erase_status(self.key)
        
        shell = sublime.platform() == "windows"
        p = subprocess.Popen([bin_path, "-l",  view.file_name()], shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (stdout, stderr) = p.communicate()
        
        if "" == stderr:
            data = stdout
        else:
            data = stderr
        
        result = re.match(r"(.+?) in (.+?) on line ([0-9]+).*", data, re.M | re.S)
        if result:
            error = result.group(1)
            line = result.group(3)
            
            view.add_regions(self.key, [view.full_line(view.text_point(int(line) - 1, 0))], "markup.deleted", "dot")
            view.set_status(self.key, error + " on line " + line)

Nem egy bonyolult jószág, ha létezik a config és a fájl kiterjesztése benne van a configban megadott listában, akkor megfuttatjuk a PHP binárist és megkeressük a kimenetében, hogy hányadik sorban volt a hiba. A hibás sort kiemeljük és a hiba szövegét a státuszba ki is írjuk. A szükséges config pedig valahogy így néz ki:

"php_lint" : {
    "binary" : "d:\\php\\5.2\\php.exe",
    "extensions" : [".php"]
}

Ezt lehet pakolni a Preferences > Settings - User részbe vagy akár a projekt beállításai közé is (a .sublime-project fájlon belül a "settings" blokkba).

Több, mint 5 és fél év után elérkezett az idő, hogy nyugdíjba vonuljon a régi oldal és megszülessen az 5.0-s verzió. Mivel egyébként nagyjából 8 év magasságában járunk, elég nagy bizonyossággal állíthatom, hogy ilyen sokáig még egy design se bírta. Sok mindent nem is tudnék hozzátenni, az eredmény jól látható (ha csak nem rss olvasóban nézi a kedves olvasó a bejegyzést). Néhány dolog, ami változott:

  • A modern kor elvárásaihoz némiképp igazodva az oldal valamivel reszponzívabb lett.
  • A kommentelési lehetőség kikerült, a továbbiakban a bejegyzéshez kapcsolódó Google+ postban lehet majd megjegyezni dolgokat.
  • Like/+1 gombok sincsenek, csak hogy letisztultabbak és egyszerűbbek legyünk.
  • Bár még mindig nem vittem túlzásba a tartalmat, de már nem csak "Folyamatban..." van az Archívum oldalon. :)

Ééés nagyjából ennyi... Nem vittem túlzásba. :) Aztán biztos maradt egy rakat hiba és hiányosság benne, amit majd az elkövetkezendő évek során bőven lesz időm javítani.

Szóval, már egy ideje foglalkoztat a mobil fejlesztés. Annak is főleg a zöld robotos ágazata. Gondoltam ideje lenne valami maradandóbbat alkotni a gépen heverő sok teszt projektnél, úgyhogy bele is vágtam egy listás alkalmazás elkészítésébe, annak ellenére, hogy listás alkalmazásokkal Dunát lehetne rekeszteni (vagy ha már itt tartunk, lassan már bármilyen típusú alkalmazásokkal... :)). A végeredmény (vagy inkább az első verzió) megtekinthető a Google Play-en:

Vagy mobilosoknak egy kényelmesebb market alkalmazás linken:

Amit tud:

  • Listákat kezelni! :)
  • Külső alkalmazás segítségével QR kódot beolvasni és azt elmenteni listaelemként az egyszerű és gyors felvitel érdekében.
  • Ha linket kap listaelemnek, azt feldolgozza és a meta adatokkal együtt jeleníti meg (a Facebook-os Open Graph tagek hozzák igazán lázba, mással nem nagyon foglalkozik :)).
  • Megosztani egy listát (pl. e-mailben elküldeni).

Nagyjából ennyi, nem egy bonyolult jószág. Az elkészítésében az ActionBarSherlock volt a segítségemre, ami remekül valósítja meg a 4.0-s Action Bar-t 4.0 előtti készülékeken is. Kellemes listázást. :)

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 &quot;${sass_dir}:${css_target}&quot;" />
    </target>
    
    <target name="coffee">
        <exec command="coffee -o &quot;${js_target}&quot; &quot;${coffee_dir}&quot;" />
    </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.

Épp a sorozatos oldal második verziójának fejlesztésébe készülök komolyabban belevágni. Ennek kapcsán eszembe jutott, hogy milyen jó bejegyzést lehetne ebből kanyarítani. Mármint abból, hogy milyen módjai vannak a kényelmes otthoni projekt fejlesztésnek.

Összepiszkíthatnánk például a jelenlegi operációs rendszerünket mindenféle web- és egyéb szerverekkel, de ez nem egy szép megoldás. Telepíthetnénk egy extra operációs rendszert egy külön partícióra, de az, hogy a jelenlegiből ki kell lépni, oda pedig be... esélytelenné teszi a fejlesztést egy kellően lusta ember számára (én :)). A legjobb lenne egy külön gép, amit hálózaton keresztül elérünk. Ennek a legköltséghatékonyabb változata a virtuális gép, így ezen a vonalon fogunk tovább haladni. Hozzávalók egy személyre:

Pro tipp: az Ubuntu szerver iso-ját ne a VirtualBox telepítése közben töltsük le, mert a VirtualBox telepítés közben hajlamos időlegesen megkavarni az internet kapcsolatot és jól meg fog szakadni a letöltés.

Telepítés

A letöltések és a szokásos next-next-finish telepítés befejeztével hozzáadhatunk egy új Linux / Ubuntu típusú virtuális gépet és egy új virtuális merevlemezt a varázsló segítségével. Még mielőtt elindítanánk, a Settings / Shared Folders részben érdemes hozzáadni egy könyvtárat a saját gépünkről, amiben a projekteket fogjuk tárolni, hogy ne kelljen később Samba-t telepíteni. Az Auto-mount részt ne pipáljuk be, azt később kézzel beállítjuk majd. A Settings / Network részbe se árthat benézni és az Adapter 1-et ízlés szerint megpiszkálgatni. Nálam a Bridged Adapter volt a nyerő az Attached to részben. A VirtualBox elég okos és az első indításnál felajánlja, hogy etessünk meg a géppel egy CD-t. Ajánlatos itt beadagolni a korábban letöltött Ubuntu szerver iso-ját, mert az nagyban megkönnyíti a telepítést. :)

Az Ubuntu nem egy bonyolult jószág, így valószínűleg a telepítéssel se lesznek problémák. Amíg fut, tetszés szerint lehet fogyasztani a bespájzolt hideg élelmet illetve sört. Hogy, hogy nem előbb-utóbb eljutunk egy ilyen képernyőhöz:

Itt a LAMP server-t az Apache-PHP-MySQL szentháromság miatt erősen ajánlott bepipálni, mert valószínűleg szükségünk lesz rá. Én telepíteni szoktam OpenSSH server-t is, mert már annyira hozzászoktam a PuTTY használatához. :)
Ha ezzel megvagyunk, az első belépés után rögtön érdemes is nyomni egy frissítést:

sudo apt-get update
sudo apt-get upgrade

Valamint telepíteni a VirtualBox Guest csomagját a jobb támogatás érdekében:

sudo apt-get install virtualbox-guest-utils

A projekt könyvtárak beállítása

A fejlesztés a /var/www/ könyvtárban fog történni a virtuális gép nézőpontjából. Hogy kényelmes legyen, érdemes ezt kivezetni valahova a gazda gép merevlemezére. Ezért állítottuk be korábban a Shared Folders részt. A művelet elvégzéséhez a következő sorokat kell felvenni az /etc/fstab fájl végére (na jó, a komment nem kötelező :)):

# VirtualBox Shared Folder
projects /var/www vboxsf auto,rw,uid=1000,gid=33 0 0

A projects helyére a Shared Folder felvitelénél megadott nevet kell írni. Az uid=1000 a rendszer telepítése során létrehozott felhasználó, a gid=33 a www-data csoport. A módszernek az az előnye is megvan a Samba-féle megoldással szemben, hogy nem kell futnia a virtuális gépnek ahhoz, hogy a fájlokat módosítani tudjuk. Az uid és gid értékeként megadható számok után az /etc/passwd és /etc/group fájlokban lehet érdeklődni.

Szerver elérés

Ha minden jól ment, az ifconfig eth0 által kidobott ip címen el tudjuk érni a gépet. Ha nem, akkor a VirtualBox beállítások Network részénél érdemes a lehetőségeket végigpróbálgatni, hogy melyik jön be (ahány hálózat, annyi beállítás).
Az egyszerűséget szem előtt tartva érdemes valami egyedi, egyébként nem létező domain-el felruházni a gépet, hogy ne ip címeket kelljen mindig írogatni. Nálam a *.vbox domain-ek vannak erre fenntartva. A legegyszerűbb, ha a hosts fájlba felvesszük őket (Windows: c:\Windows\System32\drivers\etc\hosts, Linux: /etc/hosts), pl.:

192.168.1.117 default.vbox
192.168.1.117 projektneve.vbox
192.168.1.117 subdomain.projektneve.vbox

Apache, PHP, MySQL beállítás

Az egyes projektek a /var/www/projektneve.vbox/ könyvtárban kapnak helyet. Az alap Apache confignak csinálunk egy default.vbox nevet/könyvtárat:

mkdir /var/www/default.vbox
sudo mcedit /etc/apache2/sites-available/default

A megnyíló fájlban a DocmentRoot és a Directory résznél szereplő /var/www/ után kell még egy default.vbox/-ot írni. Aztán pedig

sudo service apache2 reload

A /etc/apache2/httpd.conf-ba esetleg még érdemes egy ServerName default.vbox sort beledobni és újraindítani az Apache-ot, hogy megszűnjön a "Could not reliably determine the server's fully qualified domain name" hibaüzenet.

A projekt VirtualHost beállításai a /etc/apache2/sites-available/projektneve.conf fájlba kerülnek. Egy egyszerű példa, hogy nagyjából mit is tartalmaz egy ilyen:

<VirtualHost *:80>
    ServerName projektneve.vbox
    ServerAlias www.projektneve.vbox

    DocumentRoot /var/www/projektneve.vbox/www
    <Directory />
        Options FollowSymLinks
        AllowOverride All
    </Directory>
    <Directory /var/www/projektneve.vbox/www/>
        Options FollowSymLinks
        AllowOverride All
    </Directory>

    ErrorLog /var/www/projektneve.vbox/log/apache_www_error.log
    CustomLog /var/www/projektneve.vbox/log/apache_www_access.log combined

    LogLevel warn
</VirtualHost>

A kész site beállításokat a következő parancsokkal tudjuk engedélyezni:

sudo a2ensite projektneve.conf
sudo service apache2 reload

A MySQL-en nincs sok beállítani való, telepítéskor elkérte a root felhasználójához az új jelszót, mást meg nem nagyon kell piszkálni. A vizuálisabb típusoknak esetleg egy phpmyadmin telepítése még nem árthat:

sudo apt-get install phpmyadmin

Ha kértük, a csomagból telepítés során be is köti magát az Apache-ba a /etc/apache2/conf.d/phpmyadmin.conf segítségével és a http://ipcím/phpmyadmin/ címen el is érhető az oldal. Ehelyett, ha kedvünk tartja létrehozhatunk neki egy saját VirtualHost-ot is akár.

A PHP beállításánál érdemes arra törekedni, hogy minél jobban hasonlítson az éles rendszerre, így ezzel kapcsolatban nem sokat tudok mondani.

Első körben ennyi, kellemes telepítgetést. :)