|
@@ -0,0 +1,219 @@
|
|
1
|
+#!/usr/bin/env python3
|
|
2
|
+# -*- coding: UTF-8 -*-
|
|
3
|
+#
|
|
4
|
+# generated by wxGlade 0.6.8 on Sun Mar 9 14:56:37 2014
|
|
5
|
+#
|
|
6
|
+
|
|
7
|
+application_name = u'NeMo'
|
|
8
|
+application_version = u'0.1.0'
|
|
9
|
+
|
|
10
|
+import json
|
|
11
|
+import os
|
|
12
|
+import subprocess
|
|
13
|
+import wx
|
|
14
|
+
|
|
15
|
+# begin wxGlade: dependencies
|
|
16
|
+import gettext
|
|
17
|
+# end wxGlade
|
|
18
|
+
|
|
19
|
+# begin wxGlade: extracode
|
|
20
|
+# end wxGlade
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+class NeMo(wx.Frame):
|
|
24
|
+ def __init__(self, *args, **kwds):
|
|
25
|
+ # begin wxGlade: NeMo.__init__
|
|
26
|
+ kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
|
|
27
|
+ wx.Frame.__init__(self, *args, **kwds)
|
|
28
|
+ self.SetSize((900, 480))
|
|
29
|
+ self.text_ctrl_stdout = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_READONLY)
|
|
30
|
+ self.text_ctrl_stderr = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_READONLY)
|
|
31
|
+
|
|
32
|
+ self.__set_properties()
|
|
33
|
+ self.__do_layout()
|
|
34
|
+ # end wxGlade
|
|
35
|
+
|
|
36
|
+ def __set_properties(self):
|
|
37
|
+ # begin wxGlade: NeMo.__set_properties
|
|
38
|
+ self.SetTitle(_("NeMo"))
|
|
39
|
+ self.text_ctrl_stdout.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
|
|
40
|
+ self.text_ctrl_stderr.SetForegroundColour(wx.Colour(255, 0, 0))
|
|
41
|
+ self.text_ctrl_stderr.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
|
|
42
|
+ # end wxGlade
|
|
43
|
+ self.SetTitle(_("%s - V%s" % (application_name, application_version)))
|
|
44
|
+
|
|
45
|
+ def __do_layout(self):
|
|
46
|
+ # begin wxGlade: NeMo.__do_layout
|
|
47
|
+ main_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
48
|
+ output_sizer = wx.BoxSizer(wx.VERTICAL)
|
|
49
|
+ stderr_sizer = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("stderr")), wx.HORIZONTAL)
|
|
50
|
+ stdout_sizer = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("stdout")), wx.HORIZONTAL)
|
|
51
|
+ action_sizer = wx.BoxSizer(wx.VERTICAL)
|
|
52
|
+ action_sizer.Add((0, 0), 0, 0, 0)
|
|
53
|
+ action_sizer.Add((0, 0), 0, 0, 0)
|
|
54
|
+ main_sizer.Add(action_sizer, 1, wx.EXPAND, 0)
|
|
55
|
+ stdout_sizer.Add(self.text_ctrl_stdout, 1, wx.EXPAND, 0)
|
|
56
|
+ output_sizer.Add(stdout_sizer, 1, wx.EXPAND, 0)
|
|
57
|
+ stderr_sizer.Add(self.text_ctrl_stderr, 1, wx.EXPAND, 0)
|
|
58
|
+ output_sizer.Add(stderr_sizer, 1, wx.EXPAND, 0)
|
|
59
|
+ main_sizer.Add(output_sizer, 3, wx.EXPAND, 0)
|
|
60
|
+ self.SetSizer(main_sizer)
|
|
61
|
+ self.Layout()
|
|
62
|
+ self.Centre()
|
|
63
|
+ # end wxGlade
|
|
64
|
+ self.action_sizer = action_sizer
|
|
65
|
+
|
|
66
|
+ def AddStaBu(self, stabu):
|
|
67
|
+ self.action_sizer.Add(stabu, 0, wx.EXPAND, 0)
|
|
68
|
+ self.Layout()
|
|
69
|
+# end of class NeMo
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+class StaBu(wx.BoxSizer):
|
|
73
|
+ SSH_FS = 'ssh'
|
|
74
|
+ WEB_DAV = 'dav'
|
|
75
|
+ FTP_FS = 'ftp'
|
|
76
|
+
|
|
77
|
+ def __init__(self, wx_frame, stdout, stderr, **kwargs):
|
|
78
|
+ self.wx_frame = wx_frame
|
|
79
|
+ self.stdout = stdout
|
|
80
|
+ self.stderr = stderr
|
|
81
|
+
|
|
82
|
+ for key in ['name', 'prot', 'remote_host', 'remote_path', 'local_path', 'user', 'port']:
|
|
83
|
+ setattr(self, key, kwargs[key])
|
|
84
|
+ for key, value in [('password', None), ]:
|
|
85
|
+ setattr(self, key, kwargs.get(key, value))
|
|
86
|
+
|
|
87
|
+ wx.BoxSizer.__init__(self, wx.HORIZONTAL)
|
|
88
|
+ self.button = wx.Button(wx_frame, wx.ID_ANY, _(self.name))
|
|
89
|
+ self.panel = wx.Panel(wx_frame, wx.ID_ANY)
|
|
90
|
+ if kwargs.get('hidden', False):
|
|
91
|
+ self.button.Hide()
|
|
92
|
+ self.panel.Hide()
|
|
93
|
+ elif kwargs.get('disabled', False):
|
|
94
|
+ self.button.Disable()
|
|
95
|
+ self.Add(self.button, 3, 0, 0)
|
|
96
|
+ self.Add(self.panel, 1, wx.EXPAND, 0)
|
|
97
|
+ wx_frame.Bind(wx.EVT_BUTTON, self.mount_pressed, self.button)
|
|
98
|
+ self.panel.Bind(wx.EVT_LEFT_UP, self.open_pressed)
|
|
99
|
+ wx_frame.Bind(wx.EVT_IDLE, self.panel_update, None)
|
|
100
|
+ wx_frame.AddStaBu(self)
|
|
101
|
+
|
|
102
|
+ def set_password(self):
|
|
103
|
+ if self.password == None:
|
|
104
|
+ box = wx.PasswordEntryDialog(self.wx_frame, 'Please enter password for %(name)s:' % self.__dict__, 'Password')
|
|
105
|
+ if box.ShowModal() == wx.ID_OK:
|
|
106
|
+ self.password = box.GetValue()
|
|
107
|
+ box.Destroy()
|
|
108
|
+
|
|
109
|
+ def error_msg(self, msg):
|
|
110
|
+ self.stderr.write('nemo-file (%s): ' % self.name)
|
|
111
|
+ self.stderr.write(msg)
|
|
112
|
+
|
|
113
|
+ def panel_update(self, event):
|
|
114
|
+ if self.is_mounted():
|
|
115
|
+ #self.button_open.SetBackgroundColour('green')
|
|
116
|
+ self.panel.SetBackgroundColour('green')
|
|
117
|
+ else:
|
|
118
|
+ #self.button_open.SetBackgroundColour('red')
|
|
119
|
+ self.panel.SetBackgroundColour('red')
|
|
120
|
+ event.Skip()
|
|
121
|
+
|
|
122
|
+ def mount_pressed(self, event):
|
|
123
|
+ if self.is_mounted():
|
|
124
|
+ self.umount()
|
|
125
|
+ else:
|
|
126
|
+ self.mount()
|
|
127
|
+ event.Skip()
|
|
128
|
+
|
|
129
|
+ def open_pressed(self, event):
|
|
130
|
+ for prog in ['nautilus', 'dolphin', 'nemo', 'thunar']:
|
|
131
|
+ try:
|
|
132
|
+ subprocess.Popen([prog, self.local_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
133
|
+ except OSError:
|
|
134
|
+ pass
|
|
135
|
+ else:
|
|
136
|
+ break
|
|
137
|
+ event.Skip()
|
|
138
|
+
|
|
139
|
+ def check_prot(self):
|
|
140
|
+ test_cmd = self.mount_cmd(True)
|
|
141
|
+ if test_cmd == None:
|
|
142
|
+ self.__ok__ = False
|
|
143
|
+ self.error_msg('Protocol not supported!\n')
|
|
144
|
+ #TODO: try to execute test_cmd to get info that progs are installed
|
|
145
|
+
|
|
146
|
+ def is_mounted(self):
|
|
147
|
+ p = subprocess.Popen(["mount"], stdout=subprocess.PIPE)
|
|
148
|
+ out, err = p.communicate()
|
|
149
|
+ self.stderr.write(err or '')
|
|
150
|
+ if self.local_path in out.decode('utf-8'):
|
|
151
|
+ return True
|
|
152
|
+ else:
|
|
153
|
+ return False
|
|
154
|
+
|
|
155
|
+ def umount(self):
|
|
156
|
+ self.stdout.write('umounting %s\n' % (self.local_path))
|
|
157
|
+ p = subprocess.Popen(['fusermount', '-u', self.local_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
158
|
+ out, err = p.communicate()
|
|
159
|
+ if not self.is_mounted():
|
|
160
|
+ self.stdout.write('SUCCESS.\n')
|
|
161
|
+ else:
|
|
162
|
+ self.stdout.write('FAILED.\n')
|
|
163
|
+ self.stdout.write(out or '')
|
|
164
|
+ self.stderr.write(err or '')
|
|
165
|
+
|
|
166
|
+ def mount(self):
|
|
167
|
+ cmd = self.mount_cmd()
|
|
168
|
+ self.stdout.write('mounting %(name)s to %(local_path)s\n' % self.__dict__)
|
|
169
|
+ if cmd != None:
|
|
170
|
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
171
|
+ out, err = p.communicate()
|
|
172
|
+ out = out.decode('utf-8')
|
|
173
|
+ err = err.decode('utf-8')
|
|
174
|
+ if self.password != None:
|
|
175
|
+ out = out.replace(self.password, u'*****')
|
|
176
|
+ err = err.replace(self.password, u'*****')
|
|
177
|
+ if self.is_mounted():
|
|
178
|
+ self.stdout.write('SUCCESS.\n')
|
|
179
|
+ else:
|
|
180
|
+ self.stdout.write('FAILED.\n')
|
|
181
|
+ self.password = None
|
|
182
|
+ self.stdout.write(out or '')
|
|
183
|
+ self.stderr.write(err or '')
|
|
184
|
+ else:
|
|
185
|
+ self.stdout.write('FAILED.\n')
|
|
186
|
+
|
|
187
|
+ def mount_cmd(self, test_cmd=False):
|
|
188
|
+ if self.prot == self.SSH_FS:
|
|
189
|
+ if test_cmd:
|
|
190
|
+ return ['sshfs', '--version']
|
|
191
|
+ return ['sshfs', '%(user)s@%(remote_host)s:%(remote_path)s' % self.__dict__, self.local_path]
|
|
192
|
+ elif self.prot == self.WEB_DAV:
|
|
193
|
+ if test_cmd:
|
|
194
|
+ return ['wdfs', '--version']
|
|
195
|
+ self.set_password()
|
|
196
|
+ return ['wdfs', '-o', 'accept_sslcert,username=%(user)s,password=%(password)s' % self.__dict__, self.remote_host + self.remote_path, self.local_path]
|
|
197
|
+ elif self.prot == self.FTP_FS:
|
|
198
|
+ if test_cmd:
|
|
199
|
+ return ['curlftpfs', '--version']
|
|
200
|
+ self.set_password()
|
|
201
|
+ return ['curlftpfs', 'ftp://%(user)s:%(password)s@%(remote_host)s:%(port)s%(remote_path)s' % self.__dict__, self.local_path]
|
|
202
|
+ else:
|
|
203
|
+ return None
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+if __name__ == "__main__":
|
|
207
|
+ gettext.install("app") # replace with the appropriate catalog name
|
|
208
|
+ app = wx.App(0)
|
|
209
|
+ nemo_frame = NeMo(None, wx.ID_ANY, "")
|
|
210
|
+ #
|
|
211
|
+
|
|
212
|
+ with open(os.path.abspath(os.path.join(os.path.expanduser('~'), '.nemo.json')), 'r') as fh:
|
|
213
|
+ config = json.load(fh)
|
|
214
|
+ for entry in config:
|
|
215
|
+ StaBu(nemo_frame, nemo_frame.text_ctrl_stdout, nemo_frame.text_ctrl_stderr, **entry)
|
|
216
|
+ #
|
|
217
|
+ app.SetTopWindow(nemo_frame)
|
|
218
|
+ nemo_frame.Show()
|
|
219
|
+ app.MainLoop()
|