diff --git a/crates/didbot-setup/src/bin/didbot-setup.rs b/crates/didbot-setup/src/bin/didbot-setup.rs index 45ece9ee..256805a9 100644 --- a/crates/didbot-setup/src/bin/didbot-setup.rs +++ b/crates/didbot-setup/src/bin/didbot-setup.rs @@ -316,7 +316,13 @@ fn do_service_add( query: options.roles.query.clone(), zone: options.zone.clone(), names: options.names.clone(), - data: options.data.clone(), + // A server told to keep nothing would fall through to the + // script's own default, which is the first server's directory, + // and `pds.lock` would refuse it. Its own by default instead. + data: match (kind, &options.data) { + (ServiceKind::Pds, None) => Some(didbot_stack::default_data_dir(name)), + (_, data) => data.clone(), + }, }, ); save( diff --git a/crates/didbot-stack/src/defaults.rs b/crates/didbot-stack/src/defaults.rs index e92b6063..869eab34 100644 --- a/crates/didbot-stack/src/defaults.rs +++ b/crates/didbot-stack/src/defaults.rs @@ -14,8 +14,9 @@ const PROJECT_DIR: &str = "didbot"; /// Name of the configuration file itself. const CONFIG_FILE: &str = "stack.toml"; -/// The state directory a personal data server keeps its store in. -const PDS_DIR: &str = "pds"; +/// The personal data server the default profile names, and so the directory +/// its store lands in. +const PDS_SERVICE: &str = "pds"; /// The interface a service listens on unless it says otherwise. /// @@ -57,7 +58,7 @@ pub fn default_config_path() -> PathBuf { .join(CONFIG_FILE) } -/// `$XDG_STATE_HOME/didbot/pds`, where a development server keeps its store. +/// `$XDG_STATE_HOME/didbot/`, where that server keeps its store. /// /// State rather than configuration: nothing here is hand-editable, and losing /// it costs this machine its local accounts and nothing else. That is what @@ -67,11 +68,13 @@ pub fn default_config_path() -> PathBuf { /// /// Per user rather than per checkout, because the agents on this machine /// address one server on one port; a second checkout serving the same port -/// is refused by `pds.lock` before it can write. -pub fn default_data_dir() -> PathBuf { +/// is refused by `pds.lock` before it can write. Keyed by service name so +/// that a machine running two of them keeps two stores: one log has one +/// writer, and the second opener is refused rather than interleaved. +pub fn default_data_dir(service: &str) -> PathBuf { xdg_base("XDG_STATE_HOME", ".local/state") .join(PROJECT_DIR) - .join(PDS_DIR) + .join(service) } /// One of everything, on the ports and the state directory `scripts/dev-*.sh` @@ -86,7 +89,7 @@ pub fn default_data_dir() -> PathBuf { pub(crate) fn builtin() -> Config { let mut services = BTreeMap::new(); services.insert( - "pds".to_owned(), + PDS_SERVICE.to_owned(), Service { kind: ServiceKind::Pds, port: 3000, @@ -96,14 +99,14 @@ pub(crate) fn builtin() -> Config { pds: None, index: None, query: None, - data: Some(default_data_dir()), + data: Some(default_data_dir(PDS_SERVICE)), }, ); let mut profiles = BTreeMap::new(); profiles.insert( DEFAULT_PROFILE.to_owned(), Profile { - pds: "pds".to_owned(), + pds: PDS_SERVICE.to_owned(), // The record host, the index, the query service and the // canvas are vibescrobble.com's processes now. `ServiceKind` // still names them, so a developer running both can declare them @@ -162,8 +165,9 @@ mod tests { .join("scripts"); let source = std::fs::read_to_string(root.join("dev-pds.sh")) .unwrap_or_else(|err| panic!("read dev-pds.sh: {err}")); + let service = &builtin().profiles[DEFAULT_PROFILE].pds; let needle = format!( - "${{DIDBOT_PDS_DATA-${{XDG_STATE_HOME:-$HOME/.local/state}}/{PROJECT_DIR}/{PDS_DIR}}}" + "${{DIDBOT_PDS_DATA-${{XDG_STATE_HOME:-$HOME/.local/state}}/{PROJECT_DIR}/{service}}}" ); assert!( source.contains(&needle),