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

Make --config and --isolated global flags #10150

Merged
merged 19 commits into from
Mar 4, 2024
Merged
Changes from 16 commits
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
163 changes: 90 additions & 73 deletions crates/ruff/src/args.rs
Original file line number Diff line number Diff line change
@@ -28,6 +28,64 @@ use ruff_workspace::configuration::{Configuration, RuleSelection};
use ruff_workspace::options::{Options, PycodestyleOptions};
use ruff_workspace::resolver::ConfigurationTransformer;

/// All configuration options that can be passed "globally",
/// i.e., can be passed to all subcommands
#[derive(Debug, Default, Clone, clap::Args)]
pub struct GlobalConfigArgs {
#[clap(flatten)]
AlexWaygood marked this conversation as resolved.
Show resolved Hide resolved
log_level_args: LogLevelArgs,
/// Either a path to a TOML configuration file (`pyproject.toml` or `ruff.toml`),
/// or a TOML `<KEY> = <VALUE>` pair
/// (such as you might find in a `ruff.toml` configuration file)
/// overriding a specific configuration option.
/// Overrides of individual settings using this option always take precedence
/// over all configuration files, including configuration files that were also
/// specified using `--config`.
#[arg(
long,
action = clap::ArgAction::Append,
value_name = "CONFIG_OPTION",
value_parser = ConfigArgumentParser,
global = true,
MichaReiser marked this conversation as resolved.
Show resolved Hide resolved
help_heading = "Global options",
)]
pub config: Vec<SingleConfigArgument>,
/// Ignore all configuration files.
//
// Note: We can't mark this as conflicting with `--config` here
// as `--config` can be used for specifying configuration overrides
// as well as configuration files.
// Specifying a configuration file conflicts with `--isolated`;
// specifying a configuration override does not.
// If a user specifies `ruff check --isolated --config=ruff.toml`,
// we emit an error later on, after the initial parsing by clap.
#[arg(long, help_heading = "Global options", global = true)]
pub isolated: bool,
}

impl GlobalConfigArgs {
pub fn new(
AlexWaygood marked this conversation as resolved.
Show resolved Hide resolved
log_level_args: LogLevelArgs,
config_flags: Vec<SingleConfigArgument>,
isolated: bool,
) -> Self {
Self {
log_level_args,
config: config_flags,
isolated,
}
}

pub fn log_level(&self) -> LogLevel {
LogLevel::from(&self.log_level_args)
}

#[must_use]
fn partition(self) -> (LogLevel, Vec<SingleConfigArgument>, bool) {
(self.log_level(), self.config, self.isolated)
}
}

#[derive(Debug, Parser)]
#[command(
author,
@@ -38,9 +96,9 @@ use ruff_workspace::resolver::ConfigurationTransformer;
#[command(version)]
pub struct Args {
#[command(subcommand)]
pub command: Command,
pub(crate) command: Command,
#[clap(flatten)]
pub log_level_args: LogLevelArgs,
pub(crate) global_options: GlobalConfigArgs,
}

#[allow(clippy::large_enum_variant)]
@@ -161,20 +219,6 @@ pub struct CheckCommand {
preview: bool,
#[clap(long, overrides_with("preview"), hide = true)]
no_preview: bool,
/// Either a path to a TOML configuration file (`pyproject.toml` or `ruff.toml`),
/// or a TOML `<KEY> = <VALUE>` pair
/// (such as you might find in a `ruff.toml` configuration file)
/// overriding a specific configuration option.
/// Overrides of individual settings using this option always take precedence
/// over all configuration files, including configuration files that were also
/// specified using `--config`.
#[arg(
long,
action = clap::ArgAction::Append,
value_name = "CONFIG_OPTION",
value_parser = ConfigArgumentParser,
)]
pub config: Vec<SingleConfigArgument>,
/// Comma-separated list of rule codes to enable (or ALL, to enable all rules).
#[arg(
long,
@@ -306,17 +350,6 @@ pub struct CheckCommand {
/// Disable cache reads.
#[arg(short, long, env = "RUFF_NO_CACHE", help_heading = "Miscellaneous")]
pub no_cache: bool,
/// Ignore all configuration files.
//
// Note: We can't mark this as conflicting with `--config` here
// as `--config` can be used for specifying configuration overrides
// as well as configuration files.
// Specifying a configuration file conflicts with `--isolated`;
// specifying a configuration override does not.
// If a user specifies `ruff check --isolated --config=ruff.toml`,
// we emit an error later on, after the initial parsing by clap.
#[arg(long, help_heading = "Miscellaneous")]
pub isolated: bool,
/// Path to the cache directory.
#[arg(long, env = "RUFF_CACHE_DIR", help_heading = "Miscellaneous")]
pub cache_dir: Option<PathBuf>,
@@ -408,20 +441,6 @@ pub struct FormatCommand {
/// difference between the current file and how the formatted file would look like.
#[arg(long)]
pub diff: bool,
/// Either a path to a TOML configuration file (`pyproject.toml` or `ruff.toml`),
/// or a TOML `<KEY> = <VALUE>` pair
/// (such as you might find in a `ruff.toml` configuration file)
/// overriding a specific configuration option.
/// Overrides of individual settings using this option always take precedence
/// over all configuration files, including configuration files that were also
/// specified using `--config`.
#[arg(
long,
action = clap::ArgAction::Append,
value_name = "CONFIG_OPTION",
value_parser = ConfigArgumentParser,
)]
pub config: Vec<SingleConfigArgument>,

/// Disable cache reads.
#[arg(short, long, env = "RUFF_NO_CACHE", help_heading = "Miscellaneous")]
@@ -462,17 +481,6 @@ pub struct FormatCommand {
/// Set the line-length.
#[arg(long, help_heading = "Format configuration")]
pub line_length: Option<LineLength>,
/// Ignore all configuration files.
//
// Note: We can't mark this as conflicting with `--config` here
// as `--config` can be used for specifying configuration overrides
// as well as configuration files.
// Specifying a configuration file conflicts with `--isolated`;
// specifying a configuration override does not.
// If a user specifies `ruff check --isolated --config=ruff.toml`,
// we emit an error later on, after the initial parsing by clap.
#[arg(long, help_heading = "Miscellaneous")]
pub isolated: bool,
/// The name of the file when passing it through stdin.
#[arg(long, help_heading = "Miscellaneous")]
pub stdin_filename: Option<PathBuf>,
@@ -513,7 +521,7 @@ pub enum HelpFormat {
}

#[allow(clippy::module_name_repetitions)]
#[derive(Debug, clap::Args)]
#[derive(Debug, Default, Clone, clap::Args)]
pub struct LogLevelArgs {
/// Enable verbose logging.
#[arg(
@@ -561,6 +569,10 @@ impl From<&LogLevelArgs> for LogLevel {
/// Configuration-related arguments passed via the CLI.
#[derive(Default)]
pub struct ConfigArguments {
/// Whether the user specified --isolated on the command line
pub(crate) isolated: bool,
/// The logging level to be used, derived from command-line arguments passed
pub(crate) log_level: LogLevel,
/// Path to a pyproject.toml or ruff.toml configuration file (etc.).
/// Either 0 or 1 configuration file paths may be provided on the command line.
config_file: Option<PathBuf>,
@@ -581,21 +593,19 @@ impl ConfigArguments {
}

fn from_cli_arguments(
config_options: Vec<SingleConfigArgument>,
global_options: GlobalConfigArgs,
per_flag_overrides: ExplicitConfigOverrides,
isolated: bool,
) -> anyhow::Result<Self> {
let mut new = Self {
per_flag_overrides,
..Self::default()
};
let (log_level, config_options, isolated) = global_options.partition();
let mut config_file: Option<PathBuf> = None;
let mut overrides = Configuration::default();

for option in config_options {
match option {
SingleConfigArgument::SettingsOverride(overridden_option) => {
let overridden_option = Arc::try_unwrap(overridden_option)
.unwrap_or_else(|option| option.deref().clone());
new.overrides = new.overrides.combine(Configuration::from_options(
overrides = overrides.combine(Configuration::from_options(
overridden_option,
None,
&path_dedot::CWD,
@@ -614,7 +624,7 @@ The argument `--config={}` cannot be used with `--isolated`
path.display()
);
}
if let Some(ref config_file) = new.config_file {
if let Some(ref config_file) = config_file {
let (first, second) = (config_file.display(), path.display());
bail!(
"\
@@ -625,11 +635,17 @@ You cannot specify more than one configuration file on the command line.
"
);
}
new.config_file = Some(path);
config_file = Some(path);
}
}
}
Ok(new)
Ok(Self {
isolated,
log_level,
config_file,
overrides,
per_flag_overrides,
})
}
}

@@ -643,7 +659,10 @@ impl ConfigurationTransformer for ConfigArguments {
impl CheckCommand {
/// Partition the CLI into command-line arguments and configuration
/// overrides.
pub fn partition(self) -> anyhow::Result<(CheckArguments, ConfigArguments)> {
pub fn partition(
self,
global_options: GlobalConfigArgs,
) -> anyhow::Result<(CheckArguments, ConfigArguments)> {
let check_arguments = CheckArguments {
add_noqa: self.add_noqa,
diff: self.diff,
@@ -652,7 +671,6 @@ impl CheckCommand {
exit_zero: self.exit_zero,
files: self.files,
ignore_noqa: self.ignore_noqa,
isolated: self.isolated,
no_cache: self.no_cache,
output_file: self.output_file,
show_files: self.show_files,
@@ -696,21 +714,22 @@ impl CheckCommand {
extension: self.extension,
};

let config_args =
ConfigArguments::from_cli_arguments(self.config, cli_overrides, self.isolated)?;
let config_args = ConfigArguments::from_cli_arguments(global_options, cli_overrides)?;
Ok((check_arguments, config_args))
}
}

impl FormatCommand {
/// Partition the CLI into command-line arguments and configuration
/// overrides.
pub fn partition(self) -> anyhow::Result<(FormatArguments, ConfigArguments)> {
pub fn partition(
self,
global_options: GlobalConfigArgs,
) -> anyhow::Result<(FormatArguments, ConfigArguments)> {
let format_arguments = FormatArguments {
check: self.check,
diff: self.diff,
files: self.files,
isolated: self.isolated,
no_cache: self.no_cache,
stdin_filename: self.stdin_filename,
range: self.range,
@@ -730,8 +749,8 @@ impl FormatCommand {
..ExplicitConfigOverrides::default()
};

let config_args =
ConfigArguments::from_cli_arguments(self.config, cli_overrides, self.isolated)?;
let config_args = ConfigArguments::from_cli_arguments(global_options, cli_overrides)?;

Ok((format_arguments, config_args))
}
}
@@ -957,7 +976,6 @@ pub struct CheckArguments {
pub exit_zero: bool,
pub files: Vec<PathBuf>,
pub ignore_noqa: bool,
pub isolated: bool,
pub no_cache: bool,
pub output_file: Option<PathBuf>,
pub show_files: bool,
@@ -975,7 +993,6 @@ pub struct FormatArguments {
pub no_cache: bool,
pub diff: bool,
pub files: Vec<PathBuf>,
pub isolated: bool,
pub stdin_filename: Option<PathBuf>,
pub range: Option<FormatRange>,
}
9 changes: 2 additions & 7 deletions crates/ruff/src/commands/format.rs
Original file line number Diff line number Diff line change
@@ -61,13 +61,8 @@ impl FormatMode {
pub(crate) fn format(
cli: FormatArguments,
config_arguments: &ConfigArguments,
log_level: LogLevel,
) -> Result<ExitStatus> {
let pyproject_config = resolve(
cli.isolated,
config_arguments,
cli.stdin_filename.as_deref(),
)?;
let pyproject_config = resolve(config_arguments, cli.stdin_filename.as_deref())?;
let mode = FormatMode::from_cli(&cli);
let files = resolve_default_files(cli.files, false);
let (paths, resolver) = python_files_in_path(&files, &pyproject_config, config_arguments)?;
@@ -202,7 +197,7 @@ pub(crate) fn format(
}

// Report on the formatting changes.
if log_level >= LogLevel::Default {
if config_arguments.log_level >= LogLevel::Default {
if mode.is_diff() {
// Allow piping the diff to e.g. a file by writing the summary to stderr
results.write_summary(&mut stderr().lock())?;
6 changes: 1 addition & 5 deletions crates/ruff/src/commands/format_stdin.rs
Original file line number Diff line number Diff line change
@@ -23,11 +23,7 @@ pub(crate) fn format_stdin(
cli: &FormatArguments,
config_arguments: &ConfigArguments,
) -> Result<ExitStatus> {
let pyproject_config = resolve(
cli.isolated,
config_arguments,
cli.stdin_filename.as_deref(),
)?;
let pyproject_config = resolve(config_arguments, cli.stdin_filename.as_deref())?;

let mut resolver = Resolver::new(&pyproject_config);
warn_incompatible_formatter_settings(&resolver);
39 changes: 16 additions & 23 deletions crates/ruff/src/lib.rs
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ use std::process::ExitCode;
use std::sync::mpsc::channel;

use anyhow::Result;
use args::GlobalConfigArgs;
use clap::CommandFactory;
use colored::Colorize;
use log::warn;
@@ -126,7 +127,7 @@ fn resolve_help_output_format(output_format: HelpFormat, format: Option<HelpForm
pub fn run(
Args {
command,
log_level_args,
global_options,
}: Args,
) -> Result<ExitStatus> {
{
@@ -155,8 +156,7 @@ pub fn run(
#[cfg(windows)]
assert!(colored::control::set_virtual_terminal(true).is_ok());

let log_level = LogLevel::from(&log_level_args);
set_up_logging(&log_level)?;
set_up_logging(global_options.log_level())?;

match command {
Command::Version { output_format } => {
@@ -191,38 +191,34 @@ pub fn run(
Ok(ExitStatus::Success)
}
Command::Clean => {
commands::clean::clean(log_level)?;
commands::clean::clean(global_options.log_level())?;
Ok(ExitStatus::Success)
}
Command::GenerateShellCompletion { shell } => {
shell.generate(&mut Args::command(), &mut stdout());
Ok(ExitStatus::Success)
}
Command::Check(args) => check(args, log_level),
Command::Format(args) => format(args, log_level),
Command::Check(args) => check(args, global_options),
Command::Format(args) => format(args, global_options),
}
}

fn format(args: FormatCommand, log_level: LogLevel) -> Result<ExitStatus> {
let (cli, config_arguments) = args.partition()?;
fn format(args: FormatCommand, global_options: GlobalConfigArgs) -> Result<ExitStatus> {
let (cli, config_arguments) = args.partition(global_options)?;

if is_stdin(&cli.files, cli.stdin_filename.as_deref()) {
commands::format_stdin::format_stdin(&cli, &config_arguments)
} else {
commands::format::format(cli, &config_arguments, log_level)
commands::format::format(cli, &config_arguments)
}
}

pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
let (cli, config_arguments) = args.partition()?;
pub fn check(args: CheckCommand, global_options: GlobalConfigArgs) -> Result<ExitStatus> {
let (cli, config_arguments) = args.partition(global_options)?;

// Construct the "default" settings. These are used when no `pyproject.toml`
// files are present, or files are injected from outside of the hierarchy.
let pyproject_config = resolve::resolve(
cli.isolated,
&config_arguments,
cli.stdin_filename.as_deref(),
)?;
let pyproject_config = resolve::resolve(&config_arguments, cli.stdin_filename.as_deref())?;

let mut writer: Box<dyn Write> = match cli.output_file {
Some(path) if !cli.watch => {
@@ -313,7 +309,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
}
let modifications =
commands::add_noqa::add_noqa(&files, &pyproject_config, &config_arguments)?;
if modifications > 0 && log_level >= LogLevel::Default {
if modifications > 0 && config_arguments.log_level >= LogLevel::Default {
let s = if modifications == 1 { "" } else { "s" };
#[allow(clippy::print_stderr)]
{
@@ -325,7 +321,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {

let printer = Printer::new(
output_format,
log_level,
config_arguments.log_level,
fix_mode,
unsafe_fixes,
printer_flags,
@@ -382,11 +378,8 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
};

if matches!(change_kind, ChangeKind::Configuration) {
pyproject_config = resolve::resolve(
cli.isolated,
&config_arguments,
cli.stdin_filename.as_deref(),
)?;
pyproject_config =
resolve::resolve(&config_arguments, cli.stdin_filename.as_deref())?;
}
Printer::clear_screen()?;
printer.write_to_user("File change detected...\n");
3 changes: 1 addition & 2 deletions crates/ruff/src/resolve.rs
Original file line number Diff line number Diff line change
@@ -16,12 +16,11 @@ use crate::args::ConfigArguments;
/// Resolve the relevant settings strategy and defaults for the current
/// invocation.
pub fn resolve(
isolated: bool,
config_arguments: &ConfigArguments,
stdin_filename: Option<&Path>,
) -> Result<PyprojectConfig> {
// First priority: if we're running in isolated mode, use the default settings.
if isolated {
if config_arguments.isolated {
let config = config_arguments.transform(Configuration::default());
let settings = config.into_settings(&path_dedot::CWD)?;
debug!("Isolated mode, not reading any pyproject.toml");
105 changes: 105 additions & 0 deletions crates/ruff/tests/version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//! Tests the --version command
use std::fs;
use std::process::Command;

use anyhow::Result;
use insta_cmd::{assert_cmd_snapshot, get_cargo_bin};
use tempfile::TempDir;

const BIN_NAME: &str = "ruff";
const VERSION_FILTER: [(&str, &str); 1] = [(
r"\d+\.\d+\.\d+(\+\d+)?( \(\w{9} \d\d\d\d-\d\d-\d\d\))?",
"[VERSION]",
)];

#[test]
fn version_basics() {
insta::with_settings!({filters => VERSION_FILTER.to_vec()}, {
assert_cmd_snapshot!(
Command::new(get_cargo_bin(BIN_NAME)).arg("version"), @r###"
success: true
exit_code: 0
----- stdout -----
ruff [VERSION]
----- stderr -----
"###
);
});
}

/// `--config` is a global option,
/// so it's allowed to pass --config to subcommands such as `version`
/// -- the flag is simply ignored
#[test]
fn config_option_allowed_but_ignored() -> Result<()> {
let tempdir = TempDir::new()?;
let ruff_dot_toml = tempdir.path().join("ruff.toml");
fs::File::create(&ruff_dot_toml)?;
insta::with_settings!({filters => VERSION_FILTER.to_vec()}, {
assert_cmd_snapshot!(
Command::new(get_cargo_bin(BIN_NAME))
.arg("version")
.arg("--config")
.arg(&ruff_dot_toml)
.args(["--config", "lint.isort.extra-standard-library = ['foo', 'bar']"]), @r###"
success: true
exit_code: 0
----- stdout -----
ruff [VERSION]
----- stderr -----
"###
);
});
Ok(())
}
#[test]
fn config_option_ignored_but_validated() {
insta::with_settings!({filters => VERSION_FILTER.to_vec()}, {
assert_cmd_snapshot!(
Command::new(get_cargo_bin(BIN_NAME))
.arg("version")
.args(["--config", "foo = bar"]), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: invalid value 'foo = bar' for '--config <CONFIG_OPTION>'
tip: A `--config` flag must either be a path to a `.toml` configuration file
or a TOML `<KEY> = <VALUE>` pair overriding a specific configuration
option
The supplied argument is not valid TOML:
TOML parse error at line 1, column 7
|
1 | foo = bar
| ^
invalid string
expected `"`, `'`
For more information, try '--help'.
"###
);
});
}

/// `--isolated` is also a global option,
#[test]
fn isolated_option_allowed() {
insta::with_settings!({filters => VERSION_FILTER.to_vec()}, {
assert_cmd_snapshot!(
Command::new(get_cargo_bin(BIN_NAME)).arg("version").arg("--isolated"), @r###"
success: true
exit_code: 0
----- stdout -----
ruff [VERSION]
----- stderr -----
"###
);
});
}
10 changes: 3 additions & 7 deletions crates/ruff_dev/src/format_dev.rs
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@ use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::EnvFilter;

use ruff::args::{ConfigArguments, FormatArguments, FormatCommand, LogLevelArgs};
use ruff::args::{ConfigArguments, FormatArguments, FormatCommand, GlobalConfigArgs, LogLevelArgs};
use ruff::resolve::resolve;
use ruff_formatter::{FormatError, LineWidth, PrintError};
use ruff_linter::logging::LogLevel;
@@ -43,7 +43,7 @@ fn parse_cli(dirs: &[PathBuf]) -> anyhow::Result<(FormatArguments, ConfigArgumen
.no_binary_name(true)
.get_matches_from(dirs);
let arguments: FormatCommand = FormatCommand::from_arg_matches(&args_matches)?;
let (cli, config_arguments) = arguments.partition()?;
let (cli, config_arguments) = arguments.partition(GlobalConfigArgs::default())?;
Ok((cli, config_arguments))
}

@@ -52,11 +52,7 @@ fn find_pyproject_config(
cli: &FormatArguments,
config_arguments: &ConfigArguments,
) -> anyhow::Result<PyprojectConfig> {
let mut pyproject_config = resolve(
cli.isolated,
config_arguments,
cli.stdin_filename.as_deref(),
)?;
let mut pyproject_config = resolve(config_arguments, cli.stdin_filename.as_deref())?;
// We don't want to format pyproject.toml
pyproject_config.settings.file_resolver.include = FilePatternSet::try_from_iter([
FilePattern::Builtin("*.py"),
44 changes: 34 additions & 10 deletions crates/ruff_dev/src/main.rs
Original file line number Diff line number Diff line change
@@ -4,8 +4,11 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use ruff::check;
use ruff_linter::logging::{set_up_logging, LogLevel};
use ruff::{
args::{GlobalConfigArgs, LogLevelArgs},
check,
};
use ruff_linter::logging::set_up_logging;
use std::process::ExitCode;

mod format_dev;
@@ -28,6 +31,30 @@ const ROOT_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../");
struct Args {
#[command(subcommand)]
command: Command,
#[arg(
long,
action = clap::ArgAction::Append,
value_name = "CONFIG_OPTION",
value_parser = ruff::args::ConfigArgumentParser,
global = true,
help_heading = "Global configuration options"
)]
config: Vec<ruff::args::SingleConfigArgument>,
#[arg(long, help_heading = "Global configuration options", global = true)]
isolated: bool,
}

impl Args {
#[must_use]
fn partition(self) -> (Command, GlobalConfigArgs) {
let Args {
command,
config,
isolated,
} = self;
let global_options = GlobalConfigArgs::new(LogLevelArgs::default(), config, isolated);
(command, global_options)
}
}

#[derive(Subcommand)]
@@ -57,8 +84,6 @@ enum Command {
Repeat {
#[clap(flatten)]
args: ruff::args::CheckCommand,
#[clap(flatten)]
log_level_args: ruff::args::LogLevelArgs,
/// Run this many times
#[clap(long)]
repeat: usize,
@@ -76,8 +101,9 @@ enum Command {

fn main() -> Result<ExitCode> {
let args = Args::parse();
let (command, global_options) = args.partition();
#[allow(clippy::print_stdout)]
match args.command {
match command {
Command::GenerateAll(args) => generate_all::main(&args)?,
Command::GenerateJSONSchema(args) => generate_json_schema::main(&args)?,
Command::GenerateRulesTable => println!("{}", generate_rules_table::generate()),
@@ -89,14 +115,12 @@ fn main() -> Result<ExitCode> {
Command::PrintTokens(args) => print_tokens::main(&args)?,
Command::RoundTrip(args) => round_trip::main(&args)?,
Command::Repeat {
args,
args: subcommand_args,
repeat,
log_level_args,
} => {
let log_level = LogLevel::from(&log_level_args);
set_up_logging(&log_level)?;
set_up_logging(global_options.log_level())?;
for _ in 0..repeat {
check(args.clone(), log_level)?;
check(subcommand_args.clone(), global_options.clone())?;
}
}
Command::FormatDev(args) => {
2 changes: 1 addition & 1 deletion crates/ruff_linter/src/logging.rs
Original file line number Diff line number Diff line change
@@ -121,7 +121,7 @@ impl LogLevel {
}
}

pub fn set_up_logging(level: &LogLevel) -> Result<()> {
pub fn set_up_logging(level: LogLevel) -> Result<()> {
fern::Dispatch::new()
.format(|out, message, record| match record.level() {
Level::Error => {
51 changes: 33 additions & 18 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -540,6 +540,17 @@ Log levels:
-s, --silent Disable all logging (but still exit with status code "1" upon
detecting diagnostics)
Global options:
--config <CONFIG_OPTION>
Either a path to a TOML configuration file (`pyproject.toml` or
`ruff.toml`), or a TOML `<KEY> = <VALUE>` pair (such as you might
find in a `ruff.toml` configuration file) overriding a specific
configuration option. Overrides of individual settings using this
option always take precedence over all configuration files, including
configuration files that were also specified using `--config`
--isolated
Ignore all configuration files
For help with a specific command, see: `ruff help <command>`.
```

@@ -596,13 +607,6 @@ Options:
--preview
Enable preview mode; checks will include unstable rules and fixes.
Use `--no-preview` to disable
--config <CONFIG_OPTION>
Either a path to a TOML configuration file (`pyproject.toml` or
`ruff.toml`), or a TOML `<KEY> = <VALUE>` pair (such as you might
find in a `ruff.toml` configuration file) overriding a specific
configuration option. Overrides of individual settings using this
option always take precedence over all configuration files, including
configuration files that were also specified using `--config`
--extension <EXTENSION>
List of mappings from file extension to language (one of ["python",
"ipynb", "pyi"]). For example, to treat `.ipy` files as IPython
@@ -658,8 +662,6 @@ File selection:
Miscellaneous:
-n, --no-cache
Disable cache reads [env: RUFF_NO_CACHE=]
--isolated
Ignore all configuration files
--cache-dir <CACHE_DIR>
Path to the cache directory [env: RUFF_CACHE_DIR=]
--stdin-filename <STDIN_FILENAME>
@@ -675,6 +677,17 @@ Log levels:
-q, --quiet Print diagnostics, but nothing else
-s, --silent Disable all logging (but still exit with status code "1" upon
detecting diagnostics)
Global options:
--config <CONFIG_OPTION>
Either a path to a TOML configuration file (`pyproject.toml` or
`ruff.toml`), or a TOML `<KEY> = <VALUE>` pair (such as you might
find in a `ruff.toml` configuration file) overriding a specific
configuration option. Overrides of individual settings using this
option always take precedence over all configuration files, including
configuration files that were also specified using `--config`
--isolated
Ignore all configuration files
```

<!-- End auto-generated check help. -->
@@ -699,13 +712,6 @@ Options:
Avoid writing any formatted files back; instead, exit with a non-zero
status code and the difference between the current file and how the
formatted file would look like
--config <CONFIG_OPTION>
Either a path to a TOML configuration file (`pyproject.toml` or
`ruff.toml`), or a TOML `<KEY> = <VALUE>` pair (such as you might
find in a `ruff.toml` configuration file) overriding a specific
configuration option. Overrides of individual settings using this
option always take precedence over all configuration files, including
configuration files that were also specified using `--config`
--extension <EXTENSION>
List of mappings from file extension to language (one of ["python",
"ipynb", "pyi"]). For example, to treat `.ipy` files as IPython
@@ -724,8 +730,6 @@ Miscellaneous:
Disable cache reads [env: RUFF_NO_CACHE=]
--cache-dir <CACHE_DIR>
Path to the cache directory [env: RUFF_CACHE_DIR=]
--isolated
Ignore all configuration files
--stdin-filename <STDIN_FILENAME>
The name of the file when passing it through stdin
@@ -755,6 +759,17 @@ Log levels:
-q, --quiet Print diagnostics, but nothing else
-s, --silent Disable all logging (but still exit with status code "1" upon
detecting diagnostics)
Global options:
--config <CONFIG_OPTION>
Either a path to a TOML configuration file (`pyproject.toml` or
`ruff.toml`), or a TOML `<KEY> = <VALUE>` pair (such as you might
find in a `ruff.toml` configuration file) overriding a specific
configuration option. Overrides of individual settings using this
option always take precedence over all configuration files, including
configuration files that were also specified using `--config`
--isolated
Ignore all configuration files
```

<!-- End auto-generated format help. -->