diff options
| -rw-r--r-- | Cargo.lock | 23 | ||||
| -rw-r--r-- | locales/help_docs/en.yml | 36 | ||||
| -rw-r--r-- | locales/help_docs/zh-CN.yml | 68 | ||||
| -rw-r--r-- | scripts/completions/bash/completion_jv.sh | 5 | ||||
| -rw-r--r-- | scripts/completions/powershell/completion_jv.ps1 | 5 | ||||
| -rw-r--r-- | src/bin/jv.rs | 364 |
6 files changed, 256 insertions, 245 deletions
@@ -1314,12 +1314,22 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "rand_chacha", + "rand_chacha 0.3.1", "rand_core 0.6.4", ] [[package]] name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand" version = "0.10.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ec474812b9de55111b29da8a1559f1718ef3dc20fa36f031f1b5d9e3836ad6c" @@ -1339,6 +1349,16 @@ dependencies = [ ] [[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2075,6 +2095,7 @@ dependencies = [ "chrono", "data_struct", "dirs", + "rand 0.9.2", "serde", "sha1_hash", "string_proc", diff --git a/locales/help_docs/en.yml b/locales/help_docs/en.yml index a5a9fb0..e7e049d 100644 --- a/locales/help_docs/en.yml +++ b/locales/help_docs/en.yml @@ -263,9 +263,9 @@ jv: info - Display individual file status **FILE TRANSFER**: - import <PACKAGE_NAME> - Import files from import area [[cyan]][REMOTE][[/]] - import <REFERENCE_SHEET_PATH> - Import files from reference sheet [[cyan]][REMOTE][[/]] - export <FILE> <SHEET_NAME> - Export files to other sheets [[cyan]][REMOTE][[/]] + share <FILE> <SHEET> <DESC> - Share files to other sheet [[cyan]][REMOTE][[/]] + share import <SHARE_ID> - Import share to current sheet [[cyan]][REMOTE][[/]] + share status - Display current sheet's share status **FILE OPERATIONS**: move <FILE> <TO> - Safely rename files [[cyan]][REMOTE][[/]] @@ -418,26 +418,24 @@ jv: The move mapping operation modifies the upstream mapping and synchronizes the local structure (use `--only-remote` to cancel local modification) After moving, you usually need `jv align moved remote` to synchronize the local structure to the upstream - export: | - **Export Files to Import Area of Other Sheets** - **Usage**: jv export <FILE> <TARGET_SHEET> -m <DESCRIPTION> -n <PACKAGE_NAME> - - **Example**: jv export data.csv analytics -m "Export analysis data" -n "analysis_data" - This operation packages the specified files and sends them to the import area of the target sheet. + share: | + **Share File Visibility** + **Usage**: + jv share <file> <sheet> <description> - Share mapping to other sheets + jv share --work - Share files in editor mode - Other collaborators can use the jv import command in the target sheet to import these files. + jv share status - View incoming shares - import: | - **Import Files to Current Sheet** - **Usage**: - jv import <PACKAGE_NAME> - Import files from import area - jv import <REFERENCE_SHEET_PATH> - Import files from reference sheet + jv share import <share_id> - Import share to current sheet + jv share import <ref_mapping> - Import mapping from `ref` sheet - **Example**: - jv import Player_Import - From import area defined name - jv import ref@Data/Player.csv - From reference sheet path + **Tip**: The import command can use the following parameters + --only-remote - Only import mapping into the sheet, do not modify local structure + --strict - Strict import mode, reject all conflicts, this is the default scheme + --skip - Skip conflicting items + --overwrite - Force overwrite conflicting mappings, dangerous operation - Import operation copies files from other sheets or import areas to the current workspace. + **Sharing** is the simplest way to give file visibility to others direct: | **Direct to Specified Upstream Vault and Stain This Workspace** diff --git a/locales/help_docs/zh-CN.yml b/locales/help_docs/zh-CN.yml index dc00606..c5e17ce 100644 --- a/locales/help_docs/zh-CN.yml +++ b/locales/help_docs/zh-CN.yml @@ -242,33 +242,33 @@ jv: **表操作**: sheet [list|use|exit|make|drop|align] - list - 列出所有表 - use - 使用表,并开始工作 - exit - 退出表,清除当前修改 - make - 创建新表以供自己使用 [[cyan]][远程][[/]] - drop - 抛弃表以供他人使用 [[cyan]][远程][[/]] - align - 对齐文件结构到表 [[cyan]][远程][[/]] + list - 列出所有表 + use - 使用表,并开始工作 + exit - 退出表,清除当前修改 + make - 创建新表以供自己使用 [[cyan]][远程][[/]] + drop - 抛弃表以供他人使用 [[cyan]][远程][[/]] + align - 对齐文件结构到表 [[cyan]][远程][[/]] **上下文查询**: - here - 显示当前路径的相关信息 - status - 显示当前表的状态信息 - info - 显示单个文件的状态 + here - 显示当前路径的相关信息 + status - 显示当前表的状态信息 + info - 显示单个文件的状态 **文件传递**: - import <文件包名称> - 从导入区导入文件 [[cyan]][远程][[/]] - import <参照表中目录> - 从参照表导入文件 [[cyan]][远程][[/]] - export <文件> <表名称> - 导出文件到其他表 [[cyan]][远程][[/]] + share <文件> <表> <描述> - 分享当前上下文的文件至其他表 [[cyan]][远程][[/]] + share import <分享ID> - 将分享导入到当前表 [[cyan]][远程][[/]] + share status - 显示当前表的分享状态 **文件操作**: - move <文件> <到> - 安全地重命名文件 [[cyan]][远程][[/]] - track <文件> - 追踪文件内容到最新版本 [[cyan]][远程][[/]] - hold <文件> - 拿取文件,同步版本并获得编辑权 [[cyan]][远程][[/]] - throw <文件> - 丢弃文件,同步版本并放弃编辑权 [[cyan]][远程][[/]] - jump <文件> <版本> - 将文件的版本跳转至其他版本 [[cyan]][远程][[/]] + move <文件> <到> - 安全地重命名文件 [[cyan]][远程][[/]] + track <文件> - 追踪文件内容到最新版本 [[cyan]][远程][[/]] + hold <文件> - 拿取文件,同步版本并获得编辑权 [[cyan]][远程][[/]] + throw <文件> - 丢弃文件,同步版本并放弃编辑权 [[cyan]][远程][[/]] + jump <文件> <版本> - 将文件的版本跳转至其他版本 [[cyan]][远程][[/]] **内建文档**: - docs list - 列出所有可用的文档 - docs <文档名称> - 查看指定文档的内容 + docs list - 列出所有可用的文档 + docs <文档名称> - 查看指定文档的内容 您可以使用 jv <命令名称> --help 来查询更详细的帮助! @@ -407,26 +407,24 @@ jv: 移动映射操作会修改上游的映射,并同步修改本地结构(使用 `--only-remote` 取消同步修改) 在移动完成后,通常需要 `jv align moved remote` 将本地结构同步至上游 - export: | - **将文件导出至其他表的待导入区** - **用法**:jv export <文件> <目标表> -m <描述> -n <文件包名称> - - **例如**:jv export data.csv analytics -m "导出分析数据" -n "analysis_data" - 该操作会将指定的文件打包并发送到目标表的导入区 + share: | + **分享文件的可见性** + **用法**: + jv share <文件> <表> <描述> - 分享映射到其他表 + jv share --work - 编辑器模式下分享文件 - 其他协作者可以在目标表中使用 jv import 命令来导入这些文件 + jv share status - 查看传入的分享 - import: | - **导入文件到当前表** - **用法**: - jv import <文件包名称> - 从导入区导入文件 - jv import <参照表中目录> - 从参照表导入文件 + jv share import <分享ID> - 将分享导入到当前表 + jv share import <REF映射> - 从 `ref` 表中导入映射 - **例如**: - jv import Player_Import - 来自导入区定义的名称 - jv import ref@Data/Player.csv - 来自参照表的路径 + **提示**:import 命令可使用如下参数 + --only-remote - 只在表中导入映射,不修改本地结构 + --strict - 严格的导入模式,拒绝所有冲突,这是默认的方案 + --skip - 跳过冲突项 + --overwrite - 强制覆盖冲突的映射,危险的操作 - 导入操作会将文件从其他表或导入区复制到当前工作区 + **分享** 是将文件可见性交由其他人的最简途径 direct: | **定向到指定上游库,并染色该工作区** diff --git a/scripts/completions/bash/completion_jv.sh b/scripts/completions/bash/completion_jv.sh index be5afc6..604fb8c 100644 --- a/scripts/completions/bash/completion_jv.sh +++ b/scripts/completions/bash/completion_jv.sh @@ -16,8 +16,7 @@ _jv_completion() { # Subcommands local base_commands="create init direct unstain account update \ - sheet status here import export in out \ - move mv docs exit use sheets accounts \ + sheet status here move mv docs exit use sheets accounts \ as make drop track hold throw login \ jump align" @@ -222,7 +221,7 @@ _jv_completion() { "move"|"mv") COMPREPLY=($(compgen -f -- "$cur")) ;; - "import"|"export"|"in"|"out"|"track"|"hold"|"throw") + "track"|"hold"|"throw") COMPREPLY=($(compgen -f -- "$cur")) ;; esac diff --git a/scripts/completions/powershell/completion_jv.ps1 b/scripts/completions/powershell/completion_jv.ps1 index b756fbd..46a56cc 100644 --- a/scripts/completions/powershell/completion_jv.ps1 +++ b/scripts/completions/powershell/completion_jv.ps1 @@ -14,8 +14,7 @@ Register-ArgumentCompleter -Native -CommandName jv -ScriptBlock { # Base commands $baseCommands = @( "create", "init", "direct", "unstain", "account", "update", - "sheet", "status", "here", "import", "export", "in", "out", - "move", "mv", "docs", "exit", "use", "sheets", "accounts", + "sheet", "status", "here", "move", "mv", "docs", "exit", "use", "sheets", "accounts", "as", "make", "drop", "track", "hold", "throw", "login", "jump", "align" ) @@ -199,7 +198,7 @@ Register-ArgumentCompleter -Native -CommandName jv -ScriptBlock { return $docs | Where-Object { $_ -like "$wordToComplete*" } } } - { @("move", "mv", "import", "export", "in", "out", "track", "hold", "throw") -contains $_ } { + { @("move", "mv", "track", "hold", "throw") -contains $_ } { # File completion for file operations return Get-ChildItem -Name -File -Path "." | Where-Object { $_ -like "$wordToComplete*" } } diff --git a/src/bin/jv.rs b/src/bin/jv.rs index 29b2c36..e4df459 100644 --- a/src/bin/jv.rs +++ b/src/bin/jv.rs @@ -66,6 +66,7 @@ use std::{ path::PathBuf, process::exit, str::FromStr, + sync::Arc, time::SystemTime, }; @@ -94,6 +95,7 @@ use tokio::{ fs::{self}, net::TcpSocket, process::Command, + sync::mpsc::{self, Receiver}, }; // Import i18n files @@ -165,13 +167,8 @@ enum JustEnoughVcsWorkspaceCommand { #[command(alias = "mv")] Move(MoveMappingArgs), - /// Export files to other worksheet - #[command(alias = "out")] - Export(ExportFileArgs), - - /// Import files from reference sheet or import area - #[command(alias = "in")] - Import(ImportFileArgs), + /// Share file visibility to other sheets + Share(ShareFileArgs), /// Sync information from upstream vault #[command(alias = "u")] @@ -625,14 +622,7 @@ struct MoveMappingArgs { } #[derive(Parser, Debug)] -struct ExportFileArgs { - /// Show help information - #[arg(short, long)] - help: bool, -} - -#[derive(Parser, Debug)] -struct ImportFileArgs { +struct ShareFileArgs { /// Show help information #[arg(short, long)] help: bool, @@ -1074,19 +1064,12 @@ async fn main() { } jv_move(move_file_args).await; } - JustEnoughVcsWorkspaceCommand::Export(export_file_args) => { - if export_file_args.help { - println!("{}", md(t!("jv.export"))); - return; - } - jv_export(export_file_args).await; - } - JustEnoughVcsWorkspaceCommand::Import(import_file_args) => { - if import_file_args.help { - println!("{}", md(t!("jv.import"))); + JustEnoughVcsWorkspaceCommand::Share(share_file_args) => { + if share_file_args.help { + println!("{}", md(t!("jv.share"))); return; } - jv_import(import_file_args).await; + jv_share(share_file_args).await; } JustEnoughVcsWorkspaceCommand::Update(update_file_args) => { if update_file_args.help { @@ -2218,7 +2201,7 @@ async fn jv_sheet_make(args: SheetMakeArgs) { None => return, }; - let (pool, ctx) = match build_pool_and_ctx(&local_config).await { + let (pool, ctx, _output) = match build_pool_and_ctx(&local_config).await { Some(result) => result, None => return, }; @@ -2314,7 +2297,7 @@ async fn jv_sheet_drop(args: SheetDropArgs) { None => return, }; - let (pool, ctx) = match build_pool_and_ctx(&local_config).await { + let (pool, ctx, _output) = match build_pool_and_ctx(&local_config).await { Some(result) => result, None => return, }; @@ -2575,7 +2558,7 @@ async fn jv_sheet_align(args: SheetAlignArgs) { if !align_to_remote { // Align to local // Network move mapping - let (pool, ctx) = match build_pool_and_ctx(&local_cfg).await { + let (pool, ctx, _output) = match build_pool_and_ctx(&local_cfg).await { Some(result) => result, None => return, }; @@ -2806,7 +2789,7 @@ async fn jv_track(args: TrackFileArgs) { return; }; - let (pool, ctx) = match build_pool_and_ctx(&local_config).await { + let (pool, ctx, mut output) = match build_pool_and_ctx(&local_config).await { Some(result) => result, None => return, }; @@ -2815,7 +2798,7 @@ async fn jv_track(args: TrackFileArgs) { let overwrite = args.allow_overwrite; let update_info = get_update_info(local_workspace, &files, args).await; - match proc_track_file_action( + let track_action = proc_track_file_action( &pool, ctx, TrackFileActionArguments { @@ -2824,156 +2807,165 @@ async fn jv_track(args: TrackFileArgs) { print_infos: true, allow_overwrite_modified: overwrite, }, - ) - .await - { - Ok(result) => match result { - TrackFileActionResult::Done { - created, - updated, - synced, - skipped, - } => { - println!( - "{}", - md(t!( - "jv.result.track.done", - count = created.len() + updated.len() + synced.len(), - created = created.len(), - updated = updated.len(), - synced = synced.len() - )) - ); + ); - if skipped.len() > 0 { - println!( - "\n{}", - md(t!( - "jv.result.track.tip_has_skipped", - skipped_num = skipped.len(), - skipped = skipped - .iter() - .map(|f| f.display().to_string()) - .collect::<Vec<String>>() - .join("\n") - .trim() - )) - .yellow() - ); - } - } - TrackFileActionResult::AuthorizeFailed(e) => { - eprintln!("{}", md(t!("jv.result.common.authroize_failed", err = e))) - } - TrackFileActionResult::StructureChangesNotSolved => { - eprintln!("{}", md(t!("jv.result.track.structure_changes_not_solved"))) - } - TrackFileActionResult::CreateTaskFailed(create_task_result) => match create_task_result - { - CreateTaskResult::Success(_) => {} // Success is not handled here - CreateTaskResult::CreateFileOnExistPath(path) => { - eprintln!( - "{}", - md(t!( - "jv.result.track.create_failed.create_file_on_exist_path", - path = path.display() - )) - ) - } - CreateTaskResult::SheetNotFound(sheet) => { - eprintln!( - "{}", - md(t!( - "jv.result.track.create_failed.sheet_not_found", - name = sheet - )) - ) - } - }, - TrackFileActionResult::UpdateTaskFailed(update_task_result) => match update_task_result - { - UpdateTaskResult::Success(_) => {} // Success is not handled here - UpdateTaskResult::VerifyFailed { path, reason } => match reason { - VerifyFailReason::SheetNotFound(sheet_name) => { - eprintln!( - "{}", - md(t!( - "jv.result.track.update_failed.verify.sheet_not_found", - sheet_name = sheet_name - )) - ) - } - VerifyFailReason::MappingNotFound => { - eprintln!( - "{}", - md(t!( - "jv.result.track.update_failed.verify.mapping_not_found", - path = path.display() - )) - ) - } - VerifyFailReason::VirtualFileNotFound(vfid) => { - eprintln!( - "{}", - md(t!( - "jv.result.track.update_failed.verify.virtual_file_not_found", - vfid = vfid - )) - ) - } - VerifyFailReason::VirtualFileReadFailed(vfid) => { - eprintln!( + tokio::select! { + result = track_action => { + match result { + Ok(result) => match result { + TrackFileActionResult::Done { + created, + updated, + synced, + skipped, + } => { + println!( "{}", md(t!( - "jv.result.track.update_failed.verify.virtual_file_read_failed", - vfid = vfid + "jv.result.track.done", + count = created.len() + updated.len() + synced.len(), + created = created.len(), + updated = updated.len(), + synced = synced.len() )) - ) - } - VerifyFailReason::NotHeld => { - eprintln!( - "{}", - md(t!( - "jv.result.track.update_failed.verify.not_held", - path = path.display() - )) - ) - } - VerifyFailReason::VersionDismatch(current_version, latest_version) => { - eprintln!( - "{}", - md(t!( - "jv.result.track.update_failed.verify.version_dismatch", - version_current = current_version, - version_latest = latest_version - )) - ) + ); + + if skipped.len() > 0 { + println!( + "\n{}", + md(t!( + "jv.result.track.tip_has_skipped", + skipped_num = skipped.len(), + skipped = skipped + .iter() + .map(|f| f.display().to_string()) + .collect::<Vec<String>>() + .join("\n") + .trim() + )) + .yellow() + ); + } } - VerifyFailReason::UpdateButNoDescription => { - eprintln!( - "{}", - md(t!( - "jv.result.track.update_failed.verify.update_but_no_description" - )) - ) + TrackFileActionResult::AuthorizeFailed(e) => { + eprintln!("{}", md(t!("jv.result.common.authroize_failed", err = e))) } - VerifyFailReason::VersionAlreadyExist(latest_version) => { - eprintln!( - "{}", - md(t!( - "jv.result.track.update_failed.verify.version_already_exist", - path = path.display(), - version = latest_version - )) - ) + TrackFileActionResult::StructureChangesNotSolved => { + eprintln!("{}", md(t!("jv.result.track.structure_changes_not_solved"))) } + TrackFileActionResult::CreateTaskFailed(create_task_result) => match create_task_result + { + CreateTaskResult::Success(_) => {} // Success is not handled here + CreateTaskResult::CreateFileOnExistPath(path) => { + eprintln!( + "{}", + md(t!( + "jv.result.track.create_failed.create_file_on_exist_path", + path = path.display() + )) + ) + } + CreateTaskResult::SheetNotFound(sheet) => { + eprintln!( + "{}", + md(t!( + "jv.result.track.create_failed.sheet_not_found", + name = sheet + )) + ) + } + }, + TrackFileActionResult::UpdateTaskFailed(update_task_result) => match update_task_result + { + UpdateTaskResult::Success(_) => {} // Success is not handled here + UpdateTaskResult::VerifyFailed { path, reason } => match reason { + VerifyFailReason::SheetNotFound(sheet_name) => { + eprintln!( + "{}", + md(t!( + "jv.result.track.update_failed.verify.sheet_not_found", + sheet_name = sheet_name + )) + ) + } + VerifyFailReason::MappingNotFound => { + eprintln!( + "{}", + md(t!( + "jv.result.track.update_failed.verify.mapping_not_found", + path = path.display() + )) + ) + } + VerifyFailReason::VirtualFileNotFound(vfid) => { + eprintln!( + "{}", + md(t!( + "jv.result.track.update_failed.verify.virtual_file_not_found", + vfid = vfid + )) + ) + } + VerifyFailReason::VirtualFileReadFailed(vfid) => { + eprintln!( + "{}", + md(t!( + "jv.result.track.update_failed.verify.virtual_file_read_failed", + vfid = vfid + )) + ) + } + VerifyFailReason::NotHeld => { + eprintln!( + "{}", + md(t!( + "jv.result.track.update_failed.verify.not_held", + path = path.display() + )) + ) + } + VerifyFailReason::VersionDismatch(current_version, latest_version) => { + eprintln!( + "{}", + md(t!( + "jv.result.track.update_failed.verify.version_dismatch", + version_current = current_version, + version_latest = latest_version + )) + ) + } + VerifyFailReason::UpdateButNoDescription => { + eprintln!( + "{}", + md(t!( + "jv.result.track.update_failed.verify.update_but_no_description" + )) + ) + } + VerifyFailReason::VersionAlreadyExist(latest_version) => { + eprintln!( + "{}", + md(t!( + "jv.result.track.update_failed.verify.version_already_exist", + path = path.display(), + version = latest_version + )) + ) + } + }, + }, + TrackFileActionResult::SyncTaskFailed(sync_task_result) => match sync_task_result { + SyncTaskResult::Success(_) => {} // Success is not handled here + }, }, - }, - TrackFileActionResult::SyncTaskFailed(sync_task_result) => match sync_task_result { - SyncTaskResult::Success(_) => {} // Success is not handled here - }, - }, - Err(e) => handle_err(e), + Err(e) => handle_err(e), + } + } + _ = async { + while let Some(msg) = output.recv().await { + println!("{}", msg); + } + } => {} } } @@ -3476,7 +3468,7 @@ async fn jv_change_edit_right( return; } - let (pool, ctx) = match build_pool_and_ctx(&local_cfg).await { + let (pool, ctx, _output) = match build_pool_and_ctx(&local_cfg).await { Some(result) => result, None => return, }; @@ -3646,7 +3638,7 @@ async fn jv_move(args: MoveMappingArgs) { None => return, }; - let (pool, ctx) = match build_pool_and_ctx(&local_cfg).await { + let (pool, ctx, _output) = match build_pool_and_ctx(&local_cfg).await { Some(result) => result, None => return, }; @@ -3767,11 +3759,7 @@ async fn proc_mapping_edit( } } -async fn jv_export(_args: ExportFileArgs) { - todo!() -} - -async fn jv_import(_args: ImportFileArgs) { +async fn jv_share(_args: ShareFileArgs) { todo!() } @@ -3991,7 +3979,7 @@ async fn jv_update(update_file_args: UpdateArgs) { None => return, }; - let (pool, ctx) = match build_pool_and_ctx(&local_config).await { + let (pool, ctx, _output) = match build_pool_and_ctx(&local_config).await { Some(result) => result, None => return, }; @@ -4435,14 +4423,22 @@ async fn precheck() -> Option<LocalConfig> { /// Build action pool and context for upstream communication /// Returns Some((ActionPool, ActionContext)) if successful, None otherwise -async fn build_pool_and_ctx(local_config: &LocalConfig) -> Option<(ActionPool, ActionContext)> { +async fn build_pool_and_ctx( + local_config: &LocalConfig, +) -> Option<(ActionPool, ActionContext, Receiver<String>)> { let pool = client_registry::client_action_pool(); let upstream = local_config.upstream_addr(); let instance = connect(upstream).await?; - let ctx = ActionContext::local().insert_instance(instance); - Some((pool, ctx)) + // Build context and insert instance + let mut ctx = ActionContext::local().insert_instance(instance); + + // Build channel for communication + let (tx, rx) = mpsc::channel::<String>(100); + ctx.insert_arc_data(Arc::new(tx)); + + Some((pool, ctx, rx)) } /// Sort paths in a vector of strings. |
