Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[red-knot] Add verbosity argument to CLI #12404

Merged
merged 3 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
[red-knot] Add verbosity argument to CLI
  • Loading branch information
MichaReiser committed Jul 19, 2024
commit 3bd767a1721e599aceb7ca03d5c785891ba1949a
2 changes: 2 additions & 0 deletions crates/red_knot/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub(crate) mod target_version;
pub(crate) mod verbosity;
30 changes: 30 additions & 0 deletions crates/red_knot/src/cli/verbosity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) enum VerbosityLevel {
Info,
Debug,
Trace,
}

/// Logging flags to `#[command(flatten)]` into your CLI
#[derive(clap::Args, Debug, Clone, Default)]
#[command(about = None, long_about = None)]
pub(crate) struct Verbosity {
#[arg(
long,
short = 'v',
action = clap::ArgAction::Count,
global = true,
)]
verbose: u8,
}

impl Verbosity {
pub(crate) fn level(&self) -> Option<VerbosityLevel> {
match self.verbose {
0 => None,
1 => Some(VerbosityLevel::Info),
2 => Some(VerbosityLevel::Debug),
_ => Some(VerbosityLevel::Trace),
}
}
}
79 changes: 48 additions & 31 deletions crates/red_knot/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ use red_knot::workspace::WorkspaceMetadata;
use ruff_db::program::{ProgramSettings, SearchPathSettings};
use ruff_db::system::{OsSystem, System, SystemPathBuf};

use self::target_version::TargetVersion;
use cli::target_version::TargetVersion;
use cli::verbosity::{Verbosity, VerbosityLevel};

mod target_version;
mod cli;

#[derive(Debug, Parser)]
#[command(
Expand All @@ -43,14 +44,19 @@ struct Args {
help = "Custom directory to use for stdlib typeshed stubs"
)]
custom_typeshed_dir: Option<SystemPathBuf>,

#[arg(
long,
value_name = "PATH",
help = "Additional path to use as a module-resolution source (can be passed multiple times)"
)]
extra_search_path: Vec<SystemPathBuf>,

#[arg(long, help = "Python version to assume when resolving types", default_value_t = TargetVersion::default(), value_name="VERSION")]
target_version: TargetVersion,

#[clap(flatten)]
verbosity: Verbosity,
}

#[allow(
Expand All @@ -60,16 +66,18 @@ struct Args {
clippy::dbg_macro
)]
pub fn main() -> anyhow::Result<()> {
countme::enable(true);
setup_tracing();

let Args {
current_directory,
custom_typeshed_dir,
extra_search_path: extra_paths,
target_version,
verbosity,
} = Args::parse_from(std::env::args().collect::<Vec<_>>());

let verbosity = verbosity.level();
countme::enable(verbosity == Some(VerbosityLevel::Trace));
setup_tracing(verbosity);

let cwd = if let Some(cwd) = current_directory {
let canonicalized = cwd.as_utf8_path().canonicalize_utf8().unwrap();
SystemPathBuf::from_utf8_path_buf(canonicalized)
Expand Down Expand Up @@ -97,7 +105,7 @@ pub fn main() -> anyhow::Result<()> {
// cache and load the cache if it exists.
let mut db = RootDatabase::new(workspace_metadata, program_settings, system);

let (main_loop, main_loop_cancellation_token) = MainLoop::new();
let (main_loop, main_loop_cancellation_token) = MainLoop::new(verbosity);

// Listen to Ctrl+C and abort the watch mode.
let main_loop_cancellation_token = Mutex::new(Some(main_loop_cancellation_token));
Expand Down Expand Up @@ -126,18 +134,19 @@ pub fn main() -> anyhow::Result<()> {
}

struct MainLoop {
orchestrator_sender: crossbeam_channel::Sender<OrchestratorMessage>,
main_loop_receiver: crossbeam_channel::Receiver<MainLoopMessage>,
verbosity: Option<VerbosityLevel>,
orchestrator: crossbeam_channel::Sender<OrchestratorMessage>,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the renames but clippy became very angry at me and told me that the old name was a bad name.

receiver: crossbeam_channel::Receiver<MainLoopMessage>,
}

impl MainLoop {
fn new() -> (Self, MainLoopCancellationToken) {
fn new(verbosity: Option<VerbosityLevel>) -> (Self, MainLoopCancellationToken) {
let (orchestrator_sender, orchestrator_receiver) = crossbeam_channel::bounded(1);
let (main_loop_sender, main_loop_receiver) = crossbeam_channel::bounded(1);

let mut orchestrator = Orchestrator {
receiver: orchestrator_receiver,
sender: main_loop_sender.clone(),
main_loop: main_loop_sender.clone(),
revision: 0,
};

Expand All @@ -147,8 +156,9 @@ impl MainLoop {

(
Self {
orchestrator_sender,
main_loop_receiver,
verbosity,
orchestrator: orchestrator_sender,
receiver: main_loop_receiver,
},
MainLoopCancellationToken {
sender: main_loop_sender,
Expand All @@ -158,29 +168,27 @@ impl MainLoop {

fn file_changes_notifier(&self) -> FileChangesNotifier {
FileChangesNotifier {
sender: self.orchestrator_sender.clone(),
sender: self.orchestrator.clone(),
}
}

#[allow(clippy::print_stderr)]
fn run(self, db: &mut RootDatabase) {
self.orchestrator_sender
.send(OrchestratorMessage::Run)
.unwrap();
self.orchestrator.send(OrchestratorMessage::Run).unwrap();

for message in &self.main_loop_receiver {
for message in &self.receiver {
tracing::trace!("Main Loop: Tick");

match message {
MainLoopMessage::CheckWorkspace { revision } => {
let db = db.snapshot();
let sender = self.orchestrator_sender.clone();
let orchestrator = self.orchestrator.clone();

// Spawn a new task that checks the workspace. This needs to be done in a separate thread
// to prevent blocking the main loop here.
rayon::spawn(move || {
if let Ok(result) = db.check() {
sender
orchestrator
.send(OrchestratorMessage::CheckCompleted {
diagnostics: result,
revision,
Expand All @@ -195,10 +203,14 @@ impl MainLoop {
}
MainLoopMessage::CheckCompleted(diagnostics) => {
eprintln!("{}", diagnostics.join("\n"));
eprintln!("{}", countme::get_all());
if self.verbosity == Some(VerbosityLevel::Trace) {
eprintln!("{}", countme::get_all());
}
}
MainLoopMessage::Exit => {
eprintln!("{}", countme::get_all());
if self.verbosity == Some(VerbosityLevel::Trace) {
eprintln!("{}", countme::get_all());
}
return;
}
}
Expand All @@ -208,7 +220,7 @@ impl MainLoop {

impl Drop for MainLoop {
fn drop(&mut self) {
self.orchestrator_sender
self.orchestrator
.send(OrchestratorMessage::Shutdown)
.unwrap();
}
Expand Down Expand Up @@ -240,7 +252,7 @@ impl MainLoopCancellationToken {

struct Orchestrator {
/// Sends messages to the main loop.
sender: crossbeam_channel::Sender<MainLoopMessage>,
main_loop: crossbeam_channel::Sender<MainLoopMessage>,
/// Receives messages from the main loop.
receiver: crossbeam_channel::Receiver<OrchestratorMessage>,
revision: usize,
Expand All @@ -252,7 +264,7 @@ impl Orchestrator {
while let Ok(message) = self.receiver.recv() {
match message {
OrchestratorMessage::Run => {
self.sender
self.main_loop
.send(MainLoopMessage::CheckWorkspace {
revision: self.revision,
})
Expand All @@ -265,7 +277,7 @@ impl Orchestrator {
} => {
// Only take the diagnostics if they are for the latest revision.
if self.revision == revision {
self.sender
self.main_loop
.send(MainLoopMessage::CheckCompleted(diagnostics))
.unwrap();
} else {
Expand Down Expand Up @@ -313,8 +325,8 @@ impl Orchestrator {
},
default(std::time::Duration::from_millis(10)) => {
// No more file changes after 10 ms, send the changes and schedule a new analysis
self.sender.send(MainLoopMessage::ApplyChanges(changes)).unwrap();
self.sender.send(MainLoopMessage::CheckWorkspace { revision: self.revision}).unwrap();
self.main_loop.send(MainLoopMessage::ApplyChanges(changes)).unwrap();
self.main_loop.send(MainLoopMessage::CheckWorkspace { revision: self.revision}).unwrap();
return;
}
}
Expand Down Expand Up @@ -349,7 +361,14 @@ enum OrchestratorMessage {
FileChanges(Vec<FileWatcherChange>),
}

fn setup_tracing() {
fn setup_tracing(verbosity: Option<VerbosityLevel>) {
let trace_level = match verbosity {
None => Level::WARN,
Some(VerbosityLevel::Info) => Level::INFO,
Some(VerbosityLevel::Debug) => Level::DEBUG,
Some(VerbosityLevel::Trace) => Level::TRACE,
};

let subscriber = Registry::default().with(
tracing_tree::HierarchicalLayer::default()
.with_indent_lines(true)
Expand All @@ -359,9 +378,7 @@ fn setup_tracing() {
.with_targets(true)
.with_writer(|| Box::new(std::io::stderr()))
.with_timer(Uptime::default())
.with_filter(LoggingFilter {
trace_level: Level::TRACE,
}),
.with_filter(LoggingFilter { trace_level }),
);

tracing::subscriber::set_global_default(subscriber).unwrap();
Expand Down
6 changes: 3 additions & 3 deletions crates/red_knot_module_resolver/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,11 @@ pub(crate) fn module_resolution_settings(db: &dyn Db) -> ModuleResolutionSetting
} = program.search_paths(db.upcast());

if let Some(custom_typeshed) = custom_typeshed {
tracing::debug!("Custom typeshed directory: {custom_typeshed}");
tracing::info!("Custom typeshed directory: {custom_typeshed}");
}

if !extra_paths.is_empty() {
tracing::debug!("extra search paths: {extra_paths:?}");
tracing::info!("extra search paths: {extra_paths:?}");
}

let current_directory = db.system().current_directory();
Expand Down Expand Up @@ -174,7 +174,7 @@ pub(crate) fn module_resolution_settings(db: &dyn Db) -> ModuleResolutionSetting
// TODO vendor typeshed's third-party stubs as well as the stdlib and fallback to them as a final step

let target_version = program.target_version(db.upcast());
tracing::debug!("Target version: {target_version}");
tracing::info!("Target version: {target_version}");

// Filter out module resolution paths that point to the same directory on disk (the same invariant maintained by [`sys.path` at runtime]).
// (Paths may, however, *overlap* -- e.g. you could have both `src/` and `src/foo`
Expand Down
4 changes: 2 additions & 2 deletions crates/ruff_db/src/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl Files {
///
/// The operation always succeeds even if the path doesn't exist on disk, isn't accessible or if the path points to a directory.
/// In these cases, a file with status [`FileStatus::Deleted`] is returned.
#[tracing::instrument(level = "debug", skip(self, db), ret)]
#[tracing::instrument(level = "trace", skip(self, db), ret)]
fn system(&self, db: &dyn Db, path: &SystemPath) -> File {
let absolute = SystemPath::absolute(path, db.system().current_directory());
let absolute = FilePath::System(absolute);
Expand Down Expand Up @@ -102,7 +102,7 @@ impl Files {

/// Looks up a vendored file by its path. Returns `Some` if a vendored file for the given path
/// exists and `None` otherwise.
#[tracing::instrument(level = "debug", skip(self, db), ret)]
#[tracing::instrument(level = "trace", skip(self, db), ret)]
fn vendored(&self, db: &dyn Db, path: &VendoredPath) -> Option<File> {
let file = match self
.inner
Expand Down
Loading