feat: define manifest models as structs
This commit is contained in:
parent
f1cc4be4b1
commit
106fee3d46
8 changed files with 1347 additions and 47 deletions
1169
Cargo.lock
generated
1169
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -39,3 +39,11 @@ libc = "0.2.172"
|
|||
strum = "0.27.1"
|
||||
strum_macros = "0.27.1"
|
||||
lazy_static = "1.5.0"
|
||||
reqwest = "0.12.15"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.140"
|
||||
semver = { version = "1.0.26", features = ["serde"] }
|
||||
uuid = { version = "1.16.0", features = ["serde"] }
|
||||
url = { version = "2.5.4", features = ["serde"] }
|
||||
langtag = { version = "0.4.0", features = ["serde"] }
|
||||
serde_with = "3.12.0"
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use std::env::consts;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{Display, EnumString};
|
||||
|
||||
#[derive(Debug, Clone, Copy, EnumString, Display)]
|
||||
#[derive(Debug, Clone, Copy, EnumString, Display, Deserialize, Serialize)]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum Arch {
|
||||
X86,
|
||||
X64,
|
||||
|
@ -17,4 +19,4 @@ impl Default for Arch {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ mod app;
|
|||
pub(crate) mod mode;
|
||||
mod errors;
|
||||
mod logging;
|
||||
mod manifest;
|
||||
|
||||
pub const APP_NAME: &str = concat!(env!("CARGO_PKG_NAME"), " v", env!("CARGO_PKG_VERSION"));
|
||||
|
||||
|
|
56
src/manifest/channel.rs
Executable file
56
src/manifest/channel.rs
Executable file
|
@ -0,0 +1,56 @@
|
|||
use langtag::LangTag;
|
||||
use serde::Deserialize;
|
||||
use serde_with::serde_as;
|
||||
use url::Url;
|
||||
|
||||
use crate::{ManifestInfo, app::arch::Arch};
|
||||
|
||||
use super::{ChannelItemType, Payload};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Manifest<'manifest> {
|
||||
pub manifest_version: String,
|
||||
pub info: ChannelManifestInfo,
|
||||
#[serde(borrow)]
|
||||
pub channel_items: Vec<ChannelItem<'manifest>>,
|
||||
}
|
||||
|
||||
ManifestInfo! {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ChannelManifestInfo {
|
||||
pub commit_id: String,
|
||||
pub community_or_lower_flight_id: String,
|
||||
pub professional_or_greater_flight_id: String,
|
||||
pub q_build_session_id: String,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde_as]
|
||||
pub struct ChannelItem<'lang> {
|
||||
pub id: String,
|
||||
pub version: String,
|
||||
pub r#type: ChannelItemType,
|
||||
pub payloads: Option<Vec<Payload>>,
|
||||
#[serde(borrow)]
|
||||
pub localized_resoures: Option<Vec<LocalizedResource<'lang>>>,
|
||||
#[serde_as(as = "FromStr")]
|
||||
pub chip: Arch,
|
||||
#[serde_as(as = "FromStr")]
|
||||
pub product_arch: Arch,
|
||||
pub release_notes: Url,
|
||||
pub supports_download_then_update: bool,
|
||||
// TODO: requirements
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LocalizedResource<'lang> {
|
||||
#[serde(borrow)]
|
||||
pub language: &'lang LangTag,
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub license: Url,
|
||||
}
|
48
src/manifest/installer/mod.rs
Executable file
48
src/manifest/installer/mod.rs
Executable file
|
@ -0,0 +1,48 @@
|
|||
use serde::Deserialize;
|
||||
use signer::Signer;
|
||||
|
||||
use crate::ManifestInfo;
|
||||
|
||||
use super::Payload;
|
||||
|
||||
pub mod signer;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Manifest {
|
||||
pub manifest_version: String,
|
||||
pub engine_version: String,
|
||||
pub info: InstallerManifestInfo,
|
||||
pub signers: Vec<Signer>,
|
||||
pub packages: Vec<Package>,
|
||||
}
|
||||
|
||||
ManifestInfo! {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InstallerManifestInfo {}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Package {
|
||||
id: String,
|
||||
version: String,
|
||||
r#type: PackageType,
|
||||
payloads: Vec<Payload>,
|
||||
install_sizes: InstallSizes,
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize)]
|
||||
pub enum PackageType {
|
||||
Component,
|
||||
Msi,
|
||||
Exe,
|
||||
Vsix,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InstallSizes {
|
||||
pub target_drive: u64,
|
||||
}
|
46
src/manifest/installer/signer.rs
Executable file
46
src/manifest/installer/signer.rs
Executable file
|
@ -0,0 +1,46 @@
|
|||
use serde::Deserialize;
|
||||
use serde_with::serde_as;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde_as]
|
||||
pub struct Signer {
|
||||
#[serde_as(as = "FromStr")]
|
||||
#[serde(rename = "$id")]
|
||||
pub id: usize,
|
||||
#[serde(rename = "camelCase")]
|
||||
pub subject_name: String, // TODO: Use a RFC2253 parser
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SignerRef(usize);
|
||||
|
||||
impl SignerRef {
|
||||
pub fn new(id: usize) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
|
||||
pub fn downcast(self, signers: Vec<Signer>) -> Signer {
|
||||
signers[self.0].clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for SignerRef {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
struct RefWrapper {
|
||||
#[serde(rename = "$ref")]
|
||||
reference: String,
|
||||
}
|
||||
|
||||
let wrapper = RefWrapper::deserialize(deserializer)?;
|
||||
let id = wrapper
|
||||
.reference
|
||||
.parse::<usize>()
|
||||
.map_err(serde::de::Error::custom)?;
|
||||
|
||||
Ok(SignerRef(id))
|
||||
}
|
||||
}
|
60
src/manifest/mod.rs
Executable file
60
src/manifest/mod.rs
Executable file
|
@ -0,0 +1,60 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use installer::signer::SignerRef;
|
||||
use serde::Deserialize;
|
||||
use url::Url;
|
||||
|
||||
pub mod channel;
|
||||
pub mod installer;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! ManifestInfo {
|
||||
(#[derive($($derive:meta),*)] $pub:vis struct $name:ident { $($fpub:vis $field:ident : $type:ty,)* }) => {
|
||||
#[derive(serde::Deserialize, $($derive),*)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde_with::serde_as]
|
||||
$pub struct $name {
|
||||
pub id: String,
|
||||
pub build_branch: String,
|
||||
pub build_version: String,
|
||||
pub local_build: String,
|
||||
pub manifest_name: String,
|
||||
pub manifest_type: crate::manifest::ManifestType,
|
||||
pub product_display_version: String,
|
||||
pub product_line: String,
|
||||
pub product_line_version: String,
|
||||
pub product_milestone: String,
|
||||
#[serde_as(as = "FromStr")]
|
||||
pub product_milestone_is_prerelease: bool,
|
||||
pub product_name: String,
|
||||
#[serde_as(as = "FromStr")]
|
||||
pub product_patch_version: u32,
|
||||
pub product_semantic_version: semver::Version,
|
||||
$($fpub $field : $type,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Copy)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ManifestType {
|
||||
Channel,
|
||||
Installer,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Copy)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub enum ChannelItemType {
|
||||
Manifest,
|
||||
ChannelProduct,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Payload {
|
||||
pub file_name: String,
|
||||
pub sha256: String,
|
||||
pub size: usize,
|
||||
pub url: Url,
|
||||
pub signer: Option<Vec<SignerRef>>,
|
||||
}
|
Loading…
Add table
Reference in a new issue