wtorek, 24 kwietnia 2007
Winowajca odnaleziony
czwartek, 19 kwietnia 2007
New look and feel
środa, 7 marca 2007
PLD/FreeBSD Preview 1
Po uruchomieniu maszyny i zalogowaniu się na roota
(hasło puste) trzeba skonfigurować sieć:
ifconfig lnc0 192.168.1.2albo wyedytować znane z PLD pliki odpowiedzialne za powyższe i zrestartować usługę
route add default 192.168.1.1
echo "nameserver 192.168.1.1" > /etc/resolv.conf
network
/etc/rc.d/init.d/network restartI już można działać. Nie polecam instalowania pakietu
kernel
i loader
bo te które są na FTPie mogą kompletnie rozwalić system. Zainteresowanym życzę miłej zabawy.
Jak tylko znajdę chwilę czasu postaram się opisać jak zainstalować PLD/FreeBSD na fizycznej maszynie przy pomocy płyty instalacyjnej FreeBSD.
wtorek, 6 marca 2007
Do builderów podejscie trzecie
czwartek, 15 lutego 2007
Ciekawa własność NULLa
Najprościej bedzie na przykladzie. Załózmy, że mamy dwie tabele "process" i "task". Tabela "process" zawiera listę procesów wykonywanych przez pewien abstrakcyjny procesor, na każdy proces składa się pewna ilość zadań, przy czym każde zadanie może należeć tylko do jednego procesu; czyli prosta relacja jeden do wielu. Dodatkowo każde zadanie posiada właściwość "status" określająca stan tego zadania. Dla ustalenia uwagi niech pole "status" może przyjmować trzy wartości: "none", "running" lub "completed". Definicja tych tabel może wyglądac tak:
CREATE TABLE process (
id INT UNSIGNED PRIMARY KEY NOT NULL auto_increment,
name VARCHAR);
CREATE TABLE task (
id INT UNSIGNED PRIMARY KEY NOT NULL auto_increment,
id_process INT UNSIGNED NOT NULL,
status ENUM('none', 'running', 'completed') NOT NULL);
Zapytanie które zwróci nam identyfikator procesu wraz z ilością zadań przyporzadkowanych do tego procesu jest oczywiście trywialne i wyglada tak:
SELECT id_process, COUNT(*) FROM task GROUP BY id_process;
Problemem natomiast jest zapytanie zwracajace identyfikator procesu wraz z ilością zadań przyporzadkowanych do tego procesu, ale takich które nie zostały jeszcze zakończone, czyli mają status różny od 'completed'. Proste:
SELECT id_process, COUNT(status != 'completed') FROM task GROUP BY id_process;nie wystarcza ponieważ
COUNT
zlicza zgrupowane wartości bez wzgledu na ich wartość. W tym przypadku zarówno TRUE
jak i FALSE
jest traktowane jako element to zliczenia. Zatem powyższe zapytanie zwraca to samo co poprzednie, czyli identyfikator procesu wraz z ilością zadań przyporzadkowanych do tego procesu. Możnaby oczywiście uzyć funkcji SUM
i IF
w następujący sposób:
SELECT id_process, SUM(IF(status != 'completed), 1, 0) FROM task GROUP BY id_process;Ale to nie dość, że niezgodne z zasadami sztuki, to jeszcze mało czytelne i pewnie mało wydajne.
Aby w prosty sposób uzyskać oczekiwany wynik wystarczy wykorzystać to że wartości NULL
są niepoliczalne dla funkcji COUNT
. Jeżeli zgrupujemy rekordy które w zadanym polu maja cztery wartości z czego dwie są równe NULL
to funkcja COUNT
na tym polu zwróci nam 2
, a nie 4
.
Wystarczy zatem doprowadzić ostatnie zapytanie wykorzystujące funkcję COUNT
do takiej postaci, w której wartość argumentu jest policzalna gdy pole "status" jest inne niż 'completed', a niepoliczalna (czyli równa NULL
) w przeciwnym wypadku. Wyrażenie
status != 'completed' OR NULLspełnia te założenia ponieważ przyjmuje jedną z dwóch wartości:
TRUE
dla pola "status" różnego od 'completed', albo NULL
w przeciwnym wypadku. Ostatecznie zapytanie zwracajace identyfikator procesu wraz z ilością zadań przyporzadkowanych do tego procesu, takich które nie zostały jeszcze zakończone wygląda tak:
SELECT id_process, COUNT(status != 'completed' OR NULL) FROM task GROUP BY id_process;
Śliczne, prawda?
wtorek, 6 lutego 2007
Dlaczego CVS ssie...
Struktura repozytorium różni sie znacząco od płaskiego modelu repozytorium stosowanego w PLD. W dużym uproszczeniu wygląda ona tak:
packages
+- trunk
| +- db
| | +- SOURCES
| | | +- patch1.patch
| | | +- patch2.patch
| | +- SPECS
| | +- db.spec
| +- rpm
| +- SOURCES
| | +- patch1.patch
| | +- patch2.patch
| +- SPECS
| +- rpm.spec
+- branches
| +- rpm-4.1.1
| | +- db
| | | +- SOURCES
| | | | +- patch1.patch
| | | | +- patch2.patch
| | | +- SPECS
| | | +- db.spec
| | +- rpm
| | +- SOURCES
| | | +- patch1.patch
| | | +- patch2.patch
| | +- SPECS
| | +- rpm.spec
| +- rpm-4.4.1
| +- db
| | +- SOURCES
| | | +- patch1.patch
| | | +- patch2.patch
| | +- SPECS
| | +- rpm.spec
| +- rpm
| +- SOURCES
| | +- patch1.patch
| | +- patch2.patch
| +- SPECS
| +- rpm.spec
+- tags
+- Ac-rpm-4.4.1-2
+- db
| +- SOURCES
| | +- patch1.patch
| | +- patch2.patch
| +- SPECS
| +- rpm.spec
+- rpm
+- SOURCES
| +- patch1.patch
| +- patch2.patch
+- SPECS
+- rpm.spec
Jak widać na powyższym schemacie dla każdego pakietu została wydzielona osobna gałąź w drzewie repozytorium. Taki zabieg, poza uporzadkowaniem i separacją składników poszczególnych pakietów, pozwala na rozdzielenie przestrzeni nazw plików w pakietach. A co za tym idzie, powoduje że np. nazwa patcha może być dowolna dla zadanego pakietu i nie istnieje konieczność pilnowania żeby nazwy łatek dla różnych pakietów nie kolidowały ze sobą. W szczególności, nie ma potrzeby narzucania nazewnictwa tych łatek do postaci nazwa_pakietu-nazwa_łatki.patch
jak ma to miejsce w PLD.
Ściagnięcie całego drzewa trunk
może wygląda nastepująco:
svn checkout http://svn.pld-freebsd.org/svn/packages/trunk packagesNatomiast ściagniecie i kompilacja pakietu db z takiego repozytorium wygląda tak:
$ cd ~/packagesPowyższy przykład nie uwzględnia oczywiście ściagnięcia ewentualnych tarballi z distfiles.
$ svn checkout http://svn.pld-freebsd.org/svn/packages/trunk/db
$ cd db/SPECS
$ rpmbuild -ba --define "_topdir ~/packages/db" db.spec
Drzewiastej strukturze repozytorium można zarzucać niemozliwość "przegrepowania" wszystkich specy, albo wprowadzania masowych zmian w specach. Wadę tą można wyeliminować używając polecenia find
. I tak odpowiednikiem grep jakisstring *
w katalogu SPECS jest
find . -name "*.spec" -exec grep -H jakisstring {} \;w katalogu packages/trunk.
Praca z takim repozytorium nie jest dużo bardziej skomplikowana, niż z płaskim repozytorium CVSowym. A prawie zupełnie nie różni się gdy użyjemy odpowiednio zmodyfikowanego skryptu builder.
Kolejną przewagą nad CVSem są "atomowe" commity. Polega to na tym, że po wprowadzeniu zmian z pakiecie, zmiany są przekazywane do repozytorium jednym poleceniem, np.
$ cd ~/packagesCo najważniejsze, takie dokonanie zmiany jest traktowane w repozytorium jako integralna całość identyfikowana numerem rewizji w repozytorium, a nie jest złożeniem zmian w poszczególnych plikach. Co za tym idzie możemy łatwo odszukać, że np. update db do wersji 4.5 pociągneło za sobą usuniecie pliku SOURCES/patch1.patch. W CVSie, niestety, każda tego typu zmiana jest w repozytorium traktowana osobno, dlatego dużo wiecej pracy kosztuje odnalezienie jak zmieniły się pozostałe pliki pakietu, podczas określonej zmiany pliku spec. Takie zachowanie CVSa jest dla mnie szczególnie uciążliwe, ponieważ w swojej pracy intensywnie śledzę zmiany w repozytorium PLD w celu nanoszenia niektórych z nich w PLD/FreeBSD.
$ svn commit -m "- updated to 4.5\n- updated patch1 patch" db
Atomowość commitów w repozytorium pociaga za sobą również zwiekszenie przejrzystości commitlogów, dzięki temu są one generowane jako pojedynczy mail, a nie dwa osobne maile zawierajace zmiany odpowiednio, w module SPECS i w module SOURCES.
Kolejna przewagą Subversion jest możliwość przenoszenia plików (z zachowaniem historii zmian) z poziomu użytkownika. W CVSie taka operacja wymaga zaangażowania administratora repozytorium, który musi dokonać takiej zmiany po stronie serwera.
Dla niektórych kolejną wadą SVNa może być niemożliwość generowania sekcji %changelog
, tak jak ma to miejsce w chwili obecnej w PLD. Według mnie używanie $Log$
do generowania loga to średnio dobry pomysł, tym bardziej, że taki log nie jest tworzony w formacie przyjmowanym przez RPMa. Słuszniej byłoby gdyby %changelog
był generowany z loga SVNa na source-builderach w formacie natywnym dla RPMa.
Na koniec wypada jeszcze wspomnieć o łatwości instalacji serwera Subversion. Po raz pierwszy zajeło mi to kilkanaście minut, podczas gdy na instalację serwera CVSu straciłem kilka(naście) godzin.
środa, 31 stycznia 2007
In the Beginning... umarł blog, niech żyje blog
Tak się złożyło że powziąłem noworoczne postanowienie, że w końcu zacznę pracować nad serwisem WWW dla PLD/FreeBSD. Niech świat się dowie że istnieje coś takiego jak PLD/FreeBSD, a nuż ktoś sie zlituje i pomoże, albo jeszcze lepiej przekona, że to nie ma sensu. Jak to z postanowieniami bywa, zacząłem je realizować z "niewielkim" opóźnieniem.
Ponieważ wszelkiego rodzaju Wiki są obecnie na topie (czyt. trendi, albo dzezi, albo jeśli ktoś woli kaczi), tam też postanowiłem szukać silnika do serwisu. Drugim ważnym kryterium jakie powinien spełniać silnik było to że musiał być napisany w Jedynym Słusznym Języku Skryptowym(TM) czyli perlu. Wśród tak ograniczajacych kryteriów jedynym godnym uwagi silnikiem okazał sie TWiki. I tak zostało.
Przy okazji przewalania dokumentacji TWiki okazało się, że posiada od rozbudowany system wtyczek, wśród których jest jedna zmieniająca dział TWiki w dość zaawansowany system blogowy. Po drobnych problemach z instalacją, system stanął i zapadła decyzja o wskrzeszeniu bloga. I oto jest.
Do mojego prywatnego TODO powędrowały dodatkowo: spolszczenie systemu do używalnej postaci i stworzenie jakiegoś ślicznego layoutu. Do tego drugiego zatrudniłbym któregoś ze znajomych web-grafików. Zobaczymy.