From 8629f81364db3319babbcdfce886306711215079 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Mon, 4 Mar 2024 19:44:16 -0800 Subject: [PATCH 01/46] Add client and python_backend docs to Toc. --- docs/contents.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/docs/contents.md b/docs/contents.md index ca952fed2c..becb5085fd 100644 --- a/docs/contents.md +++ b/docs/contents.md @@ -102,3 +102,68 @@ customization_guide/test examples/jetson/README examples/jetson/concurrency_and_dynamic_batching/README ``` + +```{toctree} +:maxdepth: 1 +:caption: Client + +client/README +``` + +```{toctree} +:maxdepth: 1 +:caption: Performance Analyzer + +client/src/c++/perf_analyzer/docs/measurements_metrics +client/src/c++/perf_analyzer/docs/install +client/src/c++/perf_analyzer/docs/quick_start +client/src/c++/perf_analyzer/docs/benchmarking +client/src/c++/perf_analyzer/docs/input_data +client/src/c++/perf_analyzer/docs/inference_load_modes +client/src/c++/perf_analyzer/docs/cli +client/src/c++/perf_analyzer/docs/README +client/src/c++/perf_analyzer/docs/llm +client/src/c++/perf_analyzer/README +``` + +```{toctree} +:maxdepth: 1 +:caption: Performance Analyzer + +client/src/grpc_generated/go/README +client/src/grpc_generated/javascript/README +client/src/grpc_generated/java/README +``` + +```{toctree} +:maxdepth: 1 +:caption: Java + +client/src/java/README +``` + +```{toctree} +:maxdepth: 1 +:caption: Python Backend + +python_backend/README.md +``` + +```{toctree} +:maxdepth: 1 +:caption: Python Backend Inferentia +python_backend/inferentia/README.md +``` + +```{toctree} +:maxdepth: 1 +:caption: Python Backend Examples +python_backend/examples/instance_kind/README.md +python_backend/examples/custom_metrics/README.md +python_backend/examples/bls/README.md +python_backend/examples/decoupled/README.md +python_backend/examples/bls_decoupled/README.md +python_backend/examples/jax/README.md +python_backend/examples/auto_complete/README.md +python_backend/examples/preprocessing/README.md +``` \ No newline at end of file From 1c6b22d087979ca46f01212c64aad8f3be73a2d2 Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Thu, 7 Mar 2024 17:50:14 -0800 Subject: [PATCH 02/46] Server and Client repo documented together --- build.py | 32 ++++++++++++++++++++++++- generate_docs.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 generate_docs.py diff --git a/build.py b/build.py index 51c7c12120..a5116c21ca 100755 --- a/build.py +++ b/build.py @@ -35,6 +35,7 @@ import stat import subprocess import sys +import json from inspect import getsourcefile import requests @@ -2358,9 +2359,38 @@ def enable_all(): required=False, help="Override specified backend CMake argument in the build as :=. The argument is passed to CMake as -D=. This flag only impacts CMake arguments that are used by build.py. To unconditionally add a CMake argument to the backend build use --extra-backend-cmake-arg.", ) - + parser.add_argument( + "--docs", + action="store_true", + required=False, + help="Execute a script for documentation generation." + ) FLAGS = parser.parse_args() + if FLAGS.docs: + log("Calling the documentation generation script...") + script_path = os.path.join(THIS_SCRIPT_DIR, "generate_docs.py") + cmd = [ + "python3", + script_path, + "--server-tag", str(FLAGS.version), + "--backend-tag", str(FLAGS.build_dir) + ] + # TODO: Make this dynamic or make it read a config file + repo_details = [ + {'repo': 'client', 'tag': 'main', 'org': 'triton-inference-server'}, + ] + repo_details_str = json.dumps(repo_details) + result = subprocess.run(['python3', script_path, repo_details_str], text=True, capture_output=True) + if result.returncode == 0: + log("Documentation generation completed successfully.") + else: + log("Documentation generation failed.") + log(result.stdout) + log(result.stderr) + # TODO: Think about cleanup of all the cloned repos + sys.exit(1) + if FLAGS.image is None: FLAGS.image = [] if FLAGS.repo_tag is None: diff --git a/generate_docs.py b/generate_docs.py new file mode 100644 index 0000000000..9b00504848 --- /dev/null +++ b/generate_docs.py @@ -0,0 +1,62 @@ +import json +import sys +import subprocess +import os + +def run_command(command): + try: + result = subprocess.run(command, shell=True, check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + print(result.stdout) + except subprocess.CalledProcessError as e: + print(f"Error executing command: {e.cmd}") + print(e.output) + print(e.stderr) + +def build_docker_image(tag): + command = f"docker build -t i_docs:1.0 ." + run_command(command) + +def run_docker_image(tag, host_dir, container_dir): + command = f"docker run -it -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make html'" + run_command(command) + +def clone_from_github(repo, tag, org): + # Construct the full GitHub repository URL + repo_url = f"https://github.com/{org}/{repo}.git" + + # Construct the git clone command + if tag: + clone_command = ["git", "clone", "--branch", tag, "--single-branch", repo_url] + else: + clone_command = ["git", "clone", repo_url] + + # Execute the git clone command + try: + subprocess.run(clone_command, check=True) + print(f"Successfully cloned {repo}") + except subprocess.CalledProcessError as e: + print(f"Failed to clone {repo}. Error: {e}") + +def main(): + # Deserialize the JSON string back to Python data structure + repo_data = json.loads(sys.argv[1]) + current_directory = os.getcwd() + docs_dir_name = "docs" + # Path + os.chdir(docs_dir_name) + + for item in repo_data: + clone_from_github(item['repo'], item['tag'], item['org']) + + tag = "i_docs" # image tag + host_dir = current_directory # The directory on the host to mount + container_dir = "/mnt" # The mount point inside the container + + build_docker_image(tag) + + # Run the Docker image + run_docker_image(tag, host_dir, container_dir) + + +if __name__ == "__main__": + main() \ No newline at end of file From b276c424ba1974c06669dae129412a38580fd5b8 Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Fri, 8 Mar 2024 17:55:39 -0800 Subject: [PATCH 03/46] Logging to /tmp/docs.log added --- generate_docs.py | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/generate_docs.py b/generate_docs.py index 9b00504848..f0eb560fb7 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -2,21 +2,50 @@ import sys import subprocess import os +import logging + +def setup_logger(): + # Create a custom logger + logger = logging.getLogger(__name__) + + # Set the log level + logger.setLevel(logging.INFO) + + # Create handlers + file_handler = logging.FileHandler('/tmp/docs.log') + + # Create formatters and add it to the handlers + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + file_handler.setFormatter(formatter) + + # Add handlers to the logger + logger.addHandler(file_handler) + + return logger + +def log_message(message): + # Setup the logger + logger = setup_logger() + + # Log the message + logger.info(message) def run_command(command): try: result = subprocess.run(command, shell=True, check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - print(result.stdout) + log_message(result.stdout) except subprocess.CalledProcessError as e: - print(f"Error executing command: {e.cmd}") - print(e.output) - print(e.stderr) + log_message(f"Error executing command: {e.cmd}") + log_message(e.output) + log_message(e.stderr) def build_docker_image(tag): + log_message("Running Docker Build") command = f"docker build -t i_docs:1.0 ." run_command(command) def run_docker_image(tag, host_dir, container_dir): + log_message("Running Docker RUN") command = f"docker run -it -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make html'" run_command(command) @@ -33,9 +62,9 @@ def clone_from_github(repo, tag, org): # Execute the git clone command try: subprocess.run(clone_command, check=True) - print(f"Successfully cloned {repo}") + log_message(f"Successfully cloned {repo}") except subprocess.CalledProcessError as e: - print(f"Failed to clone {repo}. Error: {e}") + log_message(f"Failed to clone {repo}. Error: {e}") def main(): # Deserialize the JSON string back to Python data structure @@ -56,7 +85,7 @@ def main(): # Run the Docker image run_docker_image(tag, host_dir, container_dir) - + log_message("**DONE**") if __name__ == "__main__": - main() \ No newline at end of file + main() From 89bc12789dace75e74d997fc2d08f82f08b66bf1 Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Fri, 8 Mar 2024 18:03:10 -0800 Subject: [PATCH 04/46] Dockerfile fix --- generate_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate_docs.py b/generate_docs.py index f0eb560fb7..e4eb4d7c3b 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -41,7 +41,7 @@ def run_command(command): def build_docker_image(tag): log_message("Running Docker Build") - command = f"docker build -t i_docs:1.0 ." + command = f"docker build -f Dockerfile.docs -t i_docs:1.0 ." run_command(command) def run_docker_image(tag, host_dir, container_dir): From ec38273791003f3cf380c12c661445e3b97d47f3 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Mon, 11 Mar 2024 04:03:41 -0700 Subject: [PATCH 05/46] Update toc struture and order --- docs/contents.md | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/docs/contents.md b/docs/contents.md index becb5085fd..0f022d47f8 100644 --- a/docs/contents.md +++ b/docs/contents.md @@ -108,62 +108,45 @@ examples/jetson/concurrency_and_dynamic_batching/README :caption: Client client/README +client/src/java/README ``` ```{toctree} :maxdepth: 1 :caption: Performance Analyzer -client/src/c++/perf_analyzer/docs/measurements_metrics +client/src/c++/perf_analyzer/README +client/src/c++/perf_analyzer/docs/README client/src/c++/perf_analyzer/docs/install client/src/c++/perf_analyzer/docs/quick_start -client/src/c++/perf_analyzer/docs/benchmarking -client/src/c++/perf_analyzer/docs/input_data -client/src/c++/perf_analyzer/docs/inference_load_modes client/src/c++/perf_analyzer/docs/cli -client/src/c++/perf_analyzer/docs/README +client/src/c++/perf_analyzer/docs/inference_load_modes +client/src/c++/perf_analyzer/docs/input_data +client/src/c++/perf_analyzer/docs/measurements_metrics +client/src/c++/perf_analyzer/docs/benchmarking client/src/c++/perf_analyzer/docs/llm -client/src/c++/perf_analyzer/README -``` - -```{toctree} -:maxdepth: 1 -:caption: Performance Analyzer - client/src/grpc_generated/go/README client/src/grpc_generated/javascript/README client/src/grpc_generated/java/README ``` -```{toctree} -:maxdepth: 1 -:caption: Java - -client/src/java/README -``` - ```{toctree} :maxdepth: 1 :caption: Python Backend python_backend/README.md -``` - -```{toctree} -:maxdepth: 1 -:caption: Python Backend Inferentia python_backend/inferentia/README.md ``` ```{toctree} :maxdepth: 1 :caption: Python Backend Examples -python_backend/examples/instance_kind/README.md -python_backend/examples/custom_metrics/README.md +python_backend/examples/auto_complete/README.md python_backend/examples/bls/README.md -python_backend/examples/decoupled/README.md python_backend/examples/bls_decoupled/README.md +python_backend/examples/custom_metrics/README.md +python_backend/examples/decoupled/README.md +python_backend/examples/instance_kind/README.md python_backend/examples/jax/README.md -python_backend/examples/auto_complete/README.md python_backend/examples/preprocessing/README.md -``` \ No newline at end of file +``` From 303660b5f2cc94e7bafac2c002edb409087c7469 Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Wed, 13 Mar 2024 00:10:41 -0700 Subject: [PATCH 06/46] Build.py changes removed added args to generate_docs.py --- generate_docs.py | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/generate_docs.py b/generate_docs.py index e4eb4d7c3b..b03a5ee691 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -3,6 +3,13 @@ import subprocess import os import logging +import argparse +from collections import defaultdict + +parser = argparse.ArgumentParser(description="Process some arguments.") +parser.add_argument('--repo-tag', action='append', help='Repository tags in format key:value') +parser.add_argument('--backend', action='append', help='Repository tags in format key:value') +parser.add_argument('--github-organization', help='GitHub organization name') def setup_logger(): # Create a custom logger @@ -31,6 +38,7 @@ def log_message(message): logger.info(message) def run_command(command): + print(command) try: result = subprocess.run(command, shell=True, check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) log_message(result.stdout) @@ -52,10 +60,10 @@ def run_docker_image(tag, host_dir, container_dir): def clone_from_github(repo, tag, org): # Construct the full GitHub repository URL repo_url = f"https://github.com/{org}/{repo}.git" - + print(repo_url) # Construct the git clone command if tag: - clone_command = ["git", "clone", "--branch", tag, "--single-branch", repo_url] + clone_command = ["git", "clone", "--branch", tag[0], "--single-branch", repo_url] else: clone_command = ["git", "clone", repo_url] @@ -66,17 +74,32 @@ def clone_from_github(repo, tag, org): except subprocess.CalledProcessError as e: log_message(f"Failed to clone {repo}. Error: {e}") +def parse_repo_tag(repo_tags): + repo_dict = defaultdict(list) + for tag in repo_tags: + key, value = tag.split(':', 1) + repo_dict[key].append(value) + return dict(repo_dict) + def main(): - # Deserialize the JSON string back to Python data structure - repo_data = json.loads(sys.argv[1]) + args = parser.parse_args() + repo_tags = parse_repo_tag(args.repo_tag) if args.repo_tag else {} + backend_tags = parse_repo_tag(args.backend) if args.backend else {} + github_org = args.github_organization + print("Parsed repository tags:", repo_tags) + print("Parsed repository tags:", backend_tags) current_directory = os.getcwd() docs_dir_name = "docs" # Path os.chdir(docs_dir_name) - for item in repo_data: - clone_from_github(item['repo'], item['tag'], item['org']) - + if 'client' in repo_tags: + clone_from_github('client', repo_tags['client'], github_org) + if 'core' in repo_tags: + clone_from_github('core', repo_tags['core'], github_org) + if 'python_backend' in backend_tags: + clone_from_github('python_backend', backend_tags['python_backend'], github_org) + tag = "i_docs" # image tag host_dir = current_directory # The directory on the host to mount container_dir = "/mnt" # The mount point inside the container From f5b9b0f31aa13e71bb01b022a0ef816dedc5a2f3 Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Thu, 14 Mar 2024 11:55:49 -0700 Subject: [PATCH 07/46] Update Generate docs --- generate_docs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/generate_docs.py b/generate_docs.py index b03a5ee691..a2953140e3 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -95,10 +95,10 @@ def main(): if 'client' in repo_tags: clone_from_github('client', repo_tags['client'], github_org) - if 'core' in repo_tags: - clone_from_github('core', repo_tags['core'], github_org) - if 'python_backend' in backend_tags: - clone_from_github('python_backend', backend_tags['python_backend'], github_org) + if 'python_backend' in repo_tags: + clone_from_github('python_backend', repo_tags['python_backend'], github_org) + if 'custom_backend' in backend_tags: + clone_from_github('custom_backend', backend_tags['custom_backend'], github_org) tag = "i_docs" # image tag host_dir = current_directory # The directory on the host to mount From ace21b442d73c463fa4906bc5b614f9184f648f0 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Thu, 14 Mar 2024 18:49:16 -0700 Subject: [PATCH 08/46] Replace embedded Github URL with relative file path and revert build.py --- build.py | 32 +---------- generate_docs.py | 142 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 117 insertions(+), 57 deletions(-) diff --git a/build.py b/build.py index a5116c21ca..51c7c12120 100755 --- a/build.py +++ b/build.py @@ -35,7 +35,6 @@ import stat import subprocess import sys -import json from inspect import getsourcefile import requests @@ -2359,37 +2358,8 @@ def enable_all(): required=False, help="Override specified backend CMake argument in the build as :=. The argument is passed to CMake as -D=. This flag only impacts CMake arguments that are used by build.py. To unconditionally add a CMake argument to the backend build use --extra-backend-cmake-arg.", ) - parser.add_argument( - "--docs", - action="store_true", - required=False, - help="Execute a script for documentation generation." - ) - FLAGS = parser.parse_args() - if FLAGS.docs: - log("Calling the documentation generation script...") - script_path = os.path.join(THIS_SCRIPT_DIR, "generate_docs.py") - cmd = [ - "python3", - script_path, - "--server-tag", str(FLAGS.version), - "--backend-tag", str(FLAGS.build_dir) - ] - # TODO: Make this dynamic or make it read a config file - repo_details = [ - {'repo': 'client', 'tag': 'main', 'org': 'triton-inference-server'}, - ] - repo_details_str = json.dumps(repo_details) - result = subprocess.run(['python3', script_path, repo_details_str], text=True, capture_output=True) - if result.returncode == 0: - log("Documentation generation completed successfully.") - else: - log("Documentation generation failed.") - log(result.stdout) - log(result.stderr) - # TODO: Think about cleanup of all the cloned repos - sys.exit(1) + FLAGS = parser.parse_args() if FLAGS.image is None: FLAGS.image = [] diff --git a/generate_docs.py b/generate_docs.py index a2953140e3..ffe74bc1d9 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -1,15 +1,29 @@ -import json -import sys -import subprocess -import os -import logging import argparse +import logging +import os +import re +import subprocess +import sys from collections import defaultdict parser = argparse.ArgumentParser(description="Process some arguments.") -parser.add_argument('--repo-tag', action='append', help='Repository tags in format key:value') -parser.add_argument('--backend', action='append', help='Repository tags in format key:value') -parser.add_argument('--github-organization', help='GitHub organization name') +parser.add_argument( + "--repo-tag", action="append", help="Repository tags in format key:value" +) +parser.add_argument( + "--backend", action="append", help="Repository tags in format key:value" +) +parser.add_argument("--github-organization", help="GitHub organization name") + +SERVER_REPO_DIR = os.getcwd() +SERVER_DOCS_DIR = os.path.join(os.getcwd(), "docs") +DOMAIN_REG = "https://github.com/triton-inference-server" +TAG_REG = "/(blob|tree)/main" +DOC_FILE_PATH_REG = ( + rf"(?<=\()\s*{DOMAIN_REG}/([\w\-]+)({TAG_REG})/*([\w\-/]+.md)\s*(?=[\)#])" +) +DOC_DIR_PATH_REG = rf"(?<=\()\s*{DOMAIN_REG}/([\w\-]+)({TAG_REG})?/*([\w\-/]*)(?=#)" + def setup_logger(): # Create a custom logger @@ -19,10 +33,12 @@ def setup_logger(): logger.setLevel(logging.INFO) # Create handlers - file_handler = logging.FileHandler('/tmp/docs.log') + file_handler = logging.FileHandler("/tmp/docs.log") # Create formatters and add it to the handlers - formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + ) file_handler.setFormatter(formatter) # Add handlers to the logger @@ -30,6 +46,7 @@ def setup_logger(): return logger + def log_message(message): # Setup the logger logger = setup_logger() @@ -37,33 +54,51 @@ def log_message(message): # Log the message logger.info(message) + def run_command(command): print(command) try: - result = subprocess.run(command, shell=True, check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + result = subprocess.run( + command, + shell=True, + check=True, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) log_message(result.stdout) except subprocess.CalledProcessError as e: log_message(f"Error executing command: {e.cmd}") log_message(e.output) log_message(e.stderr) + def build_docker_image(tag): log_message("Running Docker Build") command = f"docker build -f Dockerfile.docs -t i_docs:1.0 ." run_command(command) + def run_docker_image(tag, host_dir, container_dir): log_message("Running Docker RUN") command = f"docker run -it -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make html'" run_command(command) + def clone_from_github(repo, tag, org): # Construct the full GitHub repository URL repo_url = f"https://github.com/{org}/{repo}.git" print(repo_url) # Construct the git clone command if tag: - clone_command = ["git", "clone", "--branch", tag[0], "--single-branch", repo_url] + clone_command = [ + "git", + "clone", + "--branch", + tag[0], + "--single-branch", + repo_url, + ] else: clone_command = ["git", "clone", repo_url] @@ -74,13 +109,60 @@ def clone_from_github(repo, tag, org): except subprocess.CalledProcessError as e: log_message(f"Failed to clone {repo}. Error: {e}") + def parse_repo_tag(repo_tags): repo_dict = defaultdict(list) for tag in repo_tags: - key, value = tag.split(':', 1) + key, value = tag.split(":", 1) repo_dict[key].append(value) return dict(repo_dict) + +def preprocess_docs(repo): + cmd = ["find", repo, "-name", "*.md"] + result = subprocess.run(cmd, check=True, capture_output=True, text=True) + + docs_list = list(filter(None, result.stdout.split("\n"))) + for doc_path in docs_list: + doc_path = os.path.abspath(doc_path) + filedata = None + with open(doc_path, "r") as f: + filedata = f.read() + + def replace_url_with_relpath(m): + target_repo_name, target_path_from_its_repo = m.group(1), os.path.normpath( + m.group(4) + ) + + if target_repo_name != "server": + target_path = os.path.join( + SERVER_DOCS_DIR, target_repo_name, target_path_from_its_repo + ) + else: + target_path = os.path.join(SERVER_REPO_DIR, target_path_from_its_repo) + + # check if file or directory exists + if os.path.isfile(target_path): + pass + elif os.path.isdir(target_path) and os.path.isfile( + os.path.join(target_path, "README.md") + ): + target_path = os.path.join(target_path, "README.md") + else: + return m.group(0) + + # target_path must be a file at this line + rel_path = os.path.relpath(target_path, start=os.path.dirname(doc_path)) + + return rel_path + + filedata = re.sub(DOC_FILE_PATH_REG, replace_url_with_relpath, filedata) + filedata = re.sub(DOC_DIR_PATH_REG, replace_url_with_relpath, filedata) + + with open(doc_path, "w") as f: + f.write(filedata) + + def main(): args = parser.parse_args() repo_tags = parse_repo_tag(args.repo_tag) if args.repo_tag else {} @@ -89,20 +171,27 @@ def main(): print("Parsed repository tags:", repo_tags) print("Parsed repository tags:", backend_tags) current_directory = os.getcwd() - docs_dir_name = "docs" + # docs_dir_name = "docs" # Path - os.chdir(docs_dir_name) - - if 'client' in repo_tags: - clone_from_github('client', repo_tags['client'], github_org) - if 'python_backend' in repo_tags: - clone_from_github('python_backend', repo_tags['python_backend'], github_org) - if 'custom_backend' in backend_tags: - clone_from_github('custom_backend', backend_tags['custom_backend'], github_org) - - tag = "i_docs" # image tag - host_dir = current_directory # The directory on the host to mount - container_dir = "/mnt" # The mount point inside the container + os.chdir(SERVER_DOCS_DIR) + + if "client" in repo_tags: + clone_from_github("client", repo_tags["client"], github_org) + if "python_backend" in repo_tags: + clone_from_github("python_backend", repo_tags["python_backend"], github_org) + if "custom_backend" in backend_tags: + clone_from_github("custom_backend", backend_tags["custom_backend"], github_org) + + if "client" in repo_tags: + preprocess_docs("client") + if "python_backend" in repo_tags: + preprocess_docs("python_backend") + if "custom_backend" in backend_tags: + preprocess_docs("custom_backend") + + tag = "i_docs" # image tag + host_dir = current_directory # The directory on the host to mount + container_dir = "/mnt" # The mount point inside the container build_docker_image(tag) @@ -110,5 +199,6 @@ def main(): run_docker_image(tag, host_dir, container_dir) log_message("**DONE**") + if __name__ == "__main__": main() From 57f8fc9f3fc369be3d1deaa7c49146034c9bfe85 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Sat, 16 Mar 2024 15:02:54 -0700 Subject: [PATCH 09/46] Replace embedded directory paths with URLs. --- generate_docs.py | 98 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/generate_docs.py b/generate_docs.py index ffe74bc1d9..dbd807996e 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -5,6 +5,7 @@ import subprocess import sys from collections import defaultdict +from functools import partial parser = argparse.ArgumentParser(description="Process some arguments.") parser.add_argument( @@ -17,12 +18,14 @@ SERVER_REPO_DIR = os.getcwd() SERVER_DOCS_DIR = os.path.join(os.getcwd(), "docs") -DOMAIN_REG = "https://github.com/triton-inference-server" +HTTP_REG = r"https?://" +DOMAIN_REG = rf"{HTTP_REG}github.com/triton-inference-server" TAG_REG = "/(blob|tree)/main" -DOC_FILE_PATH_REG = ( +DOC_FILE_URL_REG = ( rf"(?<=\()\s*{DOMAIN_REG}/([\w\-]+)({TAG_REG})/*([\w\-/]+.md)\s*(?=[\)#])" ) -DOC_DIR_PATH_REG = rf"(?<=\()\s*{DOMAIN_REG}/([\w\-]+)({TAG_REG})?/*([\w\-/]*)(?=#)" +DOC_DIR_URL_REG = rf"(?<=\()\s*{DOMAIN_REG}/([\w\-]+)({TAG_REG})?/*([\w\-/]*)(?=#)" +REL_PATH_REG = rf"]\s*\(\s*([^)]+)\)" def setup_logger(): @@ -118,6 +121,49 @@ def parse_repo_tag(repo_tags): return dict(repo_dict) +def replace_url_with_relpath(m, src_doc_path): + target_repo_name, target_path_from_its_repo = m.group(1), os.path.normpath( + m.group(4) + ) + + if target_repo_name != "server": + target_path = os.path.join( + SERVER_DOCS_DIR, target_repo_name, target_path_from_its_repo + ) + else: + target_path = os.path.join(SERVER_REPO_DIR, target_path_from_its_repo) + + # check if file or directory exists + if os.path.isfile(target_path): + pass + elif os.path.isdir(target_path) and os.path.isfile( + os.path.join(target_path, "README.md") + ): + target_path = os.path.join(target_path, "README.md") + else: + return m.group(0) + + # target_path must be a file at this line + rel_path = os.path.relpath(target_path, start=os.path.dirname(src_doc_path)) + + return rel_path + + +def replace_relpath_with_url(m, target_repo_name, src_doc_path): + reference = m.group(1) + target_path = os.path.join(os.path.dirname(src_doc_path), reference) + target_path = os.path.normpath(target_path) + + # check if file or directory exists + if os.path.isdir(target_path): + targe_repo_dir = os.path.join(SERVER_DOCS_DIR, target_repo_name) + target_path_from_its_repo = os.path.relpath(target_path, start=targe_repo_dir) + url = f"https://github.com/triton-inference-server/{target_repo_name}/blob/main/{target_path_from_its_repo}/" + return f"]({url})" + else: + return m.group(0) + + def preprocess_docs(repo): cmd = ["find", repo, "-name", "*.md"] result = subprocess.run(cmd, check=True, capture_output=True, text=True) @@ -129,35 +175,23 @@ def preprocess_docs(repo): with open(doc_path, "r") as f: filedata = f.read() - def replace_url_with_relpath(m): - target_repo_name, target_path_from_its_repo = m.group(1), os.path.normpath( - m.group(4) - ) - - if target_repo_name != "server": - target_path = os.path.join( - SERVER_DOCS_DIR, target_repo_name, target_path_from_its_repo - ) - else: - target_path = os.path.join(SERVER_REPO_DIR, target_path_from_its_repo) - - # check if file or directory exists - if os.path.isfile(target_path): - pass - elif os.path.isdir(target_path) and os.path.isfile( - os.path.join(target_path, "README.md") - ): - target_path = os.path.join(target_path, "README.md") - else: - return m.group(0) - - # target_path must be a file at this line - rel_path = os.path.relpath(target_path, start=os.path.dirname(doc_path)) - - return rel_path - - filedata = re.sub(DOC_FILE_PATH_REG, replace_url_with_relpath, filedata) - filedata = re.sub(DOC_DIR_PATH_REG, replace_url_with_relpath, filedata) + filedata = re.sub( + DOC_FILE_URL_REG, + partial(replace_url_with_relpath, src_doc_path=doc_path), + filedata, + ) + filedata = re.sub( + DOC_DIR_URL_REG, + partial(replace_url_with_relpath, src_doc_path=doc_path), + filedata, + ) + filedata = re.sub( + REL_PATH_REG, + partial( + replace_relpath_with_url, target_repo_name=repo, src_doc_path=doc_path + ), + filedata, + ) with open(doc_path, "w") as f: f.write(filedata) From c67ab441d14f1d128c2c766698154a09a443e17e Mon Sep 17 00:00:00 2001 From: Yingge He Date: Tue, 19 Mar 2024 03:28:00 -0700 Subject: [PATCH 10/46] Adding structure reference to the new document --- docs/contents.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contents.md b/docs/contents.md index 0f022d47f8..c802219c2d 100644 --- a/docs/contents.md +++ b/docs/contents.md @@ -84,6 +84,7 @@ protocol/extension_sequence protocol/extension_shared_memory protocol/extension_statistics protocol/extension_trace +protocol/extension_parameters ``` ```{toctree} From 235c0d31f4f75f3ad967c526235e11c702ed3507 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Wed, 20 Mar 2024 16:13:36 -0700 Subject: [PATCH 11/46] save the work --- generate_docs.py | 165 ++++++++++++++++++++++++++++++----------------- 1 file changed, 106 insertions(+), 59 deletions(-) diff --git a/generate_docs.py b/generate_docs.py index dbd807996e..eb5cfc6087 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -7,6 +7,20 @@ from collections import defaultdict from functools import partial +from docs.tests.test import run_test + +# global variables +SERVER_REPO_PATH = os.getcwd() +SERVER_DOCS_DIR_PATH = os.path.join(os.getcwd(), "docs") +DOCS_TEST_DIR_PATH = os.path.join(SERVER_DOCS_DIR_PATH, "tests") + +HTTP_REG = r"^https?://" +TAG_REG = "/(?:blob|tree)/main" +TRITON_REPO_REG = rf"{HTTP_REG}github.com/triton-inference-server" +TRITON_GITHUB_URL_REG = rf"{TRITON_REPO_REG}/([^/#]+)(?:{TAG_REG})?/*([^#]*)\s*(?=#|$)" +RELPATH_REG = r"]\s*\(\s*([^)]+)\)" +REFERENCE_REG = r"(]\s*\(\s*)([^)]+?)(\s*\))" + parser = argparse.ArgumentParser(description="Process some arguments.") parser.add_argument( "--repo-tag", action="append", help="Repository tags in format key:value" @@ -16,17 +30,6 @@ ) parser.add_argument("--github-organization", help="GitHub organization name") -SERVER_REPO_DIR = os.getcwd() -SERVER_DOCS_DIR = os.path.join(os.getcwd(), "docs") -HTTP_REG = r"https?://" -DOMAIN_REG = rf"{HTTP_REG}github.com/triton-inference-server" -TAG_REG = "/(blob|tree)/main" -DOC_FILE_URL_REG = ( - rf"(?<=\()\s*{DOMAIN_REG}/([\w\-]+)({TAG_REG})/*([\w\-/]+.md)\s*(?=[\)#])" -) -DOC_DIR_URL_REG = rf"(?<=\()\s*{DOMAIN_REG}/([\w\-]+)({TAG_REG})?/*([\w\-/]*)(?=#)" -REL_PATH_REG = rf"]\s*\(\s*([^)]+)\)" - def setup_logger(): # Create a custom logger @@ -121,80 +124,120 @@ def parse_repo_tag(repo_tags): return dict(repo_dict) -def replace_url_with_relpath(m, src_doc_path): - target_repo_name, target_path_from_its_repo = m.group(1), os.path.normpath( - m.group(4) - ) +def replace_url_with_relpath(url, src_doc_path): + m = re.match(TRITON_GITHUB_URL_REG, url) + # Do not replace URL if it is not a Triton GitHub file + if not m: + return url - if target_repo_name != "server": + target_repo_name = m.group(1) + target_relpath_from_target_repo = os.path.normpath(m.groups("")[1]) + section = url[len(m.group(0)) :] + valid_hashtag = section not in ["", "#"] and section.startswith("#") + + if target_repo_name == "server": + target_path = os.path.join(SERVER_REPO_PATH, target_relpath_from_target_repo) + else: target_path = os.path.join( - SERVER_DOCS_DIR, target_repo_name, target_path_from_its_repo + SERVER_DOCS_DIR_PATH, target_repo_name, target_relpath_from_target_repo ) - else: - target_path = os.path.join(SERVER_REPO_DIR, target_path_from_its_repo) - # check if file or directory exists - if os.path.isfile(target_path): + """ + Only replace Triton Inference Server GitHub URLs with relative paths in following cases. + 1. URL is a doc file, e.g. ".md" file. + 2. URL is a directory which contains README.md and URL has a hashtag. + """ + # TODO: files must be inside server/docs + if os.path.isfile(target_path) and os.path.splitext(target_path)[1] == ".md": pass - elif os.path.isdir(target_path) and os.path.isfile( - os.path.join(target_path, "README.md") + elif ( + os.path.isdir(target_path) + and os.path.isfile(os.path.join(target_path, "README.md")) + and valid_hashtag ): target_path = os.path.join(target_path, "README.md") else: return m.group(0) # target_path must be a file at this line - rel_path = os.path.relpath(target_path, start=os.path.dirname(src_doc_path)) + relpath = os.path.relpath(target_path, start=os.path.dirname(src_doc_path)) + print(re.sub(TRITON_GITHUB_URL_REG, relpath, url, 1)) + return re.sub(TRITON_GITHUB_URL_REG, relpath, url, 1) - return rel_path - -def replace_relpath_with_url(m, target_repo_name, src_doc_path): - reference = m.group(1) - target_path = os.path.join(os.path.dirname(src_doc_path), reference) +def replace_relpath_with_url(relpath, src_repo_name, src_doc_path): + target_path = relpath.rsplit("#")[0] + section = relpath[len(target_path) :] + valid_hashtag = section not in ["", "#"] and section.startswith("#") + target_path = os.path.join(os.path.dirname(src_doc_path), relpath) target_path = os.path.normpath(target_path) - # check if file or directory exists - if os.path.isdir(target_path): - targe_repo_dir = os.path.join(SERVER_DOCS_DIR, target_repo_name) - target_path_from_its_repo = os.path.relpath(target_path, start=targe_repo_dir) - url = f"https://github.com/triton-inference-server/{target_repo_name}/blob/main/{target_path_from_its_repo}/" - return f"]({url})" + """ + Only replace relative paths with Triton Inference Server GitHub URLs in following cases. + 1. Relative path is pointing to a directory or file inside the same repo (excluding server). + 2. URL is a directory which contains README.md and URL has a hashtag. + """ + url = f"https://github.com/triton-inference-server/{src_repo_name}/blob/main/" + src_repo_abspath = os.path.join(SERVER_DOCS_DIR_PATH, src_repo_name) + + # TODO: should we replace with repo URL? + # Relative path is not in the current repo + if os.path.commonpath([src_repo_abspath, target_path]) != src_repo_abspath: + return relpath + + target_path_from_src_repo = os.path.relpath(target_path, start=src_repo_abspath) + # if not os.path.exists(target_path) or \ + # os.path.isfile(target_path) and os.path.splitext(target_path)[1] != ".md" or \ + # os.path.isdir(target_path) and not valid_hashtag: + # return url + target_path_from_src_repo + section + # else: + # return relpath + + if os.path.exists(target_path) and ( + os.path.isdir(target_path) + and valid_hashtag + or os.path.isfile(target_path) + and os.path.splitext(target_path)[1] != ".md" + ): + return relpath else: - return m.group(0) + return url + target_path_from_src_repo + section + + +def replace_reference(m, src_repo_name, src_doc_path): + hyperlink_str = m.group(2) + match = re.match(HTTP_REG, hyperlink_str) + + if match: + # Hyperlink is a URL + res = replace_url_with_relpath(hyperlink_str, src_doc_path) + else: + # Hyperlink is a relative path + res = replace_relpath_with_url(hyperlink_str, src_repo_name, src_doc_path) + + return m.group(1) + res + m.group(3) def preprocess_docs(repo): + # find all ".md" files inside the current repo cmd = ["find", repo, "-name", "*.md"] result = subprocess.run(cmd, check=True, capture_output=True, text=True) - docs_list = list(filter(None, result.stdout.split("\n"))) + for doc_path in docs_list: doc_path = os.path.abspath(doc_path) - filedata = None + content = None with open(doc_path, "r") as f: - filedata = f.read() + content = f.read() - filedata = re.sub( - DOC_FILE_URL_REG, - partial(replace_url_with_relpath, src_doc_path=doc_path), - filedata, - ) - filedata = re.sub( - DOC_DIR_URL_REG, - partial(replace_url_with_relpath, src_doc_path=doc_path), - filedata, - ) - filedata = re.sub( - REL_PATH_REG, - partial( - replace_relpath_with_url, target_repo_name=repo, src_doc_path=doc_path - ), - filedata, + content = re.sub( + REFERENCE_REG, + partial(replace_reference, src_repo_name=repo, src_doc_path=doc_path), + content, ) with open(doc_path, "w") as f: - f.write(filedata) + f.write(content) def main(): @@ -204,10 +247,10 @@ def main(): github_org = args.github_organization print("Parsed repository tags:", repo_tags) print("Parsed repository tags:", backend_tags) - current_directory = os.getcwd() + # docs_dir_name = "docs" # Path - os.chdir(SERVER_DOCS_DIR) + os.chdir(SERVER_DOCS_DIR_PATH) if "client" in repo_tags: clone_from_github("client", repo_tags["client"], github_org) @@ -224,7 +267,7 @@ def main(): preprocess_docs("custom_backend") tag = "i_docs" # image tag - host_dir = current_directory # The directory on the host to mount + host_dir = SERVER_REPO_PATH # The directory on the host to mount container_dir = "/mnt" # The mount point inside the container build_docker_image(tag) @@ -233,6 +276,10 @@ def main(): run_docker_image(tag, host_dir, container_dir) log_message("**DONE**") + # clean up workspace + rm_cmd = ["rm", "-rf", "client", "python_backend", "custom_backend"] + # subprocess.run(rm_cmd, check=True) + if __name__ == "__main__": main() From 24944fa9e460f54661c69a6f860c6de240031b36 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Wed, 20 Mar 2024 17:18:12 -0700 Subject: [PATCH 12/46] Optimized the logic and checkd the replacements. --- generate_docs.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/generate_docs.py b/generate_docs.py index eb5cfc6087..ac4b9ecd80 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -7,12 +7,12 @@ from collections import defaultdict from functools import partial -from docs.tests.test import run_test +# from docs.tests.test import run_test # global variables SERVER_REPO_PATH = os.getcwd() SERVER_DOCS_DIR_PATH = os.path.join(os.getcwd(), "docs") -DOCS_TEST_DIR_PATH = os.path.join(SERVER_DOCS_DIR_PATH, "tests") +# DOCS_TEST_DIR_PATH = os.path.join(SERVER_DOCS_DIR_PATH, "tests") HTTP_REG = r"^https?://" TAG_REG = "/(?:blob|tree)/main" @@ -161,7 +161,6 @@ def replace_url_with_relpath(url, src_doc_path): # target_path must be a file at this line relpath = os.path.relpath(target_path, start=os.path.dirname(src_doc_path)) - print(re.sub(TRITON_GITHUB_URL_REG, relpath, url, 1)) return re.sub(TRITON_GITHUB_URL_REG, relpath, url, 1) @@ -169,10 +168,11 @@ def replace_relpath_with_url(relpath, src_repo_name, src_doc_path): target_path = relpath.rsplit("#")[0] section = relpath[len(target_path) :] valid_hashtag = section not in ["", "#"] and section.startswith("#") - target_path = os.path.join(os.path.dirname(src_doc_path), relpath) + target_path = os.path.join(os.path.dirname(src_doc_path), target_path) target_path = os.path.normpath(target_path) """ + TODO: Need to update comment Only replace relative paths with Triton Inference Server GitHub URLs in following cases. 1. Relative path is pointing to a directory or file inside the same repo (excluding server). 2. URL is a directory which contains README.md and URL has a hashtag. @@ -180,10 +180,8 @@ def replace_relpath_with_url(relpath, src_repo_name, src_doc_path): url = f"https://github.com/triton-inference-server/{src_repo_name}/blob/main/" src_repo_abspath = os.path.join(SERVER_DOCS_DIR_PATH, src_repo_name) - # TODO: should we replace with repo URL? - # Relative path is not in the current repo - if os.path.commonpath([src_repo_abspath, target_path]) != src_repo_abspath: - return relpath + # Relative path is not in the current repo, which should not happen. + assert os.path.commonpath([src_repo_abspath, target_path]) == src_repo_abspath target_path_from_src_repo = os.path.relpath(target_path, start=src_repo_abspath) # if not os.path.exists(target_path) or \ @@ -197,7 +195,7 @@ def replace_relpath_with_url(relpath, src_repo_name, src_doc_path): os.path.isdir(target_path) and valid_hashtag or os.path.isfile(target_path) - and os.path.splitext(target_path)[1] != ".md" + and os.path.splitext(target_path)[1] == ".md" ): return relpath else: @@ -278,7 +276,7 @@ def main(): # clean up workspace rm_cmd = ["rm", "-rf", "client", "python_backend", "custom_backend"] - # subprocess.run(rm_cmd, check=True) + subprocess.run(rm_cmd, check=True) if __name__ == "__main__": From a2ea26b82a83af85b9e9c65ae98109df3d339d7a Mon Sep 17 00:00:00 2001 From: Yingge He Date: Wed, 20 Mar 2024 17:21:10 -0700 Subject: [PATCH 13/46] Optimized the logic and checkd the replacements. --- generate_docs.py | 163 ++++++++++++++++++++++++++++++----------------- 1 file changed, 104 insertions(+), 59 deletions(-) diff --git a/generate_docs.py b/generate_docs.py index dbd807996e..ac4b9ecd80 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -7,6 +7,20 @@ from collections import defaultdict from functools import partial +# from docs.tests.test import run_test + +# global variables +SERVER_REPO_PATH = os.getcwd() +SERVER_DOCS_DIR_PATH = os.path.join(os.getcwd(), "docs") +# DOCS_TEST_DIR_PATH = os.path.join(SERVER_DOCS_DIR_PATH, "tests") + +HTTP_REG = r"^https?://" +TAG_REG = "/(?:blob|tree)/main" +TRITON_REPO_REG = rf"{HTTP_REG}github.com/triton-inference-server" +TRITON_GITHUB_URL_REG = rf"{TRITON_REPO_REG}/([^/#]+)(?:{TAG_REG})?/*([^#]*)\s*(?=#|$)" +RELPATH_REG = r"]\s*\(\s*([^)]+)\)" +REFERENCE_REG = r"(]\s*\(\s*)([^)]+?)(\s*\))" + parser = argparse.ArgumentParser(description="Process some arguments.") parser.add_argument( "--repo-tag", action="append", help="Repository tags in format key:value" @@ -16,17 +30,6 @@ ) parser.add_argument("--github-organization", help="GitHub organization name") -SERVER_REPO_DIR = os.getcwd() -SERVER_DOCS_DIR = os.path.join(os.getcwd(), "docs") -HTTP_REG = r"https?://" -DOMAIN_REG = rf"{HTTP_REG}github.com/triton-inference-server" -TAG_REG = "/(blob|tree)/main" -DOC_FILE_URL_REG = ( - rf"(?<=\()\s*{DOMAIN_REG}/([\w\-]+)({TAG_REG})/*([\w\-/]+.md)\s*(?=[\)#])" -) -DOC_DIR_URL_REG = rf"(?<=\()\s*{DOMAIN_REG}/([\w\-]+)({TAG_REG})?/*([\w\-/]*)(?=#)" -REL_PATH_REG = rf"]\s*\(\s*([^)]+)\)" - def setup_logger(): # Create a custom logger @@ -121,80 +124,118 @@ def parse_repo_tag(repo_tags): return dict(repo_dict) -def replace_url_with_relpath(m, src_doc_path): - target_repo_name, target_path_from_its_repo = m.group(1), os.path.normpath( - m.group(4) - ) +def replace_url_with_relpath(url, src_doc_path): + m = re.match(TRITON_GITHUB_URL_REG, url) + # Do not replace URL if it is not a Triton GitHub file + if not m: + return url - if target_repo_name != "server": + target_repo_name = m.group(1) + target_relpath_from_target_repo = os.path.normpath(m.groups("")[1]) + section = url[len(m.group(0)) :] + valid_hashtag = section not in ["", "#"] and section.startswith("#") + + if target_repo_name == "server": + target_path = os.path.join(SERVER_REPO_PATH, target_relpath_from_target_repo) + else: target_path = os.path.join( - SERVER_DOCS_DIR, target_repo_name, target_path_from_its_repo + SERVER_DOCS_DIR_PATH, target_repo_name, target_relpath_from_target_repo ) - else: - target_path = os.path.join(SERVER_REPO_DIR, target_path_from_its_repo) - # check if file or directory exists - if os.path.isfile(target_path): + """ + Only replace Triton Inference Server GitHub URLs with relative paths in following cases. + 1. URL is a doc file, e.g. ".md" file. + 2. URL is a directory which contains README.md and URL has a hashtag. + """ + # TODO: files must be inside server/docs + if os.path.isfile(target_path) and os.path.splitext(target_path)[1] == ".md": pass - elif os.path.isdir(target_path) and os.path.isfile( - os.path.join(target_path, "README.md") + elif ( + os.path.isdir(target_path) + and os.path.isfile(os.path.join(target_path, "README.md")) + and valid_hashtag ): target_path = os.path.join(target_path, "README.md") else: return m.group(0) # target_path must be a file at this line - rel_path = os.path.relpath(target_path, start=os.path.dirname(src_doc_path)) + relpath = os.path.relpath(target_path, start=os.path.dirname(src_doc_path)) + return re.sub(TRITON_GITHUB_URL_REG, relpath, url, 1) - return rel_path - -def replace_relpath_with_url(m, target_repo_name, src_doc_path): - reference = m.group(1) - target_path = os.path.join(os.path.dirname(src_doc_path), reference) +def replace_relpath_with_url(relpath, src_repo_name, src_doc_path): + target_path = relpath.rsplit("#")[0] + section = relpath[len(target_path) :] + valid_hashtag = section not in ["", "#"] and section.startswith("#") + target_path = os.path.join(os.path.dirname(src_doc_path), target_path) target_path = os.path.normpath(target_path) - # check if file or directory exists - if os.path.isdir(target_path): - targe_repo_dir = os.path.join(SERVER_DOCS_DIR, target_repo_name) - target_path_from_its_repo = os.path.relpath(target_path, start=targe_repo_dir) - url = f"https://github.com/triton-inference-server/{target_repo_name}/blob/main/{target_path_from_its_repo}/" - return f"]({url})" + """ + TODO: Need to update comment + Only replace relative paths with Triton Inference Server GitHub URLs in following cases. + 1. Relative path is pointing to a directory or file inside the same repo (excluding server). + 2. URL is a directory which contains README.md and URL has a hashtag. + """ + url = f"https://github.com/triton-inference-server/{src_repo_name}/blob/main/" + src_repo_abspath = os.path.join(SERVER_DOCS_DIR_PATH, src_repo_name) + + # Relative path is not in the current repo, which should not happen. + assert os.path.commonpath([src_repo_abspath, target_path]) == src_repo_abspath + + target_path_from_src_repo = os.path.relpath(target_path, start=src_repo_abspath) + # if not os.path.exists(target_path) or \ + # os.path.isfile(target_path) and os.path.splitext(target_path)[1] != ".md" or \ + # os.path.isdir(target_path) and not valid_hashtag: + # return url + target_path_from_src_repo + section + # else: + # return relpath + + if os.path.exists(target_path) and ( + os.path.isdir(target_path) + and valid_hashtag + or os.path.isfile(target_path) + and os.path.splitext(target_path)[1] == ".md" + ): + return relpath else: - return m.group(0) + return url + target_path_from_src_repo + section + + +def replace_reference(m, src_repo_name, src_doc_path): + hyperlink_str = m.group(2) + match = re.match(HTTP_REG, hyperlink_str) + + if match: + # Hyperlink is a URL + res = replace_url_with_relpath(hyperlink_str, src_doc_path) + else: + # Hyperlink is a relative path + res = replace_relpath_with_url(hyperlink_str, src_repo_name, src_doc_path) + + return m.group(1) + res + m.group(3) def preprocess_docs(repo): + # find all ".md" files inside the current repo cmd = ["find", repo, "-name", "*.md"] result = subprocess.run(cmd, check=True, capture_output=True, text=True) - docs_list = list(filter(None, result.stdout.split("\n"))) + for doc_path in docs_list: doc_path = os.path.abspath(doc_path) - filedata = None + content = None with open(doc_path, "r") as f: - filedata = f.read() + content = f.read() - filedata = re.sub( - DOC_FILE_URL_REG, - partial(replace_url_with_relpath, src_doc_path=doc_path), - filedata, - ) - filedata = re.sub( - DOC_DIR_URL_REG, - partial(replace_url_with_relpath, src_doc_path=doc_path), - filedata, - ) - filedata = re.sub( - REL_PATH_REG, - partial( - replace_relpath_with_url, target_repo_name=repo, src_doc_path=doc_path - ), - filedata, + content = re.sub( + REFERENCE_REG, + partial(replace_reference, src_repo_name=repo, src_doc_path=doc_path), + content, ) with open(doc_path, "w") as f: - f.write(filedata) + f.write(content) def main(): @@ -204,10 +245,10 @@ def main(): github_org = args.github_organization print("Parsed repository tags:", repo_tags) print("Parsed repository tags:", backend_tags) - current_directory = os.getcwd() + # docs_dir_name = "docs" # Path - os.chdir(SERVER_DOCS_DIR) + os.chdir(SERVER_DOCS_DIR_PATH) if "client" in repo_tags: clone_from_github("client", repo_tags["client"], github_org) @@ -224,7 +265,7 @@ def main(): preprocess_docs("custom_backend") tag = "i_docs" # image tag - host_dir = current_directory # The directory on the host to mount + host_dir = SERVER_REPO_PATH # The directory on the host to mount container_dir = "/mnt" # The mount point inside the container build_docker_image(tag) @@ -233,6 +274,10 @@ def main(): run_docker_image(tag, host_dir, container_dir) log_message("**DONE**") + # clean up workspace + rm_cmd = ["rm", "-rf", "client", "python_backend", "custom_backend"] + subprocess.run(rm_cmd, check=True) + if __name__ == "__main__": main() From 4df3422986c94aabb7e40460b8ed0a47573b8477 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Wed, 20 Mar 2024 18:10:48 -0700 Subject: [PATCH 14/46] Fix missing sections after url. --- generate_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate_docs.py b/generate_docs.py index ac4b9ecd80..04f56cb7b5 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -157,7 +157,7 @@ def replace_url_with_relpath(url, src_doc_path): ): target_path = os.path.join(target_path, "README.md") else: - return m.group(0) + return url # target_path must be a file at this line relpath = os.path.relpath(target_path, start=os.path.dirname(src_doc_path)) From 4987c09c7b8ccc5d89d9745ad814c59e677fc647 Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Wed, 20 Mar 2024 18:23:26 -0700 Subject: [PATCH 15/46] Remove --it --- generate_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate_docs.py b/generate_docs.py index ac4b9ecd80..8811a6ef1b 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -87,7 +87,7 @@ def build_docker_image(tag): def run_docker_image(tag, host_dir, container_dir): log_message("Running Docker RUN") - command = f"docker run -it -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make html'" + command = f"docker run -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" run_command(command) From 49ef5d17a24bfa6c04ae26cef5176eaf85d3e63b Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Wed, 20 Mar 2024 19:06:30 -0700 Subject: [PATCH 16/46] Add a flag --- generate_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate_docs.py b/generate_docs.py index 0d5bf2e623..421cee05f8 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -87,7 +87,7 @@ def build_docker_image(tag): def run_docker_image(tag, host_dir, container_dir): log_message("Running Docker RUN") - command = f"docker run -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" + command = f"docker run --rm -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" run_command(command) From b4ce3cda887d315e515246e5b18c0465b2429dbd Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Wed, 20 Mar 2024 19:08:09 -0700 Subject: [PATCH 17/46] Add a flag --- generate_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate_docs.py b/generate_docs.py index 421cee05f8..5f2eea95f1 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -87,7 +87,7 @@ def build_docker_image(tag): def run_docker_image(tag, host_dir, container_dir): log_message("Running Docker RUN") - command = f"docker run --rm -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" + command = f"docker run --rm --it -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" run_command(command) From 4d35be7589b320433db86b5e70ebce07e28ec5aa Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Wed, 20 Mar 2024 19:08:57 -0700 Subject: [PATCH 18/46] Add a flag --- generate_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate_docs.py b/generate_docs.py index 5f2eea95f1..b948544ea5 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -87,7 +87,7 @@ def build_docker_image(tag): def run_docker_image(tag, host_dir, container_dir): log_message("Running Docker RUN") - command = f"docker run --rm --it -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" + command = f"docker run --rm -it -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" run_command(command) From 09bc15b7ef3b5c555cb9d06efcb3e8ddfd8ed9be Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Wed, 20 Mar 2024 19:48:32 -0700 Subject: [PATCH 19/46] Rewrite docker commands --- generate_docs.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/generate_docs.py b/generate_docs.py index b948544ea5..53968d4726 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -81,13 +81,29 @@ def run_command(command): def build_docker_image(tag): log_message("Running Docker Build") - command = f"docker build -f Dockerfile.docs -t i_docs:1.0 ." + command = f"docker build -t i_docs_build - < docs/Dockerfile.docs" + +# command = f"docker build -f Dockerfile.docs -t i_docs:1.0 ." + run_command(command) + +def create_docker(): + log_message("Running Docker CREATE") + command = f"docker create --name i_docs -w /docs i_docs_build /bin/bash -c 'make clean;make html'" +# docker run --rm -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" + run_command(command) + command = f"docker cp $PWD/docs i_docs:/" + run_command(command) + command = f"docker start -a i_docs" + run_command(command) + command = f"docker cp i_docs:/docs/build/html html" + run_command(command) + command = f"docker rm -f i_docs" run_command(command) def run_docker_image(tag, host_dir, container_dir): log_message("Running Docker RUN") - command = f"docker run --rm -it -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" + command = f"docker run --rm -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" run_command(command) @@ -267,11 +283,12 @@ def main(): tag = "i_docs" # image tag host_dir = SERVER_REPO_PATH # The directory on the host to mount container_dir = "/mnt" # The mount point inside the container - + os.chdir(SERVER_REPO_PATH) build_docker_image(tag) # Run the Docker image - run_docker_image(tag, host_dir, container_dir) + #run_docker_image(tag, host_dir, container_dir) + create_docker() log_message("**DONE**") # clean up workspace From cf6966b0786658014b3abeb4bf8ba87184a74df9 Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Wed, 20 Mar 2024 20:27:44 -0700 Subject: [PATCH 20/46] Cleanup --- generate_docs.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/generate_docs.py b/generate_docs.py index 53968d4726..d5855594bf 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -79,20 +79,18 @@ def run_command(command): log_message(e.stderr) -def build_docker_image(tag): +def build_docker_image(): log_message("Running Docker Build") command = f"docker build -t i_docs_build - < docs/Dockerfile.docs" - -# command = f"docker build -f Dockerfile.docs -t i_docs:1.0 ." run_command(command) -def create_docker(): +def create_and_run_docker(): log_message("Running Docker CREATE") command = f"docker create --name i_docs -w /docs i_docs_build /bin/bash -c 'make clean;make html'" -# docker run --rm -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" run_command(command) command = f"docker cp $PWD/docs i_docs:/" run_command(command) + log_message("Running Docker START") command = f"docker start -a i_docs" run_command(command) command = f"docker cp i_docs:/docs/build/html html" @@ -284,11 +282,8 @@ def main(): host_dir = SERVER_REPO_PATH # The directory on the host to mount container_dir = "/mnt" # The mount point inside the container os.chdir(SERVER_REPO_PATH) - build_docker_image(tag) - - # Run the Docker image - #run_docker_image(tag, host_dir, container_dir) - create_docker() + build_docker_image() + create_and_run_docker() log_message("**DONE**") # clean up workspace From 478faee3cccbc0246b58bb330944ac9309c59c37 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Fri, 22 Mar 2024 12:31:51 -0700 Subject: [PATCH 21/46] Preprocess the server repo. --- generate_docs.py | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/generate_docs.py b/generate_docs.py index 04f56cb7b5..6b49a779af 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -19,7 +19,8 @@ TRITON_REPO_REG = rf"{HTTP_REG}github.com/triton-inference-server" TRITON_GITHUB_URL_REG = rf"{TRITON_REPO_REG}/([^/#]+)(?:{TAG_REG})?/*([^#]*)\s*(?=#|$)" RELPATH_REG = r"]\s*\(\s*([^)]+)\)" -REFERENCE_REG = r"(]\s*\(\s*)([^)]+?)(\s*\))" +# regex pattern to find all references excluding embedded images in a .md file. +REFERENCE_REG = r"((?, e.g. ]+>. Whether we want to + # find and replace the link depends on if they link to internal .md files + # or allows relative paths. I haven't seen one such case in our doc so + # should be safe for now. hyperlink_str = m.group(2) match = re.match(HTTP_REG, hyperlink_str) @@ -213,15 +224,32 @@ def replace_reference(m, src_repo_name, src_doc_path): # Hyperlink is a relative path res = replace_relpath_with_url(hyperlink_str, src_repo_name, src_doc_path) + # TODO: This needs improvement. One way is to replace m.group(2) only return m.group(1) + res + m.group(3) -def preprocess_docs(repo): +def preprocess_docs(repo, excluded_dir_list=[]): # find all ".md" files inside the current repo - cmd = ["find", repo, "-name", "*.md"] - result = subprocess.run(cmd, check=True, capture_output=True, text=True) + + # treat server repo as special case + if repo == "server": + excluded_dir_list.append("build") + # find . -type d \( -path ./build -o -path ./client -o -path ./python_backend \) -prune -o -type f -name "*.md" -print + cmd = ( + ["find", ".", "-type", "d", "\\("] + + " -o ".join([f"-path './{dir}'" for dir in excluded_dir_list]).split(" ") + + ["\\)", "-prune", "-o", "-type", "f", "-name", "'*.md'", "-print"] + ) + cmd = " ".join(cmd) + result = subprocess.run( + cmd, check=True, capture_output=True, text=True, shell=True + ) + else: + cmd = ["find", repo, "-name", "*.md"] + result = subprocess.run(cmd, check=True, capture_output=True, text=True) docs_list = list(filter(None, result.stdout.split("\n"))) + # Read, preprocess and write to each doc file for doc_path in docs_list: doc_path = os.path.abspath(doc_path) content = None @@ -257,6 +285,10 @@ def main(): if "custom_backend" in backend_tags: clone_from_github("custom_backend", backend_tags["custom_backend"], github_org) + # Preprocess after all repos are cloned + preprocess_docs( + "server", excluded_dir_list=["client", "python_backend", "custom_backend"] + ) if "client" in repo_tags: preprocess_docs("client") if "python_backend" in repo_tags: From 774b412a19ef3a88ef057f6d6de604edac3de17e Mon Sep 17 00:00:00 2001 From: Yingge He Date: Fri, 22 Mar 2024 12:41:28 -0700 Subject: [PATCH 22/46] Reorganize toc in contents.md --- docs/contents.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/contents.md b/docs/contents.md index c802219c2d..634dab2715 100644 --- a/docs/contents.md +++ b/docs/contents.md @@ -110,6 +110,9 @@ examples/jetson/concurrency_and_dynamic_batching/README client/README client/src/java/README +client/src/grpc_generated/go/README +client/src/grpc_generated/javascript/README +client/src/grpc_generated/java/README ``` ```{toctree} @@ -126,9 +129,6 @@ client/src/c++/perf_analyzer/docs/input_data client/src/c++/perf_analyzer/docs/measurements_metrics client/src/c++/perf_analyzer/docs/benchmarking client/src/c++/perf_analyzer/docs/llm -client/src/grpc_generated/go/README -client/src/grpc_generated/javascript/README -client/src/grpc_generated/java/README ``` ```{toctree} @@ -137,11 +137,6 @@ client/src/grpc_generated/java/README python_backend/README.md python_backend/inferentia/README.md -``` - -```{toctree} -:maxdepth: 1 -:caption: Python Backend Examples python_backend/examples/auto_complete/README.md python_backend/examples/bls/README.md python_backend/examples/bls_decoupled/README.md From 1ae545595239e7bfb19cdc18c4ce3414b3969fb6 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Sat, 23 Mar 2024 10:03:31 -0700 Subject: [PATCH 23/46] Minor changes --- docs/conf.py | 4 ++-- docs/contents.md | 4 ++-- generate_docs.py | 8 +++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 9378329752..bf5e8ce2e0 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -76,7 +76,7 @@ "sphinx_sitemap", ] -suppress_warnings = ["myst.domains", "ref.ref"] +suppress_warnings = ["myst.domains", "ref.ref", "myst.header"] numfig = True @@ -105,7 +105,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["README.md"] +exclude_patterns = ["README.md", "examples/README.md", "user_guide/perf_analyzer.md"] # -- Options for HTML output ------------------------------------------------- diff --git a/docs/contents.md b/docs/contents.md index 634dab2715..87241ca43d 100644 --- a/docs/contents.md +++ b/docs/contents.md @@ -30,6 +30,7 @@ :maxdepth: 1 :caption: Getting Started +index getting_started/quickstart ``` @@ -47,7 +48,6 @@ user_guide/optimization user_guide/ragged_batching user_guide/rate_limiter user_guide/model_analyzer -user_guide/perf_analyzer user_guide/model_management user_guide/custom_operations user_guide/decoupled_models @@ -128,7 +128,7 @@ client/src/c++/perf_analyzer/docs/inference_load_modes client/src/c++/perf_analyzer/docs/input_data client/src/c++/perf_analyzer/docs/measurements_metrics client/src/c++/perf_analyzer/docs/benchmarking -client/src/c++/perf_analyzer/docs/llm +client/src/c++/perf_analyzer/genai-perf/README ``` ```{toctree} diff --git a/generate_docs.py b/generate_docs.py index 6f9a800c99..7f933e834a 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -85,6 +85,7 @@ def build_docker_image(): command = f"docker build -t i_docs_build - < docs/Dockerfile.docs" run_command(command) + def create_and_run_docker(): log_message("Running Docker CREATE") command = f"docker create --name i_docs -w /docs i_docs_build /bin/bash -c 'make clean;make html'" @@ -157,6 +158,10 @@ def replace_url_with_relpath(url, src_doc_path): SERVER_DOCS_DIR_PATH, target_repo_name, target_relpath_from_target_repo ) + # Return URL if it points to a path outside server/docs. + if os.path.commonpath([SERVER_DOCS_DIR_PATH, target_path]) != SERVER_DOCS_DIR_PATH: + return url + """ Only replace Triton Inference Server GitHub URLs with relative paths in following cases. 1. URL is a doc file, e.g. ".md" file. @@ -173,9 +178,6 @@ def replace_url_with_relpath(url, src_doc_path): else: return url - # Assert target path is under the server repo directory. - assert os.path.commonpath([SERVER_REPO_PATH, target_path]) == SERVER_REPO_PATH - # target_path must be a file at this line relpath = os.path.relpath(target_path, start=os.path.dirname(src_doc_path)) return re.sub(TRITON_GITHUB_URL_REG, relpath, url, 1) From 4b176b36df3277b127e0fd58f128fb2094fd928e Mon Sep 17 00:00:00 2001 From: Yingge He Date: Sat, 23 Mar 2024 12:56:18 -0700 Subject: [PATCH 24/46] Move generate_docs.py to docs/. --- generate_docs.py => docs/generate_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename generate_docs.py => docs/generate_docs.py (99%) diff --git a/generate_docs.py b/docs/generate_docs.py similarity index 99% rename from generate_docs.py rename to docs/generate_docs.py index 7f933e834a..bf06c35ceb 100644 --- a/generate_docs.py +++ b/docs/generate_docs.py @@ -95,7 +95,7 @@ def create_and_run_docker(): log_message("Running Docker START") command = f"docker start -a i_docs" run_command(command) - command = f"docker cp i_docs:/docs/build/html html" + command = f"docker cp i_docs:/docs/build docs/build" run_command(command) command = f"docker rm -f i_docs" run_command(command) From 152b7f039dba6991960bc06dbd70070795660fbc Mon Sep 17 00:00:00 2001 From: Yingge He Date: Sat, 23 Mar 2024 13:19:49 -0700 Subject: [PATCH 25/46] cd to server repo dir after running the script. --- docs/generate_docs.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index bf06c35ceb..0ebd678cc6 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -324,6 +324,9 @@ def main(): rm_cmd = ["rm", "-rf", "client", "python_backend", "custom_backend"] subprocess.run(rm_cmd, check=True) + # Restore previous working state + os.chdir(SERVER_REPO_PATH) + if __name__ == "__main__": main() From ca05658a42eeb7fe67f906725fe42b7e93dfcd2f Mon Sep 17 00:00:00 2001 From: Yingge He Date: Sun, 24 Mar 2024 18:10:49 -0700 Subject: [PATCH 26/46] Simplify logic --- docs/generate_docs.py | 79 +++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index 0ebd678cc6..01e76ec93b 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -12,7 +12,6 @@ # global variables SERVER_REPO_PATH = os.getcwd() SERVER_DOCS_DIR_PATH = os.path.join(os.getcwd(), "docs") -# DOCS_TEST_DIR_PATH = os.path.join(SERVER_DOCS_DIR_PATH, "tests") HTTP_REG = r"^https?://" TAG_REG = "/(?:blob|tree)/main" @@ -140,6 +139,30 @@ def parse_repo_tag(repo_tags): return dict(repo_dict) +# Return the Git repo name of given file path +def get_git_repo_name(file_path): + # Execute git command to get remote URL + try: + # Get the directory containing the file + directory = os.path.dirname(file_path) + # Execute git command with the file's directory as the cwd + remote_url = ( + subprocess.check_output( + ["git", "-C", directory, "remote", "get-url", "origin"] + ) + .decode() + .strip() + ) + except subprocess.CalledProcessError: + return None + + # Extract repository name from the remote URL + if remote_url.endswith(".git"): + remote_url = remote_url[:-4] # Remove '.git' extension + repo_name = os.path.basename(remote_url) + return repo_name + + def replace_url_with_relpath(url, src_doc_path): m = re.match(TRITON_GITHUB_URL_REG, url) # Do not replace URL if it is not a Triton GitHub file @@ -183,12 +206,13 @@ def replace_url_with_relpath(url, src_doc_path): return re.sub(TRITON_GITHUB_URL_REG, relpath, url, 1) -def replace_relpath_with_url(relpath, src_repo_name, src_doc_path): +def replace_relpath_with_url(relpath, src_doc_path): target_path = relpath.rsplit("#")[0] section = relpath[len(target_path) :] valid_hashtag = section not in ["", "#"] and section.startswith("#") target_path = os.path.join(os.path.dirname(src_doc_path), target_path) target_path = os.path.normpath(target_path) + src_git_repo_name = get_git_repo_name(src_doc_path) """ TODO: Need to update comment @@ -196,12 +220,12 @@ def replace_relpath_with_url(relpath, src_repo_name, src_doc_path): 1. Relative path is pointing to a directory or file inside the same repo (excluding server). 2. URL is a directory which contains README.md and URL has a hashtag. """ - url = f"https://github.com/triton-inference-server/{src_repo_name}/blob/main/" - if src_repo_name == "server": + url = f"https://github.com/triton-inference-server/{src_git_repo_name}/blob/main/" + if src_git_repo_name == "server": src_repo_abspath = SERVER_REPO_PATH # TODO: assert the relative path not pointing to cloned repo, e.g. client else: - src_repo_abspath = os.path.join(SERVER_DOCS_DIR_PATH, src_repo_name) + src_repo_abspath = os.path.join(SERVER_DOCS_DIR_PATH, src_git_repo_name) # Assert target path is under the current repo directory. assert os.path.commonpath([src_repo_abspath, target_path]) == src_repo_abspath @@ -225,7 +249,7 @@ def replace_relpath_with_url(relpath, src_repo_name, src_doc_path): return url + target_path_from_src_repo + section -def replace_reference(m, src_repo_name, src_doc_path): +def replace_reference(m, src_doc_path): # TODO: markdown allows , e.g. ]+>. Whether we want to # find and replace the link depends on if they link to internal .md files # or allows relative paths. I haven't seen one such case in our doc so @@ -238,31 +262,28 @@ def replace_reference(m, src_repo_name, src_doc_path): res = replace_url_with_relpath(hyperlink_str, src_doc_path) else: # Hyperlink is a relative path - res = replace_relpath_with_url(hyperlink_str, src_repo_name, src_doc_path) + res = replace_relpath_with_url(hyperlink_str, src_doc_path) # TODO: This needs improvement. One way is to replace m.group(2) only return m.group(1) + res + m.group(3) -def preprocess_docs(repo, excluded_dir_list=[]): +def preprocess_docs(excluded_paths=[]): # find all ".md" files inside the current repo # treat server repo as special case - if repo == "server": - excluded_dir_list.append("build") - # find . -type d \( -path ./build -o -path ./client -o -path ./python_backend \) -prune -o -type f -name "*.md" -print - cmd = ( - ["find", ".", "-type", "d", "\\("] - + " -o ".join([f"-path './{dir}'" for dir in excluded_dir_list]).split(" ") - + ["\\)", "-prune", "-o", "-type", "f", "-name", "'*.md'", "-print"] - ) - cmd = " ".join(cmd) - result = subprocess.run( - cmd, check=True, capture_output=True, text=True, shell=True - ) - else: - cmd = ["find", repo, "-name", "*.md"] - result = subprocess.run(cmd, check=True, capture_output=True, text=True) + # if repo == "server": + # find . -type d \( -path ./build -o -path ./client -o -path ./python_backend \) -prune -o -type f -name "*.md" -print + cmd = ( + ["find", ".", "-type", "d", "\\("] + + " -o ".join([f"-path './{dir}'" for dir in excluded_paths]).split(" ") + + ["\\)", "-prune", "-o", "-type", "f", "-name", "'*.md'", "-print"] + ) + cmd = " ".join(cmd) + result = subprocess.run(cmd, check=True, capture_output=True, text=True, shell=True) + # else: + # cmd = ["find", ".", "-name", "*.md"] + # result = subprocess.run(cmd, check=True, capture_output=True, text=True) docs_list = list(filter(None, result.stdout.split("\n"))) # Read, preprocess and write to each doc file @@ -274,7 +295,7 @@ def preprocess_docs(repo, excluded_dir_list=[]): content = re.sub( REFERENCE_REG, - partial(replace_reference, src_repo_name=repo, src_doc_path=doc_path), + partial(replace_reference, src_doc_path=doc_path), content, ) @@ -302,15 +323,7 @@ def main(): clone_from_github("custom_backend", backend_tags["custom_backend"], github_org) # Preprocess after all repos are cloned - preprocess_docs( - "server", excluded_dir_list=["client", "python_backend", "custom_backend"] - ) - if "client" in repo_tags: - preprocess_docs("client") - if "python_backend" in repo_tags: - preprocess_docs("python_backend") - if "custom_backend" in backend_tags: - preprocess_docs("custom_backend") + preprocess_docs(excluded_paths=["build"]) tag = "i_docs" # image tag host_dir = SERVER_REPO_PATH # The directory on the host to mount From 12aea0027baabff82e524f94471ffe0e03d3c0be Mon Sep 17 00:00:00 2001 From: Yingge He Date: Sun, 24 Mar 2024 19:39:00 -0700 Subject: [PATCH 27/46] Fix clean up code --- docs/generate_docs.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index 01e76ec93b..5b39feb623 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -334,11 +334,12 @@ def main(): log_message("**DONE**") # clean up workspace - rm_cmd = ["rm", "-rf", "client", "python_backend", "custom_backend"] - subprocess.run(rm_cmd, check=True) - - # Restore previous working state - os.chdir(SERVER_REPO_PATH) + if "client" in repo_tags: + subprocess.run(["rm", "-rf", "docs/client"], check=True) + if "python_backend" in repo_tags: + subprocess.run(["rm", "-rf", "docs/python_backend"], check=True) + if "custom_backend" in backend_tags: + subprocess.run(["rm", "-rf", "docs/custom_backend"], check=True) if __name__ == "__main__": From 667d01ac9bd9d7fe99764c4404aa8822cad399f1 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Mon, 25 Mar 2024 16:14:30 -0700 Subject: [PATCH 28/46] Exclude files specified in conf.py. --- docs/generate_docs.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index 5b39feb623..c4b9a53ad9 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -10,6 +10,8 @@ # from docs.tests.test import run_test # global variables +exclude_patterns = ["README.md", "examples/README.md", "user_guide/perf_analyzer.md"] + SERVER_REPO_PATH = os.getcwd() SERVER_DOCS_DIR_PATH = os.path.join(os.getcwd(), "docs") @@ -139,6 +141,15 @@ def parse_repo_tag(repo_tags): return dict(repo_dict) +def is_excluded(file_path): + for exclude_pattern in exclude_patterns: + file_abspath = os.path.abspath(file_path) + exclude_pattern = os.path.abspath(exclude_pattern) + if os.path.commonpath([file_abspath, exclude_pattern]) == exclude_pattern: + return True + return False + + # Return the Git repo name of given file path def get_git_repo_name(file_path): # Execute git command to get remote URL @@ -190,12 +201,17 @@ def replace_url_with_relpath(url, src_doc_path): 1. URL is a doc file, e.g. ".md" file. 2. URL is a directory which contains README.md and URL has a hashtag. """ - if os.path.isfile(target_path) and os.path.splitext(target_path)[1] == ".md": + if ( + os.path.isfile(target_path) + and os.path.splitext(target_path)[1] == ".md" + and not is_excluded(target_path) + ): pass elif ( os.path.isdir(target_path) and os.path.isfile(os.path.join(target_path, "README.md")) and valid_hashtag + and not is_excluded(os.path.join(target_path, "README.md")) ): target_path = os.path.join(target_path, "README.md") else: @@ -241,8 +257,10 @@ def replace_relpath_with_url(relpath, src_doc_path): if os.path.exists(target_path) and ( os.path.isdir(target_path) and valid_hashtag + and not is_excluded(os.path.join(target_path, "README.md")) or os.path.isfile(target_path) and os.path.splitext(target_path)[1] == ".md" + and not is_excluded(target_path) ): return relpath else: @@ -288,6 +306,9 @@ def preprocess_docs(excluded_paths=[]): # Read, preprocess and write to each doc file for doc_path in docs_list: + if is_excluded(doc_path): + continue + doc_path = os.path.abspath(doc_path) content = None with open(doc_path, "r") as f: From b386a92b4c337ceb5e3fcc1d65073e3c2a285e0f Mon Sep 17 00:00:00 2001 From: Yingge He Date: Mon, 25 Mar 2024 16:16:39 -0700 Subject: [PATCH 29/46] Run generate_docs.py in a container. --- docs/generate_docs.py | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index c4b9a53ad9..73f39cb031 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -81,33 +81,6 @@ def run_command(command): log_message(e.stderr) -def build_docker_image(): - log_message("Running Docker Build") - command = f"docker build -t i_docs_build - < docs/Dockerfile.docs" - run_command(command) - - -def create_and_run_docker(): - log_message("Running Docker CREATE") - command = f"docker create --name i_docs -w /docs i_docs_build /bin/bash -c 'make clean;make html'" - run_command(command) - command = f"docker cp $PWD/docs i_docs:/" - run_command(command) - log_message("Running Docker START") - command = f"docker start -a i_docs" - run_command(command) - command = f"docker cp i_docs:/docs/build docs/build" - run_command(command) - command = f"docker rm -f i_docs" - run_command(command) - - -def run_docker_image(tag, host_dir, container_dir): - log_message("Running Docker RUN") - command = f"docker run --rm -v {host_dir}:{container_dir} {tag}:1.0 /bin/bash -c 'cd {container_dir}/docs && make clean && make html'" - run_command(command) - - def clone_from_github(repo, tag, org): # Construct the full GitHub repository URL repo_url = f"https://github.com/{org}/{repo}.git" @@ -346,14 +319,6 @@ def main(): # Preprocess after all repos are cloned preprocess_docs(excluded_paths=["build"]) - tag = "i_docs" # image tag - host_dir = SERVER_REPO_PATH # The directory on the host to mount - container_dir = "/mnt" # The mount point inside the container - os.chdir(SERVER_REPO_PATH) - build_docker_image() - create_and_run_docker() - log_message("**DONE**") - # clean up workspace if "client" in repo_tags: subprocess.run(["rm", "-rf", "docs/client"], check=True) From 4d23c6d25266145a1b053abc10ccb53d583df548 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Mon, 25 Mar 2024 17:02:18 -0700 Subject: [PATCH 30/46] fix --- docs/generate_docs.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index 73f39cb031..e150ade3d5 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -81,6 +81,24 @@ def run_command(command): log_message(e.stderr) +def run_command(command): + print(command) + try: + result = subprocess.run( + command, + shell=True, + check=True, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + log_message(result.stdout) + except subprocess.CalledProcessError as e: + log_message(f"Error executing command: {e.cmd}") + log_message(e.output) + log_message(e.stderr) + + def clone_from_github(repo, tag, org): # Construct the full GitHub repository URL repo_url = f"https://github.com/{org}/{repo}.git" @@ -318,8 +336,11 @@ def main(): # Preprocess after all repos are cloned preprocess_docs(excluded_paths=["build"]) + log_message("Running Docker CREATE") + run_command("make html") # clean up workspace + os.chdir(SERVER_REPO_PATH) if "client" in repo_tags: subprocess.run(["rm", "-rf", "docs/client"], check=True) if "python_backend" in repo_tags: From 2114b51b5a1fd8cf1e4d60b491c50af55f5aae2e Mon Sep 17 00:00:00 2001 From: Yingge He Date: Mon, 25 Mar 2024 17:09:10 -0700 Subject: [PATCH 31/46] Revert contents.md --- docs/contents.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/contents.md b/docs/contents.md index 87241ca43d..8da94d07da 100644 --- a/docs/contents.md +++ b/docs/contents.md @@ -30,7 +30,6 @@ :maxdepth: 1 :caption: Getting Started -index getting_started/quickstart ``` From f4e77c0eb5ca9e0ae2444d60816e93e2b6dff480 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Mon, 25 Mar 2024 17:21:05 -0700 Subject: [PATCH 32/46] import exclude_patterns from conf.py --- docs/generate_docs.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index e150ade3d5..b5e803f4a1 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -7,11 +7,9 @@ from collections import defaultdict from functools import partial -# from docs.tests.test import run_test +from conf import exclude_patterns # global variables -exclude_patterns = ["README.md", "examples/README.md", "user_guide/perf_analyzer.md"] - SERVER_REPO_PATH = os.getcwd() SERVER_DOCS_DIR_PATH = os.path.join(os.getcwd(), "docs") From 3de3f522e228518575a572704d3698d741ba6235 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Tue, 26 Mar 2024 11:30:45 -0700 Subject: [PATCH 33/46] Improve readability. --- docs/generate_docs.py | 155 +++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 86 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index b5e803f4a1..94d5bcb45d 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -9,18 +9,20 @@ from conf import exclude_patterns -# global variables -SERVER_REPO_PATH = os.getcwd() -SERVER_DOCS_DIR_PATH = os.path.join(os.getcwd(), "docs") - -HTTP_REG = r"^https?://" -TAG_REG = "/(?:blob|tree)/main" -TRITON_REPO_REG = rf"{HTTP_REG}github.com/triton-inference-server" -TRITON_GITHUB_URL_REG = rf"{TRITON_REPO_REG}/([^/#]+)(?:{TAG_REG})?/*([^#]*)\s*(?=#|$)" -RELPATH_REG = r"]\s*\(\s*([^)]+)\)" -# regex pattern to find all references excluding embedded images in a .md file. -REFERENCE_REG = r"((?, e.g. ]+>. Whether we want to +def replace_hyperlink(m, src_doc_path): + # TODO: Markdown allows , e.g. ]+>. Whether we want to # find and replace the link depends on if they link to internal .md files # or allows relative paths. I haven't seen one such case in our doc so # should be safe for now. hyperlink_str = m.group(2) - match = re.match(HTTP_REG, hyperlink_str) + match = re.match(http_reg, hyperlink_str) if match: - # Hyperlink is a URL + # Hyperlink is a URL. res = replace_url_with_relpath(hyperlink_str, src_doc_path) else: - # Hyperlink is a relative path + # Hyperlink is a relative path. res = replace_relpath_with_url(hyperlink_str, src_doc_path) - # TODO: This needs improvement. One way is to replace m.group(2) only + # TODO: This can be improved. One way is to replace m.group(2) only. return m.group(1) + res + m.group(3) def preprocess_docs(excluded_paths=[]): - # find all ".md" files inside the current repo - - # treat server repo as special case - # if repo == "server": - # find . -type d \( -path ./build -o -path ./client -o -path ./python_backend \) -prune -o -type f -name "*.md" -print + # Find all ".md" files inside the current repo. cmd = ( ["find", ".", "-type", "d", "\\("] + " -o ".join([f"-path './{dir}'" for dir in excluded_paths]).split(" ") @@ -288,12 +273,9 @@ def preprocess_docs(excluded_paths=[]): ) cmd = " ".join(cmd) result = subprocess.run(cmd, check=True, capture_output=True, text=True, shell=True) - # else: - # cmd = ["find", ".", "-name", "*.md"] - # result = subprocess.run(cmd, check=True, capture_output=True, text=True) docs_list = list(filter(None, result.stdout.split("\n"))) - # Read, preprocess and write to each doc file + # Read, preprocess and write back to each document file. for doc_path in docs_list: if is_excluded(doc_path): continue @@ -304,8 +286,8 @@ def preprocess_docs(excluded_paths=[]): content = f.read() content = re.sub( - REFERENCE_REG, - partial(replace_reference, src_doc_path=doc_path), + hyperlink_reg, + partial(replace_hyperlink, src_doc_path=doc_path), content, ) @@ -321,9 +303,8 @@ def main(): print("Parsed repository tags:", repo_tags) print("Parsed repository tags:", backend_tags) - # docs_dir_name = "docs" - # Path - os.chdir(SERVER_DOCS_DIR_PATH) + # Change working directory to server/docs. + os.chdir(server_docs_dir_path) if "client" in repo_tags: clone_from_github("client", repo_tags["client"], github_org) @@ -332,19 +313,21 @@ def main(): if "custom_backend" in backend_tags: clone_from_github("custom_backend", backend_tags["custom_backend"], github_org) - # Preprocess after all repos are cloned - preprocess_docs(excluded_paths=["build"]) + # Preprocess documents in server_docs_dir_path after all repos are cloned. + preprocess_docs() log_message("Running Docker CREATE") run_command("make html") - # clean up workspace - os.chdir(SERVER_REPO_PATH) + # Clean up working directory. if "client" in repo_tags: - subprocess.run(["rm", "-rf", "docs/client"], check=True) + run_command("rm -rf client") if "python_backend" in repo_tags: - subprocess.run(["rm", "-rf", "docs/python_backend"], check=True) + run_command("rm -rf python_backend") if "custom_backend" in backend_tags: - subprocess.run(["rm", "-rf", "docs/custom_backend"], check=True) + run_command("rm -rf custom_backend") + + # Return to previous working directory server/. + os.chdir(server_repo_path) if __name__ == "__main__": From 4882bb324b15cbd95d8bba799ca9f915f00561ee Mon Sep 17 00:00:00 2001 From: Yingge He Date: Tue, 26 Mar 2024 11:51:54 -0700 Subject: [PATCH 34/46] Fix "find" command. --- docs/generate_docs.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index 94d5bcb45d..e5d549e587 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -264,34 +264,36 @@ def replace_hyperlink(m, src_doc_path): return m.group(1) + res + m.group(3) -def preprocess_docs(excluded_paths=[]): +def preprocess_docs(exclude_paths=[]): # Find all ".md" files inside the current repo. - cmd = ( - ["find", ".", "-type", "d", "\\("] - + " -o ".join([f"-path './{dir}'" for dir in excluded_paths]).split(" ") - + ["\\)", "-prune", "-o", "-type", "f", "-name", "'*.md'", "-print"] - ) + if exclude_paths: + cmd = ( + ["find", server_docs_dir_path, "-type", "d", "\\("] + + " -o ".join([f"-path './{dir}'" for dir in exclude_paths]).split(" ") + + ["\\)", "-prune", "-o", "-type", "f", "-name", "'*.md'", "-print"] + ) + else: + cmd = f"find {server_docs_dir_path} -name '.md'" cmd = " ".join(cmd) result = subprocess.run(cmd, check=True, capture_output=True, text=True, shell=True) docs_list = list(filter(None, result.stdout.split("\n"))) # Read, preprocess and write back to each document file. - for doc_path in docs_list: - if is_excluded(doc_path): + for doc_abspath in docs_list: + if is_excluded(doc_abspath): continue - doc_path = os.path.abspath(doc_path) content = None - with open(doc_path, "r") as f: + with open(doc_abspath, "r") as f: content = f.read() content = re.sub( hyperlink_reg, - partial(replace_hyperlink, src_doc_path=doc_path), + partial(replace_hyperlink, src_doc_path=doc_abspath), content, ) - with open(doc_path, "w") as f: + with open(doc_abspath, "w") as f: f.write(content) From 1905a3f849b763f50e74ce12179093acd013f3f4 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Tue, 26 Mar 2024 11:54:37 -0700 Subject: [PATCH 35/46] Fix --- docs/generate_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index e5d549e587..69adbbff06 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -273,7 +273,7 @@ def preprocess_docs(exclude_paths=[]): + ["\\)", "-prune", "-o", "-type", "f", "-name", "'*.md'", "-print"] ) else: - cmd = f"find {server_docs_dir_path} -name '.md'" + cmd = ["find", server_docs_dir_path, "-name", ".md"] cmd = " ".join(cmd) result = subprocess.run(cmd, check=True, capture_output=True, text=True, shell=True) docs_list = list(filter(None, result.stdout.split("\n"))) From ebb1eb02d8de54913f8367f40e4fcb7452175204 Mon Sep 17 00:00:00 2001 From: Indrajit Maloji Bhosale Date: Tue, 26 Mar 2024 13:02:42 -0700 Subject: [PATCH 36/46] PR Cleanup --- docs/generate_docs.py | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index 69adbbff06..32c0786728 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -34,37 +34,42 @@ def setup_logger(): + """ + This function is to setup logging + """ # Create a custom logger logger = logging.getLogger(__name__) - # Set the log level logger.setLevel(logging.INFO) - # Create handlers file_handler = logging.FileHandler("/tmp/docs.log") - # Create formatters and add it to the handlers formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) file_handler.setFormatter(formatter) - # Add handlers to the logger logger.addHandler(file_handler) - return logger def log_message(message): + """ + This function is for logging to /tmp + - message: Message to log + """ # Setup the logger logger = setup_logger() - # Log the message logger.info(message) def run_command(command): - print(command) + """ + This function runs any command using subprocess and logs failures + - command: Command to execute + """ + log_message(f"Running command: {command}") try: result = subprocess.run( command, @@ -74,7 +79,6 @@ def run_command(command): stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) - log_message(result.stdout) except subprocess.CalledProcessError as e: log_message(f"Error executing command: {e.cmd}") log_message(e.output) @@ -82,6 +86,12 @@ def run_command(command): def clone_from_github(repo, tag, org): + """ + This function clones from github, in-sync with build.py + - repo: Repo Name + - tag: Tag Name + - org: Org Name + """ # Construct the full GitHub repository URL repo_url = f"https://github.com/{org}/{repo}.git" print(repo_url) @@ -97,7 +107,6 @@ def clone_from_github(repo, tag, org): ] else: clone_command = ["git", "clone", repo_url] - # Execute the git clone command try: subprocess.run(clone_command, check=True) @@ -302,22 +311,25 @@ def main(): repo_tags = parse_repo_tag(args.repo_tag) if args.repo_tag else {} backend_tags = parse_repo_tag(args.backend) if args.backend else {} github_org = args.github_organization - print("Parsed repository tags:", repo_tags) - print("Parsed repository tags:", backend_tags) # Change working directory to server/docs. os.chdir(server_docs_dir_path) + # Usage generate_docs.py --repo-tag=client:main if "client" in repo_tags: clone_from_github("client", repo_tags["client"], github_org) + + # Usage generate_docs.py --repo-tag=python_backend:main if "python_backend" in repo_tags: clone_from_github("python_backend", repo_tags["python_backend"], github_org) + + # Usage generate_docs.py --backend-tag=custom_backend:main + # Custom backend can be anything currently empty if "custom_backend" in backend_tags: clone_from_github("custom_backend", backend_tags["custom_backend"], github_org) # Preprocess documents in server_docs_dir_path after all repos are cloned. preprocess_docs() - log_message("Running Docker CREATE") run_command("make html") # Clean up working directory. From aed88e4c6b34bdffdfbecaac06243a7b6a459389 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Tue, 26 Mar 2024 15:01:47 -0700 Subject: [PATCH 37/46] fix bug --- docs/generate_docs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index 69adbbff06..a72f74c2eb 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -273,7 +273,7 @@ def preprocess_docs(exclude_paths=[]): + ["\\)", "-prune", "-o", "-type", "f", "-name", "'*.md'", "-print"] ) else: - cmd = ["find", server_docs_dir_path, "-name", ".md"] + cmd = ["find", server_docs_dir_path, "-name", "'*.md'"] cmd = " ".join(cmd) result = subprocess.run(cmd, check=True, capture_output=True, text=True, shell=True) docs_list = list(filter(None, result.stdout.split("\n"))) @@ -317,7 +317,6 @@ def main(): # Preprocess documents in server_docs_dir_path after all repos are cloned. preprocess_docs() - log_message("Running Docker CREATE") run_command("make html") # Clean up working directory. From c28a22a2727b074982629ae55ec38ba2109c725d Mon Sep 17 00:00:00 2001 From: Yingge He Date: Tue, 26 Mar 2024 16:21:31 -0700 Subject: [PATCH 38/46] test --- docs/protocol/extension_model_configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/protocol/extension_model_configuration.md b/docs/protocol/extension_model_configuration.md index 04a2d28fac..4b462f5173 100644 --- a/docs/protocol/extension_model_configuration.md +++ b/docs/protocol/extension_model_configuration.md @@ -63,7 +63,7 @@ $model_configuration_response = The contents of the response will be the JSON representation of the model's configuration described by the [ModelConfig message from -model_config.proto](https://github.com/triton-inference-server/common/blob/main/protobuf/model_config.proto). +model_config.proto](#restricted-protocols). A failed model configuration request must be indicated by an HTTP error status (typically 400). The HTTP body must contain the @@ -115,4 +115,4 @@ message ModelConfigResponse ``` Where the ModelConfig message is defined in -[model_config.proto](https://github.com/triton-inference-server/common/blob/main/protobuf/model_config.proto). +[model_config.proto](../protocol#restricted-protocols). From e61a81a1fefd4aa9d9846e548ce83c219884765a Mon Sep 17 00:00:00 2001 From: Yingge He Date: Tue, 26 Mar 2024 17:28:15 -0700 Subject: [PATCH 39/46] Fix --- docs/generate_docs.py | 60 +++++++++++++------ .../protocol/extension_model_configuration.md | 4 +- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index a461611328..bb56996020 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -13,6 +13,7 @@ server_repo_path = os.getcwd() server_docs_dir_path = os.path.join(os.getcwd(), "docs") +# TODO: Branch is not always main. # Regex patterns http_reg = r"^https?://" tag_reg = "/(?:blob|tree)/main" @@ -160,9 +161,19 @@ def get_git_repo_name(file_path): def replace_url_with_relpath(url, src_doc_path): """ This function replaces Triton Inference Server GitHub URLs with relative paths in following cases. - 1. URL is a doc file not in exclude_patterns, e.g. ".md" file. - 2. URL is a directory which contains README.md and URL ends with a hashtag. - README.md is not in exclude_patterns. + 1. URL is a doc file, e.g. ".md" file. + 2. URL is a directory which contains README.md and URL ends with "#
". + + Examples: + https://github.com/triton-inference-server/server/blob/main/docs/protocol#restricted-protocols + https://github.com/triton-inference-server/server/blob/main/docs/protocol/extension_shared_memory.md + https://github.com/triton-inference-server/server/blob/main/docs/user_guide/model_configuration.md#dynamic-batcher + + Keep URL in the following cases: + https://github.com/triton-inference-server/server/tree/r24.02 + https://github.com/triton-inference-server/server/blob/main/build.py + https://github.com/triton-inference-server/server/blob/main/qa + https://github.com/triton-inference-server/server/blob/main/CONTRIBUTING.md """ m = re.match(triton_github_url_reg, url) # Do not replace URL if it is not a Triton GitHub file. @@ -208,14 +219,27 @@ def replace_url_with_relpath(url, src_doc_path): def replace_relpath_with_url(relpath, src_doc_path): """ - TODO: Need to update comment This function replaces relative paths with Triton Inference Server GitHub URLs in following cases. - 1. Relative path is pointing to a directory or file inside the same repo (excluding server). - 2. URL is a directory which contains README.md and URL has a hashtag. + 1. Relative path is a file that is not ".md" type inside the current repo. + 2. Relative path is a directory but not (has "README.md" and ends with "#
"). + 3. Relative path does not exist (shows 404 page). + + Examples: + ../examples/model_repository + ../examples/model_repository/inception_graphdef/config.pbtxt + + Keep relpath in the following cases: + build.md + build.md#building-with-docker + #building-with-docker + ../getting_started/quickstart.md + ../protocol#restricted-protocols """ target_path = relpath.rsplit("#")[0] section = relpath[len(target_path) :] - valid_hashtag = section not in ["", "#"] and section.startswith("#") + valid_hashtag = section not in ["", "#"] + if relpath.startswith("#"): + target_path = os.path.basename(src_doc_path) target_path = os.path.join(os.path.dirname(src_doc_path), target_path) target_path = os.path.normpath(target_path) src_git_repo_name = get_git_repo_name(src_doc_path) @@ -233,26 +257,26 @@ def replace_relpath_with_url(relpath, src_doc_path): target_path_from_src_repo = os.path.relpath(target_path, start=src_repo_abspath) - if os.path.exists(target_path) and ( + # For example, target_path of "../protocol#restricted-protocols" should be "/server/docs/protocol/README.md" + if ( os.path.isdir(target_path) and valid_hashtag - and not is_excluded(os.path.join(target_path, "README.md")) - or os.path.isfile(target_path) + and os.path.isfile(os.path.join(target_path, "README.md")) + ): + relpath = os.path.join(relpath.rsplit("#")[0], "README.md") + section + target_path = os.path.join(target_path, "README.md") + + if ( + os.path.isfile(target_path) and os.path.splitext(target_path)[1] == ".md" + and os.path.commonpath([server_docs_dir_path, target_path]) + == server_docs_dir_path and not is_excluded(target_path) ): return relpath else: return url + target_path_from_src_repo + section - # TODO: Compare which version is more concise - # if not os.path.exists(target_path) or \ - # os.path.isfile(target_path) and os.path.splitext(target_path)[1] != ".md" or \ - # os.path.isdir(target_path) and not valid_hashtag: - # return url + target_path_from_src_repo + section - # else: - # return relpath - def replace_hyperlink(m, src_doc_path): # TODO: Markdown allows , e.g. ]+>. Whether we want to diff --git a/docs/protocol/extension_model_configuration.md b/docs/protocol/extension_model_configuration.md index 4b462f5173..04a2d28fac 100644 --- a/docs/protocol/extension_model_configuration.md +++ b/docs/protocol/extension_model_configuration.md @@ -63,7 +63,7 @@ $model_configuration_response = The contents of the response will be the JSON representation of the model's configuration described by the [ModelConfig message from -model_config.proto](#restricted-protocols). +model_config.proto](https://github.com/triton-inference-server/common/blob/main/protobuf/model_config.proto). A failed model configuration request must be indicated by an HTTP error status (typically 400). The HTTP body must contain the @@ -115,4 +115,4 @@ message ModelConfigResponse ``` Where the ModelConfig message is defined in -[model_config.proto](../protocol#restricted-protocols). +[model_config.proto](https://github.com/triton-inference-server/common/blob/main/protobuf/model_config.proto). From 3791a8372159d2114a41b87b188519bf8b5b3bf7 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Wed, 3 Apr 2024 12:26:46 -0700 Subject: [PATCH 40/46] Remove unused module and variable. --- docs/generate_docs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index bb56996020..f9c88d5161 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -3,7 +3,6 @@ import os import re import subprocess -import sys from collections import defaultdict from functools import partial @@ -72,7 +71,7 @@ def run_command(command): """ log_message(f"Running command: {command}") try: - result = subprocess.run( + subprocess.run( command, shell=True, check=True, From 15742f6355c5ce502c2ec87f0a40cf63945e8d90 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Thu, 4 Apr 2024 08:27:15 -0700 Subject: [PATCH 41/46] Fix Sphinx warning. --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index bf5e8ce2e0..4715bba76d 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -183,7 +183,7 @@ def ultimateReplace(app, docname, source): # bibtex_default_style = "plain" ### We currently use Myst: https://myst-nb.readthedocs.io/en/latest/use/execute.html -jupyter_execute_notebooks = "off" # Global execution disable +nb_execution_mode = "off" # Global execution disable # execution_excludepatterns = ['tutorials/tts-python-basics.ipynb'] # Individual notebook disable From 3f5267d94145c90b233629db46a6f06fe49a44f6 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Thu, 4 Apr 2024 08:28:15 -0700 Subject: [PATCH 42/46] Use compiled regex to improve efficiency. --- docs/generate_docs.py | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index f9c88d5161..0ff8231034 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -12,15 +12,30 @@ server_repo_path = os.getcwd() server_docs_dir_path = os.path.join(os.getcwd(), "docs") -# TODO: Branch is not always main. +""" +TODO: Needs to handle cross-branch linkage. + +For example, server/docs/user_guide/architecture.md on branch 24.04 links to +server/docs/user_guide/model_analyzer.md on main branch. In this case, the +hyperlink of model_analyzer.md should be a URL instead of relative path. + +Another example can be server/docs/user_guide/model_analyzer.md on branch 24.04 +links to a file in server repo with relative path. Currently all URLs are +hardcoded to main branch. We need to make sure that the URL actually points to the +correct branch. We also need to handle cases like deprecated or removed files from +older branch to avoid 404 error code. +""" # Regex patterns -http_reg = r"^https?://" -tag_reg = "/(?:blob|tree)/main" -triton_repo_reg = rf"{http_reg}github.com/triton-inference-server" -triton_github_url_reg = rf"{triton_repo_reg}/([^/#]+)(?:{tag_reg})?/*([^#]*)\s*(?=#|$)" -relpath_reg = r"]\s*\(\s*([^)]+)\)" -# Hyperlink excluding embedded images in a .md file. -hyperlink_reg = r"((? Date: Thu, 4 Apr 2024 21:17:22 -0700 Subject: [PATCH 43/46] improve code --- docs/generate_docs.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index 0ff8231034..4ed1bb50e9 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -9,8 +9,8 @@ from conf import exclude_patterns # Global constants -server_repo_path = os.getcwd() -server_docs_dir_path = os.path.join(os.getcwd(), "docs") +server_abspath = os.environ("SERVER_ABSPATH") +server_docs_abspath = os.path.join(server_abspath, "docs") """ TODO: Needs to handle cross-branch linkage. @@ -200,14 +200,14 @@ def replace_url_with_relpath(url, src_doc_path): valid_hashtag = section not in ["", "#"] and section.startswith("#") if target_repo_name == "server": - target_path = os.path.join(server_repo_path, target_relpath_from_target_repo) + target_path = os.path.join(server_abspath, target_relpath_from_target_repo) else: target_path = os.path.join( - server_docs_dir_path, target_repo_name, target_relpath_from_target_repo + server_docs_abspath, target_repo_name, target_relpath_from_target_repo ) # Return URL if it points to a path outside server/docs. - if os.path.commonpath([server_docs_dir_path, target_path]) != server_docs_dir_path: + if os.path.commonpath([server_docs_abspath, target_path]) != server_docs_abspath: return url if ( @@ -260,11 +260,11 @@ def replace_relpath_with_url(relpath, src_doc_path): url = f"https://github.com/triton-inference-server/{src_git_repo_name}/blob/main/" if src_git_repo_name == "server": - src_repo_abspath = server_repo_path + src_repo_abspath = server_abspath # TODO: Assert the relative path not pointing to cloned repo, e.g. client. # This requires more information which may be stored in a global variable. else: - src_repo_abspath = os.path.join(server_docs_dir_path, src_git_repo_name) + src_repo_abspath = os.path.join(server_docs_abspath, src_git_repo_name) # Assert target path is under the current repo directory. assert os.path.commonpath([src_repo_abspath, target_path]) == src_repo_abspath @@ -283,8 +283,8 @@ def replace_relpath_with_url(relpath, src_doc_path): if ( os.path.isfile(target_path) and os.path.splitext(target_path)[1] == ".md" - and os.path.commonpath([server_docs_dir_path, target_path]) - == server_docs_dir_path + and os.path.commonpath([server_docs_abspath, target_path]) + == server_docs_abspath and not is_excluded(target_path) ): return relpath @@ -314,12 +314,12 @@ def preprocess_docs(exclude_paths=[]): # Find all ".md" files inside the current repo. if exclude_paths: cmd = ( - ["find", server_docs_dir_path, "-type", "d", "\\("] + ["find", server_docs_abspath, "-type", "d", "\\("] + " -o ".join([f"-path './{dir}'" for dir in exclude_paths]).split(" ") + ["\\)", "-prune", "-o", "-type", "f", "-name", "'*.md'", "-print"] ) else: - cmd = ["find", server_docs_dir_path, "-name", "'*.md'"] + cmd = ["find", server_docs_abspath, "-name", "'*.md'"] cmd = " ".join(cmd) result = subprocess.run(cmd, check=True, capture_output=True, text=True, shell=True) docs_list = list(filter(None, result.stdout.split("\n"))) @@ -349,7 +349,8 @@ def main(): github_org = args.github_organization # Change working directory to server/docs. - os.chdir(server_docs_dir_path) + os.chdir(server_docs_abspath) + run_command("make clean") # Usage generate_docs.py --repo-tag=client:main if "client" in repo_tags: @@ -364,7 +365,7 @@ def main(): if "custom_backend" in backend_tags: clone_from_github("custom_backend", backend_tags["custom_backend"], github_org) - # Preprocess documents in server_docs_dir_path after all repos are cloned. + # Preprocess documents in server_docs_abspath after all repos are cloned. preprocess_docs() run_command("make html") @@ -377,7 +378,7 @@ def main(): run_command("rm -rf custom_backend") # Return to previous working directory server/. - os.chdir(server_repo_path) + os.chdir(server_abspath) if __name__ == "__main__": From 5241bc833c91ef9f5d9ff168d1e4c6f92d2259f9 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Thu, 4 Apr 2024 21:37:53 -0700 Subject: [PATCH 44/46] Fix --- docs/generate_docs.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index 4ed1bb50e9..da291cae4f 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -9,7 +9,7 @@ from conf import exclude_patterns # Global constants -server_abspath = os.environ("SERVER_ABSPATH") +server_abspath = os.environ["SERVER_ABSPATH"] server_docs_abspath = os.path.join(server_abspath, "docs") """ @@ -293,10 +293,17 @@ def replace_relpath_with_url(relpath, src_doc_path): def replace_hyperlink(m, src_doc_path): - # TODO: Markdown allows , e.g. ]+>. Whether we want to - # find and replace the link depends on if they link to internal .md files - # or allows relative paths. I haven't seen one such case in our doc so - # should be safe for now. + """ + TODO: Support of HTML tags for future docs. + 1. Markdown allows , e.g. ]+>. Whether we want to + find and replace the link depends on if they link to internal .md files + or allows relative paths. I haven't seen one such case in our doc so + should be safe for now. + 2. Broken images have been found in the client repo src/grpc_generated/java/README.md. + Sphinx did not compile HTML image tags correctly. Reach out to @yinggeh for more detail. + Ex: + """ + hyperlink_str = m.group(2) match = http_reg.match(hyperlink_str) From 350147c73bb1951de2cfc00967597dbeb846d6d3 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Thu, 4 Apr 2024 22:58:36 -0700 Subject: [PATCH 45/46] improve code --- docs/generate_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generate_docs.py b/docs/generate_docs.py index da291cae4f..0efec5348a 100644 --- a/docs/generate_docs.py +++ b/docs/generate_docs.py @@ -9,7 +9,7 @@ from conf import exclude_patterns # Global constants -server_abspath = os.environ["SERVER_ABSPATH"] +server_abspath = os.environ.get("SERVER_ABSPATH", os.getcwd()) server_docs_abspath = os.path.join(server_abspath, "docs") """ From c73d5fb3dcc29db37770d7e7f3c37725b00264b9 Mon Sep 17 00:00:00 2001 From: Yingge He Date: Thu, 4 Apr 2024 23:05:10 -0700 Subject: [PATCH 46/46] update docs --- docs/contents.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/contents.md b/docs/contents.md index 8da94d07da..cc6a559c91 100644 --- a/docs/contents.md +++ b/docs/contents.md @@ -70,7 +70,7 @@ user_guide/faq :maxdepth: 1 :caption: Protocol Guides -protocol/README.md +protocol/README customization_guide/inference_protocols protocol/extension_binary_data protocol/extension_classification @@ -128,20 +128,21 @@ client/src/c++/perf_analyzer/docs/input_data client/src/c++/perf_analyzer/docs/measurements_metrics client/src/c++/perf_analyzer/docs/benchmarking client/src/c++/perf_analyzer/genai-perf/README +client/src/c++/perf_analyzer/genai-perf/examples/tutorial ``` ```{toctree} :maxdepth: 1 :caption: Python Backend -python_backend/README.md -python_backend/inferentia/README.md -python_backend/examples/auto_complete/README.md -python_backend/examples/bls/README.md -python_backend/examples/bls_decoupled/README.md -python_backend/examples/custom_metrics/README.md -python_backend/examples/decoupled/README.md -python_backend/examples/instance_kind/README.md -python_backend/examples/jax/README.md -python_backend/examples/preprocessing/README.md +python_backend/README +python_backend/inferentia/README +python_backend/examples/auto_complete/README +python_backend/examples/bls/README +python_backend/examples/bls_decoupled/README +python_backend/examples/custom_metrics/README +python_backend/examples/decoupled/README +python_backend/examples/instance_kind/README +python_backend/examples/jax/README +python_backend/examples/preprocessing/README ```