def main(): enforce_requirements() setup_windows_console() # The hook will only be used in the Qt GUI right now setup_thread_excepthook() # on osx, delete Process Serial Number arg generated for apps launched in Finder sys.argv = [x for x in sys.argv if not x.startswith('-psn')] # old 'help' syntax if len(sys.argv) > 1 and sys.argv[1] == 'help': sys.argv.remove('help') sys.argv.append('-h') # read arguments from stdin pipe and prompt for i, arg in enumerate(sys.argv): if arg == '-': if not sys.stdin.isatty(): sys.argv[i] = sys.stdin.read() break else: raise Exception('Cannot get argument from stdin') elif arg == '?': sys.argv[i] = input("Enter argument:") elif arg == ':': sys.argv[i] = prompt_password('Enter argument (will not echo):', False) # parse command line parser = get_parser() args = parser.parse_args() # config is an object passed to various constructors config_options = args.__dict__ config_options = { key: value for key, value in config_options.items() if value is not None and key not in config_variables.get(args.cmd, {}) } logs.set_level(config_options['verbose']) if config_options.get('server'): config_options['auto_connect'] = False config_options['cwd'] = os.getcwd() # fixme: this can probably be achieved with a runtime hook (pyinstaller) portable_base_path = None try: if startup.is_bundle and os.path.exists( os.path.join(sys._MEIPASS, 'is_portable')): config_options['portable'] = True # Ensure the wallet data is stored in the same directory as the executable. portable_base_path = os.path.dirname(sys.executable) except AttributeError: config_options['portable'] = False if config_options.get('portable'): if portable_base_path is None: # Default to the same directory the 'electrum-sv' script is in. portable_base_path = os.path.dirname(os.path.realpath(sys.argv[0])) config_options['electrum_sv_path'] = os.path.join( portable_base_path, 'electrum_sv_data') if config_options.get('file_logging'): if config_options.get('portable'): log_path = os.path.join(config_options['electrum_sv_path'], "logs") else: log_path = os.path.join(platform.user_dir(prefer_local=True), "logs") os.makedirs(log_path, exist_ok=True) log_path = os.path.join(log_path, time.strftime("%Y%m%d-%H%M%S") + ".log") logs.add_file_output(log_path) if config_options.get('testnet'): Net.set_to(SVTestnet) elif config_options.get('scalingtestnet'): Net.set_to(SVScalingTestnet) # check uri uri = config_options.get('url') if uri: if not web.is_URI(uri): print('unknown command:', uri, file=sys.stderr) sys.exit(1) config_options['url'] = uri # todo: defer this to gui config = SimpleConfig(config_options) cmdname = config.get('cmd') # Set the app state proxy if cmdname == 'gui': try: from electrumsv.gui.qt.app_state import QtAppStateProxy except ImportError as e: platform.missing_import(e) QtAppStateProxy(config, 'qt') elif cmdname == 'daemon' and 'daemon_app_module' in config_options: load_app_module(config_options['daemon_app_module'], config) else: AppStateProxy(config, 'cmdline') app_state.set_app(DefaultApp()) # run non-RPC commands separately if cmdname in ['create', 'restore']: run_non_RPC(config) sys.exit(0) if cmdname == 'gui': fd, server = daemon.get_fd_or_server(config) if fd is not None: run_app_with_daemon(fd, True, config_options) else: result = server.gui(config_options) elif cmdname == 'daemon': subcommand = config.get('subcommand') if subcommand in ['load_wallet']: init_daemon(config_options) if subcommand in [None, 'start']: fd, server = daemon.get_fd_or_server(config) if fd is not None: if not app_state.has_app(): print("No application present to run.") sys.exit(0) if subcommand == 'start': if not hasattr(os, "fork"): print( f"Starting the daemon is not supported on {sys.platform}." ) sys.exit(0) pid = os.fork() if pid: print("Starting daemon (PID %d)" % pid, file=sys.stderr) sys.exit(0) run_app_with_daemon(fd, False, config_options) else: result = server.daemon(config_options) else: server = daemon.get_server(config) if server is not None: result = server.daemon(config_options) else: print("Daemon not running") sys.exit(1) else: # command line server = daemon.get_server(config) init_cmdline(config_options, server) if server is not None: result = server.run_cmdline(config_options) else: cmd = known_commands[cmdname] if cmd.requires_network: print("Daemon not running; try 'electrum-sv daemon start'") sys.exit(1) else: result = run_offline_command(config, config_options) # print result if isinstance(result, str): print(result) elif type(result) is dict and result.get('error'): print(result.get('error'), file=sys.stderr) elif result is not None: print(json_encode(result)) sys.exit(0)
def main(): # The hook will only be used in the Qt GUI right now setup_thread_excepthook() # on osx, delete Process Serial Number arg generated for apps launched in Finder sys.argv = [x for x in sys.argv if not x.startswith('-psn')] # old 'help' syntax if len(sys.argv) > 1 and sys.argv[1] == 'help': sys.argv.remove('help') sys.argv.append('-h') # read arguments from stdin pipe and prompt for i, arg in enumerate(sys.argv): if arg == '-': if not sys.stdin.isatty(): sys.argv[i] = sys.stdin.read() break else: raise Exception('Cannot get argument from stdin') elif arg == '?': sys.argv[i] = input("Enter argument:") elif arg == ':': sys.argv[i] = prompt_password('Enter argument (will not echo):', False) # parse command line parser = get_parser() args = parser.parse_args() # config is an object passed to the various constructors (wallet, interface, gui) config_options = args.__dict__ config_options = { key: value for key, value in config_options.items() if value is not None and key not in config_variables.get(args.cmd, {}) } logs.set_level(config_options['verbose']) if config_options.get('server'): config_options['auto_connect'] = False config_options['cwd'] = os.getcwd() # fixme: this can probably be achieved with a runtime hook (pyinstaller) try: if is_bundle and os.path.exists( os.path.join(sys._MEIPASS, 'is_portable')): config_options['portable'] = True except AttributeError: config_options['portable'] = False if config_options.get('portable'): config_options['electrum_sv_path'] = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'electrum_sv_data') if config_options.get('file_logging'): log_path = os.path.join(platform.user_dir(prefer_local=True), "logs") os.makedirs(log_path, exist_ok=True) log_path = os.path.join(log_path, time.strftime("%Y%m%d-%H%M%S") + ".log") logs.add_file_output(log_path) if config_options.get('testnet'): Net.set_to(SVTestnet) # check uri uri = config_options.get('url') if uri: if not web.is_URI(uri): print('unknown command:', uri, file=sys.stderr) sys.exit(1) config_options['url'] = uri # todo: defer this to gui config = SimpleConfig(config_options) cmdname = config.get('cmd') # Set the app state proxy if cmdname == 'gui': try: from electrumsv.gui.qt.app_state import QtAppStateProxy except ImportError as e: platform.missing_import(e) QtAppStateProxy(config, 'qt') else: AppStateProxy(config, 'cmdline') # run non-RPC commands separately if cmdname in ['create', 'restore']: run_non_RPC(config) sys.exit(0) if cmdname == 'gui': fd, server = daemon.get_fd_or_server(config) if fd is not None: d = daemon.Daemon(fd, True) d.start() app_state.app.run_gui() sys.exit(0) else: result = server.gui(config_options) elif cmdname == 'daemon': subcommand = config.get('subcommand') if subcommand in ['load_wallet']: init_daemon(config_options) if subcommand in [None, 'start']: fd, server = daemon.get_fd_or_server(config) if fd is not None: if subcommand == 'start': pid = os.fork() if pid: print("starting daemon (PID %d)" % pid, file=sys.stderr) sys.exit(0) d = daemon.Daemon(fd, False) d.start() if config.get('websocket_server'): try: from electrumsv import websockets except ImportError as e: platform.missing_import(e) websockets.WebSocketServer(config, d.network).start() if config.get('requests_dir'): path = os.path.join(config.get('requests_dir'), 'index.html') if not os.path.exists(path): print("Requests directory not configured.") print("You can configure it using " "https://github.com/spesmilo/electrum-merchant") sys.exit(1) d.join() sys.exit(0) else: result = server.daemon(config_options) else: server = daemon.get_server(config) if server is not None: result = server.daemon(config_options) else: print("Daemon not running") sys.exit(1) else: # command line server = daemon.get_server(config) init_cmdline(config_options, server) if server is not None: result = server.run_cmdline(config_options) else: cmd = known_commands[cmdname] if cmd.requires_network: print("Daemon not running; try 'electrum-sv daemon start'") sys.exit(1) else: result = run_offline_command(config, config_options) # print result if isinstance(result, str): print(result) elif type(result) is dict and result.get('error'): print(result.get('error'), file=sys.stderr) elif result is not None: print(json_encode(result)) sys.exit(0)
def _copy_electron_cash_wallets(self): """ Work out whether we should show UI to offer to copy the user's Electron Cash wallets to their ElectrumSV wallet directory, and if so, show it and give them the chance. """ def ignore_wallet_file(wallet_path): if os.path.isdir(wallet_path): return True if wallet_path.startswith("."): return True return False def count_user_wallets(wallets_path): if os.path.exists(wallets_path): filenames = [ filename for filename in os.listdir(wallets_path) if not ignore_wallet_file( os.path.join(wallets_path, filename)) ] return len(filenames) return 0 # If the user has ElectrumSV wallets already, we do not offer to copy the one's # Electron Cash has. esv_wallets_dir = os.path.join(platform.user_dir(), "wallets") if count_user_wallets(esv_wallets_dir) > 0: return ec_wallets_dir = get_electron_cash_user_dir(esv_wallets_dir) ec_wallet_count = count_user_wallets(ec_wallets_dir) # If the user does not have Electron Cash wallets to copy, there's no point in offering. if ec_wallet_count == 0: return def update_summary_label(): selection_count = len(file_list.selectedItems()) if selection_count == 0: summary_label.setText( _("No wallets are selected / will be copied.")) elif selection_count == 1: summary_label.setText( _("1 wallet is selected / will be copied.")) else: summary_label.setText( _("%d wallets are selected / will be copied.") % selection_count) wallet_filenames = sorted(os.listdir(ec_wallets_dir), key=lambda s: s.lower()) file_list = QListWidget() file_list.setSelectionMode(QAbstractItemView.ExtendedSelection) for filename in wallet_filenames: if not ignore_wallet_file(os.path.join(ec_wallets_dir, filename)): file_list.addItem(QListWidgetItem(filename)) file_list.itemSelectionChanged.connect(update_summary_label) vbox = QVBoxLayout() introduction_label = QLabel( _("Your Electron Cash wallet directory was found. If you want ElectrumSV to import " "any of them on your behalf, select the ones you want copied from the list below " "before clicking the Next button.")) introduction_label.setWordWrap(True) vbox.setSpacing(20) vbox.addWidget(introduction_label) vbox.addWidget(file_list) summary_label = QLabel() update_summary_label() vbox.addWidget(summary_label) self._set_standard_layout(vbox, title=_('Import Electron Cash wallets')) v = self.loop.exec_() # Cancel, exit application. if v == -1: raise UserCancelled() if v != 2: raise GoBack() # If the user selected any files, then we copy them before exiting to the next page. for item in file_list.selectedItems(): filename = item.text() source_path = os.path.join(ec_wallets_dir, filename) target_path = os.path.join(esv_wallets_dir, filename) try: shutil.copyfile(source_path, target_path) except shutil.Error: # For now we ignore copy errors. pass