Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/better logging #118

Merged
merged 17 commits into from
Nov 6, 2024
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ members = [
"src/lib/net/crates/codec",
"src/lib/plugins",
"src/lib/storage",
"src/lib/utils", "src/lib/utils/logging", "src/lib/utils/profiling", "src/lib/utils/general_purpose",
"src/lib/utils", "src/lib/utils/logging", "src/lib/utils/profiling", "src/lib/utils/general_purpose", "src/lib/utils/color",
"src/lib/world",
"src/lib/derive_macros",
"src/lib/adapters/nbt", "src/lib/adapters/mca",
Expand Down
3 changes: 3 additions & 0 deletions src/lib/derive_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ edition = "2021"
proc-macro = true

[dependencies]
colored = { version = "2.0" }
color = { path = "../utils/color" }

0xnim marked this conversation as resolved.
Show resolved Hide resolved
quote = { workspace = true }
syn = { workspace = true, features = ["full"] }
thiserror = { workspace = true }
Expand Down
38 changes: 30 additions & 8 deletions src/lib/derive_macros/src/net/packets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@ use quote::quote;
use std::env;
use std::ops::Add;
use syn::{parse_macro_input, LitInt, LitStr};
use colored::Colorize;

use color::ColorSupport;


/// Essentially, this just reads all the files in the directory and generates a match arm for each packet.
/// (packet_id, state) => { ... }
pub fn bake_registry(input: TokenStream) -> TokenStream {
let color_support = ColorSupport::new();
let color_bool = color_support.supports_color();
if color_bool {
colored::control::set_override(true);
}

let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
let module_path = parse_macro_input!(input as syn::LitStr).value();

Expand All @@ -18,7 +28,11 @@ pub fn bake_registry(input: TokenStream) -> TokenStream {
let base_path = module_path.split("\\").collect::<Vec<&str>>()[2..].join("::");
let base_path = format!("crate::{}", base_path);

println!("[FERRUMC_MACROS] Parsing packets in {}", dir_path.display());
println!(
" {} {}",
"[FERRUMC_MACROS]".blue().bold(),
format!("Parsing packets in {}", dir_path.display()).white().bold()
);

if !std::fs::metadata(dir_path).unwrap().is_dir() {
return TokenStream::from(quote! {
Expand Down Expand Up @@ -90,17 +104,20 @@ pub fn bake_registry(input: TokenStream) -> TokenStream {
let struct_name = &item_struct.ident;

println!(
"[FERRUMC_MACROS] Found Packet (ID: 0x{:02X}, State: {}, Struct Name: {})",
packet_id, state, struct_name
" {} {} (ID: {}, State: {}, Struct Name: {})",
"[FERRUMC_MACROS]".bold().blue(),
"Found Packet".white().bold(),
"0x00".cyan(),
"status".green(),
"StatusRequestPacket".yellow()
);

let path = format!(
// "crate::net::packets::incoming::{}",
"{}::{}",
base_path,
file_name.to_string_lossy().replace(".rs", "")
);

let struct_path = format!("{}::{}", path, struct_name);

let struct_path = syn::parse_str::<syn::Path>(&struct_path).expect("parse_str failed");
Expand All @@ -119,10 +136,15 @@ pub fn bake_registry(input: TokenStream) -> TokenStream {
}

let elapsed = start.elapsed();
println!("[FERRUMC_MACROS] Found {} packets", match_arms.len());
println!(
"[FERRUMC_MACROS] It took: {:?} to parse all the files and generate the packet registry",
elapsed
" {} {}",
"[FERRUMC_MACROS]".bold().blue(),
format!("Found {} packets", match_arms.len()).purple().bold()
);
println!(
" {} {}",
"[FERRUMC_MACROS]".bold().blue(),
format!("It took: {:?} to parse all the files and generate the packet registry", elapsed).red().bold()
);

let match_arms = match_arms.into_iter();
Expand Down
7 changes: 7 additions & 0 deletions src/lib/utils/color/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "color"
version = "0.1.0"
edition = "2021"

[dependencies]
atty = "0.2.14"
125 changes: 125 additions & 0 deletions src/lib/utils/color/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use std::env;
use atty::Stream;

#[derive(Debug, PartialEq)]
pub enum ColorLevel {
None,
Basic,
Enhanced,
TrueColor,
}

impl ColorLevel {
pub fn to_bool(&self) -> bool {
matches!(self, ColorLevel::Basic | ColorLevel::Enhanced | ColorLevel::TrueColor)
}

pub fn new() -> Self {
Self::None
}

pub fn basic(&self) -> Self {
match self {
ColorLevel::Enhanced => ColorLevel::Enhanced,
ColorLevel::TrueColor => ColorLevel::TrueColor,
_ => ColorLevel::Basic,
}
}

pub fn enhanced(&self) -> Self {
match self {
ColorLevel::TrueColor => ColorLevel::TrueColor,
_ => ColorLevel::Enhanced,
}
}

pub fn true_color(&self) -> Self {
Self::TrueColor
}

pub fn force_none() -> Self {
Self::None
}
}
pub struct ColorSupport {
pub stdout: ColorLevel,
pub stderr: ColorLevel,
}

impl ColorSupport {
pub fn new() -> Self {
Self {
stdout: determine_color_level(Stream::Stdout),
stderr: determine_color_level(Stream::Stderr),
}
}

pub fn supports_color(&self) -> bool {
self.stdout.to_bool() || self.stderr.to_bool()
}
}

fn determine_color_level(stream: Stream) -> ColorLevel {
// Check FORCE_COLOR environment variable first
let mut color_level = ColorLevel::new();

if let Ok(force_color) = env::var("FORCE_COLOR") {
match force_color.as_str() {
"0" => color_level = ColorLevel::force_none(),
"1" => color_level = ColorLevel::basic(&color_level),
"2" => color_level = ColorLevel::enhanced(&color_level),
"3" => color_level = ColorLevel::true_color(&color_level),
_ => (),
};
if color_level == ColorLevel::None {
return color_level;
}
}

// Handle specific CI environments
if env::var("CI").is_ok() {
if env::var("GITHUB_ACTIONS").is_ok() || env::var("GITEA_ACTIONS").is_ok() {
return ColorLevel::TrueColor;
}

let ci_providers = ["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE", "codeship"];
if ci_providers.iter().any(|ci| env::var(ci).is_ok()) {
return ColorLevel::Basic;
}
}

// Check terminal types and other environment variables
match env::var("TERM").as_deref() {
Ok("dumb") => (),
Ok("xterm-kitty") | Ok("truecolor") | Ok("ansi") => color_level = ColorLevel::true_color(&color_level),
Ok(term) if term.ends_with("-256color") => color_level = ColorLevel::enhanced(&color_level),
Ok(term) if term.starts_with("xterm") || term.starts_with("screen") => color_level = ColorLevel::basic(&color_level),
_ => (),
}

// Final fallback based on whether the stream is a TTY
if atty::is(stream) {
color_level = ColorLevel::basic(&color_level);
}

color_level
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_default_color_level() {
let color_support = ColorSupport::new();
assert!(matches!(color_support.stdout, ColorLevel::Basic) || matches!(color_support.stdout, ColorLevel::None));
assert!(matches!(color_support.stderr, ColorLevel::Basic) || matches!(color_support.stderr, ColorLevel::None));
}

#[test]
fn test_force_color_env() {
env::set_var("FORCE_COLOR", "3");
assert_eq!(determine_color_level(Stream::Stdout), ColorLevel::TrueColor);
env::remove_var("FORCE_COLOR");
}
}