Add EwwPaths struct and refactor path handling in general
This commit is contained in:
parent
5b3344fc5b
commit
8dba5aca83
5 changed files with 114 additions and 84 deletions
12
src/app.rs
12
src/app.rs
|
@ -4,13 +4,14 @@ use crate::{
|
|||
display_backend, eww_state,
|
||||
script_var_handler::*,
|
||||
value::{Coords, NumWithUnit, PrimitiveValue, VarName},
|
||||
EwwPaths,
|
||||
};
|
||||
use anyhow::*;
|
||||
use debug_stub_derive::*;
|
||||
use gdk::WindowExt;
|
||||
use gtk::{ContainerExt, CssProviderExt, GtkWindowExt, StyleContextExt, WidgetExt};
|
||||
use itertools::Itertools;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
use std::collections::HashMap;
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
|
||||
/// Response that the app may send as a response to a event.
|
||||
|
@ -91,8 +92,7 @@ pub struct App {
|
|||
#[debug_stub = "ScriptVarHandler(...)"]
|
||||
pub script_var_handler: ScriptVarHandlerHandle,
|
||||
|
||||
pub config_file_path: PathBuf,
|
||||
pub scss_file_path: PathBuf,
|
||||
pub paths: EwwPaths,
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
@ -110,14 +110,14 @@ impl App {
|
|||
DaemonCommand::ReloadConfigAndCss(sender) => {
|
||||
let mut errors = Vec::new();
|
||||
|
||||
let config_result =
|
||||
config::RawEwwConfig::read_from_file(&self.config_file_path).and_then(config::EwwConfig::generate);
|
||||
let config_result = config::RawEwwConfig::read_from_file(&self.paths.get_eww_xml_path())
|
||||
.and_then(config::EwwConfig::generate);
|
||||
match config_result {
|
||||
Ok(new_config) => self.handle_command(DaemonCommand::UpdateConfig(new_config)),
|
||||
Err(e) => errors.push(e),
|
||||
}
|
||||
|
||||
let css_result = crate::util::parse_scss_from_file(&self.scss_file_path);
|
||||
let css_result = crate::util::parse_scss_from_file(&self.paths.get_eww_scss_path());
|
||||
match css_result {
|
||||
Ok(new_css) => self.handle_command(DaemonCommand::UpdateCss(new_css)),
|
||||
Err(e) => errors.push(e),
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::process::Stdio;
|
|||
use crate::{
|
||||
app,
|
||||
opts::{self, ActionClientOnly},
|
||||
EwwPaths,
|
||||
};
|
||||
use anyhow::*;
|
||||
use std::{
|
||||
|
@ -10,11 +11,11 @@ use std::{
|
|||
os::unix::net::UnixStream,
|
||||
};
|
||||
|
||||
pub fn handle_client_only_action(action: ActionClientOnly) -> Result<()> {
|
||||
pub fn handle_client_only_action(paths: &EwwPaths, action: ActionClientOnly) -> Result<()> {
|
||||
match action {
|
||||
ActionClientOnly::Logs => {
|
||||
std::process::Command::new("tail")
|
||||
.args(["-f", crate::LOG_FILE.to_string_lossy().as_ref()].iter())
|
||||
.args(["-f", paths.get_log_file().to_string_lossy().as_ref()].iter())
|
||||
.stdin(Stdio::null())
|
||||
.spawn()?
|
||||
.wait()?;
|
||||
|
|
130
src/main.rs
130
src/main.rs
|
@ -12,8 +12,10 @@ extern crate gio;
|
|||
extern crate gtk;
|
||||
|
||||
use anyhow::*;
|
||||
|
||||
use std::{os::unix::net, path::PathBuf};
|
||||
use std::{
|
||||
os::unix::net,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
pub mod app;
|
||||
pub mod application_lifecycle;
|
||||
|
@ -30,38 +32,6 @@ pub mod util;
|
|||
pub mod value;
|
||||
pub mod widgets;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref IPC_SOCKET_PATH: std::path::PathBuf = std::env::var("XDG_RUNTIME_DIR")
|
||||
.map(std::path::PathBuf::from)
|
||||
.unwrap_or_else(|_| std::path::PathBuf::from("/tmp"))
|
||||
.join("eww-server");
|
||||
|
||||
pub static ref CONFIG_DIR: std::path::PathBuf = std::env::var("XDG_CONFIG_HOME")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| PathBuf::from(std::env::var("HOME").unwrap()).join(".config"))
|
||||
.join("eww");
|
||||
|
||||
pub static ref LOG_FILE: std::path::PathBuf = std::env::var("XDG_CACHE_HOME")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| PathBuf::from(std::env::var("HOME").unwrap()).join(".cache"))
|
||||
.join("eww.log");
|
||||
}
|
||||
|
||||
pub struct Paths {}
|
||||
|
||||
pub fn calculate_socket_path<P: AsRef<std::path::Path>>(config_file_path: P) -> std::path::PathBuf {
|
||||
let daemon_id = base64::encode(format!("{}", config_file_path.as_ref().display()));
|
||||
let socket_filename = format!(
|
||||
"{}_{}",
|
||||
&*crate::IPC_SOCKET_PATH
|
||||
.file_name()
|
||||
.and_then(|x| x.to_str())
|
||||
.expect("Invalid socket path"),
|
||||
daemon_id,
|
||||
);
|
||||
crate::IPC_SOCKET_PATH.with_file_name(socket_filename).to_path_buf()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let opts: opts::Opt = opts::Opt::from_env();
|
||||
|
||||
|
@ -76,16 +46,20 @@ fn main() {
|
|||
.init();
|
||||
|
||||
let result: Result<_> = try {
|
||||
let socket_path = calculate_socket_path(opts.config_path.clone().unwrap_or(CONFIG_DIR.join("eww.xml")));
|
||||
let paths = opts.config_path.map(EwwPaths::from_config_dir).unwrap_or_default();
|
||||
|
||||
match opts.action {
|
||||
opts::Action::ClientOnly(action) => {
|
||||
client::handle_client_only_action(action)?;
|
||||
client::handle_client_only_action(&paths, action)?;
|
||||
}
|
||||
opts::Action::WithServer(action) => {
|
||||
log::info!("Trying to find server process at socket {}", socket_path.display());
|
||||
match net::UnixStream::connect(&socket_path) {
|
||||
log::info!(
|
||||
"Trying to find server process at socket {}",
|
||||
paths.get_ipc_socket_file().display()
|
||||
);
|
||||
match net::UnixStream::connect(&paths.get_ipc_socket_file()) {
|
||||
Ok(stream) => {
|
||||
log::info!("Connected to Eww server ({}).", &socket_path.display());
|
||||
log::info!("Connected to Eww server ({}).", &paths.get_ipc_socket_file().display());
|
||||
let response =
|
||||
client::do_server_call(stream, action).context("Error while forwarding command to server")?;
|
||||
if let Some(response) = response {
|
||||
|
@ -105,15 +79,15 @@ fn main() {
|
|||
|
||||
opts::Action::Daemon => {
|
||||
// make sure that there isn't already a Eww daemon running.
|
||||
if check_server_running(&socket_path) {
|
||||
if check_server_running(paths.get_ipc_socket_file()) {
|
||||
eprintln!("Eww server already running.");
|
||||
std::process::exit(1);
|
||||
} else {
|
||||
log::info!("Initializing Eww server. ({})", socket_path.display());
|
||||
let _ = std::fs::remove_file(socket_path);
|
||||
log::info!("Initializing Eww server. ({})", paths.get_ipc_socket_file().display());
|
||||
let _ = std::fs::remove_file(paths.get_ipc_socket_file());
|
||||
|
||||
println!("Run `eww logs` to see any errors, warnings or information while editing your configuration.");
|
||||
server::initialize_server(opts.config_path)?;
|
||||
server::initialize_server(paths)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,9 +100,77 @@ fn main() {
|
|||
}
|
||||
|
||||
/// Check if a eww server is currently running by trying to send a ping message to it.
|
||||
fn check_server_running(socket_path: &std::path::PathBuf) -> bool {
|
||||
fn check_server_running(socket_path: impl AsRef<Path>) -> bool {
|
||||
let response = net::UnixStream::connect(socket_path)
|
||||
.ok()
|
||||
.and_then(|stream| client::do_server_call(stream, opts::ActionWithServer::Ping).ok());
|
||||
response.is_some()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EwwPaths {
|
||||
log_file: PathBuf,
|
||||
ipc_socket_file: PathBuf,
|
||||
config_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl EwwPaths {
|
||||
pub fn from_config_dir<P: AsRef<Path>>(config_dir: P) -> Self {
|
||||
let daemon_id = base64::encode(format!("{}", config_dir.as_ref().display()));
|
||||
|
||||
EwwPaths {
|
||||
config_dir: config_dir.as_ref().to_path_buf(),
|
||||
log_file: std::env::var("XDG_CACHE_HOME")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| PathBuf::from(std::env::var("HOME").unwrap()).join(".cache"))
|
||||
.join(format!("eww_{}.log", daemon_id)),
|
||||
ipc_socket_file: std::env::var("XDG_RUNTIME_DIR")
|
||||
.map(std::path::PathBuf::from)
|
||||
.unwrap_or_else(|_| std::path::PathBuf::from("/tmp"))
|
||||
.join(format!("eww-server_{}", daemon_id)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_log_file(&self) -> &Path {
|
||||
self.log_file.as_path()
|
||||
}
|
||||
|
||||
pub fn get_ipc_socket_file(&self) -> &Path {
|
||||
self.ipc_socket_file.as_path()
|
||||
}
|
||||
|
||||
pub fn get_config_dir(&self) -> &Path {
|
||||
self.config_dir.as_path()
|
||||
}
|
||||
|
||||
pub fn get_eww_xml_path(&self) -> PathBuf {
|
||||
self.config_dir.join("eww.xml")
|
||||
}
|
||||
|
||||
pub fn get_eww_scss_path(&self) -> PathBuf {
|
||||
self.config_dir.join("eww.scss")
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EwwPaths {
|
||||
fn default() -> Self {
|
||||
let config_dir = std::env::var("XDG_CONFIG_HOME")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| PathBuf::from(std::env::var("HOME").unwrap()).join(".config"))
|
||||
.join("eww");
|
||||
|
||||
Self::from_config_dir(config_dir)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for EwwPaths {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"config-dir: {}, ipc-socket: {}, log-file: {}",
|
||||
self.config_dir.display(),
|
||||
self.ipc_socket_file.display(),
|
||||
self.log_file.display()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ struct RawOpt {
|
|||
#[structopt(long = "debug", global = true)]
|
||||
log_debug: bool,
|
||||
|
||||
/// override config-file path (path to eww.xml)
|
||||
/// override path to configuration directory (directory that contains eww.xml and eww.scss)
|
||||
#[structopt(short, long, global = true)]
|
||||
config: Option<std::path::PathBuf>,
|
||||
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
use crate::{app, config, eww_state::*, ipc_server, script_var_handler, try_logging_errors, util};
|
||||
use crate::{app, config, eww_state::*, ipc_server, script_var_handler, try_logging_errors, util, EwwPaths};
|
||||
use anyhow::*;
|
||||
use futures_util::StreamExt;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
os::unix::io::AsRawFd,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::{collections::HashMap, os::unix::io::AsRawFd, path::Path};
|
||||
use tokio::sync::mpsc::*;
|
||||
|
||||
pub fn initialize_server(config_dir_override: Option<std::path::PathBuf>) -> Result<()> {
|
||||
do_detach()?;
|
||||
pub fn initialize_server(paths: EwwPaths) -> Result<()> {
|
||||
do_detach(&paths.get_log_file())?;
|
||||
|
||||
println!(
|
||||
r#"
|
||||
|
@ -28,18 +24,11 @@ pub fn initialize_server(config_dir_override: Option<std::path::PathBuf>) -> Res
|
|||
});
|
||||
let (ui_send, mut ui_recv) = tokio::sync::mpsc::unbounded_channel();
|
||||
|
||||
let config_file_path = config_dir_override.unwrap_or(crate::CONFIG_DIR.join("eww.xml"));
|
||||
std::env::set_current_dir(&paths.get_config_dir())
|
||||
.with_context(|| format!("Failed to change working directory to {}", paths.get_config_dir().display()))?;
|
||||
|
||||
let config_dir = config_file_path
|
||||
.parent()
|
||||
.context("config file did not have a parent?!")?
|
||||
.to_owned();
|
||||
std::env::set_current_dir(&config_dir)
|
||||
.with_context(|| format!("Failed to change working directory to {}", config_dir.display()))?;
|
||||
let scss_file_path = config_dir.join("eww.scss");
|
||||
|
||||
log::info!("reading configuration from {:?}", &config_file_path);
|
||||
let eww_config = config::EwwConfig::read_from_file(&config_file_path)?;
|
||||
log::info!("Loading paths: {}", &paths);
|
||||
let eww_config = config::EwwConfig::read_from_file(&paths.get_eww_xml_path())?;
|
||||
|
||||
gtk::init()?;
|
||||
|
||||
|
@ -53,20 +42,19 @@ pub fn initialize_server(config_dir_override: Option<std::path::PathBuf>) -> Res
|
|||
css_provider: gtk::CssProvider::new(),
|
||||
script_var_handler,
|
||||
app_evt_send: ui_send.clone(),
|
||||
config_file_path,
|
||||
scss_file_path,
|
||||
paths,
|
||||
};
|
||||
|
||||
if let Some(screen) = gdk::Screen::get_default() {
|
||||
gtk::StyleContext::add_provider_for_screen(&screen, &app.css_provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
}
|
||||
|
||||
if let Ok(eww_css) = util::parse_scss_from_file(&app.scss_file_path) {
|
||||
if let Ok(eww_css) = util::parse_scss_from_file(&app.paths.get_eww_scss_path()) {
|
||||
app.load_css(&eww_css)?;
|
||||
}
|
||||
|
||||
// initialize all the handlers and tasks running asyncronously
|
||||
init_async_part(app.config_file_path.clone(), app.scss_file_path.clone(), ui_send);
|
||||
init_async_part(app.paths.clone(), ui_send);
|
||||
|
||||
glib::MainContext::default().spawn_local(async move {
|
||||
while let Some(event) = ui_recv.recv().await {
|
||||
|
@ -80,7 +68,7 @@ pub fn initialize_server(config_dir_override: Option<std::path::PathBuf>) -> Res
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn init_async_part(config_file_path: PathBuf, scss_file_path: PathBuf, ui_send: UnboundedSender<app::DaemonCommand>) {
|
||||
fn init_async_part(paths: EwwPaths, ui_send: UnboundedSender<app::DaemonCommand>) {
|
||||
std::thread::spawn(move || {
|
||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
|
@ -89,14 +77,13 @@ fn init_async_part(config_file_path: PathBuf, scss_file_path: PathBuf, ui_send:
|
|||
rt.block_on(async {
|
||||
let filewatch_join_handle = {
|
||||
let ui_send = ui_send.clone();
|
||||
let config_file_path = config_file_path.clone();
|
||||
tokio::spawn(async move { run_filewatch(config_file_path, scss_file_path, ui_send).await })
|
||||
let paths = paths.clone();
|
||||
tokio::spawn(async move { run_filewatch(paths.get_eww_xml_path(), paths.get_eww_scss_path(), ui_send).await })
|
||||
};
|
||||
|
||||
let ipc_server_join_handle = {
|
||||
let ui_send = ui_send.clone();
|
||||
let socket_path = crate::calculate_socket_path(config_file_path);
|
||||
tokio::spawn(async move { ipc_server::run_server(ui_send, socket_path).await })
|
||||
tokio::spawn(async move { ipc_server::run_server(ui_send, paths.get_ipc_socket_file()).await })
|
||||
};
|
||||
|
||||
let forward_exit_to_app_handle = {
|
||||
|
@ -168,7 +155,7 @@ async fn run_filewatch<P: AsRef<Path>>(
|
|||
}
|
||||
|
||||
/// detach the process from the terminal, also redirecting stdout and stderr to LOG_FILE
|
||||
fn do_detach() -> Result<()> {
|
||||
fn do_detach(log_file_path: impl AsRef<Path>) -> Result<()> {
|
||||
// detach from terminal
|
||||
match unsafe { nix::unistd::fork()? } {
|
||||
nix::unistd::ForkResult::Parent { .. } => {
|
||||
|
@ -180,10 +167,10 @@ fn do_detach() -> Result<()> {
|
|||
let file = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(&*crate::LOG_FILE)
|
||||
.open(&log_file_path)
|
||||
.expect(&format!(
|
||||
"Error opening log file ({}), for writing",
|
||||
&*crate::LOG_FILE.to_string_lossy()
|
||||
log_file_path.as_ref().to_string_lossy()
|
||||
));
|
||||
let fd = file.as_raw_fd();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue