Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add cli entry point for ide #340

Merged
merged 4 commits into from
Oct 7, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

:profiles {:dev {:plugins [[lein-codox "0.10.7"]]
:dependencies [[org.clojure/clojure "1.10.1"]
[log4j/log4j "1.2.17"]]
[log4j/log4j "1.2.17"]
[org.clojure/tools.cli "1.0.194"]]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Судя по всему, org.clojure/tools.cli должна быть в основных зависимостях, а не только для разработки.


:resource-paths ["env/dev/resources"]

Expand Down
16 changes: 9 additions & 7 deletions src/etaoin/ide/flow.clj
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,17 @@
suite-tests))

(defn find-tests
[{:keys [test-id test-ids suite-id suite-ids test-name suite-name]}
[{:keys [test-id test-ids suite-id suite-ids test-name suite-name test-names suite-names]}
{:keys [tests] :as parsed-file}]
(let [test-ids (cond-> #{}
test-id (conj (first (filter #(= test-id (:id %)) tests)))
test-name (conj (first (filter #(= test-name (:name %)) tests)))
suite-id (into (get-tests-by-suite-id suite-id :id parsed-file))
suite-name (into (get-tests-by-suite-id suite-name :name parsed-file))
test-ids (into (filter #((set test-ids) (:id %)) tests))
suite-ids (into (mapcat #(get-tests-by-suite-id % :id parsed-file) suite-ids)))
test-id (conj (first (filter #(= test-id (:id %)) tests)))
test-name (conj (first (filter #(= test-name (:name %)) tests)))
suite-id (into (get-tests-by-suite-id suite-id :id parsed-file))
suite-name (into (get-tests-by-suite-id suite-name :name parsed-file))
test-ids (into (filter #((set test-ids) (:id %)) tests))
suite-ids (into (mapcat #(get-tests-by-suite-id % :id parsed-file) suite-ids))
test-names (into (filter #((set test-names) (:name %)) tests))
suite-names (into (mapcat #(get-tests-by-suite-id % :name parsed-file) suite-names)))
tests-found (filter test-ids tests)]
(if (empty? tests-found)
tests
Expand Down
99 changes: 95 additions & 4 deletions src/etaoin/ide/main.clj
Original file line number Diff line number Diff line change
@@ -1,8 +1,99 @@
(ns etaoin.ide.main
(:require [etaoin.api :refer :all]
[etaoin.ide.flow :refer [run-ide-script]])
(:require [clojure.tools.cli :refer [parse-opts summarize]]
[etaoin.api :refer :all]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нам точно нужно вкатывать все из etaoin.api? Может, лучше через алиас?

[etaoin.ide.flow :refer [run-ide-script]]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Здесь двойное объявление etaoin.ide.flow, только один раз с refer, а второй с алиасом. Их можно объединить:

[foo.bar :as bar :refer [...]]

и лучше просто оставить алиас flow, чтобы все вызовы были через него

[etaoin.ide.flow :as flow]

(flow/run-ide-script...)

[clojure.string :as str]
[clojure.java.io :as io]
[etaoin.ide.flow :as ide])
(:gen-class))

(defn str->vec
[string]
(str/split string #","))

(defn -main
[& args])
(def cli-options
[["-d" "--driver-name name" "The name of driver. The default is `chrome`"
:default :chrome
:parse-fn keyword
:validate [#(#{:chrome :safari :firefox :edge :phantom} %)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

тут можно просто оставить множество, потому что оно ведет себя как функция. Еще лучше будет вынести это множество на уровень модуля (как константу). Строку ниже со списком драйверов генерить в полете через (str/join ", " browsers-set)

"Must be one of the list items - chrome, safari, firefox, egde, phantom"]]

["-p" "--params params" "Parameters for the driver represented as edn string"
:default {}
:parse-fn read-string]

["-f" "--file path" "Path to the ide file on disk"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Т.е. уже после проверки аргументов мы берем файл или ресурс, проверяем и делаем System/exit, если что-то не так.

:validate [#(let [file (io/file %)]
(and (.exists file)
(not (.isDirectory file)))) "The IDE file not found"]]

["-r" "--resource path" "Path to the resource"
:parse-fn #(-> % io/resource str)
:validate [#(not (str/blank? %)) "Resource not found"]]

[nil "--test-ids" "Comma-separeted test ID(s)"
:parse-fn str->vec]

[nil "--suite-ids" "Comma-separeted suite ID(s)"
:parse-fn str->vec]

[nil "--test-name" "Comma-separeted test name(s)"
:parse-fn str->vec]

[nil "--suite-name" "Comma-separeted suite name(s)"
:parse-fn str->vec]

[nil "--base-url" "Base url for test"]
["-h" "--help"]])

(defn usage [options-summary]
(->> ["This is cli interface for running ide files."
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут же можно и через одну строку без склейки вектора? Будет меньше шума из-за кавычек.

"
Usage:

Example:

"

""
"Usage:"
"Required parameter is the path to the ide file. `--file` or `--resource`"
""
"lein run -m etaoin.ide.main -d firefox -p '{:port 8888 :args [\"--no-sandbox\"]} -r ide/test.side'"
""
"java -cp .../poject.jar -m etaoin.ide.main -d firefox -p '{:port 8888} -f ide/test.side'"
""
"Options:"
options-summary]
(str/join \newline)))

(defn error-msg [errors]
(str "The following errors occurred while parsing your command:\n\n"
(str/join \newline errors)))

(defn validate-args
[args]
(let [{:keys [options errors summary]} (parse-opts args cli-options)]
(cond
(:help options)
{:exit-message (usage summary) :ok? true}

errors
{:exit-message (error-msg errors)}

(or (:file options)
(:resource options))
{:options options}

:else
{:exit-message (usage summary)})))

(defn exit [status msg]
(println msg)
(System/exit status))

(defn -main [& args]
(let [{:keys [options exit-message ok?]} (validate-args args)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

тут можно подупростить:

  1. Парсим арументы, получаем [options errors summary]
  2. Если были errors, выходим с 1
  3. Если help, показываем сообщение и выходим с 0
  4. Выбираем file или resource. Если нет ничего, выходим с 1. Проверяем на наличие, если нет, выходим с 0
  5. Запускаем скрипт

Т.е. чуть что не так, вызываем exit.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно добавить в util функцию

(defn exit
  [code template & args]
  (let [out (if (zero? code)
              *out*
              *err*)]
    (binding [*out* out]
      (println (apply format
        template args))))
  (System/exit code))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Она учитывает канал вывода в зависимости от кода, плюс форматирует сообщеньку.

(if exit-message
(exit (if ok? 0 1) exit-message)
(let [{:keys [driver-name params file resource]} options
opt (select-keys options [:base-url :test-ids
:test-names :suite-ids
:suite-names])
file-path (or file
resource)]
(with-driver driver-name params driver
(run-ide-script driver file-path opt))))))