Skip to content

Commit

Permalink
Split jj debug command into multiple files
Browse files Browse the repository at this point in the history
  • Loading branch information
fowles committed Jun 19, 2024
1 parent 2364cf2 commit bbe7162
Show file tree
Hide file tree
Showing 11 changed files with 663 additions and 442 deletions.
442 changes: 0 additions & 442 deletions cli/src/commands/debug.rs

This file was deleted.

48 changes: 48 additions & 0 deletions cli/src/commands/debug/fileset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2023 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt::Debug;
use std::io::Write as _;

use jj_lib::fileset;

use crate::cli_util::CommandHelper;
use crate::command_error::CommandError;
use crate::ui::Ui;

/// Parse fileset expression
#[derive(clap::Args, Clone, Debug)]
pub struct FilesetArgs {
#[arg(value_hint = clap::ValueHint::AnyPath)]
path: String,
}

pub fn cmd_debug_fileset(
ui: &mut Ui,
command: &CommandHelper,
args: &FilesetArgs,
) -> Result<(), CommandError> {
let workspace_command = command.workspace_helper(ui)?;
let path_converter = workspace_command.path_converter();

let expression = fileset::parse_maybe_bare(&args.path, path_converter)?;
writeln!(ui.stdout(), "-- Parsed:")?;
writeln!(ui.stdout(), "{expression:#?}")?;
writeln!(ui.stdout())?;

let matcher = expression.to_matcher();
writeln!(ui.stdout(), "-- Matcher:")?;
writeln!(ui.stdout(), "{matcher:#?}")?;
Ok(())
}
67 changes: 67 additions & 0 deletions cli/src/commands/debug/index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2023 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt::Debug;
use std::io::Write as _;

use jj_lib::default_index::{AsCompositeIndex as _, DefaultReadonlyIndex};
use jj_lib::op_walk;

use crate::cli_util::CommandHelper;
use crate::command_error::{internal_error, user_error, CommandError};
use crate::ui::Ui;

/// Show commit index stats
#[derive(clap::Args, Clone, Debug)]
pub struct IndexArgs {}

pub fn cmd_debug_index(
ui: &mut Ui,
command: &CommandHelper,
_args: &IndexArgs,
) -> Result<(), CommandError> {
// Resolve the operation without loading the repo, so this command won't
// merge concurrent operations and update the index.
let workspace = command.load_workspace()?;
let repo_loader = workspace.repo_loader();
let op = op_walk::resolve_op_for_load(repo_loader, &command.global_args().at_operation)?;
let index_store = repo_loader.index_store();
let index = index_store
.get_index_at_op(&op, repo_loader.store())
.map_err(internal_error)?;
if let Some(default_index) = index.as_any().downcast_ref::<DefaultReadonlyIndex>() {
let stats = default_index.as_composite().stats();
writeln!(ui.stdout(), "Number of commits: {}", stats.num_commits)?;
writeln!(ui.stdout(), "Number of merges: {}", stats.num_merges)?;
writeln!(
ui.stdout(),
"Max generation number: {}",
stats.max_generation_number
)?;
writeln!(ui.stdout(), "Number of heads: {}", stats.num_heads)?;
writeln!(ui.stdout(), "Number of changes: {}", stats.num_changes)?;
writeln!(ui.stdout(), "Stats per level:")?;
for (i, level) in stats.levels.iter().enumerate() {
writeln!(ui.stdout(), " Level {i}:")?;
writeln!(ui.stdout(), " Number of commits: {}", level.num_commits)?;
writeln!(ui.stdout(), " Name: {}", level.name.as_ref().unwrap())?;
}
} else {
return Err(user_error(format!(
"Cannot get stats for indexes of type '{}'",
index_store.name()
)));
}
Ok(())
}
83 changes: 83 additions & 0 deletions cli/src/commands/debug/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright 2023 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod fileset;
pub mod index;
pub mod operation;
pub mod reindex;
pub mod revset;
pub mod template;
pub mod tree;
pub mod watchman;
pub mod working_copy;

use std::any::Any;
use std::fmt::Debug;

use clap::Subcommand;
use jj_lib::local_working_copy::LocalWorkingCopy;

use self::fileset::{cmd_debug_fileset, FilesetArgs};
use self::index::{cmd_debug_index, IndexArgs};
use self::operation::{cmd_debug_operation, OperationArgs};
use self::reindex::{cmd_debug_reindex, ReindexArgs};
use self::revset::{cmd_debug_revset, RevsetArgs};
use self::template::{cmd_debug_template, TemplateArgs};
use self::tree::{cmd_debug_tree, TreeArgs};
use self::watchman::{cmd_debug_watchman, WatchmanCommand};
use self::working_copy::{cmd_debug_working_copy, WorkingCopyArgs};
use crate::cli_util::CommandHelper;
use crate::command_error::{user_error, CommandError};
use crate::ui::Ui;

/// Low-level commands not intended for users
#[derive(Subcommand, Clone, Debug)]
#[command(hide = true)]
pub enum DebugCommand {
Fileset(FilesetArgs),
Revset(RevsetArgs),
#[command(name = "workingcopy")]
WorkingCopy(WorkingCopyArgs),
Template(TemplateArgs),
Index(IndexArgs),
Reindex(ReindexArgs),
#[command(visible_alias = "view")]
Operation(OperationArgs),
Tree(TreeArgs),
#[command(subcommand)]
Watchman(WatchmanCommand),
}

pub fn cmd_debug(
ui: &mut Ui,
command: &CommandHelper,
subcommand: &DebugCommand,
) -> Result<(), CommandError> {
match subcommand {
DebugCommand::Fileset(args) => cmd_debug_fileset(ui, command, args),
DebugCommand::Revset(args) => cmd_debug_revset(ui, command, args),
DebugCommand::WorkingCopy(args) => cmd_debug_working_copy(ui, command, args),
DebugCommand::Template(args) => cmd_debug_template(ui, command, args),
DebugCommand::Index(args) => cmd_debug_index(ui, command, args),
DebugCommand::Reindex(args) => cmd_debug_reindex(ui, command, args),
DebugCommand::Operation(args) => cmd_debug_operation(ui, command, args),
DebugCommand::Tree(args) => cmd_debug_tree(ui, command, args),
DebugCommand::Watchman(args) => cmd_debug_watchman(ui, command, args),
}
}

fn check_local_disk_wc(x: &dyn Any) -> Result<&LocalWorkingCopy, CommandError> {
x.downcast_ref()
.ok_or_else(|| user_error("This command requires a standard local-disk working copy"))
}
67 changes: 67 additions & 0 deletions cli/src/commands/debug/operation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2023 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt::Debug;
use std::io::Write as _;

use jj_lib::object_id::ObjectId;
use jj_lib::op_walk;

use crate::cli_util::CommandHelper;
use crate::command_error::CommandError;
use crate::ui::Ui;

/// Show information about an operation and its view
#[derive(clap::Args, Clone, Debug)]
pub struct OperationArgs {
#[arg(default_value = "@")]
operation: String,
#[arg(long, value_enum, default_value = "all")]
display: OperationDisplay,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)]
pub enum OperationDisplay {
/// Show only the operation details.
Operation,
/// Show the operation id only
Id,
/// Show only the view details
View,
/// Show both the view and the operation
All,
}

pub fn cmd_debug_operation(
ui: &mut Ui,
command: &CommandHelper,
args: &OperationArgs,
) -> Result<(), CommandError> {
// Resolve the operation without loading the repo, so this command can be used
// even if e.g. the view object is broken.
let workspace = command.load_workspace()?;
let repo_loader = workspace.repo_loader();
let op = op_walk::resolve_op_for_load(repo_loader, &args.operation)?;
if args.display == OperationDisplay::Id {
writeln!(ui.stdout(), "{}", op.id().hex())?;
return Ok(());
}
if args.display != OperationDisplay::View {
writeln!(ui.stdout(), "{:#?}", op.store_operation())?;
}
if args.display != OperationDisplay::Operation {
writeln!(ui.stdout(), "{:#?}", op.view()?.store_view())?;
}
Ok(())
}
57 changes: 57 additions & 0 deletions cli/src/commands/debug/reindex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2023 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt::Debug;
use std::io::Write as _;

use jj_lib::default_index::{AsCompositeIndex as _, DefaultIndexStore};
use jj_lib::op_walk;

use crate::cli_util::CommandHelper;
use crate::command_error::{internal_error, user_error, CommandError};
use crate::ui::Ui;

/// Rebuild commit index
#[derive(clap::Args, Clone, Debug)]
pub struct ReindexArgs {}

pub fn cmd_debug_reindex(
ui: &mut Ui,
command: &CommandHelper,
_args: &ReindexArgs,
) -> Result<(), CommandError> {
// Resolve the operation without loading the repo. The index might have to
// be rebuilt while loading the repo.
let workspace = command.load_workspace()?;
let repo_loader = workspace.repo_loader();
let op = op_walk::resolve_op_for_load(repo_loader, &command.global_args().at_operation)?;
let index_store = repo_loader.index_store();
if let Some(default_index_store) = index_store.as_any().downcast_ref::<DefaultIndexStore>() {
default_index_store.reinit().map_err(internal_error)?;
let default_index = default_index_store
.build_index_at_operation(&op, repo_loader.store())
.map_err(internal_error)?;
writeln!(
ui.status(),
"Finished indexing {:?} commits.",
default_index.as_composite().stats().num_commits
)?;
} else {
return Err(user_error(format!(
"Cannot reindex indexes of type '{}'",
index_store.name()
)));
}
Ok(())
}
71 changes: 71 additions & 0 deletions cli/src/commands/debug/revset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2023 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt::Debug;
use std::io::Write as _;

use jj_lib::object_id::ObjectId;
use jj_lib::revset;

use crate::cli_util::CommandHelper;
use crate::command_error::CommandError;
use crate::revset_util;
use crate::ui::Ui;

/// Evaluate revset to full commit IDs
#[derive(clap::Args, Clone, Debug)]
pub struct RevsetArgs {
revision: String,
}

pub fn cmd_debug_revset(
ui: &mut Ui,
command: &CommandHelper,
args: &RevsetArgs,
) -> Result<(), CommandError> {
let workspace_command = command.workspace_helper(ui)?;
let workspace_ctx = workspace_command.revset_parse_context();
let repo = workspace_command.repo().as_ref();

let expression = revset::parse(&args.revision, &workspace_ctx)?;
writeln!(ui.stdout(), "-- Parsed:")?;
writeln!(ui.stdout(), "{expression:#?}")?;
writeln!(ui.stdout())?;

let expression = revset::optimize(expression);
writeln!(ui.stdout(), "-- Optimized:")?;
writeln!(ui.stdout(), "{expression:#?}")?;
writeln!(ui.stdout())?;

let symbol_resolver = revset_util::default_symbol_resolver(
repo,
command.revset_extensions().symbol_resolvers(),
workspace_command.id_prefix_context()?,
);
let expression = expression.resolve_user_expression(repo, &symbol_resolver)?;
writeln!(ui.stdout(), "-- Resolved:")?;
writeln!(ui.stdout(), "{expression:#?}")?;
writeln!(ui.stdout())?;

let revset = expression.evaluate(repo)?;
writeln!(ui.stdout(), "-- Evaluated:")?;
writeln!(ui.stdout(), "{revset:#?}")?;
writeln!(ui.stdout())?;

writeln!(ui.stdout(), "-- Commit IDs:")?;
for commit_id in revset.iter() {
writeln!(ui.stdout(), "{}", commit_id.hex())?;
}
Ok(())
}
Loading

0 comments on commit bbe7162

Please sign in to comment.