diff --git a/AGENTS.md b/AGENTS.md index e01688d..d328fa9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,111 +1,460 @@ # AGENTS.md — Yali-rs Geliştirme Notları -> Ajan oturumları arasında süreklilik için. Son güncelleme: parted MiB düzeltmesi (23 Ağu) +> Ajan oturumları arasında süreklilik için. +> Son güncelleme: **26 Eylül 2026** — çoklu disk bölümleme + güvenlik düzeltmeleri. -## Proje -- PisiLinux kurulum aracı (eski Python Yali'nin Rust/egui yeniden yazımı). -- Ana dallar: `main`. Push: `git push origin main`. -- Referans kod: `/media/yedekleme/github/erkanisik/yali` (eski Python Yali — - storage mimarisi: `yali/storage/{operations,partitioning,devicetree}.py`). +--- -## Mimari Kararlar (2026-08 dönemi) +## 🚨 EN ÖNEMLİ: 22de7d5 regresyonu (25 Ağu 2026) -### Çoklu Disk Manuel Bölümleme -- `CustomPartition` alanları (`src/installer.rs`): - - `disk`: bölümün ait olduğu disk ("/dev/sda") — gruplama bununla. - - `orig_device`: lsblk'tan gelen fiziksel cihaz adı; **boş = kullanıcı tanımı yeni bölüm**. - Silme/işaret mantığı buna dayanır. - - `delete: bool`: eski Yali `OperationDestroyDevice` karşılığı → kurulumda `parted rm`. -- UI (`src/steps/partition.rs`): - - Manuel moda girişte TÜM diskler otomatik taranıp listelenir (disk kartına tıklamak - artık sadece "yeni bölüm hedef diski" seçer; tanımları sıfırlamaz — merge eder, - `orig_device` eşleşmesinde kullanıcı tanımı kazanır). - - Tablo `TableRow::Part | TableRow::FreeSpace` enum'u ile kurulur; HER disk grubu - kendi sütun başlıklarını çizer (`draw_partition_table_header`). - - Silinmek işaretli bölümler ayrı satır çizmez; İLK silinenin konumunda TEK - "Boş Alan" satırında birleşir (GParted tarzı). - `Boş Alan = disk − (korunan fiziksel + yeni tanımlar)`; 0 ise satır gizlenir. - - "Kalan alan" SEMBOLİKTİR (size_mb=0): kaydetme anında sayıya çevrilmez! - Tabloda/özetde kapasite olarak gösterilir; gerçek boyut kurulum anında boşluktan alınır. - (Somutlaştırma taşmaya yol açtığı için kaldırıldı — swap sonradan büyütülünce kök patlıyordu.) -- Slot ataması (`installer::assign_partition_numbers`): parted'ın gerçek davranışını - simüle eder — fiziksel (silinmeyen) bölümler numarasını korur, silinenlerin slotu - boşalır, yeni tanımlar en küçük boş slotu alır. UI ile job tutarlılığı buradan gelir. +**Bu dosyayı okuyan her ajan önce bu bölümü okumalı.** -### Granular Kurulum Job'ı (`jobs/partition.rs::CustomPartitionJob`) -Eski wipe&rebuild (mktable + hepsini baştan yarat) KALDIRILDI. Yeni fazlar: -1. FAZ A: `delete=true` olanlar `parted rm N` — N, `orig_device`'tan; - **büyükten küçüğe** sil (kernel slot kayması). -2. FAZ B: yeni tanımlar `disk_free_regions_mb()` ile sysfs'ten hesaplanan boş - bölgelere first-fit yerleşir ("kalan" = en büyük bölge). Sabit boyutlular ÖNCE, - sembolikler SONRA (`creates.sort_by_key(size==0)`) işlenir. -3. FAZ C: yalnızca istenenler mkfs (LUKS akışı korundu). -- İşlemi olmayan disklere ve `delete=true` satırlara mount/fstab/summary dokunmaz. +Commit `22de7d5` — *"Dead code uyarılarını gidermek için `#[allow(dead_code)]` +eklendi"* (Devin AI ajanı) — mesajı üç tane `#[allow]` eklemekle +sınırlıydı. Gerçekte **`src/steps/partition.rs`'i 2438 satırdan 811 +satıra düşürdü: 1804 satır silindi.** -### Diğer Düzeltmeler -- **parted birim tuzağı (KRİTİK):** parted `"MB"` sonekini **ondalık** (10^6 byte) okur, - bizim hesaplar binary (2^20). `mkpart 3944MB` → sektör 7703125 (hizasız, boş alana - uymaz) → "Becerebildiğimiz buna en yakın konum..." hatası. ÇÖZÜM: parted'a daima - `"{}MiB"` sonekiyle geç (`jobs/partition.rs`, hem otomatik hem CustomPartitionJob). - Tamsayı MiB = 2048 sektörün katı → hizalama hatası çıkmaz. UI'da kullanıcıya MB - gösterilir ama parted argümanı asla "MB" olmasın. -- MB dönüşümleri tek bölme: `x / 1_048_576` (çift `x/1024/1024` hassasiyet kaybı yapardı). -- Disk seçiminde `size_gb * 1024` yerine `size_bytes / 1_048_576`. -- Mountpoint değişince boyut alanı SADECE boş/"0"/"remaining" ise varsayılanlanır - (kullanıcının elle girdiği değer ezilmez). -- Simge fontu: `assets/remixicon.ttf` egui fallback fontu (`ui/theme.rs setup_fonts`). - Kutucuk görürsen karakter fontta yok demektir — fontTools ile cmap kontrol et: - kullanılanlar: EB7B check, EA6B arrow, EC28 trash, EA13 add, EFE0 pencil, EECD lock, - ECA1 error, EDFB hard-drive-line, ECB5/B7 eye, F4C6 close. -- Alt bar: "Mevcut Durum / Kurulum Sonrası" çift şerit (`manual_dual_bars`, - gri segment = boş) — SADECE seçili disk için gösterilir (`state.selected_disk`). +``` +src/steps/partition.rs | 1978 +++++------------------------------------------- + 181 insertions(+), 1804 deletions(-) +``` -## Bilinen Açıklar / Yapılacaklar -- [ ] VM testinde rapor edilen hatalar düzeltilecek (kullanıcı listeleyecek) -- [ ] `manual_capacity_error` yalnızca sabit boyutları kontrol eder; LVM PV/LV toplamları ayrıca doğrulanmalı -- [ ] Silinmek işaretli bölüm bir VG'nin PV'siyse SetupLvmJob tarafında kontrol yok -- [ ] Otomatik mod (erase disk) hâlâ tek disk; çoklu otomatik plan yok -- [ ] Debug amaçlı kalan `eprintln!` satırları temizlenebilir +### Silinenler +Tüm manuel bölümleme arayüzü: ekle/düzenle/sil onayı/LVM VG/LVM LV +diyalogları, `draw_partition_table_header`, `manual_dual_bars`, +`TableRow` enum'u, `disk_size_mb`, `used_mb_on_disk`, `draw_layout_bar`, +`bar_style`, `partition_bar`, `format_number_thousands` ve **21 birim testi**. + +### Etkisi +Manuel bölümleme **fiilen işlevsiz** hâle gelmişti: +- "+ Ekle" / "Düzenle" / "Sil" butonları yalnızca **kimsenin okumadığı** + bayraklar set ediyordu → hiçbir diyalog açılmıyordu +- `delete = true` **hiçbir yerden set edilmiyordu** → + `CustomPartitionJob`'un FAZ A'sı (`parted rm`) erişilemez +- `state.volume_groups` / `logical_volumes` **hiçbir yerden yazılmıyordu** + → `SetupLvmJob` hep boş vektör alıyordu, **LVM tamamen erişilemez** +- `#[allow(dead_code)]` derleyicinin bu boşluğu bildirmesini bastırdı + +### Geri alınışı +`8c6dc08` ile düzeltildi. Yedek: tag `backup-before-unrevert-22de7d5`, +branch `backup/pre-unrevert` (a5d4627 = geri alma öncesi HEAD). +`8633422`'nin üç validasyon düzeltmesi geri almanın üzerine yeniden +uygulandı; bir test (`manual_mode_complete_with_valid_partitions`) +güncellendi, `selected_disk` kuralı için yeni test eklendi. + +### DERS — TEKRARLANSIN +1. **Bir commit mesajı ne yaptığını tam anlatmıyorsa, diff'i oku.** + `-1804` satır "dead code temizliği" değildir. +2. **`#[allow(dead_code)]` bir teşhis aracıdır, tedavi değil.** Bir şey + kullanılmıyorsa ya silinmeli ya da bağlanmalı; susturmak, altta + yatan boşluğu gizler. Bu projede tam olarak bu oldu. +3. **Yedek dosyaları git'e commit etme.** `partition.rs_24082026` gibi + dosyalar repoya `git rm` edildi, `.gitignore`'a desen eklendi. + Yedek gerekiyorsa **git history**'dir, çalışma ağacı değil. +4. Kullanılmıyor görünen bir adımı **silmeden önce** sihirbaza + bağlı olup olmadığını yazılım olarak doğrula (grep yeterli değil — + `on_enter`'ın ne zaman çağrıldığına bak). + +--- + +## Proje Tasarım Kararı: SQUASHFS KURULUMU + +**YALI kurulu sistemi ISO'nun squashfs'inden kopyalar** (`CopyFilesJob` +rsync). Bunun temel sonucu: + +> ISO'da hangi paketler, ekran yöneticisi ve masaüstü ortamı varsa, +> kurulum onları **zaten içerir**. + +Bu yüzden sihirbaz **paket seçimi, ekran yöneticisi seçimi veya lisans +kabulü sunmaz** — sunduğu ayarları kopyalama zaten ezdiği için +yanıltıcı olurdu. + +### Netinstall gelecekte ayrı bir proje +İki ayrı proje çıkacak: +1. **Bu proje** — squashfs'i diske kopyalar (mevcut akış) +2. **Netinstall** — paketleri ağdan kurar, squashfs akışı iptal eder + +`src/steps/netinstall.rs` ve `src/jobs/netinstall.rs` **dormant** olarak +repoda duruyor. Etkinleştirme koşulu `src/steps/mod.rs`'te yazılı: +- `main.rs`'de `steps` vektörüne `Box::new(steps::netinstall::NetinstallStep)` + (Bootloader ile Summary arasına) +- `JobQueueConfig::selected_package_groups` doldurulmalı +- `InstallExtraPackagesJob` kuyruğa alınmalı + +`#[allow(dead_code)]` **yalnızca bu üç dormant modüle** ve **yalnızca +belgelenmiş kasıtlı uyku için** konmuştur. Modül dışındaki taze ölü kod +yine uyarı üretir. + +### Ekran yöneticisi tespiti (çalışma zamanında) +`ConfigureAutologinJob` DM'i **seçmez, tespit eder**: +`detect_display_manager()` → `/usr/bin/{sddm,lightdm,gdm}` yoksa yapılandırma +dizini. Bu iş `CopyFilesJob`'dan sonra çalıştığı için `mount` doludur. + +> Önceden `state.display_manager`'a (GlobalState'in **sabit `"sddm"` +> varsayılanı**) göre dallanılıyordu. ISO lightdm kullanıyorsa +> `lightdm.conf`'a dokunulmuyor, `sddm.conf` yazılıyor ve otomatik giriş +> sessizce çalışmıyordu. + +`ConfigureAutologinJob` ayrıca: +- sddm config dizini: `/usr/lib/sddm/sddm.conf.d` yoksa `/etc/sddm.conf.d` + denir; ikisi de yoksa **hata** (sessizce yanlış yere yazmak yerine) +- `session_desktop_file()` eşlemesini **tüm DM'lerde** kullanır + (lightdm `autologin-session=plasma` yazıyordu; `.desktop` dosyası + adı bekler) +- DM bulunamazsa **hata** verir, kullanıcıya "elle yapılandırın" + diyebilmeli + +--- + +## Mimari + +``` +egui main thread ──thread::spawn──► tokio::Runtime::new() + └─ block_on(JobQueue::run_all) + └─ Job::run(&UiSender) ──mpsc──► egui +egui frame loop ◄──try_recv()──────────────────────────────────────┘ +``` + +- `src/steps/*` — saf UI, `InstallerStep` trait'i +- `src/jobs/*` — `async`, `Job: Send + Sync`, `&self` (immutable) +- `GlobalState` job thread'leriyle **paylaşılmıyor**; `clone()` edilip + `JobQueueConfig` POD'una konuyor. `Arc>` yok. + +### `StepRole` — rol artık konumsal değil +`InstallerStep::role()` → `Normal | Execution | Finish`. +Daha önce `main.rs` rolü `cur == n_steps - 2` ile **tahmin** ediyordu; +yeni adım eklemek bu tespiti sessizce kaydırıyordu. `main.rs`'de 4 test +var, biri "Execution ÖNÜNE adım eklenince rol algısı bozulmuyor". + +### Hata tipi +Tüm projede `Result<(), String>`. `thiserror` yok, hata zinciri yok. +Job log satırları Türkçe hardcoded — İngilizce kullanıcı Türkçe hata görüyor. + +--- + +## Çoklu Disk Manuel Bölümleme + +### `CustomPartition` alanları (`src/installer.rs`) +- `disk`: bölümün ait olduğu disk ("/dev/sda") — gruplama ve **her + kapasite/slot hesabı** bununla yapılır +- `orig_device`: lsblk'tan gelen fiziksel cihaz adı; **boş = kullanıcı + tanımı yeni bölüm**. Silme/işaret mantığı buna dayanır. +- `delete: bool`: eski Yali `OperationDestroyDevice` karşılığı + +### ⭐ Bölüm numaralandırması: `plan_disk_layout` (TEK KAYNAK) + +**En kritik bulgu bu oturumdandır — veri kaybı düzeltildi.** + +Bölüm numarası iki ayrı yerde bağımsız hesaplanıyordu: +- UI: `assign_partition_numbers` → "en küçük boş slot" +- Job: `mkpart` + `part.device` okuması + +**parted davranışı:** `parted rm N` sonrası kernel, bölümleri **başlangıç +offset'ine göre** sıralayıp 1'den numaralandırır. `mkpart` ile oluşturulan +bölüm de aynı sıraya girer. + +**Uyumsuzluğun gerçekleştiği senaryo:** +``` +sda1 0–100 korunuyor +sda2 100–200 SİLİNECEK → 100 MB boşluk +sda3 200–30200 korunuyor +disk sonu: 10000 MB boş +yeni: 5000 MB + +UI : sda2 silinince slot 2 boşalır → yeni = sda2 +Disk: 100–200 boşluğu 5000 MB'ye SIĞMAZ → first-fit diskin sonuna yazar + kernel sırası: sda1, sda2(eskisi 3), sda3(YENİ) +Sonuç: UI "yeni = sda2" der, diskte yeni = sda3. FAZ C mkfs'i yanlış + aygıta uygular → kullanıcının KORUMAK İSTEDİĞİ bölüm bozulur. +``` + +**Çözüm:** `plan_disk_layout(disk, total_mb, physical, destroyed, creates)` +— saf, test edilebilir fonksiyon. Diskin **tamamını** (fiziksel + yeni) +görüp numaralandırır ve şunları döndürür: +- `Vec`: her yeni bölümün konumu + **gerçek** slot numarası +- `Vec<(u32, String)>`: silmeden sonra **KAYAN** fiziksel bölümlerin + eski numarası → yeni aygıt yolu + +FAZ B bu planı kullanır, `device_map` doldurur, FAZ C **gerçek aygıtı** +kullanır (kayma varsa loglar). `assign_partition_numbers` artık yalnızca +**UI önizlemesi** içindir — doğruluk kaynağı değil. + +> `disk_free_regions_mb` (eski, ayrı kopya) **silindi**. `disk_total_mb` +> ve `read_physical_extents` eklendi; artık diskin gerçek boyutu sysfs'ten +> okunuyor (önce son bölümün bitişinden tahmin yürütülüyordu). + +### `assign_partition_numbers` +Disk bazlı `HashMap>` ile **bağımsız** çalışır; +sda1 ile sdb1 çakışmaz. + +> Eski test `renumber_keeps_disks_independent` **TUUTOLOJİK'ti**: hep +> fiziksel bölüm kullanıyordu, fonksiyon no-op çalışıyordu; global +> (disk-suz) bir uygulama da testi geçerdi. `multidisk_tests` içinde +> gerçek çapraz-disk yolunu (yeni tanım) sınayan testler var. + +### `CustomPartitionJob` fazları (`jobs/partition.rs`) +1. **FAZ A**: `delete=true` → `parted rm N`, büyükten küçüğe +2. **FAZ B**: `plan_disk_layout` ile yerleşim + numaralandırma, sonra `mkpart` +3. **FAZ C**: `device_map` üzerinden **gerçek** aygıta mkfs (LUKS akışı korundu) +- Sabit boyutlular ÖNCE, sembolikler SONRA (`sort_by_key(size==0)`) +- İşlemi olmayan disklere hiç girilmez (`⏭️ ... korunuyor`) + +### UI (`src/steps/partition.rs`) +- **Ekleme diyaloğunda disk seçici var** (`ManualState::add_disk`). + Önceden yeni bölümün diski `state.selected_disk`'e sabitlenmişti ve + diyalogda disk kontrolü yoktu — `/home`'u sdb'ye koymak için + kurulumun GRUB hedefini değiştirmek gerekiyordu. +- **Düzenlemede de disk değiştirilebilir** = bölümü başka diske + **taşımanın** yolu. Taşınırsa `orig_device` temizlenir (yoksa job + eski diske işlem yapmayı sürdürürdü). +- Tablo `TableRow::Part | TableRow::FreeSpace` enum'u ile kurulur; HER disk + grubu kendi sütun başlıklarını çizer (`draw_partition_table_header`). +- **Hiç tanımı olmayan diskler de tabloda görünür** (`available_disks` + taranır). Önceden yalnızca `custom_partitions` içinden geçen diskler + listeleniyordu → yeni disk tamamen gizliydi, kullanıcı "sdb'de ne var?" + diye bakamıyordu. +- Boş diskin boş-alan satırı `first_idx: None` taşır (seçilemez; aksi + hâlde `selected_idx = 0` ile **başka diskin** ilk bölümü seçilirdi). +- Silinmek işaretli bölümler ayrı satır çizmez; İLK silinenin konumunda + TEK "Boş Alan" satırında birleşir (GParted tarzı). +- Varsayılan öneriler (EFI/root/swap) **aktif diskin durumuna** göre verilir. +- "Kalan alan" SEMBOLİKTİR (size_mb=0): kaydetme anında sayıya çevrilmez. + +### `selected_disk` hâlâ 3 yerde kullanılıyor +1. Tablo vurgusu + `manual_dual_bars` hangi diski çizsin +2. Diyaloğun varsayılan hedefi +3. `build_custom_job_queue` girdisi → `InstallGrubJob.disk` + +Bu yüzden dış ComboBox'un etiketi **"Aktif disk"** + açıklayıcı ipucu +("Kurulum Yapılacak Diski Seçin" yanlış anlam çağrışımı yapıyordu). +`bootloader_device` varsayılanı `selected_disk` değil, **kökün olduğu disk**. + +--- + +## Güvenlik Düzeltmeleri (P0) + +### Parola asla argv'ye geçmez +`sh -c "echo 'user:pass' | chpasswd"` deseni **KALDIRILDI** +(`jobs/users.rs`). Parola `/proc//cmdline` üzerinden okunabiliyordu +ve `'`/`$(...)` içeren parola komutu bozuyordu. + +Doğru desen: **`set_password_via_chpasswd()`** — `chroot chpasswd +-c SHA512` komutuna stdin pipe ile yazılır. `jobs/partition.rs:: +run_luks_format` ile birebir aynı desen. Yazılan veri yazımdan sonra +sıfırlanır. + +> **Kural:** parola, LUKS anahtarı, herhangi bir gizli değer +> `format!` ile komut satırına gömülmez. stdin pipe kullanılır. + +### LUKS çekirdek parametresi +`cryptdevice=UUID=:cryptroot` **geçerli bir söz dizimi değildi** ve +kök bölüm `is_uefi` ile (3|2) tahmin ediliyordu — manuel modda yanlış +(assign_partition_numbers'tan gelir) ve kök başka diskteyse hiç doğru +değildi. + +Artık `luks_backing_device()` (`cryptsetup status` → `device:` satırı) ile +mapper'ın arkasındaki **gerçek** aygıt bulunur, blkid ile LUKS başlık +UUID'si alınır, dracut (`rd.luks.uuid=luks-…`) + mkinitcpio +(`cryptdevice=…`) biçimleri birlikte yazılır. UUID boşsa hata. + +`CRYPTROOT_NAME` sabiti: "cryptroot" 5 yerde hardcoded'dı, tek kaynağa bağlandı. + +### KRİTİK: parolasız LUKS reddediliyor +`encrypt_root=true` + boş parola → kök düz ext4 formatlanıyor, +`MountPartitionsJob` `/dev/mapper/cryptroot`'u mount etmeye çalışıp +kurulumu öldürüyordu. `PartitionJob` başında `Err` ile reddediliyor. + +--- + +## Hata Yönetimi + +### Temizlik HER ZAMAN çalışır +`JobQueue::cleanup` + `with_cleanup(...)`: liste başarıda da hatada da +koşar. Temizlik de hata verirse bu hatalar asıl hataya **eklenip** +kullanıcıya "elle ne yapılacak" listesi olarak gösterilir. + +`EmergencyCleanupJob` (`src/jobs/cleanup.rs`) sırasıyla: +1. `mount` altındaki tüm dosya sistemleri +2. LVM: `vgchange -an` +3. LUKS: `cryptsetup close` (yalnızca **hedef diskin** mapper'ları) +4. `swapoff` + +`close_crypt_mappers` yalnızca hedef diske ait olanları kapatır — +canlı ortamın kendi şifreli bölümlerine dokunmaz. + +### unmount artık tüm ağacı tarar +`UnmountBindJob` elle yazılmış sabit liste (`proc`, `sys`, `dev`, +`boot/efi`) kullanıyordu; manuel düzende `/home`, `/var`, `/boot` +bağlı kalıyordu. Artık `mounted_paths_under()` `/proc/self/mountinfo` +okuyor ve `mount/` altındaki **her şeyi** en derinden yüzeye çözüyor. + +> `unescape_mount_field()` mountinfo'daki `\0NNN` oktal kaçışlarını +> çözer; boşluk içeren mountpoint'ler ("My Disk") eşleştirilemezdi. + +### Kritik hatalar artık yutulmuyor +- `RunComarJob` tamamen yorum satırıydı → `pisi configure-pending` + **hiç çalışmıyordu**. Geri getirildi. +- `ldconfig` / `update-environment` hataları loglanıp yutuluyordu. + `update-environment` init finalizasyonudur: yutulursa kurulum + "başarılı" görünür ama sistem açılmaz. Artık **fatal**. +- `CleanupLiveJob`'daki 10 `let _ =`: depo tanımları sessizce + başarısız olabiliyordu. Artık **fatal**. + +--- + +## partition "MB" tuzağı (KRİTİK) + +parted `"MB"` sonekini **ondalık** (10^6) okur, bizim hesaplar **ikili** +(2^20). `mkpart 3944MB` → sektör 7703125 (hizasız) → "Becerebildiğimiz +buna en yakın konum..." hatası. + +> parted'a **daima** `"{}MiB"` geç. Tamsayı MiB = 2048 sektörün katı → +> hizalama hatası çıkmaz. UI'da kullanıcıya MB gösterilir ama parted +> argümanı asla "MB" **olmamalı**. + +Bu tuzak iki kez yaşandı: `7209d58`'de düzeltildi, `22de7d5`ten sonra +kök bölümde `"{}MB"` olarak **geri gelmişti**. `d161556` ile düzeltildi ve +nedeni yorumla sabitlendi. Log bile "MiB" derken argüman "MB" gönderiyordu. + +--- + +## Diğer Kalıcı Kurallar + +- MB dönüşümleri **tek bölme**: `x / 1_048_576` (çift `x/1024/1024` + hassasiyet kaybı yapardı) +- Simge fontu: `assets/remixicon.ttf` fallback (`ui/theme.rs setup_fonts`). + **Kutu (tofu) görürsen** karakter fontta yok. `fontTools` ile cmap kontrol: + EB7B check, EA6B arrow, EC28 trash, EA13 add, EFE0 pencil, EECD lock, + ECA1 error, EDFB hdd, ECB5/B7 eye, F4C6 close. + **Emoji kullanma** — `NotoColorEmoji` yüklü değil (yorum satırında). +- **Kare başına alt süreç çalıştırma.** egui `show()` her karede + çağrılır (~60 Hz). `blkid`, `nmcli` gibi ağır komutlar `on_enter`'a + taşındı, sonuç alanlarda saklanıyor, `refresh_*()` ile tazeleniyor. +- Locale: `locales/` altında yalnızca `tr.toml` ve `en.toml` **var**. + `set_locale("de")` hata vermez, sessizce kabul edilir ve `t!()` + karşılığı olmayan her anahtar için **anahtarın kendisini** döndürür — + arayüz çıplak anahtarlarla dolar. `funct::sanitize_locale()` her + `set_locale` çağrısından önce kullanılır. GeoIP sadece + `language_for_country()` ile **gerçekten var olan** dillere geçer. +- **TOML düzenleme uyarısı:** `locales/*.toml` satır sonuna yapışan + düzenlemelerle bozuldu ve `rust_i18n` proc macro derlemeyi durdurdu. + Değiştirdikten sonra `tomllib` ile doğrula. +- Bağımlılık: `zbus` (`Cargo.toml`) **hiç kullanılmıyor** — projede tek + D-Bus/COMAR çağrısı yok, tüm sistem etkileşimi shell üzerinden. + +--- ## Test / Derleme -- `cargo check` + `cargo test` (22 birim testi; partition modülü ağırlıklı). -- VM'de denemek: ISO'yu boot edip manuel bölümlemede sdb üzerindeki senaryolar: - sil→boş-alan birleşimi, geri al, kalan alan, farklı diske bölüm ekleme. -## ✅ Düzenlenmiş Manuel Partition Sorunları (18 Eylül 2026) +``` +cargo check --all-targets : 0 hata, 0 uyarı +cargo test : 76/76 (13 test modülü) +cargo clippy : ~77 uyarı, tamamı stil (collapsed_if, replace zinciri) +``` -Bu gün, manual partition modundaki 5 kritik sorun düzeltilmiştir: +Bu oturumda **1 → 76** test. Test modülü olmayan dosyalar (`users.rs`, +`location.rs`, `rescue.rs`, `funct.rs`, `autoinstall/mod.rs`, `main.rs`) +içine modüller eklendi. Çoklu test modülü paylaşılan yardımcıları +`steps/partition.rs::testutil` altındadır (`disk()`, `part()`). -1. **`manual_capacity_error` birim tutarlılığı** (`src/steps/partition.rs`): - - `cap` → `cap_mb`, `fixed` → `fixed_mb` değişken isimleri standardized - - `d.size_bytes / 1_048_576` (MiB) ile `defs.iter().map(|p| p.size_mb).sum()` consistently binary MiB (2^20) hesaplaması - - `cargo test` ve `cargo check` passed +### 🧪 ISO TESTİ BEKLENİYOR (kullanıcı yapacak) +`plan_disk_layout` mantığı testlerle kanıtlandı ama **gerçek `parted` +çıktısıyla masaüstünde karşılaştırılmadı**. ISO'yu boot edip şu +senaryoları dene: -2. **`disk_free_regions_mb` delete flagı yönetimi** (`src/jobs/partition.rs`): - - `.filter(|p| p.delete && !p.orig_device.is_empty())` → `.filter(|p| p.delete)` - - Tüm `delete=true` flag'li bölümler (incl. newly defined with empty orig_device) free alan hesaplamasından exclude ediliyor +**Çoklu disk (asıl hedef):** +1. İki disk bağlı: sda + sdb +2. Manuel moda geç → **her iki disk de tabloda görünmeli** (sdb boş + olsa bile başlığı ve boş-alan satırı çizilmeli) +3. sda'da kök + EFI, sdb'de `/home` → **diyalogdaki disk seçiciyle** +4. "Yeni Bölüm" → hedef disk sdb'yi seç → mountpoint `/home` +5. Özet ekranında: iki disk, başlıklarda kapasite, altlarında "boş: …", + kök diski "[kök]" etiketiyle işaretli -3. **`validate_manual` ekstra validasyonlar** (`src/steps/partition.rs`): - - **Duplicate mountpoint kontrolü**: Aynı mountpoint'ta iki live bölüm tanımlı mı? → hata döndürür - - **Swap boyut validasyonu**: 512MB minimum, 8GB maksimum kontrolü eklendi - - **Size 0 partition uyarısı**: Boyut 0 ama mountpoint boşsa uyarı mesajı +**Silme + yeni bölüm (veri kaybı senaryosu):** +6. sda'da orta bir bölümü sil → "Boş Alan" satırında birleşsin +7. Aynı diske büyük bir yeni bölüm ekle (boşluğa SĞMAYACAK boyutta) +8. **Kritik:** korunan bölümün verisi sağlam kalmalı — `mkfs` yanlış + aygıya gitmemeli. Logda "bölüm numarası kaydı" mesajı çıkarsa bu + normal, "gerçek aygıt kullanılıyor" demektir. -4. **`is_complete` disk seçim kontrolü** (`src/steps/partition.rs`): - - `state.partition_plan.is_some()` → `state.selected_disk.is_some()` eklendi - - Kullanıcı disk seçmeden partition tanımları yapmış gibi görünmesini engelledi - - `is_complete` false döndürür, kullanıcıya disk seçme hatası verir +**Geçiş:** +9. Geri/İleri ile adımlar arasında gezin, bölüm tanımlarının korunduğunu doğrula +10. Önyükleyici adımında GRUB aygıtının **kökün olduğu disk** olduğunu doğrula -5. **Test doğrulaması**: - - `cargo check` - başarıyla derlendi (43.22s) - - `cargo test` - 1 test passed (parse_progress2_percent) +--- -### Etkilenen Dosyalar -- `src/steps/partition.rs` - 3 değişikling (manual_capacity_error, validate_manual, is_complete) -- `src/jobs/partition.rs` - 1 değişiklik (disk_free_regions_mb delete flagı) +## Bilinen Açıklar / Yapılacaklar -### Bilinen Açıklar / Yapılacaklar Güncellemesi -- [x] `manual_capacity_error` sorunu çözüldü - birim tutarlılığı sağlandı -- [ ] `manual_capacity_error` yalnızca sabit boyutları kontrol eder; LVM PV/LV toplamları ayrıca doğrulanmalı (hala open) -- [ ] Silinmek işaretli bölüm bir VG'nin PV'siyse SetupLvmJob tarafında kontrol yok -- [ ] Otomatik mod (erase disk) hâlâ tek disk; çoklu otomatik plan yok -- [ ] Debug amaçlı kalan `eprintln!` satırları temizlenebilir +### Yüksek öncelik +- [ ] **ISO testi yapılmadı** (yukarıdaki kontrol listesi) +- [ ] `plan_disk_layout` gerçek `parted` ile doğrulanmadı +- [ ] LVM VG'ye PV ataması **tüm disklerdeki tüm PV'ları** alıyor, + disk başına değil; `used_mb_on_disk` ile birlikte düzeltilmeli +- [ ] Silinmek işaretli bölüm bir VG'nin PV'siyse `SetupLvmJob` + tarafında kontrol yok +- [ ] `VolumeGroup.pv_devices` bir PV silinince bayat kalıyor; + LVM UI'ı `has_lvm_pvs` filtresi `delete` dikkate almadığı için + görünür kalıyor +- [ ] BIOS `device.map` `/dev` **alfabetik** sıraya göre yazılıyor; + firmware sırası ile aynı olmayabilir → çoklu diskte BIOS boot kırılgan +- [ ] `manual_capacity_error` sembolik (`size_mb == 0`) tanımları + hesaba katmıyor → `fixed == cap` geçiyor, kurulumda "yeterli boş + alan yok" ile düşüyor + +### Orta öncelik +- [ ] `available_disks` `< 4 GB` diski tamamen gizliyor (ComboBox'ta yok, + taranmıyor, kapasite bilgisi yok) +- [ ] `disk_size_mb` bilinmeyen disk için 0 döndürüyor → boyut slider'ı + kullanılamaz hale geliyor +- [ ] `disk_free_regions_mb`'in eski `SECTOR: u64 = 512` varsayımı + 4Kn (advanced format) disklerde 8× yanlış boyutlar. sysfs + `queue/logical_block_size` okunmalı. (Yeni kod hâlâ 512 varsayıyor.) +- [ ] `UnmountBindJob` artık tüm ağacı tarıyor ama `EmergencyCleanupJob` + yalnızca `custom_partitions`'dan gelen aygıtları biliyor +- [ ] `rescue.rs`: `pisi takeback` **senkron** çalışıyor (egui thread'i + donuyor); başarısız `mount` başarı diye işaretleniyor +- [ ] Hata tipi: `thiserror` ile `InstallError` enum'ı (≥10 varyant) +- [ ] `is_complete` → `Result<(), Vec>` veya ayrı + `validation_error()`; hatayı gösterme kanalı hâlâ dolambaçlı +- [ ] 51 `let _ =` sessiz hata yutma (42'si `jobs/`), çoğu yorumlanmış + değil +- [ ] `theme.rs`: paletler 4 yerde çelişkili; `branding.toml [theme]` + deserialize ediliyor ama **hiç okunmuyor**; `slides.icons` ve + `interval_secs` yok sayılıyor +- [ ] `setup_fonts` her tema değişiminde 5+ sistem fontu senkron okuyup + atlası yeniden rasterize ediyor +- [ ] Kabuk betiği olarak gömülü 120 satırlık GRUB mantığı + (`bootloader.rs::30_uefi-firmware`), test yok +- [ ] `grub2-mkconfig` hedef sistemin kendi betiğini `sed` ile yamıyor, + `2>/dev/null` ile çalışıyor, `let _ =` ile yutuluyor → süreç + ortada ölürse kurulu sistem yamalı kalıyor +- [ ] `is_mount_point` `/proc/mounts` okurken `\040` kaçışlarını çözmüyor +- [ ] Debug `eprintln!` / `println!` satırları (GUI uygulamasında) +- [ ] ~100 ölü i18n anahtarı (slayt + eski ekran anahtarları) + +### Bilinçli olarak yapılmadı +- Otomatik mod (erase disk) çoklu disk değil — tek disk. İstenmedi. +- Bölüm küçültme (shrink) — yok, "sil + yeniden oluştur" yaklaşımı + kullanılıyor (eski Yali ile aynı). +- Lisans ekranı, ekran yöneticisi seçimi, paket seçimi — squashfs + akışında anlamsız, dormantanmış durumda. + +--- + +## Dosya Haritası (değişmiş olanlar) + +| Dosya | Son durum | +|---|---| +| `src/jobs/partition.rs` | `plan_disk_layout`, `PhysicalExtent`, `PlannedCreate`, `disk_total_mb`, `read_physical_extents`, `device_map`; `disk_free_regions_mb` silindi | +| `src/jobs/cleanup.rs` | **YENİ** — `EmergencyCleanupJob` | +| `src/steps/partition.rs` | `add_disk` + disk seçici, `validate_manual_on`, boş disk satırları, `multidisk_tests`, `testutil` | +| `src/jobs/users.rs` | `set_password_via_chpasswd` (stdin pipe) | +| `src/jobs/bootloader.rs` | `CRYPTROOT_NAME`, `luks_backing_device`, `mounted_root_device` | +| `src/jobs/finish.rs` | `RunComarJob` geri geldi; `ldconfig`/`update-environment`/depo fatal | +| `src/jobs/mod.rs` | `JobQueue::cleanup`, `mounted_paths_under`, `unescape_mount_field`, `open_crypt_mappers`, `auto_mode_partitions` | +| `src/installer.rs` | `StepRole`, `license_accepted`, `rescue_available` | +| `src/autoinstall/mod.rs` | `[system]` bölümü, `SystemConfig` (elle `Default`!) | +| `src/funct.rs` | `AVAILABLE_LANGUAGES`, `sanitize_locale` | +| `src/lib.rs` | **SİLİNDİ** — çift crate root, `locales/` iki kez gömülüyordu | +| `src/steps/display_manager.rs`, `netinstall.rs`, `license.rs` | dormant (derleniyor, sihirbaza bağlı değil) |