-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
329 additions
and
48 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
use crate::Result; | ||
|
||
mod run; | ||
|
||
#[derive(Debug, clap::Args)] | ||
pub struct Daemon { | ||
#[clap(subcommand)] | ||
command: Commands, | ||
} | ||
|
||
#[derive(Debug, clap::Subcommand)] | ||
enum Commands { | ||
Run(run::Run), | ||
} | ||
|
||
impl Daemon { | ||
pub async fn run(self) -> Result<()> { | ||
match self.command { | ||
Commands::Run(run) => run.run().await, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,37 @@ | ||
pub use std::env; | ||
use once_cell::sync::Lazy; | ||
pub use std::env; | ||
use std::path::PathBuf; | ||
use log::trace; | ||
|
||
pub static HOME_DIR: Lazy<PathBuf> = Lazy::new(|| dirs::home_dir().unwrap_or(PathBuf::new())); | ||
pub static PITCHFORK_STATE_DIR: Lazy<PathBuf> = Lazy::new(|| { | ||
dirs::state_dir() | ||
.unwrap_or(HOME_DIR.join(".local").join("state")) | ||
.join("pitchfork") | ||
var_path("PITCHFORK_STATE_DIR").unwrap_or( | ||
dirs::state_dir() | ||
.unwrap_or(HOME_DIR.join(".local").join("state")) | ||
.join("pitchfork"), | ||
) | ||
}); | ||
pub static PITCHFORK_PID_FILE: Lazy<PathBuf> = Lazy::new(|| PITCHFORK_STATE_DIR.join("pids.toml")); | ||
pub static PITCHFORK_LOG: Lazy<log::LevelFilter> = Lazy::new(|| { | ||
env::var("PITCHFORK_LOG") | ||
.ok() | ||
.and_then(|level| level.parse().ok()) | ||
.unwrap_or(log::LevelFilter::Info) | ||
}); | ||
pub static PITCHFORK_LOG_FILE_LEVEL: Lazy<log::LevelFilter> = Lazy::new(|| { | ||
env::var("PITCHFORK_LOG_FILE_LEVEL") | ||
.ok() | ||
.and_then(|level| level.parse().ok()) | ||
.unwrap_or(*PITCHFORK_LOG) | ||
}); | ||
pub static PITCHFORK_LOG_FILE: Lazy<PathBuf> = Lazy::new(|| { | ||
var_path("PITCHFORK_LOG_FILE").unwrap_or( | ||
PITCHFORK_STATE_DIR | ||
.join("logs") | ||
.join("pitchfork") | ||
.join("pitchfork.log"), | ||
) | ||
}); | ||
|
||
fn var_path(name: &str) -> Option<PathBuf> { | ||
env::var(name).map(|path| PathBuf::from(path)).ok() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
use eyre::Result; | ||
use std::fs::{File, OpenOptions}; | ||
use std::io::Write; | ||
use std::path::Path; | ||
use std::sync::Mutex; | ||
use std::thread; | ||
|
||
use crate::{env, ui}; | ||
use log::{warn, Level, LevelFilter, Metadata, Record}; | ||
use once_cell::sync::Lazy; | ||
|
||
#[derive(Debug)] | ||
struct Logger { | ||
level: LevelFilter, | ||
term_level: LevelFilter, | ||
file_level: LevelFilter, | ||
log_file: Option<Mutex<File>>, | ||
} | ||
|
||
impl log::Log for Logger { | ||
fn enabled(&self, metadata: &Metadata) -> bool { | ||
metadata.level() <= self.level | ||
} | ||
|
||
fn log(&self, record: &Record) { | ||
if record.level() <= self.file_level { | ||
if let Some(log_file) = &self.log_file { | ||
let mut log_file = log_file.lock().unwrap(); | ||
let out = self.render(record, self.file_level); | ||
let _ = writeln!(log_file, "{}", console::strip_ansi_codes(&out)); | ||
} | ||
} | ||
if record.level() <= self.term_level { | ||
let out = self.render(record, self.term_level); | ||
eprintln!("{}", out); | ||
} | ||
} | ||
|
||
fn flush(&self) {} | ||
} | ||
|
||
static LOGGER: Lazy<Logger> = Lazy::new(Logger::init); | ||
|
||
impl Logger { | ||
fn init() -> Self { | ||
let term_level = *env::PITCHFORK_LOG; | ||
let file_level = *env::PITCHFORK_LOG_FILE_LEVEL; | ||
|
||
let mut logger = Logger { | ||
level: std::cmp::max(term_level, file_level), | ||
file_level, | ||
term_level, | ||
log_file: None, | ||
}; | ||
|
||
let log_file = &*env::PITCHFORK_LOG_FILE; | ||
if let Ok(log_file) = init_log_file(log_file) { | ||
logger.log_file = Some(Mutex::new(log_file)); | ||
} else { | ||
warn!("could not open log file: {log_file:?}"); | ||
} | ||
|
||
logger | ||
} | ||
|
||
fn render(&self, record: &Record, level: LevelFilter) -> String { | ||
match level { | ||
LevelFilter::Off => "".to_string(), | ||
LevelFilter::Trace => { | ||
let meta = ui::style::edim(format!( | ||
"{thread_id:>2} [{file}:{line}]", | ||
thread_id = thread_id(), | ||
file = record.file().unwrap_or("<unknown>"), | ||
line = record.line().unwrap_or(0), | ||
)); | ||
format!( | ||
"{level} {meta} {args}", | ||
level = self.styled_level(record.level()), | ||
args = record.args() | ||
) | ||
} | ||
LevelFilter::Debug => format!( | ||
"{level} {args}", | ||
level = self.styled_level(record.level()), | ||
args = record.args() | ||
), | ||
_ => { | ||
let mise = match record.level() { | ||
Level::Error => ui::style::ered("mise"), | ||
Level::Warn => ui::style::eyellow("mise"), | ||
_ => ui::style::edim("mise"), | ||
}; | ||
match record.level() { | ||
Level::Info => format!("{mise} {args}", args = record.args()), | ||
_ => format!( | ||
"{mise} {level} {args}", | ||
level = self.styled_level(record.level()), | ||
args = record.args() | ||
), | ||
} | ||
} | ||
} | ||
} | ||
|
||
fn styled_level(&self, level: Level) -> String { | ||
let level = match level { | ||
Level::Error => ui::style::ered("ERROR").to_string(), | ||
Level::Warn => ui::style::eyellow("WARN").to_string(), | ||
Level::Info => ui::style::ecyan("INFO").to_string(), | ||
Level::Debug => ui::style::emagenta("DEBUG").to_string(), | ||
Level::Trace => ui::style::edim("TRACE").to_string(), | ||
}; | ||
console::pad_str(&level, 5, console::Alignment::Left, None).to_string() | ||
} | ||
} | ||
|
||
pub fn thread_id() -> String { | ||
let id = format!("{:?}", thread::current().id()); | ||
let id = id.replace("ThreadId(", ""); | ||
id.replace(")", "") | ||
} | ||
|
||
pub fn init() { | ||
static INIT: std::sync::Once = std::sync::Once::new(); | ||
INIT.call_once(|| { | ||
if let Err(err) = log::set_logger(&*LOGGER).map(|()| log::set_max_level(LOGGER.level)) { | ||
eprintln!("mise: could not initialize logger: {err}"); | ||
} | ||
}); | ||
} | ||
|
||
fn init_log_file(log_file: &Path) -> Result<File> { | ||
if let Some(log_dir) = log_file.parent() { | ||
xx::file::mkdirp(log_dir)?; | ||
} | ||
Ok(OpenOptions::new() | ||
.create(true) | ||
.append(true) | ||
.open(log_file)?) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.