def launch_worker(self, gui=False, redirect_output=None, job_name=None): start = time.monotonic() id = next(self.launched_worker_counter) fd, rfile = tempfile.mkstemp(prefix='ipc_result_%d_%d_' % (self.id, id), dir=base_dir(), suffix='.pickle') os.close(fd) if redirect_output is None: redirect_output = not gui env = { 'CALIBRE_WORKER_ADDRESS': environ_item(as_hex_unicode(msgpack_dumps(self.address))), 'CALIBRE_WORKER_KEY': environ_item(as_hex_unicode(self.auth_key)), 'CALIBRE_WORKER_RESULT': environ_item(as_hex_unicode(rfile)), } cw = self.do_launch(env, gui, redirect_output, rfile, job_name=job_name) if isinstance(cw, string_or_bytes): raise CriticalError('Failed to launch worker process:\n' + force_unicode(cw)) if DEBUG: print( 'Worker Launch took: {:.2f} seconds'.format(time.monotonic() - start)) return cw
def env(self): if ispy3: env = os.environ.copy() else: # We use this inefficient method of copying the environment variables # because of non ascii env vars on windows. See https://bugs.launchpad.net/bugs/811191 env = {} for key in os.environ: try: val = os.environ[key] if isinstance(val, unicode_type): # On windows subprocess cannot handle unicode env vars try: val = val.encode(filesystem_encoding) except ValueError: val = val.encode('utf-8') if isinstance(key, unicode_type): key = key.encode('ascii') env[key] = val except: pass env[native_string_type('CALIBRE_WORKER')] = environ_item('1') td = as_hex_unicode(msgpack_dumps(base_dir())) env[native_string_type('CALIBRE_WORKER_TEMP_DIR')] = environ_item(td) env.update(self._env) return env
def launch_worker(self, gui=False, redirect_output=None, job_name=None): start = time.time() with self._worker_launch_lock: self.launched_worker_count += 1 id = self.launched_worker_count fd, rfile = tempfile.mkstemp(prefix=u'ipc_result_%d_%d_' % (self.id, id), dir=base_dir(), suffix=u'.pickle') os.close(fd) if redirect_output is None: redirect_output = not gui env = { 'CALIBRE_WORKER_ADDRESS': environ_item(hexlify(msgpack_dumps(self.listener.address))), 'CALIBRE_WORKER_KEY': environ_item(hexlify(self.auth_key)), 'CALIBRE_WORKER_RESULT': environ_item(hexlify(rfile.encode('utf-8'))), } cw = self.do_launch(env, gui, redirect_output, rfile, job_name=job_name) if isinstance(cw, string_or_bytes): raise CriticalError('Failed to launch worker process:\n' + cw) if DEBUG: print('Worker Launch took:', time.time() - start) return cw
def env(self): env = os.environ.copy() env[native_string_type('CALIBRE_WORKER')] = environ_item('1') td = as_hex_unicode(msgpack_dumps(base_dir())) env[native_string_type('CALIBRE_WORKER_TEMP_DIR')] = environ_item(td) env.update(self._env) return env
def create_worker(env, priority='normal', cwd=None, func='main'): from calibre.utils.ipc.server import create_listener auth_key = os.urandom(32) address, listener = create_listener(auth_key) env = dict(env) env.update({ 'CALIBRE_WORKER_ADDRESS': environ_item(as_hex_unicode(msgpack_dumps(address))), 'CALIBRE_WORKER_KEY': environ_item(as_hex_unicode(auth_key)), 'CALIBRE_SIMPLE_WORKER': environ_item('calibre.utils.ipc.simple_worker:%s' % func), }) w = Worker(env) w(cwd=cwd, priority=priority) return listener, w
def windows_repair(library_path=None): import subprocess from calibre.utils.serialize import json_dumps, json_loads from polyglot.binary import as_hex_unicode, from_hex_bytes if library_path: library_path = as_hex_unicode(json_dumps(library_path)) winutil.prepare_for_restart() os.environ['CALIBRE_REPAIR_CORRUPTED_DB'] = environ_item(library_path) subprocess.Popen([sys.executable]) else: try: app = Application([]) from calibre.gui2.dialogs.restore_library import repair_library_at library_path = json_loads( from_hex_bytes(os.environ.pop('CALIBRE_REPAIR_CORRUPTED_DB'))) done = repair_library_at(library_path, wait_time=4) except Exception: done = False error_dialog( None, _('Failed to repair library'), _('Could not repair library. Click "Show details" for more information.' ), det_msg=traceback.format_exc(), show=True) if done: subprocess.Popen([sys.executable]) app.quit()
def __call__(self, redirect_output=True, cwd=None, priority=None): ''' If redirect_output is True, output from the child is redirected to a file on disk and this method returns the path to that file. ''' exe = self.gui_executable if self.gui else self.executable env = self.env try: origwd = cwd or os.path.abspath(getcwd()) except EnvironmentError: # cwd no longer exists origwd = cwd or os.path.expanduser('~') env[native_string_type('ORIGWD')] = environ_item( as_hex_unicode(msgpack_dumps(origwd))) _cwd = cwd if priority is None: priority = prefs['worker_process_priority'] cmd = [exe] if isinstance(exe, string_or_bytes) else exe args = { 'env': env, 'cwd': _cwd, } if iswindows: priority = { 'high': subprocess.HIGH_PRIORITY_CLASS, 'normal': subprocess.NORMAL_PRIORITY_CLASS, 'low': subprocess.IDLE_PRIORITY_CLASS }[priority] args['creationflags'] = subprocess.CREATE_NO_WINDOW | priority else: niceness = { 'normal': 0, 'low': 10, 'high': 20, }[priority] args['env']['CALIBRE_WORKER_NICENESS'] = str(niceness) ret = None if redirect_output: self._file = PersistentTemporaryFile('_worker_redirect.log') args['stdout'] = self._file._fd args['stderr'] = subprocess.STDOUT if iswindows: args['stdin'] = subprocess.PIPE ret = self._file.name if iswindows and 'stdin' not in args: # On windows when using the pythonw interpreter, # stdout, stderr and stdin may not be valid args['stdin'] = subprocess.PIPE args['stdout'] = windows_null_file args['stderr'] = subprocess.STDOUT self.child = subprocess.Popen(cmd, **args) if 'stdin' in args: self.child.stdin.close() self.log_path = ret return ret
def run_in_debug_mode(): from calibre.debug import run_calibre_debug import tempfile, subprocess fd, logpath = tempfile.mkstemp('.txt') os.close(fd) os.environ['CALIBRE_RESTARTING_FROM_GUI'] = environ_item('1') run_calibre_debug( '--gui-debug', logpath, stdout=lopen(logpath, 'w'), stderr=subprocess.STDOUT, stdin=lopen(os.devnull, 'r'))
def main(): fp, d = os.path.abspath(__file__), os.path.dirname if 'CALIBRE_DEVELOP_FROM' not in os.environ: env = os.environ.copy() env['CALIBRE_DEVELOP_FROM'] = environ_item(d(d(d(d(d(fp)))))) subprocess.call(['calibre-debug', '-e', fp], env=env) return sys.path.insert(0, os.path.dirname(fp)) if 'wpd' in sys.modules: del sys.modules['wpd'] import wpd from calibre.constants import plugins plugins._plugins['wpd'] = (wpd, '') sys.path.pop(0) # from calibre.devices.mtp.test import run # run() # return from calibre.devices.winusb import scan_usb_devices from calibre.devices.mtp.driver import MTP_DEVICE dev = MTP_DEVICE(None) dev.startup() print(dev.wpd, dev.wpd_error) try: devices = scan_usb_devices() pnp_id = dev.detect_managed_devices(devices) if not pnp_id: raise ValueError('Failed to detect device') # pprint.pprint(dev.detected_devices) print('Trying to connect to:', pnp_id) dev.open(pnp_id, '') pprint.pprint(dev.dev.data) print('Connected to:', dev.get_gui_name()) print('Total space', dev.total_space()) print('Free space', dev.free_space()) # pprint.pprint(dev.dev.create_folder(dev.filesystem_cache.entries[0].object_id, # 'zzz')) # print ('Fetching file: oFF (198214 bytes)') # stream = dev.get_file('oFF') # print ("Fetched size: ", stream.tell()) # size = 4 # stream = io.BytesIO(b'a'*size) # name = 'zzz-test-file.txt' # stream.seek(0) # f = dev.put_file(dev.filesystem_cache.entries[0], name, stream, size) # print ('Put file:', f) dev.filesystem_cache.dump() finally: dev.shutdown() print('Device connection shutdown')
def launch_worker(self, gui=False, redirect_output=None, job_name=None): start = time.time() with self._worker_launch_lock: self.launched_worker_count += 1 id = self.launched_worker_count fd, rfile = tempfile.mkstemp(prefix=u'ipc_result_%d_%d_'%(self.id, id), dir=base_dir(), suffix=u'.pickle') os.close(fd) if redirect_output is None: redirect_output = not gui env = { 'CALIBRE_WORKER_ADDRESS' : environ_item(as_hex_unicode(msgpack_dumps(self.address))), 'CALIBRE_WORKER_KEY' : environ_item(as_hex_unicode(self.auth_key)), 'CALIBRE_WORKER_RESULT' : environ_item(as_hex_unicode(rfile)), } cw = self.do_launch(env, gui, redirect_output, rfile, job_name=job_name) if isinstance(cw, string_or_bytes): raise CriticalError('Failed to launch worker process:\n'+cw) if DEBUG: print('Worker Launch took:', time.time() - start) return cw
def create_worker(env, priority='normal', cwd=None, func='main'): env = dict(env) a, b = Pipe() with a: env.update({ 'CALIBRE_WORKER_FD': str(a.fileno()), 'CALIBRE_SIMPLE_WORKER': environ_item('calibre.utils.ipc.simple_worker:%s' % func), }) w = Worker(env) w(cwd=cwd, priority=priority, pass_fds=(a.fileno(), )) return b, w
def do_launch(self, gui, redirect_output, rfile, job_name=None): a, b = Pipe() with a: env = { 'CALIBRE_WORKER_FD': str(a.fileno()), 'CALIBRE_WORKER_RESULT': environ_item(as_hex_unicode(rfile)) } w = Worker(env, gui=gui, job_name=job_name) try: w(pass_fds=(a.fileno(), ), redirect_output=redirect_output) except BaseException: try: w.kill() except: pass b.close() import traceback return traceback.format_exc() return ConnectedWorker(w, b, rfile)
def windows_repair(library_path=None): import subprocess from calibre.utils.serialize import json_dumps, json_loads from polyglot.binary import as_hex_unicode, from_hex_bytes if library_path: library_path = as_hex_unicode(json_dumps(library_path)) winutil.prepare_for_restart() os.environ['CALIBRE_REPAIR_CORRUPTED_DB'] = environ_item(library_path) subprocess.Popen([sys.executable]) else: try: app = Application([]) from calibre.gui2.dialogs.restore_library import repair_library_at library_path = json_loads(from_hex_bytes(os.environ.pop('CALIBRE_REPAIR_CORRUPTED_DB'))) done = repair_library_at(library_path, wait_time=4) except Exception: done = False error_dialog(None, _('Failed to repair library'), _( 'Could not repair library. Click "Show details" for more information.'), det_msg=traceback.format_exc(), show=True) if done: subprocess.Popen([sys.executable]) app.quit()
def __call__(self, redirect_output=True, cwd=None, priority=None): ''' If redirect_output is True, output from the child is redirected to a file on disk and this method returns the path to that file. ''' exe = self.gui_executable if self.gui else self.executable env = self.env try: origwd = cwd or os.path.abspath(os.getcwdu()) except EnvironmentError: # cwd no longer exists origwd = cwd or os.path.expanduser(u'~') env[native_string_type('ORIGWD')] = environ_item(as_hex_unicode(msgpack_dumps(origwd))) _cwd = cwd if priority is None: priority = prefs['worker_process_priority'] cmd = [exe] if isinstance(exe, string_or_bytes) else exe args = { 'env' : env, 'cwd' : _cwd, } if iswindows: priority = { 'high' : win32process.HIGH_PRIORITY_CLASS, 'normal' : win32process.NORMAL_PRIORITY_CLASS, 'low' : win32process.IDLE_PRIORITY_CLASS}[priority] args['creationflags'] = win32process.CREATE_NO_WINDOW|priority else: niceness = { 'normal' : 0, 'low' : 10, 'high' : 20, }[priority] args['preexec_fn'] = partial(renice, niceness) ret = None if redirect_output: self._file = PersistentTemporaryFile('_worker_redirect.log') args['stdout'] = self._file._fd args['stderr'] = subprocess.STDOUT if iswindows: args['stdin'] = subprocess.PIPE ret = self._file.name if iswindows and 'stdin' not in args: # On windows when using the pythonw interpreter, # stdout, stderr and stdin may not be valid args['stdin'] = subprocess.PIPE args['stdout'] = windows_null_file args['stderr'] = subprocess.STDOUT if not iswindows: # Close inherited file descriptors in worker # On windows, this is done in the worker process # itself args['close_fds'] = True self.child = subprocess.Popen(cmd, **args) if 'stdin' in args: self.child.stdin.close() self.log_path = ret return ret
def run_gui(opts, args, listener, app, gui_debug=None): si = singleinstance('db') if not si: ext = '.exe' if iswindows else '' error_dialog(None, _('Cannot start calibre'), _( 'Another calibre program that can modify calibre libraries, such as,' ' {} or {} is already running. You must first shut it down, before' ' starting the main calibre program. If you are sure no such' ' program is running, try restarting your computer.').format( 'calibre-server' + ext, 'calibredb' + ext), show=True) return 1 initialize_file_icon_provider() app.load_builtin_fonts(scan_for_fonts=True) if not dynamic.get('welcome_wizard_was_run', False): from calibre.gui2.wizard import wizard wizard().exec_() dynamic.set('welcome_wizard_was_run', True) from calibre.gui2.ui import Main if isosx: actions = tuple(Main.create_application_menubar()) else: actions = tuple(Main.get_menubar_actions()) 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] if getattr(runner.main, 'debug_on_restart', False) or gui_debug is not None: run_in_debug_mode() else: import subprocess if hasattr(sys, 'frameworks_dir'): app = os.path.dirname(os.path.dirname(os.path.realpath(sys.frameworks_dir))) prints('Restarting with:', app) subprocess.Popen('sleep 3s; open ' + shellquote(app), shell=True) else: os.environ['CALIBRE_RESTARTING_FROM_GUI'] = environ_item('1') if iswindows and hasattr(winutil, 'prepare_for_restart'): winutil.prepare_for_restart() args = ['-g'] if os.path.splitext(e)[0].endswith('-debug') else [] prints('Restarting with:', ' '.join([e] + args)) subprocess.Popen([e] + args) else: if iswindows: try: runner.main.system_tray_icon.hide() except: pass if getattr(runner.main, 'gui_debug', None) is not None: e = sys.executable if getattr(sys, 'frozen', False) else sys.argv[0] debugfile = runner.main.gui_debug from calibre.gui2 import open_local_file if iswindows: with open(debugfile, 'r+b') as f: raw = f.read() raw = re.sub(b'(?<!\r)\n', b'\r\n', raw) f.seek(0) f.truncate() f.write(raw) open_local_file(debugfile) return ret
isbsd = isfreebsd or isnetbsd or isdragonflybsd ishaiku = 'haiku1' in _plat islinux = not(iswindows or isosx or isbsd or ishaiku) isfrozen = hasattr(sys, 'frozen') isunix = isosx or islinux or ishaiku isportable = hasenv('CALIBRE_PORTABLE_BUILD') ispy3 = sys.version_info.major > 2 isxp = isoldvista = False if iswindows: wver = sys.getwindowsversion() isxp = wver.major < 6 isoldvista = wver.build < 6002 is64bit = sys.maxsize > (1 << 32) isworker = hasenv('CALIBRE_WORKER') or hasenv('CALIBRE_SIMPLE_WORKER') if isworker: os.environ.pop(environ_item('CALIBRE_FORCE_ANSI'), None) FAKE_PROTOCOL, FAKE_HOST = 'https', 'calibre-internal.invalid' VIEWER_APP_UID = 'com.calibre-ebook.viewer' EDITOR_APP_UID = 'com.calibre-ebook.edit-book' MAIN_APP_UID = 'com.calibre-ebook.main-gui' try: preferred_encoding = locale.getpreferredencoding() codecs.lookup(preferred_encoding) except: preferred_encoding = 'utf-8' win32event = importlib.import_module('win32event') if iswindows else None winerror = importlib.import_module('winerror') if iswindows else None win32api = importlib.import_module('win32api') if iswindows else None fcntl = None if iswindows else importlib.import_module('fcntl')
def main(args=sys.argv): if os.environ.pop('CALIBRE_RESTARTING_FROM_GUI', None) == environ_item('1'): time.sleep(2) # give the parent process time to cleanup and close if iswindows and 'CALIBRE_REPAIR_CORRUPTED_DB' in os.environ: windows_repair() return 0 gui_debug = None if args[0] == '__CALIBRE_GUI_DEBUG__': gui_debug = args[1] args = ['calibre'] if iswindows: # Ensure that all ebook editor instances are grouped together in the task # bar. This prevents them from being grouped with viewer process when # launched from within calibre, as both use calibre-parallel.exe set_app_uid(MAIN_APP_UID) try: app, opts, args = init_qt(args) except AbortInit: return 1 try: si = singleinstance(singleinstance_name) except Exception: error_dialog(None, _('Cannot start calibre'), _( 'Failed to start calibre, single instance locking failed. Click "Show Details" for more information'), det_msg=traceback.format_exc(), show=True) return 1 if si and opts.shutdown_running_calibre: return 0 if si: try: listener = create_listener() except socket.error: if iswindows or islinux: cant_start(det_msg=traceback.format_exc(), listener_failed=True) if os.path.exists(gui_socket_address()): os.remove(gui_socket_address()) try: listener = create_listener() except socket.error: cant_start(det_msg=traceback.format_exc(), listener_failed=True) else: return run_gui(opts, args, listener, app, gui_debug=gui_debug) else: return run_gui(opts, args, listener, app, gui_debug=gui_debug) otherinstance = False try: listener = create_listener() except socket.error: # Good singleinstance is correct (on UNIX) otherinstance = True else: # On windows only singleinstance can be trusted otherinstance = True if iswindows else False if not otherinstance and not opts.shutdown_running_calibre: return run_gui(opts, args, listener, app, gui_debug=gui_debug) communicate(opts, args) return 0
def run_gui(opts, args, listener, app, gui_debug=None): si = singleinstance('db') if not si: ext = '.exe' if iswindows else '' error_dialog( None, _('Cannot start calibre'), _('Another calibre program that can modify calibre libraries, such as,' ' {} or {} is already running. You must first shut it down, before' ' starting the main calibre program. If you are sure no such' ' program is running, try restarting your computer.').format( 'calibre-server' + ext, 'calibredb' + ext), show=True) return 1 initialize_file_icon_provider() app.load_builtin_fonts(scan_for_fonts=True) if not dynamic.get('welcome_wizard_was_run', False): from calibre.gui2.wizard import wizard wizard().exec_() dynamic.set('welcome_wizard_was_run', True) from calibre.gui2.ui import Main if isosx: actions = tuple(Main.create_application_menubar()) else: actions = tuple(Main.get_menubar_actions()) 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] if getattr(runner.main, 'debug_on_restart', False) or gui_debug is not None: run_in_debug_mode() else: if hasattr(sys, 'frameworks_dir'): app = os.path.dirname( os.path.dirname(os.path.realpath(sys.frameworks_dir))) from calibre.debug import run_calibre_debug prints('Restarting with:', app) run_calibre_debug( '-c', 'import sys, os, time; time.sleep(3); os.execlp("open", "open", sys.argv[-1])', app) else: import subprocess os.environ['CALIBRE_RESTARTING_FROM_GUI'] = environ_item('1') if iswindows and hasattr(winutil, 'prepare_for_restart'): winutil.prepare_for_restart() if hasattr(sys, 'run_local'): cmd = [sys.run_local] if DEBUG: cmd += ['calibre-debug', '-g'] else: cmd.append('calibre') else: args = [ '-g' ] if os.path.splitext(e)[0].endswith('-debug') else [] cmd = [e] + args prints('Restarting with:', ' '.join(cmd)) subprocess.Popen(cmd) else: if iswindows: try: runner.main.system_tray_icon.hide() except: pass if getattr(runner.main, 'gui_debug', None) is not None: e = sys.executable if getattr(sys, 'frozen', False) else sys.argv[0] debugfile = runner.main.gui_debug from calibre.gui2 import open_local_file if iswindows: with open(debugfile, 'r+b') as f: raw = f.read() raw = re.sub(b'(?<!\r)\n', b'\r\n', raw) f.seek(0) f.truncate() f.write(raw) open_local_file(debugfile) return ret
def main(args=sys.argv): if os.environ.pop('CALIBRE_RESTARTING_FROM_GUI', None) == environ_item('1'): time.sleep(2) # give the parent process time to cleanup and close if iswindows and 'CALIBRE_REPAIR_CORRUPTED_DB' in os.environ: windows_repair() return 0 gui_debug = None if args[0] == '__CALIBRE_GUI_DEBUG__': gui_debug = args[1] args = ['calibre'] try: app, opts, args = init_qt(args) except AbortInit: return 1 try: si = singleinstance(singleinstance_name) except Exception: error_dialog( None, _('Cannot start calibre'), _('Failed to start calibre, single instance locking failed. Click "Show Details" for more information' ), det_msg=traceback.format_exc(), show=True) return 1 if si and opts.shutdown_running_calibre: return 0 if si: try: listener = create_listener() except socket.error: if iswindows or islinux: cant_start(det_msg=traceback.format_exc(), listener_failed=True) if os.path.exists(gui_socket_address()): os.remove(gui_socket_address()) try: listener = create_listener() except socket.error: cant_start(det_msg=traceback.format_exc(), listener_failed=True) else: return run_gui(opts, args, listener, app, gui_debug=gui_debug) else: return run_gui(opts, args, listener, app, gui_debug=gui_debug) otherinstance = False try: listener = create_listener() except socket.error: # Good singleinstance is correct (on UNIX) otherinstance = True else: # On windows only singleinstance can be trusted otherinstance = True if iswindows else False if not otherinstance and not opts.shutdown_running_calibre: return run_gui(opts, args, listener, app, gui_debug=gui_debug) communicate(opts, args) return 0