feat(export): 添加导出数据库功能支持json和csv格式
新增export子命令,支持将数据库中的目录条目导出为json或csv格式。添加了相关依赖库serde_json和csv,并更新了所有shell的自动补全脚本。
This commit is contained in:
parent
d52c6336b8
commit
a128974954
|
|
@ -260,6 +260,27 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938"
|
||||
dependencies = [
|
||||
"csv-core",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "difflib"
|
||||
version = "0.4.0"
|
||||
|
|
@ -712,18 +733,28 @@ checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -994,6 +1025,7 @@ dependencies = [
|
|||
"clap_complete_fig",
|
||||
"clap_complete_nushell",
|
||||
"color-print",
|
||||
"csv",
|
||||
"dirs",
|
||||
"dunce",
|
||||
"fastrand",
|
||||
|
|
@ -1003,6 +1035,7 @@ dependencies = [
|
|||
"rstest",
|
||||
"rstest_reuse",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"which",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@ dirs = "6.0.0"
|
|||
dunce = "1.0.1"
|
||||
fastrand = "2.0.0"
|
||||
glob = "0.3.0"
|
||||
csv = "1.2.0"
|
||||
ouroboros = "0.18.3"
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
serde_json = "1.0.96"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix = { version = "0.30.1", default-features = false, features = [
|
||||
|
|
|
|||
|
|
@ -94,6 +94,18 @@ _arguments "${_arguments_options[@]}" : \
|
|||
;;
|
||||
esac
|
||||
;;
|
||||
(export)
|
||||
_arguments "${_arguments_options[@]}" : \
|
||||
'-f+[Output format (json or csv)]:FORMAT:(json csv)' \
|
||||
'--format=[Output format (json or csv)]:FORMAT:(json csv)' \
|
||||
'-o+[Output file path (default\: stdout)]:OUT:_files' \
|
||||
'--out=[Output file path (default\: stdout)]:OUT:_files' \
|
||||
'-h[Print help]' \
|
||||
'--help[Print help]' \
|
||||
'-V[Print version]' \
|
||||
'--version[Print version]' \
|
||||
&& ret=0
|
||||
;;
|
||||
(import)
|
||||
_arguments "${_arguments_options[@]}" : \
|
||||
'--from=[Application to import from]:FROM:(autojump z)' \
|
||||
|
|
@ -155,6 +167,7 @@ _zoxide_commands() {
|
|||
local commands; commands=(
|
||||
'add:Add a new directory or increment its rank' \
|
||||
'edit:Edit the database' \
|
||||
'export:Export entries from the database' \
|
||||
'import:Import entries from another application' \
|
||||
'init:Generate shell configuration' \
|
||||
'query:Search for a directory in the database' \
|
||||
|
|
@ -197,6 +210,11 @@ _zoxide__edit__reload_commands() {
|
|||
local commands; commands=()
|
||||
_describe -t commands 'zoxide edit reload commands' commands "$@"
|
||||
}
|
||||
(( $+functions[_zoxide__export_commands] )) ||
|
||||
_zoxide__export_commands() {
|
||||
local commands; commands=()
|
||||
_describe -t commands 'zoxide export commands' commands "$@"
|
||||
}
|
||||
(( $+functions[_zoxide__import_commands] )) ||
|
||||
_zoxide__import_commands() {
|
||||
local commands; commands=()
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
|
|||
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
|
||||
[CompletionResult]::new('add', 'add', [CompletionResultType]::ParameterValue, 'Add a new directory or increment its rank')
|
||||
[CompletionResult]::new('edit', 'edit', [CompletionResultType]::ParameterValue, 'Edit the database')
|
||||
[CompletionResult]::new('export', 'export', [CompletionResultType]::ParameterValue, 'Export entries from the database')
|
||||
[CompletionResult]::new('import', 'import', [CompletionResultType]::ParameterValue, 'Import entries from another application')
|
||||
[CompletionResult]::new('init', 'init', [CompletionResultType]::ParameterValue, 'Generate shell configuration')
|
||||
[CompletionResult]::new('query', 'query', [CompletionResultType]::ParameterValue, 'Search for a directory in the database')
|
||||
|
|
@ -81,6 +82,17 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
|
|||
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
|
||||
break
|
||||
}
|
||||
'zoxide;export' {
|
||||
[CompletionResult]::new('-f', '-f', [CompletionResultType]::ParameterName, 'Output format (json or csv)')
|
||||
[CompletionResult]::new('--format', '--format', [CompletionResultType]::ParameterName, 'Output format (json or csv)')
|
||||
[CompletionResult]::new('-o', '-o', [CompletionResultType]::ParameterName, 'Output file path (default: stdout)')
|
||||
[CompletionResult]::new('--out', '--out', [CompletionResultType]::ParameterName, 'Output file path (default: stdout)')
|
||||
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
|
||||
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
|
||||
[CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version')
|
||||
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
|
||||
break
|
||||
}
|
||||
'zoxide;import' {
|
||||
[CompletionResult]::new('--from', '--from', [CompletionResultType]::ParameterName, 'Application to import from')
|
||||
[CompletionResult]::new('--merge', '--merge', [CompletionResultType]::ParameterName, 'Merge into existing database')
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ _zoxide() {
|
|||
zoxide,edit)
|
||||
cmd="zoxide__edit"
|
||||
;;
|
||||
zoxide,export)
|
||||
cmd="zoxide__export"
|
||||
;;
|
||||
zoxide,import)
|
||||
cmd="zoxide__import"
|
||||
;;
|
||||
|
|
@ -53,7 +56,7 @@ _zoxide() {
|
|||
|
||||
case "${cmd}" in
|
||||
zoxide)
|
||||
opts="-h -V --help --version add edit import init query remove"
|
||||
opts="-h -V --help --version add edit export import init query remove"
|
||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
|
|
@ -158,6 +161,58 @@ _zoxide() {
|
|||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
;;
|
||||
zoxide__export)
|
||||
opts="-f -o -h -V --format --out --help --version"
|
||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
fi
|
||||
case "${prev}" in
|
||||
--format)
|
||||
COMPREPLY=($(compgen -W "json csv" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
-f)
|
||||
COMPREPLY=($(compgen -W "json csv" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--out)
|
||||
local oldifs
|
||||
if [ -n "${IFS+x}" ]; then
|
||||
oldifs="$IFS"
|
||||
fi
|
||||
IFS=$'\n'
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
if [ -n "${oldifs+x}" ]; then
|
||||
IFS="$oldifs"
|
||||
fi
|
||||
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
|
||||
compopt -o filenames
|
||||
fi
|
||||
return 0
|
||||
;;
|
||||
-o)
|
||||
local oldifs
|
||||
if [ -n "${IFS+x}" ]; then
|
||||
oldifs="$IFS"
|
||||
fi
|
||||
IFS=$'\n'
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
if [ -n "${oldifs+x}" ]; then
|
||||
IFS="$oldifs"
|
||||
fi
|
||||
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
|
||||
compopt -o filenames
|
||||
fi
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=()
|
||||
;;
|
||||
esac
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
;;
|
||||
zoxide__import)
|
||||
opts="-h -V --from --merge --help --version <PATH>"
|
||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ set edit:completion:arg-completer[zoxide] = {|@words|
|
|||
cand --version 'Print version'
|
||||
cand add 'Add a new directory or increment its rank'
|
||||
cand edit 'Edit the database'
|
||||
cand export 'Export entries from the database'
|
||||
cand import 'Import entries from another application'
|
||||
cand init 'Generate shell configuration'
|
||||
cand query 'Search for a directory in the database'
|
||||
|
|
@ -71,6 +72,16 @@ set edit:completion:arg-completer[zoxide] = {|@words|
|
|||
cand -V 'Print version'
|
||||
cand --version 'Print version'
|
||||
}
|
||||
&'zoxide;export'= {
|
||||
cand -f 'Output format (json or csv)'
|
||||
cand --format 'Output format (json or csv)'
|
||||
cand -o 'Output file path (default: stdout)'
|
||||
cand --out 'Output file path (default: stdout)'
|
||||
cand -h 'Print help'
|
||||
cand --help 'Print help'
|
||||
cand -V 'Print version'
|
||||
cand --version 'Print version'
|
||||
}
|
||||
&'zoxide;import'= {
|
||||
cand --from 'Application to import from'
|
||||
cand --merge 'Merge into existing database'
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ complete -c zoxide -n "__fish_zoxide_needs_command" -s h -l help -d 'Print help'
|
|||
complete -c zoxide -n "__fish_zoxide_needs_command" -s V -l version -d 'Print version'
|
||||
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "add" -d 'Add a new directory or increment its rank'
|
||||
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "edit" -d 'Edit the database'
|
||||
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "export" -d 'Export entries from the database'
|
||||
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "import" -d 'Import entries from another application'
|
||||
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "init" -d 'Generate shell configuration'
|
||||
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "query" -d 'Search for a directory in the database'
|
||||
|
|
@ -49,6 +50,11 @@ complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subc
|
|||
complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from increment" -s V -l version -d 'Print version'
|
||||
complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from reload" -s h -l help -d 'Print help'
|
||||
complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from reload" -s V -l version -d 'Print version'
|
||||
complete -c zoxide -n "__fish_zoxide_using_subcommand export" -s f -l format -d 'Output format (json or csv)' -r -f -a "json\t''
|
||||
csv\t''"
|
||||
complete -c zoxide -n "__fish_zoxide_using_subcommand export" -s o -l out -d 'Output file path (default: stdout)' -r -F
|
||||
complete -c zoxide -n "__fish_zoxide_using_subcommand export" -s h -l help -d 'Print help'
|
||||
complete -c zoxide -n "__fish_zoxide_using_subcommand export" -s V -l version -d 'Print version'
|
||||
complete -c zoxide -n "__fish_zoxide_using_subcommand import" -l from -d 'Application to import from' -r -f -a "autojump\t''
|
||||
z\t''"
|
||||
complete -c zoxide -n "__fish_zoxide_using_subcommand import" -l merge -d 'Merge into existing database'
|
||||
|
|
|
|||
|
|
@ -43,6 +43,18 @@ module completions {
|
|||
--version(-V) # Print version
|
||||
]
|
||||
|
||||
def "nu-complete zoxide export format" [] {
|
||||
[ "json" "csv" ]
|
||||
}
|
||||
|
||||
# Export entries from the database
|
||||
export extern "zoxide export" [
|
||||
--format(-f): string@"nu-complete zoxide export format" # Output format (json or csv)
|
||||
--out(-o): path # Output file path (default: stdout)
|
||||
--help(-h) # Print help
|
||||
--version(-V) # Print version
|
||||
]
|
||||
|
||||
def "nu-complete zoxide import from" [] {
|
||||
[ "autojump" "z" ]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,42 @@ const completion: Fig.Spec = {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "export",
|
||||
description: "Export entries from the database",
|
||||
options: [
|
||||
{
|
||||
name: ["-f", "--format"],
|
||||
description: "Output format (json or csv)",
|
||||
isRepeatable: true,
|
||||
args: {
|
||||
name: "format",
|
||||
suggestions: [
|
||||
"json",
|
||||
"csv",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: ["-o", "--out"],
|
||||
description: "Output file path (default: stdout)",
|
||||
isRepeatable: true,
|
||||
args: {
|
||||
name: "out",
|
||||
isOptional: true,
|
||||
template: "filepaths",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: ["-h", "--help"],
|
||||
description: "Print help",
|
||||
},
|
||||
{
|
||||
name: ["-V", "--version"],
|
||||
description: "Print version",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "import",
|
||||
description: "Import entries from another application",
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ https://github.com/ajeetdsouza/zoxide
|
|||
pub enum Cmd {
|
||||
Add(Add),
|
||||
Edit(Edit),
|
||||
Export(Export),
|
||||
Import(Import),
|
||||
Init(Init),
|
||||
Query(Query),
|
||||
|
|
@ -88,6 +89,28 @@ pub enum EditCommand {
|
|||
Reload,
|
||||
}
|
||||
|
||||
/// Export entries from the database
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(
|
||||
author,
|
||||
help_template = HelpTemplate,
|
||||
)]
|
||||
pub struct Export {
|
||||
/// Output format (json or csv)
|
||||
#[clap(value_enum, long, short)]
|
||||
pub format: ExportFormat,
|
||||
|
||||
/// Output file path (default: stdout)
|
||||
#[clap(long, short, value_hint = ValueHint::FilePath)]
|
||||
pub out: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Clone, Debug)]
|
||||
pub enum ExportFormat {
|
||||
Json,
|
||||
Csv,
|
||||
}
|
||||
|
||||
/// Import entries from another application
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use crate::cmd::{Export, ExportFormat, Run};
|
||||
use crate::db::Database;
|
||||
|
||||
impl Run for Export {
|
||||
fn run(&self) -> Result<()> {
|
||||
let db = Database::open()?;
|
||||
let dirs = db.dirs();
|
||||
|
||||
let output = match self.format {
|
||||
ExportFormat::Json => serde_json::to_string(dirs)
|
||||
.context("could not serialize to JSON")?,
|
||||
ExportFormat::Csv => {
|
||||
let mut wtr = csv::Writer::from_writer(Vec::new());
|
||||
for dir in dirs {
|
||||
wtr.write_record([&*dir.path, &dir.rank.to_string(), &dir.last_accessed.to_string()])
|
||||
.context("could not write CSV record")?;
|
||||
}
|
||||
wtr.flush().context("could not flush CSV writer")?;
|
||||
String::from_utf8(wtr.into_inner().context("could not get CSV bytes")?)
|
||||
.context("CSV output is not valid UTF-8")?
|
||||
}
|
||||
};
|
||||
|
||||
match &self.out {
|
||||
Some(path) => {
|
||||
write_to_file(path, &output)
|
||||
.with_context(|| format!("could not write to file: {}", path.display()))?;
|
||||
}
|
||||
None => {
|
||||
writeln!(io::stdout(), "{output}")
|
||||
.context("could not write to stdout")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_to_file(path: impl AsRef<Path>, content: &str) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
if let Some(parent) = path.parent() {
|
||||
if !parent.as_os_str().is_empty() {
|
||||
fs::create_dir_all(parent)
|
||||
.with_context(|| format!("could not create directory: {}", parent.display()))?;
|
||||
}
|
||||
}
|
||||
fs::write(path, content)
|
||||
.with_context(|| format!("could not write to file: {}", path.display()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
mod add;
|
||||
mod cmd;
|
||||
mod edit;
|
||||
mod export;
|
||||
mod import;
|
||||
mod init;
|
||||
mod query;
|
||||
|
|
@ -19,6 +20,7 @@ impl Run for Cmd {
|
|||
match self {
|
||||
Cmd::Add(cmd) => cmd.run(),
|
||||
Cmd::Edit(cmd) => cmd.run(),
|
||||
Cmd::Export(cmd) => cmd.run(),
|
||||
Cmd::Import(cmd) => cmd.run(),
|
||||
Cmd::Init(cmd) => cmd.run(),
|
||||
Cmd::Query(cmd) => cmd.run(),
|
||||
|
|
|
|||
Loading…
Reference in New Issue