aboutsummaryrefslogtreecommitdiffstats
path: root/crates/client/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/client/src')
-rw-r--r--crates/client/src/atuin_common/api.rs22
-rw-r--r--crates/client/src/atuin_common/mod.rs58
-rw-r--r--crates/client/src/atuin_common/record.rs284
-rw-r--r--crates/client/src/atuin_common/shell.rs52
-rw-r--r--crates/client/src/atuin_common/tls.rs15
-rw-r--r--crates/client/src/atuin_common/utils.rs257
-rw-r--r--crates/client/src/command/client/server.rs56
-rw-r--r--crates/client/src/lib.rs4
-rw-r--r--crates/client/src/main.rs3
9 files changed, 0 insertions, 751 deletions
diff --git a/crates/client/src/atuin_common/api.rs b/crates/client/src/atuin_common/api.rs
deleted file mode 100644
index 0868943d..00000000
--- a/crates/client/src/atuin_common/api.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use semver::Version;
-use serde::{Deserialize, Serialize};
-use std::borrow::Cow;
-use std::sync::LazyLock;
-
-// the usage of X- has been deprecated for quite along time, it turns out
-pub(crate) static ATUIN_HEADER_VERSION: &str = "Atuin-Version";
-pub(crate) static ATUIN_CARGO_VERSION: &str = env!("CARGO_PKG_VERSION");
-
-pub(crate) static ATUIN_VERSION: LazyLock<Version> =
- LazyLock::new(|| Version::parse(ATUIN_CARGO_VERSION).expect("failed to parse self semver"));
-
-#[derive(Debug, Serialize, Deserialize)]
-pub(crate) struct ErrorResponse<'a> {
- pub(crate) reason: Cow<'a, str>,
-}
-
-#[derive(Debug, Serialize, Deserialize)]
-pub(crate) struct IndexResponse {
- pub(crate) homage: String,
- pub(crate) version: String,
-}
diff --git a/crates/client/src/atuin_common/mod.rs b/crates/client/src/atuin_common/mod.rs
deleted file mode 100644
index 635c9fc3..00000000
--- a/crates/client/src/atuin_common/mod.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-/// Defines a new UUID type wrapper
-macro_rules! new_uuid {
- ($name:ident) => {
- #[derive(
- Debug,
- Copy,
- Clone,
- PartialEq,
- Eq,
- Hash,
- PartialOrd,
- Ord,
- serde::Serialize,
- serde::Deserialize,
- )]
- #[serde(transparent)]
- pub(crate) struct $name(pub(crate) Uuid);
-
- impl<DB: sqlx::Database> sqlx::Type<DB> for $name
- where
- Uuid: sqlx::Type<DB>,
- {
- fn type_info() -> <DB as sqlx::Database>::TypeInfo {
- Uuid::type_info()
- }
- }
-
- impl<'r, DB: sqlx::Database> sqlx::Decode<'r, DB> for $name
- where
- Uuid: sqlx::Decode<'r, DB>,
- {
- fn decode(
- value: DB::ValueRef<'r>,
- ) -> std::result::Result<Self, sqlx::error::BoxDynError> {
- Uuid::decode(value).map(Self)
- }
- }
-
- impl<'q, DB: sqlx::Database> sqlx::Encode<'q, DB> for $name
- where
- Uuid: sqlx::Encode<'q, DB>,
- {
- fn encode_by_ref(
- &self,
- buf: &mut DB::ArgumentBuffer<'q>,
- ) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Send + Sync + 'static>>
- {
- self.0.encode_by_ref(buf)
- }
- }
- };
-}
-
-pub(crate) mod api;
-pub(crate) mod record;
-pub(crate) mod shell;
-pub(crate) mod tls;
-pub(crate) mod utils;
diff --git a/crates/client/src/atuin_common/record.rs b/crates/client/src/atuin_common/record.rs
deleted file mode 100644
index f8f9f8a7..00000000
--- a/crates/client/src/atuin_common/record.rs
+++ /dev/null
@@ -1,284 +0,0 @@
-use std::collections::HashMap;
-
-use eyre::Result;
-use serde::{Deserialize, Serialize};
-use typed_builder::TypedBuilder;
-use uuid::Uuid;
-
-#[derive(Clone, Debug, PartialEq)]
-pub(crate) struct DecryptedData(pub(crate) Vec<u8>);
-
-#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
-pub(crate) struct EncryptedData {
- pub(crate) data: String,
- pub(crate) content_encryption_key: String,
-}
-
-#[derive(Debug, PartialEq, PartialOrd, Ord, Eq)]
-pub(crate) struct Diff {
- pub(crate) host: HostId,
- pub(crate) tag: String,
- pub(crate) local: Option<RecordIdx>,
- pub(crate) remote: Option<RecordIdx>,
-}
-
-#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
-pub(crate) struct Host {
- pub(crate) id: HostId,
- pub(crate) name: String,
-}
-
-impl Host {
- pub(crate) fn new(id: HostId) -> Self {
- Self {
- id,
- name: String::new(),
- }
- }
-}
-
-new_uuid!(RecordId);
-new_uuid!(HostId);
-
-pub(crate) type RecordIdx = u64;
-
-/// A single record stored inside of our local database
-#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TypedBuilder)]
-pub(crate) struct Record<Data> {
- /// a unique ID
- #[builder(default = RecordId(crate::atuin_common::utils::uuid_v7()))]
- pub(crate) id: RecordId,
-
- /// The integer record ID. This is only unique per (host, tag).
- pub(crate) idx: RecordIdx,
-
- /// The unique ID of the host.
- // TODO(ellie): Optimize the storage here. We use a bunch of IDs, and currently store
- // as strings. I would rather avoid normalization, so store as UUID binary instead of
- // encoding to a string and wasting much more storage.
- pub(crate) host: Host,
-
- /// The creation time in nanoseconds since unix epoch
- #[builder(default = time::OffsetDateTime::now_utc().unix_timestamp_nanos() as u64)]
- pub(crate) timestamp: u64,
-
- /// The version the data in the entry conforms to
- // However we want to track versions for this tag, eg v2
- pub(crate) version: String,
-
- /// The type of data we are storing here. Eg, "history"
- pub(crate) tag: String,
-
- /// Some data. This can be anything you wish to store. Use the tag field to know how to handle it.
- pub(crate) data: Data,
-}
-
-/// Extra data from the record that should be encoded in the data
-#[derive(Debug, Copy, Clone)]
-pub(crate) struct AdditionalData<'a> {
- pub(crate) id: &'a RecordId,
- pub(crate) idx: &'a u64,
- pub(crate) version: &'a str,
- pub(crate) tag: &'a str,
- pub(crate) host: &'a HostId,
-}
-
-/// An index representing the current state of the record stores
-/// This can be both remote, or local, and compared in either direction
-#[derive(Debug, Serialize, Deserialize)]
-pub(crate) struct RecordStatus {
- // A map of host -> tag -> max(idx)
- pub(crate) hosts: HashMap<HostId, HashMap<String, RecordIdx>>,
-}
-
-impl Default for RecordStatus {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl Extend<(HostId, String, RecordIdx)> for RecordStatus {
- fn extend<T: IntoIterator<Item = (HostId, String, RecordIdx)>>(&mut self, iter: T) {
- for (host, tag, tail_idx) in iter {
- self.set_raw(host, tag, tail_idx);
- }
- }
-}
-
-impl RecordStatus {
- pub(crate) fn new() -> Self {
- Self {
- hosts: HashMap::new(),
- }
- }
-
- /// Insert a new tail record into the store
- pub(crate) fn set_raw(&mut self, host: HostId, tag: String, tail_id: RecordIdx) {
- self.hosts.entry(host).or_default().insert(tag, tail_id);
- }
-
- pub(crate) fn get(&self, host: HostId, tag: &str) -> Option<RecordIdx> {
- self.hosts.get(&host).and_then(|v| v.get(tag)).copied()
- }
-
- /// Diff this index with another, likely remote index.
- /// The two diffs can then be reconciled, and the optimal change set calculated
- /// Returns a tuple, with (host, tag, Option(OTHER))
- /// OTHER is set to the value of the idx on the other machine. If it is greater than our index,
- /// then we need to do some downloading. If it is smaller, then we need to do some uploading
- /// Note that we cannot upload if we are not the owner of the record store - hosts can only
- /// write to their own store.
- pub(crate) fn diff(&self, other: &Self) -> Vec<Diff> {
- let mut ret = Vec::new();
-
- // First, we check if other has everything that self has
- for (host, tag_map) in &self.hosts {
- for (tag, idx) in tag_map {
- match other.get(*host, tag) {
- // The other store is all up to date! No diff.
- Some(t) if t.eq(idx) => (),
-
- // The other store does exist, and it is either ahead or behind us. A diff regardless
- Some(t) => ret.push(Diff {
- host: *host,
- tag: tag.clone(),
- local: Some(*idx),
- remote: Some(t),
- }),
-
- // The other store does not exist :O
- None => ret.push(Diff {
- host: *host,
- tag: tag.clone(),
- local: Some(*idx),
- remote: None,
- }),
- }
- }
- }
-
- // At this point, there is a single case we have not yet considered.
- // If the other store knows of a tag that we are not yet aware of, then the diff will be missed
-
- // account for that!
- for (host, tag_map) in &other.hosts {
- for (tag, idx) in tag_map {
- match self.get(*host, tag) {
- // If we have this host/tag combo, the comparison and diff will have already happened above
- Some(_) => (),
-
- None => ret.push(Diff {
- host: *host,
- tag: tag.clone(),
- remote: Some(*idx),
- local: None,
- }),
- }
- }
- }
-
- // Stability is a nice property to have
- ret.sort();
- ret
- }
-}
-
-pub(crate) trait Encryption {
- fn re_encrypt(
- data: EncryptedData,
- ad: AdditionalData<'_>,
- old_key: &[u8; 32],
- new_key: &[u8; 32],
- ) -> Result<EncryptedData> {
- let data = Self::decrypt(data, ad, old_key)?;
- Ok(Self::encrypt(data, ad, new_key))
- }
- fn encrypt(data: DecryptedData, ad: AdditionalData<'_>, key: &[u8; 32]) -> EncryptedData;
- fn decrypt(
- data: EncryptedData,
- ad: AdditionalData<'_>,
- key: &[u8; 32],
- ) -> Result<DecryptedData>;
-}
-
-impl Record<DecryptedData> {
- pub(crate) fn encrypt<E: Encryption>(self, key: &[u8; 32]) -> Record<EncryptedData> {
- let ad = AdditionalData {
- id: &self.id,
- version: &self.version,
- tag: &self.tag,
- host: &self.host.id,
- idx: &self.idx,
- };
- Record {
- data: E::encrypt(self.data, ad, key),
- id: self.id,
- host: self.host,
- idx: self.idx,
- timestamp: self.timestamp,
- version: self.version,
- tag: self.tag,
- }
- }
-}
-
-impl Record<EncryptedData> {
- pub(crate) fn decrypt<E: Encryption>(self, key: &[u8; 32]) -> Result<Record<DecryptedData>> {
- let ad = AdditionalData {
- id: &self.id,
- version: &self.version,
- tag: &self.tag,
- host: &self.host.id,
- idx: &self.idx,
- };
- Ok(Record {
- data: E::decrypt(self.data, ad, key)?,
- id: self.id,
- host: self.host,
- idx: self.idx,
- timestamp: self.timestamp,
- version: self.version,
- tag: self.tag,
- })
- }
-
- pub(crate) fn re_encrypt<E: Encryption>(
- self,
- old_key: &[u8; 32],
- new_key: &[u8; 32],
- ) -> Result<Self> {
- let ad = AdditionalData {
- id: &self.id,
- version: &self.version,
- tag: &self.tag,
- host: &self.host.id,
- idx: &self.idx,
- };
- Ok(Self {
- data: E::re_encrypt(self.data, ad, old_key, new_key)?,
- id: self.id,
- host: self.host,
- idx: self.idx,
- timestamp: self.timestamp,
- version: self.version,
- tag: self.tag,
- })
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::atuin_common::record::{Host, HostId};
-
- use super::{DecryptedData, Record};
-
- fn test_record() -> Record<DecryptedData> {
- Record::builder()
- .host(Host::new(HostId(crate::atuin_common::utils::uuid_v7())))
- .version("v1".into())
- .tag(crate::atuin_common::utils::uuid_v7().simple().to_string())
- .data(DecryptedData(vec![0, 1, 2, 3]))
- .idx(0)
- .build()
- }
-}
diff --git a/crates/client/src/atuin_common/shell.rs b/crates/client/src/atuin_common/shell.rs
deleted file mode 100644
index 880ff00f..00000000
--- a/crates/client/src/atuin_common/shell.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-#[derive(PartialEq)]
-pub(crate) enum Shell {
- Sh,
- Bash,
- Fish,
- Zsh,
- Xonsh,
- Nu,
- Powershell,
-
- Unknown,
-}
-
-impl std::fmt::Display for Shell {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let shell = match self {
- Self::Bash => "bash",
- Self::Fish => "fish",
- Self::Zsh => "zsh",
- Self::Nu => "nu",
- Self::Xonsh => "xonsh",
- Self::Sh => "sh",
- Self::Powershell => "powershell",
-
- Self::Unknown => "unknown",
- };
-
- write!(f, "{shell}")
- }
-}
-
-impl Shell {
- pub(crate) fn from_env() -> Self {
- std::env::var("ATUIN_SHELL").map_or(Self::Unknown, |shell| {
- Self::from_string(shell.trim().to_lowercase().as_str())
- })
- }
-
- pub(crate) fn from_string(name: &str) -> Self {
- match name {
- "bash" => Self::Bash,
- "fish" => Self::Fish,
- "zsh" => Self::Zsh,
- "xonsh" => Self::Xonsh,
- "nu" => Self::Nu,
- "sh" => Self::Sh,
- "powershell" => Self::Powershell,
-
- _ => Self::Unknown,
- }
- }
-}
diff --git a/crates/client/src/atuin_common/tls.rs b/crates/client/src/atuin_common/tls.rs
deleted file mode 100644
index 3736f878..00000000
--- a/crates/client/src/atuin_common/tls.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use std::sync::Once;
-
-static INIT: Once = Once::new();
-
-/// Ensure the rustls crypto provider (ring) is installed.
-///
-/// Must be called before creating any reqwest clients. Safe to call
-/// multiple times — only the first call installs the provider.
-pub(crate) fn ensure_crypto_provider() {
- INIT.call_once(|| {
- rustls::crypto::ring::default_provider()
- .install_default()
- .expect("Failed to install rustls crypto provider");
- });
-}
diff --git a/crates/client/src/atuin_common/utils.rs b/crates/client/src/atuin_common/utils.rs
deleted file mode 100644
index dbe9dfbc..00000000
--- a/crates/client/src/atuin_common/utils.rs
+++ /dev/null
@@ -1,257 +0,0 @@
-use std::borrow::Cow;
-use std::env;
-use std::path::{Path, PathBuf};
-
-use uuid::Uuid;
-
-pub(crate) fn uuid_v7() -> Uuid {
- Uuid::now_v7()
-}
-
-pub(crate) fn has_git_dir(path: &str) -> bool {
- let mut gitdir = PathBuf::from(path);
- gitdir.push(".git");
-
- gitdir.exists()
-}
-
-// in a git worktree, .git is a file containing "gitdir: <path>" pointing
-// to the main repo's .git/worktrees/<name> directory. follow the pointer
-// back to the main repo root so all worktrees share a workspace.
-fn resolve_git_worktree(path: &Path) -> Option<PathBuf> {
- let git_path = path.join(".git");
-
- if !git_path.is_file() {
- return None;
- }
-
- let contents = std::fs::read_to_string(&git_path).ok()?;
- let gitdir_str = contents.strip_prefix("gitdir: ")?.trim();
-
- let gitdir = PathBuf::from(gitdir_str);
- let gitdir = if gitdir.is_absolute() {
- gitdir
- } else {
- path.join(gitdir_str)
- };
-
- // walk up from e.g. /repo/.git/worktrees/feature to find /repo
- let mut candidate = gitdir.as_path();
- while let Some(parent) = candidate.parent() {
- if parent.join(".git").is_dir() {
- return Some(parent.to_path_buf());
- }
- candidate = parent;
- }
-
- None
-}
-
-// detect if any parent dir has a git repo in it
-// I really don't want to bring in libgit for something simple like this
-// If we start to do anything more advanced, then perhaps
-pub(crate) fn in_git_repo(path: &str) -> Option<PathBuf> {
- let mut gitdir = PathBuf::from(path);
-
- while gitdir.parent().is_some() && !has_git_dir(gitdir.to_str().unwrap()) {
- gitdir.pop();
- }
-
- // No parent? then we hit root, finding no git
- if gitdir.parent().is_some() {
- // if .git is a file (worktree), resolve to the main repo root
- if let Some(main_repo) = resolve_git_worktree(&gitdir) {
- return Some(main_repo);
- }
- return Some(gitdir);
- }
-
- None
-}
-
-// TODO: more reliable, more tested
-// I don't want to use ProjectDirs, it puts config in awkward places on
-// mac. Data too. Seems to be more intended for GUI apps.
-
-pub(crate) fn home_dir() -> PathBuf {
- directories::BaseDirs::new()
- .map(|d| d.home_dir().to_path_buf())
- .expect("could not determine home directory")
-}
-
-pub(crate) fn config_dir() -> PathBuf {
- let config_dir =
- env::var("XDG_CONFIG_HOME").map_or_else(|_| home_dir().join(".config"), PathBuf::from);
- config_dir.join("atuin")
-}
-
-pub(crate) fn data_dir() -> PathBuf {
- let data_dir = env::var("XDG_DATA_HOME")
- .map_or_else(|_| home_dir().join(".local").join("share"), PathBuf::from);
-
- data_dir.join("atuin")
-}
-
-pub(crate) fn runtime_dir() -> PathBuf {
- env::var("XDG_RUNTIME_DIR").map_or_else(|_| data_dir(), PathBuf::from)
-}
-
-pub(crate) fn logs_dir() -> PathBuf {
- home_dir().join(".atuin").join("logs")
-}
-
-pub(crate) fn get_current_dir() -> String {
- // Prefer PWD environment variable over cwd if available to better support symbolic links
- env::var("PWD").unwrap_or_else(|_| {
- env::current_dir().map_or_else(|_| String::new(), |dir| dir.display().to_string())
- })
-}
-
-pub(crate) fn broken_symlink<P: Into<PathBuf>>(path: P) -> bool {
- let path = path.into();
- path.is_symlink() && !path.exists()
-}
-
-/// Extension trait for anything that can behave like a string to make it easy to escape control
-/// characters.
-///
-/// Intended to help prevent control characters being printed and interpreted by the terminal when
-/// printing history as well as to ensure the commands that appear in the interactive search
-/// reflect the actual command run rather than just the printable characters.
-pub(crate) trait Escapable: AsRef<str> {
- fn escape_control(&self) -> Cow<'_, str> {
- if self.as_ref().contains(|c: char| c.is_ascii_control()) {
- let mut remaining = self.as_ref();
- // Not a perfect way to reserve space but should reduce the allocations
- let mut buf = String::with_capacity(remaining.len());
- while let Some(i) = remaining.find(|c: char| c.is_ascii_control()) {
- // safe to index with `..i`, `i` and `i+1..` as part[i] is a single byte ascii char
- buf.push_str(&remaining[..i]);
- buf.push('^');
- buf.push(match remaining.as_bytes()[i] {
- 0x7F => '?',
- code => char::from_u32(u32::from(code) + 64).unwrap(),
- });
- remaining = &remaining[i + 1..];
- }
- buf.push_str(remaining);
- buf.into()
- } else {
- self.as_ref().into()
- }
- }
-}
-
-impl<T: AsRef<str>> Escapable for T {}
-
-#[cfg(test)]
-mod tests {
- use super::{Cow, Escapable, Uuid, env, in_git_repo, uuid_v7};
-
- use std::collections::HashSet;
-
- #[test]
- fn uuid_is_unique() {
- let how_many: usize = 1_000_000;
-
- // for peace of mind
- let mut uuids: HashSet<Uuid> = HashSet::with_capacity(how_many);
-
- // there will be many in the same millisecond
- for _ in 0..how_many {
- let uuid = uuid_v7();
- uuids.insert(uuid);
- }
-
- assert_eq!(uuids.len(), how_many);
- }
-
- #[test]
- fn escape_control_characters() {
- use super::Escapable;
- // CSI colour sequence
- assert_eq!("\x1b[31mfoo".escape_control(), "^[[31mfoo");
-
- // Tabs count as control chars
- assert_eq!("foo\tbar".escape_control(), "foo^Ibar");
-
- // space is in control char range but should be excluded
- assert_eq!("two words".escape_control(), "two words");
-
- // unicode multi-byte characters
- let s = "🐢\x1b[32m🦀";
- assert_eq!(s.escape_control(), s.replace("\x1b", "^["));
- }
-
- #[test]
- fn escape_no_control_characters() {
- use super::Escapable as _;
- assert!(matches!(
- "no control characters".escape_control(),
- Cow::Borrowed(_)
- ));
- assert!(matches!(
- "with \x1b[31mcontrol\x1b[0m characters".escape_control(),
- Cow::Owned(_)
- ));
- }
-
- #[cfg(not(windows))]
- #[test]
- fn in_git_repo_regular() {
- // regular git repo should resolve to the directory containing .git
- let tmp = env::temp_dir().join("atuin-test-regular-git");
- drop(std::fs::remove_dir_all(&tmp));
- let subdir = tmp.join("src").join("deep");
- std::fs::create_dir_all(&subdir).unwrap();
- std::fs::create_dir_all(tmp.join(".git")).unwrap();
-
- let result = in_git_repo(subdir.to_str().unwrap());
- assert_eq!(result, Some(tmp.clone()));
-
- std::fs::remove_dir_all(&tmp).unwrap();
- }
-
- #[cfg(not(windows))]
- #[test]
- fn in_git_repo_worktree_resolves_to_main_repo() {
- // worktree .git is a file pointing back to the main repo —
- // in_git_repo should follow it so all worktrees share a workspace
- let tmp = env::temp_dir().join("atuin-test-worktree-git");
- drop(std::fs::remove_dir_all(&tmp));
-
- // main repo at tmp/main with a real .git directory
- let main_repo = tmp.join("main");
- let worktree_git_dir = main_repo.join(".git").join("worktrees").join("feature");
- std::fs::create_dir_all(&worktree_git_dir).unwrap();
-
- // worktree at tmp/worktree with a .git file
- let worktree = tmp.join("worktree");
- let worktree_subdir = worktree.join("src");
- std::fs::create_dir_all(&worktree_subdir).unwrap();
- std::fs::write(
- worktree.join(".git"),
- format!("gitdir: {}", worktree_git_dir.to_str().unwrap()),
- )
- .unwrap();
-
- // should resolve to the main repo root, not the worktree root
- let result = in_git_repo(worktree_subdir.to_str().unwrap());
- assert_eq!(result, Some(main_repo.clone()));
-
- std::fs::remove_dir_all(&tmp).unwrap();
- }
-
- #[test]
- fn dumb_random_test() {
- // Obviously not a test of randomness, but make sure we haven't made some
- // catastrophic error
-
- assert_ne!(crypto_random_string::<1>(), crypto_random_string::<1>());
- assert_ne!(crypto_random_string::<2>(), crypto_random_string::<2>());
- assert_ne!(crypto_random_string::<4>(), crypto_random_string::<4>());
- assert_ne!(crypto_random_string::<8>(), crypto_random_string::<8>());
- assert_ne!(crypto_random_string::<16>(), crypto_random_string::<16>());
- assert_ne!(crypto_random_string::<32>(), crypto_random_string::<32>());
- }
-}
diff --git a/crates/client/src/command/client/server.rs b/crates/client/src/command/client/server.rs
deleted file mode 100644
index 88b12a7a..00000000
--- a/crates/client/src/command/client/server.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use std::net::SocketAddr;
-
-use crate::atuin_server::{Settings, database::DbType, launch, launch_metrics_server};
-
-use clap::Subcommand;
-use eyre::{Context, Result, eyre};
-
-#[derive(Subcommand, Clone, Debug)]
-#[command(infer_subcommands = true)]
-pub(crate) enum Cmd {
- /// Start the server
- Start {
- /// The host address to bind
- #[clap(long)]
- host: Option<String>,
-
- /// The port to bind
- #[clap(long, short)]
- port: Option<u16>,
- },
-
- /// Print server example configuration
- DefaultConfig,
-}
-
-impl Cmd {
- pub(crate) async fn run(self) -> Result<()> {
- match self {
- Self::Start { host, port } => {
- let settings = Settings::new().wrap_err("could not load server settings")?;
- let host = host.as_ref().unwrap_or(&settings.host).clone();
- let port = port.unwrap_or(settings.port);
- let addr = SocketAddr::new(host.parse()?, port);
-
- if settings.metrics.enable {
- tokio::spawn(launch_metrics_server(
- settings.metrics.host.clone(),
- settings.metrics.port,
- ));
- }
-
- match settings.db_settings.db_type() {
- DbType::Postgres => launch(settings, addr).await,
- DbType::Unknown => {
- Err(eyre!("db_uri must start with postgres:// or sqlite://"))
- }
- }
- }
- Self::DefaultConfig => {
- // TODO(@bpeetz): Add this back <2026-06-11>
- println!("TODO");
- Ok(())
- }
- }
- }
-}
diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs
deleted file mode 100644
index 82bbc78f..00000000
--- a/crates/client/src/lib.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-pub fn test() -> String {
- dbg!("Hi!");
- String::new()
-}
diff --git a/crates/client/src/main.rs b/crates/client/src/main.rs
index 12858140..2453c0e1 100644
--- a/crates/client/src/main.rs
+++ b/crates/client/src/main.rs
@@ -21,11 +21,8 @@ use command::AtuinCmd;
mod command;
pub(crate) mod atuin_client;
-pub(crate) mod atuin_common;
-pub(crate) mod atuin_daemon;
pub(crate) mod atuin_history;
pub(crate) mod atuin_pty_proxy;
-pub(crate) mod atuin_server;
mod print_error;
mod sync;