Skip to content

Commit b095540

Browse files
committed
v0.3.7: UI 빌드 파일을 GitHub에서 직접 다운로드
- PyPI 패키지에 UI 소스(vite.config, src/)가 포함되지 않아 npm build 불가능 - GitHub master 브랜치에서 ZIP 다운로드 → ui/build/ 디렉토리만 추출 복사 - npm/Node.js 의존성 완전 제거 — 비개발자 환경에서도 동작
1 parent 3f90fe8 commit b095540

2 files changed

Lines changed: 44 additions & 63 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "dartlab-desktop"
3-
version = "0.3.6"
3+
version = "0.3.7"
44
edition = "2024"
55
description = "DartLab AI Desktop Launcher for Windows"
66
license = "MIT"

src/setup.rs

Lines changed: 43 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -144,85 +144,66 @@ pub fn ensure_ui_build(app_dir: &Path) -> Result<(), String> {
144144
return Ok(());
145145
}
146146

147-
if !ui_dir.join("package.json").exists() {
148-
return Err("dartlab UI 소스를 찾을 수 없습니다 (package.json 없음)".into());
147+
logger::log("UI 빌드 파일 없음 — GitHub에서 다운로드");
148+
149+
let zip_url = "https://github.com/eddmpython/dartlab/archive/refs/heads/master.zip";
150+
let zip_path = app_dir.join("dartlab-ui.zip");
151+
download_file(zip_url, &zip_path)?;
152+
153+
let extract_dir = app_dir.join("_dartlab_ui_tmp");
154+
if extract_dir.exists() {
155+
std::fs::remove_dir_all(&extract_dir).ok();
149156
}
157+
std::fs::create_dir_all(&extract_dir).map_err(|e| e.to_string())?;
158+
extract_zip(&zip_path, &extract_dir)?;
159+
std::fs::remove_file(&zip_path).ok();
150160

151-
let npm = find_npm()?;
161+
let src_build = find_build_dir(&extract_dir)
162+
.ok_or("다운로드한 레포에서 ui/build 디렉토리를 찾을 수 없습니다")?;
152163

153-
logger::log("dartlab UI npm install 실행 중...");
154-
let output = Command::new(&npm)
155-
.args(["install"])
156-
.current_dir(&ui_dir)
157-
.creation_flags(CREATE_NO_WINDOW)
158-
.output()
159-
.map_err(|e| format!("npm install 실행 실패: {e}"))?;
164+
std::fs::create_dir_all(&ui_dir).map_err(|e| e.to_string())?;
160165

161-
if !output.status.success() {
162-
let stderr = String::from_utf8_lossy(&output.stderr);
163-
logger::log(&format!("npm install stderr: {stderr}"));
164-
return Err(format!("npm install 실패: {stderr}"));
166+
if build_dir.exists() {
167+
std::fs::remove_dir_all(&build_dir).ok();
165168
}
169+
copy_dir_all(&src_build, &build_dir)?;
166170

167-
logger::log("dartlab UI 빌드 중...");
168-
let output = Command::new(&npm)
169-
.args(["run", "build"])
170-
.current_dir(&ui_dir)
171-
.creation_flags(CREATE_NO_WINDOW)
172-
.output()
173-
.map_err(|e| format!("npm run build 실행 실패: {e}"))?;
174-
175-
if !output.status.success() {
176-
let stderr = String::from_utf8_lossy(&output.stderr);
177-
logger::log(&format!("npm run build stderr: {stderr}"));
178-
return Err(format!("UI 빌드 실패: {stderr}"));
179-
}
171+
std::fs::remove_dir_all(&extract_dir).ok();
180172

181-
if !build_dir.exists() || !build_dir.join("index.html").exists() {
182-
return Err("UI 빌드 완료되었으나 build/index.html이 생성되지 않았습니다".into());
173+
if !build_dir.join("index.html").exists() {
174+
return Err("UI 빌드 파일 복사 완료되었으나 index.html이 없습니다".into());
183175
}
184176

185-
logger::log("dartlab UI 빌드 완료");
177+
logger::log("UI 빌드 파일 설치 완료");
186178
Ok(())
187179
}
188180

189-
fn find_npm() -> Result<String, String> {
190-
if Command::new("npm")
191-
.arg("--version")
192-
.creation_flags(CREATE_NO_WINDOW)
193-
.output()
194-
.map(|o| o.status.success())
195-
.unwrap_or(false)
196-
{
197-
return Ok("npm".to_string());
198-
}
199-
200-
let candidates = [
201-
r"C:\Program Files\nodejs\npm.cmd",
202-
r"C:\Program Files (x86)\nodejs\npm.cmd",
203-
];
204-
205-
for c in &candidates {
206-
if std::path::Path::new(c).exists() {
207-
return Ok(c.to_string());
181+
fn find_build_dir(extract_dir: &Path) -> Option<std::path::PathBuf> {
182+
if let Ok(entries) = std::fs::read_dir(extract_dir) {
183+
for entry in entries.flatten() {
184+
let candidate = entry.path()
185+
.join("src").join("dartlab").join("ui").join("build");
186+
if candidate.join("index.html").exists() {
187+
return Some(candidate);
188+
}
208189
}
209190
}
191+
None
192+
}
210193

211-
if let Ok(appdata) = std::env::var("APPDATA") {
212-
let nvm_dir = std::path::Path::new(&appdata).join("nvm");
213-
if nvm_dir.exists() {
214-
if let Ok(entries) = std::fs::read_dir(&nvm_dir) {
215-
for entry in entries.flatten() {
216-
let npm_cmd = entry.path().join("npm.cmd");
217-
if npm_cmd.exists() {
218-
return Ok(npm_cmd.to_string_lossy().to_string());
219-
}
220-
}
221-
}
194+
fn copy_dir_all(src: &Path, dst: &Path) -> Result<(), String> {
195+
std::fs::create_dir_all(dst).map_err(|e| e.to_string())?;
196+
for entry in std::fs::read_dir(src).map_err(|e| e.to_string())? {
197+
let entry = entry.map_err(|e| e.to_string())?;
198+
let ty = entry.file_type().map_err(|e| e.to_string())?;
199+
let dst_path = dst.join(entry.file_name());
200+
if ty.is_dir() {
201+
copy_dir_all(&entry.path(), &dst_path)?;
202+
} else {
203+
std::fs::copy(entry.path(), &dst_path).map_err(|e| e.to_string())?;
222204
}
223205
}
224-
225-
Err("Node.js가 설치되어 있지 않습니다. https://nodejs.org 에서 설치 후 다시 시도해 주세요.".into())
206+
Ok(())
226207
}
227208

228209
fn cleanup_legacy(app_dir: &Path) {

0 commit comments

Comments
 (0)