use serde::{Serialize, Deserialize};
use std::fmt;
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct Cask {
pub token: String,
pub full_token: String,
pub old_tokens: Vec<String>,
pub tap: String,
pub name: Vec<String>,
pub desc: Option<String>,
pub homepage: String,
pub url: String,
pub url_specs: UrlSpecs,
pub version: String,
pub installed: Option<String>,
pub installed_time: Option<u64>,
pub bundle_version: Option<String>,
pub bundle_short_version: Option<String>,
pub outdated: bool,
pub sha256: Option<String>,
pub artifacts: Vec<Artifact>,
pub caveats: Option<String>,
pub depends_on: DependsOn,
pub conflicts_with: Option<ConflictsWith>,
pub container: Option<Container>,
pub auto_updates: Option<AutoUpdates>,
pub deprecated: bool,
pub deprecation_date: Option<String>,
pub deprecation_reason: Option<String>,
pub deprecation_replacement: Option<String>,
pub disabled: bool,
pub disable_date: Option<String>,
pub disable_reason: Option<String>,
pub disable_replacement: Option<String>,
pub tap_git_head: Option<String>,
pub languages: Vec<String>,
pub ruby_source_path: Option<String>,
pub ruby_source_checksum: Option<RubySourceChecksum>,
}
impl Cask {
pub fn is_installed(&self) -> bool {
self.installed.is_some()
}
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct Container {
#[serde(rename = "type")]
pub type_: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)] pub enum AutoUpdates {
Bool(bool),
String(String),
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct UrlSpecs {
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct Artifact {
pub preflight: Option<String>,
pub app: Option<Vec<App>>,
pub uninstall: Option<Vec<Uninstall>>,
pub installer: Option<Vec<Uninstall>>,
pub binary: Option<Vec<Binary>>,
pub zap: Option<Vec<Zap>>,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct Installer {
pub script: Option<InstallerScript>,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct InstallerScript {
pub args: Option<Vec<String>>,
pub executable: Option<String>,
pub sudo: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)] pub enum Uninstall {
Struct(UninstallStruct),
String(String),
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct UninstallStruct {
pub quit: Option<Quit>,
pub delete: Option<Quit>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)] pub enum Quit {
Vec(Vec<String>),
String(String),
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)] pub enum App {
Struct(AppStruct),
String(String),
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct AppStruct {
pub target: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)] pub enum Binary {
Struct(BinaryStruct),
String(String),
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct BinaryStruct {
pub target: Option<String>,
pub path: Option<String>,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct Zap {
pub trash: Option<Trash>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)] pub enum Trash {
Vec(Vec<String>),
String(String),
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct DependsOn {
pub macos: Option<MacOS>,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct MacOS {
#[serde(rename = ">=")]
pub version_gte: Option<Vec<String>>,
#[serde(rename = "==")]
pub version_eq: Option<Vec<String>>,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct ConflictsWith {
pub cask: Option<Vec<String>>,
pub formula: Option<Vec<String>>,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct RubySourceChecksum {
pub sha256: String,
}
impl fmt::Display for UrlSpecs {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{...}}")
}
}
impl fmt::Display for RubySourceChecksum {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.sha256)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{collections::HashMap, fs, path::PathBuf};
use crate::info_all;
use serde_json::{self, Value};
#[test]
fn test_all_to_cask() {
let tempfile = PathBuf::from("target/package.json");
if !tempfile.exists() {
let pkg = info_all().unwrap();
pkg.to_file(&tempfile).unwrap();
}
let out = fs::read_to_string(&tempfile).unwrap();
let all_packages: HashMap<String, Value> = serde_json::from_str(&out).unwrap();
for (key, value) in &all_packages {
println!("{key}");
if key == "formulae" {
continue;
}
let packages: Vec<Value> = value.as_array().unwrap().to_vec();
for val in &packages {
let name = &val["token"];
let pkg_m = serde_json::from_value::<Cask>(val.clone()).map_err(|e| anyhow::Error::new(e));
match pkg_m{
Ok(pkg) => assert_eq!(&pkg.token, name),
Err(e) => {
let text = serde_json::to_string_pretty(val).unwrap();
fs::write("target/cask.json", &text).expect("Failed write");
println!("{}\n{}", text, name);
panic!("{e}")
}
}
}
println!("{}", packages.len());
}
}
}