Может ли clang-format сказать мне, нужны ли изменения форматирования?
Есть ли способ, которым вы можете запускать clang-format
в режиме, когда он сообщает, соответствует ли файл указанному формату? Это своего рода сухой режим, в котором он сообщает, если требуется изменение, но не делает изменения. В идеале я хотел бы, чтобы clang-format просто возвращал ненулевой код выхода, если файл нуждается в изменениях. Или, что еще более идеально, ненулевой код выхода и список файлов, которые нуждаются в изменениях на стандартном выходе.
Я пытаюсь сохранить общий вопрос, так что больше людей могут ответить, но я пытаюсь написать git pre-commit hook, который отклонит любые коммиты, которые не соответствуют ожидаемому. clang-format. Легко запускать clang-format в списке файлов в индексе. Но трудно понять, действительно ли clang-format что-то изменил.
У меня есть одно потенциальное решение на основе -output-replacements-xml
(которое я выложу в качестве ответа), но это взломать, и я чувствую, что это должно быть более простым. Комментарии/предложения, изменения, различные ответы/подходы приветствуются.
Ответы
Ответ 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
- Получить полные имена файлов в индексе (исключая файлы, которые удаляются, и другие необычные случаи, когда я не хочу обрабатывать файл)
- Сохраняйте только имена файлов, информацию о которых я хочу проверить (в моем случае это просто файлы c, m и h)
- Запустите результаты через xargs, чтобы по существу "для каждой" следующей команды
- Запустите clang-format с параметром -output-replacements-xml для всех файлов
- Поиск замены (в отличие от замен), который указывает, что в формате clang найдена замена, которую он хочет сделать. (Отказ от всего вывода как XML не будет иметь смысла для пользователя.)
- Последняя команда выходит из 1 (grep говорит, что мы ничего не нашли), мы сделали, и все в порядке.
- Если нет, отобразите сообщение и выйдите из 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 {} \;) -
то есть..
-
cat
все cpp-ish файлы и труба, которая к diff
(diff
примет stdin
потому что я указываю -
в конце) - используйте подстановку процесса (синтаксис
<(.. )
), чтобы запустить clang-format
для тех же файлов. Не используйте форматирование на месте здесь. Это другая половина, которую отправили на diff
- если
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