From 308d9ab7b08c9d143efe6fd3466b93b67bb58c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kat=20March=C3=A1n?= Date: Fri, 24 Mar 2023 21:09:52 -0700 Subject: [PATCH] feat(gitinfo): add a FromStr impl for GitInfo also, remove the public plain parser method and have people just use FromStr for PackageSpec directly --- crates/oro-package-spec/src/gitinfo.rs | 72 ++++++++++++++++++++++++++ crates/oro-package-spec/src/lib.rs | 2 +- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/crates/oro-package-spec/src/gitinfo.rs b/crates/oro-package-spec/src/gitinfo.rs index acd67bb5..fcdc03ed 100644 --- a/crates/oro-package-spec/src/gitinfo.rs +++ b/crates/oro-package-spec/src/gitinfo.rs @@ -2,9 +2,13 @@ use std::fmt; use std::str::FromStr; use node_semver::Range; +use nom::combinator::all_consuming; +use nom::Err; use url::Url; use crate::error::{PackageSpecError, SpecErrorKind}; +use crate::parsers::git; +use crate::PackageSpec; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum GitHost { @@ -220,10 +224,78 @@ impl fmt::Display for GitInfo { } } +impl FromStr for GitInfo { + type Err = PackageSpecError; + + fn from_str(s: &str) -> Result { + parse_gitinfo(s) + } +} + +fn parse_gitinfo(input: I) -> Result +where + I: AsRef, +{ + let input = input.as_ref(); + match all_consuming(git::git_spec)(input) { + Ok((_, PackageSpec::Git(arg))) => Ok(arg), + Ok(_) => unreachable!("This should only return git specs"), + Err(err) => Err(match err { + Err::Error(e) | Err::Failure(e) => PackageSpecError { + input: input.into(), + offset: e.input.as_ptr() as usize - input.as_ptr() as usize, + kind: if let Some(kind) = e.kind { + kind + } else if let Some(ctx) = e.context { + SpecErrorKind::Context(ctx) + } else { + SpecErrorKind::Other + }, + }, + Err::Incomplete(_) => PackageSpecError { + input: input.into(), + offset: input.len() - 1, + kind: SpecErrorKind::IncompleteInput, + }, + }), + } +} #[cfg(test)] mod tests { use super::*; + #[test] + fn from_str() { + let info_url = GitInfo::Url { + url: "https://foo.com/hello.git".parse().unwrap(), + committish: Some("deadbeef".into()), + semver: None, + }; + let parsed_url: GitInfo = "git+https://foo.com/hello.git#deadbeef".parse().unwrap(); + assert_eq!(parsed_url, info_url); + + let info_ssh = GitInfo::Ssh { + ssh: "git@foo.com:here.git".into(), + committish: None, + semver: Some("^1.2.3".parse().unwrap()), + }; + let parsed_ssh: GitInfo = "git+ssh://git@foo.com:here.git#semver:>=1.2.3 <2.0.0-0" + .parse() + .unwrap(); + assert_eq!(parsed_ssh, info_ssh); + + let info_hosted = GitInfo::Hosted { + owner: "foo".into(), + repo: "bar".into(), + host: GitHost::GitHub, + committish: None, + semver: None, + requested: None, + }; + let parsed_hosted: GitInfo = "github:foo/bar".parse().unwrap(); + assert_eq!(parsed_hosted, info_hosted); + } + #[test] fn display_url() { let info = GitInfo::Url { diff --git a/crates/oro-package-spec/src/lib.rs b/crates/oro-package-spec/src/lib.rs index 65a68122..6b19d955 100644 --- a/crates/oro-package-spec/src/lib.rs +++ b/crates/oro-package-spec/src/lib.rs @@ -136,7 +136,7 @@ impl fmt::Display for VersionSpec { } } -pub fn parse_package_spec(input: I) -> Result +fn parse_package_spec(input: I) -> Result where I: AsRef, {