mirror of
https://github.com/yuzu-emu/liftinstall.git
synced 2024-11-22 16:25:44 +01:00
Select latest release file in install pipeline
This commit is contained in:
parent
a61709c3d0
commit
139ff5793c
@ -1,5 +1,4 @@
|
|||||||
/// Serves static files from a asset directory.
|
/// Serves static files from a asset directory.
|
||||||
|
|
||||||
extern crate mime_guess;
|
extern crate mime_guess;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
@ -13,10 +13,9 @@ use sources::get_by_name;
|
|||||||
/// Description of the source of a package.
|
/// Description of the source of a package.
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
pub struct PackageSource {
|
pub struct PackageSource {
|
||||||
pub name : String,
|
pub name: String,
|
||||||
#[serde(rename="match")]
|
#[serde(rename = "match")] pub match_regex: String,
|
||||||
pub match_regex : String,
|
pub config: toml::Value,
|
||||||
pub config : toml::Value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes a overview of a individual package.
|
/// Describes a overview of a individual package.
|
||||||
@ -25,7 +24,7 @@ pub struct PackageDescription {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub default: Option<bool>,
|
pub default: Option<bool>,
|
||||||
pub source: PackageSource
|
pub source: PackageSource,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes the application itself.
|
/// Describes the application itself.
|
||||||
@ -58,9 +57,9 @@ impl PackageSource {
|
|||||||
pub fn get_current_releases(&self) -> Result<Vec<Release>, String> {
|
pub fn get_current_releases(&self) -> Result<Vec<Release>, String> {
|
||||||
let package_handler = match get_by_name(&self.name) {
|
let package_handler = match get_by_name(&self.name) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
_ => return Err(format!("Handler {} not found", self.name))
|
_ => return Err(format!("Handler {} not found", self.name)),
|
||||||
};
|
};
|
||||||
|
|
||||||
package_handler.get_current_releases(&self.config)
|
package_handler.get_current_releases(&self.config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ impl InstallerFramework {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a request for something to be installed.
|
/// Sends a request for something to be installed.
|
||||||
pub fn install(&self, items : Vec<String>) {
|
pub fn install(&self, items: Vec<String>) {
|
||||||
// TODO: Error handling
|
// TODO: Error handling
|
||||||
println!("Framework: Installing {:?}", items);
|
println!("Framework: Installing {:?}", items);
|
||||||
|
|
||||||
@ -60,17 +60,21 @@ impl InstallerFramework {
|
|||||||
|
|
||||||
let results = package.source.get_current_releases().unwrap();
|
let results = package.source.get_current_releases().unwrap();
|
||||||
|
|
||||||
println!("Got releases");
|
|
||||||
|
|
||||||
let filtered_regex = package.source.match_regex.replace("#PLATFORM#", OS);
|
let filtered_regex = package.source.match_regex.replace("#PLATFORM#", OS);
|
||||||
println!("Filtered regex: {}" , filtered_regex);
|
|
||||||
let regex = Regex::new(&filtered_regex).unwrap();
|
let regex = Regex::new(&filtered_regex).unwrap();
|
||||||
|
|
||||||
// Find the latest release in here
|
// Find the latest release in here
|
||||||
let latest_result = results.into_iter()
|
let latest_result = results
|
||||||
.filter(|f| f.files.iter().filter(|x| regex.is_match(x)).count() > 0)
|
.into_iter()
|
||||||
.max_by_key(|f| f.version.clone());
|
.filter(|f| f.files.iter().filter(|x| regex.is_match(&x.name)).count() > 0)
|
||||||
println!("{:?}", latest_result);
|
.max_by_key(|f| f.version.clone()).unwrap();
|
||||||
|
|
||||||
|
// Find the matching file in here
|
||||||
|
let latest_file = latest_result.files.into_iter()
|
||||||
|
.filter(|x| regex.is_match(&x.name))
|
||||||
|
.next().unwrap();
|
||||||
|
|
||||||
|
println!("{:?}", latest_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ extern crate serde_derive;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
|
|
||||||
extern crate semver;
|
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
extern crate semver;
|
||||||
|
|
||||||
mod assets;
|
mod assets;
|
||||||
mod rest;
|
mod rest;
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
///
|
///
|
||||||
/// Provides a HTTP/REST server for both frontend<->backend communication, as well
|
/// Provides a HTTP/REST server for both frontend<->backend communication, as well
|
||||||
/// as talking to external applications.
|
/// as talking to external applications.
|
||||||
|
|
||||||
extern crate nfd;
|
extern crate nfd;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
|
|
||||||
@ -153,7 +152,8 @@ impl Service for WebService {
|
|||||||
|
|
||||||
return Box::new(req.body().concat2().map(move |b| {
|
return Box::new(req.body().concat2().map(move |b| {
|
||||||
let results = form_urlencoded::parse(b.as_ref())
|
let results = form_urlencoded::parse(b.as_ref())
|
||||||
.into_owned().collect::<HashMap<String, String>>();
|
.into_owned()
|
||||||
|
.collect::<HashMap<String, String>>();
|
||||||
|
|
||||||
let mut to_install = Vec::new();
|
let mut to_install = Vec::new();
|
||||||
|
|
||||||
@ -194,7 +194,7 @@ impl Service for WebService {
|
|||||||
.with_header(ContentLength(file.len() as u64))
|
.with_header(ContentLength(file.len() as u64))
|
||||||
.with_header(content_type)
|
.with_header(content_type)
|
||||||
.with_body(file)
|
.with_body(file)
|
||||||
},
|
}
|
||||||
None => Response::new().with_status(StatusCode::NotFound),
|
None => Response::new().with_status(StatusCode::NotFound),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,12 @@ use serde_json;
|
|||||||
|
|
||||||
use sources::types::*;
|
use sources::types::*;
|
||||||
|
|
||||||
pub struct GithubReleases {
|
pub struct GithubReleases {}
|
||||||
}
|
|
||||||
|
|
||||||
/// The configuration for this release.
|
/// The configuration for this release.
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct GithubConfig {
|
struct GithubConfig {
|
||||||
repo : String
|
repo: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GithubReleases {
|
impl GithubReleases {
|
||||||
@ -38,87 +37,104 @@ impl ReleaseSource for GithubReleases {
|
|||||||
// Reparse our Config as strongly typed
|
// Reparse our Config as strongly typed
|
||||||
let config_string = match toml::to_string(config) {
|
let config_string = match toml::to_string(config) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(v) => return Err(format!("Failed to convert config: {:?}", v))
|
Err(v) => return Err(format!("Failed to convert config: {:?}", v)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let config : GithubConfig = match toml::from_str(&config_string) {
|
let config: GithubConfig = match toml::from_str(&config_string) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(v) => return Err(format!("Failed to convert config: {:?}", v))
|
Err(v) => return Err(format!("Failed to convert config: {:?}", v)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut core = match Core::new() {
|
let mut core = match Core::new() {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(v) => return Err(format!("Failed to init Tokio: {:?}", v))
|
Err(v) => return Err(format!("Failed to init Tokio: {:?}", v)),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build the HTTP client up
|
// Build the HTTP client up
|
||||||
let client = Client::configure()
|
let client = Client::configure()
|
||||||
.connector(match HttpsConnector::new(4, &core.handle()) {
|
.connector(match HttpsConnector::new(4, &core.handle()) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(v) => return Err(format!("Failed to init https: {:?}", v))
|
Err(v) => return Err(format!("Failed to init https: {:?}", v)),
|
||||||
})
|
})
|
||||||
.build(&core.handle());
|
.build(&core.handle());
|
||||||
|
|
||||||
let mut results: Vec<Release> = Vec::new();
|
let mut results: Vec<Release> = Vec::new();
|
||||||
let target_url : Uri = match format!("https://api.github.com/repos/{}/releases",
|
let target_url: Uri =
|
||||||
config.repo).parse() {
|
match format!("https://api.github.com/repos/{}/releases", config.repo).parse() {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(v) => return Err(format!("Failed to generate target url: {:?}", v))
|
Err(v) => return Err(format!("Failed to generate target url: {:?}", v)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut req = Request::new(Method::Get, target_url);
|
let mut req = Request::new(Method::Get, target_url);
|
||||||
req.headers_mut().set(UserAgent::new("installer-rs (j-selby)"));
|
req.headers_mut()
|
||||||
|
.set(UserAgent::new("installer-rs (j-selby)"));
|
||||||
|
|
||||||
// Build our future
|
// Build our future
|
||||||
let future = client.request(req).and_then(|res| {
|
let future = client.request(req).and_then(|res| {
|
||||||
res.body().concat2().and_then(move |body| {
|
res.body().concat2().and_then(move |body| {
|
||||||
let raw_json : Result<serde_json::Value, String>
|
let raw_json: Result<serde_json::Value, String> =
|
||||||
= match serde_json::from_slice(&body) {
|
match serde_json::from_slice(&body) {
|
||||||
Ok(v) => Ok(v),
|
Ok(v) => Ok(v),
|
||||||
Err(v) => Err(format!("Failed to parse response: {:?}", v))
|
Err(v) => Err(format!("Failed to parse response: {:?}", v)),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(raw_json)
|
Ok(raw_json)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
// Unwrap the future's results
|
// Unwrap the future's results
|
||||||
let result : serde_json::Value = match core.run(future) {
|
let result: serde_json::Value = match core.run(future) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(v) => return Err(format!("Failed to fetch info: {:?}", v))
|
Err(v) => return Err(format!("Failed to fetch info: {:?}", v)),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
let result : &Vec<serde_json::Value> = match result.as_array() {
|
let result: &Vec<serde_json::Value> = match result.as_array() {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return Err(format!("JSON payload not an array"))
|
None => return Err(format!("JSON payload not an array")),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse JSON from server
|
// Parse JSON from server
|
||||||
for entry in result.into_iter() {
|
for entry in result.into_iter() {
|
||||||
let mut files = Vec::new();
|
let mut files = Vec::new();
|
||||||
|
|
||||||
let id : u64 = match entry["id"].as_u64() {
|
let id: u64 = match entry["id"].as_u64() {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return Err(format!("JSON payload missing information about ID"))
|
None => return Err(format!("JSON payload missing information about ID")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let assets = match entry["assets"].as_array() {
|
let assets = match entry["assets"].as_array() {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return Err(format!("JSON payload not an array"))
|
None => return Err(format!("JSON payload not an array")),
|
||||||
};
|
};
|
||||||
|
|
||||||
for asset in assets.into_iter() {
|
for asset in assets.into_iter() {
|
||||||
let string = match asset["name"].as_str() {
|
let string = match asset["name"].as_str() {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return Err(format!("JSON payload missing information about ID"))
|
None => {
|
||||||
|
return Err(format!(
|
||||||
|
"JSON payload missing information about release name"
|
||||||
|
))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
files.push(string.to_owned());
|
let url = match asset["browser_download_url"].as_str() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
return Err(format!(
|
||||||
|
"JSON payload missing information about release URL"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
files.push(File {
|
||||||
|
name: string.to_owned(),
|
||||||
|
url: url.to_owned(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
results.push(Release {
|
results.push(Release {
|
||||||
version: Version::new_number(id),
|
version: Version::new_number(id),
|
||||||
files
|
files,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,11 +9,9 @@ pub mod github;
|
|||||||
use self::types::ReleaseSource;
|
use self::types::ReleaseSource;
|
||||||
|
|
||||||
/// Returns a ReleaseSource by a name, if possible
|
/// Returns a ReleaseSource by a name, if possible
|
||||||
pub fn get_by_name(name : &str) -> Option<Box<ReleaseSource>> {
|
pub fn get_by_name(name: &str) -> Option<Box<ReleaseSource>> {
|
||||||
match name {
|
match name {
|
||||||
"github" => {
|
"github" => Some(Box::new(github::GithubReleases::new())),
|
||||||
Some(Box::new(github::GithubReleases::new()))
|
_ => None,
|
||||||
}
|
|
||||||
_ => None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ pub use toml::value::Value as TomlValue;
|
|||||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
pub enum Version {
|
pub enum Version {
|
||||||
Semver(SemverVersion),
|
Semver(SemverVersion),
|
||||||
Integer(u64)
|
Integer(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Version {
|
impl Version {
|
||||||
@ -21,18 +21,19 @@ impl Version {
|
|||||||
fn coarse_into_semver(&self) -> SemverVersion {
|
fn coarse_into_semver(&self) -> SemverVersion {
|
||||||
match self {
|
match self {
|
||||||
&Version::Semver(ref version) => version.to_owned(),
|
&Version::Semver(ref version) => version.to_owned(),
|
||||||
&Version::Integer(ref version) => SemverVersion::from((version.to_owned(),
|
&Version::Integer(ref version) => {
|
||||||
0 as u64, 0 as u64))
|
SemverVersion::from((version.to_owned(), 0 as u64, 0 as u64))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new Version, backed by semver.
|
/// Returns a new Version, backed by semver.
|
||||||
pub fn new_semver(version : SemverVersion) -> Version {
|
pub fn new_semver(version: SemverVersion) -> Version {
|
||||||
Version::Semver(version)
|
Version::Semver(version)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new Version, backed by a integer.
|
/// Returns a new Version, backed by a integer.
|
||||||
pub fn new_number(version : u64) -> Version {
|
pub fn new_number(version: u64) -> Version {
|
||||||
Version::Integer(version)
|
Version::Integer(version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,18 +41,14 @@ impl Version {
|
|||||||
impl PartialOrd for Version {
|
impl PartialOrd for Version {
|
||||||
fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
|
||||||
match self {
|
match self {
|
||||||
&Version::Semver(ref version) => {
|
&Version::Semver(ref version) => match other {
|
||||||
match other {
|
&Version::Semver(ref other_version) => Some(version.cmp(other_version)),
|
||||||
&Version::Semver(ref other_version) => Some(version.cmp(other_version)),
|
_ => None,
|
||||||
_ => None
|
},
|
||||||
}
|
&Version::Integer(ref num) => match other {
|
||||||
|
&Version::Integer(ref other_num) => Some(num.cmp(other_num)),
|
||||||
|
_ => None,
|
||||||
},
|
},
|
||||||
&Version::Integer(ref num) => {
|
|
||||||
match other {
|
|
||||||
&Version::Integer(ref other_num) => Some(num.cmp(other_num)),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,16 +59,23 @@ impl Ord for Version {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A individual file in a release.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct File {
|
||||||
|
pub name: String,
|
||||||
|
pub url: String,
|
||||||
|
}
|
||||||
|
|
||||||
/// A individual release of an application.
|
/// A individual release of an application.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Release {
|
pub struct Release {
|
||||||
pub version : Version,
|
pub version: Version,
|
||||||
pub files : Vec<String>
|
pub files: Vec<File>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A source of releases.
|
/// A source of releases.
|
||||||
pub trait ReleaseSource {
|
pub trait ReleaseSource {
|
||||||
/// Gets a list of the available releases from this source. Should cache internally
|
/// Gets a list of the available releases from this source. Should cache internally
|
||||||
/// if possible using a mutex.
|
/// if possible using a mutex.
|
||||||
fn get_current_releases(&self, config : &TomlValue) -> Result<Vec<Release>, String>;
|
fn get_current_releases(&self, config: &TomlValue) -> Result<Vec<Release>, String>;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user