diff --git a/.gitignore b/.gitignore index 4160b6eb..0c92be4c 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,11 @@ popochiu popochiu/** game game/** + +# Documentation ignores +docs/**/*.import +docs/**/scripting-reference/*.md +!docs/**/scripting-reference/index.md +Collector*.gd +ReferenceCollectorCLI*.gd +reference.json diff --git a/Dockerfile.DocsMaker b/Dockerfile.DocsMaker new file mode 100644 index 00000000..9949dcf1 --- /dev/null +++ b/Dockerfile.DocsMaker @@ -0,0 +1,46 @@ +FROM python:slim + +ARG GODOT_VERSION="4.1.3" +ARG GODOT_RELEASE_NAME="stable" +ARG GODOT_SUBDIR="" +ARG GODOT_PLATFORM="linux.x86_64" + +ARG GDM_COMMIT_SHA="07cb0d8f0af6da745260d7bfabfc475504c413f1" + +# Override user name at build. If build-arg is not passed, will create user named `host_user` +ARG DOCKER_USER=host_user +ARG DOCKER_USER_UID=1000 +ARG DOCKER_USER_GID=1000 + + +RUN addgroup --system --gid ${DOCKER_USER_GID} ${DOCKER_USER} \ + && adduser --system --uid ${DOCKER_USER_UID} --gid ${DOCKER_USER_GID} --home /home/${DOCKER_USER} ${DOCKER_USER} \ + # Ensure proper permissions on user's home directory + && chown -R ${DOCKER_USER}:${DOCKER_USER} /home/${DOCKER_USER} \ + # Install system-wide dependencies + && apt-get update && apt-get install -y --no-install-recommends unzip wget zip libfontconfig1 \ + && rm -rf /var/lib/apt/lists/* \ + # Install Godot from CDN + && wget -q https://downloads.tuxfamily.org/godotengine/${GODOT_VERSION}${GODOT_SUBDIR}/Godot_v${GODOT_VERSION}-${GODOT_RELEASE_NAME}_${GODOT_PLATFORM}.zip \ + && mkdir /home/${DOCKER_USER}/.cache \ + && mkdir -p /home/${DOCKER_USER}/.config/godot \ + && mkdir -p /home/${DOCKER_USER}/.local/share/godot/export_templates/${GODOT_VERSION}.${GODOT_RELEASE_NAME} \ + && unzip Godot_v${GODOT_VERSION}-${GODOT_RELEASE_NAME}_${GODOT_PLATFORM}.zip \ + && mv Godot_v${GODOT_VERSION}-${GODOT_RELEASE_NAME}_${GODOT_PLATFORM} /usr/local/bin/godot \ + && chmod a+x /usr/local/bin/godot \ + && rm -f Godot_v${GODOT_VERSION}-${GODOT_RELEASE_NAME}_${GODOT_PLATFORM}.zip \ + # Download gdscript-docs-maker source code + && wget https://github.com/GDQuest/gdscript-docs-maker/archive/${GDM_COMMIT_SHA}.zip -O gdscript-docs-maker.zip \ + && unzip gdscript-docs-maker.zip \ + && mv gdscript-docs-maker-${GDM_COMMIT_SHA} /app \ + && rm -f gdscript-docs-maker.zip + +WORKDIR /app + +COPY --chmod=777 generate_reference generate_reference + +# Install application dependencies +RUN python3 setup.py install + +# Run dockmaker script +ENTRYPOINT ["./generate_reference"] diff --git a/Dockerfile b/Dockerfile.MkDocs similarity index 100% rename from Dockerfile rename to Dockerfile.MkDocs diff --git a/Makefile b/Makefile index ecb08e68..4cba5639 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,31 @@ +CURRENT_UID := $(shell id -u):$(shell id -g) + all: up -up: +docs-up: docker compose pull docker compose up -d -down: +docs-down: docker compose down +gdm-build: + docker build \ + --no-cache \ + --build-arg="DOCKER_USER_UID=$(shell id -u)" \ + --build-arg="DOCKER_USER_GID=$(shell id -g)" \ + -t popochiu-docs-maker:latest \ + -f Dockerfile.DocsMaker . + +gdm-generate: + docker run --rm \ + -v .:/project \ + -v ./docs/content/the-engine-handbook/scripting-reference:/output \ + -u $(CURRENT_UID) \ + popochiu-docs-maker:latest /project \ + -o /output \ + -d addons/popochiu/engine/ + cli: docker compose run --rm documentation bash diff --git a/docker-compose.yml b/docker-compose.yml index 7192e413..6a8103c6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,5 +10,5 @@ services: - com.dnsdock.alias=docs.popochiu.local build: context: . - dockerfile: Dockerfile + dockerfile: Dockerfile.MkDocs command: serve -a 0.0.0.0:80 \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 95a651e3..a76b2634 100644 --- a/docs/README.md +++ b/docs/README.md @@ -34,7 +34,7 @@ Please remember to install Docker as well as the Compose plugin. Make is provided by the `build-essential` metapackage on Ubuntu and derivatives, while on Arch and derivatives you can install `base-devel`: -* **Ubuntu**: `sudo apt install build-essentials` +* **Ubuntu**: `sudo apt install build-essential` * **Arch**: `sudo pacman -Sy base-devel` That's it. You can go to the "Run the docs" section to learn how to run your dock. @@ -78,18 +78,38 @@ About Make, there are different ways to install it: To run the documentation, just enter the project's directory and issue this command: -> `make local-docs-up' +> `make docs-up' This will start the Docker container, and will bind port 286 of the host to the running instance of MkDocs in the container. To view the docs live in your browser, just visit [http://localhost:286](http://localhost:286). To stop the container service, just issue -> `make local-docs-down` +> `make docs-down` The documentation supports live reloading, so your browser will automatically update when you save a file you're working on, create a new file or folder. Please, read the contribution rules before pushing changes to Popochiu Documentation. +## How to export scripting reference to the local development environment + +Scripting reference is automatically exported by GitHub Actions when the doc is published to production. +Should you want to export the refs locally to preview your work on the docs, a make command is available for that. + +**IMPORTANT:** a preliminary step to export the scripting reference is to build the necessary docker image. For that, issue: + +> `make gdm-build` + +and wait for the build to end successfully. Once it's done you can issue: + +> `make gdm-generate` + +to export all of the engine API docs to markdown format. +The exported refereces will be available in `The Engine Handbook > Scripting Reference` section of the documentation. + +**NOTE**: There is no live-reload of the source code. If you change the docblocks in the engine's source files, you will have to manually export local refs again. + +**NOTE**: Locally generated exports are ignored by Git. + ## How to publish the documentation to production MkDocs is automatically triggered by GitHub automation so that new versions of the documentation are published whit every new release. diff --git a/docs/content/_assets/css/custom.css b/docs/content/_assets/css/custom.css index e820032a..00b8acd6 100644 --- a/docs/content/_assets/css/custom.css +++ b/docs/content/_assets/css/custom.css @@ -805,6 +805,10 @@ code, border: none; border-radius: 4px; } +.rst-content pre code { + color: inherit; + background-color: var(--code-background-color); +} .rst-content tt.literal, .rst-content code.literal { diff --git a/docs/content/_assets/js/custom.js b/docs/content/_assets/js/custom.js index f287084b..cb62c037 100644 --- a/docs/content/_assets/js/custom.js +++ b/docs/content/_assets/js/custom.js @@ -302,6 +302,9 @@ $(document).ready(() => { } } + // Activate Highlight.js syntax-highlighter + hljs.highlightAll(); + // Change indentation from spaces to tabs for codeblocks. const codeBlocks = document.querySelectorAll('.rst-content div[class^="highlight"] pre'); for (const codeBlock of codeBlocks) { diff --git a/docs/content/_assets/js/gdscript.min.js b/docs/content/_assets/js/gdscript.min.js new file mode 100644 index 00000000..3204130f --- /dev/null +++ b/docs/content/_assets/js/gdscript.min.js @@ -0,0 +1 @@ +hljs.registerLanguage("gdscript",function(){"use strict";var e=e||{};function r(e){return{aliases:["godot","gdscript"],keywords:{keyword:"and in not or self void as assert breakpoint class class_name extends is func setget signal tool yield const enum export onready static var break continue if elif else for pass return match while remote sync master puppet remotesync mastersync puppetsync",built_in:"Color8 ColorN abs acos asin atan atan2 bytes2var cartesian2polar ceil char clamp convert cos cosh db2linear decimals dectime deg2rad dict2inst ease exp floor fmod fposmod funcref get_stack hash inst2dict instance_from_id inverse_lerp is_equal_approx is_inf is_instance_valid is_nan is_zero_approx len lerp lerp_angle linear2db load log max min move_toward nearest_po2 ord parse_json polar2cartesian posmod pow preload print_stack push_error push_warning rad2deg rand_range rand_seed randf randi randomize range_lerp round seed sign sin sinh smoothstep sqrt step_decimals stepify str str2var tan tanh to_json type_exists typeof validate_json var2bytes var2str weakref wrapf wrapi bool int float String NodePath Vector2 Rect2 Transform2D Vector3 Rect3 Plane Quat Basis Transform Color RID Object NodePath Dictionary Array PoolByteArray PoolIntArray PoolRealArray PoolStringArray PoolVector2Array PoolVector3Array PoolColorArray",literal:"true false null"},contains:[e.NUMBER_MODE,e.HASH_COMMENT_MODE,{className:"comment",begin:/"""/,end:/"""/},e.QUOTE_STRING_MODE,{variants:[{className:"function",beginKeywords:"func"},{className:"class",beginKeywords:"class"}],end:/:/,contains:[e.UNDERSCORE_TITLE_MODE]}]}}return e.exports=function(e){e.registerLanguage("gdscript",r)},e.exports.definer=r,e.exports.definer||e.exports}()); \ No newline at end of file diff --git a/docs/content/the-engine-handbook/scripting-reference/index.md b/docs/content/the-engine-handbook/scripting-reference/index.md index 3a0de6fc..286a307e 100644 --- a/docs/content/the-engine-handbook/scripting-reference/index.md +++ b/docs/content/the-engine-handbook/scripting-reference/index.md @@ -2,4 +2,3 @@ weight: 3020 empty: true --- - diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 49da5095..7a0d9af1 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -1,7 +1,16 @@ site_name: Popochiu extra_css: - _assets/css/custom.css + - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/tomorrow-night-bright.min.css extra_javascript: + - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js + - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/markdown.min.js + - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/bash.min.js + - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/yaml.min.js + - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/json.min.js + - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/dockerfile.min.js + - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/makefile.min.js + - _assets/js/gdscript.min.js - _assets/js/custom.js markdown_extensions: - admonition diff --git a/generate_reference b/generate_reference new file mode 100755 index 00000000..b3b191af --- /dev/null +++ b/generate_reference @@ -0,0 +1,271 @@ +#!/usr/bin/env sh + +project_directory="$1" +output_directory="export" +directories_override="" +format="markdown" +author="developer" + +echo_help() { + cat <<'EOT' + Generate a code reference from GDScript + Usage: + generate_reference $project_directory [options] + + Required arguments: + + $project_directory -- path to your Godot project directory. + This directory or one of its subdirectories should contain a + project.godot file. + + Options: + + -h/--help -- Display this help message. + -o/--output-directory -- directory path to output the documentation into. + -d/--directory -- Name of a directory to find files and generate the code reference in the Godot project. + You can use the option multiple times to generate a reference for multiple directories. + -f/--format -- Either `markdown` or `hugo`. If `hugo`, the output document includes a TOML front-matter + at the top. Default: `markdown`. + -a/--author -- If --format is `hugo`, controls the author property in the TOML front-matter. + + + Usage example: + + generate_reference ~/Repositories/other/nakama-godot/project/ -o export-nakama -d addons + + This command walks files in the res://addons directory of the Godot Nakama project, and converts it + to markdown files output in ./export-nakama. +EOT + exit 0 +} + +get_godot_cmd() { + if command -v godot > /dev/null + then + echo godot + else + godotcmd="" + + if [ "$(echo $OSTYPE | head -c 6)" = "darwin" ] + then + godotcmd=$(find $(echo $PATH | tr ":" " ") -name "Godot*.app" -maxdepth 1 2>/dev/null | head -n 1 | tr -d '\n') + if [ "$(echo $godotcmd | tr -d '\n' | tail -c 4)" = ".app" ] + then + godotcmd="$godotcmd/Contents/MacOS/Godot" + fi + fi + + if [ "$godotcmd" = "" ] + then + if command -v zsh > /dev/null + then + godotcmd=$(zsh -c "whence -ap -m 'Godot*' | head -n 1") + elif command -v bash > /dev/null + then + godotcmd=$(bash -c "compgen -c Godot | head -n 1") + fi + fi + + if [ "$godotcmd" = "" ] + then + echo godot + else + echo $godotcmd + fi + fi +} + +is_gnu_sed(){ + sed --version >/dev/null 2>&1 +} + + +# Interpret arguments + +if [ $(echo $1 | head -c 1) != "-" ] +then + shift 1 +fi + +while getopts ':hodfa-:' OPTION; do + # Support of long options with this syntax: --format=hugo + if [ "$OPTION" = "-" ]; then + OPTION="${OPTARG%%=*}" + OPTARG="${OPTARG#$OPTION}" + OPTARG="${OPTARG#=}" + fi + + # Support of long options with this syntax: --format hugo + if [ "$OPTARG" = "" ] + then + OPTARG="$(eval echo \${$OPTIND})"; OPTIND=$(( $OPTIND + 1 )) + fi + if [ "$(echo $OPTARG | cut -c1)" = "-" ] + then + OPTARG="" + OPTIND=$(( $OPTIND - 1 )) + fi + + # Option processing + if [ "$OPTION" = "h" -o "$OPTION" = "help" ] + then + echo_help + elif [ "$OPTARG" = "" ] + then + echo "Missing value for option $OPTION. Try 'generate_reference --help' for more information" + exit 1 + else + case "$OPTION" in + o | output-directory) + output_directory="$OPTARG" + ;; + d | directory) + directories_override="$directories_override $OPTARG" + ;; + f | format) + format="$OPTARG" + ;; + a | author) + author="$OPTARG" + ;; + ?) + echo "Missing arguments. Try 'generate_reference --help' for more information" + exit 1 + ;; + esac + fi +done + +echo "Checking parameters" + +if test -z "$project_directory"; then + echo "Missing first parameter: project_directory." + exit 1 +fi + +if ! test -d "$project_directory"; then + echo "Directory $project_directory does not exist, exiting." + exit 1 +fi + +godot_project_file=$(find "$project_directory" -iname project.godot -print -quit) +if ! test -f "$godot_project_file"; then + echo "Could not find a project.godot file in $project_directory. This program needs a Godot project to work." + exit 1 +fi + + +ERROR_LOG=$(mktemp) +LOG=$(mktemp) +godot_project_dir=$(dirname "$godot_project_file") +godot=$(get_godot_cmd) + +$godot --version 2>"$ERROR_LOG" >/dev/null +test $? -eq 0 -o $? -eq 255 +godot_exec_ok=$? + +if [ $godot_exec_ok -eq 0 ] +then + version=$($godot --version | tail -n 1 | cut -c1-1) + + if [ "$version" = "3" ] + then + ref_collector="ReferenceCollectorCLI.gd" + path_collector="godot-scripts/Collector.gd" + path_ref_collector="godot-scripts/ReferenceCollectorCLI.gd" + else + ref_collector="ReferenceCollectorCLIGd4.gd" + path_collector="godot-scripts/CollectorGd4.gd" + path_ref_collector="godot-scripts/ReferenceCollectorCLIGd4.gd" + fi + + # Override the content of the directories variable in ReferenceCollectorCLI.gd if we got --directory arguments + file_ref_collector=$(mktemp) + cat $path_ref_collector > "$file_ref_collector" + if test "$directories_override" != ""; then + echo "Setting directories" + args=$(echo "$directories_override" | sed -r 's#([-/._a-zA-Z0-9]+)#"res://\1",#g' | sed -r 's/,$//') + + if is_gnu_sed + then + sed -ri "s#^var directories.+#var directories := [$args]#" "$file_ref_collector" + else + sed -i "" -r "s#^var directories.+#var directories := [$args]#" "$file_ref_collector" + fi + fi + + echo "Copying collectors to project directory" + + cp "$file_ref_collector" "$godot_project_dir/$(basename $path_ref_collector)" >/dev/null + cp $path_collector "$godot_project_dir" >/dev/null + + echo "Generating reference json data..." + + if [ "$version" = "3" ] + then + $godot --editor --quit --no-window --script $ref_collector \ + --path "$godot_project_dir" 2>"$ERROR_LOG" >"$LOG" + else + $godot --editor --quit --headless --script $ref_collector \ + --path "$godot_project_dir" 2>"$ERROR_LOG" >"$LOG" + fi + + godot_exec_ok=1 + if grep -q -F "Saved data to res://reference.json" "$LOG" >/dev/null 2>/dev/null + then + godot_exec_ok=0 + fi +fi + +if [ $godot_exec_ok -ne 0 ] +then + ERRORS=$(cat "$ERROR_LOG") + cat </dev/null +fi + +if ! python3 -m gdscript_docs_maker "$godot_project_dir/reference.json" --path "$output_directory" --format "$format" \ + --author "$author" 2>"$ERROR_LOG" +then + echo "Error running gdscript_docs_maker. This is the log:" + cat "$ERROR_LOG" + exit 1 +fi + +echo "Cleaning up..." +rm "$ERROR_LOG" >/dev/null +rm "$LOG" >/dev/null +rm "$godot_project_dir/$(basename $path_ref_collector)" >/dev/null +rm "$godot_project_dir/$(basename $path_collector)" >/dev/null +rm "$godot_project_dir/reference.json" >/dev/null + +exit 0 \ No newline at end of file