PiSi delta paketleri üzerinde çalışırken, bir problem ile karşılaştım. Python ile çıkan çözüm de hoşuma gitti.

Delta paketlerin ne olduğunu da kısaca özetleyecek olursam problem daha rahat anlaşılacaktır. Paketlerimizin boyutları lzma sağolsun oldukça ufaldı. Ancak şöyle bir problemimiz var: Bazen paketlerin yeni sürümleri için yapılan güncellemelerde paket içerisinde yalnızca bir-iki dosya’nın değiştiği durumlar olabiliyor. (İsmail kızmasın diye openoffice’i örnek olarak vermeyeceğim :) ) Düşünün 99 MB’lık bir paketiniz var (openoffice değil ama), yeni versiyonundaki değişikliğe baktığınızda ise, içerisinde sadece 100 KB’lık çalıştırılabilir bir dosya’nın değiştiğini görüyorsunuz. Bunun dışında 1-2 KB da örnek yeni config dosyası filan eklenmiş diye düşünün. Şu anki durumda, kullanıcı yalnızca bu 100 KB’lık değişiklik için yeniden 99 MB çekmek durumunda kalıyor. Değişikliğin çok daha ufak olduğu durumlarda ise gerçekten can sıkıcı bir durum ortaya çıkıyor. PiSi delta paketleri ile sürümler arasında yalnızca bu farkları barındıracak olan paketler hazırlamayı planlıyoruz. Bunun için de alt yapı çalışmaları yapıyoruz. Kullanıcı güncellemek istediğinde, eğer delta paketler mevcut ise otomatik olarak güncelleme bu paketler ile yapılacak. xdelta’nın ilerde düzelecek, lzma sorunlarını geçin (iyi ki varlar :) ), gereksiz yere de ek bir araç kullanıp bağımlı olacağımıza, bu şekilde çok sade ve temiz bir çözüm düşündük. Delta paketler yalnızca fark dosyalarını içerecek.

Şimdiki planımız her zaman Pardus 2007 sürümü ile son güncel paketler arasında delta paketleri oluşturulmak. Ki bu sayede yeni Pardus 2007 kurulumu yapılmış olan bir makinede güncelleme boyutu yeterince az olabilsin. Bunun dışında aynı paketin son iki sürümü arasındaki delta paketleri de her zaman bulunabilecek.

Konuya gelecek olursak problem şu şekilde: Elinizde eski ve yeni paketlerde bulunan dosya bilgileri bulunuyor. İki adet liste. Liste elemanları ise her bir dosyanın ayrıntılı bilgisini barındıran nesneler. Nesne elemanları da dosya’nın yol, hash, tip, boyut, vs. gibi bilgilerden oluşuyor. Yapmam gereken ise bu iki liste içerisindeki nesnelerin arasından aynı dosyayı bulmak, bunların hashlerini karşılaştırmak ve eğer hash değişmiş ise dosya’nın da değişmiş olduğunu kabul ederek delta paketi içerisine eklemek. Bunun dışında ayrıca yeni pakette bulunan ama eski pakette olmayan dosyaları da tabi ki bu listeler arasından tespit edip yine delta paketine eklemem gerekiyor.

Akla ilk gelen O(n²) karmaşıklığındaki çözümü kodlamayı hiç istemedim. Dün nasıl yapılabilir diye bayağı düşündüm, liste karşılaştırmaları üzerine yapmak istediğime yakın örnek kod araştırdım fakat bir şey çıkaramadım. Ama bugün hoş bir çözüm buldum:

    files_all = set(map(lambda x:(x.path, x.hash), files.list))
    files_old = set(map(lambda x:(x.path, x.hash), oldfiles.list))
    files_delta = files_all - files_old

files.list yeni paketteki dosya nesnelerini içeren, oldfiles.list ise eski paketteki dosya nesnelerini içeren listelerimiz. Satır sayısından çok sadelik ve okunabilirliğe önem versem de, 3 satırda bu kadar işi halledebilmek gerçekten hoş oldu. Böylece files_delta içerisinde bulunan dosya’nın yollarına bakarak da tek tek delta paketi içerisine ekleyebiliyorum.