Skip to content

Commit

Permalink
Add scripts to check C++ examples in documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
rmisev committed Nov 2, 2023
1 parent 3d98fb9 commit 54684cf
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 4 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,20 @@ jobs:
UPA_DOCS_VERSION: ${{ github.ref_name }}
steps:
- uses: actions/checkout@v4

# Check C++ examples in documentation
- name: Extract and try to build C++ examples from docs
run: |
tools/extract-cpp.py examples/extracted-cpp README.md
cmake -S . -B build -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_STANDARD=20 -DURL_BUILD_TESTS=OFF -DURL_BUILD_EXTRACTED=ON
cmake --build build
# Run doxygen
- name: Download theme
run: doc/download-theme.sh
- uses: mattnotmitt/doxygen-action@edge

# Deploy docs
- name: Is there a gh-pages branch?
if: env.upa_deploy
run: echo "upa_checkout=$(git ls-remote --heads https://github.com/$upa_docs_repository.git refs/heads/gh-pages)" >> "$GITHUB_ENV"
Expand Down
14 changes: 10 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ if (NOT DEFINED URL_MAIN_PROJECT)
endif()

# Options
option(URL_BUILD_TESTS "Build the URL tests." ${URL_MAIN_PROJECT})
option(URL_BUILD_FUZZER "Build the URL fuzzer." OFF)
option(URL_BUILD_EXAMPLES "Build the URL examples." OFF)
option(URL_BUILD_TESTS "Build the Upa URL tests." ${URL_MAIN_PROJECT})
option(URL_BUILD_FUZZER "Build the Upa URL fuzzer." OFF)
option(URL_BUILD_EXAMPLES "Build the Upa URL examples." OFF)
option(URL_BUILD_EXTRACTED "Build Upa URL examples extracted from the docs." OFF)
option(URL_BUILD_TOOLS "Build tools." OFF)
option(URL_INSTALL "Generate the install target." ON)
# library options
Expand Down Expand Up @@ -99,7 +100,8 @@ endif()
include_directories(deps)

# Are Upa URL and ICU libraries needed?
if (URL_BUILD_TESTS OR URL_BUILD_FUZZER OR URL_BUILD_EXAMPLES OR URL_INSTALL OR NOT URL_BUILD_TOOLS)
if (URL_BUILD_TESTS OR URL_BUILD_FUZZER OR URL_BUILD_EXAMPLES OR URL_BUILD_EXTRACTED OR
URL_INSTALL OR NOT URL_BUILD_TOOLS)
# This library depends on ICU
find_package(ICU REQUIRED COMPONENTS i18n uc)

Expand Down Expand Up @@ -199,6 +201,10 @@ if (URL_BUILD_EXAMPLES)
target_link_libraries(urlparse ${upa_lib_target})
endif()

if (URL_BUILD_EXTRACTED)
add_subdirectory(examples/extracted-cpp)
endif()

# Tool's targets

if (URL_BUILD_TOOLS)
Expand Down
1 change: 1 addition & 0 deletions examples/extracted-cpp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.cpp
8 changes: 8 additions & 0 deletions examples/extracted-cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Examples to build
file(GLOB example_sources *.cpp)

foreach(source ${example_sources})
get_filename_component(exe_name ${source} NAME_WE)
add_executable(${exe_name} ${source})
target_link_libraries(${exe_name} PRIVATE upa::url)
endforeach()
100 changes: 100 additions & 0 deletions tools/extract-cpp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env python3
#
# Copyright 2023 Rimas Misevičius
# Distributed under the BSD-style license that can be
# found in the LICENSE file.
from enum import auto, Enum
import os
import sys

INDENT_TEXT = " "
COMMON_CPP_HEADER = """
#include \"upa/url.h\"
#include <iostream>
#include <string>
"""

def has_main(cpp_text):
return "int main(" in cpp_text

class CppExamples:
class State(Enum):
Outside = auto()
EnterCpp = auto()
InCpp = auto()
InCppSnipet = auto()

def __init__(self, out_path):
self._cpp_file_num = 0
self._cpp_example_num = 0
self._cpp_examples_text = COMMON_CPP_HEADER
self._out_path = out_path

def extract_cpp_from_md_file(self, md_path):
state = self.State.Outside.value
cpp_text = ""

# Open the MD file
print("Processing Markdown file:", md_path)
with open(md_path, "r") as file:
for line_nl in file:
# remove ending newline character
line = line_nl.rstrip()
if state == self.State.Outside.value:
if line == "```cpp":
state = self.State.EnterCpp.value;
cpp_text = ""
elif line == "```":
if state == self.State.InCpp.value:
if has_main(cpp_text):
self._cpp_file_num += 1
out_file_path = os.path.join(self._out_path, f"example-{self._cpp_file_num}.cpp")
print(" creating:", out_file_path)
with open(out_file_path, "w") as out_file:
out_file.write(f"// Example from: {md_path}\n")
out_file.write(cpp_text)
elif state == self.State.InCppSnipet.value:
self._cpp_example_num += 1
self._cpp_examples_text += f"\n// Example from: {md_path}\n"
self._cpp_examples_text += f"void example_{self._cpp_example_num}() {{\n"
self._cpp_examples_text += cpp_text
self._cpp_examples_text += "}\n"
state = self.State.Outside.value;
else:
if state == self.State.EnterCpp.value:
state = self.State.InCpp.value if line.startswith("#include") else self.State.InCppSnipet.value
if state == self.State.InCppSnipet.value:
cpp_text += INDENT_TEXT
cpp_text += line_nl

def output_common_cpp(self):
if self._cpp_example_num > 0:
# create main()
self._cpp_examples_text += "\nint main() {\n"
for num in range(1, self._cpp_example_num + 1):
self._cpp_examples_text += f"{INDENT_TEXT}example_{num}();\n"
self._cpp_examples_text += f"{INDENT_TEXT}return 0;\n"
self._cpp_examples_text += "}\n"
# save code
out_file_path = os.path.join(self._out_path, "examples.cpp")
print(" creating:", out_file_path)
with open(out_file_path, "w") as out_file:
out_file.write(self._cpp_examples_text)


if __name__ == "__main__":
# Command line arguments
if len(sys.argv) >= 3:
out_path = sys.argv[1]
md_files = sys.argv[2:]

print("Output directory:", out_path)
cpp_examples = CppExamples(out_path)
for md_path in md_files:
cpp_examples.extract_cpp_from_md_file(md_path)
cpp_examples.output_common_cpp()
else:
app_name = os.path.basename(os.path.basename(__file__))
print(f"Usage: {app_name} <output dir> <markdown file> ...",
file=sys.stderr)
sys.exit(1)

0 comments on commit 54684cf

Please sign in to comment.