Создание сценариев CLI в Clojure - PullRequest
0 голосов
/ 19 мая 2018

Каковы общие / стандартные способы создания сценариев CLI в Clojure?

На мой взгляд, такой метод должен включать следующие характеристики:

  • Способлегко иметь дело с аргументами, stdin / out / err.

  • Не требуя слишком много для загрузки (в идеале имея какой-то JIT), иначе человек теряет цель взламывать вещи вместе в своей оболочке.

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

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

#!/bin/bash
    echo "$@"
    cat /dev/stdin

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

Ответы [ 5 ]

0 голосов
/ 21 сентября 2018

Теперь, когда есть новый инструмент CLI , можно создать автономный скрипт Clojure без использования сторонних инструментов.Если у вас установлен clj инструмент командной строки установлен , скрипт, подобный приведенному ниже, должен просто работать.

С точки зрения исходного вопроса это может быть так же хорошо, как и любой другойПрограмма CLI Clojure / JVM для работы с аргументами командной строки и системным вводом / выводом в зависимости от того, какие библиотеки вы :require.Я не тестировал его, поэтому не буду комментировать производительность, но если вас это беспокоит, то, пожалуйста, поэкспериментируйте сами, чтобы убедиться, что время запуска приемлемо для вас.Я бы сказал, что это очень хорошо для управления зависимостями, так как скрипт полностью автономен (кроме инструмента clj, который в любом случае является рекомендуемым способом запуска Clojure).

Файл: ~/bin/script.sh

#!/bin/sh

"exec" "clj" "-Sdeps" "{:deps,{hiccup,{:mvn/version,\"1.0.5\"}}}" "$0" "$@"

(ns my-script
  (:require
    [hiccup.core :as hiccup]))

(println
  (hiccup/html
    [:div
      [:span "Command line args: " (clojure.string/join ", " *command-line-args*)]
      [:span "Stdin: " (read-line)]]))

Затем убедитесь, что он исполняемый:

$ chmod +x ~/bin/script.sh

И запустите его:

$ echo "stdin" | script.sh command line args
<div><span>Command line args: command, line, args</span><span>Stdin: stdin</span></div>

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

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

Благодаря добрым людям на канале # tools-deps группы Slack "clojurians", откуда эторешение пришло.

0 голосов
/ 29 июня 2018

Я пишу несколько сценариев Clojure (JVM) и использую библиотеку CLI-matic https://github.com/l3nz/cli-matic/, чтобы абстрагировать большую часть стандартного шаблона, который связан с анализом командной строки, созданием и обслуживанием справки, ошибок,и т.д.

0 голосов
/ 19 мая 2018

Опция будет Планка , которая работает на MacOS и Linux.Он использует собственный хост ClojureScript, имеет быстрый запуск и нацелен на JavaScriptCore.

Он имеет приятный SDK и имитирует некоторые вещи из Clojure, которых нет в ClojureScript, например, planck.io напоминаетclojure.java.io.Он поддерживает загрузку зависимостей через tools.deps.alpha / deps.edn.

Повтор stdin так же прост:

(require '[planck.core :refer [*in* slurp]])
(print (slurp *in*))

и печать аргументов командной строки:

(println *command-line-args*)

...

$ echo "foo" | planck stdin.cljs 1 2 3
foo
(1 2 3)

Пример автономного скрипта, т.е. не проекта, с зависимостями: инструмент командной строки tree в Planck .

Одно предостережение: Planck не поддерживает использование npmзависимостей.Поэтому, если вам это нужно, перейдите на Lumo , который предназначен для NodeJS.

Третьим вариантом будет joker , который является интерпретатором Clojure, написанным на Go.

0 голосов
/ 22 мая 2018

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

TLDR: перейдите к разделу «Создание исполняемой команды CLI» ниже

Справочная информация

У меня был почти такой же список требований, как вы делали некоторое время назад и приземлилсяна создание исполняемых файлов JAR.Я не говорю об исполняемых файлах через java -jar myfile.jar, а скорее о автономных uber-jar-файлах, которые вы можете запускать напрямую, как и при работе с любым другим двоичным файлом.

Если вы прочитали спецификацию zip-файла (к которой относятся jar-файлы, поскольку jar-файл является zip-файлом), оказывается, что это действительно возможно.Короткая версия заключается в том, что вам необходимо:

  • собрать толстый jar с необходимым вам материалом
  • вставить скрипт bash / bat / shell в двоичный контент jar в началеваш файл
  • chmod +x файл Uber JAR (или, если в Windows, установите флажок исполняемого файла)
  • переписать записи метаданных JAR-файла, чтобы вставленный текст скрипта не лишал законной силы почтовый индексвнутренние смещения файла

Следует отметить, что это фактически поддерживается спецификацией zip-файла.Вот как работают самораспаковывающиеся zip-файлы и т. Д., И получившийся толстый jar (после описанного выше процесса) по-прежнему является действительным jar-файлом и действительным zip-архивом.Все соответствующие команды, такие как java -jar, все еще работают, и файл теперь также исполняется непосредственно из командной строки.

Кроме того, следуя вышеприведенному шаблону, также можно добавить поддержку таких вещей, как drip jvm launcher , что значительно ускоряет время запуска ваших сценариев cli.

Как оказалось, когда я начал изучать это около года назад, библиотеки для последней точки перезаписи метаданных jar-файла не существовало.Не только в ближайшем будущем, но и на JVM в целом.Это все еще поражает воображение: центральная единица развертывания всех языков в jvm - это файл jar, и не было никакой библиотеки, которая фактически читала бы внутренние файлы jar.Внутренние компоненты, как в реальной структуре zip-файлов, а не только то, что делает ZipFile и друзья java.

Кроме того, я не смог найти библиотеку для clojure, которая имела бы дело с видом бинарной структуры, требуемой спецификацией zip-файла дляпуть.

Решение:

  • октет имеет то, что я считаю наиболее чистым интерфейсом из доступных двоичных библиотек для clojure, поэтому я написал запрос на извлечение октета , добавив поддержкуфункции, требуемые спецификацией zip-файла.
  • Затем я создал новую библиотеку clj-zip-meta , которая считывает и интерпретирует метаданные файла zip и может перезаписывать смещение, как описано в последнем пункте выше.
  • Затем я создал запрос на получение для существующей библиотеки clojure lein-binplus , чтобы добавить поддержку перезаписи zip-мета, реализованной с помощью clj-zip-meta, а также добавитьподдержка пользовательских сценариев преамбулы, позволяющих создавать реальные исполняемые файлы jar без необходимости java -jar.
  • После всего этого я создал шаблон leiningen cli-cmd для поддержки создания командных проектов cli, которые поддерживают все перечисленные выше функции и имеют хорошо структурированную настройку синтаксического анализа командной строки ... илито, что я считал хорошо структурированным:).Комментарии приветствуются.

Создание исполняемой команды CLI

Итак, вы можете создать новое приложение clojure для командной строки с leiningen и запустить его, используя:

~> lein new cli-cmd mycmd

~> cd mycmd

~> lein bin 

Compiling mycmd.core
Compiling mycmd.core
Created /home/mbjarland/tmp/clj-cmd/mycmd/target/mycmd-0.1.0-SNAPSHOT.jar
Created /home/mbjarland/tmp/clj-cmd/mycmd/target/mycmd-0.1.0-SNAPSHOT-standalone.jar
Creating standalone executable: /home/mbjarland/tmp/clj-cmd/mycmd/target/mycmd
Re-aligning zip offsets

~> target/mycmd 
---- debug output, remove for production code ----
options    {:port 80, :hostname "localhost", :verbosity 0}
arguments  []
errors     nil
summary    
   -p, --port PORT      80         Port number
  -H, --hostname HOST  localhost  Remote host
      --detach                    Detach from controlling process
  -v                              Verbosity level; may be specified multiple times to increase value
  -h, --help
--------------------------------------------------
This is my program. There are many like it, but this one is mine.

Usage: mycmd [options] action

Options:
  -p, --port PORT      80         Port number
  -H, --hostname HOST  localhost  Remote host
      --detach                    Detach from controlling process
  -v                              Verbosity level; may be specified multiple times to increase value
  -h, --help

Actions:
  start    Start a new server
  stop     Stop an existing server
  status   Print a server's status

Please refer to the manual page for more information.

Error: invalid action '' specified!   

Там, где выходные данные команды - это просто пример синтаксического анализа командной строки, который я добавил в шаблон leiningen.

Настраиваемый сценарий преамбулы находится по адресу boot/jar-preamble.sh и имеет поддержку функции drip.Другими словами, если у вас есть путь к файлу, сгенерированный исполняемый файл будет использовать его, в противном случае он вернется к стандартному java -jar способу запуска uber jar для внутреннего использования.

Исходный код для разбора командной строки и код для приложения cli находятся в каталоге src, как обычно.

Если вам захочется взломать, можно изменить сценарий преамбулы и повторно запустить lein bin, и новая преамбула будет вставлена ​​в ваш исполняемый файл в процессе сборки.

Также следует отметить, что этот метод все еще делает java -jar под одеялом, поэтому вам нужно нужна Java на вашем пути.

Ayway, многословное объяснение,но, надеюсь, это будет полезно для кого-то с этой проблемой.

0 голосов
/ 19 мая 2018

Рассмотрим Lumo , среду ClojureScript, которая была специально разработана для сценариев.

Обратите внимание, что, хотя она поддерживает зависимости как ClojureScript (JAR), так и NPM, поддержка зависимостей по-прежнему в разработке .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...