| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
use crate::domain::{AppId, Target, Version}; |
| 16 |
use anyhow::Result; |
| 17 |
use std::collections::HashMap; |
| 18 |
use std::path::Path; |
| 19 |
|
| 20 |
|
| 21 |
pub struct Release<'a> { |
| 22 |
pub app: &'a AppId, |
| 23 |
pub target: Target, |
| 24 |
pub version: &'a Version, |
| 25 |
pub notes: String, |
| 26 |
} |
| 27 |
|
| 28 |
|
| 29 |
|
| 30 |
|
| 31 |
pub trait OtaBackend: Send + Sync { |
| 32 |
fn id(&self) -> &str; |
| 33 |
fn supports(&self, target: Target) -> bool; |
| 34 |
|
| 35 |
|
| 36 |
|
| 37 |
fn publish(&self, rel: &Release, artifact: &Path) -> Result<String>; |
| 38 |
} |
| 39 |
|
| 40 |
|
| 41 |
#[derive(Default)] |
| 42 |
pub struct OtaRegistry { |
| 43 |
backends: HashMap<String, Box<dyn OtaBackend>>, |
| 44 |
} |
| 45 |
|
| 46 |
impl OtaRegistry { |
| 47 |
pub fn new() -> Self { |
| 48 |
Self::default() |
| 49 |
} |
| 50 |
|
| 51 |
pub fn register(&mut self, backend: Box<dyn OtaBackend>) { |
| 52 |
self.backends.insert(backend.id().to_string(), backend); |
| 53 |
} |
| 54 |
|
| 55 |
pub fn get(&self, channel: &str) -> Option<&dyn OtaBackend> { |
| 56 |
self.backends.get(channel).map(|b| b.as_ref()) |
| 57 |
} |
| 58 |
|
| 59 |
|
| 60 |
pub fn standard(mnw_base_url: impl Into<String>) -> Self { |
| 61 |
let mut reg = Self::new(); |
| 62 |
reg.register(Box::new(TauriMnwBackend { base_url: mnw_base_url.into() })); |
| 63 |
reg |
| 64 |
} |
| 65 |
} |
| 66 |
|
| 67 |
|
| 68 |
|
| 69 |
|
| 70 |
|
| 71 |
|
| 72 |
pub struct TauriMnwBackend { |
| 73 |
pub base_url: String, |
| 74 |
} |
| 75 |
|
| 76 |
impl OtaBackend for TauriMnwBackend { |
| 77 |
fn id(&self) -> &str { |
| 78 |
"tauri-mnw" |
| 79 |
} |
| 80 |
|
| 81 |
fn supports(&self, target: Target) -> bool { |
| 82 |
use crate::domain::Platform::*; |
| 83 |
|
| 84 |
matches!(target.platform, Macos | Linux | Windows) |
| 85 |
} |
| 86 |
|
| 87 |
fn publish(&self, rel: &Release, artifact: &Path) -> Result<String> { |
| 88 |
|
| 89 |
anyhow::ensure!(artifact.exists(), "artifact {} does not exist", artifact.display()); |
| 90 |
|
| 91 |
|
| 92 |
|
| 93 |
Ok(format!( |
| 94 |
"tauri-mnw: would publish {app} {ver} {target} ({artifact}) to {base} [P2: upload not yet wired]", |
| 95 |
app = rel.app, |
| 96 |
ver = rel.version, |
| 97 |
target = rel.target, |
| 98 |
artifact = artifact.display(), |
| 99 |
base = self.base_url, |
| 100 |
)) |
| 101 |
} |
| 102 |
} |
| 103 |
|
| 104 |
#[cfg(test)] |
| 105 |
mod tests { |
| 106 |
use super::*; |
| 107 |
|
| 108 |
#[test] |
| 109 |
fn standard_registry_has_tauri_mnw() { |
| 110 |
let reg = OtaRegistry::standard("https://makenot.work"); |
| 111 |
let b = reg.get("tauri-mnw").expect("registered"); |
| 112 |
assert_eq!(b.id(), "tauri-mnw"); |
| 113 |
assert!(b.supports("macos/aarch64".parse().unwrap())); |
| 114 |
assert!(b.supports("linux/x86_64".parse().unwrap())); |
| 115 |
assert!(!b.supports("ios/universal".parse().unwrap())); |
| 116 |
assert!(reg.get("nope").is_none()); |
| 117 |
} |
| 118 |
|
| 119 |
#[test] |
| 120 |
fn publish_refuses_missing_artifact() { |
| 121 |
let reg = OtaRegistry::standard("https://makenot.work"); |
| 122 |
let b = reg.get("tauri-mnw").unwrap(); |
| 123 |
let app = AppId::new("goingson"); |
| 124 |
let ver = Version::parse("0.4.1").unwrap(); |
| 125 |
let rel = Release { app: &app, target: "macos/aarch64".parse().unwrap(), version: &ver, notes: String::new() }; |
| 126 |
assert!(b.publish(&rel, Path::new("/no/such/file")).is_err()); |
| 127 |
} |
| 128 |
} |
| 129 |
|