mirror of
https://github.com/PR0M3TH3AN/Marlin.git
synced 2025-09-08 07:08:44 +00:00
updated CLI
This commit is contained in:
51
README.md
51
README.md
@@ -145,26 +145,26 @@ Paste & run each block in your terminal.
|
||||
|
||||
---
|
||||
|
||||
### 0 Prepare & build
|
||||
### 0 Prepare, build & install
|
||||
|
||||
```bash
|
||||
# Clone or cd into your Marlin repo
|
||||
cd ~/Documents/GitHub/Marlin
|
||||
|
||||
# Build the release binary
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
sudo install -Dm755 target/release/marlin /usr/local/bin/marlin
|
||||
````
|
||||
|
||||
> Now `marlin` is available everywhere.
|
||||
|
||||
---
|
||||
|
||||
### 1 Install on your PATH
|
||||
### 1 Enable shell completion (optional but handy)
|
||||
|
||||
```bash
|
||||
sudo install -Dm755 target/release/marlin /usr/local/bin/marlin
|
||||
marlin completions bash > ~/.config/bash_completion.d/marlin
|
||||
# or for zsh / fish, similarly...
|
||||
```
|
||||
|
||||
> Now `marlin` is available everywhere.
|
||||
|
||||
---
|
||||
|
||||
### 2 Prepare a clean demo directory
|
||||
@@ -184,16 +184,14 @@ printf "fake jpg\n" > ~/marlin_demo/Media/Photos/vacation.jpg
|
||||
### 3 Initialize & index files
|
||||
|
||||
```bash
|
||||
# Use --verbose if you want full debug traces:
|
||||
marlin init
|
||||
marlin scan ~/marlin_demo
|
||||
|
||||
# or, to see every path tested:
|
||||
marlin --verbose init
|
||||
# show every path tested:
|
||||
marlin --verbose scan ~/marlin_demo
|
||||
```
|
||||
|
||||
> **Tip:** Rerun `marlin scan` after you add/remove/modify files; only changed files get re-indexed.
|
||||
> Only changed files get re-indexed on subsequent runs.
|
||||
|
||||
---
|
||||
|
||||
@@ -204,11 +202,10 @@ marlin --verbose scan ~/marlin_demo
|
||||
marlin tag "~/marlin_demo/Projects/Alpha/**/*" project/alpha
|
||||
|
||||
# Mark all PDFs as reviewed
|
||||
marlin attr set "~/marlin_demo/**/*.pdf" reviewed yes
|
||||
marlin attr set "~/marlin_demo/**/*.pdf" reviewed=yes
|
||||
|
||||
# (or with debug)
|
||||
marlin --verbose tag "~/marlin_demo/Projects/Alpha/**/*" project/alpha
|
||||
marlin --verbose attr set "~/marlin_demo/**/*.pdf" reviewed yes
|
||||
# Output as JSON instead:
|
||||
marlin --format=json attr set "~/marlin_demo/**/*.pdf" reviewed=yes
|
||||
```
|
||||
|
||||
---
|
||||
@@ -219,38 +216,34 @@ marlin --verbose attr set "~/marlin_demo/**/*.pdf" reviewed yes
|
||||
# By tag or filename
|
||||
marlin search alpha
|
||||
|
||||
# Combined terms (AND across path+attrs)
|
||||
# Combined terms:
|
||||
marlin search "reviewed AND pdf"
|
||||
|
||||
# Run a command on each hit
|
||||
marlin search reviewed --exec "echo HIT → {}"
|
||||
|
||||
# If things aren’t matching, add --verbose to see the underlying FTS query:
|
||||
marlin --verbose search "reviewed AND pdf"
|
||||
# Run a command on each hit:
|
||||
marlin search reviewed --exec 'echo HIT → {}'
|
||||
```
|
||||
|
||||
> `{}` in `--exec` is replaced with each file’s path.
|
||||
|
||||
---
|
||||
|
||||
### 6 Backup & restore
|
||||
|
||||
```bash
|
||||
# Snapshot and store its name
|
||||
# Snapshot
|
||||
snap=$(marlin backup | awk '{print $NF}')
|
||||
|
||||
# Simulate data loss
|
||||
# Simulate loss
|
||||
rm ~/.local/share/marlin/index.db
|
||||
|
||||
# Restore instantly
|
||||
# Restore
|
||||
marlin restore "$snap"
|
||||
|
||||
# Verify your files still show up
|
||||
# Verify
|
||||
marlin search reviewed
|
||||
```
|
||||
|
||||
> Backups live under `~/.local/share/marlin/backups` by default.
|
||||
|
||||
|
||||
##### What you just exercised
|
||||
|
||||
| Command | Purpose |
|
||||
|
81
src/cli.rs
81
src/cli.rs
@@ -1,15 +1,36 @@
|
||||
// src/cli.rs
|
||||
use std::path::PathBuf;
|
||||
use clap::{Parser, Subcommand};
|
||||
pub mod link;
|
||||
pub mod coll;
|
||||
pub mod view;
|
||||
pub mod state;
|
||||
pub mod task;
|
||||
pub mod remind;
|
||||
pub mod annotate;
|
||||
pub mod version;
|
||||
pub mod event;
|
||||
|
||||
use clap::{Parser, Subcommand, ArgEnum, Args, CommandFactory};
|
||||
use clap_complete::Shell;
|
||||
|
||||
/// Output format for commands.
|
||||
#[derive(ArgEnum, Clone, Copy, Debug)]
|
||||
pub enum Format {
|
||||
Text,
|
||||
Json,
|
||||
}
|
||||
|
||||
/// Marlin – metadata-driven file explorer (CLI utilities)
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about)]
|
||||
#[command(author, version, about, propagate_version = true)]
|
||||
pub struct Cli {
|
||||
/// Enable debug logging and extra output
|
||||
#[arg(long)]
|
||||
pub verbose: bool,
|
||||
|
||||
/// Output format (text or JSON)
|
||||
#[arg(long, default_value = "text", value_enum, global = true)]
|
||||
pub format: Format,
|
||||
|
||||
#[command(subcommand)]
|
||||
pub command: Commands,
|
||||
}
|
||||
@@ -21,12 +42,15 @@ pub enum Commands {
|
||||
|
||||
/// Scan one or more directories and populate the file index
|
||||
Scan {
|
||||
paths: Vec<PathBuf>,
|
||||
/// Directories to scan (defaults to cwd)
|
||||
paths: Vec<std::path::PathBuf>,
|
||||
},
|
||||
|
||||
/// Tag files matching a glob pattern (hierarchical tags use `/`)
|
||||
Tag {
|
||||
/// Glob or path pattern
|
||||
pattern: String,
|
||||
/// Hierarchical tag name (`foo/bar`)
|
||||
tag_path: String,
|
||||
},
|
||||
|
||||
@@ -46,14 +70,57 @@ pub enum Commands {
|
||||
/// Create a timestamped backup of the database
|
||||
Backup,
|
||||
|
||||
/// Restore from a backup file (over-writes current DB)
|
||||
/// Restore from a backup file (overwrites current DB)
|
||||
Restore {
|
||||
backup_path: PathBuf,
|
||||
backup_path: std::path::PathBuf,
|
||||
},
|
||||
|
||||
/// Generate shell completions (hidden)
|
||||
#[command(hide = true)]
|
||||
Completions {
|
||||
#[arg(value_enum)]
|
||||
shell: Shell,
|
||||
},
|
||||
|
||||
/// File-to-file links
|
||||
#[command(subcommand)]
|
||||
Link { cmd: link::LinkCmd },
|
||||
|
||||
/// Collections (groups) of files
|
||||
#[command(subcommand)]
|
||||
Coll { cmd: coll::CollCmd },
|
||||
|
||||
/// Smart views (saved queries)
|
||||
#[command(subcommand)]
|
||||
View { cmd: view::ViewCmd },
|
||||
|
||||
/// Workflow states on files
|
||||
#[command(subcommand)]
|
||||
State { cmd: state::StateCmd },
|
||||
|
||||
/// TODO/tasks management
|
||||
#[command(subcommand)]
|
||||
Task { cmd: task::TaskCmd },
|
||||
|
||||
/// Reminders on files
|
||||
#[command(subcommand)]
|
||||
Remind { cmd: remind::RemindCmd },
|
||||
|
||||
/// File annotations and highlights
|
||||
#[command(subcommand)]
|
||||
Annotate { cmd: annotate::AnnotateCmd },
|
||||
|
||||
/// Version diffs
|
||||
#[command(subcommand)]
|
||||
Version { cmd: version::VersionCmd },
|
||||
|
||||
/// Calendar events & timelines
|
||||
#[command(subcommand)]
|
||||
Event { cmd: event::EventCmd },
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum AttrCmd {
|
||||
Set { pattern: String, key: String, value: String },
|
||||
Ls { path: PathBuf },
|
||||
Ls { path: std::path::PathBuf },
|
||||
}
|
||||
|
28
src/cli/annotate.rs
Normal file
28
src/cli/annotate.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
// src/cli/annotate.rs
|
||||
use clap::{Subcommand, Args};
|
||||
use rusqlite::Connection;
|
||||
use crate::cli::Format;
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum AnnotateCmd {
|
||||
Add (ArgsAdd),
|
||||
List(ArgsList),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsAdd {
|
||||
pub file: String,
|
||||
pub note: String,
|
||||
#[arg(long)] pub range: Option<String>,
|
||||
#[arg(long)] pub highlight: bool,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsList { pub file_pattern: String }
|
||||
|
||||
pub fn run(cmd: &AnnotateCmd, conn: &mut Connection, format: Format) -> anyhow::Result<()> {
|
||||
match cmd {
|
||||
AnnotateCmd::Add(a) => todo!("annotate add {:?}", a),
|
||||
AnnotateCmd::List(a) => todo!("annotate list {:?}", a),
|
||||
}
|
||||
}
|
26
src/cli/coll.rs
Normal file
26
src/cli/coll.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
// src/cli/coll.rs
|
||||
use clap::{Subcommand, Args};
|
||||
use rusqlite::Connection;
|
||||
use crate::cli::Format;
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum CollCmd {
|
||||
Create(CreateArgs),
|
||||
Add (AddArgs),
|
||||
List (ListArgs),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct CreateArgs { pub name: String }
|
||||
#[derive(Args, Debug)]
|
||||
pub struct AddArgs { pub name: String, pub file_pattern: String }
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ListArgs { pub name: String }
|
||||
|
||||
pub fn run(cmd: &CollCmd, conn: &mut Connection, format: Format) -> anyhow::Result<()> {
|
||||
match cmd {
|
||||
CollCmd::Create(a) => todo!("coll create {:?}", a),
|
||||
CollCmd::Add(a) => todo!("coll add {:?}", a),
|
||||
CollCmd::List(a) => todo!("coll list {:?}", a),
|
||||
}
|
||||
}
|
81
src/cli/commands.yaml
Normal file
81
src/cli/commands.yaml
Normal file
@@ -0,0 +1,81 @@
|
||||
# cli/commands.yaml
|
||||
# Philosophy: one canonical spec stops drift between docs & code.
|
||||
link:
|
||||
description: "Manage typed relationships between files"
|
||||
actions:
|
||||
add:
|
||||
args: [from, to]
|
||||
flags: ["--type"]
|
||||
rm:
|
||||
args: [from, to]
|
||||
flags: ["--type"]
|
||||
list:
|
||||
args: [pattern]
|
||||
flags: ["--direction", "--type"]
|
||||
backlinks:
|
||||
args: [pattern]
|
||||
|
||||
coll:
|
||||
description: "Manage named collections of files"
|
||||
actions:
|
||||
create:
|
||||
args: [name]
|
||||
add:
|
||||
args: [name, file_pattern]
|
||||
list:
|
||||
args: [name]
|
||||
|
||||
view:
|
||||
description: "Save and use smart views (saved queries)"
|
||||
actions:
|
||||
save:
|
||||
args: [view_name, query]
|
||||
list: {}
|
||||
exec:
|
||||
args: [view_name]
|
||||
|
||||
state:
|
||||
description: "Track workflow states on files"
|
||||
actions:
|
||||
set:
|
||||
args: [file_pattern, new_state]
|
||||
transitions-add:
|
||||
args: [from_state, to_state]
|
||||
log:
|
||||
args: [file_pattern]
|
||||
|
||||
task:
|
||||
description: "Extract TODOs and manage tasks"
|
||||
actions:
|
||||
scan:
|
||||
args: [directory]
|
||||
list:
|
||||
flags: ["--due-today"]
|
||||
|
||||
remind:
|
||||
description: "Attach reminders to files"
|
||||
actions:
|
||||
set:
|
||||
args: [file_pattern, timestamp, message]
|
||||
|
||||
annotate:
|
||||
description: "Add notes or highlights to files"
|
||||
actions:
|
||||
add:
|
||||
args: [file, note]
|
||||
flags: ["--range", "--highlight"]
|
||||
list:
|
||||
args: [file_pattern]
|
||||
|
||||
version:
|
||||
description: "Versioning and diffs"
|
||||
actions:
|
||||
diff:
|
||||
args: [file]
|
||||
|
||||
event:
|
||||
description: "Link files to dates/events"
|
||||
actions:
|
||||
add:
|
||||
args: [file, date, description]
|
||||
timeline: {}
|
24
src/cli/event.rs
Normal file
24
src/cli/event.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
// src/cli/event.rs
|
||||
use clap::{Subcommand, Args};
|
||||
use rusqlite::Connection;
|
||||
use crate::cli::Format;
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum EventCmd {
|
||||
Add (ArgsAdd),
|
||||
Timeline,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsAdd {
|
||||
pub file: String,
|
||||
pub date: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
pub fn run(cmd: &EventCmd, conn: &mut Connection, format: Format) -> anyhow::Result<()> {
|
||||
match cmd {
|
||||
EventCmd::Add(a) => todo!("event add {:?}", a),
|
||||
EventCmd::Timeline => todo!("event timeline"),
|
||||
}
|
||||
}
|
43
src/cli/link.rs
Normal file
43
src/cli/link.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
// src/cli/link.rs
|
||||
use clap::{Subcommand, Args};
|
||||
use rusqlite::Connection;
|
||||
use crate::cli::Format;
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum LinkCmd {
|
||||
Add(LinkArgs),
|
||||
Rm (LinkArgs),
|
||||
List(ListArgs),
|
||||
Backlinks(BacklinksArgs),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct LinkArgs {
|
||||
pub from: String,
|
||||
pub to: String,
|
||||
#[arg(long)]
|
||||
pub r#type: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ListArgs {
|
||||
pub pattern: String,
|
||||
#[arg(long)]
|
||||
pub direction: Option<String>,
|
||||
#[arg(long)]
|
||||
pub r#type: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct BacklinksArgs {
|
||||
pub pattern: String,
|
||||
}
|
||||
|
||||
pub fn run(cmd: &LinkCmd, conn: &mut Connection, format: Format) -> anyhow::Result<()> {
|
||||
match cmd {
|
||||
LinkCmd::Add(args) => todo!("link add {:?}", args),
|
||||
LinkCmd::Rm(args) => todo!("link rm {:?}", args),
|
||||
LinkCmd::List(args) => todo!("link list {:?}", args),
|
||||
LinkCmd::Backlinks(args) => todo!("link backlinks {:?}", args),
|
||||
}
|
||||
}
|
22
src/cli/remind.rs
Normal file
22
src/cli/remind.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
// src/cli/remind.rs
|
||||
use clap::{Subcommand, Args};
|
||||
use rusqlite::Connection;
|
||||
use crate::cli::Format;
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum RemindCmd {
|
||||
Set(ArgsSet),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsSet {
|
||||
pub file_pattern: String,
|
||||
pub timestamp: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
pub fn run(cmd: &RemindCmd, conn: &mut Connection, format: Format) -> anyhow::Result<()> {
|
||||
match cmd {
|
||||
RemindCmd::Set(a) => todo!("remind set {:?}", a),
|
||||
}
|
||||
}
|
26
src/cli/state.rs
Normal file
26
src/cli/state.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
// src/cli/state.rs
|
||||
use clap::{Subcommand, Args};
|
||||
use rusqlite::Connection;
|
||||
use crate::cli::Format;
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum StateCmd {
|
||||
Set(ArgsSet),
|
||||
TransitionsAdd(ArgsTrans),
|
||||
Log(ArgsLog),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsSet { pub file_pattern: String, pub new_state: String }
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsTrans { pub from_state: String, pub to_state: String }
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsLog { pub file_pattern: String }
|
||||
|
||||
pub fn run(cmd: &StateCmd, conn: &mut Connection, format: Format) -> anyhow::Result<()> {
|
||||
match cmd {
|
||||
StateCmd::Set(a) => todo!("state set {:?}", a),
|
||||
StateCmd::TransitionsAdd(a)=> todo!("state transitions-add {:?}", a),
|
||||
StateCmd::Log(a) => todo!("state log {:?}", a),
|
||||
}
|
||||
}
|
22
src/cli/task.rs
Normal file
22
src/cli/task.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
// src/cli/task.rs
|
||||
use clap::{Subcommand, Args};
|
||||
use rusqlite::Connection;
|
||||
use crate::cli::Format;
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum TaskCmd {
|
||||
Scan(ArgsScan),
|
||||
List(ArgsList),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsScan { pub directory: String }
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsList { #[arg(long)] pub due_today: bool }
|
||||
|
||||
pub fn run(cmd: &TaskCmd, conn: &mut Connection, format: Format) -> anyhow::Result<()> {
|
||||
match cmd {
|
||||
TaskCmd::Scan(a) => todo!("task scan {:?}", a),
|
||||
TaskCmd::List(a) => todo!("task list {:?}", a),
|
||||
}
|
||||
}
|
18
src/cli/version.rs
Normal file
18
src/cli/version.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
// src/cli/version.rs
|
||||
use clap::{Subcommand, Args};
|
||||
use rusqlite::Connection;
|
||||
use crate::cli::Format;
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum VersionCmd {
|
||||
Diff(ArgsDiff),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsDiff { pub file: String }
|
||||
|
||||
pub fn run(cmd: &VersionCmd, conn: &mut Connection, format: Format) -> anyhow::Result<()> {
|
||||
match cmd {
|
||||
VersionCmd::Diff(a) => todo!("version diff {:?}", a),
|
||||
}
|
||||
}
|
24
src/cli/view.rs
Normal file
24
src/cli/view.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
// src/cli/view.rs
|
||||
use clap::{Subcommand, Args};
|
||||
use rusqlite::Connection;
|
||||
use crate::cli::Format;
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum ViewCmd {
|
||||
Save(ArgsSave),
|
||||
List,
|
||||
Exec(ArgsExec),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsSave { pub view_name: String, pub query: String }
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ArgsExec { pub view_name: String }
|
||||
|
||||
pub fn run(cmd: &ViewCmd, conn: &mut Connection, format: Format) -> anyhow::Result<()> {
|
||||
match cmd {
|
||||
ViewCmd::Save(a) => todo!("view save {:?}", a),
|
||||
ViewCmd::List => todo!("view list"),
|
||||
ViewCmd::Exec(a)=> todo!("view exec {:?}", a),
|
||||
}
|
||||
}
|
54
src/main.rs
54
src/main.rs
@@ -6,48 +6,55 @@ mod logging;
|
||||
mod scan;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use clap::Parser;
|
||||
use clap::{Parser, Subcommand};
|
||||
use clap_complete::{generate, Shell};
|
||||
use glob::Pattern;
|
||||
use rusqlite::params;
|
||||
use shellexpand;
|
||||
use shlex;
|
||||
use std::{env, path::PathBuf, process::Command};
|
||||
use std::{env, io, path::PathBuf, process::Command};
|
||||
use tracing::{debug, error, info};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use cli::{AttrCmd, Cli, Commands};
|
||||
use cli::{Cli, Commands, Format};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// Parse CLI and bootstrap logging
|
||||
let args = Cli::parse();
|
||||
let mut args = Cli::parse();
|
||||
if args.verbose {
|
||||
// switch on debug‐level logs
|
||||
env::set_var("RUST_LOG", "debug");
|
||||
}
|
||||
logging::init();
|
||||
|
||||
// Handle shell completions as a hidden command
|
||||
if let Commands::Completions { shell } = args.command {
|
||||
let mut cmd = Cli::command();
|
||||
generate(shell, &mut cmd, "marlin", &mut io::stdout());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let cfg = config::Config::load()?;
|
||||
|
||||
// Backup before any non-init, non-backup/restore command
|
||||
if !matches!(args.command, Commands::Init | Commands::Backup | Commands::Restore { .. }) {
|
||||
match db::backup(&cfg.db_path) {
|
||||
match &args.command {
|
||||
Commands::Init | Commands::Backup | Commands::Restore { .. } => {}
|
||||
_ => match db::backup(&cfg.db_path) {
|
||||
Ok(path) => info!("Pre-command auto-backup created at {}", path.display()),
|
||||
Err(e) => error!("Failed to create pre-command auto-backup: {}", e),
|
||||
}
|
||||
Err(e) => error!("Failed to create pre-command auto-backup: {}", e),
|
||||
},
|
||||
}
|
||||
|
||||
// Open (and migrate) the DB
|
||||
let mut conn = db::open(&cfg.db_path)?;
|
||||
|
||||
// Dispatch
|
||||
match args.command {
|
||||
Commands::Init => {
|
||||
info!("Database initialised at {}", cfg.db_path.display());
|
||||
}
|
||||
|
||||
Commands::Scan { paths } => {
|
||||
// if none given, default to current dir
|
||||
let scan_paths = if paths.is_empty() {
|
||||
vec![env::current_dir()?]
|
||||
vec![std::env::current_dir()?]
|
||||
} else {
|
||||
paths
|
||||
};
|
||||
@@ -55,38 +62,43 @@ fn main() -> Result<()> {
|
||||
scan::scan_directory(&mut conn, &p)?;
|
||||
}
|
||||
}
|
||||
|
||||
Commands::Tag { pattern, tag_path } => {
|
||||
apply_tag(&conn, &pattern, &tag_path)?;
|
||||
}
|
||||
|
||||
Commands::Attr { action } => match action {
|
||||
AttrCmd::Set { pattern, key, value } => {
|
||||
cli::AttrCmd::Set { pattern, key, value } => {
|
||||
attr_set(&conn, &pattern, &key, &value)?;
|
||||
}
|
||||
AttrCmd::Ls { path } => {
|
||||
cli::AttrCmd::Ls { path } => {
|
||||
attr_ls(&conn, &path)?;
|
||||
}
|
||||
},
|
||||
|
||||
Commands::Search { query, exec } => {
|
||||
run_search(&conn, &query, exec)?;
|
||||
}
|
||||
|
||||
Commands::Backup => {
|
||||
let path = db::backup(&cfg.db_path)?;
|
||||
println!("Backup created: {}", path.display());
|
||||
}
|
||||
|
||||
Commands::Restore { backup_path } => {
|
||||
drop(conn);
|
||||
db::restore(&backup_path, &cfg.db_path)
|
||||
.with_context(|| format!("Failed to restore DB from {}", backup_path.display()))?;
|
||||
println!("Restored DB file from {}", backup_path.display());
|
||||
println!("Restored DB from {}", backup_path.display());
|
||||
db::open(&cfg.db_path)
|
||||
.with_context(|| format!("Could not open restored DB at {}", cfg.db_path.display()))?;
|
||||
info!("Successfully opened and processed restored database.");
|
||||
info!("Successfully opened restored database.");
|
||||
}
|
||||
// new domains delegate to their run() functions
|
||||
Commands::Link { cmd } => cli::link::run(&cmd, &mut conn, args.format)?,
|
||||
Commands::Coll { cmd } => cli::coll::run(&cmd, &mut conn, args.format)?,
|
||||
Commands::View { cmd } => cli::view::run(&cmd, &mut conn, args.format)?,
|
||||
Commands::State { cmd } => cli::state::run(&cmd, &mut conn, args.format)?,
|
||||
Commands::Task { cmd } => cli::task::run(&cmd, &mut conn, args.format)?,
|
||||
Commands::Remind { cmd } => cli::remind::run(&cmd, &mut conn, args.format)?,
|
||||
Commands::Annotate { cmd } => cli::annotate::run(&cmd, &mut conn, args.format)?,
|
||||
Commands::Version { cmd } => cli::version::run(&cmd, &mut conn, args.format)?,
|
||||
Commands::Event { cmd } => cli::event::run(&cmd, &mut conn, args.format)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
Reference in New Issue
Block a user