web-dev-qa-db-fra.com

Le format peut-il m'indiquer si des modifications de formatage sont nécessaires?

Existe-t-il un moyen d'exécuter clang-format dans un mode dans lequel il indique si le fichier respecte le format spécifié? Une sorte de mode de fonctionnement à sec où il signale si un changement est nécessaire, mais ne le fait pas. Idéalement, j'aimerais que le format Clang renvoie simplement un code de sortie non nul si le fichier nécessite des modifications. Ou, encore plus idéalement, un code de sortie non nul et une liste des fichiers qui nécessitent des modifications sur la sortie standard.

J'essaie de garder la question générique, afin que davantage de personnes puissent répondre, mais ce que j'essaie de faire, c'est d'écrire un hook git de pré-validation qui rejettera toute validation qui ne correspond pas au format .clang attendu. Il est facile d’exécuter le format clang dans la liste des fichiers de l’index. Mais il est difficile de savoir si le format Clang a réellement changé quelque chose. 

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

55
David Ogren

Une des raisons pour lesquelles je pense que cela devrait être plus facile que cela parce que -output-remplacements-xml me donne essentiellement la réponse que je veux, mais ne me la donne pas de manière facile à consommer. Cependant, étant donné que 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 maintenant c'est 

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

Cela renvoie en fait l'inverse du code de sortie que je veux, puisque grep renvoie 0 si quelque chose correspond, 1 si rien ne correspond. Mais c'est assez facile à gérer.

Donc, le bit pertinent de mon crochet git pré-commit 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 de fichiers complets des fichiers de l'index (à l'exclusion des fichiers en cours de suppression et des autres cas inhabituels où je ne souhaite peut-être pas traiter le fichier)
  2. Ne conservez que les noms de fichiers des éléments dont je souhaite vérifier le formatage (dans mon cas, seuls les fichiers c, m et h)
  3. Exécuter les résultats via xargs pour essentiellement "pour chaque" la prochaine commande
  4. Exécuter le format clang avec l'option -output-replacements-xml sur tous les fichiers
  5. Recherche de remplacement (par opposition aux remplacements) qui indique que le format clang a trouvé le remplacement qu’il souhaite remplacer. (Supprimer toutes les sorties car le XML ne sera pas significatif pour l'utilisateur.)
  6. La dernière commande quitte 1 (grep dit que nous n'avons rien trouvé), nous avons terminé et tout va bien.
  7. Sinon, affiche un message et quitte 1, ce qui annule la validation. Malheureusement, nous ne disposons pas d'un moyen facile de dire à l'utilisateur quel fichier pose problème, mais ils peuvent utiliser le format Clang eux-mêmes et voir.
35
David Ogren

Je ne suis pas tout à fait sûr de votre cas d'utilisation, mais consultez le format git-clang ( https://llvm.org/svn/llvm-project/cfe/trunk/tools/clang-format/git-clang- format ). Il fournit essentiellement une intégration au format clang pour git et c’est peut-être ce que vous recherchez.

4
djasper

J'ai légèrement ajusté le commentaire de phs dans cet article pour arriver à:

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..

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

J'ai mon service de CI (Travis) exécuter cette ligne dans un script bash pour m'assurer que les choses sont formatées correctement. J'ai un autre script pour exécuter le formateur sur place. Cela me rappelle une mise en garde: vous devez utiliser un shell capable de traiter les sous-processus ( le shell posix ne le fait pas ).

2
Matt

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

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

 run-clang-format example

2
Matthieu Moy

J'utilise git-clang-format et un script de pré-validation du blog de Mike Rhodes:

#!/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 sens qu'il ne fonctionne pas lorsqu'il n'y a pas de validations (essayer de vérifier par rapport à HEAD qui n'existe pas encore). Pour éviter cela, utilisez l’option -n ou --no-verify.

L'utilisation de -n pour ignorer le script de pré-validation peut également être utile lorsque vous devez contourner la vérification, car cela peut prendre du temps pour une base de code volumineuse.

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

1
Daniel

Après avoir été inspiré par le message de David Ogren j'ai créé un hook pre-commit capable de travailler sur les changements mis en scène. Cela garantira que le hook pre-commit fonctionnera sur le code qui constituera le contenu du commit et ne pourra pas être trompé par une exécution clang-format qui n'a pas été effectuée.

#!/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
Martin