diff --git a/src/allmydata/gui/macapp.py b/src/allmydata/gui/macapp.py index d8eee3e79..e8f105773 100644 --- a/src/allmydata/gui/macapp.py +++ b/src/allmydata/gui/macapp.py @@ -2,6 +2,7 @@ import operator import os import stat +import subprocess import sys import thread import threading @@ -16,6 +17,7 @@ from twisted.python import log, logfile import allmydata from allmydata import client from allmydata.gui.confwiz import ConfWizApp, ACCOUNT_PAGE, DEFAULT_SERVER_URL +from allmydata.uri import NewDirectoryURI import amdicon @@ -170,6 +172,7 @@ def DisplayTraceback(message): WEBOPEN_ID = wx.NewId() ACCOUNT_PAGE_ID = wx.NewId() +MOUNT_ID = wx.NewId() class SplashFrame(wx.Frame): def __init__(self): @@ -217,10 +220,145 @@ class SplashPanel(wx.Panel): self.SetAutoLayout(True) +class MountFrame(wx.Frame): + def __init__(self, app): + wx.Frame.__init__(self, None, -1, 'Allmydata Tahoe Mount Filesystem') + + self.SetSizeHints(100, 100, 600, 800) + self.SetIcon(amdicon.getIcon()) + self.Bind(wx.EVT_CLOSE, self.on_close) + + background = wx.Panel(self, -1) + background.parent = self + self.mount_panel = MountPanel(background, self.on_close, app) + sizer = wx.BoxSizer(wx.VERTICAL) + background_sizer = wx.BoxSizer(wx.VERTICAL) + background_sizer.Add(self.mount_panel, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 26) + background.SetSizer(background_sizer) + sizer.Add(background, 0, wx.EXPAND | wx.ALL, 0) + self.SetSizer(sizer) + self.SetAutoLayout(True) + self.Fit() + self.Layout() + + def on_close(self, event): + self.Show(False) + +class MountPanel(wx.Panel): + def __init__(self, parent, on_close, app): + wx.Panel.__init__(self, parent, -1) + self.parent = parent + self.app = app + + self.sizer = wx.BoxSizer(wx.VERTICAL) + + self.caps = self.find_dir_caps() + + self.label = wx.StaticText(self, -1, 'Allmydata Tahoe Mount Filesystem') + self.mnt_label = wx.StaticText(self, -1, 'Mount') + self.cap_choice = wx.Choice(self, -1, (120, 64), choices=self.caps.keys()) + root_dir = self.cap_choice.FindString('root_dir') + if root_dir != -1: + self.cap_choice.SetSelection(root_dir) + self.at_label = wx.StaticText(self, -1, 'at') + self.mountpoint = wx.TextCtrl(self, -1, 'choose a mount dir', size=(256,22)) + self.mnt_browse = wx.Button(self, -1, 'Browse') + mount_sizer = wx.BoxSizer(wx.HORIZONTAL) + mount_sizer.Add(self.mnt_label, 0, wx.ALL, 4) + mount_sizer.Add(self.cap_choice, 0, wx.ALL, 4) + mount_sizer.Add(self.at_label, 0, wx.ALL, 4) + mount_sizer.Add(self.mountpoint, 0, wx.ALL, 4) + mount_sizer.Add(self.mnt_browse, 0, wx.ALL, 4) + self.mount = wx.Button(self, -1, 'Mount') + self.Bind(wx.EVT_BUTTON, self.on_mount, self.mount) + #self.Bind(wx.EVT_CHOICE, self.on_choice, self.cap_choice) + self.Bind(wx.EVT_BUTTON, self.on_mnt_browse, self.mnt_browse) + self.sizer.Add(self.label, 0, wx.CENTER | wx.ALL, 2) + self.sizer.Add(wx.Size(28,28), 1, wx.EXPAND | wx.ALL, 2) + self.sizer.Add(mount_sizer, 0, wx.EXPAND | wx.ALL, 0) + self.sizer.Add(wx.Size(28,28), 1, wx.EXPAND | wx.ALL, 2) + self.sizer.Add(self.mount, 0, wx.CENTER | wx.ALL, 2) + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + + def find_dir_caps(self): + priv_dir = os.path.join(self.app.basedir, 'private') + fs = os.listdir(priv_dir) + caps = {} + for f in fs: + if not f.endswith('.cap'): + continue + try: + log.msg('reading: %r' % (f,)) + fh = file(os.path.join(priv_dir, f), 'rb') + cap = fh.read().strip() + fh.close() + uri = NewDirectoryURI.init_from_string(cap) + caps[f[:-4]] = cap + except: + log.msg('failed to read dir cap from "%s"' % (f,)) + log.err() + return caps + + #def on_choice(self, event): + #choice = event.GetString() + #log.msg('chose dir: %s' % (choice,)) + + def on_mount(self, event): + mountpoint = str(self.mountpoint.GetValue()) + if not os.path.isdir(mountpoint): + wx.MessageBox(u'"%s" is not a directory' % (mountpoint,)) + else: + cap_name = self.cap_choice.GetStringSelection() + self.do_mount(cap_name, mountpoint) + + def on_mnt_browse(self, event): + dlg = wx.DirDialog(self, "Choose a Mountpoint Directory:", + style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON) + if dlg.ShowModal() == wx.ID_OK: + mountpoint = dlg.GetPath() + self.mountpoint.SetValue(mountpoint) + dlg.Destroy() + + def do_mount(self, cap_name, mountpoint): + log.msg('do_mount(%r, %r)' % (cap_name, mountpoint)) + log.msg('sys.exec = %r' % (sys.executable,)) + if not sys.executable.endswith('Tahoe.app/Contents/MacOS/python'): + log.msg("can't find tahoe.app: sys.executable = %r" % (sys.executable,)) + wx.MessageBox("Can't determine location of Allmydata Tahoe.app") + self.parent.parent.Show(False) + return + bin_path = sys.executable[:-6] + 'Allmydata Tahoe' + log.msg('%r exists: %r' % (bin_path, os.path.exists(bin_path),)) + + icns_path = os.path.join(self.app.basedir, 'private', cap_name+'.icns') + if os.path.exists(icns_path): + icon_arg = ['-ovolicon=%s' % (icns_path,)] + else: + icon_arg = [] + + command = [bin_path, 'fuse', cap_name] + icon_arg + [mountpoint] + log.msg('spawning command %r' % (command,)) + proc = subprocess.Popen(command, + cwd=self.app.basedir, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + log.msg('spawned process, pid %s' % (proc.pid,)) + wx.FutureCall(4096, self.check_mount, proc) + self.parent.parent.Show(False) + + def check_mount(self, proc): + message = [ 'pid: %s' % (proc.pid,), + 'ret: %s' % (proc.returncode,), + 'stdout:\n%s' % (proc.stdout.read(),), + 'stderr:\n%s' % (proc.stderr.read(),), + ] + log.msg('\n'.join(['spawned process:'] + message)) + class MacGuiApp(wx.App): def __init__(self, app): - wx.App.__init__(self) self.app = app + wx.App.__init__(self) def OnInit(self): try: @@ -230,6 +368,8 @@ class MacGuiApp(wx.App): wx.FutureCall(4096, self.on_timer, None) + self.mount_frame = MountFrame(self.app) + self.setup_dock_icon() menubar = self.setup_app_menu(self.frame) self.frame.SetMenuBar(menubar) @@ -254,6 +394,8 @@ class MacGuiApp(wx.App): frame.Bind(wx.EVT_MENU, self.on_webopen, item) item = file_menu.Append(ACCOUNT_PAGE_ID, text='Open Account Page') frame.Bind(wx.EVT_MENU, self.on_account_page, item) + item = file_menu.Append(MOUNT_ID, text='Mount Filesystem') + frame.Bind(wx.EVT_MENU, self.on_mount, item) item = file_menu.Append(wx.ID_ABOUT, text='About') frame.Bind(wx.EVT_MENU, self.on_about, item) item = file_menu.Append(wx.ID_EXIT, text='Quit') @@ -269,6 +411,8 @@ class MacGuiApp(wx.App): self.tbicon.Bind(wx.EVT_MENU, self.on_webopen, item) item = dock_menu.Append(ACCOUNT_PAGE_ID, text='Open Account Page') self.tbicon.Bind(wx.EVT_MENU, self.on_account_page, item) + item = dock_menu.Append(MOUNT_ID, text='Mount Filesystem') + self.tbicon.Bind(wx.EVT_MENU, self.on_mount, item) self.tbicon.PopupMenu(dock_menu) def on_about(self, event): @@ -283,3 +427,6 @@ class MacGuiApp(wx.App): def on_account_page(self, event): webbrowser.open(DEFAULT_SERVER_URL + ACCOUNT_PAGE) + def on_mount(self, event): + self.mount_frame.Show(True) +