Files
networkSetup/docs/changes/2026-11-13-offline-setup-replace.md
T
jychoi4andClaude Opus 5.5 4964f2ced4 feat: add prerequisites, offline prerequisite setup and version tabs
- EXE versions: prerequisite list with the built-in catalog, custom
  installers, download link checks and install file analysis; entries
  are added by the user (no automatic adding), one "추가" dialog with
  기본 목록 / 직접 추가 tabs
- offline prerequisite setup: single exe made from PrerequisiteSetup.exe
  (Windows task dialog, no prerequisites) plus every installer, hash
  checked before, while and after appending; optional WebView2 Runtime
  chosen in the save dialog; replaces an existing file only after the
  user agrees (CLI --replace)
- desktop: progress popup with 생성위치 열기, save dialog fix for
  verbatim paths, EXE 서명 and 설치파일 생성 as version tabs, start
  screen 도구 › 서명하기 placeholder
- CLAUDE.md: results are overwritten only with the user's consent
- test kit and scripts for Windows Sandbox and Hyper-V checks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 16:26:24 +09:00

42 lines
4.9 KiB
Markdown

# 오프라인 설치기 덮어쓰기
2026-11-13. **오프라인용 설치기 생성**이 같은 이름의 기존 파일을 사용자가 동의했을 때 새 설치기로 바꾸게 했다. 기존에는 저장 창에서 기존 파일을 고르면 `OutputExists`로 멈췄다. 같은 날 "결과는 덮어쓰지 않는다" 원칙을 "결과는 사용자가 판단해 동의할 때만 덮어쓴다"로 바꿨다. 이 변경은 MSIX 빌드 결과와 내보내기에 동의 절차를 만들지 않았고, 프로젝트·소스 파일의 덮어쓰기를 허용하지 않는다.
## 결정
- 사용자 요청: "덮어 쓰기 가능하게 해줘"(`OutputExists` 오류 화면과 함께).
- 원칙 변경: "결과는 사용자 판단에 의해 덮어쓰기 가능하게 해"(사용자 결정). `CLAUDE.md`의 "결과는 덮어쓰지 않는다"를 "결과는 사용자가 판단해 동의할 때만 덮어쓴다"로 바꿨다. 동의가 없으면 기존 결과를 거부하고, 동의해도 새 결과가 완성된 뒤에 한 번에 바꾼다. 지금 동의 절차가 있는 것은 오프라인 설치기뿐이다.
- 동의는 사용자가 직접 한다. GUI는 Windows 저장 창이 기존 파일을 바꿀지 묻고(`FOS_OVERWRITEPROMPT`를 명시적으로 켬), 동의해야 그 경로를 돌려준다. CLI는 `--replace`를 줄 때만 바꾸고, 없으면 지금처럼 `OutputExists`로 거부한다.
- 교체는 새 설치기가 완성된 뒤 한 번에 한다. 같은 폴더의 임시 파일에 쓰고 다시 읽어 SHA-256을 확인한 다음, 한 번의 이름 바꾸기(`MoveFileEx` 교체)로 기존 파일 자리에 놓는다. 입력 검사 거부, 설치 프로그램 변경·누락, 취소, 다시 읽기 실패에서는 기존 파일이 그대로 남는다.
- 동의해도 바꾸지 않는 것: 같은 이름의 폴더(`InvalidSetupOutput`), 이번 설치기를 만드는 데 쓰는 파일인 설치기 원본 `PrerequisiteSetup.exe`와 담을 설치 프로그램 파일(`OutputIsInput`). 바꿀 파일이 실행 중이거나 읽기 전용이면 `OutputNotWritten`으로 멈춘다.
## 고친 오류
- 같은 날 사용자 화면에서 **오프라인용 설치기 생성**이 "매개 변수가 틀립니다. (0x80070057)"로 멈췄다. 열린 프로젝트 경로는 `canonicalize` 때문에 `\\?\D:\...` 형식인데, 저장 창의 시작 폴더를 만드는 `SHCreateItemFromParsingName`은 이 형식을 `E_INVALIDARG`로 거부한다(이 PC에서 `D:\networkSetup`은 `0x00000000`, `\\?\D:\networkSetup`은 `0x80070057`로 확인). `save_dialog.rs`의 `shell_path`가 `\\?\D:\…`를 `D:\…`로, `\\?\UNC\server\share\…`를 `\\server\share\…`로 바꿔 넘기고, 실패하면 `SaveDialogFailed`와 폴더를 알린다. 고친 뒤 실제 앱에서 저장 창을 여는 시험은 수행하지 않았다.
## 모델과 실행
- 프로젝트·로컬·버전 파일: 바뀌지 않는다.
- 엔진: `package_infra::build_offline_setup(doc, version, inputs, output, replace, cancel, progress)`. `replace`가 새 인수다. `check_output`은 기존 파일을 `replace`일 때만 받고 폴더는 거부한다. 설치 프로그램 위치를 정한 뒤 `check_not_input`이 출력과 원본·설치 프로그램의 정규 경로를 비교한다. 마지막 저장은 `replace`면 `persist`, 아니면 `persist_noclobber`이다.
- GUI: `build_offline_setup` Tauri 명령은 저장 창이 물은 뒤 받은 경로이므로 `replace = true`로 호출한다. 명령 인자와 권한은 바뀌지 않는다.
- CLI: `package-builder offline-setup ... --replace`.
- 새 오류 코드: `OutputIsInput`. `OutputExists`와 `OutputNotWritten`은 조치 문구를 바꿨다.
- 범위 밖: 백업 파일(`.bak`)을 남기지 않는다. 바뀐 기존 파일은 되돌릴 수 없다.
## 확인 결과
- `cargo fmt --all --check`, `cargo clippy --locked --workspace --all-targets -- -D warnings` 통과.
- Rust 테스트 133개 통과, 7개 무시(`#[ignore]`). 오프라인 설치기 통합 테스트 9개 통과, 1개 무시(네트워크 다운로드). 새 테스트:
- `an_existing_output_is_refused_unless_the_user_agreed_to_replace_it`
- `an_agreed_replacement_happens_only_once_the_new_setup_is_complete`
- `a_folder_the_setup_program_or_a_carried_installer_is_never_replaced`
- 프런트엔드 테스트 149개 통과. TypeScript 검사와 Vite 빌드 통과.
- GUI에서 저장 창의 덮어쓰기 확인을 실제로 누르는 시험, CLI `--replace` 실제 실행, 실행 중인 파일을 바꾸는 시험은 수행하지 않았다. 만든 설치기는 설치 시험을 하지 않았다(`installationTest: notRun`).
증빙: [시험 결과 JSON](../../src/tests/verification-2026-11-13-offline-setup-replace.json)
## 근거
- [FILEOPENDIALOGOPTIONS (`FOS_OVERWRITEPROMPT`)](https://learn.microsoft.com/windows/win32/api/shobjidl_core/ne-shobjidl_core-_fileopendialogoptions)
- [MoveFileExW (`MOVEFILE_REPLACE_EXISTING`)](https://learn.microsoft.com/windows/win32/api/winbase/nf-winbase-movefileexw)