Skip to content

Instantly share code, notes, and snippets.

@ExpHP
Created April 3, 2019 17:06
Show Gist options
  • Select an option

  • Save ExpHP/4bc95908166fddb624d87fa30c2f78ef to your computer and use it in GitHub Desktop.

Select an option

Save ExpHP/4bc95908166fddb624d87fa30c2f78ef to your computer and use it in GitHub Desktop.
cargo-unused
#!/usr/bin/env python3
import pytoml as toml
import argparse
import subprocess
import sys
def main():
p = argparse.ArgumentParser('cargo-unused')
# TODO: Should have an --all flag that detects unused deps on all crates in a workspace
p.add_argument('--manifest-path', default='Cargo.toml', help='Path to Cargo.toml')
# TODO: it would be better to search just the rs files that belong to the crate.
# Not sure how to properly do this though; Cargo.toml can tell us the crate root,
# but only rustc knows how to find the other modules from that.
# TODO: Maybe support a glob option with globstars?
p.add_argument('--search-path', default='src', help='source directory')
# FIXME: how are you supposed to properly handle the fact that the first arg of a cargo
# subcommand is the subcommand name itself?
argv = sys.argv
if argv[0] == 'unused':
del argv[0]
args = p.parse_args(argv)
with open(args.manifest_path) as f:
cargo_toml = toml.load(f)
# TODO: build-dependencies, which should only search rs files that belong to the build script
found_unused = False
for deps_key in ('dependencies', 'dev-dependencies'):
for dep_package in cargo_toml[deps_key]:
# TODO: support renamed dependencies
dep_crate = dep_package.replace('-', '_')
result = check_rg_match(
pattern=rf'\b{dep_crate}\b',
search_paths=[args.search_path],
)
if not result:
print(f'Unused package: {dep_package}')
found_unused = True
sys.exit(int(found_unused))
def check_rg_installed():
try: subprocess.check_output(['rg', '--version'])
except FileNotFoundError: die('Please install ripgrep: cargo install rg')
except subprocess.CalledProcessError: die('Error calling rg --version')
def check_rg_match(pattern, search_paths):
try: subprocess.check_output(['rg', '--', pattern] + search_paths)
except subprocess.CalledProcessError: return False
return True
def die(*args):
print(*args, file=sys.stderr)
sys.exit(1)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment