From a7453e877a9b575883dcf077acd50b703f05da67 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 31 Aug 2019 15:05:14 +0530 Subject: [PATCH] Simplify launching of console utilities on macOS --- bypy/macos/__main__.py | 22 +++++----------------- bypy/macos/site.py | 19 ++++++++++++++----- manual/creating_plugins.rst | 3 +-- manual/develop.rst | 2 +- manual/news.rst | 2 +- src/calibre/debug.py | 2 -- src/calibre/gui2/__init__.py | 2 ++ src/calibre/linux.py | 2 +- src/calibre/utils/ipc/launch.py | 4 ++-- 9 files changed, 27 insertions(+), 31 deletions(-) diff --git a/bypy/macos/__main__.py b/bypy/macos/__main__.py index 021580cf10..c50940f7fd 100644 --- a/bypy/macos/__main__.py +++ b/bypy/macos/__main__.py @@ -203,7 +203,6 @@ class Freeze(object): if not test_launchers and not self.dont_strip: self.strip_files() if not test_launchers: - self.create_console_app() self.create_gui_apps() self.run_tests() @@ -213,8 +212,7 @@ class Freeze(object): @flush def run_tests(self): - cc_dir = join(self.contents_dir, 'calibre-debug.app', 'Contents') - self.test_runner(join(cc_dir, 'MacOS', 'calibre-debug'), self.contents_dir) + self.test_runner(join(self.contents_dir, 'MacOS', 'calibre-debug'), self.contents_dir) @flush def add_resources(self): @@ -677,14 +675,6 @@ class Freeze(object): else: os.symlink(join('../..', x), join(cc_dir, x)) - @flush - def create_console_app(self): - def specialise_plist(plist): - plist['LSBackgroundOnly'] = '1' - plist['CFBundleIdentifier'] = 'com.calibre-ebook.console' - plist['CFBundleExecutable'] = 'calibre-parallel' - self.create_app_clone('console.app', specialise_plist) - @flush def create_gui_apps(self): input_formats = sorted(set(json.loads( @@ -696,19 +686,17 @@ class Freeze(object): def specialise_plist(launcher, remove_types, plist): plist['CFBundleDisplayName'] = plist['CFBundleName'] = { - 'ebook-viewer': 'E-book Viewer', 'ebook-edit': 'Edit Book', 'calibre-debug': 'calibre (debug)', + 'ebook-viewer': 'E-book Viewer', 'ebook-edit': 'Edit Book', }[launcher] plist['CFBundleExecutable'] = launcher - if launcher != 'calibre-debug': - plist['CFBundleIconFile'] = launcher + '.icns' plist['CFBundleIdentifier'] = 'com.calibre-ebook.' + launcher + plist['CFBundleIconFile'] = launcher + '.icns' if not remove_types: e = plist['CFBundleDocumentTypes'][0] exts = 'epub azw3'.split() if launcher == 'ebook-edit' else input_formats e['CFBundleTypeExtensions'] = exts - for launcher in ('ebook-viewer', 'ebook-edit', 'calibre-debug'): - remove_types = launcher == 'calibre-debug' - self.create_app_clone(launcher + '.app', partial(specialise_plist, launcher, remove_types), remove_doc_types=remove_types) + for launcher in ('ebook-viewer', 'ebook-edit'): + self.create_app_clone(launcher + '.app', partial(specialise_plist, launcher, False), remove_doc_types=False) @flush def copy_site(self): diff --git a/bypy/macos/site.py b/bypy/macos/site.py index 3b6652ac7e..89ed6c11d7 100644 --- a/bypy/macos/site.py +++ b/bypy/macos/site.py @@ -7,20 +7,23 @@ This is stripped down and customized for use in py2app applications import sys import os + def makepath(*paths): dir = os.path.abspath(os.path.join(*paths)) return dir, os.path.normcase(dir) + def abs__file__(): """Set all module __file__ attribute to an absolute path""" for m in sys.modules.values(): if hasattr(m, '__loader__'): - continue # don't mess with a PEP 302-supplied __file__ + continue # don't mess with a PEP 302-supplied __file__ try: m.__file__ = os.path.abspath(m.__file__) except AttributeError: continue + # This ensures that the initial path provided by the interpreter contains # only absolute pathnames, even if we're running from the build directory. L = [] @@ -38,6 +41,7 @@ sys.path[:] = L del dir, dircase, L _dirs_in_sys_path = None + def _init_pathinfo(): global _dirs_in_sys_path _dirs_in_sys_path = d = {} @@ -47,6 +51,7 @@ def _init_pathinfo(): dir, dircase = makepath(dir) d[dircase] = 1 + def addsitedir(sitedir): global _dirs_in_sys_path if _dirs_in_sys_path is None: @@ -56,7 +61,7 @@ def addsitedir(sitedir): reset = 0 sitedir, sitedircase = makepath(sitedir) if sitedircase not in _dirs_in_sys_path: - sys.path.append(sitedir) # Add path component + sys.path.append(sitedir) # Add path component try: names = os.listdir(sitedir) except os.error: @@ -68,6 +73,7 @@ def addsitedir(sitedir): if reset: _dirs_in_sys_path = None + def addpackage(sitedir, name): global _dirs_in_sys_path if _dirs_in_sys_path is None: @@ -107,29 +113,31 @@ if hasattr(sys, "setdefaultencoding"): sys.setdefaultencoding('utf-8') del sys.setdefaultencoding + def run_entry_point(): bname, mod, func = sys.calibre_basename, sys.calibre_module, sys.calibre_function sys.argv[0] = bname pmod = __import__(mod, fromlist=[1], level=0) return getattr(pmod, func)() + def add_calibre_vars(base): sys.frameworks_dir = os.path.join(os.path.dirname(base), 'Frameworks') sys.resources_location = os.path.abspath(os.path.join(base, 'resources')) sys.extensions_location = os.path.join(sys.frameworks_dir, 'plugins') sys.binaries_path = os.path.join(os.path.dirname(base), 'MacOS') - sys.console_binaries_path = os.path.join(os.path.dirname(base), - 'console.app', 'Contents', 'MacOS') dv = os.environ.get('CALIBRE_DEVELOP_FROM', None) if dv and os.path.exists(dv): sys.path.insert(0, os.path.abspath(dv)) + def nuke_stdout(): # Redirect stdout, stdin and stderr to /dev/null from calibre.constants import plugins plugins['speedup'][0].detach(os.devnull) + def main(): global __file__ @@ -148,7 +156,8 @@ def main(): addsitedir(sys.site_packages) if sys.calibre_is_gui_app and not ( - sys.stdout.isatty() or sys.stderr.isatty() or sys.stdin.isatty()): + sys.stdout.isatty() or sys.stderr.isatty() or sys.stdin.isatty() + ): nuke_stdout() return run_entry_point() diff --git a/manual/creating_plugins.rst b/manual/creating_plugins.rst index 8791eba217..ca8fc285d4 100644 --- a/manual/creating_plugins.rst +++ b/manual/creating_plugins.rst @@ -37,7 +37,7 @@ the directory in which you created :file:`__init__.py`:: .. note:: On macOS, the command line tools are inside the calibre bundle, for example, if you installed calibre in :file:`/Applications` the command line tools - are in :file:`/Applications/calibre.app/Contents/console.app/Contents/MacOS/`. + are in :file:`/Applications/calibre.app/Contents/MacOS/`. You can download the Hello World plugin from `helloworld_plugin.zip `_. @@ -325,4 +325,3 @@ Sharing your plugins with others If you would like to share the plugins you have created with other users of calibre, post your plugin in a new thread in the `calibre plugins forum `_. - diff --git a/manual/develop.rst b/manual/develop.rst index 0819a70b75..b60453fc08 100644 --- a/manual/develop.rst +++ b/manual/develop.rst @@ -198,7 +198,7 @@ the previously checked out calibre code directory, for example:: calibre is the directory that contains the src and resources sub-directories. The calibre command line tools are found inside the calibre app bundle, in -:file:`/Applications/calibre.app/Contents/console.app/Contents/MacOS` +:file:`/Applications/calibre.app/Contents/MacOS` you should add this directory to your PATH environment variable, if you want to run the command line tools easily. diff --git a/manual/news.rst b/manual/news.rst index 5b56408d79..630d2eb171 100644 --- a/manual/news.rst +++ b/manual/news.rst @@ -311,7 +311,7 @@ If you're satisfied with your recipe, and you feel there is enough demand to jus .. note:: On macOS, the command line tools are inside the calibre bundle, for example, if you installed calibre in :file:`/Applications` the command line tools - are in :file:`/Applications/calibre.app/Contents/console.app/Contents/MacOS/`. + are in :file:`/Applications/calibre.app/Contents/MacOS/`. .. seealso:: diff --git a/src/calibre/debug.py b/src/calibre/debug.py index 465d943e6e..594b332b61 100644 --- a/src/calibre/debug.py +++ b/src/calibre/debug.py @@ -17,8 +17,6 @@ from polyglot.builtins import exec_path, raw_input, unicode_type, getcwd def get_debug_executable(): if hasattr(sys, 'frameworks_dir'): base = os.path.dirname(sys.frameworks_dir) - if 'calibre-debug.app' not in base: - base = os.path.join(base, 'calibre-debug.app', 'Contents') return os.path.join(base, 'MacOS', 'calibre-debug') if getattr(sys, 'frozen', False): return os.path.join(os.path.dirname(os.path.abspath(sys.executable)), 'calibre-debug' + ('.exe' if iswindows else '')) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index c219b17380..5ca021bf3f 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -1201,6 +1201,8 @@ def ensure_app(headless=True): has_headless = isosx or islinux or isbsd if headless and has_headless: args += ['-platformpluginpath', plugins_loc, '-platform', 'headless'] + if isosx: + os.environ['QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM'] = '1' _store_app = QApplication(args) if headless and has_headless: _store_app.headless = True diff --git a/src/calibre/linux.py b/src/calibre/linux.py index f3cb635251..340770dc51 100644 --- a/src/calibre/linux.py +++ b/src/calibre/linux.py @@ -1183,7 +1183,7 @@ def cli_index_strings(): return _('Command Line Interface'), _( 'On macOS, the command line tools are inside the calibre bundle, for example,' ' if you installed calibre in :file:`/Applications` the command line tools' - ' are in :file:`/Applications/calibre.app/Contents/console.app/Contents/MacOS/`.'), _( + ' are in :file:`/Applications/calibre.app/Contents/MacOS/`.'), _( 'Documented commands'), _('Undocumented commands'), _( 'You can see usage for undocumented commands by executing them without arguments in a terminal.'), _( 'Change language'), _('Search') diff --git a/src/calibre/utils/ipc/launch.py b/src/calibre/utils/ipc/launch.py index 303e362688..185ed75301 100644 --- a/src/calibre/utils/ipc/launch.py +++ b/src/calibre/utils/ipc/launch.py @@ -59,7 +59,7 @@ class Worker(object): return os.path.join(os.path.dirname(sys.executable), e+'.exe' if isfrozen else 'Scripts\\%s.exe'%e) if isosx: - return os.path.join(sys.console_binaries_path, e) + return os.path.join(sys.binaries_path, e) if isfrozen: return os.path.join(sys.executables_location, e) @@ -74,7 +74,7 @@ class Worker(object): def gui_executable(self): if isosx and not hasattr(sys, 'running_from_setup'): if self.job_name in {'ebook-viewer', 'ebook-edit'}: - return self.executable.replace('/console.app/', '/%s.app/' % self.job_name) + return self.executable.replace('/Contents/', '/Contents/%s.app/Contents/' % self.job_name) return os.path.join(sys.binaries_path, self.exe_name) return self.executable