Add EwwPaths struct and refactor path handling in general

This commit is contained in:
elkowar 2021-03-02 13:12:52 +01:00
parent 5b3344fc5b
commit 8dba5aca83
5 changed files with 114 additions and 84 deletions

View file

@ -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),

View file

@ -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()?;

View file

@ -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()
)
}
}

View file

@ -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>,

View file

@ -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();