github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/bin/make_manual.py (about) 1 #!/usr/bin/env python3 2 """ 3 Make single page versions of the documentation for release and 4 conversion into man pages etc. 5 """ 6 7 import os 8 import re 9 from datetime import datetime 10 11 docpath = "docs/content" 12 outfile = "MANUAL.md" 13 14 # Order to add docs segments to make outfile 15 docs = [ 16 "_index.md", 17 "install.md", 18 "docs.md", 19 "remote_setup.md", 20 "filtering.md", 21 "gui.md", 22 "rc.md", 23 "overview.md", 24 "flags.md", 25 26 # Keep these alphabetical by full name 27 "fichier.md", 28 "alias.md", 29 "amazonclouddrive.md", 30 "s3.md", 31 "b2.md", 32 "box.md", 33 "cache.md", 34 "chunker.md", 35 "sharefile.md", 36 "crypt.md", 37 "dropbox.md", 38 "ftp.md", 39 "googlecloudstorage.md", 40 "drive.md", 41 "googlephotos.md", 42 "http.md", 43 "hubic.md", 44 "jottacloud.md", 45 "koofr.md", 46 "mailru.md", 47 "mega.md", 48 "memory.md", 49 "azureblob.md", 50 "onedrive.md", 51 "opendrive.md", 52 "qingstor.md", 53 "swift.md", 54 "pcloud.md", 55 "premiumizeme.md", 56 "putio.md", 57 "seafile.md", 58 "sftp.md", 59 "sugarsync.md", 60 "tardigrade.md", 61 "union.md", 62 "webdav.md", 63 "yandex.md", 64 65 "local.md", 66 "changelog.md", 67 "bugs.md", 68 "faq.md", 69 "licence.md", 70 "authors.md", 71 "contact.md", 72 ] 73 74 # Order to put the commands in - any not on here will be in sorted order 75 commands_order = [ 76 "rclone_config.md", 77 "rclone_copy.md", 78 "rclone_sync.md", 79 "rclone_move.md", 80 "rclone_delete.md", 81 "rclone_purge.md", 82 "rclone_mkdir.md", 83 "rclone_rmdir.md", 84 "rclone_check.md", 85 "rclone_ls.md", 86 "rclone_lsd.md", 87 "rclone_lsl.md", 88 "rclone_md5sum.md", 89 "rclone_sha1sum.md", 90 "rclone_size.md", 91 "rclone_version.md", 92 "rclone_cleanup.md", 93 "rclone_dedupe.md", 94 ] 95 96 # Docs which aren't made into outfile 97 ignore_docs = [ 98 "downloads.md", 99 "privacy.md", 100 "donate.md", 101 ] 102 103 def read_doc(doc): 104 """Read file as a string""" 105 path = os.path.join(docpath, doc) 106 with open(path) as fd: 107 contents = fd.read() 108 parts = contents.split("---\n", 2) 109 if len(parts) != 3: 110 raise ValueError("Couldn't find --- markers: found %d parts" % len(parts)) 111 contents = parts[2].strip()+"\n\n" 112 # Remove icons 113 contents = re.sub(r'<i class="fa.*?</i>\s*', "", contents) 114 # Interpret img shortcodes 115 # {{< img ... >}} 116 contents = re.sub(r'\{\{<\s*img\s+(.*?)>\}\}', r"<img \1>", contents) 117 # Make any img tags absolute 118 contents = re.sub(r'(<img.*?src=")/', r"\1https://rclone.org/", contents) 119 # Make [...](/links/) absolute 120 contents = re.sub(r'\]\((\/.*?\/(#.*)?)\)', r"](https://rclone.org\1)", contents) 121 # Add additional links on the front page 122 contents = re.sub(r'\{\{< rem MAINPAGELINK >\}\}', "- [Donate.](https://rclone.org/donate/)", contents) 123 # Interpret provider shortcode 124 # {{< provider name="Amazon S3" home="https://aws.amazon.com/s3/" config="/s3/" >}} 125 contents = re.sub(r'\{\{<\s*provider.*?name="(.*?)".*?>\}\}', r"- \1", contents) 126 # Remove remaining shortcodes 127 contents = re.sub(r'\{\{<.*?>\}\}', r"", contents) 128 contents = re.sub(r'\{\{%.*?%\}\}', r"", contents) 129 return contents 130 131 def check_docs(docpath): 132 """Check all the docs are in docpath""" 133 files = set(f for f in os.listdir(docpath) if f.endswith(".md")) 134 files -= set(ignore_docs) 135 docs_set = set(docs) 136 if files == docs_set: 137 return 138 print("Files on disk but not in docs variable: %s" % ", ".join(files - docs_set)) 139 print("Files in docs variable but not on disk: %s" % ", ".join(docs_set - files)) 140 raise ValueError("Missing files") 141 142 def read_command(command): 143 doc = read_doc("commands/"+command) 144 doc = re.sub(r"### Options inherited from parent commands.*$", "", doc, 0, re.S) 145 doc = doc.strip()+"\n" 146 return doc 147 148 def read_commands(docpath): 149 """Reads the commands an makes them into a single page""" 150 files = set(f for f in os.listdir(docpath + "/commands") if f.endswith(".md")) 151 docs = [] 152 for command in commands_order: 153 docs.append(read_command(command)) 154 files.remove(command) 155 for command in sorted(files): 156 if command != "rclone.md": 157 docs.append(read_command(command)) 158 return "\n".join(docs) 159 160 def main(): 161 check_docs(docpath) 162 command_docs = read_commands(docpath).replace("\\", "\\\\") # escape \ so we can use command_docs in re.sub 163 with open(outfile, "w") as out: 164 out.write("""\ 165 %% rclone(1) User Manual 166 %% Nick Craig-Wood 167 %% %s 168 169 """ % datetime.now().strftime("%b %d, %Y")) 170 for doc in docs: 171 contents = read_doc(doc) 172 # Substitute the commands into doc.md 173 if doc == "docs.md": 174 contents = re.sub(r"The main rclone commands.*?for the full list.", command_docs, contents, 0, re.S) 175 out.write(contents) 176 print("Written '%s'" % outfile) 177 178 if __name__ == "__main__": 179 main()