1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
//! # updater-lp
//!
//! A no frills updater that uses Github has its base.
//! Easily create auto-updating for your cli apps!
//!
//! ## How it Works?
//!
//! Host your code on Github! Tag your code with version releases and then
//! attach builds to those releases.
//!
//! _updater-lp_ then looks for the release at your repository and then version
//! matches those release against what you state your current app version is. If
//! it finds a newer version, it can be used to 'update' your app by replacing
//! your current binary with the new binary from Github.
//!
//! ## How to use it.
//!
//! First off, a [test app](https://github.com/snsvrno/updater-lp-rs/tree/master/src-test)
//! is in the source repository that shows you how its used, as well as is used to test
//! the libraries functionality.
//!
//! ### Include the library
//!
//! Add _updater-lp_ to your `cargo.toml`.
//!
//! ```toml
//! [dependencies]
//! updater-lp = "0.2"
//! ```
//!
//! ### Using the Library
//!
//! Then you need to set your upstream address. _updater-lp_ is struct-less (or better called static)
//! so its recommended you have a `&'STATIC str` with your repository address.
//!
//! ``` rust
//! static REPO_PATH : &str = "https://github.com/snsvrno/lpsettings-rs";
//! ```
//!
//! And then where ever it makes sense, you should check for the latest version. I'd recommend putting
//! someting to prevent checking everytime the program runs (so you don't perform too many needless github
//! api calls) and instead check for updates daily.
//!
//! ```rust
//! # extern crate updater_lp;
//! # static REPO_PATH : &str = "https://github.com/snsvrno/lpsettings-rs";
//! let this_version = updater_lp::create_version(&[01,2,3,4]);
//!
//! match updater_lp::get_latest_version(REPO_PATH) {
//! Err(error) => {
//! // can't check the version for some reason, `error` should state why.
//! },
//! Ok(latest) => {
//! if latest > this_version {
//! updater_lp::update_with_version(REPO_PATH,&latest);
//! }
//! }
//! }
//! ```
//!
//! I'd recommend against using `?` on `get_latest_version` because you probably don't want your program
//! error / fail if you can't connect to the repo.
//!
//! ### A note of Versions
//!
//! _updater-lp_ uses [version-lp](https://crates.io/crates/version-lp) for all versions. This means
//! that versions are easily compairable. Version is exposed in this crate to allow for easy use
//! without requiring you to add an additional dependency to your `cargo.toml`
#[macro_use] extern crate log;
#[macro_use] extern crate failure; use failure::Error;
#[macro_use] extern crate serde_derive;
extern crate regex;
extern crate restson;
extern crate download_lp as download;
extern crate archive_lp as archive;
extern crate platform_lp as platform;
extern crate version_lp as version; use version::Version;
use std::fs;
use std::env;
mod sources;
mod source;
mod traits; use traits::provider::Provider;
pub fn get_latest_version(repo_link : &str) -> Result<Version,Error> {
//! Checks the given Repository for the latest version
let provider = source::get_provider(repo_link)?;
provider.get_latest_version()
}
pub fn get_link_for_version(repo_link : &str, version : &Version) -> Result<String,Error> {
//! Checks the given Repository for the compatible release of the given version.
//!
//! If there isn't any release for that version then it will return an Error.
let provider = source::get_provider(repo_link)?;
provider.get_link_for(version)
}
pub fn get_link_for_latest(repo_link : &str) -> Result<(String,Version),Error> {
//! Checks the given Repository for the latest compatible release.
//!
//! Might not necessarily be the latest version but rather is the
//! latest version that has a release for the user's platform. Will
//! return an error if there is connectivity issues or no releases
//! were found for the user's platform.
let provider = source::get_provider(repo_link)?;
provider.get_link_for_latest()
}
pub fn create_version_raw(version_string : &[u8]) -> Version {
//! A passthrough for the _version-lp_ crate, so you can create a version to compare against.
//!
//! Accepts a reference to an Array of `u8` of any length.
Version::new(version_string)
}
pub fn create_version(version_string : &str) -> Option<Version> {
//! A passthrough for the _version-lp_ crate, so you can create a version to compare against.
//!
//! Will attempt to create a version from a string.
Version::from_str(version_string)
}
pub fn update_from_link(link : &str) -> Result<(),Error> {
//! Updates the current application from the provided link.
//!
//! It will validate the download and check that it contains an
//! executable that is named the same as this program otherwise
//! it will fail. This is to prevent the application from deleting
//! itself without replacing itself with a proper replacement.
//!
//! It will not check for platform compatibility. It is assuming that
//! already done. Designed to work with
//! [get_link_from_latest()](fn.get_link_for_latest.html#func.get_link_for_latest)
let exe_path = env::current_exe().unwrap();
let (file,_) = download::download(&link,".")?;
match exe_path.file_name() {
None => { return Err(format_err!("Can't determine executable name")); }
Some(file_name) => {
if archive::contains_file(&file, file_name.to_str().unwrap())? {
match exe_path.parent() {
None => { return Err(format_err!("Can't determine executable path")); }
Some(parent) => {
if let Err(_) = fs::remove_file(&exe_path) {
// probably on windows, doesn't let you delete the file if you
// are currently running it, unix allows you to do this though
let mut renamed_exe = exe_path.clone();
renamed_exe.set_extension("old");
fs::rename(&exe_path,&renamed_exe)?;
}
archive::extract_root_to(&file,&parent.display().to_string())?;
fs::remove_file(file)?;
}
}
}
}
}
Ok(())
}
pub fn update_with_version(repo_link : &str, version : &Version) -> Result<(),Error> {
//! Update the application with the specific version from the Repository.
//!
//! Will fail if it cannot find an appropriate version / compatible platform.
let link = get_link_for_version(repo_link, version)?;
update_from_link(&link)
}