code formatting

This commit is contained in:
Caelan Sayler
2025-06-04 16:03:10 +01:00
committed by Caelan
parent aff7ade8a9
commit 23661f7d6b
5 changed files with 110 additions and 146 deletions

View File

@@ -3,40 +3,20 @@ use std::fs;
use std::path::Path; use std::path::Path;
fn main() { fn main() {
// Get the workspace version // Get the workspace version
let version = get_workspace_version().unwrap_or_else(|| { let version = get_workspace_version().unwrap_or_else(|| env::var("CARGO_PKG_VERSION").unwrap_or_else(|_| "0.1.0".to_string()));
env::var("CARGO_PKG_VERSION").unwrap_or_else(|_| "0.1.0".to_string())
});
let python_version = convert_to_python_version(&version); let python_version = convert_to_python_version(&version);
// Set environment variables for PyO3 // Set environment variables for PyO3
println!("cargo:rustc-env=PYTHON_VERSION={}", python_version); println!("cargo:rustc-env=PYTHON_VERSION={}", python_version);
// Try setting the package version for PyO3 to pick up // Try setting the package version for PyO3 to pick up
println!("cargo:metadata=version={}", python_version); println!("cargo:metadata=version={}", python_version);
// Also set it as a cfg value // Also set it as a cfg value
println!("cargo:rustc-cfg=version=\"{}\"", python_version); println!("cargo:rustc-cfg=version=\"{}\"", python_version);
println!("cargo:rerun-if-changed=../../Cargo.toml"); println!("cargo:rerun-if-changed=../../Cargo.toml");
} }
@@ -44,33 +24,32 @@ fn get_workspace_version() -> Option<String> {
// Navigate up to workspace root and read Cargo.toml // Navigate up to workspace root and read Cargo.toml
let manifest_dir = env::var("CARGO_MANIFEST_DIR").ok()?; let manifest_dir = env::var("CARGO_MANIFEST_DIR").ok()?;
let workspace_toml = Path::new(&manifest_dir) let workspace_toml = Path::new(&manifest_dir)
.parent()? // src .parent()? // src
.parent()? // velopack root .parent()? // velopack root
.join("Cargo.toml"); .join("Cargo.toml");
if !workspace_toml.exists() { if !workspace_toml.exists() {
return None; return None;
} }
let content = fs::read_to_string(&workspace_toml).ok()?; let content = fs::read_to_string(&workspace_toml).ok()?;
// Simple parsing to extract version from [workspace.package] section // Simple parsing to extract version from [workspace.package] section
let mut in_workspace_package = false; let mut in_workspace_package = false;
for (_line_num, line) in content.lines().enumerate() { for (_line_num, line) in content.lines().enumerate() {
let trimmed = line.trim(); let trimmed = line.trim();
if trimmed == "[workspace.package]" { if trimmed == "[workspace.package]" {
in_workspace_package = true; in_workspace_package = true;
continue; continue;
} }
if trimmed.starts_with('[') && trimmed != "[workspace.package]" { if trimmed.starts_with('[') && trimmed != "[workspace.package]" {
if in_workspace_package { if in_workspace_package {}
}
in_workspace_package = false; in_workspace_package = false;
continue; continue;
} }
if in_workspace_package && trimmed.starts_with("version") { if in_workspace_package && trimmed.starts_with("version") {
if let Some(equals_pos) = trimmed.find('=') { if let Some(equals_pos) = trimmed.find('=') {
let version_part = &trimmed[equals_pos + 1..].trim(); let version_part = &trimmed[equals_pos + 1..].trim();
@@ -80,7 +59,7 @@ fn get_workspace_version() -> Option<String> {
} }
} }
} }
None None
} }
@@ -90,38 +69,38 @@ fn convert_to_python_version(rust_version: &str) -> String {
let base = &rust_version[..git_pos]; let base = &rust_version[..git_pos];
return ensure_xyz_format(base); return ensure_xyz_format(base);
} }
// Handle local development versions like "0.0.0-local" - drop local suffix // Handle local development versions like "0.0.0-local" - drop local suffix
if rust_version.ends_with("-local") { if rust_version.ends_with("-local") {
let base = rust_version.trim_end_matches("-local"); let base = rust_version.trim_end_matches("-local");
return ensure_xyz_format(base); return ensure_xyz_format(base);
} }
// Handle Rust pre-release patterns and convert to Python equivalents // Handle Rust pre-release patterns and convert to Python equivalents
if rust_version.contains("-alpha") { if rust_version.contains("-alpha") {
let base = rust_version.split("-alpha").next().unwrap(); let base = rust_version.split("-alpha").next().unwrap();
let alpha_num = extract_prerelease_number(rust_version, "-alpha"); let alpha_num = extract_prerelease_number(rust_version, "-alpha");
return format!("{}a{}", ensure_xyz_format(base), alpha_num); return format!("{}a{}", ensure_xyz_format(base), alpha_num);
} }
if rust_version.contains("-beta") { if rust_version.contains("-beta") {
let base = rust_version.split("-beta").next().unwrap(); let base = rust_version.split("-beta").next().unwrap();
let beta_num = extract_prerelease_number(rust_version, "-beta"); let beta_num = extract_prerelease_number(rust_version, "-beta");
return format!("{}b{}", ensure_xyz_format(base), beta_num); return format!("{}b{}", ensure_xyz_format(base), beta_num);
} }
if rust_version.contains("-rc") { if rust_version.contains("-rc") {
let base = rust_version.split("-rc").next().unwrap(); let base = rust_version.split("-rc").next().unwrap();
let rc_num = extract_prerelease_number(rust_version, "-rc"); let rc_num = extract_prerelease_number(rust_version, "-rc");
return format!("{}rc{}", ensure_xyz_format(base), rc_num); return format!("{}rc{}", ensure_xyz_format(base), rc_num);
} }
// For any other dash-separated version, just take the base // For any other dash-separated version, just take the base
if rust_version.contains('-') { if rust_version.contains('-') {
let base = rust_version.split('-').next().unwrap(); let base = rust_version.split('-').next().unwrap();
return ensure_xyz_format(base); return ensure_xyz_format(base);
} }
ensure_xyz_format(rust_version) ensure_xyz_format(rust_version)
} }
@@ -159,23 +138,23 @@ mod tests {
// Git versions - drop git ref // Git versions - drop git ref
assert_eq!(convert_to_python_version("0.0.1213-g57cf68d"), "0.0.1213"); assert_eq!(convert_to_python_version("0.0.1213-g57cf68d"), "0.0.1213");
assert_eq!(convert_to_python_version("1.2-g57cf68d"), "1.2.0"); assert_eq!(convert_to_python_version("1.2-g57cf68d"), "1.2.0");
// Local versions - drop local suffix // Local versions - drop local suffix
assert_eq!(convert_to_python_version("0.0.0-local"), "0.0.0"); assert_eq!(convert_to_python_version("0.0.0-local"), "0.0.0");
assert_eq!(convert_to_python_version("1.2.3-local"), "1.2.3"); assert_eq!(convert_to_python_version("1.2.3-local"), "1.2.3");
// Pre-release versions - convert to Python format // Pre-release versions - convert to Python format
assert_eq!(convert_to_python_version("1.0.0-alpha.1"), "1.0.0a1"); assert_eq!(convert_to_python_version("1.0.0-alpha.1"), "1.0.0a1");
assert_eq!(convert_to_python_version("1.0.0-alpha"), "1.0.0a0"); assert_eq!(convert_to_python_version("1.0.0-alpha"), "1.0.0a0");
assert_eq!(convert_to_python_version("1.0.0-beta.2"), "1.0.0b2"); assert_eq!(convert_to_python_version("1.0.0-beta.2"), "1.0.0b2");
assert_eq!(convert_to_python_version("1.0.0-rc.1"), "1.0.0rc1"); assert_eq!(convert_to_python_version("1.0.0-rc.1"), "1.0.0rc1");
// Standard versions - ensure x.y.z format // Standard versions - ensure x.y.z format
assert_eq!(convert_to_python_version("1.0.0"), "1.0.0"); assert_eq!(convert_to_python_version("1.0.0"), "1.0.0");
assert_eq!(convert_to_python_version("1.2"), "1.2.0"); assert_eq!(convert_to_python_version("1.2"), "1.2.0");
assert_eq!(convert_to_python_version("1"), "1.0.0"); assert_eq!(convert_to_python_version("1"), "1.0.0");
// Other dash-separated versions - take base only // Other dash-separated versions - take base only
assert_eq!(convert_to_python_version("1.0.0-something-else"), "1.0.0"); assert_eq!(convert_to_python_version("1.0.0-something-else"), "1.0.0");
} }
} }

View File

@@ -85,8 +85,7 @@ impl VelopackAppWrapper {
/// Runs the Velopack startup logic /// Runs the Velopack startup logic
pub fn run(&mut self, _py: Python) -> PyResult<()> { pub fn run(&mut self, _py: Python) -> PyResult<()> {
// Create the Rust VelopackApp with our stored configuration // Create the Rust VelopackApp with our stored configuration
let mut app = VelopackAppRust::build() let mut app = VelopackAppRust::build().set_auto_apply_on_startup(self.auto_apply);
.set_auto_apply_on_startup(self.auto_apply);
// Set args if provided // Set args if provided
if let Some(ref args) = self.args { if let Some(ref args) = self.args {
@@ -175,4 +174,3 @@ impl VelopackAppWrapper {
Ok(()) Ok(())
} }
} }

View File

@@ -1,5 +1,5 @@
use pyo3::prelude::*;
use pyo3::exceptions::PyException; use pyo3::exceptions::PyException;
use pyo3::prelude::*;
#[pyclass(name="VelopackError", extends=PyException, module="velopack.exceptions")] #[pyclass(name="VelopackError", extends=PyException, module="velopack.exceptions")]
#[derive(Debug)] #[derive(Debug)]
@@ -18,4 +18,3 @@ impl VelopackError {
self.message.clone() self.message.clone()
} }
} }

View File

@@ -1,40 +1,37 @@
use asset::PyUpdateInfo;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::PyModule; use pyo3::types::PyModule;
mod asset; mod types;
pub use asset::PyVelopackAsset; use types::*;
mod exceptions; mod exceptions;
pub use exceptions::VelopackError; use exceptions::VelopackError;
mod app; mod app;
pub use app::VelopackAppWrapper; use app::VelopackAppWrapper;
mod manager; mod manager;
pub use manager::UpdateManagerWrapper; use manager::UpdateManagerWrapper;
#[pymodule] #[pymodule]
fn velopack(m: &Bound<'_, PyModule>) -> PyResult<()> { fn velopack(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<VelopackError>()?; m.add_class::<VelopackError>()?;
// auto-generated DTO's
m.add_class::<PyVelopackAsset>()?; m.add_class::<PyVelopackAsset>()?;
m.add_class::<PyUpdateInfo>()?; m.add_class::<PyUpdateInfo>()?;
m.add_class::<PyUpdateOptions>()?;
m.add_class::<PyVelopackLocatorConfig>()?;
// concrete classes
m.add_class::<VelopackAppWrapper>()?; m.add_class::<VelopackAppWrapper>()?;
m.add_class::<UpdateManagerWrapper>()?; m.add_class::<UpdateManagerWrapper>()?;
// add __version__ attribute // add __version__ attribute
m.add("__version__", env!("CARGO_PKG_VERSION"))?; m.add("__version__", env!("CARGO_PKG_VERSION"))?;
// add __author__ attribute // add __author__ attribute
m.add("__author__", env!("CARGO_PKG_AUTHORS"))?; m.add("__author__", env!("CARGO_PKG_AUTHORS"))?;
Ok(()) Ok(())
} }

View File

@@ -1,13 +1,12 @@
use pyo3::prelude::*;
use std::sync::mpsc; use std::sync::mpsc;
use std::thread; use std::thread;
use pyo3::prelude::*;
use velopack::{UpdateCheck, UpdateInfo, UpdateManager as VelopackUpdateManagerRust};
use velopack::sources::AutoSource; use velopack::sources::AutoSource;
use velopack::{UpdateCheck, UpdateInfo, UpdateManager as VelopackUpdateManagerRust};
use crate::exceptions::VelopackError; use crate::exceptions::VelopackError;
use crate::asset::PyUpdateInfo; use crate::types::*;
#[pyclass(name = "UpdateManager")] #[pyclass(name = "UpdateManager")]
pub struct UpdateManagerWrapper { pub struct UpdateManagerWrapper {
@@ -17,88 +16,80 @@ pub struct UpdateManagerWrapper {
#[pymethods] #[pymethods]
impl UpdateManagerWrapper { impl UpdateManagerWrapper {
// for new, just take in a string, which is the source // for new, just take in a string, which is the source
#[new] #[new]
pub fn new(source: String) -> PyResult<Self> { #[pyo3(signature = (source, options = None, locator = None))]
let source = AutoSource::new(&source); pub fn new(source: String, options: Option<PyUpdateOptions>, locator: Option<PyVelopackLocatorConfig>) -> PyResult<Self> {
// set myinner to a new VelopackUpdateManager with the source let source = AutoSource::new(&source);
let inner = VelopackUpdateManagerRust::new(source, None, None) // set myinner to a new VelopackUpdateManager with the source
.map_err(|e| PyErr::new::<VelopackError, _>(format!("Failed to create UpdateManager: {}", e)))?; let inner = VelopackUpdateManagerRust::new(source, options.map(Into::into), locator.map(Into::into))
Ok(UpdateManagerWrapper { .map_err(|e| PyErr::new::<VelopackError, _>(format!("Failed to create UpdateManager: {}", e)))?;
inner, Ok(UpdateManagerWrapper { inner })
} }
)
}
// check_for_updates return update info indicating if updates are available
// check_for_updates return update info indicating if updates are available
/// This method checks for updates and returns update info if updates are available, None otherwise. /// This method checks for updates and returns update info if updates are available, None otherwise.
pub fn check_for_updates(&mut self) -> PyResult<Option<PyUpdateInfo>> { pub fn check_for_updates(&mut self) -> PyResult<Option<PyUpdateInfo>> {
let update_check = self.inner.check_for_updates() let update_check =
.map_err(|e| PyErr::new::<VelopackError, _>(format!("Failed to check for updates: {}", e)))?; self.inner.check_for_updates().map_err(|e| PyErr::new::<VelopackError, _>(format!("Failed to check for updates: {}", e)))?;
match update_check { match update_check {
UpdateCheck::UpdateAvailable(updates) => { UpdateCheck::UpdateAvailable(updates) => {
let py_updates = PyUpdateInfo::from(updates); let py_updates = PyUpdateInfo::from(updates);
Ok(Some(py_updates)) Ok(Some(py_updates))
}, }
UpdateCheck::NoUpdateAvailable => { UpdateCheck::NoUpdateAvailable => Ok(None),
Ok(None) UpdateCheck::RemoteIsEmpty => Ok(None),
},
UpdateCheck::RemoteIsEmpty => {
Ok(None)
} }
} }
}
#[pyo3(signature = (update_info, progress_callback = None))]
pub fn download_updates(&mut self, update_info: &PyUpdateInfo, progress_callback: Option<PyObject>) -> PyResult<()> {
// Convert PyUpdateInfo back to rust UpdateInfo
let rust_update_info: UpdateInfo = update_info.clone().into();
#[pyo3(signature = (update_info, progress_callback = None))] if let Some(callback) = progress_callback {
pub fn download_updates(&mut self, update_info: &PyUpdateInfo, progress_callback: Option<PyObject>) -> PyResult<()> { // Create a channel for progress updates
// Convert PyUpdateInfo back to rust UpdateInfo let (sender, receiver) = mpsc::channel::<i16>();
let rust_update_info: UpdateInfo = update_info.clone().into();
// Spawn a thread to handle progress updates
if let Some(callback) = progress_callback { let progress_thread = thread::spawn(move || {
// Create a channel for progress updates Python::with_gil(|py| {
let (sender, receiver) = mpsc::channel::<i16>(); while let Ok(progress) = receiver.recv() {
if let Err(e) = callback.call1(py, (progress,)) {
// Spawn a thread to handle progress updates // Log error but continue - don't break the download
let progress_thread = thread::spawn(move || { eprintln!("Progress callback error: {}", e);
Python::with_gil(|py| { break;
while let Ok(progress) = receiver.recv() { }
if let Err(e) = callback.call1(py, (progress,)) {
// Log error but continue - don't break the download
eprintln!("Progress callback error: {}", e);
break;
} }
} });
}); });
});
// Call download with the sender
// Call download with the sender let result = self
let result = self.inner.download_updates(&rust_update_info, Some(sender)) .inner
.map_err(|e| PyErr::new::<VelopackError, _>(format!("Failed to download updates: {}", e))); .download_updates(&rust_update_info, Some(sender))
.map_err(|e| PyErr::new::<VelopackError, _>(format!("Failed to download updates: {}", e)));
// Wait for the progress thread to finish
let _ = progress_thread.join(); // Wait for the progress thread to finish
let _ = progress_thread.join();
result.map(|_| ())
} else { result.map(|_| ())
// No progress callback provided } else {
self.inner.download_updates(&rust_update_info, None) // No progress callback provided
.map_err(|e| PyErr::new::<VelopackError, _>(format!("Failed to download updates: {}", e))) self.inner
.download_updates(&rust_update_info, None)
.map_err(|e| PyErr::new::<VelopackError, _>(format!("Failed to download updates: {}", e)))
.map(|_| ())
}
}
pub fn apply_updates_and_restart(&mut self, update_info: &PyUpdateInfo) -> PyResult<()> {
// Convert PyUpdateInfo back to rust UpdateInfo
let rust_update_info: UpdateInfo = update_info.clone().into();
self.inner
.apply_updates_and_restart(&rust_update_info)
.map_err(|e| PyErr::new::<VelopackError, _>(format!("Failed to apply updates and restart: {}", e)))
.map(|_| ()) .map(|_| ())
} }
} }
pub fn apply_updates_and_restart(&mut self, update_info: &PyUpdateInfo) -> PyResult<()> {
// Convert PyUpdateInfo back to rust UpdateInfo
let rust_update_info: UpdateInfo = update_info.clone().into();
self.inner.apply_updates_and_restart(&rust_update_info)
.map_err(|e| PyErr::new::<VelopackError, _>(format!("Failed to apply updates and restart: {}", e)))
.map(|_| ())
}
}