mac: added 'mount filesystem' action to the mac gui

this adds an action to the dock menu and to the file menu (when visible)
"Mount Filesystem".  This action opens a windows offering the user an
opportunity to select from any of the named *.cap files in their 
.tahoe/private directory, and choose a corresponding mount point to mount
that at.

it launches the .app binary as a subprocess with the corresponding command
line arguments to launch the 'tahoe fuse' functionality to mount that file
system.  if a NAME.icns file is present in .tahoe/private alonside the
chosen NAME.cap, then that icon will be used when the filesystem is mounted.

this is highly unlikely to work when running from source, since it uses
introspection on sys.executable to find the relavent binary to launch in
order to get the right built .app's 'tahoe fuse' functionality.

it is also relatively likely that the code currently checked in, hence
linked into the build, will have as yet unresolved library dependencies.
it's quite unlikely to work on 10.5 with macfuse 1.3.1 at the moment.
This commit is contained in:
robk-tahoe 2008-02-19 18:56:59 -07:00
parent 6f5ccb1707
commit 899d602722

View File

@ -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)