2012/03/04

Windowsから複数の端末を操作する環境(Cygwin + Cygterm + Putty + GNU Screen)



ホストマシンはWindowsだけど、リモートのLinux上で作業するためのリモートシェル環境。
XWindowはまだ未考慮。まぁOracleインストールするときに慌ててXmingw立てるぐらいなもので、あまり頻度がないからまじめに整備する気が起きない。

今回の環境
ホストOS:  Windows7 x64
リモートOS:  CentOS6.4

達成したい機能

・Windowsからsshでlinuxにリモートログインして、zshで作業。
・ホストOSを一度シャットダウンしても元の作業状態に戻れる。
・画面複数分割 
 複数台に入って同時並行で作業したい、emacsで手順を参照したりメモしたりしたいときのため。
 複数Windowを立ち上げる形式は、個人的に迷子になりがちなので回避。



使用するもの

[Windows]
  1. cygwin  1.7.1 http://www.cygwin.com/ 
  2. putty-gdi  http://ice.hotmint.com/putty/  ターミナルエミュレータ。個人的に手に馴染んではいるが、今回の構成での必然性はない。
  3. cygterm  http://www.dd.iij4u.or.jp/~nsym/cygwin/cygterm/  telentリスナーを空けたcygwinを立ち上げて、さらにこれに接続した状態のターミナルエミュレータを起動する。
[CentOS]
  1. gnu screen  4.1.0  http://www.gnu.org/software/screen/  画面の分割、作業状態の保存・復元(アタッチ・デタッチ)。こいつはゲストOS側に用意。

手順
[Windows]
1. cygwin
何も考えずに最新(Cygwin1.7)を入れる。

導入パッケージは下記を除いて随意に。
cygtermのビルドに必要なもの。

・tar
・make
・gcc

2. putty
GDIで描画してくれるバージョンを突っ込む。
http://ice.hotmint.com/putty/
Windows x64で使うので、putty/x64の*.exeで、putty/の実行ファイルを上書きする。

続いてcygwin実行時に使用するセッションを作成。
セッション名は"cygterm"で。

その他設定項目は、以下の形で設定。
  • セッション>ホスト名: 127.0.0.1
  • セッション>接続タイプ: Telnet
  • 端末>ローカルエコー: 強制的にオフ
  • 端末>ローカルライン編集: 強制的にオフ
  • ウィンドウ>変換>文字セット: UTF-8
  • 接続>データ>端末タイプを表す文字列 xterm

3. cygterm
http://www.dd.iij4u.or.jp/~nsym/cygwin/cygterm/
tarとgccとmakeが必要。全部cygwinに入ってるからよしなに。 からダウンロード、解凍、make, make install。
tar xvfz cygterm107.tgz
cd cygterm
make
#今回は、cygterm.exeとcygterm.cfgを手動でcygwin/binに移動した。
cygterm.cfgの内容
TERM = {puttyをおいた場所}\putty.exe -load "cygterm" telnet://%s:%d/
TERM_TYPE = xterm
PORT_START = 20000
PORT_RANGE = 40
SHELL = /bin/zsh -l -i
ENV_1 = MAKE_MODE=unix
ENV_2 = HOME=/home/{ユーザ名}


[CentOS]
# この辺は事前状態によりけり
yum install git
yum install autoconf
yum install ncurses-devel
yum install texinfo
git clone git://git.savannah.gnu.org/screen.git
cd screen/src
autoconf
autoheader
./configure --prefix=/usr/local --enable-colors256
make
make install
vim ~/.screenrc

attrcolor b ".I"
term xterm
escape ^Zz
zombie ^[
altscreen on
shell /bin/zsh
defscrollback 5000
autodetach on
startup_message off
logfile "$HOME/.screen/screen-%Y%m%d-%n.log"
caption always "%{= Rk} %?%F%{b kr}%? %?%h%:%t (screen #%n)%? %{-}"
hardstatus alwayslastline "%{= Gk} %-Lw%40L>%{b kg} %n %t %{-}%+Lw%-040=%{b km} %l %{.b} %Y/%m/%d %C:%s %A "
sorendition "= Rk"


※アレー、最新ソースなのにCtrl-Z Vで縦分割でないよでないよー
ってやってたらCtrl-Z | にバインドされてた。恥ずかしい。

[ついで]
puttyの英文はConsolasにしておきたい。
けど、日本語がつぶれるのも困る場合。
ここでは、Consolasの日本を表示をOsaka-等幅にリンクさせる。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink
新規>複数行文字列値> "Consolas"
値>665ttc2.ttc,Osaka-等幅

まだ日本語が汚いのでどうにかしたいところ。

JavaScriptのモジュールファイル群の読み込み管理をどうしよう。(2)

全体で共通的に使うモジュールではなく、htmlごとのイベントハンドラ等の初期化スクリプトをどうするか。

前提条件
  • 画面全体は遷移しない。htmlを非同期ロードして一部のdivエリアの置き換えを行う。
    便宜上最初に読み込まれるhtmlを親画面、非同期ロードされる側を子画面と呼ぶ。
  • 親画面は、子画面の初期化に必要なものが何か知らない。どのhtmlを呼ぶかは知らない。
  • 親画面1つに対して、子画面を複数ロードしない。
ファイル構成
  • test.html 親画面
  • test.js 親画面初期化スクリプト
  • screenManager.js 子画面置き換え処理スクリプト
  • subscreen
    • subscreen.html 子画面
    • subscreen.js 子画面初期化スクリプト

概要
  • 子画面は必要とするjavascriptファイルのURLを値に持つhiddenフィールドを持つ
  • 子画面置き換え処理スクリプトは、上記のhiddenフィールド値を参照して、javascriptファイルを取得する
イケてない
  • javascriptファイルのURLを相対パスで書く場合、その基準位置は子画面htmlではない。
  • 子画面初期化スクリプトが、遷移の度にロードされる。
  • CommonJSとかClosureを使えよ。

親画面(test.html)
<html>
  <head>
  </head>
  <body>
    <div class="subScreenArea">
      <p>initial contents</p>
    </div>
    <input type="button" id="changeScreen" value="screenChange" /> <br>
    <input type="text" id="loginId" />
      <input type="button" id="completing" value="completing" />
 <div id="scriptDeclaration">
   <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
   <script src="module.js"></script>
   <script src="test.js"></script>
 </div>
  </body>
</html>

親画面初期化スクリプト(test.js)
var mymodule = mymodule || {};
mymodule.require('./screenManager.js');
mymodule.require('./completed.js');
$(function(){
    $('#completing').click(function(){
 $('#loginId').val(mymodule.compl.getCompletedScript());
    });
    $('#changeScreen').click(function(){
 mymodule.scr.change('subscreen/subscreen.html');
    });
});

子画面(subscreen/subscreen.html)
<html>
  <head>
  </head>
  <body>
    <div class="subscreenArea">
      <input type="text" id="subText">
      <input type="button" id="subButton" value="Push">
      <input type="hidden" class="requireScript" value="./subscreen/subscreen.js">
    </div>
  </body>
</html>
子画面初期化スクリプト(subscreen/subscreen.js)
$(function(){
    console.log('require script loaded.');
    $('#subButton').click(function(){
 $('#subText').val('clicked');
    });
});

子画面取得スクリプト(screenManager.js)
function ScreenManager(){
    console.log('ScreenManager is loaded.');
    this.screenClass = 'subScreenArea';
}

ScreenManager.prototype.change = function(url){
    $('.' + this.screenClass).load(url + ' .' + this.screenClass, function(){
           $.each($(this).find('input.requireScript'), function(){
        console.log('loading ' + $(this).val());
        $.getScript($(this).val());
           });
       });
};

var mymodule = mymodule || {};
mymodule.scr = new ScreenManager();