diff --git a/Cargo.lock b/Cargo.lock index ff4d3ff..46ae303 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,6 +148,7 @@ dependencies = [ "bstr", "config", "gix", + "gix-url", "insta", "lazy_static", "nom", @@ -162,6 +163,7 @@ dependencies = [ "toml_edit", "tracing", "unic-ucd-category", + "url", ] [[package]] @@ -1449,12 +1451,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "home" version = "0.5.9" @@ -2203,17 +2199,6 @@ dependencies = [ "windows-registry", ] -[[package]] -name = "resolve" -version = "0.1.0" -dependencies = [ - "anyhow", - "hex", - "serde", - "toml_edit", - "url", -] - [[package]] name = "ring" version = "0.17.8" diff --git a/Cargo.toml b/Cargo.toml index 746b916..028d937 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,4 @@ -workspace.members = [ - "crates/atom", - "crates/config", - "crates/nixec", - "crates/resolve", -] +workspace.members = ["crates/atom", "crates/config", "crates/nixec"] [package] edition = "2021" @@ -67,8 +62,10 @@ gix = { version = "^0.66", default-features = false, features = [ ] } [features] -default = ["git"] -git = ["gix"] +default = ["stores"] +git = ["gix", "atom/git"] +stores = ["git"] [patch.crates-io] -gix = { git = "https://github.com/nrdxp/gitoxide", tag = "gix-v0.66.0-eka" } +gix = { git = "https://github.com/nrdxp/gitoxide", tag = "gix-v0.66.0-eka" } +gix-url = { git = "https://github.com/nrdxp/gitoxide", tag = "gix-v0.66.0-eka" } diff --git a/crates/atom/Cargo.toml b/crates/atom/Cargo.toml index be8d40e..1b831ec 100644 --- a/crates/atom/Cargo.toml +++ b/crates/atom/Cargo.toml @@ -21,9 +21,17 @@ thiserror.workspace = true tokio.workspace = true toml_edit.workspace = true tracing.workspace = true +url.workspace = true -config = { path = "../config", features = ["git"] } -gix = { workspace = true, default-features = false, features = ["serde"] } +config = { path = "../config" } +gix = { workspace = true, default-features = false, features = [ + "serde", +], optional = true } +gix-url = { version = "^0.27", features = ["serde"] } + +[features] +default = [] +git = ["dep:gix", "config/git"] [dev-dependencies] anyhow.workspace = true diff --git a/crates/atom/src/lib.rs b/crates/atom/src/lib.rs index 893804e..8503791 100644 --- a/crates/atom/src/lib.rs +++ b/crates/atom/src/lib.rs @@ -26,6 +26,7 @@ //! point to the original commit from which the Atom's content references, ensuring //! it remains live. Ensuring we can trivially verify an Atom's content at any time. #![deny(missing_docs)] +#![cfg_attr(not(feature = "git"), allow(dead_code))] mod core; mod id; diff --git a/crates/atom/src/manifest/depends.rs b/crates/atom/src/manifest/depends.rs new file mode 100644 index 0000000..6815820 --- /dev/null +++ b/crates/atom/src/manifest/depends.rs @@ -0,0 +1,45 @@ +use std::path::PathBuf; + +use semver::Version; +use serde::{Deserialize, Serialize}; +use url::Url; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] +enum AtomSrc { + Url(Url), + Path(PathBuf), +} + +/// atom dependencies +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] +pub struct Dependencies { + version: Version, + src: AtomSrc, +} + +/// legacy pins +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] +pub struct Pins { + url: Url, +} + +/// sources fetched at build time +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] +pub struct Srcs { + url: Url, +} + +impl AtomSrc { + pub(crate) fn url(self) -> Option { + match self { + AtomSrc::Url(url) => Some(url), + _ => None, + } + } + pub(crate) fn path(self) -> Option { + match self { + AtomSrc::Path(path) => Some(path), + _ => None, + } + } +} diff --git a/crates/atom/src/publish/error.rs b/crates/atom/src/publish/error.rs index 0e08eae..3e28780 100644 --- a/crates/atom/src/publish/error.rs +++ b/crates/atom/src/publish/error.rs @@ -1,112 +1,118 @@ //! # Publishing Errors //! //! This module contains the error types for errors that might occur during publishing. -use crate::store::git::Root; -use gix::object; -use std::path::PathBuf; use thiserror::Error; #[derive(Error, Debug)] /// The error representing a failure during publishing for any store implementation. pub enum PublishError { + #[cfg(feature = "git")] /// A transparent wrapper for a [`GitError`]. #[error(transparent)] - Git(#[from] GitError), + Git(#[from] git::Error), } -/// An error representing a failure during publishing to a Git Ekala store. -#[derive(Error, Debug)] -pub enum GitError { - /// A transparent wrapper for a [`Box`] - #[error(transparent)] - RemotNotFound(#[from] Box), - /// A transparent wrapper for a [`Box`] - #[error(transparent)] - RevParseFailed(#[from] Box), - /// A transparent wrapper for a [`object::find::existing::with_conversion::Error`] - #[error(transparent)] - NoCommit(#[from] object::find::existing::with_conversion::Error), - /// A transparent wrapper for a [`object::commit::Error`] - #[error(transparent)] - NoTree(#[from] object::commit::Error), - /// A transparent wrapper for a [`object::find::existing::Error`] - #[error(transparent)] - NoObject(#[from] object::find::existing::Error), - /// A transparent wrapper for a [`object::write::Error`] - #[error(transparent)] - WriteFailed(#[from] object::write::Error), - /// A transparent wrapper for a [`gix::reference::edit::Error`] - #[error(transparent)] - RefUpdateFailed(#[from] gix::reference::edit::Error), - /// A transparent wrapper for a [`gix::revision::walk::Error`] - #[error(transparent)] - CalculatingRootFailed(#[from] gix::revision::walk::Error), - /// A transparent wrapper for a [`gix::traverse::commit::simple::Error`] - #[error(transparent)] - RootConversionFailed(#[from] gix::traverse::commit::simple::Error), - /// A transparent wrapper for a [`std::io::Error`] - #[error(transparent)] - Io(#[from] std::io::Error), - /// A transparent wrapper for a [`tokio::task::JoinError`] - #[error(transparent)] - JoinFailed(#[from] tokio::task::JoinError), - /// The reported root & the atom root are inconsistent. - #[error("Atom does not derive from the initialized history")] - InconsistentRoot { - /// The root according to the remote we are publishing to. - remote: Root, - /// The root of history for the source from which the atom is derived. - atom: Root, - }, - /// The remote is not initialized as an Ekala store. - #[error("Remote is not initialized")] - NotInitialized, - /// The Atom manifest is invalid, and this Atom will be ignored. - #[error("Ignoring invalid Atom manifest")] - Invalid(#[source] crate::manifest::AtomError, Box), - /// The path given does not point to an Atom. - #[error("The given path does not point to an Atom")] - NotAnAtom(PathBuf), - /// Failed to sync a least one Atom to the remote. - #[error("Failed to sync some Atoms to the remote")] - SomePushFailed, - /// Some Atoms failed to publish - #[error("Failed to published some of the specified Atoms")] - Failed, - /// A transparent wrapper for a [`crate::store::git::Error`] - #[error(transparent)] - StoreError(#[from] crate::store::git::Error), - /// No Atoms found under the given directory. - #[error("Failed to find any Atoms under the current directory")] - NotFound, - /// Atoms with the same Unicode ID were found in the given revision. - #[error("Duplicate Atoms detected in the given revision, refusing to publish")] - Duplicates, -} +#[cfg(feature = "git")] +pub mod git { + //! # Git Publishing Errors + use crate::store::git::Root; + use gix::object; + use std::path::PathBuf; + /// An error representing a failure during publishing to a Git Ekala store. + #[derive(thiserror::Error, Debug)] + pub enum Error { + /// A transparent wrapper for a [`Box`] + #[error(transparent)] + RemotNotFound(#[from] Box), + /// A transparent wrapper for a [`Box`] + #[error(transparent)] + RevParseFailed(#[from] Box), + /// A transparent wrapper for a [`object::find::existing::with_conversion::Error`] + #[error(transparent)] + NoCommit(#[from] object::find::existing::with_conversion::Error), + /// A transparent wrapper for a [`object::commit::Error`] + #[error(transparent)] + NoTree(#[from] object::commit::Error), + /// A transparent wrapper for a [`object::find::existing::Error`] + #[error(transparent)] + NoObject(#[from] object::find::existing::Error), + /// A transparent wrapper for a [`object::write::Error`] + #[error(transparent)] + WriteFailed(#[from] object::write::Error), + /// A transparent wrapper for a [`gix::reference::edit::Error`] + #[error(transparent)] + RefUpdateFailed(#[from] gix::reference::edit::Error), + /// A transparent wrapper for a [`gix::revision::walk::Error`] + #[error(transparent)] + CalculatingRootFailed(#[from] gix::revision::walk::Error), + /// A transparent wrapper for a [`gix::traverse::commit::simple::Error`] + #[error(transparent)] + RootConversionFailed(#[from] gix::traverse::commit::simple::Error), + /// A transparent wrapper for a [`std::io::Error`] + #[error(transparent)] + Io(#[from] std::io::Error), + /// A transparent wrapper for a [`tokio::task::JoinError`] + #[error(transparent)] + JoinFailed(#[from] tokio::task::JoinError), + /// The reported root & the atom root are inconsistent. + #[error("Atom does not derive from the initialized history")] + InconsistentRoot { + /// The root according to the remote we are publishing to. + remote: Root, + /// The root of history for the source from which the atom is derived. + atom: Root, + }, + /// The remote is not initialized as an Ekala store. + #[error("Remote is not initialized")] + NotInitialized, + /// The Atom manifest is invalid, and this Atom will be ignored. + #[error("Ignoring invalid Atom manifest")] + Invalid(#[source] crate::manifest::AtomError, Box), + /// The path given does not point to an Atom. + #[error("The given path does not point to an Atom")] + NotAnAtom(PathBuf), + /// Failed to sync a least one Atom to the remote. + #[error("Failed to sync some Atoms to the remote")] + SomePushFailed, + /// Some Atoms failed to publish + #[error("Failed to published some of the specified Atoms")] + Failed, + /// A transparent wrapper for a [`crate::store::git::Error`] + #[error(transparent)] + StoreError(#[from] crate::store::git::Error), + /// No Atoms found under the given directory. + #[error("Failed to find any Atoms under the current directory")] + NotFound, + /// Atoms with the same Unicode ID were found in the given revision. + #[error("Duplicate Atoms detected in the given revision, refusing to publish")] + Duplicates, + } -impl GitError { - const INCONSISTENT_ROOT_SUGGESTION: &str = - "You may need to reinitalize the remote if the issue persists"; + #[cfg(feature = "git")] + impl Error { + const INCONSISTENT_ROOT_SUGGESTION: &str = + "You may need to reinitalize the remote if the issue persists"; - /// Warn the user about specific error conditions encountered during publishing. - pub fn warn(&self) { - match self { - GitError::InconsistentRoot { remote, atom } => { - tracing::warn!( - message = %self, - atom_root = %**atom, - remote_root = %**remote, - suggest = GitError::INCONSISTENT_ROOT_SUGGESTION - ); - } - GitError::Invalid(e, path) => { - tracing::warn!(message = %self, path = %path.display(), message = format!("\n{}", e)); - } - GitError::NotAnAtom(path) => { - tracing::warn!(message = %self, path = %path.display()); + /// Warn the user about specific error conditions encountered during publishing. + pub fn warn(&self) { + match self { + Error::InconsistentRoot { remote, atom } => { + tracing::warn!( + message = %self, + atom_root = %**atom, + remote_root = %**remote, + suggest = Error::INCONSISTENT_ROOT_SUGGESTION + ); + } + Error::Invalid(e, path) => { + tracing::warn!(message = %self, path = %path.display(), message = format!("\n{}", e)); + } + Error::NotAnAtom(path) => { + tracing::warn!(message = %self, path = %path.display()); + } + Error::Failed => (), + _ => tracing::warn!(message = %self), } - GitError::Failed => (), - _ => tracing::warn!(message = %self), } } } diff --git a/crates/atom/src/publish/git/inner.rs b/crates/atom/src/publish/git/inner.rs index 3747804..d3b6bf3 100644 --- a/crates/atom/src/publish/git/inner.rs +++ b/crates/atom/src/publish/git/inner.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::{ core::AtomPaths, - publish::{error::GitError, ATOM_ORIGIN}, + publish::{error::git::Error, ATOM_ORIGIN}, store::git, Atom, AtomId, Manifest, }; @@ -33,7 +33,7 @@ impl<'a> GitContext<'a> { Ok(content) })?; - Manifest::get_atom(&content).map_err(|e| GitError::Invalid(e, Box::new(path.into()))) + Manifest::get_atom(&content).map_err(|e| Error::Invalid(e, Box::new(path.into()))) } /// Compute the [`ObjectId`] of the given proto-object in memory @@ -74,10 +74,10 @@ impl<'a> GitContext<'a> { let paths = AtomPaths::new(path); let entry = self .tree_search(paths.spec())? - .ok_or(GitError::NotAnAtom(path.into()))?; + .ok_or(Error::NotAnAtom(path.into()))?; if !entry.mode().is_blob() { - return Err(GitError::NotAnAtom(path.into())); + return Err(Error::NotAnAtom(path.into())); } let lock = self @@ -92,7 +92,7 @@ impl<'a> GitContext<'a> { .and_then(|spec| { let id = AtomId::compute(&self.commit, spec.id.clone())?; if self.root != *id.root() { - return Err(GitError::InconsistentRoot { + return Err(Error::InconsistentRoot { remote: self.root, atom: *id.root(), }); diff --git a/crates/atom/src/publish/git/mod.rs b/crates/atom/src/publish/git/mod.rs index 72c57f9..e1aa263 100644 --- a/crates/atom/src/publish/git/mod.rs +++ b/crates/atom/src/publish/git/mod.rs @@ -15,7 +15,7 @@ mod test; mod inner; -use super::{error::GitError, Content, PublishOutcome, Record}; +use super::{error::git::Error, Content, PublishOutcome, Record}; use crate::{ core::AtomPaths, store::{git::Root, NormalizeStorePath}, @@ -32,7 +32,7 @@ type GitAtomId = AtomId; /// The Outcome of an Atom publish attempt to a Git store. pub type GitOutcome = PublishOutcome; /// The Result type used for various methods during publishing to a Git store. -pub type GitResult = Result; +pub type GitResult = Result; type GitRecord = Record; #[derive(Debug)] @@ -49,7 +49,7 @@ pub struct GitContext<'a> { /// The reported root commit according to the remote. root: Root, /// A [`JoinSet`] of push tasks to avoid blocking on them. - push_tasks: RefCell, GitError>>>, + push_tasks: RefCell, Error>>>, /// Path buf for efficient tree searches buf: RefCell>, } @@ -143,7 +143,7 @@ impl<'a> GitPublisher<'a> { .ekala_root() .map_err(|e| { e.warn(); - GitError::NotInitialized + Error::NotInitialized })?; Ok(GitPublisher { @@ -166,7 +166,7 @@ fn calculate_capacity(record_count: usize) -> usize { use super::StateValidator; impl<'a> StateValidator for GitPublisher<'a> { - type Error = GitError; + type Error = Error; type Publisher = GitContext<'a>; fn validate(publisher: &Self::Publisher) -> Result { @@ -177,7 +177,7 @@ impl<'a> StateValidator for GitPublisher<'a> { .tree() .traverse() .breadthfirst(&mut record) - .map_err(|_| GitError::NotFound)?; + .map_err(|_| Error::NotFound)?; let cap = calculate_capacity(record.records.len()); let mut atoms: HashMap = HashMap::with_capacity(cap); @@ -195,7 +195,7 @@ impl<'a> StateValidator for GitPublisher<'a> { fst = %path.display(), snd = %duplicate.display(), ); - return Err(GitError::Duplicates); + return Err(Error::Duplicates); } atoms.insert(atom.id, path); } @@ -212,7 +212,7 @@ impl<'a> StateValidator for GitPublisher<'a> { } impl<'a> Builder<'a, Root> for GitPublisher<'a> { - type Error = GitError; + type Error = Error; type Publisher = GitContext<'a>; fn build(&self) -> Result<(ValidAtoms, Self::Publisher), Self::Error> { @@ -257,7 +257,7 @@ use std::collections::HashMap; impl<'a> super::private::Sealed for GitContext<'a> {} impl<'a> Publish for GitContext<'a> { - type Error = GitError; + type Error = Error; /// Publishes atoms. /// @@ -374,7 +374,7 @@ impl<'a> GitContext<'a> { /// which were offloaded to a seperate thread of execution of Tokio's runtime. /// /// An errors that occurred will be collected into a [`Vec`]. - pub async fn await_pushes(&self, errors: &mut Vec) { + pub async fn await_pushes(&self, errors: &mut Vec) { use tokio::sync::Mutex; let tasks = Mutex::new(self.push_tasks.borrow_mut()); @@ -390,7 +390,7 @@ impl<'a> GitContext<'a> { errors.push(e); } Err(e) => { - errors.push(GitError::JoinFailed(e)); + errors.push(Error::JoinFailed(e)); } } } diff --git a/crates/atom/src/publish/mod.rs b/crates/atom/src/publish/mod.rs index 4139504..1504e16 100644 --- a/crates/atom/src/publish/mod.rs +++ b/crates/atom/src/publish/mod.rs @@ -4,10 +4,12 @@ //! to a store implementation. Currently, only a Git store is implemented, but future //! work will likely include more alternate backends, e.g. an S3 bucket. pub mod error; +#[cfg(feature = "git")] pub mod git; use crate::{id::Id, AtomId}; +#[cfg(feature = "git")] use git::GitContent; use std::collections::HashMap; use std::path::{Path, PathBuf}; @@ -42,6 +44,7 @@ type ValidAtoms = HashMap; /// Contains the content pertinent to a specific implementation for reporting results /// to the user. pub enum Content { + #[cfg(feature = "git")] /// Content specific to the Git implementation. Git(GitContent), } diff --git a/crates/atom/src/store.rs b/crates/atom/src/store.rs index e1f77d1..cc8ba56 100644 --- a/crates/atom/src/store.rs +++ b/crates/atom/src/store.rs @@ -1,4 +1,5 @@ //! # Atom Store Interface +#[cfg(feature = "git")] pub mod git; use std::path::{Path, PathBuf}; diff --git a/crates/atom/src/uri/mod.rs b/crates/atom/src/uri/mod.rs index 9e1e731..d8d488f 100644 --- a/crates/atom/src/uri/mod.rs +++ b/crates/atom/src/uri/mod.rs @@ -23,8 +23,8 @@ use serde::{Deserialize, Serialize}; use super::id::Id; use crate::id::Error; +use gix_url::Url; -use gix::Url; use semver::VersionReq; use std::collections::HashMap; use thiserror::Error; @@ -245,7 +245,7 @@ pub enum UriError { InvalidVersionReq(#[from] semver::Error), /// The Url did not parse correctly. #[error(transparent)] - UrlParse(#[from] gix::url::parse::Error), + UrlParse(#[from] gix_url::parse::Error), /// There is no alias in the configuration matching the one given in the URI. #[error("The passed alias does not exist: {0}")] NoAlias(String), @@ -327,7 +327,7 @@ impl<'a> UrlRef<'a> { } fn to_url(&self) -> Option { - use gix::url::Scheme; + use gix_url::Scheme; let (frag, resolved) = self.render_alias().unwrap_or((self.frag?, None)); diff --git a/crates/resolve/Cargo.toml b/crates/resolve/Cargo.toml deleted file mode 100644 index c0cb02d..0000000 --- a/crates/resolve/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -edition = "2021" -name = "resolve" -version = "0.1.0" - -[dependencies] -hex = "^0.4" - -anyhow.workspace = true -serde.workspace = true -toml_edit.workspace = true -url.workspace = true diff --git a/crates/resolve/src/lib.rs b/crates/resolve/src/lib.rs deleted file mode 100644 index d8004be..0000000 --- a/crates/resolve/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod lock; - -#[cfg(test)] -mod tests {} diff --git a/crates/resolve/src/lock.rs b/crates/resolve/src/lock.rs deleted file mode 100644 index 565f614..0000000 --- a/crates/resolve/src/lock.rs +++ /dev/null @@ -1,128 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::fmt; -use url::Url; - -type Name = String; - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct Lockfile { - pub version: u8, - #[serde(flatten)] - pub schema: LockSchema, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] -#[serde(untagged)] -pub enum LockSchema { - V1(LockV1), -} -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct LockV1 { - pub dep: Vec, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct Locked { - pub name: Name, - pub repo: Url, - pub sum: Sha1Hash, - pub deps: Option>, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Sha1Hash([u8; 20]); - -impl TryFrom<&str> for Sha1Hash { - type Error = anyhow::Error; - - fn try_from(hex_str: &str) -> Result { - if hex_str.len() != 40 { - return Err(anyhow::anyhow!("SHA-1 hash must be 40 characters long")); - } - - let mut bytes = [0u8; 20]; - hex::decode_to_slice(hex_str, &mut bytes as &mut [u8])?; - - Ok(Sha1Hash(bytes)) - } -} - -impl TryFrom for Sha1Hash { - type Error = anyhow::Error; - - fn try_from(hex_str: String) -> Result { - Self::try_from(hex_str.as_str()) - } -} - -impl Serialize for Sha1Hash { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.collect_str(self) - } -} - -impl<'de> Deserialize<'de> for Sha1Hash { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - let bytes = Self::try_from(s).map_err(serde::de::Error::custom)?; - Ok(bytes) - } -} - -impl fmt::Display for Sha1Hash { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", hex::encode(self.0)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use toml_edit::de::from_str; - use toml_edit::ser::to_string_pretty; - - #[test] - fn serialize_lock() -> anyhow::Result<()> { - macro_rules! svec { - ($($x:expr),*) => (vec![$($x.to_string()),*]); - } - - let orig_string = r#" -version = 1 - -[[dep]] -name = "foo" -repo = "https://github.com/ekala-project/atom.git" -sum = "318a942f39b56f6e9af878564f883d43307ceb87" -deps = [ - "bar", - "baz", - "buz 0.2", -] -"# - .trim_start(); - - let orig = Lockfile { - version: 1, - schema: LockSchema::V1(LockV1 { - dep: vec![Locked { - name: "foo".to_owned(), - repo: Url::parse("https://github.com/ekala-project/atom.git")?, - sum: Sha1Hash::try_from("318a942f39b56f6e9af878564f883d43307ceb87")?, - deps: Some(svec!["bar", "baz", "buz 0.2"]), - }], - }), - }; - let string = to_string_pretty(&orig)?; - let lock: Lockfile = from_str(string.as_str())?; - assert_eq!(orig_string, string); - assert_eq!(orig, lock); - Ok(()) - } -} diff --git a/src/cli/commands/init.rs b/src/cli/commands/init.rs index a4e1be3..315a91e 100644 --- a/src/cli/commands/init.rs +++ b/src/cli/commands/init.rs @@ -5,30 +5,34 @@ use clap::Parser; pub struct Args { #[command(flatten)] #[cfg(feature = "git")] - git: GitArgs, + git: git::Args, } -#[derive(Parser, Debug)] -#[command(next_help_heading = "Git Options")] -struct GitArgs { - /// The target remote to initialize - #[arg(long, short = 't', default_value_t = git::default_remote().to_owned(), name = "TARGET")] - remote: String, +#[cfg(feature = "git")] +mod git { + use atom::store::git; + use clap::Parser; + #[derive(Parser, Debug)] + #[command(next_help_heading = "Git Options")] + pub(super) struct Args { + /// The target remote to initialize + #[arg(long, short = 't', default_value_t = git::default_remote().to_owned(), name = "TARGET")] + pub(super) remote: String, + } } -use atom::store::git; -pub(super) fn run(store: Option, args: Args) -> Result<(), git::Error> { - use atom::store::Init; - if let Some(store) = store { - match store { - Detected::Git(repo) => { - let repo = repo.to_thread_local(); - let remote = repo - .find_remote(args.git.remote.as_str()) - .map_err(Box::new)?; - remote.ekala_init()? - } +pub(super) fn run(store: Detected, args: Args) -> Result<(), anyhow::Error> { + match store { + #[cfg(feature = "git")] + Detected::Git(repo) => { + use atom::store::Init; + let repo = repo.to_thread_local(); + let remote = repo + .find_remote(args.git.remote.as_str()) + .map_err(Box::new)?; + remote.ekala_init()? } + _ => {} } Ok(()) } diff --git a/src/cli/commands/mod.rs b/src/cli/commands/mod.rs index ca457a4..19a85c2 100644 --- a/src/cli/commands/mod.rs +++ b/src/cli/commands/mod.rs @@ -35,7 +35,7 @@ pub async fn run(args: Args) -> anyhow::Result<()> { publish::run(store.await?, args).await?; } - Commands::Init(args) => init::run(store.await.ok(), args)?, + Commands::Init(args) => init::run(store.await?, args)?, } Ok(()) } diff --git a/src/cli/commands/publish/git/mod.rs b/src/cli/commands/publish/git/mod.rs index d3a1342..1fc3e7b 100644 --- a/src/cli/commands/publish/git/mod.rs +++ b/src/cli/commands/publish/git/mod.rs @@ -2,7 +2,7 @@ use super::PublishArgs; use atom::{ publish::{ - error::GitError, + error::git::Error, git::{GitOutcome, GitResult}, }, store::git, @@ -37,7 +37,7 @@ pub(super) struct GitArgs { pub(super) async fn run( repo: &ThreadSafeRepository, args: PublishArgs, -) -> GitResult<(Vec>, Vec)> { +) -> GitResult<(Vec>, Vec)> { use atom::{ publish::{git::GitPublisher, Builder, Publish}, store::NormalizeStorePath, @@ -62,7 +62,7 @@ pub(super) async fn run( }; if paths.is_empty() { - return Err(GitError::NotFound); + return Err(Error::NotFound); } publisher.publish(paths) } else { diff --git a/src/cli/commands/publish/mod.rs b/src/cli/commands/publish/mod.rs index c20d210..fa8e28c 100644 --- a/src/cli/commands/publish/mod.rs +++ b/src/cli/commands/publish/mod.rs @@ -3,11 +3,7 @@ mod git; use crate::cli::store::Detected; -use atom::publish::{ - self, - error::{GitError, PublishError}, - Content, -}; +use atom::publish::{self, error::PublishError}; use clap::Parser; use std::path::PathBuf; @@ -34,12 +30,14 @@ struct StoreArgs { use publish::Stats; pub(super) async fn run(store: Detected, args: PublishArgs) -> Result { - use Err as Skipped; - use Ok as Published; - let mut stats = publish::Stats::default(); + #[cfg_attr(not(feature = "stores"), allow(unused_mut))] + let mut stats = Stats::default(); match store { #[cfg(feature = "git")] Detected::Git(repo) => { + use atom::publish::{error, Content}; + use Err as Skipped; + use Ok as Published; let (results, mut errors) = git::run(repo, args).await?; for res in results { @@ -72,9 +70,11 @@ pub(super) async fn run(store: Detected, args: PublishArgs) -> Result {} } + Ok(stats) } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index f3ed7a8..e19273b 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,3 +1,4 @@ +#![cfg_attr(not(feature = "stores"), allow(unused_variables))] mod commands; pub mod logging; mod store; diff --git a/src/cli/store.rs b/src/cli/store.rs index 97f792d..8fb9810 100644 --- a/src/cli/store.rs +++ b/src/cli/store.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "git")] use atom::store::git; use thiserror::Error; @@ -9,33 +10,31 @@ use gix::ThreadSafeRepository; pub(super) enum Detected { #[cfg(feature = "git")] Git(&'static ThreadSafeRepository), + #[allow(dead_code)] + None, } -#[tracing::instrument(err)] -pub(super) async fn detect() -> Result { +pub(super) async fn detect() -> Result { #[cfg(feature = "git")] - { - if let Ok(Some(repo)) = git::repo() { - use std::fs; - let git_dir = fs::canonicalize(repo.path()) - .ok() - .map(|p| p.display().to_string()); - let work_dir = repo - .work_dir() - .and_then(|dir| fs::canonicalize(dir).ok()) - .map(|p| p.display().to_string()); + if let Ok(Some(repo)) = git::repo() { + use std::fs; + let git_dir = fs::canonicalize(repo.path()) + .ok() + .map(|p| p.display().to_string()); + let work_dir = repo + .work_dir() + .and_then(|dir| fs::canonicalize(dir).ok()) + .map(|p| p.display().to_string()); - tracing::debug!(message = "Detected Git repository", git_dir, work_dir); - return Ok(Detected::Git(repo)); - } + tracing::debug!(message = "Detected Git repository", git_dir, work_dir); + return Ok(Detected::Git(repo)); } - #[cfg_attr(feature = "git", allow(unreachable_code))] - Err(StoreError::FailedDetection) + Err(Error::FailedDetection) } #[derive(Error, Debug)] -pub(crate) enum StoreError { +pub(crate) enum Error { #[error("No supported repository found in this directory or its parents")] FailedDetection, #[cfg(feature = "git")]