├── .gitignore ├── README.md └── gen_docsets.py /.gitignore: -------------------------------------------------------------------------------- 1 | docsets/ 2 | crates/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Generating Dash docsets for third party rust crates 2 | 3 | This repo contains a simple script for quickly generating Dash compatible docsets for third-party Rust crates. 4 | 5 | ## Requirements 6 | 7 | - python3 8 | - the requests library: `pip3 install requests` 9 | - [dashing](https://github.com/technosophos/dashing): `brew install dashing` 10 | - [rsdocs-dashing](https://github.com/hobofan/rsdocs-dashing): `cargo install rsdocs-dashing` 11 | 12 | ## Usage 13 | 14 | `./gen_docsets.py serde crossbeam rand log regex` 15 | 16 | This will clone the repos for these crates (assuming the name passed is used on [crates.io](https://crates.io), 17 | generate the docsets, and copy them into the `docsets` subdir. These `.docset` files can be added to Dash in 18 | dash's preferences. 19 | -------------------------------------------------------------------------------- /gen_docsets.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import requests 5 | import os 6 | import sys 7 | import subprocess 8 | import shutil 9 | 10 | SOURCE_SUBDIR = "crates" 11 | DOCSET_SUBDIR = "docsets" 12 | CRATES_API = "https://crates.io/api/v1/crates/" 13 | 14 | def gen_docset(crate_name): 15 | """generates or updates the docset for this crate.""" 16 | 17 | repo = get_repo_url(crate_name) 18 | if repo is None: 19 | raise Exception("no repo returned for {}".format(crate_name)) 20 | print("generating docs for {} from {}".format(crate_name, repo)) 21 | local_path = repo.split('/')[-1] 22 | if not os.path.exists(local_path): 23 | clone_repo(repo) 24 | return update_docs(local_path, crate_name) 25 | 26 | 27 | def get_repo_url(crate_name): 28 | """gets the url for the repository associated with `crate_name` on crates.io""" 29 | 30 | crates_path = "https://crates.io/api/v1/crates/" + crate_name 31 | headers = {'user-agent': '@cmyr\'s dash docset generation, colin@cmyr.net'} 32 | resp = requests.get(crates_path, headers=headers) 33 | if resp.status_code != 200: 34 | raise Exception("crates.io returned %d for %s" % (resp.status_code, crate_name)) 35 | json = resp.json() 36 | return json["crate"]["repository"] 37 | 38 | 39 | def clone_repo(repo_path): 40 | subprocess.check_call("git clone {}".format(repo_path), shell=True) 41 | print("cloned {}".format(repo_path)) 42 | 43 | 44 | def update_docs(crate_dir, crate_name): 45 | os.chdir(crate_dir) 46 | try: 47 | subprocess.check_call("git diff-index --quiet HEAD --", shell=True) 48 | except subprocess.CalledProcessError: 49 | raise Exception("crate {} has dirty working directory, will not update".format(crate_dir)) 50 | 51 | subprocess.check_call("git fetch && git checkout origin/master", stdout=sys.stdout, shell=True) 52 | print("updated {} to origin/master".format(crate_name)) 53 | 54 | subprocess.check_call("cargo doc", shell=True, stdout=sys.stdout) 55 | 56 | if os.path.exists("docset"): 57 | shutil.rmtree("docset") 58 | 59 | subprocess.check_call("rsdocs-dashing target/doc/{} docset".format(crate_name), stdout=sys.stdout, shell=True) 60 | subprocess.check_call("dashing build --config docset/dashing.json --source docset/build".format(crate_name), stdout=sys.stdout, shell=True) 61 | docset_path = os.path.join(os.getcwd(), "{}.docset".format(crate_name)) 62 | return docset_path 63 | 64 | def main(): 65 | parser = argparse.ArgumentParser(description='create or update a dash docset') 66 | parser.add_argument( 67 | 'crate_names', 68 | type=str, 69 | nargs='+', 70 | help='a list of crate names to generate or update docs for') 71 | 72 | args = parser.parse_args() 73 | base_dir = os.getcwd() 74 | out_dir = os.path.join(base_dir, DOCSET_SUBDIR) 75 | source_dir = os.path.join(base_dir, SOURCE_SUBDIR) 76 | 77 | if not os.path.exists(out_dir): 78 | os.makedirs(out_dir) 79 | if not os.path.exists(source_dir): 80 | os.makedirs(source_dir) 81 | 82 | results = [] 83 | for crate in args.crate_names: 84 | os.chdir(source_dir) 85 | print("generating docs for", crate) 86 | try: 87 | docset_path = gen_docset(crate) 88 | dest_path = os.path.join(out_dir, os.path.split(docset_path)[-1]) 89 | assert dest_path.endswith(".docset") 90 | if os.path.exists(dest_path): 91 | shutil.rmtree(dest_path) 92 | shutil.move(docset_path, dest_path) 93 | results.append((True, crate, dest_path)) 94 | except Exception as e: 95 | results.append((False, crate, e)) 96 | 97 | for result in results: 98 | if result[0]: 99 | print("updated {}: {}".format(result[1], result[2])) 100 | else: 101 | print('error with crate "{}": "{}"'.format(result[1], result[2])) 102 | 103 | 104 | if __name__ == '__main__': 105 | main() 106 | --------------------------------------------------------------------------------