Skip to content

Commit

Permalink
cli: add a jj debug tree command for printing the tree
Browse files Browse the repository at this point in the history
I'm about to make conflicts also get materialized in executable
files. We'll lose some of the test coverage in `test_chmod_command.rs`
then, because the those tests rely on the materialized content to
describe the executable bits. So this commit adds a debug command for
printing tree values and uses that in the tests.
  • Loading branch information
martinvonz committed Oct 24, 2023
1 parent 947b139 commit 1257416
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 2 deletions.
30 changes: 29 additions & 1 deletion cli/src/commands/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use jj_lib::local_working_copy::{LocalWorkingCopy, LockedLocalWorkingCopy};
use jj_lib::revset;
use jj_lib::working_copy::WorkingCopy;

use crate::cli_util::{resolve_op_for_load, user_error, CommandError, CommandHelper};
use crate::cli_util::{resolve_op_for_load, user_error, CommandError, CommandHelper, RevisionArg};
use crate::template_parser;
use crate::ui::Ui;

Expand All @@ -40,6 +40,7 @@ pub enum DebugCommands {
ReIndex(DebugReIndexArgs),
#[command(visible_alias = "view")]
Operation(DebugOperationArgs),
Tree(DebugTreeArgs),
#[command(subcommand)]
Watchman(DebugWatchmanSubcommand),
}
Expand Down Expand Up @@ -89,6 +90,15 @@ pub enum DebugOperationDisplay {
All,
}

/// List the recursive entries of a tree.
#[derive(clap::Args, Clone, Debug)]
pub struct DebugTreeArgs {
#[arg(long, short = 'r', default_value = "@")]
revision: RevisionArg,
paths: Vec<String>,
// TODO: Add an option to include trees that are ancestors of the matched paths
}

#[derive(Subcommand, Clone, Debug)]
pub enum DebugWatchmanSubcommand {
QueryClock,
Expand Down Expand Up @@ -198,6 +208,7 @@ pub fn cmd_debug(
writeln!(ui.stdout(), "{:#?}", op.view()?.store_view())?;
}
}
DebugCommands::Tree(sub_args) => cmd_debug_tree(ui, command, sub_args)?,
DebugCommands::Watchman(watchman_subcommand) => {
cmd_debug_watchman(ui, command, watchman_subcommand)?;
}
Expand Down Expand Up @@ -242,6 +253,23 @@ fn cmd_debug_revset(
Ok(())
}

fn cmd_debug_tree(
ui: &mut Ui,
command: &CommandHelper,
args: &DebugTreeArgs,
) -> Result<(), CommandError> {
let workspace_command = command.workspace_helper(ui)?;
let commit = workspace_command.resolve_single_rev(&args.revision, ui)?;
let tree = commit.tree()?;
let matcher = workspace_command.matcher_from_values(&args.paths)?;
for (path, value) in tree.entries_matching(matcher.as_ref()) {
let ui_path = workspace_command.format_file_path(&path);
writeln!(ui.stdout(), "{ui_path}: {value:?}")?;
}

Ok(())
}

#[cfg(feature = "watchman")]
fn cmd_debug_watchman(
ui: &mut Ui,
Expand Down
37 changes: 36 additions & 1 deletion cli/tests/test_chmod_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ fn test_chmod_regular_conflict() {
◉ base
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree"]);
insta::assert_snapshot!(stdout,
@r###"
file: Conflicted { removes: [Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false })], adds: [Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: true }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: false })] }
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "file"]);
insta::assert_snapshot!(stdout,
@r###"
Expand All @@ -76,6 +81,11 @@ fn test_chmod_regular_conflict() {

// Test chmodding a conflict
test_env.jj_cmd_ok(&repo_path, &["chmod", "x", "file"]);
let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree"]);
insta::assert_snapshot!(stdout,
@r###"
file: Conflicted { removes: [Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: true })], adds: [Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: true }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: true })] }
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "file"]);
insta::assert_snapshot!(stdout,
@r###"
Expand All @@ -85,6 +95,11 @@ fn test_chmod_regular_conflict() {
Adding executable file with id 8ba3a16384aacc37d01564b28401755ce8053f51
"###);
test_env.jj_cmd_ok(&repo_path, &["chmod", "n", "file"]);
let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree"]);
insta::assert_snapshot!(stdout,
@r###"
file: Conflicted { removes: [Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false })], adds: [Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: false }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: false })] }
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "file"]);
insta::assert_snapshot!(stdout,
@r###"
Expand All @@ -103,6 +118,11 @@ fn test_chmod_regular_conflict() {
insta::assert_snapshot!(stderr, @r###"
Error: No such path at 'nonexistent'.
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree"]);
insta::assert_snapshot!(stdout,
@r###"
file: Conflicted { removes: [Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false })], adds: [Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: false }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: false })] }
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "file"]);
insta::assert_snapshot!(stdout,
@r###"
Expand Down Expand Up @@ -161,6 +181,11 @@ fn test_chmod_file_dir_deletion_conflicts() {
"###);

// The file-dir conflict cannot be chmod-ed
let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree", "-r=file_dir"]);
insta::assert_snapshot!(stdout,
@r###"
file: Conflicted { removes: [Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false })], adds: [Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: false }), Some(Tree(TreeId("133bb38fc4e4bf6b551f1f04db7e48f04cac2877")))] }
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "-r=file_dir", "file"]);
insta::assert_snapshot!(stdout,
@r###"
Expand All @@ -175,6 +200,11 @@ fn test_chmod_file_dir_deletion_conflicts() {
"###);

// The file_deletion conflict can be chmod-ed
let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree", "-r=file_deletion"]);
insta::assert_snapshot!(stdout,
@r###"
file: Conflicted { removes: [Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false })], adds: [Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: false }), None] }
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "-r=file_deletion", "file"]);
insta::assert_snapshot!(stdout,
@r###"
Expand All @@ -189,11 +219,16 @@ fn test_chmod_file_dir_deletion_conflicts() {
test_env.jj_cmd_ok(&repo_path, &["chmod", "x", "file", "-r=file_deletion"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Working copy now at: kmkuslsw 8b70a1d2 file_deletion | (conflict) file_deletion
Working copy now at: kmkuslsw 4cc432b5 file_deletion | (conflict) file_deletion
Parent commit : zsuskuln c51c9c55 file | file
Parent commit : royxmykx 6b18b3c1 deletion | deletion
Added 0 files, modified 1 files, removed 0 files
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree", "-r=file_deletion"]);
insta::assert_snapshot!(stdout,
@r###"
file: Conflicted { removes: [Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: true })], adds: [Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: true }), None] }
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "-r=file_deletion", "file"]);
insta::assert_snapshot!(stdout,
@r###"
Expand Down

0 comments on commit 1257416

Please sign in to comment.