Подтвердить что ты не робот

Может ли clang-format сказать мне, нужны ли изменения форматирования?

Есть ли способ, которым вы можете запускать clang-format в режиме, когда он сообщает, соответствует ли файл указанному формату? Это своего рода сухой режим, в котором он сообщает, если требуется изменение, но не делает изменения. В идеале я хотел бы, чтобы clang-format просто возвращал ненулевой код выхода, если файл нуждается в изменениях. Или, что еще более идеально, ненулевой код выхода и список файлов, которые нуждаются в изменениях на стандартном выходе.

Я пытаюсь сохранить общий вопрос, так что больше людей могут ответить, но я пытаюсь написать git pre-commit hook, который отклонит любые коммиты, которые не соответствуют ожидаемому. clang-format. Легко запускать clang-format в списке файлов в индексе. Но трудно понять, действительно ли clang-format что-то изменил.

У меня есть одно потенциальное решение на основе -output-replacements-xml (которое я выложу в качестве ответа), но это взломать, и я чувствую, что это должно быть более простым. Комментарии/предложения, изменения, различные ответы/подходы приветствуются.

4b9b3361

Ответ 1

Одна из причин, по которой я чувствую, что это должно быть проще, чем то, что -output-replacements-xml, по сути, дает мне ответ, который я хочу, просто не дает его мне в удобной форме. Тем не менее, поскольку выходные данные, если замены не требуются, очень предсказуемы, анализ выходных данных не слишком сложен.

Что у меня сейчас есть

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

Это на самом деле возвращает инверсию кода выхода, который я хочу, поскольку grep возвращает 0, если что-то совпадает, 1, если ничего не происходит. Но с этим достаточно легко иметь дело.

Таким образом, соответствующий бит моего git pre-commit hook будет

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. Получить полные имена файлов в индексе (исключая файлы, которые удаляются, и другие необычные случаи, когда я не хочу обрабатывать файл)
  2. Сохраняйте только имена файлов, информацию о которых я хочу проверить (в моем случае это просто файлы c, m и h)
  3. Запустите результаты через xargs, чтобы по существу "для каждой" следующей команды
  4. Запустите clang-format с параметром -output-replacements-xml для всех файлов
  5. Поиск замены (в отличие от замен), который указывает, что в формате clang найдена замена, которую он хочет сделать. (Отказ от всего вывода как XML не будет иметь смысла для пользователя.)
  6. Последняя команда выходит из 1 (grep говорит, что мы ничего не нашли), мы сделали, и все в порядке.
  7. Если нет, отобразите сообщение и выйдите из 1, что отменяет фиксацию. К сожалению, у нас нет простого способа сообщить пользователю, в каком файле возникла проблема, но они могут сами запустить clang-format и посмотреть.

Ответ 2

run-clang-format представляет собой простую оболочку вокруг clang-format разработанную специально для использования в качестве ловушки или в качестве сценария непрерывной интеграции: он выводит diff и выходит с разумным статусом.

Пример, приведенный на домашней странице, говорит сам за себя:

run-clang-format example

Ответ 3

Я не совсем уверен, что ваш вариант использования, но посмотрите git -clang-format (https://llvm.org/svn/llvm-project/cfe/trunk/tools/clang-format/git-clang-format). Он в основном обеспечивает интеграцию с clang-форматом для git и, возможно, именно это вы ищете.

Ответ 4

Я немного скорректировал комментарий от phs в этом посте, чтобы придумать:

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 {} \;) -

то есть..

  1. cat все cpp-ish файлы и труба, которая к diff (diff примет stdin потому что я указываю - в конце)
  2. используйте подстановку процесса (синтаксис <(.. )), чтобы запустить clang-format для тех же файлов. Не используйте форматирование на месте здесь. Это другая половина, которую отправили на diff
  3. если diff выходит без выхода, успех! Вы также можете проверить код выхода через $? - должно быть ноль.

Моя служба CI (travis) запускает эту строку в bash-скрипте, чтобы убедиться, что все отформатировано правильно. У меня есть другой скрипт для фактического запуска форматтера на месте. Это напоминает мне предостережение: вы должны использовать оболочку, которая может выполнять процесс sub (оболочка posix этого не делает).

Ответ 5

Я использую git-clang-format и pre-commit script из блога Майка Родоса:

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

script имеет небольшую ошибку в том, что он не работает, когда нет коммитов (попытка проверки против HEAD, которая еще не существует). Чтобы обойти это, используйте параметр -n или --no-verify.

Использование -n для пропуска pre-commit script также может быть полезно, когда вы должны обойти проверку, потому что это может занять много времени для большой базы кода.

Оригинальное сообщение находится здесь: http://www.dx13.co.uk/articles/2015/4/3/Setting-up-git-clang-format.html

Ответ 6

После того, как я получил вдохновение от сообщения Дэвида Огрена, я сделал крючок pre-commit, который может работать над поэтапными изменениями. Это гарантирует, что крюк pre-commit будет работать над кодом, который фактически будет составлять содержимое коммита и не может быть обманут запуском clang-format, который не был поставлен.

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