Skip to content

Commit

Permalink
feat: Added Dockerfile and optimized Collector and generate_reference
Browse files Browse the repository at this point in the history
  • Loading branch information
dploeger committed Jun 18, 2021
1 parent fa5b381 commit 5185afd
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 118 deletions.
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM barichello/godot-ci:latest


COPY . /app

RUN apt update && apt -y install python3 python3-setuptools

WORKDIR /app

RUN python3 setup.py install

ENTRYPOINT ["./generate_reference"]
88 changes: 64 additions & 24 deletions generate_reference
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ format="markdown"
author="developer"

echo_help() {
echo '
cat <<'EOT'
Generate a code reference from GDScript
Usage:
generate_reference $project_directory [options]
Expand All @@ -22,8 +22,10 @@ echo_help() {
-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`.
-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.
Expand All @@ -33,16 +35,19 @@ echo_help() {
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
}

# Interpret arguments

arguments=$(getopt --name "generate_reference" -o "h,o:,d:,f:,a:" -l "help,output-directory:,directories:" -- "$@")

eval set -- "$arguments"
while true; do
case "$1" in
-h | --help)
echo_help
echo_help
shift
;;
-o | --output-directory)
Expand All @@ -61,7 +66,6 @@ while true; do
author=$2
shift 2
;;

--)
shift
break
Expand All @@ -73,7 +77,8 @@ while true; do
esac
done

# Testing input parameters
echo "Checking parameters"

if test -z "$project_directory"; then
echo "Missing first parameter: project_directory."
exit 1
Expand All @@ -90,40 +95,75 @@ if ! test -f "$godot_project_file"; then
exit 1
fi

# Generate reference JSON data from Godot


godot_project_dir=$(dirname "$godot_project_file")

path_ref_collector="godot-scripts/ReferenceCollectorCLI.gd"
path_collector="godot-scripts/Collector.gd"

# Overrides the content of the directories variable in ReferenceCollectorCLI.gd if we got --directory arguments
# 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
cat $path_ref_collector > "$file_ref_collector"
if test "$directories_override" != ""; then
args=$(echo $directories_override | sed -r 's/([-._a-zA-Z0-9]+)/"\1",/g' | sed -r 's/,$//')
sed -ri "s/^var directories.+/var directories := [$args]/" $file_ref_collector
echo "Setting directories"
args=$(echo "$directories_override" | sed -r 's#([-/._a-zA-Z0-9]+)#"res://\1",#g' | sed -r 's/,$//')
sed -ri "s#^var directories.+#var directories := [$args]#" "$file_ref_collector"
fi

cp -v $file_ref_collector "$godot_project_dir/$(basename $path_ref_collector)"
cp -v $path_collector "$godot_project_dir"
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..."
godot --editor --quit --script --no-window --path "$godot_project_dir" ReferenceCollectorCLI.gd >/dev/null
test $? -gt 0 && echo "There was an error running 'godot'.

ERROR_LOG=$(mktemp)

if ! godot --editor --quit --no-window --script ReferenceCollectorCLI.gd \
--path "$godot_project_dir" 2>"$ERROR_LOG" >/dev/null
then
ERRORS=$(cat "$ERROR_LOG")
cat <<EOT
There was an error running 'godot'.
The program 'godot' must be available on the system '\$PATH' variable for this program to work.
For more information, see https://en.wikipedia.org/wiki/PATH_(variable).
Exiting." && exit 1
This was the error log:
$ERRORS
EOT
rm "$ERROR_LOG"
exit 1
fi

echo "Done."

if ! test -f "$godot_project_dir/reference.json"; then
if ! [ -f "$godot_project_dir/reference.json" ]
then
echo "There was an error generating the reference from Godot. The file $godot_project_dir/reference.json was not found."
exit 1
fi

rm -v "$godot_project_dir/$(basename $path_ref_collector)"
rm -v "$godot_project_dir/$(basename $path_collector)"

# Generate markdown files
echo "Generating markdown files in $output_directory"
! test -d "$output_directory" && mkdir -v "$output_directory"

python3 -m gdscript_docs_maker "$godot_project_dir/reference.json" --path $output_directory --format $format --author $author
if [ ! -d "$output_directory" ]
then
mkdir -v "$output_directory" >/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 "$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
191 changes: 97 additions & 94 deletions godot-scripts/Collector.gd
Original file line number Diff line number Diff line change
@@ -1,95 +1,98 @@
tool
extends SceneTree
# Finds and generates a code reference from gdscript files.


# Returns a list of file paths found in the directory.
#
# **Arguments**
#
# - dirpath: path to the directory from which to search files.
# - patterns: an array of string match patterns, where "*" matches zero or more
# arbitrary characters and "?" matches any single character except a period
# ("."). You can use it to find files by extensions. To find only GDScript
# files, ["*.gd"]
# - is_recursive: if `true`, walks over subdirectories recursively, returning all
# files in the tree.
func find_files(
dirpath := "", patterns := PoolStringArray(), is_recursive := false, do_skip_hidden := true
) -> PoolStringArray:
var file_paths := PoolStringArray()
var directory := Directory.new()

if not directory.dir_exists(dirpath):
printerr("The directory does not exist: %s" % dirpath)
return file_paths
if not directory.open(dirpath) == OK:
printerr("Could not open the following dirpath: %s" % dirpath)
return file_paths

directory.list_dir_begin(true, do_skip_hidden)
var file_name := directory.get_next()
var subdirectories := PoolStringArray()
while file_name != "":
if directory.current_is_dir() and is_recursive:
var subdirectory := dirpath.plus_file(file_name)
file_paths.append_array(find_files(subdirectory, patterns, is_recursive))
else:
for pattern in patterns:
if file_name.match(pattern):
file_paths.append(dirpath.plus_file(file_name))
file_name = directory.get_next()

directory.list_dir_end()
return file_paths


# Saves text to a file.
func save_text(path := "", content := "") -> void:
var dirpath := path.get_base_dir()
var basename := path.get_file()
if not dirpath:
printerr("Couldn't save: the path %s is invalid." % path)
return
if not basename.is_valid_filename():
printerr("Couldn't save: the file name, %s, contains invalid characters." % basename)
return

var directory := Directory.new()
if not directory.dir_exists(dirpath):
directory.make_dir(dirpath)

var file := File.new()

file.open(path, File.WRITE)
file.store_string(content)
file.close()
print("Saved data to %s" % path)


# Parses a list of GDScript files and returns a list of dictionaries with the
# code reference data.
#
# If `refresh_cache` is true, will refresh Godot's cache and get fresh symbols.
func get_reference(files := PoolStringArray(), refresh_cache := false) -> Dictionary:
var data := {
name = ProjectSettings.get_setting("application/config/name"),
description = ProjectSettings.get_setting("application/config/description"),
version = ProjectSettings.get_setting("application/config/version"),
classes = []
}
var workspace = Engine.get_singleton('GDScriptLanguageProtocol').get_workspace()
for file in files:
if not file.ends_with(".gd"):
continue
if refresh_cache:
workspace.parse_local_script(file)
var symbols: Dictionary = workspace.generate_script_api(file)
if symbols["name"] == "":
tool
extends SceneTree
# Finds and generates a code reference from gdscript files.


# Returns a list of file paths found in the directory.
#
# **Arguments**
#
# - dirpath: path to the directory from which to search files.
# - patterns: an array of string match patterns, where "*" matches zero or more
# arbitrary characters and "?" matches any single character except a period
# ("."). You can use it to find files by extensions. To find only GDScript
# files, ["*.gd"]
# - is_recursive: if `true`, walks over subdirectories recursively, returning all
# files in the tree.
func find_files(
dirpath := "", patterns := PoolStringArray(), is_recursive := false, do_skip_hidden := true
) -> PoolStringArray:
var file_paths := PoolStringArray()
var directory := Directory.new()

if not directory.dir_exists(dirpath):
printerr("The directory does not exist: %s" % dirpath)
return file_paths
if not directory.open(dirpath) == OK:
printerr("Could not open the following dirpath: %s" % dirpath)
return file_paths

directory.list_dir_begin(true, do_skip_hidden)
var file_name := directory.get_next()
var subdirectories := PoolStringArray()
while file_name != "":
if directory.current_is_dir() and is_recursive:
var subdirectory := dirpath.plus_file(file_name)
file_paths.append_array(find_files(subdirectory, patterns, is_recursive))
else:
for pattern in patterns:
if file_name.match(pattern):
file_paths.append(dirpath.plus_file(file_name))
file_name = directory.get_next()

directory.list_dir_end()
return file_paths


# Saves text to a file.
func save_text(path := "", content := "") -> void:
var dirpath := path.get_base_dir()
var basename := path.get_file()
if not dirpath:
printerr("Couldn't save: the path %s is invalid." % path)
return
if not basename.is_valid_filename():
printerr("Couldn't save: the file name, %s, contains invalid characters." % basename)
return

var directory := Directory.new()
if not directory.dir_exists(dirpath):
directory.make_dir(dirpath)

var file := File.new()

file.open(path, File.WRITE)
file.store_string(content)
file.close()
print("Saved data to %s" % path)


# Parses a list of GDScript files and returns a list of dictionaries with the
# code reference data.
#
# If `refresh_cache` is true, will refresh Godot's cache and get fresh symbols.
func get_reference(files := PoolStringArray(), refresh_cache := false) -> Dictionary:
var version := "n/a"
if ProjectSettings.has_setting("application/config/version"):
version = ProjectSettings.get_setting("application/config/version")
var data := {
name = ProjectSettings.get_setting("application/config/name"),
description = ProjectSettings.get_setting("application/config/description"),
version = version,
classes = []
}
var workspace = Engine.get_singleton('GDScriptLanguageProtocol').get_workspace()
for file in files:
if not file.ends_with(".gd"):
continue
if refresh_cache:
workspace.parse_local_script(file)
var symbols: Dictionary = workspace.generate_script_api(file)
if symbols.has("name") and symbols["name"] == "":
symbols["name"] = file.get_file()
data["classes"].append(symbols)
return data


func print_pretty_json(reference: Dictionary) -> String:
return JSON.print(reference, " ")
data["classes"].append(symbols)
return data


func print_pretty_json(reference: Dictionary) -> String:
return JSON.print(reference, " ")

0 comments on commit 5185afd

Please sign in to comment.