Add item to Preferences menu to restart calibre in debug mode. Fixes #7359 (Make debug mode accessible from within the GUI)

This commit is contained in:
Kovid Goyal 2010-12-16 23:57:10 -07:00
parent 29dd71b130
commit 3960f3d6f3
4 changed files with 104 additions and 17 deletions

View File

@ -23,6 +23,12 @@ Run an embedded python interpreter.
help='Debug the specified device driver.')
parser.add_option('-g', '--gui', default=False, action='store_true',
help='Run the GUI',)
parser.add_option('--gui-debug', default=None,
help='Run the GUI with a debug console, logging to the'
' specified path',)
parser.add_option('--show-gui-debug', default=None,
help='Display the specified log file.',)
parser.add_option('-w', '--viewer', default=False, action='store_true',
help='Run the ebook viewer',)
parser.add_option('--paths', default=False, action='store_true',
@ -135,7 +141,28 @@ def add_simple_plugin(path_to_plugin):
os.chdir(odir)
shutil.rmtree(tdir)
def run_debug_gui(logpath):
import time, platform
time.sleep(3) # Give previous GUI time to shutdown fully and release locks
from calibre.constants import __appname__, __version__, isosx
print __appname__, _('Debug log')
print __appname__, __version__
print platform.platform()
print platform.system()
print platform.system_alias(platform.system(), platform.release(),
platform.version())
print 'Python', platform.python_version()
try:
if iswindows:
print 'Windows:', platform.win32_ver()
elif isosx:
print 'OSX:', platform.mac_ver()
else:
print 'Linux:', platform.linux_distribution()
except:
pass
from calibre.gui2.main import main
main(['__CALIBRE_GUI_DEBUG__', logpath])
def main(args=sys.argv):
from calibre.constants import debug
@ -154,6 +181,20 @@ def main(args=sys.argv):
if opts.gui:
from calibre.gui2.main import main
main(['calibre'])
elif opts.gui_debug is not None:
run_debug_gui(opts.gui_debug)
elif opts.show_gui_debug:
import time, re
time.sleep(1)
from calibre.gui2 import open_local_file
if iswindows:
with open(opts.show_gui_debug, 'r+b') as f:
raw = f.read()
raw = re.sub('(?<!\r)\n', '\r\n', raw)
f.seek(0)
f.truncate()
f.write(raw)
open_local_file(opts.show_gui_debug)
elif opts.viewer:
from calibre.gui2.viewer.main import main
vargs = ['ebook-viewer', '--debug-javascript']

View File

@ -10,6 +10,7 @@ from PyQt4.Qt import QIcon, QMenu, Qt
from calibre.gui2.actions import InterfaceAction
from calibre.gui2.preferences.main import Preferences
from calibre.gui2 import error_dialog
from calibre.constants import DEBUG
class PreferencesAction(InterfaceAction):
@ -22,6 +23,10 @@ class PreferencesAction(InterfaceAction):
pm.addAction(QIcon(I('config.png')), _('Preferences'), self.do_config)
pm.addAction(QIcon(I('wizard.png')), _('Run welcome wizard'),
self.gui.run_wizard)
if not DEBUG:
pm.addSeparator()
pm.addAction(QIcon(I('debug.png')), _('Restart in debug mode'),
self.debug_restart)
self.qaction.setMenu(pm)
self.preferences_menu = pm
for x in (self.gui.preferences_action, self.qaction):
@ -44,4 +49,6 @@ class PreferencesAction(InterfaceAction):
d.run_wizard_requested.connect(self.gui.run_wizard,
type=Qt.QueuedConnection)
def debug_restart(self, *args):
self.gui.quit(restart=True, debug_on_restart=True)

View File

@ -135,9 +135,10 @@ class GuiRunner(QObject):
'''Make sure an event loop is running before starting the main work of
initialization'''
def __init__(self, opts, args, actions, listener, app):
def __init__(self, opts, args, actions, listener, app, gui_debug=None):
self.startup_time = time.time()
self.opts, self.args, self.listener, self.app = opts, args, listener, app
self.gui_debug = gui_debug
self.actions = actions
self.main = None
QObject.__init__(self)
@ -148,7 +149,7 @@ class GuiRunner(QObject):
def start_gui(self):
from calibre.gui2.ui import Main
main = Main(self.opts)
main = Main(self.opts, gui_debug=self.gui_debug)
if self.splash_screen is not None:
self.splash_screen.showMessage(_('Initializing user interface...'))
self.splash_screen.finish(main)
@ -249,34 +250,56 @@ class GuiRunner(QObject):
self.initialize_db()
def run_in_debug_mode(logpath=None):
e = sys.executable if getattr(sys, 'frozen', False) else sys.argv[0]
import tempfile, subprocess
fd, logpath = tempfile.mkstemp('.txt')
if hasattr(sys, 'frameworks_dir'):
base = os.path.dirname(sys.frameworks_dir)
if 'console.app' not in base:
base = os.path.join(base, 'console.app', 'Contents')
exe = os.path.basename(e)
exe = os.path.join(base, 'MacOS', exe+'-debug')
else:
base, ext = os.path.splitext(e)
exe = base + '-debug' + ext
print 'Starting debug executable:', exe
subprocess.Popen([exe, '--gui-debug', logpath], stdout=fd, stderr=fd)
def run_gui(opts, args, actions, listener, app):
def run_gui(opts, args, actions, listener, app, gui_debug=None):
initialize_file_icon_provider()
if not dynamic.get('welcome_wizard_was_run', False):
from calibre.gui2.wizard import wizard
wizard().exec_()
dynamic.set('welcome_wizard_was_run', True)
runner = GuiRunner(opts, args, actions, listener, app)
runner = GuiRunner(opts, args, actions, listener, app, gui_debug=gui_debug)
ret = app.exec_()
if getattr(runner.main, 'run_wizard_b4_shutdown', False):
from calibre.gui2.wizard import wizard
wizard().exec_()
if getattr(runner.main, 'restart_after_quit', False):
e = sys.executable if getattr(sys, 'frozen', False) else sys.argv[0]
print 'Restarting with:', e, sys.argv
if hasattr(sys, 'frameworks_dir'):
app = os.path.dirname(os.path.dirname(sys.frameworks_dir))
import subprocess
subprocess.Popen('sleep 3s; open '+app, shell=True)
if getattr(runner.main, 'debug_on_restart', False):
run_in_debug_mode()
else:
os.execvp(e, sys.argv)
print 'Restarting with:', e, sys.argv
if hasattr(sys, 'frameworks_dir'):
app = os.path.dirname(os.path.dirname(sys.frameworks_dir))
import subprocess
subprocess.Popen('sleep 3s; open '+app, shell=True)
else:
os.execvp(e, sys.argv)
else:
if iswindows:
try:
runner.main.system_tray_icon.hide()
except:
pass
if runner.main.gui_debug is not None:
e = sys.executable if getattr(sys, 'frozen', False) else sys.argv[0]
import subprocess
subprocess.Popen([e, '--show-gui-debug', runner.main.gui_debug])
return ret
def cant_start(msg=_('If you are sure it is not running')+', ',
@ -317,6 +340,11 @@ def communicate(args):
def main(args=sys.argv):
gui_debug = None
if args[0] == '__CALIBRE_GUI_DEBUG__':
gui_debug = args[1]
args = ['calibre']
app, opts, args, actions = init_qt(args)
from calibre.utils.lock import singleinstance
from multiprocessing.connection import Listener
@ -333,9 +361,11 @@ def main(args=sys.argv):
except socket.error:
cant_start()
else:
return run_gui(opts, args, actions, listener, app)
return run_gui(opts, args, actions, listener, app,
gui_debug=gui_debug)
else:
return run_gui(opts, args, actions, listener, app)
return run_gui(opts, args, actions, listener, app,
gui_debug=gui_debug)
otherinstance = False
try:
listener = Listener(address=ADDRESS)
@ -345,8 +375,7 @@ def main(args=sys.argv):
# On windows only singleinstance can be trusted
otherinstance = True if iswindows else False
if not otherinstance:
sys.setcheckinterval(50) # Make GUI more responsive
return run_gui(opts, args, actions, listener, app)
return run_gui(opts, args, actions, listener, app, gui_debug=gui_debug)
communicate(args)

View File

@ -96,10 +96,11 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
'The main GUI'
def __init__(self, opts, parent=None):
def __init__(self, opts, parent=None, gui_debug=None):
MainWindow.__init__(self, opts, parent)
self.opts = opts
self.device_connected = None
self.gui_debug = gui_debug
acmap = OrderedDict()
for action in interface_actions():
ac = action.load_actual_plugin(self)
@ -261,6 +262,14 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
for ac in self.iactions.values():
ac.initialization_complete()
if show_gui and self.gui_debug is not None:
info_dialog(self, _('Debug mode'), '<p>' +
_('You have started calibre in debug mode. After you '
'quit calibre, the debug log will be available in '
'the file: %s<p>The '
'log will be displayed automatically.')%self.gui_debug, show=True)
def start_content_server(self):
from calibre.library.server.main import start_threaded_server
from calibre.library.server import server_config
@ -495,7 +504,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
dynamic.set('sort_history', self.library_view.model().sort_history)
self.save_layout_state()
def quit(self, checked=True, restart=False):
def quit(self, checked=True, restart=False, debug_on_restart=False):
if not self.confirm_quit():
return
try:
@ -503,6 +512,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
except:
pass
self.restart_after_quit = restart
self.debug_on_restart = debug_on_restart
QApplication.instance().quit()
def donate(self, *args):