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

ignore is overwritten in nested rustfmt.toml layouts #3881

Closed
pyrrho opened this issue Oct 23, 2019 · 2 comments · Fixed by #4179
Closed

ignore is overwritten in nested rustfmt.toml layouts #3881

pyrrho opened this issue Oct 23, 2019 · 2 comments · Fixed by #4179
Labels
bug Panic, non-idempotency, invalid code, etc.

Comments

@pyrrho
Copy link

pyrrho commented Oct 23, 2019

Given a layout like,

my-crate
├── rusfmt.toml
└── src
    ├── lib.rs
    └── sub
        └── dir
            ├── file-a.rs
            ├── file-b.rs
            └── rustfmt.toml

where my-crate/rustfmt.toml include ignore = ["src/sub/dir/file-a.rs"] and my-crate/src/sub/dir/rustfmt.toml includes ignore = [], running --print-config current for files in src/sub/dir shows an empty ignore array.

$ rustfmt +nightly --print-config current ./src/sub/dir/file-b.rs | grep ignore
ignore = []

I initially expected the returned config to include "src/sub/dir/file-a.rs".

This was somewhat surprising to me, as the rest of rustfmt.toml "feels" additive to me. I put "feels" in quotations, as child rustfmt.toml files really just overwrite the single-value configurations of their parents. As that's exactly what's going on, this may be correct behavior (if somewhat limiting in atypical repo layouts).

Looking back over the configuration list, it seems ignore is the only configuration that takes a list, and one of two that expects a path (the other being license_template_path).

I would consider it an improvement if,

  1. ignore arrays were union'd together as rustfmt assembled it's 'current' configuration
  2. --print-config current emitted absolute-resolved paths (in addition to, or in place of relative paths)

I'm pairing these two features together specifically because I think it would be necessary to resolve paths into an absolute form in order to union them.

@topecongiro
Copy link
Contributor

ignore arrays were union'd together as rustfmt assembled it's 'current' configuration

This is the expected behavior, though currently not executed properly.

@topecongiro topecongiro added the bug Panic, non-idempotency, invalid code, etc. label Oct 24, 2019
@pyrrho
Copy link
Author

pyrrho commented Oct 24, 2019

To flesh out my thoughts regarding the absolute paths, here's the kind of pathological case I was considering when I was typing up this issue,

my-crate
├── Cargo.toml
├── my-crate-sys
│   ├── Cargo.toml
│   ├── rustfmt.toml # ignore = ["src/lib.rs"]
│   └── src
│       ├── data.rs
│       └── lib.rs
├── rustfmt.toml # ignore = ["src/data.rs"]
└── src
    ├── data.rs
    └── lib.rs

The intention there being src/lib.rs and my-crate-sys/src/data.rs should be formatted. Depending on how naive the union and path-matching operations are, I could see all four .rs files being ignored.

This is also why I would like to see --print-config (at least optionally) emit absolute paths. If the values of ignore are merged, but relative paths are emitted, it would be very difficult for tooling to look at the output of rustfmt +nightly --print-config current my-crate-sys/src/data.rs and not conclude that my-crate-sys/src/data.rs should be ignored.

ayazhafiz added a commit to ayazhafiz/rustfmt that referenced this issue May 16, 2020
Currently, `rustfmt` stops building its configuration after one
configuration file is found. However, users may expect that `rustfmt`
includes configuration options inhereted by configuration files in
parent directories of the directory `rustfmt` is run in.

The motivation for this commit is for a use case involving files that
should be ignored by `rustfmt`. Consider the directory structure

```
a
|-- rustfmt.toml
|-- b
    |-- rustfmt.toml
    |-- main.rs
```

Suppose `a/rustfmt.toml` has the option `ignore = ["b/main.rs"]`. A user
may expect that running `rusfmt` in either directory `a/` or `b/` will
ignore `main.rs`. Today, though, if `rustfmt` is run in `b/`, `main.rs`
will be formatted because only `b/rustfmt.toml` will be used for
configuration.

Although motivated by the use case for ignored files, this change sets
up `rustfmt` to incrementally populate all configuration options from
parent config files. The priority of population is closest config file
to most transient config file.

To avoid churn of the existing implementation for ignoring files,
populating the ignored files config option with multiple config files is
done by computing a join. Given config files "outer" and "inner", where
"inner" is of higher priority (nested in the directory of) "outer", we
merge their `ignore` configurations by finding the ignore files
specified in "outer" that are present in the "inner" directory, and
appending this to the files ignored by "inner".

This means that printing an `ignore` configuration may not be entirely
accurate, as it could be missing files that are not in the current
directory specified by transient configurations. These files are out of
the scope the `rustfmt` instance's operation, though, so for practical
purposes I don't think this matters.

Closes rust-lang#3881
ayazhafiz added a commit to ayazhafiz/rustfmt that referenced this issue May 20, 2020
Currently, `rustfmt` stops building its configuration after one
configuration file is found. However, users may expect that `rustfmt`
includes configuration options inhereted by configuration files in
parent directories of the directory `rustfmt` is run in.

The motivation for this commit is for a use case involving files that
should be ignored by `rustfmt`. Consider the directory structure

```
a
|-- rustfmt.toml
|-- b
    |-- rustfmt.toml
    |-- main.rs
```

Suppose `a/rustfmt.toml` has the option `ignore = ["b/main.rs"]`. A user
may expect that running `rusfmt` in either directory `a/` or `b/` will
ignore `main.rs`. Today, though, if `rustfmt` is run in `b/`, `main.rs`
will be formatted because only `b/rustfmt.toml` will be used for
configuration.

Although motivated by the use case for ignored files, this change sets
up `rustfmt` to incrementally populate all configuration options from
parent config files. The priority of population is closest config file
to most transient config file.

To avoid churn of the existing implementation for ignoring files,
populating the ignored files config option with multiple config files is
done by computing a join. Given config files "outer" and "inner", where
"inner" is of higher priority (nested in the directory of) "outer", we
merge their `ignore` configurations by finding the ignore files
specified in "outer" that are present in the "inner" directory, and
appending this to the files ignored by "inner".

This means that printing an `ignore` configuration may not be entirely
accurate, as it could be missing files that are not in the current
directory specified by transient configurations. These files are out of
the scope the `rustfmt` instance's operation, though, so for practical
purposes I don't think this matters.

Closes rust-lang#3881
ayazhafiz added a commit to ayazhafiz/rustfmt that referenced this issue May 22, 2020
Currently, `rustfmt` stops building its configuration after one
configuration file is found. However, users may expect that `rustfmt`
includes configuration options inhereted by configuration files in
parent directories of the directory `rustfmt` is run in.

The motivation for this commit is for a use case involving files that
should be ignored by `rustfmt`. Consider the directory structure

```
a
|-- rustfmt.toml
|-- b
    |-- rustfmt.toml
    |-- main.rs
```

Suppose `a/rustfmt.toml` has the option `ignore = ["b/main.rs"]`. A user
may expect that running `rusfmt` in either directory `a/` or `b/` will
ignore `main.rs`. Today, though, if `rustfmt` is run in `b/`, `main.rs`
will be formatted because only `b/rustfmt.toml` will be used for
configuration.

Although motivated by the use case for ignored files, this change sets
up `rustfmt` to incrementally populate all configuration options from
parent config files. The priority of population is closest config file
to most transient config file.

To avoid churn of the existing implementation for ignoring files,
populating the ignored files config option with multiple config files is
done by computing a join. Given config files "outer" and "inner", where
"inner" is of higher priority (nested in the directory of) "outer", we
merge their `ignore` configurations by finding the ignore files
specified in "outer" that are present in the "inner" directory, and
appending this to the files ignored by "inner".

This means that printing an `ignore` configuration may not be entirely
accurate, as it could be missing files that are not in the current
directory specified by transient configurations. These files are out of
the scope the `rustfmt` instance's operation, though, so for practical
purposes I don't think this matters.

Closes rust-lang#3881
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Panic, non-idempotency, invalid code, etc.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants