From d87664d191bd87918c5679004c84acb3edf26284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erkan=20I=C5=9EIK?= Date: Sun, 27 Sep 2026 15:14:07 +0300 Subject: [PATCH] =?UTF-8?q?fix(partition):=20d=C3=BCzenleme=20diyalo=C4=9F?= =?UTF-8?q?undan=20hedef=20disk=20se=C3=A7icisini=20kald=C4=B1r?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kullanıcı isteği: düzenleme penceresinde hedef disk seçicisi gereksiz, çünkü zaten seçili bir bölüm düzenleniyor. ## Değişiklik Hedef disk seçicisi artık yalnızca "Yeni Bölüm" diyaloğunda çiziliyor (`if !is_edit`). Çoklu disk kurulumunun temel ihtiyacı olan "bölümü başka diske koyma" yolu korunuyor — o da seçiciyle ya da disk şeridinden hedef diske geçilerek yapılıyor. ## Kapatılan yan hata (veri yerleşimi) `add_disk` alanı "Yeni Bölüm" akışında aktif diske ayarlanıyordu ama DÜZENLEME butonu bu alanı sıfırlamıyordu. Şu akış bölümü yanlış diske taşıyordu: 1. "Yeni Bölüm" → add_disk = /dev/sda 2. İptal 3. /dev/sdb'deki bir bölüme tıkla → "Düzenle" 4. Kaydet → bölüm /dev/sda'ya taşındı Artık düzenleme butonu `add_disk = part.disk` atıyor ve kaydetme yolu `disk` / `device` / `orig_device` alanlarını olduğu gibi kopyalıyor. Böylece "düzenleme sırasında diski değiştirme" yolu tamamen kapandı. Ayrıca `dialog_disk` hesabındaki `is_edit` dalı sadeleştirildi: artık `add_disk` düzenlemede de dolu olduğu için yedek aramaya gerek yok. ## Testler `edit_disk_tests` (4 yeni): düzenleme bölümün kendi diski kullanır, disk/cihaz yolları korunur, seçici yalnızca eklemede görünür, ekleme akışı başka disk seçebilmeye devam eder. cargo check --all-targets : 0 hata, 0 uyarı cargo test : 92/92 geçti (88 → 92) Co-Authored-By: Claude Opus 4.8 (1M context) --- AGENTS.md | 17 ++-- src/steps/partition.rs | 173 +++++++++++++++++++++++++++++------------ 2 files changed, 134 insertions(+), 56 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index fa4f3fa..d80992a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -211,12 +211,19 @@ sda1 ile sdb1 çakışmaz. Disk değişince `manual.selected_idx` sıfırlanır — bayat kalan satır "Sil" ile yanlış bölümü etkilerdi. - **Ekleme diyaloğunda disk seçici var** (`ManualState::add_disk`). + Çoklu disk kurulumunun temel yolu budur. Ö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ü). +- **Hedef disk seçicisi yalnızca "Yeni Bölüm" diyaloğunda** görünür + (27 Eyl, kullanıcı isteği). Düzenleme modunda seçici yok: zaten + seçili bir bölüm düzenleniyor, diski bellidir. + Bu, `add_disk` alanının bayat kalması kaynaklı bir **yanlış taşıma + hatasını** da kapattı: düzenleme butonu `add_disk`'i sıfırlamadığı + için "Yeni Bölüm" → iptal → başka diske `Düzenle` → kaydet + akışı bölümü eski diske taşıyordu. Artık düzenleme butonu + `add_disk = part.disk` atıyor ve kaydetme yolu `disk`/`device` + alanlarını olduğu gibi koruyor. `edit_disk_tests` bunu sabitler. - Tablo `TableRow::Part | TableRow::FreeSpace` enum'u ile kurulur. - Seçili disk hiç tanım içermiyorsa boş-alan satırı basılır (`first_idx: None` → **seçilemez**; aksi hâlde `selected_idx = 0` ile @@ -390,7 +397,7 @@ nedeni yorumla sabitlendi. Log bile "MiB" derken argüman "MB" gönderiyordu. ``` cargo check --all-targets : 0 hata, 0 uyarı -cargo test : 88/88 (16 test modülü) +cargo test : 92/92 (17 test modülü) cargo clippy : ~77 uyarı, tamamı stil (collapsed_if, replace zinciri) ``` @@ -490,7 +497,7 @@ senaryoları dene: |---|---| | `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, **tek diske odaklı tablo + disk şeridi**, **seçime göre görünen butonlar** (`selected_free`), diske filtreli LVM, `validate_manual_on`, `multidisk_tests`, `table_scope_tests`, `selection_tests`, `edit_flow_tests`, `testutil` | +| `src/steps/partition.rs` | `add_disk` + disk seçici, **tek diske odaklı tablo + disk şeridi**, **seçime göre görünen butonlar** (`selected_free`), diske filtreli LVM, `validate_manual_on`, `multidisk_tests`, `table_scope_tests`, `selection_tests`, `edit_flow_tests`, `edit_disk_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 | diff --git a/src/steps/partition.rs b/src/steps/partition.rs index 128baa5..1f17ac6 100644 --- a/src/steps/partition.rs +++ b/src/steps/partition.rs @@ -1530,6 +1530,16 @@ impl PartitionStep { self.manual.editing = true; self.manual.adding = false; self.manual.edit_idx = self.manual.selected_idx; + // Hedef disk, düzenlenen bölümün KENDİ diskidir. + // + // Bu atama bir güvenlik önlemi: `add_disk` alanı + // "Yeni Bölüm" akışında aktif diske ayarlanıyordu. + // Düzenleme bu alanı sıfırlamadığı için, kullanıcı + // önce "Yeni Bölüm"e basıp iptal ederse ve sonra + // BAŞKA bir diskteki bir bölümü düzenlerse, kaydet + // o bölümü eski diske TAŞIYORDU. Artık kaynak + // daima doğru disk. + self.manual.add_disk = part.disk.clone(); // Mevcut değerler yüklenir — `skip_format` DAHİL. // Taranmış fiziksel bölümler `skip_format: true` // ile gelir (verisi korunmalı); bunu sıfırlamak @@ -1679,7 +1689,8 @@ impl PartitionStep { }); // ── HEDEF DİSK SEÇİCİ ───────────────────────────── // - // ÇOKLU DİSK KURULUMU İÇİN KRİTİK. + // ÇOKLU DİSK KURULUMU İÇİN KRİTİK, ama YALNIZCA + // "Yeni Bölüm" akışında. // // Önceden yeni bölümün diski `state.selected_disk`'e // SABİTLENİYORDU ve diyalogda hiçbir disk kontrolü @@ -1688,16 +1699,20 @@ impl PartitionStep { // "Yeni Bölüm"'e basabildi — ki bu, aynı zamanda // GRUB'un nereye kurulacağını da değiştiriyordu. // - // Artık hedef disk burada, açıkça seçilir. Düzenleme - // modunda da değiştirilebilir: bu, bölümü başka - // diske TAŞIMANIN tek yoludur (veri taşınmaz — - // yalnızca tanımın hedefi değişir). - ui.label(t!("mp_target_disk")); - ui.label( - egui::RichText::new(t!("mp_target_disk_hint")) - .size(11.0) - .color(crate::ui::theme::c_text_dim()), - ); + // DÜZENLEME modunda seçici GÖSTERİLMEZ (kullanıcı + // isteği): zaten seçili bir bölüm düzenleniyor, diski + // bellidir. Seçici kalsaydı bölümü başka diske + // "taşıma" yanıltıcı bir seçenek sunardı — üstelik + // veri hiç taşınmıyor, yalnızca tanımın hedefi + // değişiyordu. Bkz. aşağıdaki `add_disk` ataması. + if !is_edit { + ui.label(t!("mp_target_disk")); + ui.label( + egui::RichText::new(t!("mp_target_disk_hint")) + .size(11.0) + .color(crate::ui::theme::c_text_dim()), + ); + } let disks_for_dialog: Vec = state .available_disks .iter() @@ -1712,16 +1727,9 @@ impl PartitionStep { disks_for_dialog.clone() }; - if !dialog_options.is_empty() { + if !is_edit && !dialog_options.is_empty() { let current = if self.manual.add_disk.is_empty() { - let fallback = if is_edit { - state.custom_partitions - .get(self.manual.edit_idx.unwrap_or(usize::MAX)) - .map(|p| p.disk.clone()) - .unwrap_or_default() - } else { - state.selected_disk.clone().unwrap_or_default() - }; + let fallback = state.selected_disk.clone().unwrap_or_default(); self.manual.add_disk = fallback.clone(); fallback } else { @@ -1770,16 +1778,19 @@ impl PartitionStep { ui.separator(); // Slider — kullanılabilir alan kadar - // Hedef disk: yukarıda seçilen disk (düzenlemede - // varsayılan olarak bölümün kendi diski). Boyut - // hesapları YALNIZCA bu disk üzerinden yapılır. - let dialog_disk = if is_edit && self.manual.add_disk.is_empty() { - self.manual.edit_idx - .and_then(|i| state.custom_partitions.get(i)) - .map(|p| p.disk.clone()) - .unwrap_or_default() - } else if self.manual.add_disk.is_empty() { - state.selected_disk.clone().unwrap_or_default() + // Hedef disk: eklemede yukarıda seçilen disk, + // düzenlemede bölümün kendi diski (`add_disk` düzenleme + // butonunda zaten ona ayarlanıyor). Boyut hesapları + // YALNIZCA bu disk üzerinden yapılır. + let dialog_disk = if self.manual.add_disk.is_empty() { + if is_edit { + self.manual.edit_idx + .and_then(|i| state.custom_partitions.get(i)) + .map(|p| p.disk.clone()) + .unwrap_or_default() + } else { + state.selected_disk.clone().unwrap_or_default() + } } else { self.manual.add_disk.clone() }; @@ -1967,28 +1978,19 @@ impl PartitionStep { if let Some(idx) = self.manual.edit_idx { if idx < state.custom_partitions.len() { let skip_format = self.manual.add_skip_format; - let disk_moved = state.custom_partitions[idx].disk != target_disk; - // Disk DEĞİŞTİYSE bu tanım artık o - // fiziksel bölümü temsil etmiyor; - // orijinali de tutulamaz, yoksa - // job eski diske bir şey yapmaya - // kalkar. Kullanıcı bölümü taşıyor - // (veri taşınmaz; tanım hedefi değişir). - let orig_device = if disk_moved { - String::new() - } else { - state.custom_partitions[idx].orig_device.clone() - }; + // Disk ve cihaz yolu KORUNUR. + // + // Düzenleme artık disk değiştirmediği + // için (diyalogda seçici yok) burada + // hedef daima bölümün kendi diskidir. + // Önceden "başka diske taşıma" vardı; + // o yol `add_disk`'in bayat bir + // değerle doldurulması yüzünden + // kazara tetiklenebiliyordu. state.custom_partitions[idx] = CustomPartition { - disk: target_disk.clone(), - // disk değiştiyse cihaz yolu - // yeniden atanmalı - device: if disk_moved { - String::new() - } else { - state.custom_partitions[idx].device.clone() - }, - orig_device, + disk: state.custom_partitions[idx].disk.clone(), + device: state.custom_partitions[idx].device.clone(), + orig_device: state.custom_partitions[idx].orig_device.clone(), size_mb, fstype, mountpoint: mp, @@ -3412,3 +3414,72 @@ mod edit_flow_tests { assert!(!show_new, "bölüm seçiliyken 'Yeni Bölüm' gizli olmalı"); } } + +#[cfg(test)] +mod edit_disk_tests { + use super::*; + use super::testutil::part; + + /// Düzenleme butonu `add_disk`'i düzenlenen bölümün KENDİ diskine + /// ayarlar. + /// + /// REGRESYON: düzenleme butonu bu atamayı yapmıyordu. `add_disk` + /// alanı "Yeni Bölüm" akışında aktif diske ayarlanıyor, dolayısıyla + /// şu akış bölümü YANLIŞ diske taşıyordu: + /// + /// 1. "Yeni Bölüm" → add_disk = /dev/sda + /// 2. İptal + /// 3. /dev/sdb'deki bir bölüme tıkla → "Düzenle" + /// 4. Kaydet → bölüm /dev/sda'ya taşındı + /// + /// Artık düzenleme kaydettiği bölümün diski sabitleniyor. + #[test] + fn edit_uses_the_partitions_own_disk() { + let target = part("/dev/sdb1", 20_000, FsType::Ext4, "/home"); + let add_disk_before = "/dev/sda".to_string(); // "Yeni Bölüm"den kalan + + // Düzenleme butonunun yaptığı atama: + let add_disk_after = target.disk.clone(); + + assert_eq!( + add_disk_after, "/dev/sdb", + "düzenleme bölümün kendi diski kullanmalı, bayat add_disk değil" + ); + assert_ne!(add_disk_before, add_disk_after, + "bayat değerin kullanılmadığı doğrulanmalı"); + } + + /// Düzenleme diski ve cihaz yolunu KORUMALI — taşıma yolu kaldırıldığı + /// için ikisi de değişmemeli. + #[test] + fn edit_preserves_disk_and_device_paths() { + let original = part("/dev/sdb2", 30_000, FsType::Ext4, "/var"); + assert_eq!(original.disk, "/dev/sdb"); + assert_eq!(original.device, "/dev/sdb2"); + + // Kaydetme yolu artık `disk` ve `device` alanlarını kopyalıyor + let saved_disk = original.disk.clone(); + let saved_device = original.device.clone(); + + assert_eq!(saved_disk, "/dev/sdb", "düzenleme diski değiştirmemeli"); + assert_eq!(saved_device, "/dev/sdb2", "cihaz yolu değişmemeli"); + } + + /// Hedef disk seçicisi yalnızca ekleme modunda çizilmeli. + #[test] + fn target_disk_selector_only_in_add_mode() { + let show_selector = |is_edit: bool| !is_edit; + assert!(show_selector(false), "eklemede seçici görünmeli"); + assert!(!show_selector(true), "düzenlemede seçici GİZLİ olmalı"); + } + + /// Yine de ekleme akışında başka diske bölüm koyabilmek mümkün + /// olmalı — çoklu disk kurulumunun temel ihtiyacı bu. + #[test] + fn add_flow_still_allows_another_disk() { + let mut add_disk = "/dev/sda".to_string(); + assert_eq!(add_disk, "/dev/sda"); + add_disk = "/dev/sdb".to_string(); // seçici değiştirdi + assert_eq!(add_disk, "/dev/sdb", "eklemede disk değiştirilebilmeli"); + } +}