1. bash / Говнокод #16780

    −107

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    ...
    %install
    %{__rm} -rf %{buildroot}
    mkdir -m 755 -p %{buildroot}%{_datadir}/common-lisp/source/%{name}
    for s in $(find -regex '.+\.\(lisp\|asd\|org\)$'); do
      install -D -m 644 $s %{buildroot}%{_datadir}/common-lisp/source/%{name}
    done;
    mkdir -m 755 -p %{buildroot}/etc/common-lisp/source-registry.conf.d
    for las_conf in $(ls %{buildroot}/etc/common-lisp/source-registry.conf.d | tail -n 1); do
        for last in $(echo "${last_conf}" | grep -oP '^[0-9]+'); do
            for cl_prefix in $(echo "${last}+1" | bc); do
                echo '(:include "/usr/share/common-lisp/source/%{name}/")' > \
    	            "%{buildroot}/etc/common-lisp/source-registry.conf.d/${cl_prefix}-%{name}.conf"
                install -m 644 ${cl_prefix}-%{name}.conf %{buildroot}/etc/common-lisp/source-registry.conf.d
            done;
        done;
    done;
    
    %files
    %defattr(-,root,root,-)
    %{_datadir}/common-lisp/source/%{name}/*
    ...

    И ведь что показательно, работает!

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

    Запостил: wvxvw, 30 Сентября 2014

    Комментарии (26) RSS

    • > Надо горбатится над каким-то недоязыком

      шелл как шелл. просто кто-то очень очень сильно извратился в строках 9-11.

      ЗЫ строки 12-14 пахнут. install в 14й перепишет тот файл который echo в 12-13 создает.

      > Менеджер пакетов завдующий установкой ПО написан на Питоне, но нельзя просто так взять и на Питоне же написать установочный скрипт.

      Почему нет? Пишешь питон скрипт, включаешь его в пакет, вызываешь его во время инсталяции, а потом удаляешь. Или там какой извратный chroot используется во время инсталяции?
      Ответить
      • Да, с инстоллом промахнулся. Очень все пути похоже выглядят.
        Тут главная фишка в том, что в .spec файле переменную не объявить. Т.е. эти циклы не нужны (каждый цикл выполняется ровно один раз).
        Да понятно, что можно написать инсталятор отдельно и включить его в... другой (убогий) инсталятор. Зачем они его придумали? Питон же уже был. А даже если и нет, то Перл точно был.

        Почему шелл плох для этого? Куча бойлерплейта. Вот то, что я запостил - инсталяция одного пакета, а мне для полного счастья нужно около десятка. И они все будут выглядеть на 90% одинаковыми (потому что нет модульности, структур и интерфейсов).
        Ответить
        • > Тут главная фишка в том, что в .spec файле переменную не объявить.

          а зачем тебе переменная на уровне spec файла то сдалась?

          то что сверху это всего лишь template скрипта, где %{} заменятся на значения, и результат будет скормлен шелу. почти тот же самый принцип что и в GNU make.

          другими словами, пишешь например, `R="%{buildroot}";` и дальше можешь пользоватся `$R` вместо `%{buildroot}`.

          > Почему шелл плох для этого? Куча бойлерплейта.

          признайся самому себе: ты просто не знаешь шела.

          то что написано сверху (нахождение номера последнего пакета + 1) делается весьма прямолинейно и без извратов. например:

          LAST_NUM=$(ls -1 %{buildroot}/etc/common-lisp/source-registry.conf.d | tail -n 1 | sed 's!^\(\d*\).*!\1!; s!^0*!!;')
          test -n "$LAST_NUM" || LAST_NUM=0
          let "NEW_NUM=$LAST_NUM+1"
          cl_prefix=`printf "%02d" $NEW_NUM` # уверен что там ведущие нули есть, иначе ls правильно сортировать не будет.
          echo ...
          install ...


          зы еще пахнет то что если предварительно ничего не было установлено, то ничего в /etc/common-lisp/source-registry.conf.d/ и не будет скопировано. плюс, я уверен что номера как минимум двухзначные с ведущими нулями.

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

          > И они все будут выглядеть на 90% одинаковыми

          ну блин, тебе даже же %{name} предоставляют. чего тебе еще не хватает что бы из сделать 100% одинаковыми?

          ЗЫ к слову. я тут чисто про шелл говорю - спеки ни разу не писал.

          ЗЗЫ а вот это - find -regex '.+\.\(lisp\|asd\|org\)$' - по человечески пишется find -name '*.list' -o -name '*.asd' -o -name '*.org'. (регулярка скипает имена состоящие только из расширений - если это так и задумывалось, то добавь '?' перед '*'.)
          Ответить
          • Зачем мне на уровне spec файла переменная? - Мне удобнее программировать с переменными, чем без.
            О, а в Мейкфале тоже просто так нельзя взять и объявить переменную.

            > Без извратов.
            Без извратов это так:
            last = int(listdir("/etc/common-lisp/source-registry.conf.d")[-1].split('-'))
            cl_prefix = str(last + 1).zfill(2)


            никто не сказал, что это весь скрипт, /etc/common-lisp/source-registry.conf.d/ создается где-то раньше.

            Что мне не хватает?
            Открой как-нибудь SCons файл и сравни количество текста.
            В spec файле дохрена насторек которые можно было бы заполнить по-умолчанию.
            Название пакета - почему бы не взять название папки в которой сорцы находятся? в 99% случаев это и будет название пакета. Сорцы - ровно точно так же: название папки + tar.gz. Описание? Почему бы не посмотреть в ту же папку и не прочитать его из файла README?
            А как думаешь, в каком файле окажется %changelog?
            Более того, если бы это был нормальный язык, можно было бы, например, унаследовать класс один раз от стандартного шаблона, переопределить в нем пару методов и использовать этот новый класс для однотипных задач для которых он был сделан. Тут же я вынужден копипастить бесполезную херню типа %prep %build и т.д.
            Ну вот например, хочу я, чтобы ченжлог генерировался из логов Гита? Почему бы и нет, ну правда ж в 21-м веке живем все-таки. И хочу я это для всех проектов. И что мне остается? - правильно, либо написать инсталятор на другом языке и вызывать его из RPM скрипта (нафиг тогда нужен RPM скрипт?), либо паста в RPM скрипте.

            Да, у меня есть папка .org в проекте, там локальные настройки Org-mode хранятся.
            Ответить
            • > Открой как-нибудь SCons файл и сравни количество текста.

              Я видел SCons'ы (и до этого перловы Cons'ы) из продакшн проектов. Текста там было наааамного больше. :)

              > Более того, если бы это был нормальный язык

              Ты зациклился на каком-то оverdesign'е. Как я и говорю, то чего тебе не хватает это простое знание шелла.

              В сети валяется в хтмл "Unix Power Tools". Книга типа "cookbook" и содержит много разных примеров как чего можно делать с помощью шелли и базовых утилит. (случайно нагуглил: http://bioinfo2.ugr.es/OReillyReferenceLibrary/unix/upt/index.htm - програмирование на шелле: http://bioinfo2.ugr.es/OReillyReferenceLibrary/unix/upt/part08.htm )

              > Более того, если бы это был нормальный язык [...]

              Нафиг не нужно потому что как правило в пост-инстале обрабатываются только какие-то исключения.

              Да и переплюнуть шелл по работе с файлами и текстом - в батч режиме - весьма сложно. Нужно только уметь.

              В конце концов, написать кучу говна можно на любом языке. Но это не становится виной языка.
              Ответить
              • Ага, SCnos файл для тривиального проекта на, скажем, Яве, выглядит так:
                Java()

                И все. И это описывает и сборку и как удалить стартые результаты сборки, интерфейс командной строки и т.д.

                Можно ли сделать на Шелле? - да. Нужно ли? - это совсем другой вопрос. Примеры Шелла, а особено подражания, где это доведено до абсурда, Автомейк, язык матрешка: макросы на одном языке раскрываются в макросы на другом языке (последовательным вызовом 5-6 разных програм!), а потом оказывается что если раскрыть макросы на третьем языке то из них получится 100500 разных недоязыков специальных для каждой команды этого языка. Более того, они сгенерируют 99% кода который у меня уже был, вот ну совсем рядом в соседней папке.

                Например, для использования sed не достаточно знать регулярные выражения и Шелл, нужно знать мини-язык, которым sed описывает операции которые он может сделать. И так практически с каждой коммандой. find - аналогично, printf - то же самое, и т.д. Т.е. для того, чтобы понять программу на Питоне - достаточно знать Питон (т.е. каких-то 10-20 ключевых слов и столько же встроеных функций, остальное можно понять из комбинаций предыдущего). С Шеллом так не получится, потому что каждая команда использует свой алфавит и свои правила. Это не экономно с точки зрения того, какой выразительной силой должен обладать язык для того, чтобы описать необходимые операции.
                Ответить
                • > SCnos файл для тривиального проекта на, скажем, Яве, выглядит так:
                  Java()

                  Тривиальные проекты на яве никому не нужны. Нужно управление зависимостями, подключение сторонних репозиториев пакетов, минимизация жарников, гибридная Scala/Java - компиляция, накатывания миграций на базы, тыщи действий, которые наполнят живые SCons файлы сотнями строк.
                  Ответить
            • last = int(listdir("/etc/common-lisp/source-registry.conf.d")[-1].split('-'))
              cl_prefix = str(last + 1).zfill(2)

              позвольте мне это переписать еще раз на шелле:
              cl_prefix=$(python -c 'last = int(listdir("/etc/common-lisp/source-registry.conf.d")[-1].split("-")); print str(last + 1).zfill(2)')

              ;)
              Ответить
              • Так это каша из топора? Нафига мне шел, если я без него могу лучше?
                Ответить
          • А, да, эта .d не совсем обычная, и как числа тут расставлять - я не знаю. По-хорошему, кто-то должен взяться и обновить common-lisp-listener пакет, который бы занимался регистрацией библиотек (он это делал, но так давно и плохо, что на него все забили). Т.е. по-идее, я не должен заниматься этой конфигосодомией. Но проблема в том, что нету "резидента", который бы это сделал.
            Т.е. кто-то должен быть в системе и следить за базой данных, какие пакеты установлены, что делать если один и тот же пакет пытается установиться, не почистив предыдущую установку и т.п. Разбираться с такими нюансами из установочного скрипта - буэ. Но другого нет.
            Ответить
      • > Почему нет? Пишешь питон скрипт, включаешь его в пакет, вызываешь его во время инсталяции, а потом удаляешь.

        Вызывать во время инсталляции пакета скрипт, который находится в пакете, который устанавливаем? Проблема курицы и яйца. Вероятно, есть некоторая ошибка в терминологии, но идея верна.

        %install - фаза, на которой происходит инсталляция собранных бинарников в DESTDIR, выполняется он в корне проекта, подлежащего упаковке. Поэтому дёргать из него можно всё что угодно. Теже питоны, лишь бы они были в BuildRequires. Обычно там тупой (с)make install или вызов вашего любимой системы сборки для инсталляции.
        Ответить
    • > Менеджер пакетов завдующий установкой ПО написан на Питоне

      Вот до чего же люди плохо мыслят в четырёх измерениях. Пакетный менеджер rpm написан на сишке. Управление зависимостями с пистоном появились не сразу. А переделывать всю инфраструктуру, чтобы писать скрипты на питоне - идея так себе.

      Кроме того, типичные скрипты для инсталляции выглядят одинаково паршиво и требуют много бойлерплейта на любом языке. Особенно при сборке сишного софта.
      Ответить
      • В том-то все и дело, что не требуют они этого бойлерпейта. Бойлерплейт можно было один раз написать и использовать его потом много раз один и тот же, вместо того, чтобы генерировать по-новой.

        Вообще, и Питон не нужен для этого. Изначально, когда GNU только задумывался, языком расширений должна была стать Схема (Guile). И вобщем, они к этому и идут, только очень медлено. То, что ЮНИКС решили реализовывать, по крайней мере в этом смысле, было ошибкой. Тогда, это конечно дало возможность использовать готовые програмы, но врезультате получилось то, чего и боялись (тогда от Tcl) - непродуманый беспомощный язык расширений + зоопарк замен этому языку.
        Ответить
        • Не должно быть в %install никакого бойлерплейта. Вызов make install / вашей любой системы сборки.
          Ответить
        • По поводу бойлерплейта в именах и прочее:

          Из исходников, как правило, собирается больше одного пакета. Шареные либы, платфомо-независимые данные, основные сервисы, утилиты, дебажные символы, devel-пакеты с публичными хедерами и библиотеками без soname, emacsen-пакеты, плагины для вима, очень много всего.

          Более того, это даже не отношение один ко многим, скорее многие ко многим. Для сборки тулов LLVM нужно сразу несколько архивов с исходным кодом.

          Да, логично упростить для простых пакетов. В дебиане для этого есть тула dh_make. C rpm я работал недолго, может, и там что-то такое есть.

          Но для грамотной упаковки изучать инфраструктуру пакетирования всё равно придётся, и подстановка пары имён - меньшее из всех зол.

          И что ещё важно понимать - в опенсорсе люди, которые собирают пакеты, как правило, не те же люди, что пишут софт. У них есть доступ в основном к релизным архивам с исходниками. Версии пакетов лишь отчасти связаны с версиями софта - пакеты могут накатывать собственные патчи на софт из архива в процессе сборки. Отсюда растут многие неудобства, возникающие при попытке упаковывать софт, который сам же и пишешь.

          У нас, например, метаданные пакетов версионируются в отдельном git-репозитории, и changelog пакетов генерится из git log в этом репозитории.
          Ответить
          • Да, да, и мегабайты одинакового кода из, например configure ну просто необходимо поэтому скопировать в каждый проект. А как же по-другому?
            В Дебиане те же яйца только в профиль. Нужно менять подход, а не придумавать дополнительные инструменты, которые могут нагенерировать нового бойлерпейта, т.как с каждым таким инструметном количество бойлерплейта только увеличивается.
            В чем принципиальное отличие SCons от Make? - Не в том, что единичный тривиальный билд будет меньше, а в том, что если у меня есть одинаковые сколько угодно сложные билды, написав на SCons билд один раз, я этот билд проинсталирую в системе, и все остальные билды смогут использовать его (внимание, никакого бойлерплейта! используется тот же код), или смогут импортировать часть! другого уже готового билда. Будь это Ява, Ц++, да что угодно, я смогу общий код из разных билдов использовать повторно, не копируя его!
            Ответить
            • Ок, можно собрать кучу готовых рецептов для make, положить их в пакет, добавить пакет в build-depends и не писать кучу бойлерплейта.

              Именно так у нас и сделано.

              > В чем принципиальное отличие SCons от Make?

              В том, что make есть практически на любой юникс-системе, не нужно трахаться с обратно несовместимыми версиями питона и можно рассчитывать, что твой софт будет стабильно собираться даже на кофеварке.

              Это никак не опровергает тот факт, что autotools и прочие configure - лютое говнище, а пакетирование под линупс - костыли и шаманство.
              Ответить
              • Так может надо стремиться к хорошему, вместо того, чтобы жить с уверенностью, что раз есть говно, которое мытарствами и слезами удалось довести до состояния, когда оно иногда работает, то с ним нужно оставаться жить навсегда?
                Куча готовых рецептов для Мейка - это называется замести под ковер, вместо того, чтобы решить проблему.
                Ответить
                • Я честно стремлюсь, но SCons далеко не ответ на все вопросы. CMake тоже говно. GYP тоже говно.

                  Давно хочу написать свою систему сборки с ориентацией на сишкопроекты, с Lua в качестве языка описания задач, поддержкой герметичных билдов, быстрыми инкрементальными сборками и подключением зависимстей из гитхабика одной строчкой.
                  Ответить
                  • > Давно хочу написать свою систему сборки с ориентацией на сишкопроекты [...]

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

                    до сишко/этц проектов еще дорости надо.

                    все зацикливаются на высокоуровневых функциях (авто зависимости) в то время как база остается слабой.

                    вот даже то повсеместное инсталирование библиотек и хидеров (внутри большого проекта) никто толком отслеживать не умеет. (что бы зависимости продолжали работать.) Cons умел - но SCons вроде так и не перенял.
                    Ответить
                    • Есть ещё вот такая интересная штука
                      https://github.com/ndmitchell/shake
                      Но я её ещё не ковырял.

                      Для себя довольствуюсь CMake + ninja. Инкрементальные сборки с ninja - это песня.
                      Ответить
                      • > Есть ещё вот такая интересная штука [...]

                        идея правильная - но на неправильном языке. :)
                        Ответить
                  • Ну как, написал?
                    Ответить
          • > метаданные пакетов версионируются в отдельном git-репозитории, и changelog пакетов генерится из git log в этом репозитории.
            - мне нравится эта идея. Надо будет попробовать как-то
            Ответить

    Добавить комментарий