File size: 7,456 Bytes
af1ec53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
#!/usr/bin/env python3
"""
Script to automatically generate Sphinx documentation for all modules and build the HTML website.
"""
import importlib.util
import os
import subprocess
import sys


def check_and_install_dependencies():
    """Check for required dependencies and install them if missing."""
    required_packages = [
        "sphinx",
        "sphinx-rtd-theme",
        "sphinxcontrib-napoleon",
        "sphinxcontrib-mermaid",
        "sphinx-autodoc-typehints",
    ]

    missing_packages = []

    for package in required_packages:
        # Convert package name to module name (replace - with _)
        module_name = package.replace("-", "_")

        # Check if the package is installed
        if importlib.util.find_spec(module_name) is None:
            missing_packages.append(package)

    # Install missing packages
    if missing_packages:
        print(f"Installing missing dependencies: {', '.join(missing_packages)}")
        subprocess.check_call(
            [sys.executable, "-m", "pip", "install"] + missing_packages
        )
        print("Dependencies installed successfully")
    else:
        print("All required dependencies are already installed")


def create_makefile(docs_dir):
    """Create a Makefile for Sphinx documentation if it doesn't exist."""
    makefile_path = os.path.join(docs_dir, "Makefile")

    if os.path.exists(makefile_path):
        print(f"Makefile already exists at {makefile_path}")
        return

    print(f"Creating Makefile at {makefile_path}")

    makefile_content = """# Minimal makefile for Sphinx documentation

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS    ?=
SPHINXBUILD   ?= sphinx-build
SOURCEDIR     = source
BUILDDIR      = build

# Put it first so that "make" without argument is like "make help".
help:
	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(SPHINXFLAGS)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(SPHINXFLAGS)
"""

    with open(makefile_path, "w") as f:
        f.write(makefile_content)

    print("Makefile created successfully")


def create_make_bat(docs_dir):
    """Create a make.bat file for Windows if it doesn't exist."""
    make_bat_path = os.path.join(docs_dir, "make.bat")

    if os.path.exists(make_bat_path):
        print(f"make.bat already exists at {make_bat_path}")
        return

    print(f"Creating make.bat at {make_bat_path}")

    make_bat_content = """@ECHO OFF

pushd %~dp0

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
	set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
	echo.
	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
	echo.installed, then set the SPHINXBUILD environment variable to point
	echo.to the full path of the 'sphinx-build' executable. Alternatively you
	echo.may add the Sphinx directory to PATH.
	echo.
	echo.If you don't have Sphinx installed, grab it from
	echo.https://www.sphinx-doc.org/
	exit /b 1
)

if "%1" == "" goto help

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%

:end
popd
"""

    with open(make_bat_path, "w") as f:
        f.write(make_bat_content)

    print("make.bat created successfully")


def main():
    # Check and install required dependencies
    print("=== Checking dependencies ===")
    check_and_install_dependencies()

    # Get the directory of this script
    script_dir = os.path.dirname(os.path.abspath(__file__))

    # Path to the project root
    project_root = os.path.dirname(script_dir)

    # Path to the source directory
    source_dir = os.path.join(project_root, "src")

    # Path to the docs source directory
    docs_source_dir = os.path.join(script_dir, "source")

    # Print paths for debugging
    print(f"Script directory: {script_dir}")
    print(f"Project root: {project_root}")
    print(f"Source directory: {source_dir}")
    print(f"Docs source directory: {docs_source_dir}")

    # Make sure the source directory exists
    if not os.path.exists(source_dir):
        print(f"Error: Source directory {source_dir} does not exist!")
        sys.exit(1)

    # Make sure the docs source directory exists
    if not os.path.exists(docs_source_dir):
        print(f"Creating docs source directory: {docs_source_dir}")
        os.makedirs(docs_source_dir)

    # Step 1: Run sphinx-apidoc to generate .rst files for all modules
    print("\n=== Generating API documentation ===")
    cmd = [
        "sphinx-apidoc",
        "-f",  # Force overwriting of existing files
        "-e",  # Put module documentation before submodule documentation
        "-M",  # Put module documentation before subpackage documentation
        "-o",
        docs_source_dir,  # Output directory
        source_dir,  # Source code directory
    ]

    print(f"Running command: {' '.join(cmd)}")
    result = subprocess.run(cmd, capture_output=True, text=True)

    # Print the output of the command
    print("STDOUT:")
    print(result.stdout)

    print("STDERR:")
    print(result.stderr)

    if result.returncode != 0:
        print(f"Error: sphinx-apidoc failed with return code {result.returncode}")
        sys.exit(1)

    # List the files in the docs source directory
    print("\nFiles in docs/source directory:")
    for file in sorted(os.listdir(docs_source_dir)):
        print(f"  {file}")

    print("\nDocumentation source files generated successfully!")

    # Step 2: Create Makefile and make.bat if they don't exist
    create_makefile(script_dir)
    create_make_bat(script_dir)

    # Step 3: Build the HTML documentation
    print("\n=== Building HTML documentation ===")

    # Determine the build command based on the platform
    if os.name == "nt":  # Windows
        build_cmd = ["make.bat", "html"]
    else:  # Unix/Linux/Mac
        build_cmd = ["make", "html"]

    # Change to the docs directory to run the build command
    os.chdir(script_dir)

    print(f"Running command: {' '.join(build_cmd)}")
    build_result = subprocess.run(build_cmd, capture_output=True, text=True)

    # Print the output of the build command
    print("STDOUT:")
    print(build_result.stdout)

    print("STDERR:")
    print(build_result.stderr)

    if build_result.returncode != 0:
        print(f"Error: HTML build failed with return code {build_result.returncode}")
        sys.exit(1)

    # Get the path to the built HTML documentation
    html_dir = os.path.join(script_dir, "build", "html")
    index_path = os.path.join(html_dir, "index.html")

    if os.path.exists(index_path):
        print(f"\nHTML documentation built successfully!")
        print(f"You can view it by opening: {index_path}")

        # Try to open the documentation in a browser
        try:
            import webbrowser

            print("\nAttempting to open documentation in your default browser...")
            webbrowser.open(f"file://{index_path}")
        except Exception as e:
            print(f"Could not open browser automatically: {e}")
    else:
        print(f"\nWarning: HTML index file not found at {index_path}")


if __name__ == "__main__":
    main()