Groovy用のPythonコマンドアナログ

Groovy&Grailsで自分用の小さなプロジェクトを作成する過程で、さまざまなシェルスクリプトをすべて使用することが急務でした。 新しく作成されたプロジェクトを再インストールした後、サーバーを再起動し、どこからでもログを収集し、構成などの新しいバージョンを入力します。 最初はすべてをbashスクリプトで記述しましたが、ペットプロジェクトに加えてそれを使用しているため、必要な関数、構文規則などをインターネット上で長時間検索するたびに非常にまれです。 、プロジェクト自体の開発が大幅に遅くなりました。

そして、Groovyはすでにプログラミング言語に精通していたので、それを書くことにしました。 しかし、実際には膨大な数の* .groovyファイルを作成したくはありませんでしたが、逆に、必要なコマンドがすべて含まれている1つのバックエンド制御スクリプトを作成して、表示するコマンドの機能と履歴、および必要に応じて新しいコマンドを設定して簡単に追加するために連続して実行されるコマンドのチェーン。 このウィッシュリストは、私がかつてPythonをマスターしたときに使用したcmdを思い出したためにまだ表示されています。 しかし、誰もGroovy用のそのようなコマンドを書いていないことがわかりました(後で私も理由を理解しました)、それが次の自転車建築業界 、つまりGroovyアプリケーション用の小さなCliフレームワークを作成するように促しました。

この投稿の目的は、私の「フレームワーク」を補完する客観的な批判と提案を得ることです。おそらくすべてのコードとすべてのドキュメントをbitbacketアカウントに投稿したので、誰かがそれを使用したいかもしれません。

基本


それはすべて、著者がPythonのcmdの使用方法を説明した1つの記事から始まりました。実際、私は努力をあまりせず、抽象クラスCmd.groovyが存在する同じ機能について実装しました。 簡単な例:

cli.groovyファイル:

class MyCli extends Cmd { boolean do_hello(String[] args) { if (args.length == 0) { println('Hello world!'); } else { args.each { println("Hello ${it}!"); } } return true; } } def cli = new MyCli(); if (this.args.length > 0) { cli.execute(this.args); } else { cli.start(); } 


コンソールコマンドとして使用する各メソッドには、厳密な署名が必要です。



メソッドが接頭辞「 do_ 」で始まるが、上記の条件のいずれも満たさない場合、プログラムはメソッドがコマンドのリストに含まれていない理由とその修正方法を説明する警告を発行します。

クラスのインスタンスを作成したら、次の2つの方法で開始できます。

1) " execute(String []) "メソッドを呼び出して、そこにユーザー引数を渡します。 この場合、オブジェクトは呼び出し中に受信したすべてのコマンドを実行し、実行を完了します。

 $ groovy -cp . cli.groovy help List of all available commands: (for reference on command print "help <command_name>") history - prints history of commands hello - No description help - prints commands info exit - for exit from CMD 


2)「 start() 」メソッドを呼び出して、対話型入力ループを起動します。 この場合、コマンドを入力するための挨拶と「招待」が端末に表示されます。 入力サイクルの実行は、ユーザーが「 exit 」を入力するまで続きます。

 $ groovy -cp . cli.groovy Welcome Print "help" for reference cmd:> help List of all available commands: (for reference on command print "help <command_name>") history - prints history of commands hello - No description help - prints commands info exit - for exit from CMD cmd:> exit Goodbye! $ _ 


また、 @ Descriptionアノテーションをメソッドに追加できます。これには、メソッドの簡単で完全な説明が含まれます。

 class MyCli extends Cmd { @Description( brief='prints greetings', full='prints greetins for all setted arguments, if arguments list is empty prints default message "Hello world!"' ) boolean do_hello(String[] args) { if (args.length == 0) { println('Hello world!'); } else { args.each { println("Hello ${it}!"); } } return true; } } 


このようなプログラムを実行すると、コマンドのヒントを要求できます。

 cmd:> help hello Command info ('hello'): prints greetins for all setted arguments, if arguments list is empty prints default message "Hello world!" 


チェーン


必要に応じて、単に「 + 」記号を追加するだけで、チームをチェーンにまとめることができます。

 cmd:> hello Liza + hello Artem Hello Liza! Hello Artem! cmd:> _ 


プログラムをすぐに開始したとき、 シェルは引数を設定するだけでなく、別のコマンドを呼び出そうとしていると考えたため、正規の二重アンパサンドの代わりに「 + 」記号が使用され始めました。

 //   , shell    hello   $ groovy -cp . cli.groovy hello Liza && hello Artem //      $ groovy -cp . cli.groovy hello Liza + hello Artem 


コマンドがfalseを返すと、チェーンが壊れることが予想されます

 $ groovy -cp . cli.groovy hello Liza + popa + hello Artem Hello Liza! ERROR: No such command 'popa' List of all available commands: (for reference on command print "help <command_name>") history - prints history of commands hello - No description help - prints commands info exit - for exit from CMD 


「Hello Artem!」このような起動は出力されません。

ローカリゼーション


出力のテキスト全体が変数に詰め込まれ、必要に応じて、次のように値を変更できます。

 class MyCli extends Cmd { MyCli() { super(); PROMPT = '$> '; } boolean do_hello(String[] args) { if (args.length == 0) { println('Hello world!'); } else { args.each { println("Hello ${it}!"); } } return true; } } def cli = new MyCli(); if (this.args.length > 0) { cli.execute(this.args); } else { cli.start(); } 


このようなプログラムを起動すると、標準の「 cmd:> 」ではなく「 $> 」ではなく、入力を促す修正されたプレフィックスが取得されます。

 $ groovy -cp . cli.groovy Welcome Print "help" for reference $> _ 


ローカライズ用の変数とそのデフォルト値についての詳細は、 特別なWikiページで確認できます

シェルコマンドの実行


また、1つの静的な応答実行(文字列)メソッドのみを持つシェルヘルパークラスを使用することもできます。 クラスのこのメソッドに文字列を渡すと、2つのフィールドを持つResponseクラスのインスタンスが取得されます。

  1. hasError-シェルでのコマンドの成功を示すフラグ
  2. out-コマンドの結果


たとえば、これは現在のディレクトリへのパスを表示するコマンドのように見えるかもしれません:

 boolean do_pwd(String[] args) { if (args.length != 0) { println('ERROR: this method doesn\'t have any arguments'); return false; } Response response = Shell.execute('pwd'); if (!response.hasError) { println(response.out); return true; } else { println("ERROR: ${response.out}"); return false; } } 


コマンド入力履歴


一番大変でした。 私が理解している限りでは、Java(および、それに応じてGroovy)は、少なくともLinuxバージョンのJVMで、ターミナル内のI / Oといわば非常に緊張した関係を持っています(他では試していません)。 たとえば、標準では、キーボード上の矢印で入力カーソルを移動することは不可能であることを意味します。ごみはala "^ [[C ^ [[D ^ [[A ^ [[B"]、たとえば、Tabやその他

回避策は、すべてのさまざまなJavaライブラリの形式であり、私が理解しているように、端末入力およびJavaラッパークラスを操作するためのC / C ++コードのみが含まれています。 小さなスクリプトの場合、OSに応じてファイルのjarファイルをドラッグするのは少し多すぎますが、同時に、たとえば、コマンドの履歴を表示したり、履歴から選択したコマンドの引数のリストを変更したりする機能が必要でした。 このために、私は自転車で自転車を書きました。

 Welcome Print "help" for reference cmd:> help List of all available commands: (for reference on command print "help <command_name>") help - prints commands info exit - for exit from CMD cmd:> !! <-    nix',    cmd:> help | _ 


| 」記号は、コマンド引数リストを編集できることを示しています。 Enterキーを押すだけで、インタープリターがコマンドを実行します。 「 q 」と入力すると、編集がキャンセルされます。 そして、これを行うことができます。

 cmd:> help | exit <-      cmd:> help exit | +1=hello <-       cmd:> help hello | -1 <-    


引数の変更を十分に行った後、最後にEnterキーを押すと、インタープリターがコマンドを実行し、コマンド履歴に書き込みます。

これについては、この無限に長い投稿を終了します参照によって、私の詐欺師は私のリポジトリで自由に利用できるとだけ言います

私はあなたから客観的な批判と、おそらく「フレームワーク」を補うための提案を聞きたいです。

PS:ところで、私はこの「フレームワーク」の助けを借りて、サーバーを管理するためのスクリプトだけでなく、職場でも同様のタスクに役立ちました。

PSS:LinuxのJavaのコンソールから入力の問題を解決する方法を知っている人がいれば、共有してください。

Source: https://habr.com/ru/post/J212457/


All Articles