Skip to content

Commit

Permalink
feat: restructure crates; improve folder structure of wm crate (#908)
Browse files Browse the repository at this point in the history
* Previously, the `wm` crate contained essentially everything - it's used as a library *and* the entrypoint for both the main executable + cli. This isn't super intuitive, so it's being split out into the following:
```
wm (main app)
wm-cli (cli app)
wm-common (common types/utilities)
wm-ipc-client (small websocket client)
wm-platform (abstractions over Windows apis)
wm-watcher (watcher app)
```
* Change CLI to be a distinct binary from the `wm` crate.
  * This means the CLI can be compiled without `uiAccess`, fixing the issue where CLI commands often errors with `Permission denied` (fixes #861, #902).
  • Loading branch information
lars-berger authored Jan 12, 2025
1 parent 47593a0 commit 51de98b
Show file tree
Hide file tree
Showing 141 changed files with 2,300 additions and 2,129 deletions.
84 changes: 70 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
[workspace]
resolver = "2"
members = ["packages/*"]
default-members = ["packages/wm", "packages/watcher"]
default-members = ["packages/wm", "packages/wm-cli", "packages/wm-watcher"]

[workspace.dependencies]
anyhow = { version = "1", features = ["backtrace"] }
clap = { version = "4", features = ["derive"] }
futures-util = "0.3"
home = "0.5"
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["raw_value"] }
tokio = { version = "1", features = ["full"] }
tauri-winres = "0.1"
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = "0.21"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
uuid = { version = "1", features = ["v4", "serde"] }
24 changes: 24 additions & 0 deletions packages/wm-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "wm-cli"
version = "0.0.0"
edition = "2021"

[lib]
path = "src/lib.rs"

[[bin]]
name = "glazewm-cli"
path = "src/main.rs"

[build-dependencies]
tauri-winres = { workspace = true }

[dependencies]
anyhow = { workspace = true }
futures-util = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
tokio-tungstenite = { workspace = true }
uuid = { workspace = true }
wm-common = { path = "../wm-common" }
wm-ipc-client = { path = "../wm-ipc-client" }
37 changes: 37 additions & 0 deletions packages/wm-cli/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use tauri_winres::VersionInfo;

fn main() {
println!("cargo:rerun-if-env-changed=VERSION_NUMBER");
let mut res = tauri_winres::WindowsResource::new();

res.set_icon("../../resources/assets/icon.ico");

// Set language to English (US).
res.set_language(0x0409);

res.set("OriginalFilename", "glazewm.exe");
res.set("ProductName", "GlazeWM CLI");
res.set("FileDescription", "GlazeWM CLI");

let version_parts = env!("VERSION_NUMBER")
.split('.')
.take(3)
.map(|part| part.parse().unwrap_or(0))
.collect::<Vec<u16>>();

let [major, minor, patch] =
<[u16; 3]>::try_from(version_parts).unwrap_or([0, 0, 0]);

let version_str = format!("{}.{}.{}.0", major, minor, patch);
res.set("FileVersion", &version_str);
res.set("ProductVersion", &version_str);

let version_u64 = ((major as u64) << 48)
| ((minor as u64) << 32)
| ((patch as u64) << 16);

res.set_version_info(VersionInfo::FILEVERSION, version_u64);
res.set_version_info(VersionInfo::PRODUCTVERSION, version_u64);

res.compile().unwrap();
}
38 changes: 38 additions & 0 deletions packages/wm-cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use anyhow::Context;
use wm_common::ClientResponseData;
use wm_ipc_client::IpcClient;

pub async fn start(args: Vec<String>) -> anyhow::Result<()> {
let mut client = IpcClient::connect().await?;

let message = args[1..].join(" ");
client
.send(&message)
.await
.context("Failed to send command to IPC server.")?;

let client_response = client
.client_response(&message)
.await
.context("Failed to receive response from IPC server.")?;

match client_response.data {
// For event subscriptions, omit the initial response message and
// continuously output subsequent event messages.
Some(ClientResponseData::EventSubscribe(data)) => loop {
let event_subscription = client
.event_subscription(&data.subscription_id)
.await
.context("Failed to receive response from IPC server.")?;

println!("{}", serde_json::to_string(&event_subscription)?);
},
// For all other messages, output and exit when the first response
// message is received.
_ => {
println!("{}", serde_json::to_string(&client_response)?);
}
}

Ok(())
}
44 changes: 44 additions & 0 deletions packages/wm-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::{env, process::Command};

use anyhow::Context;
use wm_cli::start;
use wm_common::AppCommand;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args = std::env::args().collect::<Vec<_>>();
let app_command = AppCommand::parse_with_default(&args);

match app_command {
AppCommand::Start { .. } => {
let exe_dir = env::current_exe()?
.parent()
.context("Failed to resolve path to the current executable.")?
.to_owned();

// Main executable is either in the current directory (when running
// debug/release builds) or in the parent directory when packaged.
let main_path =
[exe_dir.join("glazewm.exe"), exe_dir.join("../glazewm.exe")]
.into_iter()
.find(|path| path.exists())
.and_then(|path| path.to_str().map(|s| s.to_string()))
.context("Failed to resolve path to the main executable.")?;

// UIAccess applications can't be started directly, so we need to use
// CMD to start it. The start command is used to avoid a long-running
// CMD process in the background.
Command::new("cmd")
.args(
["/C", "start", "", &main_path]
.into_iter()
.chain(args.iter().skip(1).map(|s| s.as_str())),
)
.spawn()
.context("Failed to start main executable.")?;

Ok(())
}
_ => start(args).await,
}
}
15 changes: 15 additions & 0 deletions packages/wm-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "wm-common"
version = "0.0.0"
edition = "2021"

[lib]
path = "src/lib.rs"

[dependencies]
anyhow = { workspace = true }
clap = { workspace = true }
regex = "1"
serde = { workspace = true }
tracing = { workspace = true }
uuid = { workspace = true }
File renamed without changes.
Loading

0 comments on commit 51de98b

Please sign in to comment.