mirror of
https://codeberg.org/icewind/galton.git
synced 2026-06-03 10:24:07 +02:00
symlink support
This commit is contained in:
parent
7500d6ccf4
commit
1269e95b6f
2 changed files with 41 additions and 9 deletions
|
|
@ -8,6 +8,8 @@ use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct GaltonConfig {
|
pub struct GaltonConfig {
|
||||||
|
#[serde(default)]
|
||||||
|
pub watch: WatchConfig,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub rule: Vec<Rule>,
|
pub rule: Vec<Rule>,
|
||||||
}
|
}
|
||||||
|
|
@ -26,15 +28,26 @@ impl GaltonConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalize_path(path: String) -> String {
|
#[derive(Debug, Deserialize, Default)]
|
||||||
if let Some(suffix) = path.strip_prefix("~/") {
|
pub struct WatchConfig {
|
||||||
|
symlink: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WatchConfig {
|
||||||
|
pub fn symlink(&self) -> Option<String> {
|
||||||
|
self.symlink.as_deref().map(normalize_path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_path<P: Into<String> + AsRef<str>>(path: P) -> String {
|
||||||
|
if let Some(suffix) = path.as_ref().strip_prefix("~/") {
|
||||||
let home = home_dir().unwrap_or_default();
|
let home = home_dir().unwrap_or_default();
|
||||||
home.join(suffix)
|
home.join(suffix)
|
||||||
.into_os_string()
|
.into_os_string()
|
||||||
.into_string()
|
.into_string()
|
||||||
.expect("non utf8 home directory")
|
.expect("non utf8 home directory")
|
||||||
} else {
|
} else {
|
||||||
path
|
path.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
31
src/main.rs
31
src/main.rs
|
|
@ -10,6 +10,7 @@ use notify_debouncer_full::notify::{EventKind, RecursiveMode};
|
||||||
use notify_debouncer_full::{new_debouncer, DebounceEventResult};
|
use notify_debouncer_full::{new_debouncer, DebounceEventResult};
|
||||||
use std::fs::{copy, create_dir_all, remove_file, rename};
|
use std::fs::{copy, create_dir_all, remove_file, rename};
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
|
use std::os::unix::fs::symlink;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
|
|
@ -66,6 +67,7 @@ fn main() -> MainResult {
|
||||||
}
|
}
|
||||||
Commands::Watch { path, recursive } => {
|
Commands::Watch { path, recursive } => {
|
||||||
let rules = config.rule;
|
let rules = config.rule;
|
||||||
|
let symlink = config.watch.symlink();
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let mut watcher = new_debouncer(Duration::from_secs(1), None, tx)?;
|
let mut watcher = new_debouncer(Duration::from_secs(1), None, tx)?;
|
||||||
watcher.watch(
|
watcher.watch(
|
||||||
|
|
@ -84,7 +86,7 @@ fn main() -> MainResult {
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
for res in rx {
|
for res in rx {
|
||||||
handle_watch_events(res, &rules);
|
handle_watch_event(res, &rules, symlink.as_deref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +94,7 @@ fn main() -> MainResult {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_watch_events(result: DebounceEventResult, rules: &[Rule]) {
|
fn handle_watch_event(result: DebounceEventResult, rules: &[Rule], link_target: Option<&str>) {
|
||||||
match result {
|
match result {
|
||||||
Ok(events) => {
|
Ok(events) => {
|
||||||
for event in events {
|
for event in events {
|
||||||
|
|
@ -103,7 +105,22 @@ fn handle_watch_events(result: DebounceEventResult, rules: &[Rule]) {
|
||||||
sleep(Duration::from_millis(200));
|
sleep(Duration::from_millis(200));
|
||||||
match FileInfo::load(path) {
|
match FileInfo::load(path) {
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
handle_file(&file, rules);
|
if let Some(target) = handle_file(&file, rules) {
|
||||||
|
if let Some(link_target) = link_target {
|
||||||
|
match symlink(&target, link_target) {
|
||||||
|
Ok(()) => {
|
||||||
|
info!(
|
||||||
|
to = target,
|
||||||
|
from = link_target,
|
||||||
|
"created symlink"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
error!(%error, "failed to link target");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!(%error, "failed to load file info");
|
error!(%error, "failed to load file info");
|
||||||
|
|
@ -132,10 +149,10 @@ fn match_file(file: &FileInfo, rules: &[Rule]) -> Option<RuleMatch> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all, fields(file = file.path))]
|
#[instrument(skip_all, fields(file = file.path))]
|
||||||
fn handle_file(file: &FileInfo, rules: &[Rule]) {
|
fn handle_file(file: &FileInfo, rules: &[Rule]) -> Option<String> {
|
||||||
let Some(result) = match_file(file, rules) else {
|
let Some(result) = match_file(file, rules) else {
|
||||||
info!("no matches");
|
info!("no matches");
|
||||||
return;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let parent = result.target.as_deref().unwrap_or_else(|| file.parent());
|
let parent = result.target.as_deref().unwrap_or_else(|| file.parent());
|
||||||
|
|
@ -143,7 +160,7 @@ fn handle_file(file: &FileInfo, rules: &[Rule]) {
|
||||||
|
|
||||||
if let Err(error) = create_dir_all(parent) {
|
if let Err(error) = create_dir_all(parent) {
|
||||||
error!(%error, "failed to create target directory");
|
error!(%error, "failed to create target directory");
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let target = format!("{parent}/{name}");
|
let target = format!("{parent}/{name}");
|
||||||
|
|
@ -151,9 +168,11 @@ fn handle_file(file: &FileInfo, rules: &[Rule]) {
|
||||||
match cross_storage_move(&file.path, &target) {
|
match cross_storage_move(&file.path, &target) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
info!(target, "moved file");
|
info!(target, "moved file");
|
||||||
|
Some(target)
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
info!(target, ?error, "failed to moved file");
|
info!(target, ?error, "failed to moved file");
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue