maven_rs/pom/
scm.rs

1use derive_builder::Builder;
2use serde::{Deserialize, Serialize};
3use thiserror::Error;
4
5use crate::editor::{
6    utils::{add_if_present, from_element_using_builder, sync_element},
7    ElementConverter, HasElementName, UpdatableElement,
8};
9#[derive(Debug, Clone, Copy, Error)]
10pub enum SCMError {
11    #[error("The scm did not start with scm")]
12    DidNotStartWithScm,
13    #[error("The scm did not have a provider")]
14    MissingProvider,
15}
16
17#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
18#[serde(rename_all = "camelCase")]
19pub struct Scm {
20    /// URL should be formatted as `scm:{provider}:{provider_specific}`
21    #[builder(setter(into, strip_option), default)]
22    pub url: Option<String>,
23    #[builder(setter(into, strip_option), default)]
24    pub connection: Option<String>,
25    #[builder(setter(into, strip_option), default)]
26    pub tag: Option<String>,
27    #[builder(setter(into, strip_option), default)]
28    pub developer_connection: Option<String>,
29}
30impl Scm {
31    /// Gets the provider of the scm
32    /// ```rust
33    /// use maven_rs::pom::ScmBuilder;
34    /// let scm = ScmBuilder::default().connection("scm:git:https://github.com/wyatt-herkamp/maven-rs").build().unwrap();
35    /// assert_eq!(scm.get_provider_for_connection().unwrap(), Some("git".to_owned()));
36    /// ```
37    pub fn get_provider_for_connection(&self) -> Result<Option<String>, SCMError> {
38        let Some((_, provider, _)) = self.split_connection()? else {
39            return Ok(None);
40        };
41        Ok(Some(provider.to_owned()))
42    }
43    /// Gets the provider specific part of the scm
44    ///
45    /// ```rust
46    /// use maven_rs::pom::ScmBuilder;
47    /// let scm = ScmBuilder::default().connection("scm:git:https://github.com/wyatt-herkamp/maven-rs").build().unwrap();
48    ///
49    /// assert_eq!(scm.get_provider_specific_for_connection().unwrap(), Some("https://github.com/wyatt-herkamp/maven-rs".to_owned()));
50    ///
51    /// ```
52    pub fn get_provider_specific_for_connection(&self) -> Result<Option<String>, SCMError> {
53        let Some((_, _, url)) = self.split_connection()? else {
54            return Ok(None);
55        };
56        Ok(Some(url.join(":")))
57    }
58    #[allow(clippy::type_complexity)]
59    fn split_connection(&self) -> Result<Option<(&str, &str, Vec<&str>)>, SCMError> {
60        let Some(url) = self.connection.as_deref() else {
61            return Err(SCMError::MissingProvider);
62        };
63        let mut parts = url.split(':');
64        let part_one = parts.next().ok_or(SCMError::DidNotStartWithScm)?;
65        if part_one != "scm" {
66            return Err(SCMError::DidNotStartWithScm);
67        }
68        let part_two = parts.next().ok_or(SCMError::MissingProvider)?;
69        let part_three = parts.collect::<Vec<&str>>();
70        Ok(Some((part_one, part_two, part_three)))
71    }
72}
73
74impl UpdatableElement for Scm {
75    fn update_element(
76        &self,
77        element: edit_xml::Element,
78        document: &mut edit_xml::Document,
79    ) -> Result<(), crate::editor::XMLEditorError> {
80        let Self {
81            url,
82            connection,
83            tag,
84            developer_connection,
85        } = self;
86        sync_element(document, element, "url", url.as_deref());
87        sync_element(document, element, "connection", connection.as_deref());
88        sync_element(document, element, "tag", tag.as_deref());
89        sync_element(
90            document,
91            element,
92            "developerConnection",
93            developer_connection.as_deref(),
94        );
95        Ok(())
96    }
97}
98impl HasElementName for Scm {
99    fn element_name() -> &'static str {
100        "scm"
101    }
102}
103impl ElementConverter for Scm {
104    from_element_using_builder!(
105        ScmBuilder,
106        element,
107        document,
108        "url" => url,
109        "connection" => connection,
110        "tag" => tag,
111        "developerConnection" => developer_connection
112    );
113
114    fn into_children(
115        self,
116        document: &mut edit_xml::Document,
117    ) -> Result<Vec<edit_xml::Element>, crate::editor::XMLEditorError> {
118        let Self {
119            url,
120            connection,
121            tag,
122            developer_connection,
123        } = self;
124        let mut children = vec![];
125        add_if_present!(document, children, url, "url");
126        add_if_present!(document, children, connection, "connection");
127        add_if_present!(document, children, tag, "tag");
128        add_if_present!(
129            document,
130            children,
131            developer_connection,
132            "developerConnection"
133        );
134        Ok(children)
135    }
136}