|
| 1 | +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy |
| 2 | +// SPDX-License-Identifier: Apache-2.0 |
| 3 | +// SPDX-License-Identifier: MIT |
| 4 | + |
| 5 | +use serde::Deserialize; |
| 6 | + |
| 7 | +use std::{ |
| 8 | + collections::HashMap, |
| 9 | + fmt::Write, |
| 10 | + fs::read_to_string, |
| 11 | + path::{Path, PathBuf}, |
| 12 | +}; |
| 13 | + |
| 14 | +#[derive(Clone, Deserialize)] |
| 15 | +pub struct CargoLockPackage { |
| 16 | + pub name: String, |
| 17 | + pub version: String, |
| 18 | + pub source: Option<String>, |
| 19 | +} |
| 20 | + |
| 21 | +#[derive(Deserialize)] |
| 22 | +pub struct CargoLock { |
| 23 | + pub package: Vec<CargoLockPackage>, |
| 24 | +} |
| 25 | + |
| 26 | +#[derive(Clone, Deserialize)] |
| 27 | +pub struct CargoManifestDependencyPackage { |
| 28 | + pub version: Option<String>, |
| 29 | + pub git: Option<String>, |
| 30 | + pub branch: Option<String>, |
| 31 | + pub rev: Option<String>, |
| 32 | + pub path: Option<PathBuf>, |
| 33 | +} |
| 34 | + |
| 35 | +#[derive(Clone, Deserialize)] |
| 36 | +#[serde(untagged)] |
| 37 | +pub enum CargoManifestDependency { |
| 38 | + Version(String), |
| 39 | + Package(CargoManifestDependencyPackage), |
| 40 | +} |
| 41 | + |
| 42 | +#[derive(Deserialize)] |
| 43 | +pub struct CargoManifestPackage { |
| 44 | + pub version: String, |
| 45 | +} |
| 46 | + |
| 47 | +#[derive(Deserialize)] |
| 48 | +pub struct CargoManifest { |
| 49 | + pub package: CargoManifestPackage, |
| 50 | + pub dependencies: HashMap<String, CargoManifestDependency>, |
| 51 | +} |
| 52 | + |
| 53 | +pub struct CrateVersion { |
| 54 | + pub version: String, |
| 55 | + pub found_crate_versions: Vec<String>, |
| 56 | +} |
| 57 | + |
| 58 | +pub fn crate_version( |
| 59 | + tauri_dir: &Path, |
| 60 | + manifest: Option<&CargoManifest>, |
| 61 | + lock: Option<&CargoLock>, |
| 62 | + name: &str, |
| 63 | +) -> CrateVersion { |
| 64 | + let crate_lock_packages: Vec<CargoLockPackage> = lock |
| 65 | + .as_ref() |
| 66 | + .map(|lock| { |
| 67 | + lock |
| 68 | + .package |
| 69 | + .iter() |
| 70 | + .filter(|p| p.name == name) |
| 71 | + .cloned() |
| 72 | + .collect() |
| 73 | + }) |
| 74 | + .unwrap_or_default(); |
| 75 | + let (crate_version_string, found_crate_versions) = |
| 76 | + match (&manifest, &lock, crate_lock_packages.len()) { |
| 77 | + (Some(_manifest), Some(_lock), 1) => { |
| 78 | + let crate_lock_package = crate_lock_packages.first().unwrap(); |
| 79 | + let version_string = if let Some(s) = &crate_lock_package.source { |
| 80 | + if s.starts_with("git") { |
| 81 | + format!("{} ({})", s, crate_lock_package.version) |
| 82 | + } else { |
| 83 | + crate_lock_package.version.clone() |
| 84 | + } |
| 85 | + } else { |
| 86 | + crate_lock_package.version.clone() |
| 87 | + }; |
| 88 | + (version_string, vec![crate_lock_package.version.clone()]) |
| 89 | + } |
| 90 | + (None, Some(_lock), 1) => { |
| 91 | + let crate_lock_package = crate_lock_packages.first().unwrap(); |
| 92 | + let version_string = if let Some(s) = &crate_lock_package.source { |
| 93 | + if s.starts_with("git") { |
| 94 | + format!("{} ({})", s, crate_lock_package.version) |
| 95 | + } else { |
| 96 | + crate_lock_package.version.clone() |
| 97 | + } |
| 98 | + } else { |
| 99 | + crate_lock_package.version.clone() |
| 100 | + }; |
| 101 | + ( |
| 102 | + format!("{version_string} (no manifest)"), |
| 103 | + vec![crate_lock_package.version.clone()], |
| 104 | + ) |
| 105 | + } |
| 106 | + _ => { |
| 107 | + let mut found_crate_versions = Vec::new(); |
| 108 | + let mut is_git = false; |
| 109 | + let manifest_version = match manifest.and_then(|m| m.dependencies.get(name).cloned()) { |
| 110 | + Some(tauri) => match tauri { |
| 111 | + CargoManifestDependency::Version(v) => { |
| 112 | + found_crate_versions.push(v.clone()); |
| 113 | + v |
| 114 | + } |
| 115 | + CargoManifestDependency::Package(p) => { |
| 116 | + if let Some(v) = p.version { |
| 117 | + found_crate_versions.push(v.clone()); |
| 118 | + v |
| 119 | + } else if let Some(p) = p.path { |
| 120 | + let manifest_path = tauri_dir.join(&p).join("Cargo.toml"); |
| 121 | + let v = match read_to_string(manifest_path) |
| 122 | + .map_err(|_| ()) |
| 123 | + .and_then(|m| toml::from_str::<CargoManifest>(&m).map_err(|_| ())) |
| 124 | + { |
| 125 | + Ok(manifest) => manifest.package.version, |
| 126 | + Err(_) => "unknown version".to_string(), |
| 127 | + }; |
| 128 | + format!("path:{p:?} [{v}]") |
| 129 | + } else if let Some(g) = p.git { |
| 130 | + is_git = true; |
| 131 | + let mut v = format!("git:{g}"); |
| 132 | + if let Some(branch) = p.branch { |
| 133 | + let _ = write!(v, "&branch={branch}"); |
| 134 | + } else if let Some(rev) = p.rev { |
| 135 | + let _ = write!(v, "#{rev}"); |
| 136 | + } |
| 137 | + v |
| 138 | + } else { |
| 139 | + "unknown manifest".to_string() |
| 140 | + } |
| 141 | + } |
| 142 | + }, |
| 143 | + None => "no manifest".to_string(), |
| 144 | + }; |
| 145 | + |
| 146 | + let lock_version = match (lock, crate_lock_packages.is_empty()) { |
| 147 | + (Some(_lock), false) => crate_lock_packages |
| 148 | + .iter() |
| 149 | + .map(|p| p.version.clone()) |
| 150 | + .collect::<Vec<String>>() |
| 151 | + .join(", "), |
| 152 | + (Some(_lock), true) => "unknown lockfile".to_string(), |
| 153 | + _ => "no lockfile".to_string(), |
| 154 | + }; |
| 155 | + |
| 156 | + ( |
| 157 | + format!( |
| 158 | + "{} {}({})", |
| 159 | + manifest_version, |
| 160 | + if is_git { "(git manifest)" } else { "" }, |
| 161 | + lock_version |
| 162 | + ), |
| 163 | + found_crate_versions, |
| 164 | + ) |
| 165 | + } |
| 166 | + }; |
| 167 | + |
| 168 | + CrateVersion { |
| 169 | + found_crate_versions, |
| 170 | + version: crate_version_string, |
| 171 | + } |
| 172 | +} |
0 commit comments