🐣 proof of concept for Lookup
commit
626583645b
|
@ -0,0 +1 @@
|
|||
/target
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
|
||||
name = "lookup"
|
||||
version = "0.1.0"
|
||||
authors = ["_"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
|
||||
anyhow = "1.0.43"
|
||||
blake3 = "1.0.0"
|
||||
clap = "2.33.3"
|
||||
reqwest = "0.11.4"
|
||||
tokio = { version = "1.10.1", features = ["full"] }
|
|
@ -0,0 +1,3 @@
|
|||
The first build of Lookup to implement the `edit` subcommand
|
||||
|
||||
A debug build for x64 Linux.
|
|
@ -0,0 +1,126 @@
|
|||
use std::{
|
||||
env,
|
||||
fs,
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
process,
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
use anyhow::{
|
||||
Context,
|
||||
bail,
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main () -> anyhow::Result <()> {
|
||||
use clap::{Arg, App, SubCommand};
|
||||
|
||||
let matches = App::new ("ReactorScram/Lookup")
|
||||
.author ("ReactorScram (Trisha)")
|
||||
.about ("Looks up information about a file, based on its hash")
|
||||
.subcommand (SubCommand::with_name ("edit")
|
||||
.about ("Opens the Lookup file with $EDITOR")
|
||||
.arg (
|
||||
Arg::with_name ("INPUT")
|
||||
.help ("Sets the input file to use")
|
||||
.required (true)
|
||||
)
|
||||
)
|
||||
.arg (
|
||||
Arg::with_name ("INPUT")
|
||||
.help ("Sets the input file to use")
|
||||
)
|
||||
.get_matches ();
|
||||
|
||||
if let Some (matches) = matches.subcommand_matches ("edit") {
|
||||
let input_path = Path::new (matches.value_of ("INPUT").unwrap ());
|
||||
|
||||
let b3_hash = hash (input_path)?;
|
||||
|
||||
let local_path = PathBuf::from ("lookup_repo").join (repo_path (&b3_hash));
|
||||
let local_dir = local_path.parent ().unwrap ();
|
||||
|
||||
let editor = env::var ("EDITOR").unwrap_or_else (|_| String::from ("nano"));
|
||||
|
||||
fs::create_dir_all (local_dir)?;
|
||||
process::Command::new ("kate")
|
||||
.arg ("-b")
|
||||
.arg (local_path)
|
||||
.status ().context ("while spawning editor")?;
|
||||
return Ok (());
|
||||
}
|
||||
|
||||
let input_path = Path::new (matches.value_of ("INPUT").unwrap ());
|
||||
|
||||
let b3_hash = hash (input_path)?;
|
||||
|
||||
let local_path = PathBuf::from ("lookup_repo").join (repo_path (&b3_hash));
|
||||
|
||||
println! ("Local path: {:?}", local_path);
|
||||
|
||||
Ok (())
|
||||
}
|
||||
|
||||
fn hash (input_path: &Path) -> anyhow::Result <blake3::Hash>
|
||||
{
|
||||
let mut hasher = blake3::Hasher::new ();
|
||||
|
||||
{
|
||||
let mod_guard = FileModificationGuard::try_new (input_path)?;
|
||||
let mut input_file = fs::File::open (input_path)?;
|
||||
|
||||
io::copy (&mut input_file, &mut hasher)?;
|
||||
|
||||
mod_guard.check ().context ("while hashing input file")?;
|
||||
}
|
||||
|
||||
Ok (hasher.finalize ())
|
||||
}
|
||||
|
||||
fn repo_path (b3_hash: &blake3::Hash) -> PathBuf {
|
||||
let b3_hex = b3_hash.to_hex ();
|
||||
|
||||
PathBuf::from ("blake3")
|
||||
.join (&b3_hex [0..2])
|
||||
.join (&b3_hex [2..])
|
||||
}
|
||||
|
||||
struct FileModificationGuard <'a> {
|
||||
path: &'a Path,
|
||||
metadata_start: CommonFileMetadata,
|
||||
}
|
||||
|
||||
#[derive (PartialEq)]
|
||||
struct CommonFileMetadata {
|
||||
len: u64,
|
||||
modified: SystemTime
|
||||
}
|
||||
|
||||
impl <'a> FileModificationGuard <'a> {
|
||||
fn try_new (path: &'a Path) -> anyhow::Result <Self> {
|
||||
Ok (Self {
|
||||
path,
|
||||
metadata_start: CommonFileMetadata::try_new (path)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn check (&self) -> anyhow::Result <()> {
|
||||
let md = CommonFileMetadata::try_new (self.path)?;
|
||||
if md != self.metadata_start {
|
||||
bail! ("File metadata changed");
|
||||
}
|
||||
|
||||
Ok (())
|
||||
}
|
||||
}
|
||||
|
||||
impl CommonFileMetadata {
|
||||
fn try_new (path: &Path) -> anyhow::Result <Self> {
|
||||
let md = fs::metadata (path)?;
|
||||
Ok (Self {
|
||||
len: md.len (),
|
||||
modified: md.modified ()?,
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue