🐣 proof of concept for Lookup

main
_ 2021-08-29 19:50:43 +00:00
commit 626583645b
5 changed files with 1378 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

1234
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

14
Cargo.toml Normal file
View File

@ -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"] }

View File

@ -0,0 +1,3 @@
The first build of Lookup to implement the `edit` subcommand
A debug build for x64 Linux.

126
src/main.rs Normal file
View File

@ -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 ()?,
})
}
}