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

Allow banning or requiring specific features. #226

Closed
thomcc opened this issue Jul 14, 2020 · 4 comments · Fixed by #461
Closed

Allow banning or requiring specific features. #226

thomcc opened this issue Jul 14, 2020 · 4 comments · Fixed by #461
Labels
enhancement New feature or request

Comments

@thomcc
Copy link
Contributor

thomcc commented Jul 14, 2020

Is your feature request related to a problem? Please describe.

In #225 I mentioned a case where a particular feature was banned. It would be good to be able to ban X crate ever from appearing while the feature is enabled. Some examples:

  1. Certain parts of the regex-syntax unicode tables take up many megabytes for obscure regex features.

  2. For a period of time in https://github.com/mozilla/application-services/ we had a feature where networking requests could be made through reqwest instead of via necko (gecko/Firefox's network engine).
    This was used for firefox-ios (which has no gecko), but shipping this to users on other platforms would have been considered a massive problem.

    We ultimately resolved it by switching from a feature-based solution to one where you pull in a reqwest backend and manually enable it. This feels more reliable given how features work.

  3. In general features are well-known to be something that can easily be enabled at a distance by accident, and easily fail to be enabled by a misphrased cargo invocation (cargo build -p --features in workspaces does not respect the features you provide it -- although --all-features does). Some way of getting a handle here seems desirable.

Describe the solution you'd like

This is tricky a bit. Here's one way you could do it, but it's sort of bolting it on, and maybe extending the model somehow is better. Also, I'm not tied to names.

Solution high level.

  • Add a field deny-features to [ban.deny] records, which only match if there's a feature in the final crate which is in the deny-features list
  • Add a field allow-features to [ban.deny] records, which match if there's a feature in the final crate which isn't part of the allowlist
  • Add a field exact-features to [ban.deny] records, which makes allow-features strict -- if this is true, then allow-features must be the exact featureset of the final crate.

Some examples:

# Example 1: forbid specific feature
[[bans.deny]]
name = "crate1"
# this `deny` block matches if any of these are present.
deny-features = ["badnews"]

# Example 2: Forbid all features other than the listed ones.
[[bans.deny]]
name = "crate2"
# this `deny` block matches if any features exist not present in the list
allow-features = ["fast-code", "faster-code"]

# Example 3: Require exact feature set
[[bans.deny]]
name = "crate3"
allow-features = ["good-vibes"]
exact-features = true

Algorithm

Note that by "the deny block matches" I mean: the crate is denied unless allowed by some other mechanism (skip, for example). Of course, if the deny block fails to match (e.g. the crate is accepted), the crate still may be denied if another deny block happens to match. Also, feature sets are, of course, not sensitive to order. (["A", "B", "C"] and ["C", "B", "A"] are the same).

  • let CF be the final set of features for the indicated crate in the final crate graph.
  • let D be a record in bans.deny which otherwise applies to the crate (not excluded by version, for example).
  • let DF be D.deny-features if present, and the empty set otherwise.
  • if D.exact-features is true:
    • let AF be D.allow-features if present, or the empty set if missing.
    • if AF and CF are identical sets then D does not apply (e.g. crate accepted, but see above)
    • If AF and CF differ, then D does apply (e.g. crate denied, but see above).
  • if D.exact-features is false or missing:
    • if D.allowed-features is missing, then all features are considered allowed.
    • otherwise, let AF be D.allow-features
      • If CF is a subset of AF, then D does not apply (accepted), otherwise D applies (denied)
      • Equivalently: if any item in CF exists not present in AF, the crate is denied
Edge cases
  1. When loading a given [[ban.deny]] record, if any string is in both deny-features and allow-features, emit an error.

  2. It is legal for the feature lists to refer to features which do not exist. They behave the same -- e.g. if a user requires a feature and the crate does not offer that feature, they have to figure it out.

  3. For clarity:

    • if allow-features behaves similarly to bans.allow in that when not allowed it does not filter, and if it is provided it is very strict.
    • if exact-features is true and allow-features is missing, it's the same as exact-features=true and allow-features=[] -- all features are denied.
    • I suggested defaults for some of these, but it seems plausible that if you provided allow-features you should have to provide exact and vice versa.

Describe alternatives you've considered

See beginning. Scripts and avoiding the problem.

Additional context

N/A

@thomcc thomcc added the enhancement New feature or request label Jul 14, 2020
@Jake-Shadle
Copy link
Member

We've had similar problems as well, usually with regards to default features that creep in, so we are definitely motivated to add this kind of feature checking.

@Nemo157
Copy link

Nemo157 commented Aug 12, 2020

Another example usecase: using crates like hyper that expose traits from tokio, but with a different async runtime, you want to ensure the tokio runtime features are not being activated. That seems to fit into the proposed syntax

[[bans.deny]]
name = "tokio"
deny-features = ["rt-core", "io-driver", "time"]

@Stupremee
Copy link
Contributor

I would start with this if it is not blocked by anything.

@Jake-Shadle
Copy link
Member

I don't believe it is blocked by anything, go for it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
4 participants