Est-ce que clang-format peut me dire si des changements de formatage sont nécessaires?

y a-t-il un moyen d'exécuter clang-format dans un mode où il déclare si le fichier répond au format spécifié? Une sorte de mode de dry-run où il signale si un changement est nécessaire, mais ne fait pas le changement. Idéalement, j'aimerais que clang-format renvoie juste un code de sortie non-zéro si le fichier a besoin de changements. Ou, encore plus idéalement, un code de sortie non nul et une liste des fichiers qui doivent être modifiés sur la sortie standard.

j'essaie de garder la question générique, pour que plus de gens peuvent répondre, mais ce que j'essaie de faire est d'écrire un crochet de pré-commit git qui rejettera toutes les commits qui ne correspondent pas aux attentes .clang-format . Il est facile de lancer clang-format sur la liste des fichiers de l'index. Mais il est difficile de savoir si clang-format a vraiment changé quelque chose.

j'ai une solution potentielle basée sur -output-replacements-xml (que je posterai comme réponse), mais c'est un piratage et je pense que cela devrait être plus simple. Commentaires/suggestions, modifications, différentes réponses / approches sont toutes les bienvenues.

46
demandé sur David Ogren 2014-04-04 19:13:45

6 réponses

L'une des raisons pour lesquelles je pense que cela devrait être plus facile que cela ne l'est parce que-output-replacements-xml me donne essentiellement la réponse que je veux, il ne me le donne tout simplement pas d'une manière facile à consommer. Cependant, puisque la sortie si aucun remplacement n'est nécessaire est très prévisible, l'analyse de la sortie n'est pas trop difficile.

ce que j'ai en ce moment est

clang-format -style=file -output-replacements-xml | grep -c "<replacement " >/dev/null

cela retourne en fait l'inverse du code de sortie que je veux, puisque grep retourne 0 si quelque chose correspond, 1 si rien ne correspond. Mais c'est assez facile à traiter.

donc le morceau pertinent de mon crochet de pré-commit git serait

git diff --cached --name-only --diff-filter=ACMRT |
  grep "\.[cmh]$" |
  xargs -n1 clang-format -style=file -output-replacements-xml |
  grep "<replacement " >/dev/null
if [ $? -ne 1 ]; then 
    echo "Commit did not match clang-format"
    exit 1
fi
  1. obtenir les noms complets des fichiers dans l'index (à l'exclusion des fichiers qui sont supprimés et d'autres cas inhabituels où je pourrais ne pas vouloir traiter le fichier)
  2. ne garder que les noms de fichiers des choses que je veux vérifier le formatage de (dans mon cas juste c, m, et h de fichiers)
  3. exécuter les résultats par xargs à essentiellement "pour chaque" la commande suivante
  4. Run clang-format avec l'option-output-replacements-xml sur tous les fichiers
  5. recherche de remplacement (par opposition aux remplacements) qui indique que clang-format a trouvé un remplacement qu'il veut faire. (Se débarrasser de toutes les sorties car le XML ne sera pas significatif pour l'utilisateur.)
  6. la dernière commande sort 1 (grep dit que nous n'avons rien trouvé) nous avons fait et les choses vont bien.
  7. si ce n'est pas le cas, afficher un message et sortir 1, qui annule la propagation. Malheureusement, nous n'avons pas un moyen facile de dire à l'utilisateur quel fichier était le problème, mais ils peuvent lancer clang-format eux-mêmes et voir.
32
répondu David Ogren 2018-06-15 08:13:08

Je ne suis pas entièrement sûr de ce que votre cas d'utilisation est, mais vérifier git-clang-format ( https://llvm.org/svn/llvm-project/cfe/trunk/tools/clang-format/git-clang-format ). Il fournit essentiellement un clang-format d'intégration pour git et peut-être que c'est ce que vous recherchez.

4
répondu djasper 2014-06-03 08:09:01

j'utilise git-clang-format et un script de validation de Mike Rhodes blog:

#!/bin/python

import subprocess
output = subprocess.check_output(["git", "clang-format", "--diff"])

if output not in ['no modified files to format\n', 'clang-format did not modify any files\n']:
    print "Run git clang-format, then commit.\n"
    exit(1)
else:
    exit(0)

le script a une petite erreur en ce qu'il ne fonctionne pas quand il n'y a pas de commits (en essayant de vérifier par rapport à la tête qui n'existe pas encore). Pour contourner cela, utilisez l'option -n ou --no-verify .

utiliser -n pour sauter le script de pré-propagation peut également être utile lorsque vous que pour contourner le contrôle, car il peut prendre beaucoup de temps pour une grande codebase.

Le post original est ici: http://www.dx13.co.uk/articles/2015/4/3/Setting-up-git-clang-format.html

1
répondu Daniel 2016-10-07 16:11:17

j'ai légèrement ajusté le commentaire DE phs dans ce post pour venir avec:

find embedded/ -regex '.*\.\(ino\|cpp\|hpp\|cc\|cxx\|h\)' -exec cat {} \; | diff -u <(find embedded/ -regex '.*\.\(ino\|cpp\|hpp\|cc\|cxx\|h\)' -exec clang-format-3.9 -style=file {} \;) -

c'est-à-dire..

  1. cat tous les fichiers et tuyaux cpp-ish qui à diff ( diff accepteront stdin parce que je spécifie - à la fin)
  2. utiliser la substitution de processus (la syntaxe <( .. ) ) pour exécuter clang-format sur ceux même les fichiers. N'utilisez pas le formatage en place ici. C'est l'autre moitié qui est envoyée à diff
  3. si diff sort sans sortie, succès! Vous pouvez également vérifier le code de sortie via $? -- il devrait être zéro.

j'ai mon service CI (travis) exécuter cette ligne dans un script bash pour s'assurer que les choses sont formatées correctement. J'ai un autre script pour exécuter le formatage en place. Cela me rappelle une avertissement: vous devez utiliser un shell qui peut traiter sub ( le shell posix ne ).

1
répondu Matt 2018-05-10 01:12:26

après que j'ai été inspiré par post de David Ogren j'ai fait un pre-commit crochet qui est capable de travailler sur les changements mis en scène. Cela permettra de s'assurer que le hook pre-commit fonctionne sur le code qui composera réellement le contenu de la propagation et ne peut pas être dupé par un clang-format qui n'a pas été mis en scène.

#!/bin/bash

files=()
for file in `git diff --cached --name-only --diff-filter=ACMRT | grep -E "\.(cpp|hpp)$"`; do
  if ! cmp -s <(git show :${file}) <(git show :${file}|clang-format); then
    files+=("${file}")
  fi
done

if [ -n "${files}" ]; then
echo Format error within the following files:
printf "%s\n" "${files[@]}"
exit 1
fi
0
répondu Martin 2017-08-29 21:41:57

run-clang-format est une enveloppe simple autour de clang-format conçu précisément pour être utilisé comme un crochet ou comme un script d'intégration continue.

L'exemple donné sur la page d'accueil parle de lui-même:

run-clang-format example

0
répondu Matthieu Moy 2018-06-15 09:15:51