Compare commits
2 Commits
5d2441ce0c
...
60ddbc673c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60ddbc673c | ||
|
|
7d36455bad |
85
pttodoest/Cargo.lock
generated
85
pttodoest/Cargo.lock
generated
@@ -120,6 +120,12 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuchsia-cprng"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gethostname"
|
name = "gethostname"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -230,6 +236,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
"tempdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -241,6 +248,52 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||||
|
dependencies = [
|
||||||
|
"fuchsia-cprng",
|
||||||
|
"libc",
|
||||||
|
"rand_core 0.3.1",
|
||||||
|
"rdrand",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.4.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rdrand"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.3.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "remove_dir_all"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
@@ -333,6 +386,16 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempdir"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||||
|
dependencies = [
|
||||||
|
"rand",
|
||||||
|
"remove_dir_all",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.69"
|
version = "1.0.69"
|
||||||
@@ -371,6 +434,28 @@ 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 = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-link"
|
name = "windows-link"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ jsonptr = "0.7.1"
|
|||||||
serde = { version = "1.0.228", features = ["serde_derive"] }
|
serde = { version = "1.0.228", features = ["serde_derive"] }
|
||||||
serde_json = "1.0.145"
|
serde_json = "1.0.145"
|
||||||
serde_yaml = "0.9.34"
|
serde_yaml = "0.9.34"
|
||||||
|
tempdir = "0.3.7"
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use std::io::{BufRead, Read, Write};
|
|||||||
fn main() {
|
fn main() {
|
||||||
let flags = Flags::new().expect("failed to flags");
|
let flags = Flags::new().expect("failed to flags");
|
||||||
let files = flags.files().expect("failed to files");
|
let files = flags.files().expect("failed to files");
|
||||||
assert!(files.files.len() > 0, "no files");
|
|
||||||
|
|
||||||
if !flags.dry_run {
|
if !flags.dry_run {
|
||||||
for file in files.files.iter() {
|
for file in files.files.iter() {
|
||||||
@@ -55,7 +54,7 @@ struct Flags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Flags {
|
impl Flags {
|
||||||
fn new() -> Result<Flags, String> {
|
pub fn new() -> Result<Flags, String> {
|
||||||
let mut result = Flags::parse();
|
let mut result = Flags::parse();
|
||||||
|
|
||||||
if result.path.get(..1) == Some("$") {
|
if result.path.get(..1) == Some("$") {
|
||||||
@@ -70,7 +69,7 @@ impl Flags {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn files(&self) -> Result<Files, String> {
|
pub fn files(&self) -> Result<Files, String> {
|
||||||
let metadata = match std::fs::metadata(self.path.clone()) {
|
let metadata = match std::fs::metadata(self.path.clone()) {
|
||||||
Ok(v) => Ok(v),
|
Ok(v) => Ok(v),
|
||||||
Err(msg) => Err(format!("failed to load {}: {}", self.path.clone(), msg)),
|
Err(msg) => Err(format!("failed to load {}: {}", self.path.clone(), msg)),
|
||||||
@@ -82,23 +81,45 @@ impl Flags {
|
|||||||
.filter(|x| x.is_ok())
|
.filter(|x| x.is_ok())
|
||||||
.map(|x| x.unwrap())
|
.map(|x| x.unwrap())
|
||||||
.filter(|x| x.metadata().unwrap().is_file())
|
.filter(|x| x.metadata().unwrap().is_file())
|
||||||
// TODO filter out hidden files
|
|
||||||
.map(|x| x.path().display().to_string())
|
.map(|x| x.path().display().to_string())
|
||||||
|
.filter(|x| !x.contains("/."))
|
||||||
.collect()),
|
.collect()),
|
||||||
Err(msg) => Err(format!("failed to read {}: {}", self.path.clone(), msg)),
|
Err(msg) => Err(format!("failed to read {}: {}", self.path.clone(), msg)),
|
||||||
},
|
},
|
||||||
}?;
|
}?;
|
||||||
|
assert!(files.len() > 0, "no files");
|
||||||
Ok(Files::new(&files))
|
Ok(Files::new(&files))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_flags {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_flags_files_unhidden_only() {
|
||||||
|
let d = tempdir::TempDir::new("").unwrap();
|
||||||
|
std::fs::File::create(d.path().join("plain")).unwrap();
|
||||||
|
std::fs::File::create(d.path().join(".hidden")).unwrap();
|
||||||
|
|
||||||
|
let flags = Flags {
|
||||||
|
path: d.path().to_str().unwrap().to_string(),
|
||||||
|
add: None,
|
||||||
|
edit: false,
|
||||||
|
dry_run: true,
|
||||||
|
};
|
||||||
|
let files = flags.files().expect("failed to files from dir");
|
||||||
|
assert_eq!(1, files.files.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Files {
|
struct Files {
|
||||||
files: Vec<File>,
|
files: Vec<File>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Files {
|
impl Files {
|
||||||
fn new(files: &Vec<String>) -> Files {
|
pub fn new(files: &Vec<String>) -> Files {
|
||||||
let mut files = files.clone();
|
let mut files = files.clone();
|
||||||
files.sort();
|
files.sort();
|
||||||
Files {
|
Files {
|
||||||
@@ -113,15 +134,15 @@ struct File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
fn new(file: &String) -> File {
|
pub fn new(file: &String) -> File {
|
||||||
File { file: file.clone() }
|
File { file: file.clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn events(&self) -> Result<Events, String> {
|
pub fn events(&self) -> Result<Events, String> {
|
||||||
Events::new(&self.file)
|
Events::new(&self.file)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stage_persisted(&self) -> Result<(), String> {
|
pub fn stage_persisted(&self) -> Result<(), String> {
|
||||||
let stage = self.events()?.snapshot()?;
|
let stage = self.events()?.snapshot()?;
|
||||||
let plaintext = serde_yaml::to_string(&stage).unwrap();
|
let plaintext = serde_yaml::to_string(&stage).unwrap();
|
||||||
let mut f = std::fs::File::create(&self.file).expect("failed to open file for writing");
|
let mut f = std::fs::File::create(&self.file).expect("failed to open file for writing");
|
||||||
@@ -129,7 +150,7 @@ impl File {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn persist_stage(&self) -> Result<(), String> {
|
pub fn persist_stage(&self) -> Result<(), String> {
|
||||||
let persisted = self.events()?.snapshot()?;
|
let persisted = self.events()?.snapshot()?;
|
||||||
let snapshot = serde_json::to_string(&persisted).unwrap();
|
let snapshot = serde_json::to_string(&persisted).unwrap();
|
||||||
let snapshot = snapshot.as_str();
|
let snapshot = snapshot.as_str();
|
||||||
@@ -201,6 +222,20 @@ impl File {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_file {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_file() {
|
||||||
|
let d = tempdir::TempDir::new("").unwrap();
|
||||||
|
let mut f = std::fs::File::create(d.path().join("plain")).unwrap();
|
||||||
|
writeln!(f, "hello world").unwrap();
|
||||||
|
|
||||||
|
assert!(false, "not impl");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
struct Delta {
|
struct Delta {
|
||||||
ts: u64,
|
ts: u64,
|
||||||
@@ -208,14 +243,14 @@ struct Delta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Delta {
|
impl Delta {
|
||||||
fn new(patch: json_patch::PatchOperation, ts: u64) -> Delta {
|
pub fn new(patch: json_patch::PatchOperation, ts: u64) -> Delta {
|
||||||
Delta {
|
Delta {
|
||||||
patch: patch,
|
patch: patch,
|
||||||
ts: ts,
|
ts: ts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn now(patch: json_patch::PatchOperation) -> Delta {
|
pub fn now(patch: json_patch::PatchOperation) -> Delta {
|
||||||
Self::new(
|
Self::new(
|
||||||
patch,
|
patch,
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
@@ -235,7 +270,7 @@ struct Task(serde_yaml::Value);
|
|||||||
struct Events(Vec<Delta>);
|
struct Events(Vec<Delta>);
|
||||||
|
|
||||||
impl Events {
|
impl Events {
|
||||||
fn new(file: &String) -> Result<Events, String> {
|
pub fn new(file: &String) -> Result<Events, String> {
|
||||||
let logs = match std::fs::read_dir(Self::dir(&file)) {
|
let logs = match std::fs::read_dir(Self::dir(&file)) {
|
||||||
Ok(files) => Ok(files
|
Ok(files) => Ok(files
|
||||||
.filter(|x| x.is_ok())
|
.filter(|x| x.is_ok())
|
||||||
@@ -253,12 +288,14 @@ impl Events {
|
|||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
for line in std::io::BufReader::new(f).lines() {
|
for line in std::io::BufReader::new(f).lines() {
|
||||||
let line = line.unwrap();
|
let line = line.unwrap();
|
||||||
|
if line.len() > 0 {
|
||||||
let delta = match serde_json::from_str(&line) {
|
let delta = match serde_json::from_str(&line) {
|
||||||
Ok(v) => Ok(v),
|
Ok(v) => Ok(v),
|
||||||
Err(msg) => Err(format!("failed to parse line {}: {}", &line, msg)),
|
Err(msg) => Err(format!("failed to parse line {}: {}", &line, msg)),
|
||||||
}?;
|
}?;
|
||||||
result.push(delta);
|
result.push(delta);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(msg) => Err(format!("failed to read {}: {}", &log, msg)),
|
Err(msg) => Err(format!("failed to read {}: {}", &log, msg)),
|
||||||
@@ -307,3 +344,32 @@ impl Events {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_events {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_events() {
|
||||||
|
let d = tempdir::TempDir::new("").unwrap();
|
||||||
|
test_file(&d, "plain", "- persisted\n- stage only");
|
||||||
|
test_file(
|
||||||
|
&d,
|
||||||
|
".plain.log",
|
||||||
|
r#"
|
||||||
|
{"ts":1, "patch":{"op":"replace", "path":"", "value":["persisted"]}}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let events = Events::new(&d.path().join("plain").to_str().unwrap().to_string()).unwrap();
|
||||||
|
assert_eq!(1, events.0.len(), "events: {:?}", events);
|
||||||
|
|
||||||
|
assert!(false, "not impl");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_file(d: &tempdir::TempDir, fname: &str, content: &str) {
|
||||||
|
let mut f = std::fs::File::create(d.path().join("plain")).unwrap();
|
||||||
|
writeln!(f, "- persisted\n- stage only").unwrap();
|
||||||
|
f.sync_all().unwrap();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user