diff --git a/package/action/.editorconfig b/package/action/.editorconfig new file mode 100644 index 0000000..6edaa72 --- /dev/null +++ b/package/action/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = tab + +[{*.yaml,*.yml, *.md}] +indent_style = space +indent_size = 2 \ No newline at end of file diff --git a/package/action/.vscode/extensions.json b/package/action/.vscode/extensions.json new file mode 100644 index 0000000..8ac46eb --- /dev/null +++ b/package/action/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["rust-lang.rust-analyzer", "esbenp.prettier-vscode"] +} diff --git a/package/action/.vscode/settings.json b/package/action/.vscode/settings.json index 352a626..cf61ed4 100644 --- a/package/action/.vscode/settings.json +++ b/package/action/.vscode/settings.json @@ -1,5 +1,12 @@ { - "rust-analyzer.linkedProjects": [ - "./Cargo.toml" - ] -} \ No newline at end of file + "rust-analyzer.check.command": "clippy", + "rust-analyzer.linkedProjects": ["./Cargo.toml"], + "editor.formatOnSave": true, + "prettier.tabWidth": 2, + "[json][jsonc][markdown][yaml]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer" + } +} diff --git a/package/action/rustfmt.toml b/package/action/rustfmt.toml new file mode 100644 index 0000000..53bc344 --- /dev/null +++ b/package/action/rustfmt.toml @@ -0,0 +1,5 @@ +max_width = 150 +hard_tabs = true +#normalize_comments = false +#match_block_trailing_comma = true +#closure_block_indent_threshold = 1 \ No newline at end of file diff --git a/package/action/src/download.rs b/package/action/src/download.rs index 0a08146..e0aa6ad 100644 --- a/package/action/src/download.rs +++ b/package/action/src/download.rs @@ -1,9 +1,9 @@ use std::{ - env, - fs::File, - io::{Error, ErrorKind, Read, Seek, Write}, - path::PathBuf, - str::FromStr, + env, + fs::File, + io::{Error, ErrorKind, Read, Seek, Write}, + path::PathBuf, + str::FromStr, }; use anyhow::Result; @@ -12,185 +12,164 @@ use url::Url; use zip::ZipArchive; use crate::{ - github::{FetchResult, Fetcher, GitHub, Method}, - types::{LuneReleaseData, LuneReleaseFetched}, + github::{FetchResult, Fetcher, GitHub, Method}, + types::{LuneReleaseData, LuneReleaseFetched}, }; fn parse_release_data(data: &LuneReleaseData) -> LuneReleaseFetched { - const TARGET: &str = "download::parse_release_data"; + const TARGET: &str = "download::parse_release_data"; - tracing::info!(target: TARGET, "Parsing received LuneReleaseData"); + tracing::info!(target: TARGET, "Parsing received LuneReleaseData"); - let unknown = &String::from("UNKNOWN"); + let unknown = &String::from("UNKNOWN"); - let mut version = unknown.to_owned(); - let mut download = unknown.to_owned(); - let mut artifact_name = unknown.to_owned(); + let mut version = unknown.to_owned(); + let mut download = unknown.to_owned(); + let mut artifact_name = unknown.to_owned(); - tracing::info!( - target: TARGET, - "Defaulting to `unknown` values before parsing" - ); + tracing::info!( + target: TARGET, + "Defaulting to `unknown` values before parsing" + ); - for asset in &data.assets { - let parts = asset - .name - .split("-") - .map(|s| s.to_string()) - .collect::>(); + for asset in &data.assets { + let parts = asset.name.split('-').map(|s| s.to_string()).collect::>(); - // [0] => always "lune" - // [1] => version - // [2] => platform - // [3] => arch .. ".zip" + // [0] => always "lune" + // [1] => version + // [2] => platform + // [3] => arch .. ".zip" - if parts[2] == env::consts::OS && parts[3].trim_end_matches(".zip") == env::consts::ARCH { - tracing::info!( - target: TARGET, - "Supported platform found, overwriting `unknown` values" - ); + if parts[2] == env::consts::OS && parts[3].trim_end_matches(".zip") == env::consts::ARCH { + tracing::info!( + target: TARGET, + "Supported platform found, overwriting `unknown` values" + ); - version = (&parts[1]).to_owned(); - download = (&asset.browser_download_url).to_owned(); - artifact_name = (&asset.name).to_owned(); - } else { - tracing::warn!( - target: TARGET, - "Supported platform not found for asset {:?}", - asset - ); - } - } + version = (parts[1]).to_owned(); + download = (asset.browser_download_url).to_owned(); + artifact_name = (asset.name).to_owned(); + } else { + tracing::warn!( + target: TARGET, + "Supported platform not found for asset {:?}", + asset + ); + } + } - tracing::info!(target: TARGET, "Done."); + tracing::info!(target: TARGET, "Done."); - LuneReleaseFetched { - version, - download, - artifact_name, - raw: Some(data.clone()), - } + LuneReleaseFetched { + version, + download, + artifact_name, + raw: Some(data.clone()), + } } pub fn download_release(version: Option) -> Result<(PathBuf, LuneReleaseFetched)> { - const TARGET: &str = "download::download_release"; + const TARGET: &str = "download::download_release"; - tracing::info!(target: TARGET, "Initializing routine"); + tracing::info!(target: TARGET, "Initializing routine"); - let parsed_release_data: LuneReleaseFetched; + let parsed_release_data: LuneReleaseFetched; - if let Some(ver) = version { - let artifact_name = format!("lune-{ver}-{}-{}.zip", env::consts::OS, env::consts::ARCH); + if let Some(ver) = version { + let artifact_name = format!("lune-{ver}-{}-{}.zip", env::consts::OS, env::consts::ARCH); - parsed_release_data = LuneReleaseFetched { - version: ver.to_string(), - download: format!( - "https://github.com/filiptibell/lune/releases/download/v{ver}/{artifact_name}" - ), - artifact_name, - raw: None, - } - } else { - parsed_release_data = - parse_release_data(&GitHub::new(("filiptibell", "lune")).fetch_releases()?); + parsed_release_data = LuneReleaseFetched { + version: ver.to_string(), + download: format!("https://github.com/filiptibell/lune/releases/download/v{ver}/{artifact_name}"), + artifact_name, + raw: None, + } + } else { + parsed_release_data = parse_release_data(&GitHub::new(("filiptibell", "lune")).fetch_releases()?); - tracing::info!(target: TARGET, "Received API resp and parsed release data"); - } + tracing::info!(target: TARGET, "Received API resp and parsed release data"); + } - tracing::info!(target: TARGET, "Got lune {}", parsed_release_data.version); + tracing::info!(target: TARGET, "Got lune {}", parsed_release_data.version); - let fetcher = Fetcher::new(); + let fetcher = Fetcher::new(); - tracing::info!( - target: TARGET, - "Proceeding to download release from API resp (url = {})", - &parsed_release_data.download - ); + tracing::info!( + target: TARGET, + "Proceeding to download release from API resp (url = {})", + &parsed_release_data.download + ); - let resp = fetcher.fetch::<_, ()>( - Method::Get, - Url::from_str(&parsed_release_data.download.as_str())?, - false, - )?; + let resp = fetcher.fetch::<_, ()>(Method::Get, Url::from_str(parsed_release_data.download.as_str())?, false)?; - match resp { - FetchResult::Response(res) => { - tracing::info!( - target: TARGET, - "Received download resp, proceeding to write zip to disk at {}", - &parsed_release_data.artifact_name - ); + match resp { + FetchResult::Response(res) => { + tracing::info!( + target: TARGET, + "Received download resp, proceeding to write zip to disk at {}", + &parsed_release_data.artifact_name + ); - let mut zip_archive = File::create(&parsed_release_data.artifact_name)?; + let mut zip_archive = File::create(&parsed_release_data.artifact_name)?; - let mut bytes = res - .into_reader() - .bytes() - .map(|elem| elem.unwrap()) - .collect::>(); + let bytes = res.into_reader().bytes().map(|elem| elem.unwrap()).collect::>(); - zip_archive.write_all(&mut bytes)?; + zip_archive.write_all(&bytes)?; - tracing::info!(target: TARGET, "Successfully downloaded release"); - } - FetchResult::Result(_) => unreachable!("Fetcher returned Result instead of Response"), - }; + tracing::info!(target: TARGET, "Successfully downloaded release"); + } + FetchResult::Result(_) => unreachable!("Fetcher returned Result instead of Response"), + }; - Ok(( - PathBuf::from(&parsed_release_data.artifact_name), - parsed_release_data, - )) + Ok((PathBuf::from(&parsed_release_data.artifact_name), parsed_release_data)) } pub fn install_lune(lune_archive_reader: impl Read + Seek, meta: LuneReleaseFetched) -> Result<()> { - const TARGET: &str = "download::install_lune"; + const TARGET: &str = "download::install_lune"; - tracing::info!(target: TARGET, "Initializing routine"); + tracing::info!(target: TARGET, "Initializing routine"); - let dir_name = meta.artifact_name.trim_end_matches(".zip"); + let dir_name = meta.artifact_name.trim_end_matches(".zip"); - tracing::info!(target: TARGET, "Proceeding to extract release zip"); + tracing::info!(target: TARGET, "Proceeding to extract release zip"); - let mut lune_zip = ZipArchive::new(lune_archive_reader)?; - lune_zip.extract(dir_name)?; + let mut lune_zip = ZipArchive::new(lune_archive_reader)?; + lune_zip.extract(dir_name)?; - tracing::info!(target: TARGET, "Successfully extracted release zip"); + tracing::info!(target: TARGET, "Successfully extracted release zip"); - let bin_name = match env::consts::OS { - "windows" => "lune.exe", - "macos" | "linux" => "lune", - _ => panic!("unsupported platform"), - }; + let bin_name = match env::consts::OS { + "windows" => "lune.exe", + "macos" | "linux" => "lune", + _ => panic!("unsupported platform"), + }; - let bin_base_dir = BaseDirs::new() - .ok_or(Error::new( - ErrorKind::NotFound, - "failed to create BaseDirs instance", - ))? - .home_dir() - .join("bin"); + let bin_base_dir = BaseDirs::new() + .ok_or(Error::new(ErrorKind::NotFound, "failed to create BaseDirs instance"))? + .home_dir() + .join("bin"); - if !bin_base_dir.exists() { - tracing::warn!(target: TARGET, "bin_base_dir nonexistent, creating"); - std::fs::create_dir(&bin_base_dir)?; - } + if !bin_base_dir.exists() { + tracing::warn!(target: TARGET, "bin_base_dir nonexistent, creating"); + std::fs::create_dir(&bin_base_dir)?; + } - tracing::warn!( - target: TARGET, - "macOS and windows support for this action is incomplete" - ); + tracing::warn!( + target: TARGET, + "macOS and windows support for this action is incomplete" + ); - // TODO: macOS and windows support - let lune_bin_path = bin_base_dir.join(bin_name); + // TODO: macOS and windows support + let lune_bin_path = bin_base_dir.join(bin_name); - File::create(&lune_bin_path)?; - std::fs::rename(PathBuf::from(dir_name).join(bin_name), &lune_bin_path)?; + File::create(&lune_bin_path)?; + std::fs::rename(PathBuf::from(dir_name).join(bin_name), &lune_bin_path)?; - tracing::info!( - target: TARGET, - "Installed lune bin to {}", - lune_bin_path.to_string_lossy() - ); + tracing::info!( + target: TARGET, + "Installed lune bin to {}", + lune_bin_path.to_string_lossy() + ); - Ok(()) + Ok(()) } diff --git a/package/action/src/fmt.rs b/package/action/src/fmt.rs index 536041b..3f49e5c 100644 --- a/package/action/src/fmt.rs +++ b/package/action/src/fmt.rs @@ -2,8 +2,8 @@ use colored::Colorize; use std::fmt; use tracing_core::{Event, Level, Subscriber}; use tracing_subscriber::fmt::{ - format::{self, FormatEvent, FormatFields}, - FmtContext, FormattedFields, + format::{self, FormatEvent, FormatFields}, + FmtContext, FormattedFields, }; use tracing_subscriber::registry::LookupSpan; @@ -11,51 +11,46 @@ pub struct LogFormatter; impl FormatEvent for LogFormatter where - S: Subscriber + for<'a> LookupSpan<'a>, - N: for<'a> FormatFields<'a> + 'static, + S: Subscriber + for<'a> LookupSpan<'a>, + N: for<'a> FormatFields<'a> + 'static, { - fn format_event( - &self, - ctx: &FmtContext<'_, S, N>, - mut writer: format::Writer<'_>, - event: &Event<'_>, - ) -> fmt::Result { - let meta = event.metadata(); + fn format_event(&self, ctx: &FmtContext<'_, S, N>, mut writer: format::Writer<'_>, event: &Event<'_>) -> fmt::Result { + let meta = event.metadata(); - let scope = match meta.level() { - &Level::DEBUG => "?".purple().bold(), - &Level::ERROR => "!".red().bold(), - &Level::INFO => "*".green().bold(), - &Level::TRACE => ".".white().bold(), - &Level::WARN => "#".yellow().bold(), - }; + let scope = match *meta.level() { + Level::DEBUG => "?".purple().bold(), + Level::ERROR => "!".red().bold(), + Level::INFO => "*".green().bold(), + Level::TRACE => ".".white().bold(), + Level::WARN => "#".yellow().bold(), + }; - let target = if meta.level() != &Level::INFO { - let mut sep = "::".to_owned(); - sep.push_str(&meta.target().italic().underline()); + let target = if meta.level() != &Level::INFO { + let mut sep = "::".to_owned(); + sep.push_str(&meta.target().italic().underline()); - sep - } else { - "::main".to_string() - }; + sep + } else { + "::main".to_string() + }; - write!(&mut writer, "[{}][{}] ", scope, target)?; + write!(&mut writer, "[{}][{}] ", scope, target)?; - if let Some(scope) = ctx.event_scope() { - for span in scope.from_root() { - write!(writer, "{}", span.name())?; - let ext = span.extensions(); - let fields = &ext.get::>().unwrap(); + if let Some(scope) = ctx.event_scope() { + for span in scope.from_root() { + write!(writer, "{}", span.name())?; + let ext = span.extensions(); + let fields = &ext.get::>().unwrap(); - if !fields.is_empty() { - write!(writer, "{{{}}}", fields)?; - } - write!(writer, " ")?; - } - } + if !fields.is_empty() { + write!(writer, "{{{}}}", fields)?; + } + write!(writer, " ")?; + } + } - ctx.field_format().format_fields(writer.by_ref(), event)?; + ctx.field_format().format_fields(writer.by_ref(), event)?; - writeln!(writer) - } + writeln!(writer) + } } diff --git a/package/action/src/github.rs b/package/action/src/github.rs index c1e1074..9bf62ca 100644 --- a/package/action/src/github.rs +++ b/package/action/src/github.rs @@ -7,147 +7,140 @@ use url::Url; use crate::types::LuneReleaseData; +#[derive(Debug, Default, Clone)] pub struct GitHub { - fetcher: Fetcher, - repository: Repository, + fetcher: Fetcher, + repository: Repository, } impl GitHub { - pub fn new(repo: (&str, &str)) -> Self { - let fetcher = Fetcher::new(); + pub fn new(repo: (&str, &str)) -> Self { + let fetcher = Fetcher::new(); - Self { - fetcher: (&fetcher).to_owned(), - repository: Repository::new(repo.0, repo.1, fetcher), - } - } + Self { + fetcher: fetcher.to_owned(), + repository: Repository::new(repo.0, repo.1, fetcher), + } + } - pub fn fetch_releases(&self) -> Result { - let api_uri = Url::from_str(self.repository.api_url().as_str())? - .join("releases/")? - .join("latest")?; + pub fn fetch_releases(&self) -> Result { + let api_uri = Url::from_str(self.repository.api_url().as_str())?.join("releases/")?.join("latest")?; - Ok( - match self - .fetcher - .fetch::<_, LuneReleaseData>(Method::Get, api_uri, true)? - { - FetchResult::Result(res) => res, - FetchResult::Response(_) => { - unreachable!("Fetcher returned Response instead of Result") - } - }, - ) - } + Ok(match self.fetcher.fetch::<_, LuneReleaseData>(Method::Get, api_uri, true)? { + FetchResult::Result(res) => res, + FetchResult::Response(_) => { + unreachable!("Fetcher returned Response instead of Result") + } + }) + } } +#[derive(Debug, Default, Clone)] pub struct Repository { - fetcher: Fetcher, - scope: String, - repo: String, + fetcher: Fetcher, + scope: String, + repo: String, } #[derive(Debug, Deserialize, Clone)] pub struct RepositoryMeta { - pub full_name: String, - pub name: String, - pub description: String, - pub license: HashMap, - pub topics: Vec, - pub forks: u32, - pub open_issues: u32, - pub stars: u32, + pub full_name: String, + pub name: String, + pub description: String, + pub license: HashMap, + pub topics: Vec, + pub forks: u32, + pub open_issues: u32, + pub stars: u32, } impl Repository { - pub fn new(scope: T, repo: T, fetcher: Fetcher) -> Self - where - T: ToString, - { - Self { - fetcher, - scope: scope.to_string(), - repo: repo.to_string(), - } - } + pub fn new(scope: T, repo: T, fetcher: Fetcher) -> Self + where + T: ToString, + { + Self { + fetcher, + scope: scope.to_string(), + repo: repo.to_string(), + } + } - pub fn scope(&self) -> &String { - return &self.scope; - } + pub fn scope(&self) -> &String { + &self.scope + } - pub fn repo(&self) -> &String { - return &self.repo; - } + pub fn repo(&self) -> &String { + &self.repo + } - pub fn api_url(&self) -> String { - return format!("https://api.github.com/repos/{}/{}/", self.scope, self.repo); - } + pub fn api_url(&self) -> String { + format!("https://api.github.com/repos/{}/{}/", self.scope, self.repo) + } - pub fn fetch_meta(&self) -> Result { - Ok( - match self.fetcher.fetch::<_, RepositoryMeta>( - Method::Get, - Url::from_str(self.api_url().as_str())?, - true, - )? { - FetchResult::Result(deserialized) => deserialized, - FetchResult::Response(_) => { - unreachable!("Fetcher returned Response instead of Result") - } - }, - ) - } + pub fn fetch_meta(&self) -> Result { + Ok( + match self + .fetcher + .fetch::<_, RepositoryMeta>(Method::Get, Url::from_str(self.api_url().as_str())?, true)? + { + FetchResult::Result(deserialized) => deserialized, + FetchResult::Response(_) => { + unreachable!("Fetcher returned Response instead of Result") + } + }, + ) + } } #[derive(Debug, Clone)] pub struct Fetcher { - client: ureq::Agent, + client: ureq::Agent, } pub enum Method { - Get, - Post, + Get, + Post, } pub enum FetchResult { - Result(D), - Response(Response), + Result(D), + Response(Box), +} + +impl Default for Fetcher { + fn default() -> Self { + Self::new() + } } impl Fetcher { - pub fn new() -> Self { - Self { - client: ureq::builder() - .redirects(2) - .https_only(true) - .timeout(Duration::from_secs(30)) - .user_agent("lune-action/0.1.0") - .build(), - } - } + pub fn new() -> Self { + Self { + client: ureq::builder() + .redirects(2) + .https_only(true) + .timeout(Duration::from_secs(30)) + .user_agent("lune-action/0.1.0") + .build(), + } + } - pub fn fetch( - &self, - method: Method, - uri: U, - to_deserialize: bool, - ) -> Result> - where - U: Into, - D: DeserializeOwned, - { - let method = match method { - Method::Get => "GET", - Method::Post => "POST", - }; + pub fn fetch(&self, method: Method, uri: U, to_deserialize: bool) -> Result> + where + U: Into, + D: DeserializeOwned, + { + let method = match method { + Method::Get => "GET", + Method::Post => "POST", + }; - let req = self.client.request_url(method, &uri.into()); + let req = self.client.request_url(method, &uri.into()); - Ok(match to_deserialize { - true => { - FetchResult::Result(serde_json::from_reader::<_, D>(req.call()?.into_reader())?) - } - false => FetchResult::Response(req.call()?), - }) - } + Ok(match to_deserialize { + true => FetchResult::Result(serde_json::from_reader::<_, D>(req.call()?.into_reader())?), + false => FetchResult::Response(Box::new(req.call()?)), + }) + } } diff --git a/package/action/src/main.rs b/package/action/src/main.rs index fe037e3..286a5c0 100644 --- a/package/action/src/main.rs +++ b/package/action/src/main.rs @@ -2,44 +2,35 @@ use std::fs::File; use actions_core as core; use setup_lune::{ - download::{download_release, install_lune}, - fmt::LogFormatter, + download::{download_release, install_lune}, + fmt::LogFormatter, }; use tracing::Level; use tracing_unwrap::ResultExt; fn main() { - let version = match core::input("version") { - Ok(val) => Some(val), - Err(_) => None, - }; + let version = match core::input("version") { + Ok(val) => Some(val), + Err(_) => None, + }; - if cfg!(debug_assertions) { - better_panic::install(); - } + if cfg!(debug_assertions) { + better_panic::install(); + } - tracing_subscriber::fmt() - .with_max_level(match core::is_debug() || cfg!(debug_assertions) { - true => Level::DEBUG, - false => Level::INFO, - }) - .event_format(LogFormatter) - .init(); + tracing_subscriber::fmt() + .with_max_level(match core::is_debug() || cfg!(debug_assertions) { + true => Level::DEBUG, + false => Level::INFO, + }) + .event_format(LogFormatter) + .init(); - let (zip_path, meta) = - download_release(version).expect_or_log("failed to download latest lune release"); + let (zip_path, meta) = download_release(version).expect_or_log("failed to download latest lune release"); - install_lune( - File::open(&zip_path).expect( - format!( - "failed to open downloaded lune release zip file @ {}", - zip_path.to_string_lossy().to_string() - ) - .as_str(), - ), - meta, - ) - .expect_or_log( - "failed to install lune. did we not have perms to write to the required directories?", - ); + install_lune( + File::open(&zip_path).unwrap_or_else(|_| panic!("failed to open downloaded lune release zip file @ {}", zip_path.to_string_lossy())), + meta, + ) + .expect_or_log("failed to install lune. did we not have perms to write to the required directories?"); } diff --git a/package/action/src/types.rs b/package/action/src/types.rs index 71497a8..a96f0ad 100644 --- a/package/action/src/types.rs +++ b/package/action/src/types.rs @@ -2,20 +2,20 @@ use serde::Deserialize; #[derive(Deserialize, Debug, Clone)] pub struct LuneReleaseData { - pub name: String, - pub assets: Vec, + pub name: String, + pub assets: Vec, } #[derive(Deserialize, Debug, Clone)] pub struct LuneAssetData { - pub browser_download_url: String, - pub name: String, + pub browser_download_url: String, + pub name: String, } #[derive(Deserialize, Debug, Clone)] pub struct LuneReleaseFetched { - pub version: String, - pub download: String, - pub artifact_name: String, - pub raw: Option, + pub version: String, + pub download: String, + pub artifact_name: String, + pub raw: Option, }