LINUX.ORG.RU

Кастомный Setup.hs в hashell программе

 , ,


0

2

Хотел описать проблему в заголовке, чтобы было понятно, но столкнулся с ограничением по длине.

Собственно ситуация:

Написал утилиту на haskell для работы с api малоизвестного сайта. Все замечательно, но есть две проблемы, которые хотелось бы решить.

  • Ключи для api хранить в исходниках, если они открыты не очень хорошо. Как можно красиво и идиоматично подставлять их перед компиляцией? Сейчас я компилирую просто stack build, и мне кажется что писать какой-то внешний скрипт, который будет подставлять ключи в код, а потом уже запускать stack build это ужасный костыль.
  • Хочется собирать пакеты для разных дистрибутивов при компиляции сразу. (желательно, конечно по дополнительной опции) Опять же, как это «правильно» делать?

Сейчас build-type: Simple в cabal файле. Я думал сделать custom и написать соответственно код в Setup.hs который все это делает внутри. Но смущает, что нигде нет ни мануалов, ни примеров, ни вообще упоминаний что это будет работать cо stack.

Есть например https://hackage.haskell.org/package/cabal-debian - но это внешняя утилита, как я понял.

Еще есть shake. Его стоит использовать? И если да, то как?

  • Как нечто внешнее, что буду использовать в итоге вместо stack test/build/install? Т.е. сначала подставить ключи в шаблоны, потом скомпилировать вызвав stack, а потом собрав пакеты мне нужные?
  • Или его можно встроить в Setup.hs?

Во первом случае смущает, что другому человеку будет трудно все скомпилять, увидев велосипед вместо стандартного stack install. Во втором, я вообще не уверен что это возможно так если честно. Иначе почему так никто не делает?

В общем я вижу много вариантов, какие-то из них возможно наивны и/или сложны, но хочется узнать именно как правильно и почему это правильно. Совсем здорово если с ссылками на примеры.

Как можно красиво и идиоматично подставлять их перед компиляцией?

Суровые будни программирования на языке с чистыми функциями :) Обычно такое добавляют в конфиг программы.

goingUp ★★★★★
()

Вынести в конфиг? Или в ключи запуска?

anonymous
()

Ты хочешь именно вкомпилять ключ в программу?

Сейчас build-type: Simple в cabal файле. Я думал сделать custom и написать соответственно код в Setup.hs который все это делает внутри. Но смущает, что нигде нет ни мануалов, ни примеров, ни вообще упоминаний что это будет работать cо stack.

Увидел в Setup.hs строку import Distribution.Simple, загуглил Distribution.Simple, написал за пять минут костыль, который читает на этапе компиляции переменную окружения SECRET_KEY и генерирует модуль Secret.Key с функцией key, возвращающей ключ:

import Distribution.Simple
import Distribution.PackageDescription

import System.Environment
import System.IO

main = defaultMainWithHooks $ simpleUserHooks { preBuild = createKey }

genModule key =
  "module Secret.Key (key) where\n" ++
  "key = \"" ++ key ++ "\""

createKey _ _ = do
  key <- lookupEnv "SECRET_KEY"
  case key of
    Just key -> writeFile "src/Secret/Key.hs" $ genModule key
    Nothing -> error "Usage: SECRET_KEY=<KEY> stack build"
  return emptyHookedBuildInfo

Использовать так

module Main where

import Secret.Key

main :: IO ()
main = putStrLn $ "Secret key is " ++ key

Тип сборки поменять с Simple на Custom.

Компилировать примерно так:

$ SECRET_KEY=HELLO_LOR stack build

Уверен, что это не лучший вариант (можно использовать препроцессор или th), но ты ж хотел кастомный Setup.hs.

theNamelessOne ★★★★★
()
Ответ на: комментарий от goingUp

Нет никаких проблем так сделать (в конце-концов логин и пароль пользователя я в конфиге и держу), кроме одной.

Ключи выдаются в личном порядке. Т.е. всякий кто решил скачать и попробовать ключей не будет иметь, а своими делится на весь мир «не очень хорошо» - администрация ресурса не одобряет.

Конечно, можно их выковырять из бинарника всегда. Но это другой разговор)

Т.е. в общем-то была бы программа на с++ была бы аналогичная проблема, и решал бы я её тогда скорее всего внутри какого-нибудь инструмента для сборки так или иначе.

Но в данном случае уже есть stack. И хочется не городить велосипед, а как-то использовать возможности существующего инструмента.

А так собственно если брать из конфига на этапе компиляции то это принципиально не отличается от подставить в шаблон кода, остается только вопрос «как это сделать?»

P.S. Вообще это все может уйти далеко в оффтопик. С «а зачем выкладывать исходники, если воспользоваться кому попало все равно не получится»?

Но меня собственно занимает техническая сторона дела. А все это просто пример, в результате которого возник вопрос «как делать такие вещи». Собственно альтернативное не менее полезное (но не гуглил глубоко пока, может конкретно для этого есть какая-то встроенная поддержка). Добавить скажем в optparse-applicative ключ --version, который будет хардкордить версию из кабал файла при компиляции. Но тут просто это не сильно критично, скопипастить цифорку 1 раз.

chuemir
() автор топика
Ответ на: комментарий от theNamelessOne

Я не то чтобы так хотел. Скорее это то что мне показалось самым естественным.

Почему вариант анонимуса, не катит хотя объективно логичный, выше отписал.

А так это выглядит действительно примерно тем что я ожидал, Спасибо! Вариант с th, раз говоришь что он лучше, тоже посмотрю. Как-то не приходило в голову, что его можно использовать для таких вещей, даже не смотрел в его сторону думая что он просто для синтаксического сахара исключительно используется.

chuemir
() автор топика
Ответ на: комментарий от chuemir

А так собственно если брать из конфига на этапе компиляции то это принципиально не отличается от подставить в шаблон кода, остается только вопрос «как это сделать?»

QuasiQuote и что-нибудь типа here или heredoc:

key = [hereFile|secret.key|]

Laz ★★★★★
()
Ответ на: комментарий от chuemir

Добавить скажем в optparse-applicative ключ --version, который будет хардкордить версию из кабал файла при компиляции. Но тут просто это не сильно критично, скопипастить цифорку 1 раз.

Cabal генерит Paths_${projectname}.hs файл. Его можно импортить и юзать в самом проекте. В файле определяются константы версии проекта и пары путей.

Пример из hoogle:

-- cat dist/build/autogen/Paths_hoogle.hs

module Paths_hoogle (
    version,
    getBinDir, getLibDir, getDataDir, getLibexecDir,
    getDataFileName, getSysconfDir
  ) where

-- ...
version :: Version
version = Version [5,0] []

Для общей задачи встраивать блоб некоторые проекты юзают hsb2hs(pandoc) и file-embed(yesod,stack).

Но приватные ключи хардкодить в бинарник я бы не советовал :) Один бинарник проще скопировать случайно (или специально) скопировав ключ чем бинарник и конфиг.

Примеры решения похожей задачи:

  • утилита для работы с github hub(ruby,go) при первом запуске генерит oauth токен
  • утилита для работы с phabricator arc(php) тоже генерит oauth токен
sf ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.