mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
contrib: Add tool to list outdated deps in a table.
This commit is contained in:
165
contrib/cargo-outdated
Executable file
165
contrib/cargo-outdated
Executable file
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env python3.9
|
||||
import json
|
||||
import pickle
|
||||
import subprocess
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from os import getenv
|
||||
from os.path import exists, join
|
||||
from subprocess import PIPE
|
||||
|
||||
import semver
|
||||
import toml
|
||||
from colorama import Fore, Style
|
||||
from prettytable import PrettyTable
|
||||
|
||||
# Path to git repository holding crates.io index
|
||||
CRATESIO_REPO = "https://github.com/rust-lang/crates.io-index"
|
||||
CRATESIO_INDEX = join(getenv("HOME"), ".cache", "crates.io-index")
|
||||
|
||||
# Path to pickle cache for storing paths to dependency metadata
|
||||
PICKLE_CACHE = join(getenv("HOME"), ".cache", "cargo-outdated.pickle")
|
||||
|
||||
# Set of packages that are ignored by this tool
|
||||
IGNORES = {"drk-sdk", "darkfi"}
|
||||
|
||||
# Cached paths for metadata to not have to search through the crates index
|
||||
METADATA_PATHS = {}
|
||||
|
||||
if exists(PICKLE_CACHE):
|
||||
with open(PICKLE_CACHE, "rb") as f:
|
||||
json_data = pickle.load(f)
|
||||
METADATA_PATHS = json.loads(json_data)
|
||||
|
||||
|
||||
def parse_toml(file):
|
||||
with open(file) as f:
|
||||
content = f.read()
|
||||
|
||||
p = toml.loads(content)
|
||||
deps = p.get("dependencies")
|
||||
devdeps = p.get("dev-dependencies")
|
||||
|
||||
if deps and devdeps:
|
||||
dependencies = deps | devdeps
|
||||
elif deps:
|
||||
dependencies = deps
|
||||
elif devdeps:
|
||||
dependencies = devdeps
|
||||
else:
|
||||
dependencies = None
|
||||
|
||||
return (p["package"]["name"], dependencies)
|
||||
|
||||
|
||||
def get_metadata_path(name):
|
||||
find_output = subprocess.run(
|
||||
["find", CRATESIO_INDEX, "-type", "f", "-name", name], stdout=PIPE)
|
||||
|
||||
metadata_path = find_output.stdout.decode().strip()
|
||||
|
||||
if metadata_path == '':
|
||||
return None
|
||||
|
||||
# Place the path into cache
|
||||
METADATA_PATHS[name] = metadata_path
|
||||
return metadata_path
|
||||
|
||||
|
||||
def check_dep(name, data):
|
||||
if name in IGNORES:
|
||||
return None
|
||||
|
||||
metadata_path = METADATA_PATHS.get(name)
|
||||
|
||||
if not metadata_path:
|
||||
metadata_path = get_metadata_path(name)
|
||||
if not metadata_path:
|
||||
print(f"No crate found for {Fore.YELLOW}{name}{Style.RESET_ALL}")
|
||||
return None
|
||||
|
||||
# Read the metadata. It's split as JSON objects, each in its own line.
|
||||
with open(metadata_path, encoding="utf-8") as f:
|
||||
lines = f.readlines()
|
||||
lines = [i.strip() for i in lines]
|
||||
|
||||
# Latest one is at the end
|
||||
metadata = json.loads(lines[-1])
|
||||
|
||||
# Get the version from the local data
|
||||
if isinstance(data, str):
|
||||
# This is just the semver
|
||||
local_version = data
|
||||
elif isinstance(data, dict):
|
||||
local_version = data.get("version")
|
||||
if not local_version:
|
||||
# Not a versioned dependency (can be path/git/...)
|
||||
return None
|
||||
else:
|
||||
raise ValueError(f"Invalid dependency: {name}")
|
||||
|
||||
if semver.compare(local_version, metadata["vers"], loose=True) < 0:
|
||||
return (local_version, metadata["vers"])
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
parser = ArgumentParser(
|
||||
description="Prettyprint outdated dependencies in a cargo project")
|
||||
|
||||
parser.add_argument("-i",
|
||||
"--ignore",
|
||||
type=str,
|
||||
help="Comma-separated list of deps to ignore")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.ignore:
|
||||
for i in args.ignore.split(","):
|
||||
IGNORES.add(i)
|
||||
|
||||
if not exists(CRATESIO_INDEX):
|
||||
print("Cloning crates.io index...")
|
||||
subprocess.run(["git", "clone", CRATESIO_REPO, CRATESIO_INDEX],
|
||||
capture_output=False)
|
||||
|
||||
print("Updating crates.io index...")
|
||||
subprocess.run(["git", "-C", CRATESIO_INDEX, "fetch", "-a"],
|
||||
capture_output=False)
|
||||
|
||||
subprocess.run(
|
||||
["git", "-C", CRATESIO_INDEX, "reset", "--hard", "origin/master"],
|
||||
capture_output=False)
|
||||
|
||||
find_output = subprocess.run(
|
||||
["find", ".", "-type", "f", "-name", "Cargo.toml"], stdout=PIPE)
|
||||
files = [i.strip() for i in find_output.stdout.decode().split("\n")][:-1]
|
||||
|
||||
x = PrettyTable()
|
||||
x.field_names = ["package", "crate", "current", "latest", "path"]
|
||||
|
||||
for file in files:
|
||||
package, deps = parse_toml(file)
|
||||
parse_toml(file)
|
||||
print(f"Checking deps for {Fore.GREEN}{package}{Style.RESET_ALL}")
|
||||
for dep in deps:
|
||||
ret = check_dep(dep, deps[dep])
|
||||
if ret:
|
||||
x.add_row([
|
||||
package,
|
||||
dep,
|
||||
f"{Fore.YELLOW}{ret[0]}{Style.RESET_ALL}",
|
||||
f"{Fore.GREEN}{ret[1]}{Style.RESET_ALL}",
|
||||
file,
|
||||
])
|
||||
|
||||
print(x)
|
||||
|
||||
# Write the pickle
|
||||
with open(PICKLE_CACHE, "wb") as pfile:
|
||||
pickle.dump(json.dumps(METADATA_PATHS).encode(), pfile)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user