can json diff

master
bel 2025-11-10 23:20:01 -07:00
parent 56d5f59daf
commit 4067bd75fe
3 changed files with 90 additions and 64 deletions

63
pttodoest/Cargo.lock generated Normal file → Executable file
View File

@ -164,6 +164,28 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "json-patch"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f300e415e2134745ef75f04562dd0145405c2f7fd92065db029ac4b16b57fe90"
dependencies = [
"jsonptr",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "jsonptr"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe"
dependencies = [
"serde",
"serde_json",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.177" version = "0.2.177"
@ -176,6 +198,12 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]] [[package]]
name = "once_cell_polyfill" name = "once_cell_polyfill"
version = "1.70.2" version = "1.70.2"
@ -197,7 +225,9 @@ version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap",
"gethostname", "gethostname",
"json-patch",
"serde", "serde",
"serde_json",
"serde_yaml", "serde_yaml",
] ]
@ -259,6 +289,19 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "serde_json"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
"serde_core",
]
[[package]] [[package]]
name = "serde_yaml" name = "serde_yaml"
version = "0.9.34+deprecated" version = "0.9.34+deprecated"
@ -289,6 +332,26 @@ dependencies = [
"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.22" version = "1.0.22"

2
pttodoest/Cargo.toml Normal file → Executable file
View File

@ -6,5 +6,7 @@ edition = "2024"
[dependencies] [dependencies]
clap = { version = "4.5.51", features = ["derive"] } clap = { version = "4.5.51", features = ["derive"] }
gethostname = "1.1.0" gethostname = "1.1.0"
json-patch = "4.1.0"
serde = { version = "1.0.228", features = ["serde_derive"] } serde = { version = "1.0.228", features = ["serde_derive"] }
serde_json = "1.0.145"
serde_yaml = "0.9.34" serde_yaml = "0.9.34"

89
pttodoest/src/main.rs Normal file → Executable file
View File

@ -1,6 +1,7 @@
use clap::Parser; use clap::Parser;
use serde_yaml; use serde_yaml;
use std::io::Read; use std::io::{Read, Write};
use serde::{Serialize, Deserialize};
fn main() { fn main() {
for file in Flags::new() for file in Flags::new()
@ -100,27 +101,16 @@ impl File {
} }
fn reconcile_snapshot_changes(&self) -> Result<(), String> { fn reconcile_snapshot_changes(&self) -> Result<(), String> {
let history = self.events()?.snapshot()?; let snapshot = self.events()?.snapshot()?;
let cached = self.snapshot()?; let snapshot = serde_json::to_string(&snapshot).unwrap();
match history == cached { let snapshot: serde_json::Value = serde_json::from_str(snapshot.as_str()).unwrap();
true => Ok(()),
false => { let stage = self.snapshot()?;
for task in history.iter() { let stage = serde_json::to_string(&stage).unwrap();
if !cached.contains(task) { let stage: serde_json::Value = serde_json::from_str(stage.as_str()).unwrap();
self.pop(task.clone())?;
} let patch = json_patch::diff(&snapshot, &stage);
} panic!("not impl jsondiff snapshots: {:?}", patch)
for i in 0..cached.len() {
if !history.contains(&cached[i]) {
self.push(TaskAt {
task: cached[i].clone(),
at: i,
})?;
}
}
panic!("not impl")
}
}
} }
fn snapshot(&self) -> Result<Vec<Task>, String> { fn snapshot(&self) -> Result<Vec<Task>, String> {
@ -147,47 +137,36 @@ impl File {
Ok(result) Ok(result)
} }
fn push(&self, task_at: TaskAt) -> Result<(), String> {
self.append(Delta {
pushed_at: vec![task_at],
popped: vec![],
})
}
fn pop(&self, task: Task) -> Result<(), String> {
self.append(Delta {
pushed_at: vec![],
popped: vec![task],
})
}
fn append(&self, delta: Delta) -> Result<(), String> { fn append(&self, delta: Delta) -> Result<(), String> {
use std::fs::OpenOptions; use std::fs::OpenOptions;
let hostname = gethostname::gethostname(); let hostname = gethostname::gethostname();
let mut file = match OpenOptions::new().write(true).append(true).open(&self.file) { let log = format!("{}{}", Events::log_prefix(&self.file), gethostname::gethostname().into_string().unwrap());
let mut file = match OpenOptions::new().write(true).append(true).open(&log) {
Ok(f) => Ok(f), Ok(f) => Ok(f),
Err(msg) => Err(format!( Err(msg) => Err(format!(
"failed to open {} for appending: {}", "failed to open {} for appending: {}",
&self.file, msg &self.file, msg
)), )),
}?; }?;
panic!("not impl: {:?}", file) let line = serde_json::to_string(&delta).unwrap();
match
writeln!(file, "{}", line) {
Ok(_) => Ok(()),
Err(msg) => Err(format!("failed to append: {}", msg)),
}
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize, Deserialize)]
struct Delta { struct Delta(json_patch::Patch);
pushed_at: Vec<TaskAt>,
popped: Vec<Task>,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize, Deserialize)]
struct TaskAt { struct TaskAt {
task: Task, task: Task,
at: usize, at: usize,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct Task(serde_yaml::Value); struct Task(serde_yaml::Value);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -238,25 +217,7 @@ impl Events {
fn snapshot(&self) -> Result<Vec<Task>, String> { fn snapshot(&self) -> Result<Vec<Task>, String> {
let mut result = vec![]; let mut result = vec![];
for event in self.0.iter() { for event in self.0.iter() {
for popped in event.popped.iter() { panic!("not impl: {:?}", event)
for i in (0..result.len())
.map(|i| i as usize)
.filter(|i| result[*i] == *popped)
{
panic!("not impl")
}
}
for push in event.pushed_at.iter() {
result.insert(
if push.at < result.len() {
push.at
} else {
result.len()
},
push.task.clone(),
);
}
panic!("not impl: {:?}", result)
} }
Ok(result) Ok(result)
} }