Reorganize & declutter source files

This commit is contained in:
Filip Tibell 2023-01-20 21:15:58 -05:00
parent af3d022f5d
commit 86cd8ebe33
No known key found for this signature in database
10 changed files with 167 additions and 171 deletions

View file

@ -7,8 +7,8 @@ use clap::{CommandFactory, Parser};
use mlua::{Lua, Result}; use mlua::{Lua, Result};
use crate::{ use crate::{
lune::{console::Console, fs::Fs, net::Net, process::Process}, globals::{console::Console, fs::Fs, net::Net, process::Process},
utils::GithubClient, utils::github::Client as GithubClient,
}; };
/// Lune CLI /// Lune CLI

View file

@ -1,6 +1,6 @@
use mlua::{Lua, MultiValue, Result, UserData, UserDataMethods}; use mlua::{Lua, MultiValue, Result, UserData, UserDataMethods};
use crate::utils::{ use crate::utils::formatting::{
flush_stdout, pretty_format_multi_value, print_color, print_label, print_style, flush_stdout, pretty_format_multi_value, print_color, print_label, print_style,
}; };

View file

@ -6,7 +6,7 @@ use reqwest::{
Method, Method,
}; };
use crate::utils::get_github_user_agent_header; use crate::utils::github::get_github_user_agent_header;
pub struct Net(); pub struct Net();

View file

@ -5,11 +5,11 @@ use clap::Parser;
use mlua::Result; use mlua::Result;
mod cli; mod cli;
mod lune; mod globals;
mod utils; mod utils;
use cli::Cli; use cli::Cli;
use utils::{pretty_print_luau_error, print_label}; use utils::formatting::{pretty_print_luau_error, print_label};
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {

View file

@ -1,172 +1,42 @@
use std::{ use std::{
env::current_dir, fmt::Write as _,
fmt::Write, io::{self, Write as _},
io::{self, Write as IoWrite},
}; };
use anyhow::{bail, Context, Result};
use mlua::{MultiValue, Value}; use mlua::{MultiValue, Value};
use reqwest::{
header::{HeaderMap, HeaderValue},
Client,
};
use serde::{Deserialize, Serialize};
const MAX_FORMAT_DEPTH: usize = 4; const MAX_FORMAT_DEPTH: usize = 4;
const INDENT: &str = " "; const INDENT: &str = " ";
const COLOR_RESET: &str = "\x1B[0m"; pub const COLOR_RESET: &str = "\x1B[0m";
const COLOR_BLACK: &str = "\x1B[30m"; pub const COLOR_BLACK: &str = "\x1B[30m";
const COLOR_RED: &str = "\x1B[31m"; pub const COLOR_RED: &str = "\x1B[31m";
const COLOR_GREEN: &str = "\x1B[32m"; pub const COLOR_GREEN: &str = "\x1B[32m";
const COLOR_YELLOW: &str = "\x1B[33m"; pub const COLOR_YELLOW: &str = "\x1B[33m";
const COLOR_BLUE: &str = "\x1B[34m"; pub const COLOR_BLUE: &str = "\x1B[34m";
const COLOR_PURPLE: &str = "\x1B[35m"; pub const COLOR_PURPLE: &str = "\x1B[35m";
const COLOR_CYAN: &str = "\x1B[36m"; pub const COLOR_CYAN: &str = "\x1B[36m";
const COLOR_WHITE: &str = "\x1B[37m"; pub const COLOR_WHITE: &str = "\x1B[37m";
const STYLE_RESET: &str = "\x1B[22m"; pub const STYLE_RESET: &str = "\x1B[22m";
const STYLE_BOLD: &str = "\x1B[1m"; pub const STYLE_BOLD: &str = "\x1B[1m";
const STYLE_DIM: &str = "\x1B[2m"; pub const STYLE_DIM: &str = "\x1B[2m";
#[derive(Clone, Deserialize, Serialize)]
pub struct GithubReleaseAsset {
id: u64,
url: String,
name: Option<String>,
label: Option<String>,
content_type: String,
size: u64,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct GithubRelease {
id: u64,
url: String,
tag_name: String,
name: Option<String>,
body: Option<String>,
draft: bool,
prerelease: bool,
assets: Vec<GithubReleaseAsset>,
}
pub struct GithubClient {
client: Client,
github_owner: String,
github_repo: String,
}
impl GithubClient {
pub fn new() -> Result<Self> {
let (github_owner, github_repo) = get_github_owner_and_repo();
let mut headers = HeaderMap::new();
headers.insert(
"User-Agent",
HeaderValue::from_str(&get_github_user_agent_header())?,
);
headers.insert(
"Accept",
HeaderValue::from_static("application/vnd.github+json"),
);
headers.insert(
"X-GitHub-Api-Version",
HeaderValue::from_static("2022-11-28"),
);
let client = Client::builder().default_headers(headers).build()?;
Ok(Self {
client,
github_owner,
github_repo,
})
}
pub async fn fetch_releases(&self) -> Result<Vec<GithubRelease>> {
let release_api_url = format!(
"https://api.github.com/repos/{}/{}/releases",
&self.github_owner, &self.github_repo
);
let response_bytes = self
.client
.get(release_api_url)
.send()
.await
.context("Failed to send releases request")?
.bytes()
.await
.context("Failed to get releases response bytes")?;
let response_body: Vec<GithubRelease> = serde_json::from_slice(&response_bytes)?;
Ok(response_body)
}
pub async fn fetch_release_for_this_version(&self) -> Result<GithubRelease> {
let release_version_tag = format!("v{}", env!("CARGO_PKG_VERSION"));
let all_releases = self.fetch_releases().await?;
all_releases
.iter()
.find(|release| release.tag_name == release_version_tag)
.map(ToOwned::to_owned)
.with_context(|| format!("Failed to find release for version {release_version_tag}"))
}
pub async fn fetch_release_asset(
&self,
release: &GithubRelease,
asset_name: &str,
) -> Result<()> {
if let Some(asset) = release
.assets
.iter()
.find(|asset| matches!(&asset.name, Some(name) if name == asset_name))
{
let file_path = current_dir()?.join(asset_name);
let file_bytes = self
.client
.get(&asset.url)
.header("Accept", "application/octet-stream")
.send()
.await
.context("Failed to send asset download request")?
.bytes()
.await
.context("Failed to get asset download response bytes")?;
tokio::fs::write(&file_path, &file_bytes)
.await
.with_context(|| {
format!("Failed to write file at path '{}'", &file_path.display())
})?;
} else {
bail!(
"Failed to find release asset '{}' for release '{}'",
asset_name,
&release.tag_name
)
}
Ok(())
}
}
pub fn get_github_owner_and_repo() -> (String, String) {
let (github_owner, github_repo) = env!("CARGO_PKG_REPOSITORY")
.strip_prefix("https://github.com/")
.unwrap()
.split_once('/')
.unwrap();
(github_owner.to_owned(), github_repo.to_owned())
}
pub fn get_github_user_agent_header() -> String {
let (github_owner, github_repo) = get_github_owner_and_repo();
format!("{github_owner}-{github_repo}-cli")
}
// TODO: Separate utils out into github & formatting
pub fn flush_stdout() -> mlua::Result<()> { pub fn flush_stdout() -> mlua::Result<()> {
io::stdout().flush().map_err(mlua::Error::external) io::stdout().flush().map_err(mlua::Error::external)
} }
fn can_be_plain_lua_table_key(s: &mlua::String) -> bool {
let str = s.to_string_lossy().to_string();
let first_char = str.chars().next().unwrap();
if first_char.is_alphabetic() {
str.chars().all(|c| c == '_' || c.is_alphanumeric())
} else {
false
}
}
pub fn print_label<S: AsRef<str>>(s: S) -> mlua::Result<()> { pub fn print_label<S: AsRef<str>>(s: S) -> mlua::Result<()> {
print!( print!(
"{}[{}{}{}{}]{} ", "{}[{}{}{}{}]{} ",
@ -230,17 +100,7 @@ pub fn print_color<S: AsRef<str>>(s: S) -> mlua::Result<()> {
Ok(()) Ok(())
} }
fn can_be_plain_lua_table_key(s: &mlua::String) -> bool { pub fn pretty_format_value(buffer: &mut String, value: &Value, depth: usize) -> anyhow::Result<()> {
let str = s.to_string_lossy().to_string();
let first_char = str.chars().next().unwrap();
if first_char.is_alphabetic() {
str.chars().all(|c| c == '_' || c.is_alphanumeric())
} else {
false
}
}
fn pretty_format_value(buffer: &mut String, value: &Value, depth: usize) -> anyhow::Result<()> {
// TODO: Handle tables with cyclic references // TODO: Handle tables with cyclic references
// TODO: Handle other types like function, userdata, ... // TODO: Handle other types like function, userdata, ...
match &value { match &value {

134
src/utils/github.rs Normal file
View file

@ -0,0 +1,134 @@
use std::env::current_dir;
use anyhow::{bail, Context, Result};
use reqwest::header::{HeaderMap, HeaderValue};
use serde::{Deserialize, Serialize};
#[derive(Clone, Deserialize, Serialize)]
pub struct ReleaseAsset {
id: u64,
url: String,
name: Option<String>,
label: Option<String>,
content_type: String,
size: u64,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct Release {
id: u64,
url: String,
tag_name: String,
name: Option<String>,
body: Option<String>,
draft: bool,
prerelease: bool,
assets: Vec<ReleaseAsset>,
}
pub struct Client {
client: reqwest::Client,
github_owner: String,
github_repo: String,
}
impl Client {
pub fn new() -> Result<Self> {
let (github_owner, github_repo) = get_github_owner_and_repo();
let mut headers = HeaderMap::new();
headers.insert(
"User-Agent",
HeaderValue::from_str(&get_github_user_agent_header())?,
);
headers.insert(
"Accept",
HeaderValue::from_static("application/vnd.github+json"),
);
headers.insert(
"X-GitHub-Api-Version",
HeaderValue::from_static("2022-11-28"),
);
let client = reqwest::Client::builder()
.default_headers(headers)
.build()?;
Ok(Self {
client,
github_owner,
github_repo,
})
}
pub async fn fetch_releases(&self) -> Result<Vec<Release>> {
let release_api_url = format!(
"https://api.github.com/repos/{}/{}/releases",
&self.github_owner, &self.github_repo
);
let response_bytes = self
.client
.get(release_api_url)
.send()
.await
.context("Failed to send releases request")?
.bytes()
.await
.context("Failed to get releases response bytes")?;
let response_body: Vec<Release> = serde_json::from_slice(&response_bytes)?;
Ok(response_body)
}
pub async fn fetch_release_for_this_version(&self) -> Result<Release> {
let release_version_tag = format!("v{}", env!("CARGO_PKG_VERSION"));
let all_releases = self.fetch_releases().await?;
all_releases
.iter()
.find(|release| release.tag_name == release_version_tag)
.map(ToOwned::to_owned)
.with_context(|| format!("Failed to find release for version {release_version_tag}"))
}
pub async fn fetch_release_asset(&self, release: &Release, asset_name: &str) -> Result<()> {
if let Some(asset) = release
.assets
.iter()
.find(|asset| matches!(&asset.name, Some(name) if name == asset_name))
{
let file_path = current_dir()?.join(asset_name);
let file_bytes = self
.client
.get(&asset.url)
.header("Accept", "application/octet-stream")
.send()
.await
.context("Failed to send asset download request")?
.bytes()
.await
.context("Failed to get asset download response bytes")?;
tokio::fs::write(&file_path, &file_bytes)
.await
.with_context(|| {
format!("Failed to write file at path '{}'", &file_path.display())
})?;
} else {
bail!(
"Failed to find release asset '{}' for release '{}'",
asset_name,
&release.tag_name
)
}
Ok(())
}
}
pub fn get_github_owner_and_repo() -> (String, String) {
let (github_owner, github_repo) = env!("CARGO_PKG_REPOSITORY")
.strip_prefix("https://github.com/")
.unwrap()
.split_once('/')
.unwrap();
(github_owner.to_owned(), github_repo.to_owned())
}
pub fn get_github_user_agent_header() -> String {
let (github_owner, github_repo) = get_github_owner_and_repo();
format!("{github_owner}-{github_repo}-cli")
}

2
src/utils/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod formatting;
pub mod github;