Makefile while цикл try / catch эквивалентен установке зависимостей python сначала с помощью conda, а затем с помощью pip - PullRequest
0 голосов
/ 18 декабря 2018

Мне нужно запустить цикл while для установки зависимостей Python.В последнее время в мире Python существует 2 способа установки зависимостей, которые установились:

  • с использованием conda (для некоторых людей это «надежный / стабильный / желаемый способ», предоставляемый «Дистрибутив Python "называется Anaconda / Miniconda),
  • с использованием pip (в последние несколько лет включен в качестве официального способа самого Python).

" Псевдокод "должен быть:

  • попробуйте установить зависимость с помощью команды conda
  • , если она не удалась, установите ее с помощью команды pip

ВМировые зависимости Python указываются в файле requirements.txt, обычно точные версии (==) в виде одной зависимости на строку с шаблоном <MY_DEPENDENCY>==<MY_VERSION>.

Эквивалентная bash желаемая команда: while read requirement; do conda install --yes $requirement || pip install $requirement; done < requirements.txtоднако это не работает в мире GNU make / Makefile по причинам, которые я до конца не понимаю.

Я пробовал несколько разных вариантов этого цикла while - все безуспешно,Обычно после сбоя команды conda я не могу продолжить попытку pip.Я не уверен, почему это происходит (так как это работает в «обычном bash»), и я не могу найти способ управления каким-либо низкоуровневым шаблоном try / catch (для тех, кто знаком с языками программирования высокого уровня).

Это моя последняя попытка, которая не работает, потому что она останавливается при сбое conda:

foo-target:
    # equivalent to bash: conda install --yes $requirement || pip install $requirement;
    while read requirement; do \
        conda install --yes $requirement ; \
        [ $$? != 0 ] || pip install $requirement; \
    done < requirements.txt

Как мне убедиться, что я пытаюсь установить каждое требование внутри requirements.txtсначала с conda, когда conda терпит неудачу, затем с pip?

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

Редактировать:

Я закончил работатьиспользование команды bash внутри Makefile, но Я считаю это решение не идеальным , потому что мне нужно сохранить еще один кусок кода в однострочном скрипте bash (см. ниже),есть способ хранить все вещи внутри Makefile , избегая bash вообще ?

Цель Makefile:

foo-target:
    bash install-python-dependencies.sh

bash однострочный скрипт:

#!/usr/bin/env bash
while read requirement; do conda install --yes $requirement || pip install $requirement; done < requirements.txt

Я могу запустить скрипт прямо из командной строки (bash), я также могу запустить его из Makefile, но Я бы хотелизбавьтесь от скрипта bash и всегда выполняйте make foo-target без использования bash (избегая bash даже внутри Makefile).

1 Ответ

0 голосов
/ 18 декабря 2018

Как показано выше, ваш make-файл будет работать так, как вы ожидаете, кроме того, что вы должны экранировать $ в переменных оболочки, таких как $$requirement.

Я не смог воспроизвести вашу проблему с упрощеннойПример для эмуляции поведения:

foo-target:
        for i in 1 2 3; do \
            echo conda; \
            test $$i -ne 2; \
            [ $$? -eq 0 ] || echo pip; \
        done

дает ожидаемый результат:

$ make
conda
conda
pip
conda

Вы добавили цель .POSIX: в свой make-файл, который здесь не отображается?Если я сделаю это, то получу поведение, которое вы утверждаете, чтобы увидеть:

conda
make: *** [Makefile:2: foo-target] Error 1

Причина этого описана в руководстве для .POSIX:

В частности, если упоминается эта цель, то рецепты будут вызываться так, как если бы оболочке был передан флаг '-e': первая неудачная команда в рецепте вызовет немедленный сбой рецепта.

Если вы хотите сохранить режим .POSIX, но не получите эту ошибку, самый простой способ - использовать метод, который вы показали в первом примере;Я не знаю, почему вы перестали его использовать:

foo-target:
        while read requirement; do \
            conda install --yes $$requirement || pip install $$requirement; \
        done < requirements.txt
...