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
Show file tree
Hide file tree
Changes from 12 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
160 changes: 86 additions & 74 deletions crates/ruff/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ 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)]
pub struct GlobalConfigArgs {
pub log_level: LogLevel,
AlexWaygood marked this conversation as resolved.
Show resolved Hide resolved
pub config_flags: Vec<SingleConfigArgument>,
pub isolated: bool,
}

#[derive(Debug, Parser)]
#[command(
author,
Expand All @@ -38,9 +47,54 @@ use ruff_workspace::resolver::ConfigurationTransformer;
#[command(version)]
pub struct Args {
#[command(subcommand)]
pub command: Command,
command: Command,
#[clap(flatten)]
AlexWaygood marked this conversation as resolved.
Show resolved Hide resolved
pub log_level_args: LogLevelArgs,
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",
)]
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)]
isolated: bool,
}

impl Args {
#[must_use]
pub fn partition(self) -> (Command, GlobalConfigArgs) {
let Args {
command,
log_level_args,
config,
isolated,
} = self;
let global_config_args = GlobalConfigArgs {
log_level: LogLevel::from(&log_level_args),
config_flags: config,
isolated,
};
(command, global_config_args)
}
}

#[allow(clippy::large_enum_variant)]
Expand Down Expand Up @@ -161,20 +215,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,
Expand Down Expand Up @@ -306,17 +346,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>,
Expand Down Expand Up @@ -408,20 +437,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")]
Expand Down Expand Up @@ -462,17 +477,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>,
Expand Down Expand Up @@ -561,6 +565,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 isolated: bool,
AlexWaygood marked this conversation as resolved.
Show resolved Hide resolved
/// The logging level to be used, derived from command-line arguments passed
pub 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>,
Expand All @@ -581,28 +589,25 @@ impl ConfigArguments {
}

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

for option in config_options {
for option in global_config_args.config_flags {
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,
)?);
}
SingleConfigArgument::FilePath(path) => {
if isolated {
if global_config_args.isolated {
bail!(
"\
The argument `--config={}` cannot be used with `--isolated`
Expand All @@ -614,7 +619,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!(
"\
Expand All @@ -625,11 +630,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: global_config_args.isolated,
log_level: global_config_args.log_level,
config_file,
overrides,
per_flag_overrides,
})
}
}

Expand All @@ -643,7 +654,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_config_args: GlobalConfigArgs,
) -> anyhow::Result<(CheckArguments, ConfigArguments)> {
let check_arguments = CheckArguments {
add_noqa: self.add_noqa,
diff: self.diff,
Expand All @@ -652,7 +666,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,
Expand Down Expand Up @@ -696,21 +709,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_config_args, 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_config_args: 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,
Expand All @@ -730,8 +744,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_config_args, cli_overrides)?;

Ok((format_arguments, config_args))
}
}
Expand Down Expand Up @@ -957,7 +971,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,
Expand All @@ -975,7 +988,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>,
}
Expand Down
9 changes: 2 additions & 7 deletions crates/ruff/src/commands/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down Expand Up @@ -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())?;
Expand Down
6 changes: 1 addition & 5 deletions crates/ruff/src/commands/format_stdin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading
Loading