diff --git a/src-tauri/src/config.rs b/src-tauri/src/config.rs index 619242d..3def067 100644 --- a/src-tauri/src/config.rs +++ b/src-tauri/src/config.rs @@ -138,6 +138,60 @@ pub(crate) fn config_path() -> PathBuf { .join("ant-gui") } +/// User-addressable directory for persisted datamap files on **fresh +/// installs**. Lives under `~/Documents/Autonomi/Datamaps/` (or the +/// platform equivalent of Documents) so the OS file picker can navigate +/// to them — fixes the macOS gap where `~/Library` is hidden by default +/// in NSOpenPanel. +/// +/// Existing installs keep writing into `config_path()` via +/// `resolve_datamap_output_dir()` so the upgrade does not split their +/// datamaps across two locations. Only callers that need the "where do +/// new writes go" answer should use `resolve_datamap_output_dir()`; +/// this function is the new-install default. +/// +/// Falls back to `/Documents/Autonomi/Datamaps` if `dirs::document_dir` +/// can't resolve the platform path (very unusual), and to `./Autonomi/Datamaps` +/// only if even `dirs::home_dir` fails (effectively a no-home embedded env). +pub fn datamap_dir() -> PathBuf { + dirs::document_dir() + .or_else(|| dirs::home_dir().map(|h| h.join("Documents"))) + .unwrap_or_else(|| PathBuf::from(".")) + .join("Autonomi") + .join("Datamaps") +} + +/// Decide where the *next* datamap write should land. Existing installs +/// (those whose `config_path()` already contains one or more `.datamap` +/// files) keep writing into the legacy location so a single user does not +/// end up with their datamaps scattered across two directories after the +/// upgrade. Fresh installs go to `datamap_dir()` so the OS file picker can +/// reach them. +/// +/// Detection is stateless: on every write, we look at the legacy dir's +/// current contents. After the first new-install write the rule continues +/// to return `datamap_dir()` because the legacy dir never gains a +/// `.datamap` file. After the first existing-install write the rule +/// continues to return `config_path()` because the legacy dir still has +/// the original `.datamap` files alongside the new one. +fn resolve_datamap_output_dir() -> PathBuf { + let legacy = config_path(); + let has_legacy_datamaps = legacy + .read_dir() + .ok() + .map(|entries| { + entries + .filter_map(|e| e.ok()) + .any(|entry| entry.path().extension().and_then(|s| s.to_str()) == Some("datamap")) + }) + .unwrap_or(false); + if has_legacy_datamaps { + legacy + } else { + datamap_dir() + } +} + /// Resolve the OS-appropriate default downloads directory. Returns /// `~/Downloads` on macOS/Linux and `C:\Users\\Downloads` on Windows, /// falling back to `/Downloads` if the platform-specific lookup fails. @@ -219,8 +273,9 @@ pub fn get_file_metas(paths: &[String]) -> Result, String> { .collect() } -/// Persist a serialized DataMap alongside `upload_history.json` using the -/// canonical msgpack format from `ant_core::data::write_datamap`. The file +/// Persist a serialized DataMap in the user-addressable datamap directory +/// (`~/Documents/Autonomi/Datamaps/` on fresh installs, the legacy config +/// dir on existing installs — see `resolve_datamap_output_dir`). The file /// is named after the upload's original basename with `.datamap` appended, /// preserving the original extension (e.g. `holiday.jpg` → /// `holiday.jpg.datamap`). On collision the upstream `NumericSuffix` policy @@ -228,18 +283,18 @@ pub fn get_file_metas(paths: &[String]) -> Result, String> { /// /// Returns the absolute path to the written file. /// -/// This is the round-trip-safe path: ant-cli, ant-tui, and any other -/// consumer of the upstream module reads back the same on-disk format. The -/// read side (`autonomi_ops::read_datamap_file`) still accepts legacy JSON -/// datamaps written by older builds via the first-byte sniff in upstream's -/// `read_datamap`, so existing entries in `upload_history.json` keep -/// working. +/// Format is the canonical msgpack produced by `ant_core::data::write_datamap`, +/// so ant-cli, ant-tui, and any other consumer of the upstream module reads +/// back the same on-disk bytes. The read side (`autonomi_ops::read_datamap_file`) +/// still accepts legacy JSON datamaps written by older builds via the first-byte +/// sniff in upstream's `read_datamap`, so existing entries in `upload_history.json` +/// keep working. pub fn write_datamap_for( original_name: &str, dm: &ant_core::data::DataMap, ) -> Result { - let dir = config_path(); - std::fs::create_dir_all(&dir).map_err(|e| format!("Failed to create config dir: {e}"))?; + let dir = resolve_datamap_output_dir(); + std::fs::create_dir_all(&dir).map_err(|e| format!("Failed to create datamap dir: {e}"))?; ant_core::data::write_datamap( &dir, original_name,