Skip to content

Instantly share code, notes, and snippets.

@Jerakin
Last active April 29, 2021 22:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jerakin/b739dc9f2314816008a800361f00628a to your computer and use it in GitHub Desktop.
Save Jerakin/b739dc9f2314816008a800361f00628a to your computer and use it in GitHub Desktop.
Luacheck and Defold
return {
stds = {
defold = {
read_globals = {
"go", "gui", "msg", "url", "sys", "render", "factory", "particlefx", "physics", "sound", "sprite", "image",
"tilemap", "vmath", "matrix4", "vector3", "vector4", "quat", "hash", "hash_to_hex", "hashmd5", "pprint",
"iap", "facebook", "push", "http", "json", "spine", "zlib", "collectionfactory",
"__dm_script_instance__", "socket", "adtruth", "jit", "bit", "window", "webview", "profiler", "resource",
"collectionproxy", "label", "model", "timer", "zlib", "html5", "buffer", "crash", "bit32",
"RenderScriptConstantBuffer", "RenderScriptPredicate", "RenderScript", "GuiScript", "GuiScriptInstance"
},
globals = {"init", "final", "update", "on_input", "on_message", "on_reload"}
},
project = {
read_globals = {
"superstrict"
}
}
},
std = "_G+defold+project"
}

Instructions

https://github.com/mpeterv/luacheck http://luacheck.readthedocs.io/en/stable/index.html

Install luacheck on OSX

brew install lua51

sudo luarocks-5.1 install luacheck

Running luacheck

I run luacheck as a commit hook and only run it on files that are going to be committed so I provide a list of specific files. I also add a config file that have Defold globals defined.

luacheck project/main/my_file.lua project/main/my_other_file.script --config project/tool/luacheck/luacheck_std.luacheckrc

I use these additional flags

--no-unused-args I want allow not using all arguments

--no-color I don't want color because I have it hooked up to commithook and sourcetree doesn't support it

--no-max-line-length I don't care about the line length

--ignore 61. I don't care about whitespace errors

Commit hook example

The commit hook will run on commit and exit the commit if errors are found

  • Place pre-commit in your /.git/hooks folder (pro tip: Symlink in a hooks folder from somewhere else in your repository, to make sure people doesn't have to update the hooks scripts manually)
  • Place verify_lua.py relative to the pre-commit file, in the example below I assume it is in a subfolder called tests
#!/usr/bin/env python
import os
import sys
import tests.verify_lua
def main():
# Project root
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
status = tests.verify_lua.run_on_commit(root)
if not status:
sys.exit(1)
if __name__ == "__main__":
if not tests.utils.is_merging():
main()
import os
import re
import sys
import subprocess
import logging
import collections
ExecutionResult = collections.namedtuple(
"ExecutionResult",
"status, stdout, stderr"
)
def execute(cmd):
""" Executes specified command """
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout, stderr = process.communicate()
status = process.poll()
return ExecutionResult(status, stdout, stderr)
def _current_commit():
""" Returns the current commit. """
if execute("git rev-parse --verify HEAD".split()).status:
return "4b825dc642cb6eb9a060e54bf8d69288fbee4904" # Empty tree hash
else:
return "HEAD"
def echo_status(title, error_levels):
"""Used for reporting and logging errors"""
if error_levels:
logging.warning("\n{}".format(title))
for p in error_levels:
logging.warning("{}".format(p))
logging.warning("\n")
return False
return True
def get_list_of_committed_files():
""" Returns a list of files about to be commited. """
files = []
diff_index_cmd = "git diff-index --cached %s" % _current_commit()
output = subprocess.check_output(
diff_index_cmd.split()
)
for result in output.decode('utf-8').split("\n"):
if result != "":
result = result.split()
if result[4] in ["A", "M"]:
files.append(result[5])
return files
def luacheck_command(files):
"""The used luacheck command"""
command = ["luacheck"]
command.extend(files)
command.extend(
["--config", os.path.join(os.path.dirname(os.path.dirname(__file__)), "luainspect", "defold_std.luacheckrc")])
command.extend(["--ignore", "61."])
command.append("--no-unused-args")
command.append("--no-color")
command.append("--no-max-line-length")
return command
def is_lua_file(f):
"""There are more than one kind of lua file"""
if f.endswith(".lua") or f.endswith(".gui_script") or f.endswith(".script"):
return True
def clean_output(output):
"""The output we get from the luacheck command isn't in a format I like, so we clean it up"""
output = output.decode("utf-8")
clean = list()
lines = output.split("\n")
old = ""
for line in lines:
fix_line = line.replace("", "") # Remove odd whitespace character
if old.startswith("Checking") and not old.endswith("OK"): # Remove the extra new line after Checking line
old = "pass"
continue
if not line.startswith("Checking"):
a = re.search("(/.*?\.\w+)", line)
path = a.group(1) if a else None
fix_line = fix_line.replace(path, os.path.basename(path)) if path else fix_line
if fix_line and not (fix_line.endswith("OK") or fix_line.startswith("Total:")):
clean.append(fix_line)
old = line
return clean
def check_file(lua_files):
"""Check a single lua file"""
if lua_files:
cmd = luacheck_command(lua_files)
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
out, err = process.communicate()
return clean_output(out)
return []
def run_test(root, files):
error_levels = list()
lua_files = list()
for f in files:
file_path = os.path.join(root, f)
if is_lua_file(file_path):
lua_files.append(file_path)
error_levels.extend(check_file(lua_files))
echo_status("STATIC CODE ANALYSIS", error_levels)
return False if error_levels else True
def run_on_commit(root):
return run_test(root, get_list_of_committed_files())
if __name__ == '__main__':
if len(sys.argv) == 2:
run_on_commit(sys.argv[1])
else:
run_on_commit(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
@banool
Copy link

banool commented Apr 28, 2021

Just wanted to say that this was super helpful, thanks!

I found this flag also very helpful: --allow-defined. Otherwise it seems I have to define all my functions in the luacheck config.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment