Skip to content

Commit

Permalink
#15: Persisted index and metadata storage (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
kirillt committed Apr 10, 2024
1 parent 68d269f commit 99e8f34
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 76 deletions.
14 changes: 11 additions & 3 deletions ark-cli/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ark-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2021"
name = "ark-cli"

[dependencies]
arklib = { git = "https://github.com/ARK-Builders/arklib", rev = "b743977" }
arklib = { git = "https://github.com/ARK-Builders/arklib", rev = "fea125e" }
clap = { version = "3.0.10", features = ["derive"] }
env_logger = "0.9.0"
walkdir = "2.3.2"
Expand Down
213 changes: 141 additions & 72 deletions ark-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use std::path::{Path, PathBuf};
use std::thread;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};

use arklib::id::ResourceId;
use arklib::index::ResourceIndex;
use arklib::pdf::PDFQuality;
use clap::{Parser, Subcommand};
use home::home_dir;
Expand Down Expand Up @@ -42,6 +44,7 @@ enum Command {
path: Option<PathBuf>,
quality: Option<String>,
},

#[clap(subcommand)]
Link(Link),
}
Expand All @@ -50,14 +53,21 @@ enum Command {
enum Link {
Create {
#[clap(parse(from_os_str))]
path: Option<PathBuf>,
root_dir: Option<PathBuf>,

url: Option<String>,
title: Option<String>,
desc: Option<String>,
url: Option<String>,
},

Load {
#[clap(parse(from_os_str))]
root_dir: Option<PathBuf>,

#[clap(parse(from_os_str))]
file_path: Option<PathBuf>,

id: Option<ResourceId>,
},
}

Expand Down Expand Up @@ -86,51 +96,11 @@ fn main() {
}

println!("Preparing backup:");
let roots = if let Some(path) = roots_cfg {
println!(
"\tRoots config provided explicitly:\n\t\t{}",
path.display()
);
let config = File::open(&path).expect("File doesn't exist!");

parse_roots(config)
} else {
let roots_cfg = home_roots_cfg();

if let Ok(config) = File::open(&roots_cfg) {
println!(
"\tRoots config was found automatically:\n\t\t{}",
roots_cfg.display()
);

parse_roots(config)
} else {
println!("\tRoots config wasn't found.");

println!("Looking for a folder containing tag storage:");
let path = canonicalize(
current_dir().expect("Can't open current directory!"),
)
.expect("Couldn't canonicalize working directory!");

let result = path.ancestors().find(|path| {
println!("\t{}", path.display());
tag_storage_exists(path)
});

if let Some(root) = result {
println!("Root folder found:\n\t{}", root.display());
vec![root.to_path_buf()]
} else {
println!("Root folder wasn't found.");
vec![]
}
}
};
let roots = discover_roots(roots_cfg);

let (valid, invalid): (Vec<PathBuf>, Vec<PathBuf>) = roots
.into_iter()
.partition(|root| tag_storage_exists(&root));
.partition(|root| storages_exists(&root));

if !invalid.is_empty() {
println!("These folders don't contain tag storages:");
Expand Down Expand Up @@ -164,7 +134,7 @@ fn main() {
println!("\tRoot {}", root.display());
let storage_backup = backup_dir.join(&i.to_string());
let result = copy(
root.join(&arklib::TAG_STORAGE_FILENAME),
root.join(&arklib::STORAGES_FOLDER),
storage_backup,
);
if let Err(e) = result {
Expand All @@ -175,11 +145,13 @@ fn main() {
println!("Backup created:\n\t{}", backup_dir.display());
}

Command::Collisions { root_dir } => build_index(&root_dir, None),
Command::Collisions { root_dir } => monitor_index(&root_dir, None),

Command::Monitor { root_dir, interval } => {
let millis = interval.unwrap_or(1000);
build_index(&root_dir, Some(millis))
monitor_index(&root_dir, Some(millis))
}

Command::Render { path, quality } => {
let filepath = path.to_owned().unwrap();
let quality = match quality.to_owned().unwrap().as_str() {
Expand All @@ -201,66 +173,163 @@ fn main() {
let img = arklib::pdf::render_preview_page(buf, quality);
img.save(PathBuf::from(dest_path)).unwrap();
}

Command::Link(link) => match &link {
Link::Create {
root_dir,
url,
title,
desc,
url,
path,
} => {
let _url = Url::parse(url.as_deref().unwrap());
let mut _link: arklib::link::Link = arklib::link::Link::new(
let root = provide_root(root_dir);

let url = Url::parse(url.as_deref().unwrap());
let mut link: arklib::link::Link = arklib::link::Link::new(
url.unwrap(),
title.to_owned().unwrap(),
desc.to_owned().unwrap(),
_url.unwrap(),
desc.to_owned(),
);
let file_path = Path::join(
path.to_owned().unwrap().as_path(),
format!("{}.link", _link.format_name()),

let timestamp = timestamp().as_secs();
let path = Path::join(
&root,
format!("{}.link", &timestamp.to_string()),
);
_link.write_to_path_sync(file_path.clone(), true);
println!(
"Link saved successfully: {:?}",
file_path.clone().display()
)
link.write_to_path_sync(root, path.clone(), true)
.unwrap();
println!("Link saved successfully: {:?}", path.display())
}
Link::Load { file_path } => {
let link = arklib::link::Link::load_json(
file_path.to_owned().unwrap().as_path(),
);
println!("Link data:\n{}", link.unwrap());

Link::Load {
root_dir,
file_path,
id,
} => {
let root = provide_root(root_dir);

let path_from_index = id.map(|id| {
let index = provide_index(&root);
index.id2path[&id].as_path().to_path_buf()
});
let path_from_user = file_path;

let path = match (path_from_user, path_from_index) {
(Some(path), Some(path2)) => {
if path.canonicalize().unwrap() != path2 {
println!("Path {:?} was requested.", path);
println!(
"But id {} maps to path {:?}",
id.unwrap(),
path2
);
panic!()
} else {
path.to_path_buf()
}
}
(Some(path), None) => path.to_path_buf(),
(None, Some(path)) => path,
(None, None) => {
println!("Provide a path or id for request.");
panic!()
}
};

let link = arklib::link::Link::load(root, path);
println!("Link data:\n{:?}", link.unwrap());
}
},
}
}

fn build_index(root_dir: &Option<PathBuf>, interval: Option<u64>) {
let dir_path = if let Some(path) = root_dir {
fn discover_roots(roots_cfg: &Option<PathBuf>) -> Vec<PathBuf> {
if let Some(path) = roots_cfg {
println!(
"\tRoots config provided explicitly:\n\t\t{}",
path.display()
);
let config = File::open(&path).expect("File doesn't exist!");

parse_roots(config)
} else {
let roots_cfg = home_roots_cfg();

if let Ok(config) = File::open(&roots_cfg) {
println!(
"\tRoots config was found automatically:\n\t\t{}",
roots_cfg.display()
);

parse_roots(config)
} else {
println!("\tRoots config wasn't found.");

println!("Looking for a folder containing tag storage:");
let path = canonicalize(
current_dir().expect("Can't open current directory!"),
)
.expect("Couldn't canonicalize working directory!");

let result = path.ancestors().find(|path| {
println!("\t{}", path.display());
storages_exists(path)
});

if let Some(root) = result {
println!("Root folder found:\n\t{}", root.display());
vec![root.to_path_buf()]
} else {
println!("Root folder wasn't found.");
vec![]
}
}
}
}

fn provide_root(root_dir: &Option<PathBuf>) -> PathBuf {
if let Some(path) = root_dir {
path.clone()
} else {
current_dir()
.expect("Can't open current directory!")
.clone()
};
}
}

// Read-only structure
fn provide_index(root_dir: &PathBuf) -> ResourceIndex {
let rwlock =
arklib::provide_index(root_dir).expect("Failed to retrieve index");
let index = &*rwlock.read().unwrap();
index.clone()
}

fn monitor_index(root_dir: &Option<PathBuf>, interval: Option<u64>) {
let dir_path = provide_root(root_dir);

println!("Building index of folder {}", dir_path.display());
let start = Instant::now();
let dir_path = provide_root(root_dir);
let result = arklib::provide_index(dir_path);
let duration = start.elapsed();

match result {
Ok(rwlock) => {
println!("Success, took {:?}\n", duration);
println!("Build succeeded in {:?}\n", duration);

if let Some(millis) = interval {
let mut index = rwlock.write().unwrap();
loop {
let pause = Duration::from_millis(millis);
thread::sleep(pause);

let start = Instant::now();
match index.update() {
Err(msg) => println!("Oops! {}", msg),
Ok(diff) => {
let duration = start.elapsed();
println!("Updating succeeded in {:?}\n", duration);

if !diff.deleted.is_empty() {
println!("Deleted: {:?}", diff.deleted);
}
Expand Down Expand Up @@ -291,8 +360,8 @@ fn home_roots_cfg() -> PathBuf {
.join(&ROOTS_CFG_FILENAME);
}

fn tag_storage_exists(path: &Path) -> bool {
return File::open(path.join(&arklib::TAG_STORAGE_FILENAME)).is_ok();
fn storages_exists(path: &Path) -> bool {
return File::open(path.join(&arklib::STORAGES_FOLDER)).is_ok();
}

fn parse_roots(config: File) -> Vec<PathBuf> {
Expand Down

0 comments on commit 99e8f34

Please sign in to comment.