├── .cargo └── config.toml ├── .clippy.toml ├── .github ├── renovate.json5 ├── settings.yml └── workflows │ ├── audit.yml │ ├── ci.yml │ ├── committed.yml │ ├── pre-commit.yml │ ├── rust-next.yml │ └── spelling.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── committed.toml ├── deny.toml ├── examples ├── log.rs ├── log_level.rs └── tracing.rs ├── release.toml └── src ├── lib.rs ├── log.rs └── tracing.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [resolver] 2 | incompatible-rust-versions = "fallback" 3 | -------------------------------------------------------------------------------- /.clippy.toml: -------------------------------------------------------------------------------- 1 | allow-print-in-tests = true 2 | allow-expect-in-tests = true 3 | allow-unwrap-in-tests = true 4 | allow-dbg-in-tests = true 5 | disallowed-methods = [ 6 | { path = "std::option::Option::map_or", reason = "prefer `map(..).unwrap_or(..)` for legibility" }, 7 | { path = "std::option::Option::map_or_else", reason = "prefer `map(..).unwrap_or_else(..)` for legibility" }, 8 | { path = "std::result::Result::map_or", reason = "prefer `map(..).unwrap_or(..)` for legibility" }, 9 | { path = "std::result::Result::map_or_else", reason = "prefer `map(..).unwrap_or_else(..)` for legibility" }, 10 | { path = "std::iter::Iterator::for_each", reason = "prefer `for` for side-effects" }, 11 | { path = "std::iter::Iterator::try_for_each", reason = "prefer `for` for side-effects" }, 12 | ] 13 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | schedule: [ 3 | 'before 5am on the first day of the month', 4 | ], 5 | semanticCommits: 'enabled', 6 | commitMessageLowerCase: 'never', 7 | configMigration: true, 8 | dependencyDashboard: true, 9 | customManagers: [ 10 | { 11 | customType: 'regex', 12 | managerFilePatterns: [ 13 | '/^rust-toolchain\\.toml$/', 14 | '/Cargo.toml$/', 15 | '/clippy.toml$/', 16 | '/\\.clippy.toml$/', 17 | '/^\\.github/workflows/ci.yml$/', 18 | '/^\\.github/workflows/rust-next.yml$/', 19 | ], 20 | matchStrings: [ 21 | 'STABLE.*?(?\\d+\\.\\d+(\\.\\d+)?)', 22 | '(?\\d+\\.\\d+(\\.\\d+)?).*?STABLE', 23 | ], 24 | depNameTemplate: 'STABLE', 25 | packageNameTemplate: 'rust-lang/rust', 26 | datasourceTemplate: 'github-releases', 27 | }, 28 | ], 29 | packageRules: [ 30 | { 31 | commitMessageTopic: 'Rust Stable', 32 | matchManagers: [ 33 | 'custom.regex', 34 | ], 35 | matchDepNames: [ 36 | 'STABLE', 37 | ], 38 | extractVersion: '^(?\\d+\\.\\d+)', // Drop the patch version 39 | schedule: [ 40 | '* * * * *', 41 | ], 42 | automerge: true, 43 | }, 44 | // Goals: 45 | // - Keep version reqs low, ignoring compatible normal/build dependencies 46 | // - Take advantage of latest dev-dependencies 47 | // - Rollup safe upgrades to reduce CI runner load 48 | // - Help keep number of versions down by always using latest breaking change 49 | // - Have lockfile and manifest in-sync 50 | { 51 | matchManagers: [ 52 | 'cargo', 53 | ], 54 | matchDepTypes: [ 55 | 'build-dependencies', 56 | 'dependencies', 57 | ], 58 | matchCurrentVersion: '>=0.1.0', 59 | matchUpdateTypes: [ 60 | 'patch', 61 | ], 62 | enabled: false, 63 | }, 64 | { 65 | matchManagers: [ 66 | 'cargo', 67 | ], 68 | matchDepTypes: [ 69 | 'build-dependencies', 70 | 'dependencies', 71 | ], 72 | matchCurrentVersion: '>=1.0.0', 73 | matchUpdateTypes: [ 74 | 'minor', 75 | 'patch', 76 | ], 77 | enabled: false, 78 | }, 79 | { 80 | matchManagers: [ 81 | 'cargo', 82 | ], 83 | matchDepTypes: [ 84 | 'dev-dependencies', 85 | ], 86 | matchCurrentVersion: '>=0.1.0', 87 | matchUpdateTypes: [ 88 | 'patch', 89 | ], 90 | automerge: true, 91 | groupName: 'compatible (dev)', 92 | }, 93 | { 94 | matchManagers: [ 95 | 'cargo', 96 | ], 97 | matchDepTypes: [ 98 | 'dev-dependencies', 99 | ], 100 | matchCurrentVersion: '>=1.0.0', 101 | matchUpdateTypes: [ 102 | 'minor', 103 | 'patch', 104 | ], 105 | automerge: true, 106 | groupName: 'compatible (dev)', 107 | }, 108 | ], 109 | } 110 | -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | # These settings are synced to GitHub by https://probot.github.io/apps/settings/ 2 | 3 | repository: 4 | description: "Easily add a --verbose flag to CLIs using Clap" 5 | homepage: "https://docs.rs/clap-verbosity-flag" 6 | topics: "rust cli clap logging" 7 | has_issues: true 8 | has_projects: false 9 | has_wiki: false 10 | has_downloads: true 11 | default_branch: master 12 | 13 | # Preference: people do clean commits 14 | allow_merge_commit: true 15 | # Backup in case we need to clean up commits 16 | allow_squash_merge: true 17 | # Not really needed 18 | allow_rebase_merge: false 19 | 20 | allow_auto_merge: true 21 | delete_branch_on_merge: true 22 | 23 | squash_merge_commit_title: "PR_TITLE" 24 | squash_merge_commit_message: "PR_BODY" 25 | merge_commit_message: "PR_BODY" 26 | 27 | labels: 28 | # Type 29 | - name: bug 30 | color: '#b60205' 31 | description: "Not as expected" 32 | - name: enhancement 33 | color: '#1d76db' 34 | description: "Improve the expected" 35 | # Flavor 36 | - name: question 37 | color: "#cc317c" 38 | description: "Uncertainty is involved" 39 | - name: breaking-change 40 | color: "#e99695" 41 | - name: good first issue 42 | color: '#c2e0c6' 43 | description: "Help wanted!" 44 | 45 | # This serves more as documentation. 46 | # Branch protection API was replaced by rulesets but settings isn't updated. 47 | # See https://github.com/repository-settings/app/issues/825 48 | # 49 | # branches: 50 | # - name: master 51 | # protection: 52 | # required_pull_request_reviews: null 53 | # required_conversation_resolution: true 54 | # required_status_checks: 55 | # # Required. Require branches to be up to date before merging. 56 | # strict: false 57 | # contexts: ["CI", "Spell Check with Typos"] 58 | # enforce_admins: false 59 | # restrictions: null 60 | -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | name: Security audit 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | pull_request: 8 | paths: 9 | - '**/Cargo.toml' 10 | - '**/Cargo.lock' 11 | push: 12 | branches: 13 | - master 14 | 15 | env: 16 | RUST_BACKTRACE: 1 17 | CARGO_TERM_COLOR: always 18 | CLICOLOR: 1 19 | 20 | concurrency: 21 | group: "${{ github.workflow }}-${{ github.ref }}" 22 | cancel-in-progress: true 23 | 24 | jobs: 25 | security_audit: 26 | permissions: 27 | issues: write # to create issues (actions-rs/audit-check) 28 | checks: write # to create check (actions-rs/audit-check) 29 | runs-on: ubuntu-latest 30 | # Prevent sudden announcement of a new advisory from failing ci: 31 | continue-on-error: true 32 | steps: 33 | - name: Checkout repository 34 | uses: actions/checkout@v4 35 | - uses: actions-rs/audit-check@v1 36 | with: 37 | token: ${{ secrets.GITHUB_TOKEN }} 38 | 39 | cargo_deny: 40 | permissions: 41 | issues: write # to create issues (actions-rs/audit-check) 42 | checks: write # to create check (actions-rs/audit-check) 43 | runs-on: ubuntu-latest 44 | strategy: 45 | matrix: 46 | checks: 47 | - bans licenses sources 48 | steps: 49 | - uses: actions/checkout@v4 50 | - uses: EmbarkStudios/cargo-deny-action@v2 51 | with: 52 | command: check ${{ matrix.checks }} 53 | rust-version: stable 54 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | pull_request: 8 | push: 9 | branches: 10 | - master 11 | 12 | env: 13 | RUST_BACKTRACE: 1 14 | CARGO_TERM_COLOR: always 15 | CLICOLOR: 1 16 | 17 | concurrency: 18 | group: "${{ github.workflow }}-${{ github.ref }}" 19 | cancel-in-progress: true 20 | 21 | jobs: 22 | ci: 23 | permissions: 24 | contents: none 25 | name: CI 26 | needs: [test, msrv, lockfile, docs, rustfmt, clippy, minimal-versions] 27 | runs-on: ubuntu-latest 28 | if: "always()" 29 | steps: 30 | - name: Failed 31 | run: exit 1 32 | if: "contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped')" 33 | test: 34 | name: Test 35 | strategy: 36 | matrix: 37 | os: ["ubuntu-latest", "windows-latest", "macos-latest"] 38 | rust: ["stable"] 39 | continue-on-error: ${{ matrix.rust != 'stable' }} 40 | runs-on: ${{ matrix.os }} 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v4 44 | - name: Install Rust 45 | uses: dtolnay/rust-toolchain@stable 46 | with: 47 | toolchain: ${{ matrix.rust }} 48 | - uses: Swatinem/rust-cache@v2 49 | - uses: taiki-e/install-action@cargo-hack 50 | - name: Build 51 | run: cargo test --workspace --no-run 52 | - name: Test 53 | run: cargo hack test --each-feature --workspace 54 | msrv: 55 | name: "Check MSRV" 56 | runs-on: ubuntu-latest 57 | steps: 58 | - name: Checkout repository 59 | uses: actions/checkout@v4 60 | - name: Install Rust 61 | uses: dtolnay/rust-toolchain@stable 62 | with: 63 | toolchain: stable 64 | - uses: Swatinem/rust-cache@v2 65 | - uses: taiki-e/install-action@cargo-hack 66 | - name: Default features 67 | run: cargo hack check --each-feature --locked --rust-version --ignore-private --workspace --all-targets --keep-going 68 | minimal-versions: 69 | name: Minimal versions 70 | runs-on: ubuntu-latest 71 | steps: 72 | - name: Checkout repository 73 | uses: actions/checkout@v4 74 | - name: Install stable Rust 75 | uses: dtolnay/rust-toolchain@stable 76 | with: 77 | toolchain: stable 78 | - name: Install nightly Rust 79 | uses: dtolnay/rust-toolchain@stable 80 | with: 81 | toolchain: nightly 82 | - name: Downgrade dependencies to minimal versions 83 | run: cargo +nightly generate-lockfile -Z minimal-versions 84 | - name: Compile with minimal versions 85 | run: cargo +stable check --workspace --all-features --locked --keep-going 86 | lockfile: 87 | runs-on: ubuntu-latest 88 | steps: 89 | - name: Checkout repository 90 | uses: actions/checkout@v4 91 | - name: Install Rust 92 | uses: dtolnay/rust-toolchain@stable 93 | with: 94 | toolchain: stable 95 | - uses: Swatinem/rust-cache@v2 96 | - name: "Is lockfile updated?" 97 | run: cargo update --workspace --locked 98 | docs: 99 | name: Docs 100 | runs-on: ubuntu-latest 101 | steps: 102 | - name: Checkout repository 103 | uses: actions/checkout@v4 104 | - name: Install Rust 105 | uses: dtolnay/rust-toolchain@stable 106 | with: 107 | toolchain: "1.87" # STABLE 108 | - uses: Swatinem/rust-cache@v2 109 | - name: Check documentation 110 | env: 111 | RUSTDOCFLAGS: -D warnings 112 | run: cargo doc --workspace --all-features --no-deps --document-private-items --keep-going 113 | rustfmt: 114 | name: rustfmt 115 | runs-on: ubuntu-latest 116 | steps: 117 | - name: Checkout repository 118 | uses: actions/checkout@v4 119 | - name: Install Rust 120 | uses: dtolnay/rust-toolchain@stable 121 | with: 122 | toolchain: "1.87" # STABLE 123 | components: rustfmt 124 | - uses: Swatinem/rust-cache@v2 125 | - name: Check formatting 126 | run: cargo fmt --all -- --check 127 | clippy: 128 | name: clippy 129 | runs-on: ubuntu-latest 130 | permissions: 131 | security-events: write # to upload sarif results 132 | steps: 133 | - name: Checkout repository 134 | uses: actions/checkout@v4 135 | - name: Install Rust 136 | uses: dtolnay/rust-toolchain@stable 137 | with: 138 | toolchain: "1.87" # STABLE 139 | components: clippy 140 | - uses: Swatinem/rust-cache@v2 141 | - name: Install SARIF tools 142 | run: cargo install clippy-sarif --locked 143 | - name: Install SARIF tools 144 | run: cargo install sarif-fmt --locked 145 | - name: Check 146 | run: > 147 | cargo clippy --workspace --all-features --all-targets --message-format=json 148 | | clippy-sarif 149 | | tee clippy-results.sarif 150 | | sarif-fmt 151 | continue-on-error: true 152 | - name: Upload 153 | uses: github/codeql-action/upload-sarif@v3 154 | with: 155 | sarif_file: clippy-results.sarif 156 | wait-for-processing: true 157 | - name: Report status 158 | run: cargo clippy --workspace --all-features --all-targets --keep-going -- -D warnings --allow deprecated 159 | coverage: 160 | name: Coverage 161 | runs-on: ubuntu-latest 162 | steps: 163 | - name: Checkout repository 164 | uses: actions/checkout@v4 165 | - name: Install Rust 166 | uses: dtolnay/rust-toolchain@stable 167 | with: 168 | toolchain: stable 169 | - uses: Swatinem/rust-cache@v2 170 | - name: Install cargo-tarpaulin 171 | run: cargo install cargo-tarpaulin 172 | - name: Gather coverage 173 | run: cargo tarpaulin --output-dir coverage --out lcov 174 | - name: Publish to Coveralls 175 | uses: coverallsapp/github-action@master 176 | with: 177 | github-token: ${{ secrets.GITHUB_TOKEN }} 178 | -------------------------------------------------------------------------------- /.github/workflows/committed.yml: -------------------------------------------------------------------------------- 1 | # Not run as part of pre-commit checks because they don't handle sending the correct commit 2 | # range to `committed` 3 | name: Lint Commits 4 | on: [pull_request] 5 | 6 | permissions: 7 | contents: read 8 | 9 | env: 10 | RUST_BACKTRACE: 1 11 | CARGO_TERM_COLOR: always 12 | CLICOLOR: 1 13 | 14 | concurrency: 15 | group: "${{ github.workflow }}-${{ github.ref }}" 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | committed: 20 | name: Lint Commits 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Checkout Actions Repository 24 | uses: actions/checkout@v4 25 | with: 26 | fetch-depth: 0 27 | - name: Lint Commits 28 | uses: crate-ci/committed@master 29 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: pre-commit 2 | 3 | permissions: {} # none 4 | 5 | on: 6 | pull_request: 7 | push: 8 | branches: [master] 9 | 10 | env: 11 | RUST_BACKTRACE: 1 12 | CARGO_TERM_COLOR: always 13 | CLICOLOR: 1 14 | 15 | concurrency: 16 | group: "${{ github.workflow }}-${{ github.ref }}" 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | pre-commit: 21 | permissions: 22 | contents: read 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: actions/setup-python@v5 27 | with: 28 | python-version: '3.x' 29 | - uses: pre-commit/action@v3.0.1 30 | -------------------------------------------------------------------------------- /.github/workflows/rust-next.yml: -------------------------------------------------------------------------------- 1 | name: rust-next 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | schedule: 8 | - cron: '3 3 3 * *' 9 | 10 | env: 11 | RUST_BACKTRACE: 1 12 | CARGO_TERM_COLOR: always 13 | CLICOLOR: 1 14 | 15 | concurrency: 16 | group: "${{ github.workflow }}-${{ github.ref }}" 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | test: 21 | name: Test 22 | strategy: 23 | matrix: 24 | os: ["ubuntu-latest", "windows-latest", "macos-latest"] 25 | rust: ["stable", "beta"] 26 | include: 27 | - os: ubuntu-latest 28 | rust: "nightly" 29 | continue-on-error: ${{ matrix.rust != 'stable' }} 30 | runs-on: ${{ matrix.os }} 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v4 34 | - name: Install Rust 35 | uses: dtolnay/rust-toolchain@stable 36 | with: 37 | toolchain: ${{ matrix.rust }} 38 | - uses: Swatinem/rust-cache@v2 39 | - uses: taiki-e/install-action@cargo-hack 40 | - name: Build 41 | run: cargo test --workspace --no-run 42 | - name: Test 43 | run: cargo hack test --each-feature --workspace 44 | latest: 45 | name: "Check latest dependencies" 46 | runs-on: ubuntu-latest 47 | steps: 48 | - name: Checkout repository 49 | uses: actions/checkout@v4 50 | - name: Install Rust 51 | uses: dtolnay/rust-toolchain@stable 52 | with: 53 | toolchain: stable 54 | - uses: Swatinem/rust-cache@v2 55 | - uses: taiki-e/install-action@cargo-hack 56 | - name: Update dependencies 57 | run: cargo update 58 | - name: Build 59 | run: cargo test --workspace --no-run 60 | - name: Test 61 | run: cargo hack test --each-feature --workspace 62 | -------------------------------------------------------------------------------- /.github/workflows/spelling.yml: -------------------------------------------------------------------------------- 1 | name: Spelling 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: [pull_request] 7 | 8 | env: 9 | RUST_BACKTRACE: 1 10 | CARGO_TERM_COLOR: always 11 | CLICOLOR: 1 12 | 13 | concurrency: 14 | group: "${{ github.workflow }}-${{ github.ref }}" 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | spelling: 19 | name: Spell Check with Typos 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout Actions Repository 23 | uses: actions/checkout@v4 24 | - name: Spell Check Repo 25 | uses: crate-ci/typos@master 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_install_hook_types: ["pre-commit", "commit-msg"] 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v5.0.0 5 | hooks: 6 | - id: check-yaml 7 | - id: check-json 8 | - id: check-toml 9 | - id: check-merge-conflict 10 | - id: check-case-conflict 11 | - id: detect-private-key 12 | - repo: https://github.com/crate-ci/typos 13 | rev: v1.32.0 14 | hooks: 15 | - id: typos 16 | - repo: https://github.com/crate-ci/committed 17 | rev: v1.1.7 18 | hooks: 19 | - id: committed 20 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | 8 | ## [Unreleased] - ReleaseDate 9 | 10 | ## [3.0.3] - 2025-05-20 11 | 12 | ## [3.0.2] - 2024-12-16 13 | 14 | ### Features 15 | 16 | - Add a `Copy` impl to `Verbosity` 17 | 18 | ## [3.0.1] - 2024-11-26 19 | 20 | ### Features 21 | 22 | - Add `impl From` for logging level and level-filter types 23 | 24 | ## [3.0.0] - 2024-11-20 25 | 26 | ### Breaking Changes 27 | 28 | - Log support put behind the default `log` feature 29 | - `LogLevel::default` renamed to `LogLevel::default_filter` and now returns `VerbosityFilter` 30 | - `Level` and `LevelFilter` are moved into the `log` mod 31 | 32 | ### Features 33 | 34 | - Add `tracing` feature with `Verbosity::tracing_level` and `Verbosity::tracing_level_filter` 35 | 36 | ## [2.2.3] - 2024-11-16 37 | 38 | ### Features 39 | 40 | - Add `DebugLevel` and `TraceLevel` for exploratory programming 41 | 42 | ## [2.2.2] - 2024-09-26 43 | 44 | ### Fixes 45 | 46 | - Resolve overflow issues 47 | 48 | ## [2.2.1] - 2024-07-25 49 | 50 | ### Compatibility 51 | 52 | - Raised MSRV to 1.74 53 | 54 | ## [2.2.0] - 2024-02-14 55 | 56 | ### Compatibility 57 | 58 | - Raised MSRV to 1.73 59 | 60 | ### Features 61 | 62 | - Add `is_present()` to see if one of the flags is present on the command-line 63 | 64 | ## [2.1.2] - 2024-01-16 65 | 66 | ### Fixes 67 | 68 | - Don't pollute the CLIs help 69 | 70 | ## [2.1.1] - 2023-12-15 71 | 72 | ### Fixes 73 | 74 | - Tried to clarify help output for `-v` / `-q` 75 | 76 | ### Documentation 77 | 78 | - Tried to clarify role of `LogLevel` trait 79 | 80 | ## [2.1.0] - 2023-10-23 81 | 82 | ### Compatibility 83 | 84 | - Raised MSRV to 1.70.0 85 | 86 | ### Features 87 | 88 | - Implement `Default` 89 | 90 | ## [2.0.1] - 2023-03-29 91 | 92 | ### Features 93 | 94 | - Re-export enums from `log` 95 | 96 | ## [2.0.0] - 2022-09-28 97 | 98 | ### Breaking Changes 99 | 100 | - Upgraded to clap v4 101 | 102 | ### Compatibility 103 | 104 | - Raised MSRV to 1.60.0 105 | 106 | ## [1.0.1] - 2022-06-13 107 | 108 | ### Fixes 109 | 110 | - Clarify relationship with `log` 111 | 112 | ## [1.0.0] - 2022-02-09 113 | 114 | ### Breaking Changes 115 | 116 | - `set_default`has been removed in favor of being generic over `LogLevel`. 117 | - `--verbose` and `--quiet` are now global 118 | 119 | ### Features 120 | 121 | - Allow customizing help text 122 | 123 | ### Fixes 124 | 125 | - `--verbose` and `--quiet` are now global 126 | 127 | ## [0.4.1] - 2022-01-27 128 | 129 | ### Features 130 | 131 | - Added `log_level_filter` for convenience 132 | 133 | ### Fixes 134 | 135 | - `Display` now shows the combination of quiet and verbose 136 | - Improved examples in documentation 137 | 138 | ## [0.4.0] - 2021-12-31 139 | 140 | ### Breaking Changes 141 | 142 | - Upgraded to clap3 143 | 144 | ## [0.3.2] - 2021-08-07 145 | 146 | ### Added 147 | 148 | - Allow instantiating the struct 149 | 150 | ## [0.3.1] - 2020-01-16 151 | 152 | ### Fixed 153 | 154 | - Workaround bug in structopt causing `clap-verbosity-flag`s doc-comment to win out over the caller's 155 | 156 | ## [0.3.0] - 2019-10-17 157 | ### Added 158 | - Support `.set_default_level()` for configuring the default level 159 | - `--quiet` is now supported 160 | - Support Logging being disabled via `None` 161 | 162 | ### Breaking Changes 163 | - `structopt` 0.3 is now required 164 | - Removed `setuop_env_logger`. requiring you to configure the logger yourself. 165 | - `--verbosiy` changed to `--verbose` 166 | - `log_level` now returns an `Option` with the intention that `None` means no user-visible outpiut (including logging) 167 | 168 | ## [0.2.0] - 2017-06-02 169 | 170 | 171 | [Unreleased]: https://github.com/clap-rs/clap-verbosity-flag/compare/v3.0.3...HEAD 172 | [3.0.3]: https://github.com/clap-rs/clap-verbosity-flag/compare/v3.0.2...v3.0.3 173 | [3.0.2]: https://github.com/clap-rs/clap-verbosity-flag/compare/v3.0.1...v3.0.2 174 | [3.0.1]: https://github.com/clap-rs/clap-verbosity-flag/compare/v3.0.0...v3.0.1 175 | [3.0.0]: https://github.com/clap-rs/clap-verbosity-flag/compare/v2.2.3...v3.0.0 176 | [2.2.3]: https://github.com/clap-rs/clap-verbosity-flag/compare/v2.2.2...v2.2.3 177 | [2.2.2]: https://github.com/clap-rs/clap-verbosity-flag/compare/v2.2.1...v2.2.2 178 | [2.2.1]: https://github.com/clap-rs/clap-verbosity-flag/compare/v2.2.0...v2.2.1 179 | [2.2.0]: https://github.com/clap-rs/clap-verbosity-flag/compare/v2.1.2...v2.2.0 180 | [2.1.2]: https://github.com/clap-rs/clap-verbosity-flag/compare/v2.1.1...v2.1.2 181 | [2.1.1]: https://github.com/clap-rs/clap-verbosity-flag/compare/v2.1.0...v2.1.1 182 | [2.1.0]: https://github.com/clap-rs/clap-verbosity-flag/compare/v2.0.1...v2.1.0 183 | [2.0.1]: https://github.com/clap-rs/clap-verbosity-flag/compare/v2.0.0...v2.0.1 184 | [2.0.0]: https://github.com/clap-rs/clap-verbosity-flag/compare/v1.0.1...v2.0.0 185 | [1.0.1]: https://github.com/clap-rs/clap-verbosity-flag/compare/v1.0.0...v1.0.1 186 | [1.0.0]: https://github.com/clap-rs/clap-verbosity-flag/compare/v0.4.1...v1.0.0 187 | [0.4.1]: https://github.com/clap-rs/clap-verbosity-flag/compare/v0.4.0...v0.4.1 188 | [0.4.0]: https://github.com/clap-rs/clap-verbosity-flag/compare/v0.3.2...v0.4.0 189 | [0.3.2]: https://github.com/clap-rs/clap-verbosity-flag/compare/v0.3.1...v0.3.2 190 | [0.3.1]: https://github.com/clap-rs/clap-verbosity-flag/compare/v0.3.0...v0.3.1 191 | [0.3.0]: https://github.com/clap-rs/clap-verbosity-flag/compare/0.2.0...v0.3.0 192 | [0.2.0]: https://github.com/clap-rs/clap-verbosity-flag/compare/v0.1.0...0.2.0 193 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to stager 2 | 3 | Thanks for wanting to contribute! There are many ways to contribute and we 4 | appreciate any level you're willing to do. 5 | 6 | ## Feature Requests 7 | 8 | Need some new functionality to help? You can let us know by opening an 9 | [issue][new issue]. It's helpful to look through [all issues][all issues] in 10 | case it's already being talked about. 11 | 12 | ## Bug Reports 13 | 14 | Please let us know about what problems you run into, whether in behavior or 15 | ergonomics of API. You can do this by opening an [issue][new issue]. It's 16 | helpful to look through [all issues][all issues] in case it's already being 17 | talked about. 18 | 19 | ## Pull Requests 20 | 21 | Looking for an idea? Check our [issues][issues]. If the issue looks open ended, 22 | it is probably best to post on the issue how you are thinking of resolving the 23 | issue so you can get feedback early in the process. We want you to be 24 | successful and it can be discouraging to find out a lot of re-work is needed. 25 | 26 | Already have an idea? It might be good to first [create an issue][new issue] 27 | to propose it so we can make sure we are aligned and lower the risk of having 28 | to re-work some of it and the discouragement that goes along with that. 29 | 30 | ### Process 31 | 32 | As a heads up, we'll be running your PR through the following gauntlet: 33 | - warnings turned to compile errors 34 | - `cargo test` 35 | - `rustfmt` 36 | - `clippy` 37 | - `rustdoc` 38 | - [`committed`](https://github.com/crate-ci/committed) as we use [Conventional](https://www.conventionalcommits.org) commit style 39 | - [`typos`](https://github.com/crate-ci/typos) to check spelling 40 | 41 | Not everything can be checked automatically though. 42 | 43 | We request that the commit history gets cleaned up. 44 | 45 | We ask that commits are atomic, meaning they are complete and have a single responsibility. 46 | A complete commit should build, pass tests, update documentation and tests, and not have dead code. 47 | 48 | PRs should tell a cohesive story, with refactor and test commits that keep the 49 | fix or feature commits simple and clear. 50 | 51 | Specifically, we would encourage 52 | - File renames be isolated into their own commit 53 | - Add tests in a commit before their feature or fix, showing the current behavior (i.e. they should pass). 54 | The diff for the feature/fix commit will then show how the behavior changed, 55 | making the commit's intent clearer to reviewers and the community, and showing people that the 56 | test is verifying the expected state. 57 | - e.g. [clap#5520](https://github.com/clap-rs/clap/pull/5520) 58 | 59 | Note that we are talking about ideals. 60 | We understand having a clean history requires more advanced git skills; 61 | feel free to ask us for help! 62 | We might even suggest where it would work to be lax. 63 | We also understand that editing some early commits may cause a lot of churn 64 | with merge conflicts which can make it not worth editing all of the history. 65 | 66 | For code organization, we recommend 67 | - Grouping `impl` blocks next to their type (or trait) 68 | - Grouping private items after the `pub` item that uses them. 69 | - The intent is to help people quickly find the "relevant" details, allowing them to "dig deeper" as needed. Or put another way, the `pub` items serve as a table-of-contents. 70 | - The exact order is fuzzy; do what makes sense 71 | 72 | ## Releasing 73 | 74 | Pre-requisites 75 | - Running `cargo login` 76 | - A member of `rust-cli:Maintainers` 77 | - Push permission to the repo 78 | - [`cargo-release`](https://github.com/crate-ci/cargo-release/) 79 | 80 | When we're ready to release, a project owner should do the following 81 | 1. Update the changelog (see `cargo release changes` for ideas) 82 | 2. Determine what the next version is, according to semver 83 | 3. Run [`cargo release -x `](https://github.com/crate-ci/cargo-release) 84 | 85 | [issues]: https://github.com/crate-ci/clap-verbosity-flag/issues 86 | [new issue]: https://github.com/crate-ci/clap-verbosity-flag/issues/new 87 | [all issues]: https://github.com/crate-ci/clap-verbosity-flag/issues?utf8=%E2%9C%93&q=is%3Aissue 88 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anstream" 16 | version = "0.6.11" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" 19 | dependencies = [ 20 | "anstyle", 21 | "anstyle-parse", 22 | "anstyle-query", 23 | "anstyle-wincon", 24 | "colorchoice", 25 | "utf8parse", 26 | ] 27 | 28 | [[package]] 29 | name = "anstyle" 30 | version = "1.0.8" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" 33 | 34 | [[package]] 35 | name = "anstyle-parse" 36 | version = "0.2.3" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" 39 | dependencies = [ 40 | "utf8parse", 41 | ] 42 | 43 | [[package]] 44 | name = "anstyle-query" 45 | version = "1.0.2" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" 48 | dependencies = [ 49 | "windows-sys", 50 | ] 51 | 52 | [[package]] 53 | name = "anstyle-wincon" 54 | version = "3.0.2" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" 57 | dependencies = [ 58 | "anstyle", 59 | "windows-sys", 60 | ] 61 | 62 | [[package]] 63 | name = "clap" 64 | version = "4.5.31" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" 67 | dependencies = [ 68 | "clap_builder", 69 | "clap_derive", 70 | ] 71 | 72 | [[package]] 73 | name = "clap-verbosity-flag" 74 | version = "3.0.3" 75 | dependencies = [ 76 | "clap", 77 | "env_logger", 78 | "log", 79 | "tracing", 80 | "tracing-core", 81 | "tracing-subscriber", 82 | ] 83 | 84 | [[package]] 85 | name = "clap_builder" 86 | version = "4.5.31" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" 89 | dependencies = [ 90 | "anstyle", 91 | "clap_lex", 92 | ] 93 | 94 | [[package]] 95 | name = "clap_derive" 96 | version = "4.5.28" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" 99 | dependencies = [ 100 | "heck", 101 | "proc-macro2", 102 | "quote", 103 | "syn", 104 | ] 105 | 106 | [[package]] 107 | name = "clap_lex" 108 | version = "0.7.4" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 111 | 112 | [[package]] 113 | name = "colorchoice" 114 | version = "1.0.0" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 117 | 118 | [[package]] 119 | name = "env_filter" 120 | version = "0.1.0" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" 123 | dependencies = [ 124 | "log", 125 | "regex", 126 | ] 127 | 128 | [[package]] 129 | name = "env_logger" 130 | version = "0.11.6" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" 133 | dependencies = [ 134 | "anstream", 135 | "anstyle", 136 | "env_filter", 137 | "humantime", 138 | "log", 139 | ] 140 | 141 | [[package]] 142 | name = "heck" 143 | version = "0.5.0" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 146 | 147 | [[package]] 148 | name = "humantime" 149 | version = "2.1.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 152 | 153 | [[package]] 154 | name = "lazy_static" 155 | version = "1.4.0" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 158 | 159 | [[package]] 160 | name = "log" 161 | version = "0.4.21" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 164 | 165 | [[package]] 166 | name = "memchr" 167 | version = "2.5.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 170 | 171 | [[package]] 172 | name = "nu-ansi-term" 173 | version = "0.46.0" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 176 | dependencies = [ 177 | "overload", 178 | "winapi", 179 | ] 180 | 181 | [[package]] 182 | name = "once_cell" 183 | version = "1.18.0" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 186 | 187 | [[package]] 188 | name = "overload" 189 | version = "0.1.1" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 192 | 193 | [[package]] 194 | name = "pin-project-lite" 195 | version = "0.2.9" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 198 | 199 | [[package]] 200 | name = "proc-macro2" 201 | version = "1.0.73" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "2dd5e8a1f1029c43224ad5898e50140c2aebb1705f19e67c918ebf5b9e797fe1" 204 | dependencies = [ 205 | "unicode-ident", 206 | ] 207 | 208 | [[package]] 209 | name = "quote" 210 | version = "1.0.34" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a" 213 | dependencies = [ 214 | "proc-macro2", 215 | ] 216 | 217 | [[package]] 218 | name = "regex" 219 | version = "1.5.6" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" 222 | dependencies = [ 223 | "aho-corasick", 224 | "memchr", 225 | "regex-syntax", 226 | ] 227 | 228 | [[package]] 229 | name = "regex-syntax" 230 | version = "0.6.26" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" 233 | 234 | [[package]] 235 | name = "sharded-slab" 236 | version = "0.1.4" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" 239 | dependencies = [ 240 | "lazy_static", 241 | ] 242 | 243 | [[package]] 244 | name = "smallvec" 245 | version = "1.13.2" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 248 | 249 | [[package]] 250 | name = "syn" 251 | version = "2.0.44" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "92d27c2c202598d05175a6dd3af46824b7f747f8d8e9b14c623f19fa5069735d" 254 | dependencies = [ 255 | "proc-macro2", 256 | "quote", 257 | "unicode-ident", 258 | ] 259 | 260 | [[package]] 261 | name = "thread_local" 262 | version = "1.1.4" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" 265 | dependencies = [ 266 | "once_cell", 267 | ] 268 | 269 | [[package]] 270 | name = "tracing" 271 | version = "0.1.41" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 274 | dependencies = [ 275 | "pin-project-lite", 276 | "tracing-attributes", 277 | "tracing-core", 278 | ] 279 | 280 | [[package]] 281 | name = "tracing-attributes" 282 | version = "0.1.28" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 285 | dependencies = [ 286 | "proc-macro2", 287 | "quote", 288 | "syn", 289 | ] 290 | 291 | [[package]] 292 | name = "tracing-core" 293 | version = "0.1.33" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 296 | dependencies = [ 297 | "once_cell", 298 | "valuable", 299 | ] 300 | 301 | [[package]] 302 | name = "tracing-log" 303 | version = "0.2.0" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 306 | dependencies = [ 307 | "log", 308 | "once_cell", 309 | "tracing-core", 310 | ] 311 | 312 | [[package]] 313 | name = "tracing-subscriber" 314 | version = "0.3.19" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 317 | dependencies = [ 318 | "nu-ansi-term", 319 | "sharded-slab", 320 | "smallvec", 321 | "thread_local", 322 | "tracing-core", 323 | "tracing-log", 324 | ] 325 | 326 | [[package]] 327 | name = "unicode-ident" 328 | version = "1.0.0" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" 331 | 332 | [[package]] 333 | name = "utf8parse" 334 | version = "0.2.1" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 337 | 338 | [[package]] 339 | name = "valuable" 340 | version = "0.1.0" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 343 | 344 | [[package]] 345 | name = "winapi" 346 | version = "0.3.9" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 349 | dependencies = [ 350 | "winapi-i686-pc-windows-gnu", 351 | "winapi-x86_64-pc-windows-gnu", 352 | ] 353 | 354 | [[package]] 355 | name = "winapi-i686-pc-windows-gnu" 356 | version = "0.4.0" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 359 | 360 | [[package]] 361 | name = "winapi-x86_64-pc-windows-gnu" 362 | version = "0.4.0" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 365 | 366 | [[package]] 367 | name = "windows-sys" 368 | version = "0.52.0" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 371 | dependencies = [ 372 | "windows-targets", 373 | ] 374 | 375 | [[package]] 376 | name = "windows-targets" 377 | version = "0.52.0" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" 380 | dependencies = [ 381 | "windows_aarch64_gnullvm", 382 | "windows_aarch64_msvc", 383 | "windows_i686_gnu", 384 | "windows_i686_msvc", 385 | "windows_x86_64_gnu", 386 | "windows_x86_64_gnullvm", 387 | "windows_x86_64_msvc", 388 | ] 389 | 390 | [[package]] 391 | name = "windows_aarch64_gnullvm" 392 | version = "0.52.0" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" 395 | 396 | [[package]] 397 | name = "windows_aarch64_msvc" 398 | version = "0.52.0" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" 401 | 402 | [[package]] 403 | name = "windows_i686_gnu" 404 | version = "0.52.0" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" 407 | 408 | [[package]] 409 | name = "windows_i686_msvc" 410 | version = "0.52.0" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" 413 | 414 | [[package]] 415 | name = "windows_x86_64_gnu" 416 | version = "0.52.0" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" 419 | 420 | [[package]] 421 | name = "windows_x86_64_gnullvm" 422 | version = "0.52.0" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" 425 | 426 | [[package]] 427 | name = "windows_x86_64_msvc" 428 | version = "0.52.0" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" 431 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | 4 | [workspace.package] 5 | repository = "https://github.com/clap-rs/clap-verbosity-flag" 6 | license = "MIT OR Apache-2.0" 7 | edition = "2021" 8 | rust-version = "1.74" # MSRV 9 | include = [ 10 | "build.rs", 11 | "src/**/*", 12 | "Cargo.toml", 13 | "Cargo.lock", 14 | "LICENSE*", 15 | "README.md", 16 | "examples/**/*" 17 | ] 18 | 19 | [workspace.lints.rust] 20 | rust_2018_idioms = { level = "warn", priority = -1 } 21 | unnameable_types = "warn" 22 | unreachable_pub = "warn" 23 | unsafe_op_in_unsafe_fn = "warn" 24 | unused_lifetimes = "warn" 25 | unused_macro_rules = "warn" 26 | unused_qualifications = "warn" 27 | 28 | [workspace.lints.clippy] 29 | bool_assert_comparison = "allow" 30 | branches_sharing_code = "allow" 31 | checked_conversions = "warn" 32 | collapsible_else_if = "allow" 33 | create_dir = "warn" 34 | dbg_macro = "warn" 35 | debug_assert_with_mut_call = "warn" 36 | doc_markdown = "warn" 37 | empty_enum = "warn" 38 | enum_glob_use = "warn" 39 | expl_impl_clone_on_copy = "warn" 40 | explicit_deref_methods = "warn" 41 | explicit_into_iter_loop = "warn" 42 | fallible_impl_from = "warn" 43 | filter_map_next = "warn" 44 | flat_map_option = "warn" 45 | float_cmp_const = "warn" 46 | fn_params_excessive_bools = "warn" 47 | from_iter_instead_of_collect = "warn" 48 | if_same_then_else = "allow" 49 | implicit_clone = "warn" 50 | imprecise_flops = "warn" 51 | inconsistent_struct_constructor = "warn" 52 | inefficient_to_string = "warn" 53 | infinite_loop = "warn" 54 | invalid_upcast_comparisons = "warn" 55 | large_digit_groups = "warn" 56 | large_stack_arrays = "warn" 57 | large_types_passed_by_value = "warn" 58 | let_and_return = "allow" # sometimes good to name what you are returning 59 | linkedlist = "warn" 60 | lossy_float_literal = "warn" 61 | macro_use_imports = "warn" 62 | mem_forget = "warn" 63 | mutex_integer = "warn" 64 | needless_continue = "allow" 65 | needless_for_each = "warn" 66 | negative_feature_names = "warn" 67 | path_buf_push_overwrite = "warn" 68 | ptr_as_ptr = "warn" 69 | rc_mutex = "warn" 70 | redundant_feature_names = "warn" 71 | ref_option_ref = "warn" 72 | rest_pat_in_fully_bound_structs = "warn" 73 | result_large_err = "allow" 74 | same_functions_in_if_condition = "warn" 75 | self_named_module_files = "warn" 76 | semicolon_if_nothing_returned = "warn" 77 | str_to_string = "warn" 78 | string_add = "warn" 79 | string_add_assign = "warn" 80 | string_lit_as_bytes = "warn" 81 | string_to_string = "warn" 82 | todo = "warn" 83 | trait_duplication_in_bounds = "warn" 84 | uninlined_format_args = "warn" 85 | verbose_file_reads = "warn" 86 | wildcard_imports = "warn" 87 | zero_sized_map_values = "warn" 88 | 89 | [profile.dev] 90 | panic = "abort" 91 | 92 | [profile.release] 93 | panic = "abort" 94 | codegen-units = 1 95 | lto = true 96 | # debug = "line-tables-only" # requires Cargo 1.71 97 | 98 | [package] 99 | name = "clap-verbosity-flag" 100 | version = "3.0.3" 101 | description = "Easily add a `--verbose` flag to CLIs using Clap" 102 | authors = ["Pascal Hertleif "] 103 | readme = "README.md" 104 | repository.workspace = true 105 | license.workspace = true 106 | edition.workspace = true 107 | rust-version.workspace = true 108 | include.workspace = true 109 | 110 | [package.metadata.docs.rs] 111 | all-features = true 112 | rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] 113 | 114 | [package.metadata.release] 115 | pre-release-replacements = [ 116 | {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, 117 | {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, 118 | {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1}, 119 | {file="CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate\n", exactly=1}, 120 | {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/clap-rs/clap-verbosity-flag/compare/{{tag_name}}...HEAD", exactly=1}, 121 | ] 122 | 123 | [badges] 124 | codecov = { repository = "clap-rs/clap-verbosity-flag" } 125 | 126 | [features] 127 | default = ["log"] 128 | log = ["dep:log"] 129 | tracing = ["dep:tracing-core"] 130 | 131 | [dependencies] 132 | clap = { version = "4.0.0", default-features = false, features = ["std", "derive"] } 133 | log = { version = "0.4.1", optional = true } 134 | tracing-core = { version = "0.1", optional = true } 135 | 136 | [dev-dependencies] 137 | clap = { version = "4.5.4", default-features = false, features = ["help", "usage"] } 138 | env_logger = "0.11.3" 139 | tracing = "0.1" 140 | tracing-subscriber = "0.3" 141 | 142 | [lints] 143 | workspace = true 144 | 145 | [[example]] 146 | name = "log" 147 | required-features = ["log"] 148 | 149 | [[example]] 150 | name = "log_level" 151 | required-features = ["log"] 152 | 153 | [[example]] 154 | name = "tracing" 155 | required-features = ["tracing"] 156 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) Individual contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clap-verbosity-flag for `log` / `tracing` 2 | 3 | [![Documentation](https://img.shields.io/badge/docs-master-blue.svg)][Documentation] 4 | ![License](https://img.shields.io/crates/l/clap-verbosity-flag.svg) 5 | [![crates.io](https://img.shields.io/crates/v/clap-verbosity-flag.svg)][Crates.io] 6 | 7 | [Crates.io]: https://crates.io/crates/clap-verbosity-flag 8 | [Documentation]: https://docs.rs/clap-verbosity-flag/ 9 | 10 | Easily add `--verbose` and `--quiet` flags to CLIs using [Clap](http://crates.io/crates/clap). 11 | 12 | ## Examples 13 | 14 | ```console 15 | $ cargo add clap-verbosity-flag 16 | ``` 17 | 18 | ```rust 19 | use clap::Parser; 20 | 21 | #[derive(Debug, Parser)] 22 | struct Cli { 23 | #[command(flatten)] 24 | verbosity: clap_verbosity_flag::Verbosity, 25 | } 26 | 27 | fn main() { 28 | let args = Cli::parse(); 29 | env_logger::Builder::new() 30 | .filter_level(args.verbosity.into()) 31 | .init(); 32 | // Your code here 33 | } 34 | ``` 35 | 36 | For [`tracing`](https://crates.io/crates/tracing) support, use the `tracing` feature: 37 | 38 | ```console 39 | $ cargo add clap-verbosity-flag --no-default-features --features tracing 40 | ``` 41 | 42 | ```rust 43 | use clap::Parser; 44 | 45 | #[derive(Debug, Parser)] 46 | struct Cli { 47 | #[command(flatten)] 48 | verbosity: clap_verbosity_flag::Verbosity, 49 | } 50 | 51 | fn main() { 52 | let args = Cli::parse(); 53 | tracing_subscriber::fmt() 54 | .with_max_level(args.verbosity) 55 | .init(); 56 | // Your code here 57 | } 58 | ``` 59 | 60 | The default verbosity level will cause `log` / `tracing` to only report errors. The flags can be 61 | specified multiple times to increase or decrease the verbosity level. See the [Documentation] for 62 | info on how to change the default verbosity level. 63 | 64 | - silence output: `-q` / `--quiet` 65 | - show warnings: `-v` / `--verbose` 66 | - show info: `-vv` / `--verbose --verbose` 67 | - show debug: `-vvv` / `--verbose --verbose --verbose` 68 | - show trace: `-vvvv` / `--verbose --verbose --verbose --verbose` 69 | 70 | ## License 71 | 72 | Licensed under either of 73 | 74 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) 75 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or ) 76 | 77 | at your option. 78 | 79 | ### Contribution 80 | 81 | Unless you explicitly state otherwise, any contribution intentionally 82 | submitted for inclusion in the work by you, as defined in the Apache-2.0 83 | license, shall be dual-licensed as above, without any additional terms or 84 | conditions. 85 | -------------------------------------------------------------------------------- /committed.toml: -------------------------------------------------------------------------------- 1 | style="conventional" 2 | ignore_author_re="(dependabot|renovate)" 3 | merge_commit = false 4 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | # Note that all fields that take a lint level have these possible values: 2 | # * deny - An error will be produced and the check will fail 3 | # * warn - A warning will be produced, but the check will not fail 4 | # * allow - No warning or error will be produced, though in some cases a note 5 | # will be 6 | 7 | # Root options 8 | 9 | # The graph table configures how the dependency graph is constructed and thus 10 | # which crates the checks are performed against 11 | [graph] 12 | # If 1 or more target triples (and optionally, target_features) are specified, 13 | # only the specified targets will be checked when running `cargo deny check`. 14 | # This means, if a particular package is only ever used as a target specific 15 | # dependency, such as, for example, the `nix` crate only being used via the 16 | # `target_family = "unix"` configuration, that only having windows targets in 17 | # this list would mean the nix crate, as well as any of its exclusive 18 | # dependencies not shared by any other crates, would be ignored, as the target 19 | # list here is effectively saying which targets you are building for. 20 | targets = [ 21 | # The triple can be any string, but only the target triples built in to 22 | # rustc (as of 1.40) can be checked against actual config expressions 23 | #"x86_64-unknown-linux-musl", 24 | # You can also specify which target_features you promise are enabled for a 25 | # particular target. target_features are currently not validated against 26 | # the actual valid features supported by the target architecture. 27 | #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, 28 | ] 29 | # When creating the dependency graph used as the source of truth when checks are 30 | # executed, this field can be used to prune crates from the graph, removing them 31 | # from the view of cargo-deny. This is an extremely heavy hammer, as if a crate 32 | # is pruned from the graph, all of its dependencies will also be pruned unless 33 | # they are connected to another crate in the graph that hasn't been pruned, 34 | # so it should be used with care. The identifiers are [Package ID Specifications] 35 | # (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html) 36 | #exclude = [] 37 | # If true, metadata will be collected with `--all-features`. Note that this can't 38 | # be toggled off if true, if you want to conditionally enable `--all-features` it 39 | # is recommended to pass `--all-features` on the cmd line instead 40 | all-features = false 41 | # If true, metadata will be collected with `--no-default-features`. The same 42 | # caveat with `all-features` applies 43 | no-default-features = false 44 | # If set, these feature will be enabled when collecting metadata. If `--features` 45 | # is specified on the cmd line they will take precedence over this option. 46 | #features = [] 47 | 48 | # The output table provides options for how/if diagnostics are outputted 49 | [output] 50 | # When outputting inclusion graphs in diagnostics that include features, this 51 | # option can be used to specify the depth at which feature edges will be added. 52 | # This option is included since the graphs can be quite large and the addition 53 | # of features from the crate(s) to all of the graph roots can be far too verbose. 54 | # This option can be overridden via `--feature-depth` on the cmd line 55 | feature-depth = 1 56 | 57 | # This section is considered when running `cargo deny check advisories` 58 | # More documentation for the advisories section can be found here: 59 | # https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html 60 | [advisories] 61 | # The path where the advisory databases are cloned/fetched into 62 | #db-path = "$CARGO_HOME/advisory-dbs" 63 | # The url(s) of the advisory databases to use 64 | #db-urls = ["https://github.com/rustsec/advisory-db"] 65 | # A list of advisory IDs to ignore. Note that ignored advisories will still 66 | # output a note when they are encountered. 67 | ignore = [ 68 | #"RUSTSEC-0000-0000", 69 | #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, 70 | #"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish 71 | #{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" }, 72 | ] 73 | # If this is true, then cargo deny will use the git executable to fetch advisory database. 74 | # If this is false, then it uses a built-in git library. 75 | # Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support. 76 | # See Git Authentication for more information about setting up git authentication. 77 | #git-fetch-with-cli = true 78 | 79 | # This section is considered when running `cargo deny check licenses` 80 | # More documentation for the licenses section can be found here: 81 | # https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html 82 | [licenses] 83 | # List of explicitly allowed licenses 84 | # See https://spdx.org/licenses/ for list of possible licenses 85 | # [possible values: any SPDX 3.11 short identifier (+ optional exception)]. 86 | allow = [ 87 | "MIT", 88 | "MIT-0", 89 | "Apache-2.0", 90 | "BSD-2-Clause", 91 | "BSD-3-Clause", 92 | "MPL-2.0", 93 | "Unicode-DFS-2016", 94 | "CC0-1.0", 95 | "ISC", 96 | "OpenSSL", 97 | ] 98 | # The confidence threshold for detecting a license from license text. 99 | # The higher the value, the more closely the license text must be to the 100 | # canonical license text of a valid SPDX license file. 101 | # [possible values: any between 0.0 and 1.0]. 102 | confidence-threshold = 0.8 103 | # Allow 1 or more licenses on a per-crate basis, so that particular licenses 104 | # aren't accepted for every possible crate as with the normal allow list 105 | exceptions = [ 106 | # Each entry is the crate and version constraint, and its specific allow 107 | # list 108 | #{ allow = ["Zlib"], crate = "adler32" }, 109 | ] 110 | 111 | # Some crates don't have (easily) machine readable licensing information, 112 | # adding a clarification entry for it allows you to manually specify the 113 | # licensing information 114 | [[licenses.clarify]] 115 | # The package spec the clarification applies to 116 | crate = "ring" 117 | # The SPDX expression for the license requirements of the crate 118 | expression = "MIT AND ISC AND OpenSSL" 119 | # One or more files in the crate's source used as the "source of truth" for 120 | # the license expression. If the contents match, the clarification will be used 121 | # when running the license check, otherwise the clarification will be ignored 122 | # and the crate will be checked normally, which may produce warnings or errors 123 | # depending on the rest of your configuration 124 | license-files = [ 125 | # Each entry is a crate relative path, and the (opaque) hash of its contents 126 | { path = "LICENSE", hash = 0xbd0eed23 } 127 | ] 128 | 129 | [licenses.private] 130 | # If true, ignores workspace crates that aren't published, or are only 131 | # published to private registries. 132 | # To see how to mark a crate as unpublished (to the official registry), 133 | # visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field. 134 | ignore = true 135 | # One or more private registries that you might publish crates to, if a crate 136 | # is only published to private registries, and ignore is true, the crate will 137 | # not have its license(s) checked 138 | registries = [ 139 | #"https://sekretz.com/registry 140 | ] 141 | 142 | # This section is considered when running `cargo deny check bans`. 143 | # More documentation about the 'bans' section can be found here: 144 | # https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html 145 | [bans] 146 | # Lint level for when multiple versions of the same crate are detected 147 | multiple-versions = "warn" 148 | # Lint level for when a crate version requirement is `*` 149 | wildcards = "allow" 150 | # The graph highlighting used when creating dotgraphs for crates 151 | # with multiple versions 152 | # * lowest-version - The path to the lowest versioned duplicate is highlighted 153 | # * simplest-path - The path to the version with the fewest edges is highlighted 154 | # * all - Both lowest-version and simplest-path are used 155 | highlight = "all" 156 | # The default lint level for `default` features for crates that are members of 157 | # the workspace that is being checked. This can be overridden by allowing/denying 158 | # `default` on a crate-by-crate basis if desired. 159 | workspace-default-features = "allow" 160 | # The default lint level for `default` features for external crates that are not 161 | # members of the workspace. This can be overridden by allowing/denying `default` 162 | # on a crate-by-crate basis if desired. 163 | external-default-features = "allow" 164 | # List of crates that are allowed. Use with care! 165 | allow = [ 166 | #"ansi_term@0.11.0", 167 | #{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is allowed" }, 168 | ] 169 | # List of crates to deny 170 | deny = [ 171 | #"ansi_term@0.11.0", 172 | #{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is banned" }, 173 | # Wrapper crates can optionally be specified to allow the crate when it 174 | # is a direct dependency of the otherwise banned crate 175 | #{ crate = "ansi_term@0.11.0", wrappers = ["this-crate-directly-depends-on-ansi_term"] }, 176 | ] 177 | 178 | # List of features to allow/deny 179 | # Each entry the name of a crate and a version range. If version is 180 | # not specified, all versions will be matched. 181 | #[[bans.features]] 182 | #crate = "reqwest" 183 | # Features to not allow 184 | #deny = ["json"] 185 | # Features to allow 186 | #allow = [ 187 | # "rustls", 188 | # "__rustls", 189 | # "__tls", 190 | # "hyper-rustls", 191 | # "rustls", 192 | # "rustls-pemfile", 193 | # "rustls-tls-webpki-roots", 194 | # "tokio-rustls", 195 | # "webpki-roots", 196 | #] 197 | # If true, the allowed features must exactly match the enabled feature set. If 198 | # this is set there is no point setting `deny` 199 | #exact = true 200 | 201 | # Certain crates/versions that will be skipped when doing duplicate detection. 202 | skip = [ 203 | #"ansi_term@0.11.0", 204 | #{ crate = "ansi_term@0.11.0", reason = "you can specify a reason why it can't be updated/removed" }, 205 | ] 206 | # Similarly to `skip` allows you to skip certain crates during duplicate 207 | # detection. Unlike skip, it also includes the entire tree of transitive 208 | # dependencies starting at the specified crate, up to a certain depth, which is 209 | # by default infinite. 210 | skip-tree = [ 211 | #"ansi_term@0.11.0", # will be skipped along with _all_ of its direct and transitive dependencies 212 | #{ crate = "ansi_term@0.11.0", depth = 20 }, 213 | ] 214 | 215 | # This section is considered when running `cargo deny check sources`. 216 | # More documentation about the 'sources' section can be found here: 217 | # https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html 218 | [sources] 219 | # Lint level for what to happen when a crate from a crate registry that is not 220 | # in the allow list is encountered 221 | unknown-registry = "deny" 222 | # Lint level for what to happen when a crate from a git repository that is not 223 | # in the allow list is encountered 224 | unknown-git = "deny" 225 | # List of URLs for allowed crate registries. Defaults to the crates.io index 226 | # if not specified. If it is specified but empty, no registries are allowed. 227 | allow-registry = ["https://github.com/rust-lang/crates.io-index"] 228 | # List of URLs for allowed Git repositories 229 | allow-git = [] 230 | 231 | [sources.allow-org] 232 | # 1 or more github.com organizations to allow git sources for 233 | github = [] 234 | # 1 or more gitlab.com organizations to allow git sources for 235 | gitlab = [] 236 | # 1 or more bitbucket.org organizations to allow git sources for 237 | bitbucket = [] 238 | -------------------------------------------------------------------------------- /examples/log.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use clap_verbosity_flag::Verbosity; 3 | 4 | /// Foo 5 | #[derive(Debug, Parser)] 6 | struct Cli { 7 | #[command(flatten)] 8 | verbosity: Verbosity, 9 | } 10 | 11 | fn main() { 12 | let cli = Cli::parse(); 13 | 14 | env_logger::Builder::new() 15 | .filter_level(cli.verbosity.into()) 16 | .init(); 17 | 18 | log::error!("Engines exploded"); 19 | log::warn!("Engines smoking"); 20 | log::info!("Engines exist"); 21 | log::debug!("Engine temperature is 200 degrees"); 22 | log::trace!("Engine subsection is 300 degrees"); 23 | } 24 | -------------------------------------------------------------------------------- /examples/log_level.rs: -------------------------------------------------------------------------------- 1 | //! Demonstrates how to set the default log level for the logger to something other than the default 2 | //! (`ErrorLevel`). This is done with multiple subcommands, each with their own verbosity level. 3 | 4 | use clap::{Parser, Subcommand}; 5 | use clap_verbosity_flag::{ 6 | DebugLevel, ErrorLevel, InfoLevel, OffLevel, TraceLevel, Verbosity, WarnLevel, 7 | }; 8 | 9 | #[derive(Debug, Parser)] 10 | struct Cli { 11 | #[command(subcommand)] 12 | command: Command, 13 | } 14 | 15 | #[derive(Debug, Subcommand)] 16 | enum Command { 17 | Off { 18 | #[command(flatten)] 19 | verbose: Verbosity, 20 | }, 21 | Error { 22 | #[command(flatten)] 23 | verbose: Verbosity, 24 | }, 25 | Warn { 26 | #[command(flatten)] 27 | verbose: Verbosity, 28 | }, 29 | Info { 30 | #[command(flatten)] 31 | verbose: Verbosity, 32 | }, 33 | Debug { 34 | #[command(flatten)] 35 | verbose: Verbosity, 36 | }, 37 | Trace { 38 | #[command(flatten)] 39 | verbose: Verbosity, 40 | }, 41 | } 42 | 43 | impl Command { 44 | fn log_level_filter(&self) -> log::LevelFilter { 45 | match self { 46 | Command::Off { verbose } => verbose.log_level_filter(), 47 | Command::Error { verbose } => verbose.log_level_filter(), 48 | Command::Warn { verbose } => verbose.log_level_filter(), 49 | Command::Info { verbose } => verbose.log_level_filter(), 50 | Command::Debug { verbose } => verbose.log_level_filter(), 51 | Command::Trace { verbose } => verbose.log_level_filter(), 52 | } 53 | } 54 | } 55 | 56 | fn main() { 57 | let cli = Cli::parse(); 58 | env_logger::Builder::new() 59 | .filter_level(cli.command.log_level_filter()) 60 | .init(); 61 | 62 | log::error!("Engines exploded"); 63 | log::warn!("Engines smoking"); 64 | log::info!("Engines exist"); 65 | log::debug!("Engine temperature is 200 degrees"); 66 | log::trace!("Engine subsection is 300 degrees"); 67 | } 68 | -------------------------------------------------------------------------------- /examples/tracing.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use clap_verbosity_flag::Verbosity; 3 | 4 | /// Foo 5 | #[derive(Debug, Parser)] 6 | struct Cli { 7 | #[command(flatten)] 8 | verbosity: Verbosity, 9 | } 10 | 11 | fn main() { 12 | let cli = Cli::parse(); 13 | 14 | tracing_subscriber::fmt() 15 | .with_max_level(cli.verbosity) 16 | .init(); 17 | 18 | tracing::error!("Engines exploded"); 19 | tracing::warn!("Engines smoking"); 20 | tracing::info!("Engines exist"); 21 | tracing::debug!("Engine temperature is 200 degrees"); 22 | tracing::trace!("Engine subsection is 300 degrees"); 23 | } 24 | -------------------------------------------------------------------------------- /release.toml: -------------------------------------------------------------------------------- 1 | owners = ["github:clap-rs:Admins", "github:rust-cli:Maintainers"] 2 | dependent-version = "fix" 3 | allow-branch = ["master"] 4 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Easily add `--verbose` and `--quiet` flags to CLIs using [Clap](http://crates.io/crates/clap). 2 | //! 3 | //! # Examples 4 | //! 5 | //! To get `--quiet` and `--verbose` flags through your entire program, just `flatten` 6 | //! [`Verbosity`]: 7 | //! 8 | //! ```rust,no_run 9 | //! use clap::Parser; 10 | //! use clap_verbosity_flag::Verbosity; 11 | //! 12 | //! #[derive(Debug, Parser)] 13 | //! struct Cli { 14 | //! #[command(flatten)] 15 | //! verbosity: Verbosity, 16 | //! 17 | //! // ... other options 18 | //! } 19 | //! ``` 20 | //! 21 | //! You can then use this to configure your logger: 22 | //! 23 | //! ```rust,no_run 24 | //! # use clap::Parser; 25 | //! # use clap_verbosity_flag::Verbosity; 26 | //! # 27 | //! # #[derive(Debug, Parser)] 28 | //! # struct Cli { 29 | //! # #[command(flatten)] 30 | //! # verbosity: Verbosity, 31 | //! # } 32 | //! let cli = Cli::parse(); 33 | //! # #[cfg(feature = "log")] 34 | //! env_logger::Builder::new() 35 | //! .filter_level(cli.verbosity.log_level_filter()) 36 | //! .init(); 37 | //! ``` 38 | //! 39 | //! ## Use with `tracing` 40 | //! 41 | //! To use with [`tracing`](https://crates.io/crates/tracing), disable the log feature flag and 42 | //! enable the `tracing` feature flag: 43 | //! 44 | //! ```shell 45 | //! cargo add clap_verbosity_flag --no-default features --features tracing 46 | //! ``` 47 | //! 48 | //! Then you can use it like this: 49 | //! 50 | //! ```rust,no_run 51 | //! # use clap::Parser; 52 | //! # use clap_verbosity_flag::Verbosity; 53 | //! # 54 | //! # #[derive(Debug, Parser)] 55 | //! # struct Cli { 56 | //! # #[command(flatten)] 57 | //! # verbosity: Verbosity, 58 | //! # } 59 | //! let cli = Cli::parse(); 60 | //! # #[cfg(feature = "tracing")] 61 | //! tracing_subscriber::fmt() 62 | //! .with_max_level(cli.verbosity) 63 | //! .init(); 64 | //! ``` 65 | //! 66 | //! # Using `--verbose` and `--quiet` flags 67 | //! 68 | //! The default verbosity level will cause `log` / `tracing` to only report errors. The flags can be 69 | //! specified multiple times to increase or decrease the verbosity level. 70 | //! 71 | //! - silence output: `-q` / `--quiet` 72 | //! - show warnings: `-v` / `--verbose` 73 | //! - show info: `-vv` / `--verbose --verbose` 74 | //! - show debug: `-vvv` / `--verbose --verbose --verbose` 75 | //! - show trace: `-vvvv` / `--verbose --verbose --verbose --verbose` 76 | //! 77 | //! # Customizing the default log level 78 | //! 79 | //! By default, the log level is set to Error. To customize this to a different level, pass a type 80 | //! implementing the [`LogLevel`] trait to [`Verbosity`]: 81 | //! 82 | //! ```rust,no_run 83 | //! # use clap::Parser; 84 | //! use clap_verbosity_flag::{Verbosity, InfoLevel}; 85 | //! 86 | //! #[derive(Debug, Parser)] 87 | //! struct Cli { 88 | //! #[command(flatten)] 89 | //! verbose: Verbosity, 90 | //! } 91 | //! ``` 92 | //! 93 | //! Or implement our [`LogLevel`] trait to customize the default log level and help output. 94 | 95 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 96 | #![warn(clippy::print_stderr)] 97 | #![warn(clippy::print_stdout)] 98 | 99 | #[doc = include_str!("../README.md")] 100 | #[cfg(all(doctest, feature = "log", feature = "tracing"))] 101 | pub struct ReadmeDoctests; 102 | 103 | use std::fmt; 104 | 105 | #[cfg(feature = "log")] 106 | pub mod log; 107 | #[cfg(feature = "tracing")] 108 | pub mod tracing; 109 | 110 | /// Logging flags to `#[command(flatten)]` into your CLI 111 | #[derive(clap::Args, Debug, Clone, Copy, Default)] 112 | #[command(about = None, long_about = None)] 113 | pub struct Verbosity { 114 | #[arg( 115 | long, 116 | short = 'v', 117 | action = clap::ArgAction::Count, 118 | global = true, 119 | help = L::verbose_help(), 120 | long_help = L::verbose_long_help(), 121 | )] 122 | verbose: u8, 123 | 124 | #[arg( 125 | long, 126 | short = 'q', 127 | action = clap::ArgAction::Count, 128 | global = true, 129 | help = L::quiet_help(), 130 | long_help = L::quiet_long_help(), 131 | conflicts_with = "verbose", 132 | )] 133 | quiet: u8, 134 | 135 | #[arg(skip)] 136 | phantom: std::marker::PhantomData, 137 | } 138 | 139 | impl Verbosity { 140 | /// Create a new verbosity instance by explicitly setting the values 141 | pub fn new(verbose: u8, quiet: u8) -> Self { 142 | Verbosity { 143 | verbose, 144 | quiet, 145 | phantom: std::marker::PhantomData, 146 | } 147 | } 148 | 149 | /// Whether any verbosity flags (either `--verbose` or `--quiet`) 150 | /// are present on the command line. 151 | pub fn is_present(&self) -> bool { 152 | self.verbose != 0 || self.quiet != 0 153 | } 154 | 155 | /// If the user requested complete silence (i.e. not just no-logging). 156 | pub fn is_silent(&self) -> bool { 157 | self.filter() == VerbosityFilter::Off 158 | } 159 | 160 | /// Gets the filter that should be applied to the logger. 161 | pub fn filter(&self) -> VerbosityFilter { 162 | let offset = self.verbose as i16 - self.quiet as i16; 163 | L::default_filter().with_offset(offset) 164 | } 165 | } 166 | 167 | #[cfg(feature = "log")] 168 | impl Verbosity { 169 | /// Get the log level. 170 | /// 171 | /// `None` means all output is disabled. 172 | pub fn log_level(&self) -> Option { 173 | self.filter().into() 174 | } 175 | 176 | /// Get the log level filter. 177 | pub fn log_level_filter(&self) -> log::LevelFilter { 178 | self.filter().into() 179 | } 180 | } 181 | 182 | #[cfg(feature = "tracing")] 183 | impl Verbosity { 184 | /// Get the tracing level. 185 | /// 186 | /// `None` means all output is disabled. 187 | pub fn tracing_level(&self) -> Option { 188 | self.filter().into() 189 | } 190 | 191 | /// Get the tracing level filter. 192 | pub fn tracing_level_filter(&self) -> tracing_core::LevelFilter { 193 | self.filter().into() 194 | } 195 | } 196 | 197 | impl fmt::Display for Verbosity { 198 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 199 | self.filter().fmt(f) 200 | } 201 | } 202 | 203 | /// Customize the default log-level and associated help 204 | pub trait LogLevel { 205 | /// Baseline level before applying `--verbose` and `--quiet` 206 | fn default_filter() -> VerbosityFilter; 207 | 208 | /// Short-help message for `--verbose` 209 | fn verbose_help() -> Option<&'static str> { 210 | Some("Increase logging verbosity") 211 | } 212 | 213 | /// Long-help message for `--verbose` 214 | fn verbose_long_help() -> Option<&'static str> { 215 | None 216 | } 217 | 218 | /// Short-help message for `--quiet` 219 | fn quiet_help() -> Option<&'static str> { 220 | Some("Decrease logging verbosity") 221 | } 222 | 223 | /// Long-help message for `--quiet` 224 | fn quiet_long_help() -> Option<&'static str> { 225 | None 226 | } 227 | } 228 | 229 | /// A representation of the log level filter. 230 | /// 231 | /// Used to calculate the log level and filter. 232 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 233 | pub enum VerbosityFilter { 234 | Off, 235 | Error, 236 | Warn, 237 | Info, 238 | Debug, 239 | Trace, 240 | } 241 | 242 | impl VerbosityFilter { 243 | /// Apply an offset to the filter level. 244 | /// 245 | /// Negative values will decrease the verbosity, while positive values will increase it. 246 | fn with_offset(&self, offset: i16) -> VerbosityFilter { 247 | let value = match self { 248 | Self::Off => 0_i16, 249 | Self::Error => 1, 250 | Self::Warn => 2, 251 | Self::Info => 3, 252 | Self::Debug => 4, 253 | Self::Trace => 5, 254 | }; 255 | match value.saturating_add(offset) { 256 | i16::MIN..=0 => Self::Off, 257 | 1 => Self::Error, 258 | 2 => Self::Warn, 259 | 3 => Self::Info, 260 | 4 => Self::Debug, 261 | 5..=i16::MAX => Self::Trace, 262 | } 263 | } 264 | } 265 | 266 | impl fmt::Display for VerbosityFilter { 267 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 268 | match self { 269 | Self::Off => write!(f, "off"), 270 | Self::Error => write!(f, "error"), 271 | Self::Warn => write!(f, "warn"), 272 | Self::Info => write!(f, "info"), 273 | Self::Debug => write!(f, "debug"), 274 | Self::Trace => write!(f, "trace"), 275 | } 276 | } 277 | } 278 | 279 | /// Default to [`VerbosityFilter::Error`] 280 | #[derive(Copy, Clone, Debug, Default)] 281 | pub struct ErrorLevel; 282 | 283 | impl LogLevel for ErrorLevel { 284 | fn default_filter() -> VerbosityFilter { 285 | VerbosityFilter::Error 286 | } 287 | } 288 | 289 | /// Default to [`VerbosityFilter::Warn`] 290 | #[derive(Copy, Clone, Debug, Default)] 291 | pub struct WarnLevel; 292 | 293 | impl LogLevel for WarnLevel { 294 | fn default_filter() -> VerbosityFilter { 295 | VerbosityFilter::Warn 296 | } 297 | } 298 | 299 | /// Default to [`VerbosityFilter::Info`] 300 | #[derive(Copy, Clone, Debug, Default)] 301 | pub struct InfoLevel; 302 | 303 | impl LogLevel for InfoLevel { 304 | fn default_filter() -> VerbosityFilter { 305 | VerbosityFilter::Info 306 | } 307 | } 308 | 309 | /// Default to [`VerbosityFilter::Debug`] 310 | #[derive(Copy, Clone, Debug, Default)] 311 | pub struct DebugLevel; 312 | 313 | impl LogLevel for DebugLevel { 314 | fn default_filter() -> VerbosityFilter { 315 | VerbosityFilter::Debug 316 | } 317 | } 318 | 319 | /// Default to [`VerbosityFilter::Trace`] 320 | #[derive(Copy, Clone, Debug, Default)] 321 | pub struct TraceLevel; 322 | 323 | impl LogLevel for TraceLevel { 324 | fn default_filter() -> VerbosityFilter { 325 | VerbosityFilter::Trace 326 | } 327 | } 328 | 329 | /// Default to [`VerbosityFilter::Off`] (no logging) 330 | #[derive(Copy, Clone, Debug, Default)] 331 | pub struct OffLevel; 332 | 333 | impl LogLevel for OffLevel { 334 | fn default_filter() -> VerbosityFilter { 335 | VerbosityFilter::Off 336 | } 337 | } 338 | 339 | #[cfg(test)] 340 | mod test { 341 | use super::*; 342 | 343 | #[test] 344 | fn verify_app() { 345 | #[derive(Debug, clap::Parser)] 346 | struct Cli { 347 | #[command(flatten)] 348 | verbose: Verbosity, 349 | } 350 | 351 | use clap::CommandFactory; 352 | Cli::command().debug_assert(); 353 | } 354 | 355 | /// Asserts that the filter is correct for the given verbosity and quiet values. 356 | #[track_caller] 357 | fn assert_filter(verbose: u8, quiet: u8, expected: VerbosityFilter) { 358 | assert_eq!( 359 | Verbosity::::new(verbose, quiet).filter(), 360 | expected, 361 | "verbose = {verbose}, quiet = {quiet}" 362 | ); 363 | } 364 | 365 | #[test] 366 | fn verbosity_off_level() { 367 | let tests = [ 368 | (0, 0, VerbosityFilter::Off), 369 | (1, 0, VerbosityFilter::Error), 370 | (2, 0, VerbosityFilter::Warn), 371 | (3, 0, VerbosityFilter::Info), 372 | (4, 0, VerbosityFilter::Debug), 373 | (5, 0, VerbosityFilter::Trace), 374 | (6, 0, VerbosityFilter::Trace), 375 | (255, 0, VerbosityFilter::Trace), 376 | (0, 1, VerbosityFilter::Off), 377 | (0, 255, VerbosityFilter::Off), 378 | (255, 255, VerbosityFilter::Off), 379 | ]; 380 | 381 | for (verbose, quiet, expected_filter) in tests { 382 | assert_filter::(verbose, quiet, expected_filter); 383 | } 384 | } 385 | 386 | #[test] 387 | fn verbosity_error_level() { 388 | let tests = [ 389 | (0, 0, VerbosityFilter::Error), 390 | (1, 0, VerbosityFilter::Warn), 391 | (2, 0, VerbosityFilter::Info), 392 | (3, 0, VerbosityFilter::Debug), 393 | (4, 0, VerbosityFilter::Trace), 394 | (5, 0, VerbosityFilter::Trace), 395 | (255, 0, VerbosityFilter::Trace), 396 | (0, 1, VerbosityFilter::Off), 397 | (0, 2, VerbosityFilter::Off), 398 | (0, 255, VerbosityFilter::Off), 399 | (255, 255, VerbosityFilter::Error), 400 | ]; 401 | 402 | for (verbose, quiet, expected_filter) in tests { 403 | assert_filter::(verbose, quiet, expected_filter); 404 | } 405 | } 406 | 407 | #[test] 408 | fn verbosity_warn_level() { 409 | let tests = [ 410 | // verbose, quiet, expected_level, expected_filter 411 | (0, 0, VerbosityFilter::Warn), 412 | (1, 0, VerbosityFilter::Info), 413 | (2, 0, VerbosityFilter::Debug), 414 | (3, 0, VerbosityFilter::Trace), 415 | (4, 0, VerbosityFilter::Trace), 416 | (255, 0, VerbosityFilter::Trace), 417 | (0, 1, VerbosityFilter::Error), 418 | (0, 2, VerbosityFilter::Off), 419 | (0, 3, VerbosityFilter::Off), 420 | (0, 255, VerbosityFilter::Off), 421 | (255, 255, VerbosityFilter::Warn), 422 | ]; 423 | 424 | for (verbose, quiet, expected_filter) in tests { 425 | assert_filter::(verbose, quiet, expected_filter); 426 | } 427 | } 428 | 429 | #[test] 430 | fn verbosity_info_level() { 431 | let tests = [ 432 | // verbose, quiet, expected_level, expected_filter 433 | (0, 0, VerbosityFilter::Info), 434 | (1, 0, VerbosityFilter::Debug), 435 | (2, 0, VerbosityFilter::Trace), 436 | (3, 0, VerbosityFilter::Trace), 437 | (255, 0, VerbosityFilter::Trace), 438 | (0, 1, VerbosityFilter::Warn), 439 | (0, 2, VerbosityFilter::Error), 440 | (0, 3, VerbosityFilter::Off), 441 | (0, 4, VerbosityFilter::Off), 442 | (0, 255, VerbosityFilter::Off), 443 | (255, 255, VerbosityFilter::Info), 444 | ]; 445 | 446 | for (verbose, quiet, expected_filter) in tests { 447 | assert_filter::(verbose, quiet, expected_filter); 448 | } 449 | } 450 | 451 | #[test] 452 | fn verbosity_debug_level() { 453 | let tests = [ 454 | // verbose, quiet, expected_level, expected_filter 455 | (0, 0, VerbosityFilter::Debug), 456 | (1, 0, VerbosityFilter::Trace), 457 | (2, 0, VerbosityFilter::Trace), 458 | (255, 0, VerbosityFilter::Trace), 459 | (0, 1, VerbosityFilter::Info), 460 | (0, 2, VerbosityFilter::Warn), 461 | (0, 3, VerbosityFilter::Error), 462 | (0, 4, VerbosityFilter::Off), 463 | (0, 5, VerbosityFilter::Off), 464 | (0, 255, VerbosityFilter::Off), 465 | (255, 255, VerbosityFilter::Debug), 466 | ]; 467 | 468 | for (verbose, quiet, expected_filter) in tests { 469 | assert_filter::(verbose, quiet, expected_filter); 470 | } 471 | } 472 | 473 | #[test] 474 | fn verbosity_trace_level() { 475 | let tests = [ 476 | // verbose, quiet, expected_level, expected_filter 477 | (0, 0, VerbosityFilter::Trace), 478 | (1, 0, VerbosityFilter::Trace), 479 | (255, 0, VerbosityFilter::Trace), 480 | (0, 1, VerbosityFilter::Debug), 481 | (0, 2, VerbosityFilter::Info), 482 | (0, 3, VerbosityFilter::Warn), 483 | (0, 4, VerbosityFilter::Error), 484 | (0, 5, VerbosityFilter::Off), 485 | (0, 6, VerbosityFilter::Off), 486 | (0, 255, VerbosityFilter::Off), 487 | (255, 255, VerbosityFilter::Trace), 488 | ]; 489 | 490 | for (verbose, quiet, expected_filter) in tests { 491 | assert_filter::(verbose, quiet, expected_filter); 492 | } 493 | } 494 | } 495 | -------------------------------------------------------------------------------- /src/log.rs: -------------------------------------------------------------------------------- 1 | // These re-exports of the log crate make it easy to use this crate without having to depend on the 2 | // log crate directly. See for more 3 | // information. 4 | pub use log::{Level, LevelFilter}; 5 | 6 | use crate::{LogLevel, Verbosity, VerbosityFilter}; 7 | 8 | impl From for LevelFilter { 9 | fn from(filter: VerbosityFilter) -> Self { 10 | match filter { 11 | VerbosityFilter::Off => LevelFilter::Off, 12 | VerbosityFilter::Error => LevelFilter::Error, 13 | VerbosityFilter::Warn => LevelFilter::Warn, 14 | VerbosityFilter::Info => LevelFilter::Info, 15 | VerbosityFilter::Debug => LevelFilter::Debug, 16 | VerbosityFilter::Trace => LevelFilter::Trace, 17 | } 18 | } 19 | } 20 | 21 | impl From for VerbosityFilter { 22 | fn from(level: LevelFilter) -> Self { 23 | match level { 24 | LevelFilter::Off => Self::Off, 25 | LevelFilter::Error => Self::Error, 26 | LevelFilter::Warn => Self::Warn, 27 | LevelFilter::Info => Self::Info, 28 | LevelFilter::Debug => Self::Debug, 29 | LevelFilter::Trace => Self::Trace, 30 | } 31 | } 32 | } 33 | 34 | impl From for Option { 35 | fn from(filter: VerbosityFilter) -> Self { 36 | match filter { 37 | VerbosityFilter::Off => None, 38 | VerbosityFilter::Error => Some(Level::Error), 39 | VerbosityFilter::Warn => Some(Level::Warn), 40 | VerbosityFilter::Info => Some(Level::Info), 41 | VerbosityFilter::Debug => Some(Level::Debug), 42 | VerbosityFilter::Trace => Some(Level::Trace), 43 | } 44 | } 45 | } 46 | 47 | impl From> for VerbosityFilter { 48 | fn from(level: Option) -> Self { 49 | match level { 50 | None => Self::Off, 51 | Some(Level::Error) => Self::Error, 52 | Some(Level::Warn) => Self::Warn, 53 | Some(Level::Info) => Self::Info, 54 | Some(Level::Debug) => Self::Debug, 55 | Some(Level::Trace) => Self::Trace, 56 | } 57 | } 58 | } 59 | 60 | impl From> for LevelFilter { 61 | fn from(v: Verbosity) -> Self { 62 | v.log_level_filter() 63 | } 64 | } 65 | 66 | impl From> for Option { 67 | fn from(v: Verbosity) -> Self { 68 | v.log_level() 69 | } 70 | } 71 | 72 | #[cfg(test)] 73 | mod tests { 74 | use super::*; 75 | use crate::{DebugLevel, ErrorLevel, InfoLevel, OffLevel, TraceLevel, Verbosity, WarnLevel}; 76 | 77 | #[test] 78 | fn log_level() { 79 | let v = Verbosity::::default(); 80 | assert_eq!(v.log_level(), None); 81 | assert_eq!(v.log_level_filter(), LevelFilter::Off); 82 | 83 | let v = Verbosity::::default(); 84 | assert_eq!(v.log_level(), Some(Level::Error)); 85 | assert_eq!(v.log_level_filter(), LevelFilter::Error); 86 | 87 | let v = Verbosity::::default(); 88 | assert_eq!(v.log_level(), Some(Level::Warn)); 89 | assert_eq!(v.log_level_filter(), LevelFilter::Warn); 90 | 91 | let v = Verbosity::::default(); 92 | assert_eq!(v.log_level(), Some(Level::Info)); 93 | assert_eq!(v.log_level_filter(), LevelFilter::Info); 94 | 95 | let v = Verbosity::::default(); 96 | assert_eq!(v.log_level(), Some(Level::Debug)); 97 | assert_eq!(v.log_level_filter(), LevelFilter::Debug); 98 | 99 | let v = Verbosity::::default(); 100 | assert_eq!(v.log_level(), Some(Level::Trace)); 101 | assert_eq!(v.log_level_filter(), LevelFilter::Trace); 102 | } 103 | 104 | #[test] 105 | fn into_opt_level() { 106 | let v = Verbosity::::default(); 107 | assert_eq!(Option::::from(v), None); 108 | 109 | let v = Verbosity::::default(); 110 | assert_eq!(Option::::from(v), Some(Level::Error)); 111 | 112 | let v = Verbosity::::default(); 113 | assert_eq!(Option::::from(v), Some(Level::Warn)); 114 | 115 | let v = Verbosity::::default(); 116 | assert_eq!(Option::::from(v), Some(Level::Info)); 117 | 118 | let v = Verbosity::::default(); 119 | assert_eq!(Option::::from(v), Some(Level::Debug)); 120 | 121 | let v = Verbosity::::default(); 122 | assert_eq!(Option::::from(v), Some(Level::Trace)); 123 | } 124 | 125 | #[test] 126 | fn into_level_filter() { 127 | let v = Verbosity::::default(); 128 | assert_eq!(LevelFilter::from(v), LevelFilter::Off); 129 | 130 | let v = Verbosity::::default(); 131 | assert_eq!(LevelFilter::from(v), LevelFilter::Error); 132 | 133 | let v = Verbosity::::default(); 134 | assert_eq!(LevelFilter::from(v), LevelFilter::Warn); 135 | 136 | let v = Verbosity::::default(); 137 | assert_eq!(LevelFilter::from(v), LevelFilter::Info); 138 | 139 | let v = Verbosity::::default(); 140 | assert_eq!(LevelFilter::from(v), LevelFilter::Debug); 141 | 142 | let v = Verbosity::::default(); 143 | assert_eq!(LevelFilter::from(v), LevelFilter::Trace); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/tracing.rs: -------------------------------------------------------------------------------- 1 | // These re-exports of the tracing crate types it easy to use this crate without having to depend on 2 | // the tracing crate directly. See for 3 | // more information. 4 | pub use tracing_core::{Level, LevelFilter}; 5 | 6 | use crate::{LogLevel, Verbosity, VerbosityFilter}; 7 | 8 | impl From for LevelFilter { 9 | fn from(filter: VerbosityFilter) -> Self { 10 | match filter { 11 | VerbosityFilter::Off => LevelFilter::OFF, 12 | VerbosityFilter::Error => LevelFilter::ERROR, 13 | VerbosityFilter::Warn => LevelFilter::WARN, 14 | VerbosityFilter::Info => LevelFilter::INFO, 15 | VerbosityFilter::Debug => LevelFilter::DEBUG, 16 | VerbosityFilter::Trace => LevelFilter::TRACE, 17 | } 18 | } 19 | } 20 | 21 | impl From for VerbosityFilter { 22 | fn from(level: LevelFilter) -> Self { 23 | match level { 24 | LevelFilter::OFF => Self::Off, 25 | LevelFilter::ERROR => Self::Error, 26 | LevelFilter::WARN => Self::Warn, 27 | LevelFilter::INFO => Self::Info, 28 | LevelFilter::DEBUG => Self::Debug, 29 | LevelFilter::TRACE => Self::Trace, 30 | } 31 | } 32 | } 33 | 34 | impl From for Option { 35 | fn from(filter: VerbosityFilter) -> Self { 36 | match filter { 37 | VerbosityFilter::Off => None, 38 | VerbosityFilter::Error => Some(Level::ERROR), 39 | VerbosityFilter::Warn => Some(Level::WARN), 40 | VerbosityFilter::Info => Some(Level::INFO), 41 | VerbosityFilter::Debug => Some(Level::DEBUG), 42 | VerbosityFilter::Trace => Some(Level::TRACE), 43 | } 44 | } 45 | } 46 | 47 | impl From> for VerbosityFilter { 48 | fn from(level: Option) -> Self { 49 | match level { 50 | None => Self::Off, 51 | Some(Level::ERROR) => Self::Error, 52 | Some(Level::WARN) => Self::Warn, 53 | Some(Level::INFO) => Self::Info, 54 | Some(Level::DEBUG) => Self::Debug, 55 | Some(Level::TRACE) => Self::Trace, 56 | } 57 | } 58 | } 59 | 60 | impl From> for LevelFilter { 61 | fn from(v: Verbosity) -> Self { 62 | v.tracing_level_filter() 63 | } 64 | } 65 | 66 | impl From> for Option { 67 | fn from(v: Verbosity) -> Self { 68 | v.tracing_level() 69 | } 70 | } 71 | 72 | #[cfg(test)] 73 | mod tests { 74 | use super::*; 75 | use crate::{DebugLevel, ErrorLevel, InfoLevel, OffLevel, TraceLevel, Verbosity, WarnLevel}; 76 | 77 | #[test] 78 | fn tracing_level() { 79 | let v = Verbosity::::default(); 80 | assert_eq!(v.tracing_level(), None); 81 | assert_eq!(v.tracing_level_filter(), LevelFilter::OFF); 82 | 83 | let v = Verbosity::::default(); 84 | assert_eq!(v.tracing_level(), Some(Level::ERROR)); 85 | assert_eq!(v.tracing_level_filter(), LevelFilter::ERROR); 86 | 87 | let v = Verbosity::::default(); 88 | assert_eq!(v.tracing_level(), Some(Level::WARN)); 89 | assert_eq!(v.tracing_level_filter(), LevelFilter::WARN); 90 | 91 | let v = Verbosity::::default(); 92 | assert_eq!(v.tracing_level(), Some(Level::INFO)); 93 | assert_eq!(v.tracing_level_filter(), LevelFilter::INFO); 94 | 95 | let v = Verbosity::::default(); 96 | assert_eq!(v.tracing_level(), Some(Level::DEBUG)); 97 | assert_eq!(v.tracing_level_filter(), LevelFilter::DEBUG); 98 | 99 | let v = Verbosity::::default(); 100 | assert_eq!(v.tracing_level(), Some(Level::TRACE)); 101 | assert_eq!(v.tracing_level_filter(), LevelFilter::TRACE); 102 | } 103 | 104 | #[test] 105 | fn into_opt_level() { 106 | let v = Verbosity::::default(); 107 | assert_eq!(Option::::from(v), None); 108 | 109 | let v = Verbosity::::default(); 110 | assert_eq!(Option::::from(v), Some(Level::ERROR)); 111 | 112 | let v = Verbosity::::default(); 113 | assert_eq!(Option::::from(v), Some(Level::WARN)); 114 | 115 | let v = Verbosity::::default(); 116 | assert_eq!(Option::::from(v), Some(Level::INFO)); 117 | 118 | let v = Verbosity::::default(); 119 | assert_eq!(Option::::from(v), Some(Level::DEBUG)); 120 | 121 | let v = Verbosity::::default(); 122 | assert_eq!(Option::::from(v), Some(Level::TRACE)); 123 | } 124 | 125 | #[test] 126 | fn into_level_filter() { 127 | let v = Verbosity::::default(); 128 | assert_eq!(LevelFilter::from(v), LevelFilter::OFF); 129 | 130 | let v = Verbosity::::default(); 131 | assert_eq!(LevelFilter::from(v), LevelFilter::ERROR); 132 | 133 | let v = Verbosity::::default(); 134 | assert_eq!(LevelFilter::from(v), LevelFilter::WARN); 135 | 136 | let v = Verbosity::::default(); 137 | assert_eq!(LevelFilter::from(v), LevelFilter::INFO); 138 | 139 | let v = Verbosity::::default(); 140 | assert_eq!(LevelFilter::from(v), LevelFilter::DEBUG); 141 | 142 | let v = Verbosity::::default(); 143 | assert_eq!(LevelFilter::from(v), LevelFilter::TRACE); 144 | } 145 | } 146 | --------------------------------------------------------------------------------