svn + bash =コンソールsvnブラウザーを書く

コマンドラインでsvnを使用する人、およびbashスクリプトのプログラミングに興味がある人のために、このトピックでは、ターミナルで動作し、リポジトリツリーで複数の「毎日」の操作を実行できるインタラクティブなbashスクリプト「svn browser」の作成例を説明します、すなわち:さらに、操作は1つまたは2つのボタンを押すだけで行われ、コメントの入力はカウントされません。また、次のような長いパスを覚えたり入力したりする必要はありません。<br> <br>
$svn cp "http://workserver.com/_main_repository/embedded_system/product_xxx/_trunk/main_task/ http://workserver.com/_main_repository/embedded_system/product_xxx/_tags/" 

猫の下、内部の概要、結果はsvnbでダウンロードできます。
実行可能にし、ディレクトリで実行します-svnの作業コピー(どこでも実行できますが、作業するリポジトリへのパスを入力する必要があります)。

PS記事の最後に、コマンドラインsvn- path completionの使いやすさを改善する別のソリューションを追加しました。

なんで?


Subversion(svn)は、ソフトウェア開発者などによってよく使用される一般的なバージョン管理システムです。 これを使用するには、TortoiseSVN、rapidSVNなどのGUIアプリケーションがあります。 これらは、とりわけ、エクスプローラー/ウィンドウマネージャー/ファイルブラウザーと統合されています。

何と言っても便利ですが、GUIは必ずしも適切ではありません。サーバー上のsshでの作業、Xサーバーの欠如、使用できないGUIを使用したくないという当たり障りな欲求-コマンドラインが大好きです)。 コマンドラインでは、次のようなパスにアクセスできます。

 $svn up # update   
 $svn ci -m"  " #  
 $svn log #      

とても快適です!
しかし、1つの「しかし」、たとえば、コメントやファイルのリストを表示するためにリポジトリにある別のディレクトリを操作する必要があるとすぐに、目的のディレクトリへのリポジトリファイルシステムのパス+リポジトリへのパスでsvnユーティリティを呼び出す必要があります:

 $svn list (log) "http://workserver.com/_main_repository/embedded_system/product_xxx/_tags/" 
 $svn cp "http://workserver.com/_main_repository/embedded_system/product_xxx/_trunk/main_task/ http://workserver.com/_main_repository/embedded_system/product_xxx/_tags/" 

リポジトリへのパスとリポジトリ内の作業コピーへのパスを覚える必要がなく、ルートから目的のディレクトリへのsvnリストの束を作成することは、svn path引数にファイル名のオートコンプリートがないために不便であるため、それ自体はあまり便利ではありません。


どうする


svnの作業コピーには、ディレクトリ.svn /があります。このディレクトリには、他の役に立たないゴミの中に、リポジトリと作業コピーへの絶対パスを含む文字列を含むファイル.svn / entriesがあります。 これを確認するのは簡単です:

 $cat .svn/entries | grep :// 

絶対パスがありますが、これでは十分ではありません。このコマンドを使用して目的のパスをコピーし、svnコマンドで操作を実行することがよくありましたが、プロセスを自動化できます。 これらのパスを自動的に取得し、リポジトリ内のファイル/ディレクトリのリストを表示し、これらのパスを必要な操作に使用できる特定のユーティリティまたはスクリプトを作成した。


書いています!


体の動きを最小限に抑え、ログの表示やエクスポート、ディレクトリの作成/削除、svnを使用したタグ/ブランチの作成などの操作を可能にする、 非常にシンプルで直感的何かを書きたいと思います。

私は、起動時に制御自体を返さないが、インタラクティブなアプリケーションとして機能するbashスクリプトを作成することにしました。 svn関数が「ハング」しているボタンの押下をキャッチし、結果を画面に描画します。

機能:

必要な制御コマンドを定義します。
ボタンはスクリプトの最初に定義されており、好みに合わせて再定義できます

exportおよびcheckoutコマンドの場合、入力されたパスの先頭に$ HOME変数を追加して、毎回/ home / username /を入力する必要がないようにします。

「終了」コマンドにより、スクリプトは、リポジトリ内のディレクトリへのパスを表示して終了します。 スクリプトが実行できないコマンドラインで操作を実行する必要がある場合、少なくとも長いパスを駆動できず、数十のsvn listを実行できません。 目的のパスに移動し、「終了」コマンド( q uit)でスクリプトを閉じて、表示されたパスをコピーします。

キャプチャされたボタン

キーボードを読み取るには、ボタン入力のための無限の待機ループが必要です。このため、次の設計を使用します。

 ############     ############# 233 #   stdin, -s  , -n1    234 while read -s -n1 key 235 do ... 281 done 

readコマンドは、行全体を読み取ってEnterが押されるのを待つ場合にのみ制御を返しますが、各ボタンが押された後にEnterを押したくありません。 -nNスイッチは、 Enterを待たずにN文字を読み取った後に制御を返すようにreadコマンドに指示します 。 エコーも必要ありません( -sキー)。必要なものはすべて画面に表示します。 :D

カーソルキー

ターミナルのカーソルキー(およびDelete、Insertなどの他の特殊キー)は、3文字で構成される特殊なエスケープシーケンスによって送信されます。
^ [A-上矢印
^ [B-下矢印
^ [C-右矢印
^ [D-左矢印

opennet.ruには、読み取りに3文字が使用される例があります( 読み取りコマンドの-n3スイッチ )。これは、スクリプトが単一(通常のasci)文字に応答しない場合に便利であり、この場合は受け入れられません。

ESCシンボルを受信するときに設定し、シーケンスの残りの2文字を受信するときにインクリメントし、その後0にフォールドして対応する処理関数を呼び出すフラグ変数を設定しますが、不要なクリックとシーケンスはすべて無視します。上記のリスト。

スクリプトコードのESC-文字は、端末(またはコンソールエディターのvim、nano)に入力するために^ [として記述され、Ctrl + Vを押してからEscを押します。

 378 if [ "$key" == "^[" ] #   ESC- 379 then 380 cursor_ind="1" #    1 381 elif [[ "$key" == "[" && $cursor_ind == "1" ]] #   2  ESC- 382 then 383 cursor_ind="2" #    2 384 elif [[ "$key" == "A" && $cursor_ind == "2" ]] #   3 ()  ESC-,     "". 385 then 386 cursor_ind="0" #   387 menu_up #  .   

興味のあるすべてのボタンコードについても同様です。

機能

スクリプトを記述するとき、コードの繰り返し部分または意味の異なる部分は、便利に関数でフォーマットされます。これは単純に行われます。
例:1つの引数をとる関数(変数$ 1を介して)

 40 ###########    ############### 41 function svn_get_list { 42 SVN_LIST="`svn list $SVN_REPO_PATH/$1`" 43 } 

関数呼び出し(パラメーターで変数を渡す):

 133 svn_get_list "$SVN_PATH_PTR" 

関数は1つ以上の引数を取ることができますが、これは何らかの方法で制御されません。そのため、関数が引数を必要とし、引数なしで呼び出すと、期待どおりに機能しなかったり、エラーや警告がスローされたりすることさえあります

スクリーン

画面への出力はechoコマンドによって実行され、必要なものすべてを順番に描画します。次の画面を描画する前に、画面を消去する必要があります。これには、 明確なシェルコマンドがあります。
画面は毎回再描画する必要があります。カーソルが移動した場合でも、出力には時間がかかり、視覚的には目立つため、何もできません。

スタイル:

便宜上、ディレクトリは太字で表示され、カーソル(現在選択されているディレクトリは逆です)。 繰り返しになりますが、ESCシーケンスを使用してターミナルのフォントスタイルを制御できます。次に例を示します。

 echo "^[[1m   ^[[0m  ." 

出力されます:
太字 、通常のテキスト
ターミナルのテキストを使って多くのことができ、色付け、反転、点滅などができます 。ターミナルの色とスタイルの詳細については、 こちらをご覧ください

実行中のスクリプトは次のようになります。

Bash svn browser v1.1。 使用法: h elp、 q uit、 y copy、 x cut、paste、log、remane、 d elete、 m akedir、 e xport、 c heckout。
--------------------------
現在地[http:// xxxxxxx / xxxxx / _WorkServer]:/ _ main_task /ブートローダー/ _trunk /

============
Changelog.txt
License.txt
Readme.txt
コマンドライン/
ファームウェア/
============

これは端末からコピーされたテキストです。すべてがテキストコンソールであるため、私は写真を作成しませんでした。オリジナルとの唯一の違いは、カーソルがあり、テキストが反転していることです。

ページ:

バージョン管理下のリポジトリに多くのファイルがある場合、それらのリストは画面に収まらない可能性が高く、ターミナルをスキップすることは最も美しい解決策ではありません。 $ tput linesコマンドがエイドに戻り、高さの端末行の数を返します。 画面への各出力の前に、この値を見つけ、「常に存在する」行の数の場所を取り去ります(確保します)。

 187 LINE_PER_PAGE=$((`tput lines` - 8)) 

行数が制限を超えている場合、bashでの算術を使用した簡単な操作で、リストはページに分割され、PgUp / PgDownボタンでスクロールできます。

パイプ

多くの人々はパイプまたは「パイプ」が何であるかを知っています。それは、あるものの出力を他の何かと関連付ける便利な方法です。私は意図的にユーティリティを言いませんでした。 パイプはbashコマンドをリンクすることもできます。 なぜ私はそれらについて話しましたか? 私は1つの興味深い機能に出くわしたので:
パイプを介して何かが呼び出されると、シェルの子インスタンス、いわゆるサブシェルが作成されます。 そしてコツは、親シェルのすべての変数が子に表示されますが、子には親シェルすべての変数のローカルコピーがあり、値を「グローバルに」変更できないことです。 つまり 彼らの助けを借りて何も返すことはできません!
例として、画面にファイルのリストを表示する機能を考えてみましょう。

 106 ############     ############# 107 function menu_print_list { 108 109 echo "$SVN_LIST" | while read line 110 do 111 if [ "`expr "$line" : '.*/$'`" -ne "0" ] #    112 then 113 if [[ "$CNT" -eq "$V_CURSOR" ]] #       -   114 then 115 echo "^[[7m^[[1m$line^[[0m" 116 else 117 echo "^[[1m$line^[[0m" 118 fi 119 else 120 if [[ "$CNT" -eq "$V_CURSOR" ]] #       -   121 then 122 echo "^[[7m$line^[[0m" 123 else 124 echo "^[[0m$line^[[0m" 125 fi 126 fi 127 CNT=`expr $CNT + 1` 128 done 129 } 

関数は、目的の行にカーソルを表示するために、カーソルが置かれている行番号を知っている必要があり、さらに、等価条件が満たされたときに行カウンターを持っている必要があります(行113)行のテキストを反転します。 カーソルが設定されました。
関数の最後に、将来(リストからの脱出を制御するためのカーソル移動関数)に役立つ行数( CNT変数)が常にわかっています。
しかし、カウンター値を返すことはできません! パイプの右側にあるブロックを終了するとすぐに(行109)、 CNT変数はパイプが作成される前と同じ値を取ります。
行数をカウントするためだけに別の関数を作成することを除いて、他の解決策はわかりません。その結果、 ehcoパイプの外側の変数になり、ブロックの結果を引用符で囲まれたパイプで呼び出して、親シェルを変数に割り当てます:

 65 #######  -    ########## 66 function menu_get_dir_cnt { 67 DIR_CNT=0 68 DIR_CNT="`echo "$SVN_LIST" | ( while read line 69 do 70 ((DIR_CNT++)) 71 done; echo $DIR_CNT)`" 72 } 
おもしろいですが、コードパーサーはこの設計に対応しておらず、vimではちなみに、バックライトもそれに合わせて強調表示しませんでした;)

アルゴリズム

すべてのスクリプトアルゴリズムは非常に単純であり、興味のある人は簡単に理解できます。 要するに。

.svnディレクトリがあるかどうかを確認します。ある場合は、作業コピーにあり、リポジトリに関する情報を取得します(リポジトリとその中の作業コピーへの絶対パス)。 .svnディレクトリが見つからない場合は、リポジトリへのパスを入力してください。

ナビゲーション:

「カーソル左」 -すべてが単純です。作業レベルへのパスを含む変数でルートレベルに移動する必要があります。最後から「/」スラッシュまですべてをカットし、 svn listコマンドの出力を結果のパスとともに出力します。 便宜上、先ほど残したディレクトリにカーソルを置いておくといいでしょう。「カットオフ」テールを「記憶」し、リストで見つけてカーソルを置くと簡単にできます。

「右のカーソル」 -現在のパスにカーソルのある場所を追加します(同時に、これがファイルではなくディレクトリであることを確認します。ファイルに移動できないため=)、最後のディレクトリには「/」があります) 、受信したパスでsvn listコマンドの出力を表示します。

チーム:

「コピー/カット」をクリックしました-パスを覚えておいてください

「貼り付け」をクリックしました-cp / mvコマンドと前のコマンドで保存したパスを使用してsvnユーティリティを呼び出します。

「ログの表示/削除/名前の変更/エクスポート/抽出」をクリックしました-リポジトリの現在のパスに対してコマンドlog / rm / mv / export / coを使用してsvnユーティリティを呼び出し、必要に応じて、追加のパラメーター(新しい名前(名前の変更)、コメント)

チェックアウトおよびエクスポートコマンドの場合、パスの先頭に、宛先パスとして$ HOMEホームディレクトリ内のパスを自動的に入力する必要があります。
/ home / user_name / src / my_proj
src / my_proj-右))

藤堂

私が望んでいたことはすべて行われました。
おそらくコメントで、親愛なる読者は、他に何が実装されるべきか提案しますか? ;)
外部エディターの立ち上げにより、mergとdiffについて検討する予定です。 しかし、運用は「毎日」ではなく、集中と注意が必要です。

スクリプトで電子メールで提案やバグを送信します。

おわりに

スクリプトは便利であることが判明しました。私は毎日自宅や職場で使用しています。 おそらくそれは理想的であり、bash-scripting canonとはほど遠いでしょう。 さらに、おそらくこれは「自転車建設」ですが、 発明するためにそれはとても素晴らしいです! )

svnb v1.2をダウンロード
ダウンロードして、実行可能ファイルを作成し、作業コピーディレクトリで実行します。
便宜上、/ usr / local / bin /にコピーできます
ハムスターに.binディレクトリを作成し、それを$ PATHに追加して、そこにスクリプトを保存することをお勧めします)

代替オプション



考えてグーグルで調べた後、パスの自動補完を行うことにしました。この機能により多くの問題が解決され、リポジトリでのサーフィンはホームディレクトリでの操作と同じくらい快適だからです。
私はこのスクリプトを見つけテストしました-それはパスを補完しますが、パスを補完しません... man bashとインターネットを読んで、パスの補完を台無しにして、結果をダウンロードできます:

ダウンロードbash_completion_svn
別のものを置き、そのソースを実行します
 $source bash_completion_svn 
この行を.bashrcの最後に追加すると、bashの開始時に自動的に実行されます。
使用する
$ svn listと入力し 、[TAB]を押すと、現在の作業コピーにパスが追加されます。その後、すべてが通常どおりです))、[TAB]を押して、お楽しみください)。

使用素材

Opennet.ruシェルスクリプト技術

ご清聴ありがとうございました!

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


All Articles