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,
|
display_backend, eww_state,
|
||||||
script_var_handler::*,
|
script_var_handler::*,
|
||||||
value::{Coords, NumWithUnit, PrimitiveValue, VarName},
|
value::{Coords, NumWithUnit, PrimitiveValue, VarName},
|
||||||
|
EwwPaths,
|
||||||
};
|
};
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use debug_stub_derive::*;
|
use debug_stub_derive::*;
|
||||||
use gdk::WindowExt;
|
use gdk::WindowExt;
|
||||||
use gtk::{ContainerExt, CssProviderExt, GtkWindowExt, StyleContextExt, WidgetExt};
|
use gtk::{ContainerExt, CssProviderExt, GtkWindowExt, StyleContextExt, WidgetExt};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::{collections::HashMap, path::PathBuf};
|
use std::collections::HashMap;
|
||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
/// Response that the app may send as a response to a event.
|
/// Response that the app may send as a response to a event.
|
||||||
|
@ -91,8 +92,7 @@ pub struct App {
|
||||||
#[debug_stub = "ScriptVarHandler(...)"]
|
#[debug_stub = "ScriptVarHandler(...)"]
|
||||||
pub script_var_handler: ScriptVarHandlerHandle,
|
pub script_var_handler: ScriptVarHandlerHandle,
|
||||||
|
|
||||||
pub config_file_path: PathBuf,
|
pub paths: EwwPaths,
|
||||||
pub scss_file_path: PathBuf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
|
@ -110,14 +110,14 @@ impl App {
|
||||||
DaemonCommand::ReloadConfigAndCss(sender) => {
|
DaemonCommand::ReloadConfigAndCss(sender) => {
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
let config_result =
|
let config_result = config::RawEwwConfig::read_from_file(&self.paths.get_eww_xml_path())
|
||||||
config::RawEwwConfig::read_from_file(&self.config_file_path).and_then(config::EwwConfig::generate);
|
.and_then(config::EwwConfig::generate);
|
||||||
match config_result {
|
match config_result {
|
||||||
Ok(new_config) => self.handle_command(DaemonCommand::UpdateConfig(new_config)),
|
Ok(new_config) => self.handle_command(DaemonCommand::UpdateConfig(new_config)),
|
||||||
Err(e) => errors.push(e),
|
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 {
|
match css_result {
|
||||||
Ok(new_css) => self.handle_command(DaemonCommand::UpdateCss(new_css)),
|
Ok(new_css) => self.handle_command(DaemonCommand::UpdateCss(new_css)),
|
||||||
Err(e) => errors.push(e),
|
Err(e) => errors.push(e),
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::process::Stdio;
|
||||||
use crate::{
|
use crate::{
|
||||||
app,
|
app,
|
||||||
opts::{self, ActionClientOnly},
|
opts::{self, ActionClientOnly},
|
||||||
|
EwwPaths,
|
||||||
};
|
};
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -10,11 +11,11 @@ use std::{
|
||||||
os::unix::net::UnixStream,
|
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 {
|
match action {
|
||||||
ActionClientOnly::Logs => {
|
ActionClientOnly::Logs => {
|
||||||
std::process::Command::new("tail")
|
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())
|
.stdin(Stdio::null())
|
||||||
.spawn()?
|
.spawn()?
|
||||||
.wait()?;
|
.wait()?;
|
||||||
|
|
130
src/main.rs
130
src/main.rs
|
@ -12,8 +12,10 @@ extern crate gio;
|
||||||
extern crate gtk;
|
extern crate gtk;
|
||||||
|
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
|
use std::{
|
||||||
use std::{os::unix::net, path::PathBuf};
|
os::unix::net,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod application_lifecycle;
|
pub mod application_lifecycle;
|
||||||
|
@ -30,38 +32,6 @@ pub mod util;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
pub mod widgets;
|
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() {
|
fn main() {
|
||||||
let opts: opts::Opt = opts::Opt::from_env();
|
let opts: opts::Opt = opts::Opt::from_env();
|
||||||
|
|
||||||
|
@ -76,16 +46,20 @@ fn main() {
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let result: Result<_> = try {
|
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 {
|
match opts.action {
|
||||||
opts::Action::ClientOnly(action) => {
|
opts::Action::ClientOnly(action) => {
|
||||||
client::handle_client_only_action(action)?;
|
client::handle_client_only_action(&paths, action)?;
|
||||||
}
|
}
|
||||||
opts::Action::WithServer(action) => {
|
opts::Action::WithServer(action) => {
|
||||||
log::info!("Trying to find server process at socket {}", socket_path.display());
|
log::info!(
|
||||||
match net::UnixStream::connect(&socket_path) {
|
"Trying to find server process at socket {}",
|
||||||
|
paths.get_ipc_socket_file().display()
|
||||||
|
);
|
||||||
|
match net::UnixStream::connect(&paths.get_ipc_socket_file()) {
|
||||||
Ok(stream) => {
|
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 =
|
let response =
|
||||||
client::do_server_call(stream, action).context("Error while forwarding command to server")?;
|
client::do_server_call(stream, action).context("Error while forwarding command to server")?;
|
||||||
if let Some(response) = response {
|
if let Some(response) = response {
|
||||||
|
@ -105,15 +79,15 @@ fn main() {
|
||||||
|
|
||||||
opts::Action::Daemon => {
|
opts::Action::Daemon => {
|
||||||
// make sure that there isn't already a Eww daemon running.
|
// 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.");
|
eprintln!("Eww server already running.");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
} else {
|
} else {
|
||||||
log::info!("Initializing Eww server. ({})", socket_path.display());
|
log::info!("Initializing Eww server. ({})", paths.get_ipc_socket_file().display());
|
||||||
let _ = std::fs::remove_file(socket_path);
|
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.");
|
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.
|
/// 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)
|
let response = net::UnixStream::connect(socket_path)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|stream| client::do_server_call(stream, opts::ActionWithServer::Ping).ok());
|
.and_then(|stream| client::do_server_call(stream, opts::ActionWithServer::Ping).ok());
|
||||||
response.is_some()
|
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)]
|
#[structopt(long = "debug", global = true)]
|
||||||
log_debug: bool,
|
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)]
|
#[structopt(short, long, global = true)]
|
||||||
config: Option<std::path::PathBuf>,
|
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 anyhow::*;
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use std::{
|
use std::{collections::HashMap, os::unix::io::AsRawFd, path::Path};
|
||||||
collections::HashMap,
|
|
||||||
os::unix::io::AsRawFd,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
use tokio::sync::mpsc::*;
|
use tokio::sync::mpsc::*;
|
||||||
|
|
||||||
pub fn initialize_server(config_dir_override: Option<std::path::PathBuf>) -> Result<()> {
|
pub fn initialize_server(paths: EwwPaths) -> Result<()> {
|
||||||
do_detach()?;
|
do_detach(&paths.get_log_file())?;
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
r#"
|
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 (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
|
log::info!("Loading paths: {}", &paths);
|
||||||
.parent()
|
let eww_config = config::EwwConfig::read_from_file(&paths.get_eww_xml_path())?;
|
||||||
.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)?;
|
|
||||||
|
|
||||||
gtk::init()?;
|
gtk::init()?;
|
||||||
|
|
||||||
|
@ -53,20 +42,19 @@ pub fn initialize_server(config_dir_override: Option<std::path::PathBuf>) -> Res
|
||||||
css_provider: gtk::CssProvider::new(),
|
css_provider: gtk::CssProvider::new(),
|
||||||
script_var_handler,
|
script_var_handler,
|
||||||
app_evt_send: ui_send.clone(),
|
app_evt_send: ui_send.clone(),
|
||||||
config_file_path,
|
paths,
|
||||||
scss_file_path,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(screen) = gdk::Screen::get_default() {
|
if let Some(screen) = gdk::Screen::get_default() {
|
||||||
gtk::StyleContext::add_provider_for_screen(&screen, &app.css_provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION);
|
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)?;
|
app.load_css(&eww_css)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize all the handlers and tasks running asyncronously
|
// 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 {
|
glib::MainContext::default().spawn_local(async move {
|
||||||
while let Some(event) = ui_recv.recv().await {
|
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(())
|
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 || {
|
std::thread::spawn(move || {
|
||||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
|
@ -89,14 +77,13 @@ fn init_async_part(config_file_path: PathBuf, scss_file_path: PathBuf, ui_send:
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
let filewatch_join_handle = {
|
let filewatch_join_handle = {
|
||||||
let ui_send = ui_send.clone();
|
let ui_send = ui_send.clone();
|
||||||
let config_file_path = config_file_path.clone();
|
let paths = paths.clone();
|
||||||
tokio::spawn(async move { run_filewatch(config_file_path, scss_file_path, ui_send).await })
|
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 ipc_server_join_handle = {
|
||||||
let ui_send = ui_send.clone();
|
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, paths.get_ipc_socket_file()).await })
|
||||||
tokio::spawn(async move { ipc_server::run_server(ui_send, socket_path).await })
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let forward_exit_to_app_handle = {
|
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
|
/// 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
|
// detach from terminal
|
||||||
match unsafe { nix::unistd::fork()? } {
|
match unsafe { nix::unistd::fork()? } {
|
||||||
nix::unistd::ForkResult::Parent { .. } => {
|
nix::unistd::ForkResult::Parent { .. } => {
|
||||||
|
@ -180,10 +167,10 @@ fn do_detach() -> Result<()> {
|
||||||
let file = std::fs::OpenOptions::new()
|
let file = std::fs::OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
.append(true)
|
.append(true)
|
||||||
.open(&*crate::LOG_FILE)
|
.open(&log_file_path)
|
||||||
.expect(&format!(
|
.expect(&format!(
|
||||||
"Error opening log file ({}), for writing",
|
"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();
|
let fd = file.as_raw_fd();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue