Skip to content
Snippets Groups Projects
Commit ae1cde4d authored by Andreas Traczyk's avatar Andreas Traczyk
Browse files

misc: format QML files using the python format script

+ Requires that the Qt path is supplied when calling build.py --init.
+ format.py now also takes a --qt argument to specify the Qt path, used to locate qmlformat.
+ format.py takes a --type argument to specify the type of files to format (qml, cpp, or both).

qmlformat is called with `--normalize` and `--force`.

Gitlab: #1059
Change-Id: Id9ff4b17018370696792b44f55ed2f4bc8091193
parent a8f48df4
No related branches found
No related tags found
No related merge requests found
......@@ -63,7 +63,7 @@ for getting the latest development versions; otherwise, you can use
submodule).
```bash
./build.py --init
./build.py --init [--qt=<path/to/qt> (this is required for qmlformatting to work)]
```
Then you will need to install dependencies:
......
......@@ -29,7 +29,7 @@ For more information about the jami project, see the following:
## Notes
- Coding style is managed by the clang-format, if you want to contribute, please use the pre-commit hook automatically installed with `./build.py --init`
- Coding style is managed by the clang-format and qmlformat, if you want to contribute, please use the pre-commit hook automatically installed with `./build.py --init --qt=<path/to/qt>`
- We use gerrit for our review. Please read about [working with Gerrit](https://docs.jami.net/developer/working-with-gerrit.html) if you want to submit patches.
## Build
......
......@@ -304,18 +304,37 @@ def run_dependencies(args):
sys.exit(1)
def run_init():
def run_init(args):
"""Initialize the git submodules and install the commit-msg hook."""
subprocess.run(["git", "submodule", "update", "--init"],
check=True)
hooks_directories = ['.git/hooks/', f'.git/modules/daemon/hooks']
for hooks_dir in hooks_directories:
client_hooks_dir = '.git/hooks'
daemon_hooks_dir = '.git/modules/daemon/hooks'
print("Installing commit-msg hooks...")
# Copy the commit-msg hook to all modules in the same way.
for hooks_dir in [client_hooks_dir, daemon_hooks_dir]:
if not os.path.exists(hooks_dir):
os.makedirs(hooks_dir)
copy_file("./extras/scripts/commit-msg",
os.path.join(hooks_dir, "commit-msg"))
execute_script(['./extras/scripts/format.py --install %(path)s'],
{"path": hooks_dir})
print("Installing pre-commit hooks...")
format_script = "./extras/scripts/format.py"
# Prepend with the python executable if on Windows (not WSL).
if sys.platform == 'win32':
format_script = f'python {format_script}'
# The client submodule has QML files, so we need to run qmlformat on it,
# and thus need to supply the Qt path.
execute_script([f'{format_script} --install {client_hooks_dir}'
f' --qt {args.qt}' if args.qt else ''],
{"path": client_hooks_dir})
# The daemon submodule has no QML files, so we don't need to run
# qmlformat on it, and thus don't need to supply the Qt path.
execute_script([f'{format_script} --install {daemon_hooks_dir}'],
{"path": daemon_hooks_dir})
def copy_file(src, dest):
......@@ -651,7 +670,8 @@ def main():
run_dependencies(parsed_args)
elif parsed_args.init:
run_init()
run_init(parsed_args)
elif parsed_args.clean:
run_clean()
......
#!/usr/bin/env python3
"""
Clang format C/C++ source files with clang-format.
Clang format C/C++ source files with clang-format (C/C++), and
qmlformat (QML) if installed.
Also optionally installs a pre-commit hook to run this script.
Usage:
......@@ -18,16 +19,34 @@ import sys
import subprocess
import argparse
import shutil
from platform import uname
CFVERSION = "9"
CLANGFORMAT = ""
QMLFORMAT = None
def command_exists(cmd):
""" Check if a command exists """
return shutil.which(cmd) is not None
def find_qmlformat(qt_path):
"""Find the path to the qmlformat binary."""
# Correct the path if it's a Windows WSL path.
is_windows = os.name == "nt"
if 'Microsoft' in uname().release:
qt_path = qt_path.replace('C:', '/mnt/c')
is_windows = True
# Check if qmlformat is in a subdirectory called bin.
qmlformat_path = os.path.join(qt_path, "bin", "qmlformat")
qmlformat_path += ".exe" if is_windows else ""
return qmlformat_path if os.path.exists(qmlformat_path) else None
def clang_format_file(filename):
""" Format a file using clang-format """
if os.path.isfile(filename):
......@@ -36,18 +55,35 @@ def clang_format_file(filename):
def clang_format_files(files):
""" Format a list of files """
if not files:
return
for filename in files:
print(f"Formatting: {filename}", end='\r')
clang_format_file(filename)
def qml_format_files(files):
""" Format a file using qmlformat """
if QMLFORMAT is None or not files:
return
for filename in files:
if os.path.isfile(filename):
print(f"Formatting: {filename}", end='\r')
extra_args = ['--normalize', '--force']
subprocess.call([QMLFORMAT, '--inplace', filename] + extra_args)
# This may generate a backup file (ending with ~), so delete it.
backup_file = filename + "~"
if os.path.isfile(backup_file):
os.remove(backup_file)
def exit_if_no_files():
""" Exit if no files to format """
print("No files to format")
sys.exit(0)
def install_hook(hooks_path):
def install_hook(hooks_path, qt_path=None):
""" Install a pre-commit hook to run this script """
if not os.path.isdir(hooks_path):
print(f"{hooks_path} path does not exist")
......@@ -55,7 +91,8 @@ def install_hook(hooks_path):
print(f"Installing pre-commit hook in {hooks_path}")
with open(os.path.join(hooks_path, "pre-commit"),
"w", encoding="utf-8") as file:
file.write(os.path.realpath(sys.argv[0]))
file.write(os.path.realpath(sys.argv[0])
+ f' --qt={qt_path}' if qt_path else '')
os.chmod(os.path.join(hooks_path, "pre-commit"), 0o755)
......@@ -86,7 +123,7 @@ def get_files(file_types, recursive=True, committed_only=False):
def main():
"""Check if clang-format is installed, and format files."""
"""Check for formatter installations, install hooks, and format files."""
global CLANGFORMAT # pylint: disable=global-statement
parser = argparse.ArgumentParser(
description="Format source filess with a clang-format")
......@@ -94,33 +131,50 @@ def main():
help="format all files instead of only committed ones")
parser.add_argument("-i", "--install", metavar="PATH",
help="install a pre-commit hook to run this script")
parser.add_argument("-q", "--qt", default=None,
help="The Qt root path")
# Add an option to only format a specific type (qml, cpp, or both)
parser.add_argument("-t", "--type", default="both",
help="The type of files to format (qml, cpp, or both)")
args = parser.parse_args()
if not command_exists("clang-format-" + CFVERSION):
if not command_exists("clang-format"):
print("Required version of clang-format not found")
sys.exit(1)
if args.type in ["cpp", "both"]:
if not command_exists("clang-format-" + CFVERSION):
if not command_exists("clang-format"):
print("Required version of clang-format not found")
sys.exit(1)
else:
CLANGFORMAT = "clang-format"
else:
CLANGFORMAT = "clang-format"
CLANGFORMAT = "clang-format-" + CFVERSION
print("Using source formatter: " + CLANGFORMAT)
if args.qt is not None and args.type in ["qml", "both"]:
global QMLFORMAT # pylint: disable=global-statement
QMLFORMAT = find_qmlformat(args.qt)
if QMLFORMAT is not None:
print("Using qmlformatter: " + QMLFORMAT)
else:
CLANGFORMAT = "clang-format-" + CFVERSION
print("No qmlformat found, can't format QML files")
if args.install:
install_hook(args.install)
install_hook(args.install, args.qt)
sys.exit(0)
if args.all:
print("Formatting all files...")
# Find all files in the recursively in the current directory.
clang_format_files(get_files((".cpp", ".cxx", ".cc", ".h", ".hpp"),
committed_only=False))
src_files = get_files([".cpp", ".cxx", ".cc", ".h", ".hpp"],
committed_only=not args.all)
qml_files = get_files([".qml"], committed_only=not args.all)
if not src_files and not qml_files:
exit_if_no_files()
else:
files = get_files((".cpp", ".cxx", ".cc", ".h", ".hpp"),
committed_only=True)
if not files:
exit_if_no_files()
print("Formatting committed source files...")
clang_format_files(files)
if src_files and args.type in ["cpp", "both"] and CLANGFORMAT:
print("Formatting source files...")
clang_format_files(src_files)
if qml_files and args.type in ["qml", "both"] and QMLFORMAT:
print("Formatting QML files...")
qml_format_files(qml_files)
if __name__ == "__main__":
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment