wtorek, 24 kwietnia 2007

Winowajca odnaleziony

Znalazłem winnego. Byłem prawie pewien, że to był aniou, ale wydawało mi się że to było rok albo dwa wcześniej. W każdym razie taka jest geneza PLD/FreeBSD.

czwartek, 19 kwietnia 2007

New look and feel

Tak się złożyło, że dysponując chwilą wolnego czasu zabrałem się do realizacji od dawna odkładanych zadań. Skutkiem czego wiki (a zatem i blog) doczekało się w końcu nowego, lepszego wyglądu. Stare skórki są (dla ciekawych) nadal dostępne, np. http://wiki.pld-freebsd.org/bin/view/Blog/BlogEntry6?skin=pattern

środa, 7 marca 2007

PLD/FreeBSD Preview 1

Ponieważ zgłosiło się do mnie już kilka osób z pytaniem jak można zainstalować PLD/FreeBSD postanowiłem coś z tym zrobić. Na początek PLD/FreeBSD Preview 1 w postaci spakowanej maszyny wirtualnej do VMWare Workstation. Do pobrania tutaj (41.5 MB). System minimalny jak tylko się dało, więc można sobie popoldkować.

Po uruchomieniu maszyny i zalogowaniu się na roota (hasło puste) trzeba skonfigurować sieć:

ifconfig lnc0 192.168.1.2
route add default 192.168.1.1
echo "nameserver 192.168.1.1" > /etc/resolv.conf
albo wyedytować znane z PLD pliki odpowiedzialne za powyższe i zrestartować usługę network
/etc/rc.d/init.d/network restart
I 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

Po raz trzeci zabrałem się za pisanie builderów dla PLD/FreeBSD. Efekt jest taki, że podstawowe funkcjonalności są już gotowe, a w czasie kiedy na nowych builderach testowo przebudowywane są wszystkie pakiety spłodziłem krótki tekst opisujacy ich działanie. Zainteresowanych zapraszam do lektury.

czwartek, 15 lutego 2007

Ciekawa własność NULLa

W bólach implementacji swoich builderów natknąłem się na ciekawą własność NULLa w MySQL. Nie wiem czy pojawia sie ona również innych SQLach.

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 NULLniepoliczalne 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 NULL
speł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...

W gruncie rzeczy tekst ma być o tym dlaczego SVN jest lepszym wyborem w przypadku repozytorium pakietów. Swoje przemyślenia opieram na bez mała trzy i pół rocznym doświadczeniu z repozytorium http://svn.pld-freebsd.org/svn/packages, dostepnym równiez przez ViewCVS: http://svn.pld-freebsd.org/cgi-bin/viewsvn/.

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 packages
Natomiast ściagniecie i kompilacja pakietu db z takiego repozytorium wygląda tak:
$ cd ~/packages
$ svn checkout http://svn.pld-freebsd.org/svn/packages/trunk/db
$ cd db/SPECS
$ rpmbuild -ba --define "_topdir ~/packages/db" db.spec
Powyższy przykład nie uwzględnia oczywiście ściagnięcia ewentualnych tarballi z distfiles.

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 ~/packages
$ svn commit -m "- updated to 4.5\n- updated patch1 patch" db
Co 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.

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

Poprzedni blog umarł śmercią naturalną. Nie żałuję. Z początku NewsBruiser nawet mi się podobał, zapewne dlatego że pierwsze wrażenie wynikało z punktu widzenia użytkownika. Później zaczęły się problemy, a to jakaś ikona się nie wyświetla, a to nie mam kontroli nad layoutem. Dlaczego? Nie wiem, i nawet nie chce mi się tego analizować. Po prostu organicznie nie cierpię Pythona.

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.