fix(partition): düzenleme diyaloğundan hedef disk seçicisini kaldır

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) <noreply@anthropic.com>
This commit is contained in:
Erkan IŞIK
2026-09-27 15:14:07 +03:00
parent 332d5a787f
commit d87664d191
2 changed files with 134 additions and 56 deletions
+12 -5
View File
@@ -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 |
+122 -51
View File
@@ -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<String> = 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");
}
}