gui/macapp: slew of code cleanup; unmount filesystems on quit

a handful of code cleanup, renaming and refactoring.  basically consolidating
'application logic' (mount/unmount fs) into the 'MacGuiApp' class (the wx.App)
and cleaning up various scoping things around that.  renamed all references to
'app' to refer more clearly to the 'AppContainer' or to the guiapp.

globally renamed basedir -> nodedir

also made the guiapp keep a note of each filesystem it mounts, and unmount
them upon 'quit' so as to cleanup the user's environment before the tahoe node
vanishes from out underneath the orphaned tahoe fuse processes
This commit is contained in:
robk-tahoe 2008-09-25 16:32:35 -07:00
parent 9b10f46374
commit 183dd587d5

View File

@ -2,7 +2,7 @@
import operator import operator
import os import os
import stat import stat
import subprocess from subprocess import Popen, PIPE
import sys import sys
import thread import thread
import threading import threading
@ -34,20 +34,25 @@ fi
''' '''
def run_macapp(): def run_macapp():
basedir = os.path.expanduser('~/.tahoe') nodedir = os.path.expanduser('~/.tahoe')
if not os.path.isdir(basedir): if not os.path.isdir(nodedir):
app_supp = os.path.expanduser('~/Library/Application Support/Allmydata Tahoe/') app_supp = os.path.expanduser('~/Library/Application Support/Allmydata Tahoe/')
if not os.path.isdir(app_supp): if not os.path.isdir(app_supp):
os.makedirs(app_supp) os.makedirs(app_supp)
os.symlink(app_supp, basedir) os.symlink(app_supp, nodedir)
app = App(basedir) app_cont = AppContainer(nodedir)
return app.run() return app_cont.run()
class MacGuiClient(client.Client): class MacGuiClient(client.Client):
def __init__(self, basedir, app): """
self.app = app This is a subclass of the tahoe 'client' node, which hooks into the
client.Client.__init__(self, basedir) client's 'notice something went wrong' mechanism, to display the fact
in a manner sensible for a wx gui app
"""
def __init__(self, nodedir, app_cont):
self.app_cont = app_cont
client.Client.__init__(self, nodedir)
def _service_startup_failed(self, failure): def _service_startup_failed(self, failure):
wx.CallAfter(self.wx_abort, failure) wx.CallAfter(self.wx_abort, failure)
@ -56,40 +61,46 @@ class MacGuiClient(client.Client):
def wx_abort(self, failure): def wx_abort(self, failure):
wx.MessageBox(failure.getTraceback(), 'Fatal Error in Node startup') wx.MessageBox(failure.getTraceback(), 'Fatal Error in Node startup')
self.app.guiapp.ExitMainLoop() self.app_cont.guiapp.ExitMainLoop()
class App(object): class AppContainer(object):
def __init__(self, basedir): """
self.basedir = basedir This is the 'container' for the mac app, which takes care of initial
configuration concerns - e.g. running the confwiz before going any further -
of launching the reactor, and within it the tahoe node, on a separate thread,
and then lastly of launching the actual wx gui app and waiting for it to exit.
"""
def __init__(self, nodedir):
self.nodedir = nodedir
def files_exist(self, file_list): def files_exist(self, file_list):
extant_conf = [ os.path.exists(os.path.join(self.basedir, f)) for f in file_list ] extant_conf = [ os.path.exists(os.path.join(self.nodedir, f)) for f in file_list ]
return reduce(operator.__and__, extant_conf) return reduce(operator.__and__, extant_conf)
def is_config_incomplete(self): def is_config_incomplete(self):
necessary_conf_files = ['introducer.furl', 'private/root_dir.cap'] necessary_conf_files = ['introducer.furl', 'private/root_dir.cap']
need_config = not self.files_exist(necessary_conf_files) need_config = not self.files_exist(necessary_conf_files)
if need_config: if need_config:
print 'some config is missing from basedir (%s): %s' % (self.basedir, necessary_conf_files) print 'some config is missing from nodedir (%s): %s' % (self.nodedir, necessary_conf_files)
return need_config return need_config
def run(self): def run(self):
# handle initial config # handle initial config
if not os.path.exists(os.path.join(self.basedir, 'webport')): if not os.path.exists(os.path.join(self.nodedir, 'webport')):
f = file(os.path.join(self.basedir, 'webport'), 'wb') f = file(os.path.join(self.nodedir, 'webport'), 'wb')
f.write('8123') f.write('8123')
f.close() f.close()
if self.is_config_incomplete(): if self.is_config_incomplete():
app = ConfWizApp(DEFAULT_SERVER_URL, open_welcome_page=True) confwiz = ConfWizApp(DEFAULT_SERVER_URL, open_welcome_page=True)
app.MainLoop() confwiz.MainLoop()
if self.is_config_incomplete(): if self.is_config_incomplete():
print 'config still incomplete; confwiz cancelled, exiting' print 'config still incomplete; confwiz cancelled, exiting'
return 1 return 1
# set up twisted logging. this will become part of the node rsn. # set up twisted logging. this will become part of the node rsn.
logdir = os.path.join(self.basedir, 'logs') logdir = os.path.join(self.nodedir, 'logs')
if not os.path.exists(logdir): if not os.path.exists(logdir):
os.makedirs(logdir) os.makedirs(logdir)
lf = logfile.LogFile('tahoesvc.log', logdir) lf = logfile.LogFile('tahoesvc.log', logdir)
@ -99,17 +110,20 @@ class App(object):
self.maybe_install_tahoe_script() self.maybe_install_tahoe_script()
# actually start up the node and the ui # actually start up the node and the ui
os.chdir(self.basedir) os.chdir(self.nodedir)
# start the reactor thread up, launch the tahoe node therein
self.start_reactor() self.start_reactor()
try: try:
self.guiapp = MacGuiApp(app=self) # launch the actual gui on the wx event loop, wait for it to quit
self.guiapp = MacGuiApp(app_cont=self)
self.guiapp.MainLoop() self.guiapp.MainLoop()
log.msg('gui mainloop exited') log.msg('gui mainloop exited')
except: except:
log.err() log.err()
# shutdown the reactor, hence tahoe node, before exiting
self.stop_reactor() self.stop_reactor()
return 0 return 0
@ -120,8 +134,8 @@ class App(object):
def launch_reactor(self): def launch_reactor(self):
# run the node itself # run the node itself
#c = client.Client(self.basedir) #c = client.Client(self.nodedir)
c = MacGuiClient(self.basedir, self) c = MacGuiClient(self.nodedir, app_cont=self)
reactor.callLater(0, c.startService) # after reactor startup reactor.callLater(0, c.startService) # after reactor startup
reactor.run(installSignalHandlers=False) reactor.run(installSignalHandlers=False)
self.reactor_shutdown.set() self.reactor_shutdown.set()
@ -133,18 +147,6 @@ class App(object):
self.reactor_shutdown.wait() self.reactor_shutdown.wait()
log.msg('reactor shut down') log.msg('reactor shut down')
def webopen(self, alias=None):
log.msg('webopen: %r' % (alias,))
if alias is None:
alias = 'tahoe'
root_uri = get_aliases(self.basedir).get(alias)
if root_uri:
nodeurl = file(os.path.join(self.basedir, 'node.url'), 'rb').read().strip()
if nodeurl[-1] != "/":
nodeurl += "/"
url = nodeurl + "uri/%s/" % urllib.quote(root_uri)
webbrowser.open(url)
def maybe_install_tahoe_script(self): def maybe_install_tahoe_script(self):
path_candidates = ['/usr/local/bin', '~/bin', '~/Library/bin'] path_candidates = ['/usr/local/bin', '~/bin', '~/Library/bin']
env_path = map(os.path.expanduser, os.environ['PATH'].split(':')) env_path = map(os.path.expanduser, os.environ['PATH'].split(':'))
@ -253,7 +255,7 @@ class SplashPanel(wx.Panel):
class MountFrame(wx.Frame): class MountFrame(wx.Frame):
def __init__(self, app): def __init__(self, guiapp):
wx.Frame.__init__(self, None, -1, 'Allmydata Mount Filesystem') wx.Frame.__init__(self, None, -1, 'Allmydata Mount Filesystem')
self.SetSizeHints(100, 100, 600, 800) self.SetSizeHints(100, 100, 600, 800)
@ -262,7 +264,7 @@ class MountFrame(wx.Frame):
background = wx.Panel(self, -1) background = wx.Panel(self, -1)
background.parent = self background.parent = self
self.mount_panel = MountPanel(background, self.on_close, app) self.mount_panel = MountPanel(background, self.on_close, guiapp)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
background_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_sizer.Add(self.mount_panel, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 26)
@ -276,69 +278,17 @@ class MountFrame(wx.Frame):
def on_close(self, event): def on_close(self, event):
self.Show(False) self.Show(False)
def check_mount(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))
def mount_filesystem(basedir, alias_name, mountpoint, display_name=None, timeout=None):
log.msg('mount_filesystem(%r,%r,%r,%r)' % (basedir, alias_name, mountpoint, display_name))
log.msg('sys.exec = %r' % (sys.executable,))
if not sys.executable.endswith('Allmydata.app/Contents/MacOS/python'):
log.msg("can't find allmydata.app: sys.executable = %r" % (sys.executable,))
wx.MessageBox("Can't determine location of Allmydata.app")
return False
bin_path = sys.executable[:-6] + 'Allmydata'
log.msg('%r exists: %r' % (bin_path, os.path.exists(bin_path),))
foptions = []
foptions.append('-olocal') # required to display in Finder on leopard
if display_name is None:
display_name = alias_name
foptions.append('-ovolname=%s' % (display_name,))
if timeout is None:
timeout = DEFAULT_FUSE_TIMEOUT
if timeout:
foptions.append('-odaemon_timeout=%d' % (timeout,))
icns_path = os.path.join(basedir, 'private', alias_name+'.icns')
if not os.path.exists(icns_path):
icns_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable),
'../Resources/allmydata.icns'))
log.msg('set icns_path=%s' % (icns_path,))
log.msg('icns_path exists: %s' % os.path.exists(icns_path))
if os.path.exists(icns_path):
foptions.append('-ovolicon=%s' % (icns_path,))
command = [bin_path, 'fuse', '--alias', alias_name] + foptions + [mountpoint]
log.msg('spawning command %r' % (command,))
proc = subprocess.Popen(command,
cwd=basedir,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
log.msg('spawned process, pid %s' % (proc.pid,))
wx.FutureCall(4096, check_mount, proc)
return True
class MountPanel(wx.Panel): class MountPanel(wx.Panel):
def __init__(self, parent, on_close, app): def __init__(self, parent, on_close, guiapp):
wx.Panel.__init__(self, parent, -1) wx.Panel.__init__(self, parent, -1)
self.parent = parent self.parent = parent
self.app = app self.guiapp = guiapp
self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = wx.BoxSizer(wx.VERTICAL)
self.aliases = get_aliases(self.app.basedir)
self.label = wx.StaticText(self, -1, 'Allmydata Mount Filesystem') self.label = wx.StaticText(self, -1, 'Allmydata Mount Filesystem')
self.mnt_label = wx.StaticText(self, -1, 'Mount') self.mnt_label = wx.StaticText(self, -1, 'Mount')
self.alias_choice = wx.Choice(self, -1, (120, 64), choices=self.aliases.keys()) self.alias_choice = wx.Choice(self, -1, (120, 64), choices=self.guiapp.aliases.keys())
root_dir = self.alias_choice.FindString('tahoe') root_dir = self.alias_choice.FindString('tahoe')
if root_dir != -1: if root_dir != -1:
self.alias_choice.SetSelection(root_dir) self.alias_choice.SetSelection(root_dir)
@ -363,10 +313,6 @@ class MountPanel(wx.Panel):
self.SetSizer(self.sizer) self.SetSizer(self.sizer)
self.SetAutoLayout(True) self.SetAutoLayout(True)
#def on_choice(self, event):
#choice = event.GetString()
#log.msg('chose dir: %s' % (choice,))
def on_mount(self, event): def on_mount(self, event):
mountpoint = str(self.mountpoint.GetValue()) mountpoint = str(self.mountpoint.GetValue())
if not os.path.isdir(mountpoint): if not os.path.isdir(mountpoint):
@ -385,65 +331,9 @@ class MountPanel(wx.Panel):
def do_mount(self, alias_name, mountpoint): def do_mount(self, alias_name, mountpoint):
log.msg('do_mount(%r, %r)' % (alias_name, mountpoint)) log.msg('do_mount(%r, %r)' % (alias_name, mountpoint))
# XXX this needs a referential cleanup self.guiapp.mount_filesystem(alias_name, mountpoint)
timeout = self.app.config['daemon-timeout']
ok = mount_filesystem(self.app.basedir, alias_name, mountpoint, timeout=timeout)
if ok and self.app.config['auto-open']:
wx.FutureCall(2048, open_finder, mountpoint)
self.parent.parent.Show(False) self.parent.parent.Show(False)
def old_do_mount(self, alias_name, mountpoint):
log.msg('do_mount(%r, %r)' % (alias_name, mountpoint))
log.msg('sys.exec = %r' % (sys.executable,))
if not sys.executable.endswith('Allmydata.app/Contents/MacOS/python'):
log.msg("can't find allmydata.app: sys.executable = %r" % (sys.executable,))
wx.MessageBox("Can't determine location of Allmydata.app")
self.parent.parent.Show(False)
return
bin_path = sys.executable[:-6] + 'Allmydata'
log.msg('%r exists: %r' % (bin_path, os.path.exists(bin_path),))
foptions = []
foptions.append('-ovolname=%s' % (alias_name,))
foptions.append('-olocal')
timeout = DEFAULT_FUSE_TIMEOUT
# [ ] TODO: make this configurable
if timeout:
foptions.append('-odaemon_timeout=%d' % (timeout,))
icns_path = os.path.join(self.app.basedir, 'private', alias_name+'.icns')
if not os.path.exists(icns_path):
icns_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable),
'../Resources/allmydata.icns'))
log.msg('set icns_path=%s' % (icns_path,))
log.msg('icns_path exists: %s' % os.path.exists(icns_path))
if os.path.exists(icns_path):
foptions.append('-ovolicon=%s' % (icns_path,))
command = [bin_path, 'fuse', '--alias', alias_name] + foptions + [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))
def open_finder(path):
proc = subprocess.Popen(['/usr/bin/open', path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
class MacGuiApp(wx.App): class MacGuiApp(wx.App):
config = { config = {
'auto-mount': True, 'auto-mount': True,
@ -452,15 +342,18 @@ class MacGuiApp(wx.App):
'daemon-timeout': DEFAULT_FUSE_TIMEOUT, 'daemon-timeout': DEFAULT_FUSE_TIMEOUT,
} }
def __init__(self, app): def __init__(self, app_cont):
self.app = app self.app_cont = app_cont
self.nodedir = app_cont.nodedir
self.load_config() self.load_config()
self.mounted_filesystems = {}
self.aliases = get_aliases(self.nodedir)
wx.App.__init__(self) wx.App.__init__(self)
# XXX should have a table of all mounted filesystems, so that can unmount on quit
## load up setting from gui.conf dir
def load_config(self): def load_config(self):
log.msg('load_config') log.msg('load_config')
confdir = os.path.join(self.app.basedir, 'gui.conf') confdir = os.path.join(self.nodedir, 'gui.conf')
config = {} config = {}
config.update(self.config) config.update(self.config)
for k in self.config: for k in self.config:
@ -476,8 +369,8 @@ class MacGuiApp(wx.App):
val = int(val) val = int(val)
config[k] = val config[k] = val
self.config = config self.config = config
#log.msg('loaded config: %r' % (self.config,)) # XXX
## GUI wx init
def OnInit(self): def OnInit(self):
log.msg('OnInit') log.msg('OnInit')
try: try:
@ -490,10 +383,7 @@ class MacGuiApp(wx.App):
wx.FutureCall(4096, self.on_timer, None) wx.FutureCall(4096, self.on_timer, None)
# XXX clean up this ref self.mount_frame = MountFrame(guiapp=self)
self.app.config = self.config
self.mount_frame = MountFrame(self.app)
self.setup_dock_icon() self.setup_dock_icon()
menubar = self.setup_app_menu(self.frame) menubar = self.setup_app_menu(self.frame)
@ -504,21 +394,12 @@ class MacGuiApp(wx.App):
DisplayTraceback('exception on startup') DisplayTraceback('exception on startup')
sys.exit() sys.exit()
## WX menu and event handling
def on_timer(self, event): def on_timer(self, event):
self.frame.Show(False) self.frame.Show(False)
self.perhaps_automount() self.perhaps_automount()
def perhaps_automount(self):
if self.config['auto-mount']:
mountpoint = os.path.expanduser('~/.tahoe/mnt/__auto__')
if not os.path.isdir(mountpoint):
os.makedirs(mountpoint)
timeout = self.config['daemon-timeout']
mount_filesystem(self.app.basedir, 'tahoe', mountpoint, 'Allmydata', timeout)
if self.config['auto-open']:
assert os.path.isdir(mountpoint)
wx.FutureCall(2048, open_finder, mountpoint)
def setup_dock_icon(self): def setup_dock_icon(self):
self.tbicon = wx.TaskBarIcon() self.tbicon = wx.TaskBarIcon()
#self.tbicon.SetIcon(amdicon.getIcon(), "Allmydata") #self.tbicon.SetIcon(amdicon.getIcon(), "Allmydata")
@ -529,17 +410,13 @@ class MacGuiApp(wx.App):
file_menu = wx.Menu() file_menu = wx.Menu()
if self.config['show-webopen']: if self.config['show-webopen']:
webopen_menu = wx.Menu() webopen_menu = wx.Menu()
# XXX should promote to mac app inst var
aliases = get_aliases(self.app.basedir)
self.webopen_menu_ids = {} self.webopen_menu_ids = {}
for alias in aliases: for alias in self.aliases:
mid = wx.NewId() mid = wx.NewId()
self.webopen_menu_ids[mid] = alias self.webopen_menu_ids[mid] = alias
item = webopen_menu.Append(mid, alias) item = webopen_menu.Append(mid, alias)
frame.Bind(wx.EVT_MENU, self.on_webopen, item) frame.Bind(wx.EVT_MENU, self.on_webopen, item)
#log.msg('menu ids: %r' % (self.webopen_menu_ids,))
file_menu.AppendMenu(WEBOPEN_ID, 'Open Web UI', webopen_menu) file_menu.AppendMenu(WEBOPEN_ID, 'Open Web UI', webopen_menu)
self.aliases = get_aliases(self.app.basedir)
item = file_menu.Append(ACCOUNT_PAGE_ID, text='Open Account Page') item = file_menu.Append(ACCOUNT_PAGE_ID, text='Open Account Page')
frame.Bind(wx.EVT_MENU, self.on_account_page, item) frame.Bind(wx.EVT_MENU, self.on_account_page, item)
item = file_menu.Append(MOUNT_ID, text='Mount Filesystem') item = file_menu.Append(MOUNT_ID, text='Mount Filesystem')
@ -568,13 +445,13 @@ class MacGuiApp(wx.App):
self.frame.Show(True) self.frame.Show(True)
def on_quit(self, event): def on_quit(self, event):
#XXX unmount mounted (automounted!) filesystems self.unmount_filesystems()
self.ExitMainLoop() self.ExitMainLoop()
def on_webopen(self, event): def on_webopen(self, event):
alias = self.webopen_menu_ids.get(event.GetId()) alias = self.webopen_menu_ids.get(event.GetId())
#log.msg('on_webopen() alias=%r' % (alias,)) #log.msg('on_webopen() alias=%r' % (alias,))
self.app.webopen(alias) self.webopen(alias)
def on_account_page(self, event): def on_account_page(self, event):
webbrowser.open(DEFAULT_SERVER_URL + ACCOUNT_PAGE) webbrowser.open(DEFAULT_SERVER_URL + ACCOUNT_PAGE)
@ -582,3 +459,109 @@ class MacGuiApp(wx.App):
def on_mount(self, event): def on_mount(self, event):
self.mount_frame.Show(True) self.mount_frame.Show(True)
## Gui App methods
def perhaps_automount(self):
if self.config['auto-mount']:
mountpoint = os.path.join(self.nodedir, 'mnt/__auto__')
if not os.path.isdir(mountpoint):
os.makedirs(mountpoint)
self.mount_filesystem(self.nodedir, 'tahoe', mountpoint, 'Allmydata')
def webopen(self, alias=None):
log.msg('webopen: %r' % (alias,))
if alias is None:
alias = 'tahoe'
root_uri = self.aliases.get(alias)
if root_uri:
nodeurl = file(os.path.join(self.nodedir, 'node.url'), 'rb').read().strip()
if nodeurl[-1] != "/":
nodeurl += "/"
url = nodeurl + "uri/%s/" % urllib.quote(root_uri)
webbrowser.open(url)
def mount_filesystem(self, alias_name, mountpoint, display_name=None):
log.msg('mount_filesystem(%r,%r,%r)' % (alias_name, mountpoint, display_name))
log.msg('sys.exec = %r' % (sys.executable,))
# first determine if we can find the 'tahoe' binary (i.e. contents of .app)
if not sys.executable.endswith('Allmydata.app/Contents/MacOS/python'):
log.msg("can't find allmydata.app: sys.executable = %r" % (sys.executable,))
wx.MessageBox("Can't determine location of Allmydata.app")
return False
bin_path = sys.executable[:-6] + 'Allmydata'
log.msg('%r exists: %r' % (bin_path, os.path.exists(bin_path),))
# check mountpoint exists
if not os.path.exists(mountpoint):
log.msg('mountpoint %r does not exist' % (mountpoint,))
return False
# figure out options for fuse_main
foptions = []
foptions.append('-olocal') # required to display in Finder on leopard
foptions.append('-ofstypename=allmydata') # shown in 'get info'
if display_name is None:
display_name = alias_name
foptions.append('-ovolname=%s' % (display_name,))
timeout = self.config['daemon-timeout']
foptions.append('-odaemon_timeout=%d' % (timeout,))
icns_path = os.path.join(self.nodedir, 'private/icons', alias_name+'.icns')
log.msg('icns_path %r exists: %s' % (icns_path, os.path.exists(icns_path)))
if not os.path.exists(icns_path):
icns_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable),
'../Resources/allmydata.icns'))
log.msg('set icns_path=%s' % (icns_path,))
if os.path.exists(icns_path):
foptions.append('-ovolicon=%s' % (icns_path,))
# actually launch tahoe fuse
command = [bin_path, 'fuse', '--alias', alias_name] + foptions + [mountpoint]
#log.msg('spawning command %r' % (command,))
#proc = Popen(command, cwd=self.nodedir, stdout=PIPE, stderr=PIPE)
#log.msg('spawned process, pid %s' % (proc.pid,))
self.async_run_cmd(command)
# log the outcome, record the fact that we mounted this fs
#wx.FutureCall(4096, self.check_proc, proc, 'fuse')
self.mounted_filesystems[display_name] = mountpoint
# open finder, if configured to do so
if self.config['auto-open']:
wx.FutureCall(2048, self.sync_run_cmd, ['/usr/bin/open', mountpoint])
return True
def unmount_filesystems(self):
# the user may've already unmounted some, but we should ensure that
# anything the gui mounted gets shut down, since they all depend on
# the tahoe node, which is going away
for name, mountpoint in self.mounted_filesystems.items():
log.msg('unmounting %r (%s)' % (name, mountpoint))
self.sync_run_cmd(['/sbin/umount', mountpoint])
def sync_run_cmd(self, argv):
log.msg('synchronously running command: %r' % (argv,))
proc = Popen(argv, cwd=self.nodedir, stdout=PIPE, stderr=PIPE)
proc.wait()
self.check_proc(proc)
def async_run_cmd(self, argv):
log.msg('asynchronously running command: %r' % (argv,))
proc = Popen(argv, cwd=self.nodedir, stdout=PIPE, stderr=PIPE)
log.msg('spawned process, pid: %s' % (proc.pid,))
wx.FutureCall(4096, self.check_proc, proc, 'async fuse process:')
def check_proc(self, proc, description=None):
message = []
if description is not None:
message.append(description)
message.append('pid: %s retcode: %s' % (proc.pid, proc.returncode,))
stdout = proc.stdout.read()
if stdout:
message.append('\nstdout:\n%s' % (stdout,))
stderr = proc.stderr.read()
if stderr:
message.append('\nstdout:\n%s' % (stderr,))
log.msg(' '.join(message))