Compare commits

...

4 commits

Author SHA1 Message Date
Breadway
c20a6d966c Switch to tag-pinned bread-ecosystem deps; bump version to v0.1.11
Some checks failed
Mirror to GitHub / mirror (push) Failing after 2s
Build and publish package / package (push) Failing after 27s
release / build (push) Successful in 11s
2026-07-19 03:52:49 +08:00
Breadway
50efebe5df Timeout-guard subprocess calls to awww, wal, and bread-theme
wallpaper.rs/pywal.rs/theme.rs each shelled out via a bare
Command::new(...).status() with no timeout — a wedged awww-daemon, pywal
choking on a corrupt/huge image, or a hung bread-theme reload could each
block breadpaper indefinitely. Switched to bread_utils::proc::run (path
dependency for now, see the TODO in Cargo.toml), matching the exact
"anything shelling out to awww" case named in tonight's ecosystem-utils
audit.
2026-07-17 09:52:40 +08:00
Breadway
168a449edf breadpaper: commit README, align Cargo.toml version with tag
- README.md existed only in the working tree and was never committed,
  so the published repo/release tarball shipped with no documentation
  at all. Verified its usage/install instructions against the current
  code before committing; corrected the stated Rust requirement from
  1.80+ to 1.85+ (edition 2024 needs 1.85+).
- Cargo.toml: 0.1.0 -> 0.1.10, matching the latest tag (v0.1.10).
  breadpaper --version previously reported nine releases behind the
  actual release history.
2026-07-17 03:20:48 +08:00
Breadway
1671af82ee fix: rustfmt violations
Some checks failed
Mirror to GitHub / mirror (push) Failing after 2s
2026-06-19 08:38:41 +08:00
9 changed files with 337 additions and 89 deletions

View file

@ -1,38 +0,0 @@
name: CI
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-D warnings"
jobs:
test:
name: fmt · clippy · test · build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache cargo
uses: Swatinem/rust-cache@v2
- name: Format check
run: cargo fmt --all -- --check
- name: Clippy
run: cargo clippy --all-targets -- -D warnings
- name: Test
run: cargo test --all --verbose
- name: Release build
run: cargo build --release --verbose

262
Cargo.lock generated
View file

@ -38,7 +38,7 @@ version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [ dependencies = [
"windows-sys", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
@ -49,28 +49,45 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"once_cell_polyfill", "once_cell_polyfill",
"windows-sys", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.102" version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
[[package]]
name = "bread-utils"
version = "0.3.0"
source = "git+https://git.breadway.dev/Breadway/bread-ecosystem?tag=v0.3.0#8e82d2d833e992ce939a5b836f910ee109f2e939"
dependencies = [
"dirs",
"serde",
"serde_json",
]
[[package]] [[package]]
name = "breadpaper" name = "breadpaper"
version = "0.1.0" version = "0.1.11"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bread-utils",
"clap", "clap",
] ]
[[package]] [[package]]
name = "clap" name = "cfg-if"
version = "4.6.1" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "clap"
version = "4.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd059f9da4f5c36b3787f65d38ccaab1cc315f07b01f89abc8359ee6a8205011"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -78,9 +95,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.6.0" version = "4.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -112,6 +129,38 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "dirs"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.48.0",
]
[[package]]
name = "getrandom"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
@ -124,12 +173,45 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "libc"
version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "libredox"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652"
dependencies = [
"libc",
]
[[package]]
name = "memchr"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]] [[package]]
name = "once_cell_polyfill" name = "once_cell_polyfill"
version = "1.70.2" version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.106" version = "1.0.106"
@ -141,13 +223,67 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.45" version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "redox_users"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom",
"libredox",
"thiserror",
]
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
@ -156,15 +292,35 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.118" version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.24" version = "1.0.24"
@ -177,12 +333,27 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]] [[package]]
name = "windows-link" name = "windows-link"
version = "0.2.1" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.61.2" version = "0.61.2"
@ -191,3 +362,66 @@ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "zmij"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "breadpaper" name = "breadpaper"
version = "0.1.0" version = "0.1.11"
edition = "2024" edition = "2024"
description = "Wallpaper manager for the bread desktop" description = "Wallpaper manager for the bread desktop"
license = "MIT" license = "MIT"
@ -8,3 +8,4 @@ license = "MIT"
[dependencies] [dependencies]
clap = { version = "4", features = ["derive"] } clap = { version = "4", features = ["derive"] }
anyhow = "1" anyhow = "1"
bread-utils = { git = "https://git.breadway.dev/Breadway/bread-ecosystem", tag = "v0.3.0" }

53
README.md Normal file
View file

@ -0,0 +1,53 @@
# breadpaper
Wallpaper manager for the bread desktop. Sets a wallpaper via [awww](https://github.com/heywoodlh/awww), generates a colour palette with [pywal](https://github.com/dylanaraps/pywal), and reloads bread themes in one command.
## Dependencies
Runtime:
- `awww` — Wayland wallpaper daemon
- `python-pywal` — colour palette generation
- `bread-theme` — theme reload (part of the bread ecosystem)
Build:
- Rust 1.85+ (edition 2024) / cargo
## Install
**From the bakery (recommended on bread OS):**
```
bakery install breadpaper
```
**From source:**
```
cargo build --release
install -Dm755 target/release/breadpaper ~/.local/bin/breadpaper
```
**Arch Linux (PKGBUILD):**
```
cd packaging/arch
makepkg -si
```
## Usage
```
breadpaper <path> # set wallpaper (shorthand for `set`)
breadpaper set <path> # set wallpaper, generate palette, reload themes
breadpaper get # print the current wallpaper path
```
Supported formats: `png`, `jpg`, `jpeg`, `webp`, `gif`, `bmp`.
The current wallpaper path is stored by pywal at `~/.cache/wal/wal`.
## License
MIT — see [LICENSE](LICENSE).

View file

@ -1,11 +1,11 @@
# Maintainer: Breadway <rileyhorsham@gmail.com> # Maintainer: Breadway <plasticbread849@gmail.com>
pkgname=breadpaper pkgname=breadpaper
pkgver=0.1.0 pkgver=0.1.0
pkgrel=1 pkgrel=1
pkgdesc="Wallpaper manager for the bread desktop" pkgdesc="Wallpaper manager for the bread desktop"
arch=('x86_64') arch=('x86_64')
url="https://github.com/Breadway/breadpaper" url="https://git.breadway.dev/Breadway/breadpaper"
license=('MIT') license=('MIT')
options=(!lto !debug) options=(!lto !debug)
depends=('glibc') depends=('glibc')

View file

@ -4,7 +4,11 @@ use std::process;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
#[derive(Parser)] #[derive(Parser)]
#[command(name = "breadpaper", version, about = "Wallpaper manager for the bread desktop")] #[command(
name = "breadpaper",
version,
about = "Wallpaper manager for the bread desktop"
)]
struct Cli { struct Cli {
/// Image file to set as wallpaper (shorthand for `set`) /// Image file to set as wallpaper (shorthand for `set`)
path: Option<PathBuf>, path: Option<PathBuf>,
@ -16,9 +20,7 @@ struct Cli {
#[derive(Subcommand)] #[derive(Subcommand)]
enum Command { enum Command {
/// Set wallpaper, generate pywal palette, and reload bread themes /// Set wallpaper, generate pywal palette, and reload bread themes
Set { Set { path: PathBuf },
path: PathBuf,
},
/// Print the current wallpaper path /// Print the current wallpaper path
Get, Get,
} }

View file

@ -1,18 +1,19 @@
use std::path::Path; use std::path::Path;
use std::process::Command; use std::time::Duration;
use anyhow::{Context, Result, bail}; use anyhow::{Result, bail};
pub fn generate(path: &Path) -> Result<()> { pub fn generate(path: &Path) -> Result<()> {
let status = Command::new("wal") // Was a bare Command::new("wal").status() with no timeout — pywal can
.arg("-i") // hang on a corrupt/huge image; this used to be able to wedge the
.arg(path) // caller indefinitely.
.arg("-n") // skip wal's own wallpaper backend; awww already set it let out = bread_utils::proc::run(
.status() "wal",
.context("failed to run wal — is python-pywal installed?")?; &["-i", &path.to_string_lossy(), "-n"], // -n: skip wal's own wallpaper backend; awww already set it
Duration::from_secs(30),
if !status.success() { );
bail!("wal exited with {}", status); if !out.success {
bail!("wal failed (is python-pywal installed?): {}", out.stderr.trim());
} }
Ok(()) Ok(())
} }

View file

@ -1,15 +1,12 @@
use std::process::Command; use std::time::Duration;
use anyhow::{Context, Result, bail}; use anyhow::{Result, bail};
pub fn reload() -> Result<()> { pub fn reload() -> Result<()> {
let status = Command::new("bread-theme") // Was a bare Command::new("bread-theme").status() with no timeout.
.arg("reload") let out = bread_utils::proc::run("bread-theme", &["reload"], Duration::from_secs(5));
.status() if !out.success {
.context("failed to run bread-theme — is it installed?")?; bail!("bread-theme reload failed (is it installed?): {}", out.stderr.trim());
if !status.success() {
bail!("bread-theme reload exited with {}", status);
} }
Ok(()) Ok(())
} }

View file

@ -1,17 +1,15 @@
use std::path::Path; use std::path::Path;
use std::process::Command; use std::time::Duration;
use anyhow::{Context, Result, bail}; use anyhow::{Result, bail};
pub fn apply(path: &Path) -> Result<()> { pub fn apply(path: &Path) -> Result<()> {
let status = Command::new("awww") // Was a bare Command::new("awww").status() with no timeout — a wedged
.arg("img") // awww-daemon (compositor not ready yet, IPC socket stuck) used to be
.arg(path) // able to hang this call indefinitely.
.status() let out = bread_utils::proc::run("awww", &["img", &path.to_string_lossy()], Duration::from_secs(10));
.context("failed to run awww — is awww-daemon running?")?; if !out.success {
bail!("awww img failed (is awww-daemon running?): {}", out.stderr.trim());
if !status.success() {
bail!("awww img exited with {}", status);
} }
Ok(()) Ok(())
} }