1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-03-28 14:56:19 +01:00

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
This commit is contained in:
Andreas Traczyk 2023-04-05 13:34:31 -04:00
parent a8f48df4f9
commit ae1cde4dc1
4 changed files with 104 additions and 30 deletions

View file

@ -63,7 +63,7 @@ for getting the latest development versions; otherwise, you can use
submodule). submodule).
```bash ```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: Then you will need to install dependencies:

View file

@ -29,7 +29,7 @@ For more information about the jami project, see the following:
## Notes ## 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. - 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 ## Build

View file

@ -304,18 +304,37 @@ def run_dependencies(args):
sys.exit(1) 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"], subprocess.run(["git", "submodule", "update", "--init"],
check=True) check=True)
hooks_directories = ['.git/hooks/', f'.git/modules/daemon/hooks'] client_hooks_dir = '.git/hooks'
for hooks_dir in hooks_directories: 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): if not os.path.exists(hooks_dir):
os.makedirs(hooks_dir) os.makedirs(hooks_dir)
copy_file("./extras/scripts/commit-msg", copy_file("./extras/scripts/commit-msg",
os.path.join(hooks_dir, "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): def copy_file(src, dest):
@ -651,7 +670,8 @@ def main():
run_dependencies(parsed_args) run_dependencies(parsed_args)
elif parsed_args.init: elif parsed_args.init:
run_init() run_init(parsed_args)
elif parsed_args.clean: elif parsed_args.clean:
run_clean() run_clean()

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python3 #!/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. Also optionally installs a pre-commit hook to run this script.
Usage: Usage:
@ -18,16 +19,34 @@ import sys
import subprocess import subprocess
import argparse import argparse
import shutil import shutil
from platform import uname
CFVERSION = "9" CFVERSION = "9"
CLANGFORMAT = "" CLANGFORMAT = ""
QMLFORMAT = None
def command_exists(cmd): def command_exists(cmd):
""" Check if a command exists """ """ Check if a command exists """
return shutil.which(cmd) is not None 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): def clang_format_file(filename):
""" Format a file using clang-format """ """ Format a file using clang-format """
if os.path.isfile(filename): if os.path.isfile(filename):
@ -36,18 +55,35 @@ def clang_format_file(filename):
def clang_format_files(files): def clang_format_files(files):
""" Format a list of files """ """ Format a list of files """
if not files:
return
for filename in files: for filename in files:
print(f"Formatting: {filename}", end='\r') print(f"Formatting: {filename}", end='\r')
clang_format_file(filename) 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(): def exit_if_no_files():
""" Exit if no files to format """ """ Exit if no files to format """
print("No files to format") print("No files to format")
sys.exit(0) 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 """ """ Install a pre-commit hook to run this script """
if not os.path.isdir(hooks_path): if not os.path.isdir(hooks_path):
print(f"{hooks_path} path does not exist") 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}") print(f"Installing pre-commit hook in {hooks_path}")
with open(os.path.join(hooks_path, "pre-commit"), with open(os.path.join(hooks_path, "pre-commit"),
"w", encoding="utf-8") as file: "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) 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(): 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 global CLANGFORMAT # pylint: disable=global-statement
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Format source filess with a clang-format") description="Format source filess with a clang-format")
@ -94,33 +131,50 @@ def main():
help="format all files instead of only committed ones") help="format all files instead of only committed ones")
parser.add_argument("-i", "--install", metavar="PATH", parser.add_argument("-i", "--install", metavar="PATH",
help="install a pre-commit hook to run this script") 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() args = parser.parse_args()
if not command_exists("clang-format-" + CFVERSION): if args.type in ["cpp", "both"]:
if not command_exists("clang-format"): if not command_exists("clang-format-" + CFVERSION):
print("Required version of clang-format not found") if not command_exists("clang-format"):
sys.exit(1) print("Required version of clang-format not found")
sys.exit(1)
else:
CLANGFORMAT = "clang-format"
else: 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: else:
CLANGFORMAT = "clang-format-" + CFVERSION print("No qmlformat found, can't format QML files")
if args.install: if args.install:
install_hook(args.install) install_hook(args.install, args.qt)
sys.exit(0) sys.exit(0)
if args.all: src_files = get_files([".cpp", ".cxx", ".cc", ".h", ".hpp"],
print("Formatting all files...") committed_only=not args.all)
# Find all files in the recursively in the current directory. qml_files = get_files([".qml"], committed_only=not args.all)
clang_format_files(get_files((".cpp", ".cxx", ".cc", ".h", ".hpp"),
committed_only=False)) if not src_files and not qml_files:
exit_if_no_files()
else: else:
files = get_files((".cpp", ".cxx", ".cc", ".h", ".hpp"), if src_files and args.type in ["cpp", "both"] and CLANGFORMAT:
committed_only=True) print("Formatting source files...")
if not files: clang_format_files(src_files)
exit_if_no_files() if qml_files and args.type in ["qml", "both"] and QMLFORMAT:
print("Formatting committed source files...") print("Formatting QML files...")
clang_format_files(files) qml_format_files(qml_files)
if __name__ == "__main__": if __name__ == "__main__":