From a31fe7f6d61e3d46abadc8aa411997ba4b29cc39 Mon Sep 17 00:00:00 2001 From: Austin Seipp Date: Fri, 6 Sep 2024 11:48:57 -0500 Subject: [PATCH] cli: implement `workspace add --sparse-patterns` This flag implements three modes: - `copy`: copy sparse patterns from parent - `full`: do not copy sparse patterns from parent - `empty`: clear all paths, equal to `set --clear` This is useful for various tooling like tools that want to run a parallel process that queries the build system (without running into locks/blocking.) I think continuing to copy sparse patterns makes sense as the default behavior. Signed-off-by: Austin Seipp --- CHANGELOG.md | 5 +++ cli/src/commands/workspace/add.rs | 62 ++++++++++++++++++++++++------- cli/tests/cli-reference@.md.snap | 14 ++++++- cli/tests/test_workspaces.rs | 27 ++++++++++++++ 4 files changed, 94 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbf0cc404..571c7882a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,11 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). can be used to more easily introduce automatic formatting changes in a new commit separate from other changes. +* `jj workspace add` now accepts a `--sparse-patterns=` option, which + allows control of the sparse patterns for a newly created workspace: `copy` + (inherit from parent; default), `full` (full working copy), or `empty` (the + empty working copy). + ### Fixed bugs * Fixed panic when parsing invalid conflict markers of a particular form. diff --git a/cli/src/commands/workspace/add.rs b/cli/src/commands/workspace/add.rs index 5a09947ae..92f347d45 100644 --- a/cli/src/commands/workspace/add.rs +++ b/cli/src/commands/workspace/add.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::fmt::Display; use std::fs; use itertools::Itertools; @@ -31,9 +32,31 @@ use crate::command_error::user_error; use crate::command_error::CommandError; use crate::ui::Ui; +/// How to handle sparse patterns when creating a new workspace. +#[derive(clap::ValueEnum, Clone, Debug, Eq, PartialEq)] +enum SparseInheritance { + /// Copy all sparse patterns from the current workspace. + Copy, + /// Include all files in the new workspace. + Full, + /// Clear all files from the workspace (it will be empty). + Empty, +} + +impl Display for SparseInheritance { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SparseInheritance::Copy => write!(f, "copy"), + SparseInheritance::Full => write!(f, "full"), + SparseInheritance::Empty => write!(f, "empty"), + } + } +} + /// Add a workspace /// -/// Sparse patterns will be copied over from the current workspace. +/// By default, the new workspace inherits the sparse patterns of the current +/// workspace. You can override this with the `--sparse-patterns` option. #[derive(clap::Args, Clone, Debug)] pub struct WorkspaceAddArgs { /// Where to create the new workspace @@ -58,6 +81,9 @@ pub struct WorkspaceAddArgs { /// new r1 r2 r3 ...`. #[arg(long, short)] revision: Vec, + /// How to handle sparse patterns when creating a new workspace. + #[arg(long, default_value_t=SparseInheritance::Copy)] + sparse_patterns: SparseInheritance, } #[instrument(skip_all)] @@ -114,19 +140,29 @@ pub fn cmd_workspace_add( )?; } - // Copy sparse patterns from workspace where the command was run let mut new_workspace_command = command.for_workable_repo(ui, new_workspace, repo)?; - let (mut locked_ws, _wc_commit) = new_workspace_command.start_working_copy_mutation()?; - let sparse_patterns = old_workspace_command - .working_copy() - .sparse_patterns()? - .to_vec(); - locked_ws - .locked_wc() - .set_sparse_patterns(sparse_patterns) - .map_err(|err| internal_error_with_message("Failed to set sparse patterns", err))?; - let operation_id = locked_ws.locked_wc().old_operation_id().clone(); - locked_ws.finish(operation_id)?; + + let sparsity = match args.sparse_patterns { + SparseInheritance::Full => None, + SparseInheritance::Empty => Some(vec![]), + SparseInheritance::Copy => { + let sparse_patterns = old_workspace_command + .working_copy() + .sparse_patterns()? + .to_vec(); + Some(sparse_patterns) + } + }; + + if let Some(sparse_patterns) = sparsity { + let (mut locked_ws, _wc_commit) = new_workspace_command.start_working_copy_mutation()?; + locked_ws + .locked_wc() + .set_sparse_patterns(sparse_patterns) + .map_err(|err| internal_error_with_message("Failed to set sparse patterns", err))?; + let operation_id = locked_ws.locked_wc().old_operation_id().clone(); + locked_ws.finish(operation_id)?; + } let mut tx = new_workspace_command.start_transaction(); diff --git a/cli/tests/cli-reference@.md.snap b/cli/tests/cli-reference@.md.snap index bc966d4f3..824900371 100644 --- a/cli/tests/cli-reference@.md.snap +++ b/cli/tests/cli-reference@.md.snap @@ -2118,7 +2118,7 @@ Each workspace also has own sparse patterns. Add a workspace -Sparse patterns will be copied over from the current workspace. +By default, the new workspace inherits the sparse patterns of the current workspace. You can override this with the `--sparse-patterns` option. **Usage:** `jj workspace add [OPTIONS] ` @@ -2136,6 +2136,18 @@ Sparse patterns will be copied over from the current workspace. If no revisions are specified, the new workspace will be created, and its working-copy commit will exist on top of the parent(s) of the working-copy commit in the current workspace, i.e. they will share the same parent(s). If any revisions are specified, the new workspace will be created, and the new working-copy commit will be created with all these revisions as parents, i.e. the working-copy commit will exist as if you had run `jj new r1 r2 r3 ...`. +* `--sparse-patterns ` — How to handle sparse patterns when creating a new workspace + + Default value: `copy` + + Possible values: + - `copy`: + Copy all sparse patterns from the current workspace + - `full`: + Include all files in the new workspace + - `empty`: + Clear all files from the workspace (it will be empty) + diff --git a/cli/tests/test_workspaces.rs b/cli/tests/test_workspaces.rs index d6b800c6c..f50626082 100644 --- a/cli/tests/test_workspaces.rs +++ b/cli/tests/test_workspaces.rs @@ -77,6 +77,9 @@ fn test_workspaces_sparse_patterns() { let ws1_path = test_env.env_root().join("ws1"); let ws2_path = test_env.env_root().join("ws2"); let ws3_path = test_env.env_root().join("ws3"); + let ws4_path = test_env.env_root().join("ws4"); + let ws5_path = test_env.env_root().join("ws5"); + let ws6_path = test_env.env_root().join("ws6"); test_env.jj_cmd_ok(&ws1_path, &["sparse", "set", "--clear", "--add=foo"]); test_env.jj_cmd_ok(&ws1_path, &["workspace", "add", "../ws2"]); @@ -91,6 +94,30 @@ fn test_workspaces_sparse_patterns() { bar foo "###); + // --sparse-patterns behavior + test_env.jj_cmd_ok( + &ws3_path, + &["workspace", "add", "--sparse-patterns=copy", "../ws4"], + ); + let stdout = test_env.jj_cmd_success(&ws4_path, &["sparse", "list"]); + insta::assert_snapshot!(stdout, @r###" + bar + foo + "###); + test_env.jj_cmd_ok( + &ws3_path, + &["workspace", "add", "--sparse-patterns=full", "../ws5"], + ); + let stdout = test_env.jj_cmd_success(&ws5_path, &["sparse", "list"]); + insta::assert_snapshot!(stdout, @r###" + . + "###); + test_env.jj_cmd_ok( + &ws3_path, + &["workspace", "add", "--sparse-patterns=empty", "../ws6"], + ); + let stdout = test_env.jj_cmd_success(&ws6_path, &["sparse", "list"]); + insta::assert_snapshot!(stdout, @""); } /// Test adding a second workspace while the current workspace is editing a