arcbox_migration/
source.rs1use crate::error::{MigrationError, Result};
4use crate::model::{SourceConfig, SourceKind};
5use std::path::PathBuf;
6
7pub trait MigrationSource {
9 fn kind(&self) -> SourceKind;
11
12 fn default_socket_path(&self) -> PathBuf;
14}
15
16#[derive(Debug, Clone, Copy, Default)]
18pub struct DockerDesktopSource;
19
20impl MigrationSource for DockerDesktopSource {
21 fn kind(&self) -> SourceKind {
22 SourceKind::DockerDesktop
23 }
24
25 fn default_socket_path(&self) -> PathBuf {
26 dirs::home_dir()
27 .unwrap_or_else(|| PathBuf::from("/tmp"))
28 .join(".docker")
29 .join("run")
30 .join("docker.sock")
31 }
32}
33
34#[derive(Debug, Clone, Copy, Default)]
36pub struct OrbStackSource;
37
38impl MigrationSource for OrbStackSource {
39 fn kind(&self) -> SourceKind {
40 SourceKind::OrbStack
41 }
42
43 fn default_socket_path(&self) -> PathBuf {
44 dirs::home_dir()
45 .unwrap_or_else(|| PathBuf::from("/tmp"))
46 .join(".orbstack")
47 .join("run")
48 .join("docker.sock")
49 }
50}
51
52pub fn resolve_source(kind: SourceKind, override_socket: Option<PathBuf>) -> Result<SourceConfig> {
58 let path = if let Some(path) = override_socket {
59 path
60 } else {
61 match kind {
62 SourceKind::DockerDesktop => DockerDesktopSource.default_socket_path(),
63 SourceKind::OrbStack => OrbStackSource.default_socket_path(),
64 }
65 };
66
67 if !path.exists() {
68 return Err(MigrationError::MissingSource {
69 kind: kind.as_str(),
70 path,
71 });
72 }
73
74 Ok(SourceConfig {
75 kind,
76 socket_path: path,
77 })
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn docker_desktop_default_socket_ends_with_expected_path() {
86 assert!(
87 DockerDesktopSource
88 .default_socket_path()
89 .ends_with(".docker/run/docker.sock")
90 );
91 }
92
93 #[test]
94 fn orbstack_default_socket_ends_with_expected_path() {
95 assert!(
96 OrbStackSource
97 .default_socket_path()
98 .ends_with(".orbstack/run/docker.sock")
99 );
100 }
101}