Избегайте robocopy для сброса уровня ошибки в пакетном режиме

Наша система компиляции копирует бинарные зависимости, используя robocopy. Например, гипотетический файл copy_dependencies.bat может выглядеть примерно так:

@echo off
robocopy %PARAMETERS% src_path\Debug   dst_path\Debug   dep_name.dll
robocopy %PARAMETERS% src_path\Release dst_path\Release dep_name.dll

Поскольку такие двоичные файлы влияют не на успех компиляции, а на выполнение окончательных исполняемых файлов, мы хотели бы добавить к ним проверку ошибок (например, проверять изменения пути или имени файла). Идея состоит в том, чтобы поймать их как можно скорее, а не на более глубоком уровне во время выполнения тестов.

Так как если пакет возвращает ненулевой уровень ошибки, то наша система компиляции автоматически останавливается, нашим первым подходом будет проверка уровня ошибки в конце каждого пакета:

@echo off
robocopy %PARAMETERS% src_path\Debug   dst_path\Debug   dep_name.dll
robocopy %PARAMETERS% src_path\Release dst_path\Release dep_name.dll

if errorlevel 8 exit /b
exit /b 0

Примечание. Мы проверяем уровень ошибки не ниже 8, поскольку меньшие значения являются для нас просто предупреждениями (лишние файлы и т. д.). Вот почему мы также сбрасываем уровень ошибки на 0 в конце.

Проблема в том, что robocopy сбрасывает уровень ошибки, поэтому если первая команда не удалась, об этом не сообщается. Затем следующим решением будет проверка каждого отдельного вызова:

@echo off
robocopy %PARAMETERS% src_path\Debug   dst_path\Debug   dep_name.dll
if errorlevel 8 exit /b
robocopy %PARAMETERS% src_path\Release dst_path\Release dep_name.dll
if errorlevel 8 exit /b

exit /b 0

Проблема здесь в том, что нам пришлось бы изменить сотни файлов.

В дополнение к скрипту replace-all-like есть ли какой-нибудь более чистый способ сделать это? Что-то вроде флага для robocopy, который мы можем добавить к PARAMETERS, чтобы избежать сброса?

Другой подход может включать флаг выполнения для пакетов, который автоматически завершает работу скрипта, если уровень ошибки равен 8 или выше (поэтому мы можем установить его в начале компиляции).


ПС

Я публикую наше лучшее решение на данный момент, но оно все равно потребует изменения всех файлов. Изменение пакетных файлов (особенно из-за простого шаблона) сейчас не занимает много времени, но я хотел бы знать, есть ли решение, которое не требует таких изменений. Спасибо!


person cbuchart    schedule 30.01.2018    source источник
comment
Я боюсь, что для robocopy нет флага, чтобы сохранить предыдущие значения ErrorLevel. В любом случае, вы должны сначала уточнить, что вы хотите, чтобы произошло в случае сбоя первой строки robocopy, поэтому следует ли выполнять вторую или нет...   -  person aschipfl    schedule 30.01.2018
comment
@aschipfl спасибо! на самом деле в нашем случае это было бы то же самое, выполняются ли следующие робокопии или нет, пока copy_dependendies.bat терпит неудачу (уровень ошибки > 0), так как это тот, который проверяется компиляцией   -  person cbuchart    schedule 30.01.2018
comment
Почему вы все-таки используете командный файл? почему бы просто не позвонить robocopy.exe напрямую?   -  person aschipfl    schedule 30.01.2018
comment
@aschipfl наш makefile имеет примерно такую ​​структуру: 1) проверка/обновление 2) зависимости 3) компиляция 4) операции после сборки. Шаг 2 может подразумевать множество операций (десятки зависимостей), поэтому они содержатся в отдельном скрипте для каждого проекта.   -  person cbuchart    schedule 30.01.2018
comment
Это не просто робокопия. Каждый исполняемый файл Windows сбрасывает уровень ошибки. Если вы специально не напишете приложение, которое сохраняет уровень ошибок перед его запуском, но даже в этом случае вам придется передать уровень ошибок приложению в командной строке, потому что ни одно приложение не может автоматически получить код выхода ранее запущенного приложения.   -  person DodgyCodeException    schedule 07.02.2018


Ответы (1)


ОБНОВЛЕНИЕ

Как было предложено @DodgyCodeException в комментариях, решение, которое лучше всего решает эту проблему, по-видимому, состоит в том, чтобы префикс каждого оператора robocopy использовать однострочное условие, чтобы robocopy выполнялось только в том случае, если уровень ошибки не был повышен ранее. copy_dependencies.bat, показанный в примере, теперь:

@echo off
if not errorlevel 8 robocopy %PARAMETERS% src_path\Debug   dst_path\Debug   dep_name.dll
if not errorlevel 8 robocopy %PARAMETERS% src_path\Release dst_path\Release dep_name.dll

if errorlevel 8 exit /b
exit /b 0

Предыдущее решение включало использование промежуточного пакета (называемого здесь my_robocopy.bat), который распространяет уровень ошибки:

@echo off
if errorlevel 8 exit /b
robocopy %PARAMETERS% %*
exit /b

copy_dependencies.bat, показанный в примере, теперь:

@echo off
call %COMMON_PATH%\my_robocopy.bat src_path\Debug   dst_path\Debug   dep_name.dll
call %COMMON_PATH%\my_robocopy.bat src_path\Release dst_path\Release dep_name.dll

if errorlevel 8 exit /b
exit /b 0
person cbuchart    schedule 30.01.2018
comment
Либо замените исходные строки на if not errorlevel 8 robocopy %PARAMETERS% src_path\Release dst_path\Release dep_name.dll. Первая команда, создающая ошибку выше 8, приведет к провалу остальных строк. Затем просто проверьте уровень ошибок в конце. - person DodgyCodeException; 07.02.2018
comment
@DodgyCodeException, это именно то, что я искал, спасибо! Если хотите, опубликуйте его как отдельный ответ, чтобы принять его. - person cbuchart; 07.02.2018