数時間の空き時間が職場に現れ、私は自分自身の生活を楽にすることに決めました。
職業(と私はプログラマーとして)によって、リモートサーバー上でやることがたくさんあり、ssh経由でのみアクセスできます。 また、プログラムをローカルで記述してデバッグし、それを動作中のマシンに置くのが最も便利です。 したがって、sshfsを使用すると便利です。 しかし、毎回mountコマンドを入力するのはうんざりです。タワーでスクリプトを書くのは面倒です。 そのため、sshfsマウントグラフィカルマネージャー、およびKDE4の他のすべてのものが必要でした。
代替案
当然、彼は自分で書いてから、最後まで抵抗しました。 Googleが答えをくれました。 しかし、適切なものは見つかりませんでした。
KDE3でのみ何らかの理由で獲得したksshfs
sshfsguiも
動作を望みませんでした。いくつかのJavaエラーが挙げられました。 yavamashinのいくつかの異なるバージョンと実装を試してみました-助けにはなりませんでした。
自分でやらなければなりません。
読む
まず、KDE4用のアプリケーションをどのように作成しますか? この知識は、
「Programming for KDE4」という記事から学びました。
残りは
ドキュメントによって助けられました。
フレーム
インターフェイスの観点から、私はsshfsguiに焦点を合わせました。 ここから始めます。
まず、アプリケーションのフレームワークを使用します。
PyKDE4 から 。 kdeui import KApplication 、 KMainWindow 、 KPushButton 、 KHBox 、 KVBox 、 KLineEdit 、 KListWidget
PyKDE4 から 。 kdecore import i18n 、 ki18n 、 KAboutData 、 KCmdLineArgs
PyQt4 から QtCoreを インポート
PyQt4 から 。 QtGui import Qlabel
インポートシステム
クラス pyksshfsWindow ( KMainWindow ) :
selected_name = False
def __init__ (self、parent = None) :#constructor
KMainWindow 。 __init__ ( self 、 parent ) #親コンストラクターを呼び出す
appName = "pyksshfs"
カタログ = ""
programName = ki18n ( "PyKSshfs" )
バージョン = "0.1"
description = ki18n ( 「 sshfs を使用するためのGUIアプリケーション」 )
ライセンス = KAboutData License_GPL
copyright = ki18n ( "©Akademic" )
テキスト = ki18n ( "none" )
homePage = "プログラムサイト"
bugEmail = "エラーについて作成者と通信するためのメール"
aboutData = KAboutData ( appName 、 catalog 、 programName 、 version 、 description 、 license 、 copyright 、 text 、 homePage 、 bugEmail )
KCmdLineArgs 。 init ( sys。argv 、 aboutData )
app = KApplication ( )
w = pyksshfsWindow ( )
w 表示 ( )
アプリ exec_ ( )
私は一つのことを言います-それはすでに発売されており、この考えは私の心を温めます。 次のようになります。

インターフェース
プログラムは2時間で、実際に単純なので、インターフェイスに関連するすべてのものを__init__メソッドに配置しました。 Qt Designerで苦しむのではなく、コードを書くだけです。
次のようになります。
def __init__ ( self 、 parent = None ) : #constructor
KMainWindow 。 __init__ ( self 、 parent ) #親コンストラクターを呼び出す
hbox = KHBox ( self ) #水平レイヤーを作成
hbox setMargin ( 10 ) #10ピクセルのインデント
自己 。 setCentralWidget ( hbox ) #メインにする
#メイン水平内の2つの垂直レイヤー
vbox_left = KVBox ( hbox )
vbox_right = KVBox ( hbox )
#正しいレイヤーを上に揃える
hbox レイアウト ( ) 。 setAlignment ( vbox_right 、 QtCore。Qt。AlignTop )
#マウント用のデータ入力用フィールド
entry_name_label = QLabel ( 'Name:' 、 vbox_right )
自己 。 entry_name = KLineEdit ( vbox_right )
server_address_label = QLabel ( 'サーバーアドレス:' 、 vbox_right )
自己 。 server_address = KLineEdit ( vbox_right )
server_port_label = QLabel ( 'サーバーポート:' 、 vbox_right )
自己 。 server_port = KLineEdit ( vbox_right )
user_name_label = QLabel ( 'Username:' 、 vbox_right )
自己 。 user_name = KLineEdit ( vbox_right )
remote_path_label = QLabel ( 'リモートパス:' 、 vbox_right )
自己 。 remote_path = KLineEdit ( vbox_right )
local_path_label = QLabel ( 'Local path:' 、 vbox_right )
自己 。 local_path = KLineEdit ( vbox_right )
#ボタンのマウントとアンマウント
#別のレイヤーを作成
btn_hbox_right = KHBox ( vbox_right )
connect_btn = KPushButton ( btn_hbox_right )
connect_btn 。 setText ( i18n ( '接続' ) )
disconnect_btn = KPushButton ( btn_hbox_right )
disconnect_btn 。 setText ( i18n ( '切断' ) )
#保存済みプロファイルのリスト
saved_list_label = QLabel ( 'Stored connections:' 、 vbox_left )
自己 。 saved_list = KListWidget ( vbox_left )
自己 。 saved_list 。 setMaximumWidth ( 150 )
#プロファイルを保存および削除するためのボタン
btn_hbox_left = KHBox ( vbox_left )
save_btn = KPushButton ( btn_hbox_left )
save_btn setText ( i18n ( '保存' ) )
delete_btn = KPushButton ( btn_hbox_left )
delete_btn 。 setText ( i18n ( '削除' ) )
したがって、この後、フォームを表示するプログラムがあります。

イベント処理
次に、プログラムの枠組みに命を吹き込む必要があります。
ユーザー(つまり、I)はボタンをクリックし、保存されたプロファイルのリストでプロファイルを選択することですべてのアクションを実行するため、これらの要素にイベントハンドラーをインストールする必要があります。 信号とスロットのメカニズムがこれに役立ちます。
簡単です:
#イベントハンドラーをボタンにバインド
#ここでsave_btnは保存ボタンオブジェクトを含む変数です
#QtCore.SIGNAL( 'clicked()')-「ボタンをクリック」というシグナル
#self.onSave-クリックを処理するために呼び出されるメソッド
自己 。 connect ( save_btn 、 QtCore。SIGNAL ( ' clicked ()' ) 、 self。onSave )
自己 。 connect ( delete_btn 、 QtCore。SIGNAL ( ' clicked ()' ) 、 self。onDelete )
自己 。 connect ( connect_btn 、 QtCore。SIGNAL ( 'clicked()' ) 、 self。onConnect )
自己 。 connect ( disconnect_btn 、 QtCore。SIGNAL ( ' clicked ()' ) 、 self。onDisconnect )
#最も困難なことは、「リスト内のアイテムをクリックした」シグナルの名前をドキュメントで見つけることでした
自己 。 connect ( self。saved_list 、 QtCore。SIGNAL ( 'itemClicked(QListWidgetItem *)' ) 、 self。onSelectServer )
プロファイルを保存しています
ハンドラー自体を作成するのはあなた次第です。 順番に始めましょう。プロファイルを保存し、プロファイルを削除します。
プロファイルをユーザーのホームディレクトリの〜/ .pyksshfs / hosts /に保存します。
プロファイルごとに1つのファイルファイル名は、フォームで「名前」と呼ばれるものです。
起動時に、プログラムがそのようなディレクトリがあるかどうかをチェックし、不在の場合に作成する必要があるのは論理的です。
これを行うには、プログラムの説明の後に次の洗練されていないコードを追加します。
config_path = os 。 getenv ( 'HOME' ) + '/.pyksshfs/hosts'
osで ない 場合 。 パス isdir ( config_path ) :
os 。 makedirs ( config_path 、 0700 )
そして、インポートOSプログラムでファイルの先頭に
フォームフィールドの値をファイルに保存する最善の方法を考えて、私はおそらくPythonに設定を保存するための既製のモジュールがあると思いました。 そしてそれが起こった。
わずかなグーグルですぐに結果が得られました:import ConfigParser
onSaveメソッド:
def onSave ( self ) :
'' '
設定を保存する
' ' '
自己の 場合 。 entry_name 。 text ( ) : #プロファイル名がある場合
config = ConfigParser 。 RawConfigParser ( ) #構成を作成して入力する
config add_section ( '接続' )
config 設定 ( 「接続」 、 「ホスト」 、 自己 。 サーバーアドレス 。 テキスト ( ) )
config 設定 ( 「接続」 、 「ポート」 、 自己 。 サーバー ポート 。 テキスト ( ) )
config セット ( 'Connection' 、 'user_name' 、 self。user_name。text ( ) )
config set ( 'Connection' 、 'remote_path' 、 self。remote_path。text ( ) )
config set ( 'Connection' 、 'local_path' 、 self。local_path。text ( ) )
自己の 場合 。 selected_name :
os 。 unlink ( self。config_path + '/' + self。selected_name )
path = self config_path + '/' + self entry_name 。 テキスト ( )
ファイル = オープン ( パス 、 'w' )
config write ( file ) #設定を保存
ファイル 。 閉じる ( )
自己 。 selected_name = self 。 entry_name 。 テキスト ( )
自己 。 listServers ( ) #プロファイルのリストを更新
プロフィールリスト
メソッドの記述の最後に、新しいプロファイルがすぐにリストに表示されたらいいと思います。プログラムを開くと、保存されたプロファイルのリストも表示する必要があります。
そのため、出力を受信して一覧表示するメソッドをすぐに記述し、__ init__およびonSaveの最後に呼び出しを挿入します。
def listServers ( self ) :
自己 。 saved_list 。 クリア ( )
hosts = os listdir ( self。config_path )
自己 。 saved_list 。 insertItems ( O 、 hosts ) #この呼び出しで、ファイルのリストをリストウィジェットに追加します
自己の 場合 。 selected_name : #すでにプロファイルを選択している場合は、リストで選択する必要があります
item = self saved_list 。 findItems ( self。selected_name 、 QtCore。Qt。MatchExactly )
自己 。 saved_list 。 setItemSelected ( item [ O ] 、 True )
(何らかの理由で、Habrはコードに0を表示したくないため、大文字のOに置き換えました)。
アンマウント
さらに進みましょう。 リモートディレクトリをアンマウントする方法。 基本的に説明することはありません。
def onDisconnect ( self ) :
if ( self。local_path。text ( ) ) :
os 。 system ( 'fusermount -u' + str ( self。local_path。text ( ) ) )
取り付け
マウントははるかに興味深いです。 私はこの部分を最も長く苦しめました。 この方法のせいで、2時間以上かかったのは秘密です。 しかし、実際には、問題はそのような性質のものであったため、以前にそれらのことを知っていたなら、見出しに示された期限を完全に満たしていただろう。
問題:sshを使用してディレクトリをマウントするコマンドは対話型であり、ユーザーからのパスワードが必要です。 ただし、キーによる認証が行われた場合は必要ありません。 したがって、コマンドを作成し、実行し、パスワードが要求されているかどうかを確認してから、ユーザーに要求する必要があります。 パスワードが不要な場合は、ユーザーに触れないでください。
sshfsコマンドには、stdinでパスワードを渡すことができるパラメーターがあります。 ただし、ユーザーは、パスワードが不要な場合、あまり良くないものを事前に尋ねる必要があります。
別の微妙な点があります。 sshを介してサーバーにアクセスしたことがない場合は、「彼を信頼しますか?」と尋ねられます。
一般に、これらのケースを何らかの形で処理する必要があります。 このような問題を解決するために、pexpectモジュール(pexpectのインポート)があります。 これを使用すると、対話型プログラム(telnet、ftp、sshなど)で作業できます。 さて、コードを表示する時間です。
def onConnect ( self ) :
コマンド = 'sshfs'
自己の 場合 。 user_name テキスト ( ) :
command + = self user_name テキスト ( ) + '@'
command + = self server_address 。 テキスト ( )
自己の 場合 。 remote_path 。 テキスト ( ) :
command + = ':' + self remote_path 。 テキスト ( )
その他 :
コマンド + = ':/'
自己の 場合 。 server_port 。 テキスト ( ) :
command + = '-p' + self 。 server_port 。 テキスト ( )
command + = '' + self 。 local_path 。 テキスト ( )
sshfs = pexpect spawn ( str ( command ) 、 env = { 'SSH_ASKPASS' : '/ dev / null' } )
ssh_newkey = '接続を続行してもよろしいですか?
i = sshfs expect ( [ ssh_newkey 、 'assword:' 、 pexpect。EOF 、 pexpect。TIMEOUT ] )
i = = 0の 場合 :
sshfs sendline ( 'yes' )
i = sshfs expect ( [ ssh_newkey 、 'assword:' 、 pexpect。EOF ] )
i = = 1の 場合 :
#パスワードが要求されない場合
askpasscmd = 'ksshaskpass%s' % self entry_name 。 テキスト ( )
パスワード = pexpect 実行 ( askpasscmd ) 。 split ( '\ n' ) [ 1 ]
sshfs sendline ( パスワード )
j = sshfs expect ( [ pexpect。EOF 、 'assword:' ] )
j = = 1の 場合 :
#パスワードが正しくありません、強制的に接続を閉じます
「パスワードが正しくありません」を 印刷
sshfs 閉じる ( True )
#p.terminate(True)
elif i = = 2 :
#すべての問題
print "エラーが見つかりました:%s" % sshfs 。 前に
elif i = = 3 :
#タイムアウト
print "Timeout:%s" % sshfs 。 前に
sshfsを出力します。 前に
linux-volume-manager-fuse-kde4プロジェクトからコードの一部を取りました。 最初は私のコードは動作したくありませんでしたが、コードが動作した後、私はこれをすべて同じままにすることにしました。 より多くのオプションを処理します。
ユーザーからパスワードを取得するには、ksshaskpassプログラムを使用しました。 第一に、書かないために、第二に、彼女はkwalletdからパスワードを保存/受信する方法を知っています。これは非常に便利です。
オリジナルのコードは、ksshaskpassのドキュメントによるとパスワードを返す必要があるため、まったく機能しませんでしたが、その代わりに、パスワードに加えて、他のデバッグ行を返します。 彼女はこのように除外しなければなりませんでした
パスワード= pexpect.run( 'ksshaskpass').split( '\ n')[1]
ところで、突然デバッグ行が消えると、プログラムは動作を停止します。
プロフィールのアップロード
ほとんどすべての準備が整いました。 最後のアクションは残ります。ユーザーがリストから選択したときにプロファイルをロードします。 すぐにコード。
def onSelectServer ( self 、 item ) :
「」 「
seved_listでアイテムが選択されている場合、ファイルから設定を取得
「 」
name = item テキスト ( ) #ファイル名
自己 。 selected_name = name #選択を覚えておいてください
config = ConfigParser 。 RawConfigParser ( )
config readfp ( open ( self。config_path + '/' + name ) ) #設定を開きます
#設定からフォームフィールドに入力
自己 。 entry_name 。 setText ( name )
自己 。 server_address 。 setText ( config。get ( 'Connection' 、 'host' ) )
自己 。 server_port 。 setText ( config。get ( 'Connection' 、 'port' ) )
自己 。 user_name setText ( config。get ( 'Connection' 、 'user_name' ) )
自己 。 remote_path 。 setText ( config。get ( 'Connection' 、 'remote_path' ) )
自己 。 local_path 。 setText ( config。get ( 'Connection' 、 'local_path' ) )
結果
以上です。 ほんの2、3時間で、Pythonシンタックス、グーグル、ブラックベルトのみを使用して、かなり実用的なコピー/貼り付けプログラムを作成しました。
おそらく記事では、コードの一部を見逃していました。
ですから
、完全に動作するpyKSshfsバージョンを
ダウンロードするのが最善です。
最後にスクリーンショット:

計画
プログラムの作成の途中で、プラズマアプレットとしてより便利になると思いました。 そして、フラッシュドライブをマウントするためのアプレットのように見えるはずです。 しかし、ksshaskpassで忙しかったので、延期することにしました。 たぶんすぐにやろう。 または多分あなたの一人が私の先を行くでしょう-私はただうれしいです。
参照資料
- pyKSshfsをダウンロードします 。
- 「KDE4のプログラミング」
- PyQtドキュメント
- Kommanderスクリプトksshfs
- sshfsgui javaプログラム
- コードの一部はここで取得されました。
ご清聴ありがとうございました!
これをすべて読むことができたすべての人のおかげで、私はそれが簡単ではなかったことを知っています。 =)
皆さんに幸運を!