1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use std::{fmt, hash::Hash, path::PathBuf, time::SystemTime};
pub use semver;
use serde::{Deserialize, Serialize};
/// Used to specify from which particular revision of a repository.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum GitTarget {
/// The components is pointing to a specific revision in the repository.
#[serde(untagged)]
Revision {
#[serde(rename = "revision")]
hash: String,
},
/// The components is pointing to a specific tag in the repository.
#[serde(untagged)]
Tag {
#[serde(rename = "tag")]
name: String,
},
/// The components is pointing to a specific *branch* in the repository.
///
/// NOTE: When an update is issued, these type of components will trigger an update if the
/// branch they were pointing to had new commits since the time the component was installed.
/// This means that these components are _not_ deterministic and their behavior could change
/// in-between updates.
#[serde(untagged)]
Branch {
/// This is the name of the branch being tracked.
#[serde(rename = "branch")]
name: String,
/// This field represents the revision hash that is currently presently installed.
///
/// This is only meant to be used in the local manifest in order to check for updates.
latest_revision: Option<String>,
},
}
impl Default for GitTarget {
fn default() -> Self {
GitTarget::Branch {
name: String::from("main"),
latest_revision: None,
}
}
}
impl fmt::Display for GitTarget {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
GitTarget::Branch { name, .. } => write!(f, "branch = \"{name}\""),
GitTarget::Revision { hash } => write!(f, "rev = \"{hash}\""),
GitTarget::Tag { name: tag } => write!(f, "tag = \"{tag}\""),
}
}
}
impl GitTarget {
pub fn to_cargo_flag(&self) -> [String; 2] {
match &self {
GitTarget::Branch { name, .. } => [String::from("--branch"), String::from(name)],
GitTarget::Revision { hash } => [String::from("--rev"), String::from(hash)],
GitTarget::Tag { name: tag } => [String::from("--tag"), String::from(tag)],
}
}
}
/// Represents the canonical versioning authority for a tool or toolchain
#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum Authority {
/// The authority for this tool/toolchain is a local filesystem path
Path {
/// The path to the artifact.
path: PathBuf,
/// Represents the latest modification done inside this directory.
#[serde(skip_serializing_if = "Option::is_none")]
last_modification: Option<SystemTime>,
},
/// The authority for this tool/toolchain is a git repository.
Git {
/// Points to the git repository containting the [crate::manifest::Component].
repository_url: String,
/// The subdirectory within the repository which contains the component
#[serde(skip_serializing_if = "Option::is_none")]
subpath: Option<String>,
/// If the target is missing from the [crate::manifest::Manifest], then we assume that it
/// is pointing to the tip of the `main` branch
#[serde(default)]
#[serde(flatten)]
target: GitTarget,
},
/// The authority for this tool/toolchain is a semantic version resolved in the appropriate
/// registry (e.g. crates.io).
Registry {
/// The semantic versioning string for the package/artifact to fetch
version: semver::Version,
},
}
impl core::str::FromStr for Authority {
type Err = serde_json::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
serde_json::from_str(s)
}
}
impl fmt::Display for Authority {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Authority::Registry { version, .. } => write!(f, "{version}"),
Authority::Git { repository_url, target, .. } => {
write!(f, "{repository_url}:{target}")
},
Authority::Path { path, .. } => write!(f, "{}", path.display()),
}
}
}