Remove extended cli code, this is going to another binary

This commit is contained in:
Caelan Sayler
2024-02-25 22:05:12 +00:00
parent 3b22f4c3e7
commit 5bfe29f541
6 changed files with 0 additions and 371 deletions

View File

@@ -5,7 +5,6 @@ edition = "2021"
[features]
windows = []
extendedcli = []
[lib]
name = "velopack"

View File

@@ -1,146 +0,0 @@
use crate::{bundle::Manifest, shared};
use anyhow::{bail, Result};
use semver::Version;
use serde::{Deserialize, Serialize};
use std::{fs, path::PathBuf};
#[allow(non_snake_case)]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(default)]
pub struct VelopackAssetFeed {
pub Assets: Vec<VelopackAsset>,
}
#[allow(non_snake_case)]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(default)]
pub struct VelopackAsset {
pub PackageId: String,
pub Version: String,
pub Type: String,
pub FileName: String,
pub SHA1: String,
pub Size: u64,
pub NotesMarkdown: String,
pub NotesHtml: String,
}
#[allow(non_snake_case)]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(default)]
pub struct UpdateInfo {
pub TargetFullRelease: VelopackAsset,
pub IsDowngrade: bool,
}
pub fn check(app: &Manifest, path: &str, allow_downgrade: bool, channel: Option<&str>) -> Result<Option<UpdateInfo>> {
let result = if shared::is_http_url(&path) {
info!("Checking for updates from URL: {}", path);
check_url(app, path, allow_downgrade, channel)
} else {
let buf = PathBuf::from(&path);
info!("Checking for updates from Local Path: {}", buf.to_string_lossy());
if !buf.exists() {
bail!("Path must be a valid HTTP Url or a path to an existing directory: {}", path);
}
check_dir(app, buf, allow_downgrade, channel)
};
result
}
fn get_default_channel() -> String {
#[cfg(target_os = "windows")]
return "win".to_owned();
#[cfg(target_os = "linux")]
return "linux".to_owned();
#[cfg(target_os = "macos")]
return "osx".to_owned();
}
fn check_url(app: &Manifest, path: &str, allow_downgrade: bool, channel: Option<&str>) -> Result<Option<UpdateInfo>> {
let mut channel = channel.unwrap_or(&app.channel).to_string();
if channel.is_empty() {
channel = get_default_channel();
}
let non_default_channel = channel != app.channel;
let releases_name = format!("releases.{}.json", channel);
let path = path.trim_end_matches('/').to_owned() + "/";
let url = url::Url::parse(&path)?;
let mut releases_url = url.join(&releases_name)?;
releases_url.set_query(Some(format!("localVersion={}&id={}", app.version, app.id).as_str()));
info!("Downloading releases for channel {} from: {}", channel, releases_url.to_string());
let json = shared::download::download_url_as_string(releases_url.as_str())?;
let feed: VelopackAssetFeed = serde_json::from_str(&json)?;
process_feed(app, feed, allow_downgrade, non_default_channel)
}
fn check_dir(app: &Manifest, path: PathBuf, allow_downgrade: bool, channel: Option<&str>) -> Result<Option<UpdateInfo>> {
let mut channel = channel.unwrap_or(&app.channel).to_string();
if channel.is_empty() {
channel = get_default_channel();
}
let non_default_channel = channel != app.channel;
let releases_name = format!("releases.{}.json", channel);
let releases_path = path.join(&releases_name);
info!("Reading releases file for channel {} from: {}", channel, releases_path.to_string_lossy());
if !releases_path.exists() {
bail!("Could not find releases file: {}", path.to_string_lossy());
}
let json = fs::read_to_string(&releases_path)?;
let feed: VelopackAssetFeed = serde_json::from_str(&json)?;
process_feed(app, feed, allow_downgrade, non_default_channel)
}
fn process_feed(app: &Manifest, feed: VelopackAssetFeed, allow_downgrade: bool, is_non_default_channel: bool) -> Result<Option<UpdateInfo>> {
let assets = feed.Assets;
if assets.is_empty() {
bail!("Zero assets found in releases feed.");
}
let mut latest: Option<VelopackAsset> = None;
let mut latest_version: Version = Version::parse("0.0.0")?;
for asset in assets {
if let Ok(sv) = Version::parse(&asset.Version) {
debug!("Found asset: {} ({}).", asset.FileName, sv.to_string());
if latest.is_none() || (sv > latest_version && asset.Type.eq_ignore_ascii_case("Full")) {
latest = Some(asset);
latest_version = sv;
}
}
}
if latest.is_none() {
bail!("No valid full releases found in feed.");
}
let remote_version = latest_version;
let remote_asset = latest.unwrap();
debug!("Latest remote release: {} ({}).", remote_asset.FileName, remote_version.to_string());
let mut result: Option<UpdateInfo> = None;
if remote_version > app.version {
info!("Found newer remote release available ({} -> {}).", app.version, remote_version);
result = Some(UpdateInfo { TargetFullRelease: remote_asset, IsDowngrade: false });
} else if remote_version < app.version && allow_downgrade {
info!("Found older remote release available and downgrade is enabled ({} -> {}).", app.version, remote_version);
result = Some(UpdateInfo { TargetFullRelease: remote_asset, IsDowngrade: true });
} else if remote_version == app.version && allow_downgrade && is_non_default_channel {
info!("Latest remote release is the same version of a different channel, and downgrade is enabled ({} -> {}).", app.version, remote_version);
result = Some(UpdateInfo { TargetFullRelease: remote_asset, IsDowngrade: true });
} else {
info!("No update available.");
}
Ok(result)
}

View File

@@ -1,64 +0,0 @@
use crate::{bundle::Manifest, shared};
use anyhow::{bail, Result};
use std::{
fs,
path::{Path, PathBuf},
};
pub fn download<A>(root_path: &PathBuf, app: &Manifest, path: &str, clean: bool, name: &str, mut progress: A) -> Result<PathBuf>
where
A: FnMut(i16),
{
if !name.ends_with(".nupkg") {
bail!("Asset name must end with .nupkg");
}
let packages_dir_str = app.get_packages_path(root_path);
let packages_dir = Path::new(&packages_dir_str);
let target_file = packages_dir.join(name);
let mut to_delete = Vec::new();
if clean {
let g = format!("{}/*.nupkg", packages_dir_str);
info!("Searching for packages to clean in: '{}'", g);
match glob::glob(&g) {
Ok(paths) => {
for path in paths {
if let Ok(path) = path {
to_delete.push(path);
}
}
}
Err(e) => {
error!("Error while searching for packages to clean: {}", e);
}
}
}
if shared::is_http_url(path) {
info!("About to download from URL '{}' to file '{}'", path, target_file.to_string_lossy());
shared::download::download_url_to_file(path, &target_file.to_string_lossy(), &mut progress)?;
} else {
let source_path = Path::new(path);
let source_file = source_path.join(name);
info!("About to copy local file from '{}' to '{}'", source_file.to_string_lossy(), target_file.to_string_lossy());
if !source_file.exists() {
bail!("Local file does not exist: {}", source_file.to_string_lossy());
}
fs::copy(&source_file, &target_file)?;
}
info!("Successfully placed file: '{}'", target_file.to_string_lossy());
if clean {
for path in to_delete {
info!("Cleaning up old package: '{}'", path.to_string_lossy());
fs::remove_file(&path)?;
}
}
Ok(target_file)
}

View File

@@ -4,16 +4,6 @@ pub use apply::*;
mod patch;
pub use patch::*;
#[cfg(feature = "extendedcli")]
mod check;
#[cfg(feature = "extendedcli")]
pub use check::*;
#[cfg(feature = "extendedcli")]
mod download;
#[cfg(feature = "extendedcli")]
pub use download::*;
#[cfg(target_os = "linux")]
mod apply_linux_impl;
#[cfg(target_os = "macos")]

View File

@@ -8,7 +8,6 @@ use anyhow::{anyhow, bail, Result};
use clap::{arg, value_parser, ArgMatches, Command};
use std::{env, path::PathBuf};
use velopack::*;
use serde_json::json;
#[rustfmt::skip]
fn root_command() -> Command {
@@ -39,24 +38,6 @@ fn root_command() -> Command {
.disable_help_subcommand(true)
.flatten_help(true);
#[cfg(feature = "extendedcli")]
let cmd = cmd.subcommand(Command::new("download")
.about("Download/copies an available remote file into the packages directory")
.arg(arg!(--url <URL> "URL or local folder containing an update source").required(true))
.arg(arg!(--name <NAME> "The name of the asset to download").required(true))
.arg(arg!(--clean "Delete all other packages if download is successful"))
.arg(arg!(--format <FORMAT> "The format of the program output (json|text)").default_value("json"))
);
#[cfg(feature = "extendedcli")]
let cmd = cmd.subcommand(Command::new("check")
.about("Checks for available updates")
.arg(arg!(--url <URL> "URL or local folder containing an update source").required(true))
.arg(arg!(--downgrade "Allow version downgrade"))
.arg(arg!(--channel <NAME> "Explicitly switch to a specific channel"))
.arg(arg!(--format <FORMAT> "The format of the program output (json|text)").default_value("json"))
);
#[cfg(target_os = "windows")]
let cmd = cmd.subcommand(Command::new("start")
.about("Starts the currently installed version of the application")
@@ -131,11 +112,6 @@ fn main() -> Result<()> {
"start" => start(subcommand_matches).map_err(|e| anyhow!("Start error: {}", e)),
"apply" => apply(subcommand_matches).map_err(|e| anyhow!("Apply error: {}", e)),
"patch" => patch(subcommand_matches).map_err(|e| anyhow!("Patch error: {}", e)),
#[cfg(feature = "extendedcli")]
"check" => check(subcommand_matches).map_err(|e| anyhow!("Check error: {}", e)),
#[cfg(feature = "extendedcli")]
"download" => download(subcommand_matches).map_err(|e| anyhow!("Download error: {}", e)),
"get-version" => get_version(subcommand_matches).map_err(|e| anyhow!("Get-version error: {}", e)),
_ => bail!("Unknown subcommand. Try `--help` for more information."),
};
@@ -147,96 +123,6 @@ fn main() -> Result<()> {
Ok(())
}
fn get_version(_matches: &ArgMatches) -> Result<()> {
let (_, app) = shared::detect_current_manifest()?;
println!("{}", app.version);
Ok(())
}
#[cfg(feature = "extendedcli")]
fn check(matches: &ArgMatches) -> Result<()> {
let url = matches.get_one::<String>("url").unwrap();
let format = matches.get_one::<String>("format").unwrap();
let allow_downgrade = matches.get_flag("downgrade");
let channel = matches.get_one::<String>("channel").map(|x| x.as_str());
let is_json = format.eq_ignore_ascii_case("json");
info!("Command: Check");
info!(" URL: {:?}", url);
info!(" Allow Downgrade: {:?}", allow_downgrade);
info!(" Channel: {:?}", channel);
info!(" Format: {:?}", format);
// this is a machine readable command, so we write program output to stdout in the desired format
let (_, app) = shared::detect_current_manifest()?;
match commands::check(&app, url, allow_downgrade, channel) {
Ok(opt) => match opt {
Some(info) => {
if is_json {
println!("{}", serde_json::to_string(&info)?);
} else {
let asset = info.TargetFullRelease;
println!("{} {} {} {}", asset.Version, asset.SHA1, asset.FileName, asset.Size);
}
}
_ => println!("null"),
},
Err(e) => {
if is_json {
println!("{{ \"error\": {} }}", json!(format!("{}", e)));
} else {
println!("err: {}", e);
}
return Err(e);
}
}
Ok(())
}
#[cfg(feature = "extendedcli")]
fn download(matches: &ArgMatches) -> Result<()> {
let url = matches.get_one::<String>("url").unwrap();
let name = matches.get_one::<String>("name").unwrap();
let format = matches.get_one::<String>("format").unwrap();
let clean = matches.get_flag("clean");
let is_json = format.eq_ignore_ascii_case("json");
info!("Command: Download");
info!(" URL: {:?}", url);
info!(" Asset Name: {:?}", name);
info!(" Format: {:?}", format);
info!(" Clean: {:?}", clean);
// this is a machine readable command, so we write program output to stdout in the desired format
let (root_path, app) = shared::detect_current_manifest()?;
#[cfg(target_os = "windows")]
let _mutex = shared::retry_io(|| windows::create_global_mutex(&app))?;
match commands::download(&root_path, &app, url, clean, name, |p| {
if is_json {
println!("{{ \"progress\": {} }}", p);
} else {
println!("{}", p);
}
}) {
Ok(path) => {
if is_json {
println!("{{ \"complete\": true, \"progress\": 100, \"file\": {} }}", json!(path.to_string_lossy()));
} else {
println!("complete: {}", path.to_string_lossy());
}
}
Err(e) => {
if is_json {
println!("{{ \"error\": {} }}", json!(format!("{}", e)));
} else {
println!("err: {}", e);
}
return Err(e);
}
}
Ok(())
}
fn patch(matches: &ArgMatches) -> Result<()> {
let old_file = matches.get_one::<PathBuf>("old").unwrap();
let patch_file = matches.get_one::<PathBuf>("patch").unwrap();

View File

@@ -9,42 +9,6 @@ use velopack::*;
#[cfg(target_os = "windows")]
use winsafe::{self as w, co};
#[cfg(feature = "extendedcli")]
#[test]
pub fn test_check_updates() {
let fixtures = find_fixtures();
let feedjson = fixtures.join("testfeed.json");
let tmp = tempdir().unwrap();
// verify that we can't check for updates without a manifest
let mut manifest = bundle::Manifest::default();
manifest.version = semver::Version::parse("1.0.5").unwrap();
let result = commands::check(&manifest, &tmp.path().to_string_lossy(), false, Some("stable"));
assert!(result.is_err());
// we should find a version greater than ours
fs::copy(feedjson, tmp.path().join("releases.stable.json")).unwrap();
let result = commands::check(&manifest, &tmp.path().to_string_lossy(), false, Some("stable")).unwrap();
assert!(result.is_some());
assert!(semver::Version::parse(&result.unwrap().TargetFullRelease.Version).unwrap() == semver::Version::parse("1.0.11").unwrap());
// we should not find a version equal to ours
manifest.version = semver::Version::parse("1.0.11").unwrap();
let result = commands::check(&manifest, &tmp.path().to_string_lossy(), false, Some("stable")).unwrap();
assert!(result.is_none());
// we should not find a version less than ours
manifest.version = semver::Version::parse("1.0.20").unwrap();
let result = commands::check(&manifest, &tmp.path().to_string_lossy(), false, Some("stable")).unwrap();
assert!(result.is_none());
// if downgrade is allowed, we should find a version less than ours
let result = commands::check(&manifest, &tmp.path().to_string_lossy(), true, Some("stable")).unwrap();
assert!(result.is_some());
assert!(semver::Version::parse(&result.unwrap().TargetFullRelease.Version).unwrap() == semver::Version::parse("1.0.11").unwrap());
}
#[cfg(target_os = "windows")]
#[test]
pub fn test_install_apply_uninstall() {