Skip to main content

upstream_rs/models/upstream/
package.rs

1use std::path::PathBuf;
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::models::common::{
7    enums::{Channel, Filetype, Provider},
8    version::Version,
9};
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct Package {
13    pub name: String,
14    pub repo_slug: String,
15
16    pub filetype: Filetype,
17    pub version: Version,
18    pub channel: Channel,
19    pub provider: Provider,
20    pub base_url: Option<String>,
21
22    pub is_pinned: bool,
23    pub match_pattern: Option<String>,
24    pub exclude_pattern: Option<String>,
25    pub icon_path: Option<PathBuf>,
26    pub install_path: Option<PathBuf>,
27    pub exec_path: Option<PathBuf>,
28
29    pub last_upgraded: DateTime<Utc>,
30}
31
32impl Package {
33    #[allow(clippy::too_many_arguments)]
34    pub fn with_defaults(
35        name: String,
36        repo_slug: String,
37        filetype: Filetype,
38        match_pattern: Option<String>,
39        exclude_pattern: Option<String>,
40        channel: Channel,
41        provider: Provider,
42        base_url: Option<String>,
43    ) -> Self {
44        Self {
45            name,
46            repo_slug,
47
48            filetype,
49            version: Version::new(0, 0, 0, false),
50            channel,
51            provider,
52            base_url,
53
54            is_pinned: false,
55            match_pattern,
56            exclude_pattern,
57            icon_path: None,
58            install_path: None,
59            exec_path: None,
60
61            last_upgraded: Utc::now(),
62        }
63    }
64
65    pub fn is_same_as(&self, other: &Package) -> bool {
66        self.provider == other.provider
67            && self.repo_slug == other.repo_slug
68            && self.channel == other.channel
69            && self.name == other.name
70            && self.base_url == other.base_url
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::Package;
77    use crate::models::common::enums::{Channel, Filetype, Provider};
78
79    #[test]
80    fn with_defaults_sets_expected_base_state() {
81        let pkg = Package::with_defaults(
82            "bat".to_string(),
83            "sharkdp/bat".to_string(),
84            Filetype::Auto,
85            Some("linux".to_string()),
86            Some("debug".to_string()),
87            Channel::Stable,
88            Provider::Github,
89            None,
90        );
91
92        assert_eq!(pkg.version.major, 0);
93        assert!(!pkg.is_pinned);
94        assert!(pkg.install_path.is_none());
95        assert!(pkg.exec_path.is_none());
96        assert_eq!(pkg.match_pattern.as_deref(), Some("linux"));
97        assert_eq!(pkg.exclude_pattern.as_deref(), Some("debug"));
98    }
99
100    #[test]
101    fn is_same_as_uses_identity_fields_only() {
102        let mut a = Package::with_defaults(
103            "ripgrep".to_string(),
104            "BurntSushi/ripgrep".to_string(),
105            Filetype::Archive,
106            None,
107            None,
108            Channel::Stable,
109            Provider::Github,
110            Some("https://api.github.com".to_string()),
111        );
112        let mut b = a.clone();
113        b.version.major = 99;
114        b.is_pinned = true;
115        b.match_pattern = Some("x86_64".to_string());
116        assert!(a.is_same_as(&b));
117
118        a.name = "rg".to_string();
119        assert!(!a.is_same_as(&b));
120    }
121}