aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Code-formatting.md4
-rw-r--r--docs/markdown/snippets/clang-format.md4
-rw-r--r--mesonbuild/backend/ninjabackend.py10
-rw-r--r--mesonbuild/scripts/clangformat.py21
-rwxr-xr-xrun_unittests.py13
5 files changed, 40 insertions, 12 deletions
diff --git a/docs/markdown/Code-formatting.md b/docs/markdown/Code-formatting.md
index c8d83de..386c787 100644
--- a/docs/markdown/Code-formatting.md
+++ b/docs/markdown/Code-formatting.md
@@ -54,5 +54,5 @@ src/*.cpp
Note that `.clang-format-ignore` has the same format as used by
[`run-clang-format.py`](https://github.com/Sarcasm/run-clang-format).
-Modified files will be printed on the console which can be used for example by
-CI to ensure all files are correctly formatted.
+A new target `clang-format-check` has been added. It returns an error code if
+any file needs to be reformatted. This is intended to be used by CI.
diff --git a/docs/markdown/snippets/clang-format.md b/docs/markdown/snippets/clang-format.md
index 8cb88e0..a390d13 100644
--- a/docs/markdown/snippets/clang-format.md
+++ b/docs/markdown/snippets/clang-format.md
@@ -39,5 +39,5 @@ Example of `.clang-format-ignore` file:
src/*.cpp
```
-Modified files will be printed on the console which can be used for example by
-CI to ensure all files are correctly formatted.
+A new target `clang-format-check` has been added. It returns an error code if
+any file needs to be reformatted. This is intended to be used by CI.
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index b31339e..594e297 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -3042,8 +3042,12 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
# Alias that runs the target defined above
self.create_target_alias('meson-scan-build')
- def generate_clangtool(self, name):
+ def generate_clangtool(self, name, extra_arg=None):
target_name = 'clang-' + name
+ extra_args = []
+ if extra_arg:
+ target_name += f'-{extra_arg}'
+ extra_args.append(f'--{extra_arg}')
if not os.path.exists(os.path.join(self.environment.source_dir, '.clang-' + name)) and \
not os.path.exists(os.path.join(self.environment.source_dir, '_clang-' + name)):
return
@@ -3052,7 +3056,8 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
if ('', target_name) in self.build.run_target_names:
return
cmd = self.environment.get_build_command() + \
- ['--internal', 'clang' + name, self.environment.source_dir, self.environment.build_dir]
+ ['--internal', 'clang' + name, self.environment.source_dir, self.environment.build_dir] + \
+ extra_args
elem = NinjaBuildElement(self.all_outputs, 'meson-' + target_name, 'CUSTOM_COMMAND', 'PHONY')
elem.add_item('COMMAND', cmd)
elem.add_item('pool', 'console')
@@ -3063,6 +3068,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
if not environment.detect_clangformat():
return
self.generate_clangtool('format')
+ self.generate_clangtool('format', 'check')
def generate_clangtidy(self):
import shutil
diff --git a/mesonbuild/scripts/clangformat.py b/mesonbuild/scripts/clangformat.py
index 2cf757f..ceb36ac 100644
--- a/mesonbuild/scripts/clangformat.py
+++ b/mesonbuild/scripts/clangformat.py
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import argparse
import subprocess
import itertools
import fnmatch
@@ -34,15 +35,17 @@ def parse_pattern_file(fname: Path) -> T.List[str]:
pass
return patterns
-def run_clang_format(exelist: T.List[str], fname: Path) -> subprocess.CompletedProcess:
+def run_clang_format(exelist: T.List[str], fname: Path, check: bool) -> subprocess.CompletedProcess:
before = fname.stat().st_mtime
ret = subprocess.run(exelist + ['-style=file', '-i', str(fname)])
after = fname.stat().st_mtime
if before != after:
print('File reformatted: ', fname)
+ if check:
+ ret.returncode = 1
return ret
-def clangformat(exelist: T.List[str], srcdir: Path, builddir: Path) -> int:
+def clangformat(exelist: T.List[str], srcdir: Path, builddir: Path, check: bool) -> int:
patterns = parse_pattern_file(srcdir / '.clang-format-include')
if not patterns:
patterns = ['**/*']
@@ -61,17 +64,23 @@ def clangformat(exelist: T.List[str], srcdir: Path, builddir: Path) -> int:
if f.is_dir() or f.suffix not in suffixes or \
any(fnmatch.fnmatch(strf, i) for i in ignore):
continue
- futures.append(e.submit(run_clang_format, exelist, f))
+ futures.append(e.submit(run_clang_format, exelist, f, check))
returncode = max([x.result().returncode for x in futures])
return returncode
def run(args: T.List[str]) -> int:
- srcdir = Path(args[0])
- builddir = Path(args[1])
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--check', action='store_true')
+ parser.add_argument('sourcedir')
+ parser.add_argument('builddir')
+ options = parser.parse_args(args)
+
+ srcdir = Path(options.sourcedir)
+ builddir = Path(options.builddir)
exelist = detect_clangformat()
if not exelist:
print('Could not execute clang-format "%s"' % ' '.join(exelist))
return 1
- return clangformat(exelist, srcdir, builddir)
+ return clangformat(exelist, srcdir, builddir, options.check)
diff --git a/run_unittests.py b/run_unittests.py
index b95ead2..03e931a 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -5602,10 +5602,23 @@ class AllPlatformTests(BasePlatformTests):
shutil.copytree(testdir, newdir)
self.new_builddir()
self.init(newdir)
+
+ # Should reformat 1 file but not return error
output = self.build('clang-format')
self.assertEqual(1, output.count('File reformatted:'))
+
+ # Reset source tree then try again with clang-format-check, it should
+ # return an error code this time.
+ windows_proof_rmtree(newdir)
+ shutil.copytree(testdir, newdir)
+ with self.assertRaises(subprocess.CalledProcessError):
+ output = self.build('clang-format-check')
+ self.assertEqual(1, output.count('File reformatted:'))
+
+ # All code has been reformatted already, so it should be no-op now.
output = self.build('clang-format')
self.assertEqual(0, output.count('File reformatted:'))
+ self.build('clang-format-check')
class FailureTests(BasePlatformTests):