fix(server): aligner app-data-dir sur l'identifier desktop + corriger doc build web (#13)
default_app_data_dir aligné sur l'identifier tauri app.idea.ide, avec précédence IDEA_APP_DATA_DIR > XDG_DATA_HOME > HOME. Log stderr `idea --serve: app data dir = <path>` au démarrage et test de précédence. Doc build web corrigée (VITE_TRANSPORT=http npx vite build + npm au lieu de pnpm), section app-data-dir et avertissement double-writer desktop/serve. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -68,6 +68,10 @@ pub fn run_from_args(args: Vec<String>) -> ExitCode {
|
|||||||
|
|
||||||
let state = Arc::new(ServerState::new(config.clone()));
|
let state = Arc::new(ServerState::new(config.clone()));
|
||||||
eprintln!("IdeA pairing code: {}", state.pairing_code());
|
eprintln!("IdeA pairing code: {}", state.pairing_code());
|
||||||
|
eprintln!(
|
||||||
|
"idea --serve: app data dir = {}",
|
||||||
|
config.app_data_dir.display()
|
||||||
|
);
|
||||||
eprintln!("IdeA server listening on {}", config.listen);
|
eprintln!("IdeA server listening on {}", config.listen);
|
||||||
|
|
||||||
match tokio::runtime::Builder::new_multi_thread()
|
match tokio::runtime::Builder::new_multi_thread()
|
||||||
@ -1802,10 +1806,10 @@ fn default_app_data_dir() -> PathBuf {
|
|||||||
return PathBuf::from(path);
|
return PathBuf::from(path);
|
||||||
}
|
}
|
||||||
if let Some(path) = env::var_os("XDG_DATA_HOME") {
|
if let Some(path) = env::var_os("XDG_DATA_HOME") {
|
||||||
return PathBuf::from(path).join("IdeA");
|
return PathBuf::from(path).join("app.idea.ide");
|
||||||
}
|
}
|
||||||
if let Some(home) = env::var_os("HOME") {
|
if let Some(home) = env::var_os("HOME") {
|
||||||
return PathBuf::from(home).join(".local/share/IdeA");
|
return PathBuf::from(home).join(".local/share/app.idea.ide");
|
||||||
}
|
}
|
||||||
env::current_dir()
|
env::current_dir()
|
||||||
.unwrap_or_else(|_| PathBuf::from("."))
|
.unwrap_or_else(|_| PathBuf::from("."))
|
||||||
@ -2300,6 +2304,35 @@ mod tests {
|
|||||||
use http::header::HeaderName;
|
use http::header::HeaderName;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
static ENV_LOCK: Mutex<()> = Mutex::new(());
|
||||||
|
|
||||||
|
struct EnvVarGuard {
|
||||||
|
saved: Vec<(&'static str, Option<std::ffi::OsString>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EnvVarGuard {
|
||||||
|
fn new(keys: &[&'static str]) -> Self {
|
||||||
|
Self {
|
||||||
|
saved: keys
|
||||||
|
.iter()
|
||||||
|
.map(|key| (*key, std::env::var_os(key)))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for EnvVarGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
for (key, value) in self.saved.iter().rev() {
|
||||||
|
if let Some(value) = value {
|
||||||
|
std::env::set_var(key, value);
|
||||||
|
} else {
|
||||||
|
std::env::remove_var(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct RecordingSecurityLogger {
|
struct RecordingSecurityLogger {
|
||||||
events: Mutex<Vec<SecurityLogEvent>>,
|
events: Mutex<Vec<SecurityLogEvent>>,
|
||||||
@ -2341,6 +2374,30 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_app_data_dir_uses_tauri_identifier_with_env_precedence() {
|
||||||
|
let _lock = ENV_LOCK.lock().unwrap();
|
||||||
|
let _guard = EnvVarGuard::new(&["IDEA_APP_DATA_DIR", "XDG_DATA_HOME", "HOME"]);
|
||||||
|
let root = std::env::temp_dir().join(format!("idea-app-data-env-{}", Uuid::new_v4()));
|
||||||
|
let home = root.join("home");
|
||||||
|
let xdg = root.join("xdg");
|
||||||
|
let override_dir = root.join("override");
|
||||||
|
|
||||||
|
std::env::remove_var("IDEA_APP_DATA_DIR");
|
||||||
|
std::env::remove_var("XDG_DATA_HOME");
|
||||||
|
std::env::set_var("HOME", &home);
|
||||||
|
assert_eq!(
|
||||||
|
default_app_data_dir(),
|
||||||
|
home.join(".local/share/app.idea.ide")
|
||||||
|
);
|
||||||
|
|
||||||
|
std::env::set_var("XDG_DATA_HOME", &xdg);
|
||||||
|
assert_eq!(default_app_data_dir(), xdg.join("app.idea.ide"));
|
||||||
|
|
||||||
|
std::env::set_var("IDEA_APP_DATA_DIR", &override_dir);
|
||||||
|
assert_eq!(default_app_data_dir(), override_dir);
|
||||||
|
}
|
||||||
|
|
||||||
fn state() -> Arc<ServerState> {
|
fn state() -> Arc<ServerState> {
|
||||||
Arc::new(ServerState::new_for_test(test_config(), "PAIR1234"))
|
Arc::new(ServerState::new_for_test(test_config(), "PAIR1234"))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,14 +5,35 @@ build must be available as a web root containing `index.html`.
|
|||||||
|
|
||||||
## Local Development
|
## Local Development
|
||||||
|
|
||||||
|
The web build **must** be produced with the `http` transport, otherwise the
|
||||||
|
served `dist/` is a desktop (Tauri) build that fails in a plain browser with
|
||||||
|
`window.__TAURI_INTERNALS__ is undefined`. The frontend uses **npm**, not pnpm:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm --dir frontend build
|
cd frontend && VITE_TRANSPORT=http npx vite build && cd ..
|
||||||
idea --serve --web-root frontend/dist
|
idea --serve --web-root frontend/dist --app-data-dir "$HOME/.local/share/app.idea.ide"
|
||||||
```
|
```
|
||||||
|
|
||||||
The default local listener is `127.0.0.1:17373`. Loopback development may use
|
The default local listener is `127.0.0.1:17373`. Loopback development may use
|
||||||
plain HTTP; the session cookie is still `HttpOnly` and `SameSite=Strict`.
|
plain HTTP; the session cookie is still `HttpOnly` and `SameSite=Strict`.
|
||||||
|
|
||||||
|
### App data directory (must match the desktop app)
|
||||||
|
|
||||||
|
`idea --serve` reads/writes the same on-disk data as the desktop app
|
||||||
|
(projects, profiles, templates). It resolves the app-data directory in this
|
||||||
|
order:
|
||||||
|
|
||||||
|
1. `--app-data-dir PATH`
|
||||||
|
2. `IDEA_APP_DATA_DIR`
|
||||||
|
3. platform default for the Tauri identifier `app.idea.ide`
|
||||||
|
(`$XDG_DATA_HOME/app.idea.ide`, else `$HOME/.local/share/app.idea.ide`)
|
||||||
|
|
||||||
|
The resolved path is printed at startup (`idea --serve: app data dir = …`).
|
||||||
|
|
||||||
|
> **Do not run the desktop app and `idea --serve` on the same app-data
|
||||||
|
> directory at the same time.** There is no inter-process lock yet, so two
|
||||||
|
> concurrent writers can corrupt state. Close the desktop app while serving.
|
||||||
|
|
||||||
## Packaged Artifact
|
## Packaged Artifact
|
||||||
|
|
||||||
The release artifact is still a single IdeA binary/AppImage. Packaging must copy
|
The release artifact is still a single IdeA binary/AppImage. Packaging must copy
|
||||||
|
|||||||
Reference in New Issue
Block a user