mirror of
https://github.com/Noratrieb/clippyboard.git
synced 2026-01-14 18:05:04 +01:00
terrible nixos module
This commit is contained in:
parent
cead214aa1
commit
b2ff5b0763
8 changed files with 128 additions and 22 deletions
|
|
@ -3,6 +3,12 @@ name = "clippyboard"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "clippyboard-daemon"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "clippyboard-select"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ciborium = "0.2.2"
|
ciborium = "0.2.2"
|
||||||
dirs = "6.0.0"
|
dirs = "6.0.0"
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,9 @@
|
||||||
];
|
];
|
||||||
|
|
||||||
postFixup = ''
|
postFixup = ''
|
||||||
wrapProgram $out/bin/clippyboard \
|
wrapProgram $out/bin/clippyboard-select \
|
||||||
|
--suffix LD_LIBRARY_PATH : ${pkgs.lib.makeLibraryPath buildInputs}
|
||||||
|
wrapProgram $out/bin/clippyboard-daemon \
|
||||||
--suffix LD_LIBRARY_PATH : ${pkgs.lib.makeLibraryPath buildInputs}
|
--suffix LD_LIBRARY_PATH : ${pkgs.lib.makeLibraryPath buildInputs}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
|
|
||||||
27
flake.lock
generated
Normal file
27
flake.lock
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1758029226,
|
||||||
|
"narHash": "sha256-TjqVmbpoCqWywY9xIZLTf6ANFvDCXdctCjoYuYPYdMI=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "08b8f92ac6354983f5382124fef6006cade4a1c1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
47
flake.nix
Normal file
47
flake.nix
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# warning: this flake is probably terrible, whatever
|
||||||
|
{
|
||||||
|
description = "clippyboard: a clipboard manager";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { nixpkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
lib = nixpkgs.lib;
|
||||||
|
clippyboard-package = ./default.nix;
|
||||||
|
systems = lib.intersectLists lib.systems.flakeExposed lib.platforms.linux;
|
||||||
|
forAllSystems = lib.genAttrs systems;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
packages = forAllSystems (system: { default = nixpkgs.${system}.callPackage clippyboard-package { }; });
|
||||||
|
nixosModules.default = { lib, config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.clippyboard;
|
||||||
|
clippyboard = pkgs.callPackage clippyboard-package { };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.clippyboard = {
|
||||||
|
enable = lib.mkEnableOption "Enable the clippyboard daemon and clippyboard program";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(final: prev: {
|
||||||
|
clipboard = clippyboard;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
systemd.user.services.clippyboard = {
|
||||||
|
description = "a clipboard manager";
|
||||||
|
wantedBy = [ "graphical-session.target" ];
|
||||||
|
after = [ "graphical-session.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = lib.getExe' clippyboard "clippyboard-daemon";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
environment.systemPackages = [ clippyboard ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
4
src/bin/clippyboard-daemon.rs
Normal file
4
src/bin/clippyboard-daemon.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() -> Result<(), eyre::Error> {
|
||||||
|
let socket_path: std::path::PathBuf = clippyboard::socket_path()?;
|
||||||
|
clippyboard::daemon::main(&socket_path)
|
||||||
|
}
|
||||||
4
src/bin/clippyboard-select.rs
Normal file
4
src/bin/clippyboard-select.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() -> Result<(), eyre::Error> {
|
||||||
|
let socket_path = clippyboard::socket_path()?;
|
||||||
|
clippyboard::display::main(&socket_path)
|
||||||
|
}
|
||||||
|
|
@ -8,11 +8,16 @@ use rustix::event::PollFd;
|
||||||
use rustix::event::PollFlags;
|
use rustix::event::PollFlags;
|
||||||
use rustix::fs::OFlags;
|
use rustix::fs::OFlags;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::convert::Infallible;
|
||||||
|
use std::io;
|
||||||
|
use std::io::ErrorKind;
|
||||||
use std::io::PipeReader;
|
use std::io::PipeReader;
|
||||||
use std::io::{BufReader, BufWriter, PipeWriter, Read, Write};
|
use std::io::{BufReader, BufWriter, PipeWriter, Read, Write};
|
||||||
use std::os::fd::AsFd;
|
use std::os::fd::AsFd;
|
||||||
use std::os::unix::net::{UnixListener, UnixStream};
|
use std::os::unix::net::{UnixListener, UnixStream};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::{Arc, Mutex, OnceLock, atomic::AtomicU64};
|
use std::sync::{Arc, Mutex, OnceLock, atomic::AtomicU64};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
@ -430,11 +435,24 @@ fn read_fd_into_history(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(socket_path: &PathBuf) -> eyre::Result<()> {
|
pub fn main(socket_path: &PathBuf) -> eyre::Result<()> {
|
||||||
|
let Err(err) = main_inner(socket_path);
|
||||||
|
|
||||||
|
if let Some(ioerr) = err.downcast_ref::<io::Error>()
|
||||||
|
&& ioerr.kind() == ErrorKind::AddrInUse
|
||||||
|
{
|
||||||
|
// no cleanup
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup(socket_path);
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main_inner(socket_path: &PathBuf) -> eyre::Result<Infallible> {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(EnvFilter::try_from_default_env().unwrap_or(EnvFilter::new("info")))
|
.with_env_filter(EnvFilter::try_from_default_env().unwrap_or(EnvFilter::new("info")))
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let _ = std::fs::remove_file(&socket_path); // lol
|
|
||||||
let socket = UnixListener::bind(&socket_path)
|
let socket = UnixListener::bind(&socket_path)
|
||||||
.wrap_err_with(|| format!("binding path {}", socket_path.display()))?;
|
.wrap_err_with(|| format!("binding path {}", socket_path.display()))?;
|
||||||
|
|
||||||
|
|
@ -481,9 +499,11 @@ pub fn main(socket_path: &PathBuf) -> eyre::Result<()> {
|
||||||
rustix::fs::fcntl_setfl(notify_write_recv.as_fd(), OFlags::NONBLOCK).expect("todo");
|
rustix::fs::fcntl_setfl(notify_write_recv.as_fd(), OFlags::NONBLOCK).expect("todo");
|
||||||
rustix::fs::fcntl_setfl(conn.as_fd(), OFlags::NONBLOCK).expect("TODO");
|
rustix::fs::fcntl_setfl(conn.as_fd(), OFlags::NONBLOCK).expect("TODO");
|
||||||
|
|
||||||
|
let socket_path_clone = socket_path.to_owned();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
if let Err(err) = dispatch_wayland(queue, wl_state, notify_write_recv) {
|
if let Err(err) = dispatch_wayland(queue, wl_state, notify_write_recv) {
|
||||||
error!("error on Wayland thread: {err:?}");
|
error!("error on Wayland thread: {err:?}");
|
||||||
|
cleanup(&socket_path_clone);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -507,5 +527,13 @@ pub fn main(socket_path: &PathBuf) -> eyre::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
unreachable!("socket.incoming will never return None")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cleanup(socket_path: &PathBuf) {
|
||||||
|
static HAS_DONE_CLEANUP: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
if !HAS_DONE_CLEANUP.swap(true, Ordering::Relaxed) {
|
||||||
|
let _ = std::fs::remove_file(&socket_path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
mod daemon;
|
pub mod daemon;
|
||||||
mod display;
|
pub mod display;
|
||||||
|
|
||||||
use eyre::{OptionExt, bail};
|
use eyre::OptionExt;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use std::sync::Arc;
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
const MAX_ENTRY_SIZE: u64 = 50_000_000;
|
const MAX_ENTRY_SIZE: u64 = 50_000_000;
|
||||||
const MAX_HISTORY_BYTE_SIZE: usize = 100_000_000;
|
const MAX_HISTORY_BYTE_SIZE: usize = 100_000_000;
|
||||||
|
|
@ -33,20 +33,8 @@ const MESSAGE_READ: u8 = 1;
|
||||||
/// Argument: One u64-bit LE value, the ID
|
/// Argument: One u64-bit LE value, the ID
|
||||||
const MESSAGE_COPY: u8 = 2;
|
const MESSAGE_COPY: u8 = 2;
|
||||||
|
|
||||||
fn main() -> eyre::Result<()> {
|
pub fn socket_path() -> eyre::Result<PathBuf> {
|
||||||
let Some(mode) = std::env::args().nth(1) else {
|
Ok(dirs::runtime_dir()
|
||||||
bail!("missing mode");
|
|
||||||
};
|
|
||||||
|
|
||||||
let socket_path = dirs::runtime_dir()
|
|
||||||
.ok_or_eyre("missing XDG_RUNTIME_DIR")?
|
.ok_or_eyre("missing XDG_RUNTIME_DIR")?
|
||||||
.join("clippyboard.sock");
|
.join("clippyboard.sock"))
|
||||||
|
|
||||||
match mode.as_str() {
|
|
||||||
"daemon" => daemon::main(&socket_path)?,
|
|
||||||
"display" => display::main(&socket_path)?,
|
|
||||||
_ => panic!("invalid mode, supported: daemon, display"),
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue