flake8 ведет себя по-разному при запуске из скрипта bash - PullRequest
0 голосов
/ 06 ноября 2018

Полагаю, что ответ здесь может быть тривиальным, но мне могут потребоваться некоторые сложные знания bash. Я просматривал документы bash уже несколько часов и, похоже, не могу найти ответ.

Я работаю над репозиторием Python и придумала простой скрипт, который связывает только файлы, которые различаются между текущей веткой и мастером. Вот минимальный рабочий пример, извлеченный из указанного скрипта (lint.sh):

#!/bin/bash    
paths=$(git diff --name-only -r origin/master...HEAD | grep \.py$)    
flake8 $paths

В целях тестирования, допустим, я зафиксировал только один файл bad.py со следующим содержимым:

hello
there

Ожидаемый результат bash lint.sh:

bad.py:1:1: F821 undefined name 'hello'
bad.py:2:1: F821 undefined name 'there'

Однако вывод пустой. При запуске в режиме отладки bash показывает следующие команды:

++ git diff --name-only -r origin/master...HEAD
++ grep '.py$'
+ paths='bad.py'
+ flake8 'bad.py'

Что я и ожидаю. Кроме того, когда я просто запускаю flake8 bad.py, вывод будет таким, как ожидалось.

Я ожидаю, что может как-то иметь отношение к передаче параметров, которая варьируется в зависимости от версии bash. Выход bash --version: GNU bash, version 4.4.23(1)-release (x86_64-apple-darwin17.5.0)

Я буду признателен за все идеи

1 Ответ

0 голосов
/ 06 ноября 2018

Очень жаль, что это не совсем ответ, но он наверняка не вписался в комментарий!

Подсказка для меня следующая:

+ paths='bad.py'
+ flake8 'bad.py'

При выполнении того же скрипта я получаю следующее:

$ bash -x lint.sh 
++ git diff --name-only -r origin/master...HEAD
++ grep '.py$'
+ paths=bar.py
+ flake8 bar.py
bar.py:1:1: F821 undefined name 'hello'
bar.py:2:1: F821 undefined name 'world'

Обратите внимание, что мой вывод не содержит кавычки вокруг имени файла или назначения. bash обычно не добавляет кавычки, если они не нужны. Это говорит мне о том, что вероятно какой-то управляющий символ в этой строке (мое лучшее предположение - либо цвета, либо \b + некоторые другие символы (это может быть один из немногих случаев, когда скриншот на самом деле полезно!)).

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

mkdir -p bin

cat > bin/grep << EOF
#!/usr/bin/env bash
exec /bin/grep --color=always "\$@"
EOF

chmod +x bin/grep

# simulate having this `grep` on your path
PATH=$PWD/bin:$PATH bash -x lint.sh

(и хотя это кажется странным делом, в прошлом я помещал свои собственные grep в ~/bin, поэтому я мог добавить --line-buffered --color=auto теперь, когда GREP_OPTIONS устарела - можно ошибочно добавить --color=always и заставить его работать ... по большей части). Сегодня я вместо этого использую псевдоним , так как даже с этим я столкнулся с острыми краями.

Вывод в этом случае совпадает с вашим выше:

$ PATH=$PWD/bin:$PATH bash -x lint.sh
++ git diff --name-only -r origin/master...HEAD
++ grep '.py$'
+ paths='bar.py'
+ flake8 'bar.py'

Но хитрый намек есть в выделении

screenshot of terminal output

дополнение

Хотя это не имеет отношения к вашей проблеме, возможно, есть лучший способ достичь желаемого:

# if you have GNU xargs
git diff -z --name-only origin/master...HEAD -- '*.py' | xargs --null --no-run-if-empty flake8

# if you need to be more portable (I see you're probably on macos)
git diff -z --name-only origin/master...HEAD -- '*.py' | xargs -0 flake8 /dev/null

Объяснение различных частей:

  • git diff -z: выходные имена файлов с разделителями нулевых байтов. Это предотвращает соединение, если имена файлов содержат пробелы или другие специальные символы
  • xargs --null: разделить входные данные на нулевые байты при разделении аргументов
  • xargs --no-run-if-empty: вообще не запускать исполняемый файл, если нет аргументов (это расширение GNU)
  • xargs -0: то же самое, что и xargs --null, однако, если вы застряли с не-GNU xargs, у вас не будет доступа к длинным опциям
  • flake8 /dev/null: это хитрый трюк, поскольку у bsd xargs нет опции «не бежать, если пусто», он всегда будет вызывать flake8. Если flake8 вызывается с нулевыми аргументами, по умолчанию используется рекурсивный текущий рабочий каталог (и привязка всех ваших файлов). Помещая /dev/null в начале, это предотвращает это поведение и вместо этого создает пустой файл!

Приложение 2, вы, возможно, захотите рассмотреть возможность использования фреймворка git hooks, чтобы справиться со всем этим для вас, я поддерживаю pre-commit , цель которого - сгладить множество неровностей вокруг git (например, этот!).

...