feat(config): migrate 모듈 스캐폴딩 + toml_edit 의존성
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -4371,6 +4371,7 @@ dependencies = [
|
|||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"toml",
|
"toml",
|
||||||
|
"toml_edit 0.22.27",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ serde = { workspace = true }
|
|||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
|
toml_edit = "0.22"
|
||||||
dirs = "5"
|
dirs = "5"
|
||||||
# p9-fb-05: warn-log when current_dir() fails (chroot, deleted cwd)
|
# p9-fb-05: warn-log when current_dir() fails (chroot, deleted cwd)
|
||||||
# during workspace.root resolution.
|
# during workspace.root resolution.
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
mod paths;
|
mod paths;
|
||||||
|
pub mod migrate;
|
||||||
pub use paths::{expand_path, expand_path_with_base};
|
pub use paths::{expand_path, expand_path_with_base};
|
||||||
|
|
||||||
/// Signal: `Config::from_file` / `Config::load` failed due to missing path,
|
/// Signal: `Config::from_file` / `Config::load` failed due to missing path,
|
||||||
|
|||||||
47
crates/kebab-config/src/migrate.rs
Normal file
47
crates/kebab-config/src/migrate.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
//! config.toml 마이그레이션 엔진 (순수 변환, I/O 없음).
|
||||||
|
//!
|
||||||
|
//! 두 메커니즘: (1) reconciliation — default 구조에 있고 사용자 파일에
|
||||||
|
//! 없는 섹션/키를 주석과 함께 추가. (2) step 체인 — schema_version 기반
|
||||||
|
//! non-additive 변환(deprecated 제거 등). 자세한 계약은 spec
|
||||||
|
//! `docs/superpowers/specs/2026-05-31-config-migration-design.md`.
|
||||||
|
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
/// 현재 바이너리가 이해하는 config 스키마 버전. 마이그레이션 완료 시
|
||||||
|
/// 사용자 파일의 `schema_version` 을 이 값으로 stamp 한다.
|
||||||
|
pub const CURRENT_SCHEMA_VERSION: u32 = 2;
|
||||||
|
|
||||||
|
/// 한 번의 마이그레이션에서 발생한 개별 변경.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||||
|
pub struct MigrationChange {
|
||||||
|
pub kind: ChangeKind,
|
||||||
|
/// dotted path, 예: `ingest.expansion`, `workspace.include`.
|
||||||
|
pub path: String,
|
||||||
|
/// 사람·wire 용 한 줄 설명.
|
||||||
|
pub detail: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum ChangeKind {
|
||||||
|
AddedSection,
|
||||||
|
AddedKey,
|
||||||
|
RemovedDeprecated,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 마이그레이션 결과 요약(순수 변환 단계 산출). I/O 계층이 backup_path
|
||||||
|
/// 등을 채워 wire 로 내보낸다.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||||
|
pub struct MigrationOutcome {
|
||||||
|
pub from_schema_version: u32,
|
||||||
|
pub to_schema_version: u32,
|
||||||
|
pub changes: Vec<MigrationChange>,
|
||||||
|
/// 변환 후 직렬화된 새 문서 텍스트(멱등 시 입력과 동일).
|
||||||
|
pub new_text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MigrationOutcome {
|
||||||
|
pub fn changed(&self) -> bool {
|
||||||
|
!self.changes.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user