Adds a check to the Windows nsis installer and uninstaller
that will show an error popup if Electrum is still running to prevent
a broken installation that happen if the installer only partly
overwrites the existing installation (see #6748).
This works by trying to open the .exe files in the Electrum installation
directory in append mode, if Electrum is still running the installer
will not be able to open the .exe and the check fails.
Based on https://github.com/Electron-Cash/Electron-Cash/pull/2185
If osslsigncode is missing `build-wine/unsign.sh` fails silently with
status code 0 causing the `release.sh` script to interpret the result as
valid and skipping the actual comparison of the windows binaries.
probably since qt6 migration many symlinks inside the .app in bundled PyQt were broken:
```
$ cp -r $HOME/electrum/dist/Electrum.app Electrum-ghost3.app
cp: /Users/vagrant/electrum/dist/Electrum.app/Contents/Resources/PyQt6/Qt6/lib/QtMultimediaQuick.framework/QtMultimediaQuick: No such file or directory
cp: /Users/vagrant/electrum/dist/Electrum.app/Contents/Resources/PyQt6/Qt6/lib/QtQuickTimeline.framework/QtQuickTimeline: No such file or directory
cp: /Users/vagrant/electrum/dist/Electrum.app/Contents/Resources/PyQt6/Qt6/lib/QtQuickControls2.framework/QtQuickControls2: No such file or directory
```
We were stripping out lots of datas/binaries from Qt from the mac build artifact, leaving behind dangling symlinks.
Instead of adding more hacks on top of the current hacks to also rm the dangling links, I tried to clean up this blacklisting.
There was no issue re the Windows build, no symlinks there, but I like to keep these two spec files in sync.
-----
Some numbers:
- mac:
- without any exclusions at all, the mac .dmg is 80 MiB.
- with these exclusions it is 57 MiB.
- win:
- (haven't built without exclusions.)
- with the previous stripping strategy, exes were 68M/68M/50M
- with these exclusions, exes are 66M/66M/50M
trezor==0.13.10 pulls in new dep "slip10", which relies on importlib magic
see 19561f0429/slip10/__init__.py (L6)
```
10.13 | E | plugins.trezor.trezor | error importing trezor plugin deps
Traceback (most recent call last):
File "importlib/metadata/__init__.py", line 397, in from_name
StopIteration
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "electrum/plugins/trezor/trezor.py", line 29, in <module>
from .clientbase import TrezorClientBase, RecoveryDeviceInputMethod
File "PyInstaller/loader/pyimod02_importers.py", line 450, in exec_module
File "electrum/plugins/trezor/clientbase.py", line 18, in <module>
import trezorlib.device
File "PyInstaller/loader/pyimod02_importers.py", line 450, in exec_module
File "trezorlib/device.py", line 27, in <module>
File "PyInstaller/loader/pyimod02_importers.py", line 450, in exec_module
File "slip10/__init__.py", line 6, in <module>
File "importlib/metadata/__init__.py", line 889, in version
File "importlib/metadata/__init__.py", line 862, in distribution
File "importlib/metadata/__init__.py", line 399, in from_name
importlib.metadata.PackageNotFoundError: No package metadata was found for slip10
```
- this merges `contrib/deterministic-build/locale` and `electrum/locale`
- it is now once again possible have translations when running from a local git clone
- which was already possible in the past before crowdin removed their unauthenticated APIs
- see https://github.com/spesmilo/electrum/issues/9531
- however, the translations available are the often-old frozen strings from electrum-locale
- while previously one could just download the latest strings from crowdin
This removes support for Ledger HW.1 and "Nano" (non-S) devices.
These were manufactured/sold around 2015-2016, and are long unsupported by the upstream vendor.
We previously added a deprecation warning to the GUI [0] released in 4.3.3 (2023-01-02), to warn owners of these devices.
This PR now fully removes support.
As a consequence, the unmaintained btchip-python dependency can now be removed, which solves [1].
[0]: 9b82eb6d06
[1]: https://github.com/spesmilo/electrum/issues/9370#issuecomment-2593675364
Haven't checked if electrum-ecc compiles libsecp reproducibly.
For now let's just keep the old flow.
(but if we spent time on making that compilation reproducible,
the appimage and the macos builds could use it directly)
setup exe used to install Electrum to `C:\Program Files (x86)\Electrum`,
but now as the binaries are amd64, we should install to `C:\Program Files\Electrum`.
With this change, based on my experiments, looks like if there is an existing install,
nsis will keep using that path, but if it's a fresh install, it will now use the 64-bit path.
follow-up fcc4e1d387
Looks like upstream key file changed. Still the same crypto key, just updated expiration date.
```
$ sha256sum winehq_20*
78b185fabdb323971d13bd329fefc8038e08559aa51c4996de18db0639a51df6 *winehq_2019.key
d965d646defe94b3dfba6d5b4406900ac6c81065428bf9d9303ad7a72ee8d1b8 *winehq_2024.key
$ gpg winehq_2019.key
gpg: WARNING: no command supplied. Trying to guess what you mean ...
pub rsa3072 2018-12-10 [SC]
D43F640145369C51D786DDEA76F1A20FF987672F
uid WineHQ packages <wine-devel@winehq.org>
sub rsa3072 2018-12-10 [E] [expired: 2020-12-09]
$ gpg winehq_2024.key
gpg: WARNING: no command supplied. Trying to guess what you mean ...
pub rsa3072 2018-12-10 [SC]
D43F640145369C51D786DDEA76F1A20FF987672F
uid WineHQ packages <wine-devel@winehq.org>
sub rsa3072 2018-12-10 [E]
```
Co-authored-by: SomberNight <somber.night@protonmail.com>
Ah ok, I give up for now... the prev does not really work.
The prior commit works on Windows but not on macOS.
On Windows, it would package all plugins as code and only as code.
On MacOS however, it would not package any plugins at all. And with this commit,
where I mark the plugins folder to be packaged as *data*, it packages all plugins as *both* code and data.
Not sure why.
Let's just package all plugins as both code and data, and ignore the code instances explicitly...
The hw_wallet and jade plugins were being included twice in the pyinstaller binaries.
They were apparently the only two plugins being picked as "modules" (a.pure),
which by default are included as compiled-bytecode.
In addition, we included "electrum/plugins" as data (a.data), which meant all
plugins in source form.
Instead of hacking around to fix the specific issue, this attempts a larger clean-up.
```
602 WARNING: Failed to collect submodules for 'pkg_resources._vendor.pyparsing.diagram' because importing 'pkg_resources._vendor.pyparsing.diagram' raised: ModuleNotFoundError: No module named 'railroad'
libsecp256k1 library failed to load. exceptions: [FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-2.dll' (or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-1.dll'(or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-0.dll' (or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'libsecp256k1-2.dll' (or one ofits dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'libsecp256k1-1.dll' (or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'libsecp256k1-0.dll' (or one of its dependencies). Try using the full path with constructor syntax.")]
libsecp256k1 library failed to load. exceptions: [FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-2.dll' (or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-1.dll'(or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-0.dll' (or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'libsecp256k1-2.dll' (or one ofits dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'libsecp256k1-1.dll' (or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'libsecp256k1-0.dll' (or one of its dependencies). Try using the full path with constructor syntax.")]
libsecp256k1 library failed to load. exceptions: [FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-2.dll' (or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-1.dll'(or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-0.dll' (or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'libsecp256k1-2.dll' (or one ofits dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'libsecp256k1-1.dll' (or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'libsecp256k1-0.dll' (or one of its dependencies). Try using the full path with constructor syntax.")]
5921 WARNING: collect_data_files - skipping data collection for module 'electrum.plugins' as it is not a package.
```
pyinstaller tries to import electrum and its different submodules at build-time
during the "Analysis" phase. sys._GUI_QT_VERSION was not getting set there,
and the resulting exception was blocking pyinstaller from discovering that
gui/common_qt is being used.
at runtime:
```
$ ./dist/Electrum.app/Contents/MacOS/run_electrum
1.53 | E | daemon.Daemon | GUI raised exception: Exception('Error loading trustedcoin plugin: ModuleNotFoundError("No module named \'electrum.gui.common_qt\'")'). shutting down.
1.53 | E | __main__ | daemon.run_gui errored
Traceback (most recent call last):
File "electrum/plugin.py", line 135, in load_plugin
spec.loader.exec_module(module)
File "<frozen importlib._bootstrap_external>", line 883, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/Users/vagrant/electrum/dist/Electrum.app/Contents/MacOS/electrum/plugins/trustedcoin/qt.py", line 51, in <module>
from .common_qt import TrustedcoinPluginQObject
File "/Users/vagrant/electrum/dist/Electrum.app/Contents/MacOS/electrum/plugins/trustedcoin/common_qt.py", line 16, in <module>
from electrum.gui.common_qt.plugins import PluginQObject
ModuleNotFoundError: No module named 'electrum.gui.common_qt'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "run_electrum", line 456, in handle_cmd
d.run_gui()
File "electrum/daemon.py", line 617, in run_gui
self.gui_object = gui.ElectrumGui(config=self.config, daemon=self, plugins=self._plugins)
File "electrum/util.py", line 473, in do_profile
o = func(*args, **kw_args)
File "electrum/gui/qt/__init__.py", line 153, in __init__
self.plugins.load_plugin('trustedcoin')
File "electrum/plugin.py", line 138, in load_plugin
raise Exception(f"Error loading {name} plugin: {repr(e)}") from e
Exception: Error loading trustedcoin plugin: ModuleNotFoundError("No module named 'electrum.gui.common_qt'")
```
In `build-electrum-git.sh`, the `-w` CLI arg is removed: it was apparently ignored as we are using a .spec file,
and pyinstaller 5.0+ is now raising a hard error (see https://github.com/pyinstaller/pyinstaller/issues/6660).
```
option(s) not allowed:
--console/--nowindowed/--windowed/--noconsole
makespec options not valid when a .spec file is given
```
-----
In ecc_fast.py, we don't sys.exit() anymore as pyinstaller 5.0+ tries to import electrum during the Analysis phase.
see https://github.com/pyinstaller/pyinstaller/pull/6171
```
57912 INFO: Looking for dynamic libraries
1746 INFO: gettext setting initial language to None
1932 ERROR: libsecp256k1 library failed to load. exceptions: [FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-2.dll' (or one of its depende
ncies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-1.dll' (or one of its dependenc
ies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-0.dll' (or one of its dependencie
s). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'libsecp256k1-2.dll' (or one of its dependencies). Try using the full path with constructor
syntax."), FileNotFoundError("Could not find module 'libsecp256k1-1.dll' (or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find
module 'libsecp256k1-0.dll' (or one of its dependencies). Try using the full path with constructor syntax.")]
Traceback (most recent call last):
File "C:\python3\lib\runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\python3\lib\runpy.py", line 86, in _run_code
exec(code, run_globals)
File "C:\python3\scripts\pyinstaller.exe\__main__.py", line 7, in <module>
File "C:\python3\lib\site-packages\PyInstaller\__main__.py", line 194, in _console_script_run
run()
File "C:\python3\lib\site-packages\PyInstaller\__main__.py", line 180, in run
run_build(pyi_config, spec_file, **vars(args))
File "C:\python3\lib\site-packages\PyInstaller\__main__.py", line 61, in run_build
PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
File "C:\python3\lib\site-packages\PyInstaller\building\build_main.py", line 1006, in main
build(specfile, distpath, workpath, clean_build)
File "C:\python3\lib\site-packages\PyInstaller\building\build_main.py", line 928, in build
exec(code, spec_namespace)
File "deterministic.spec", line 55, in <module>
a = Analysis([home+'run_electrum',
File "C:\python3\lib\site-packages\PyInstaller\building\build_main.py", line 428, in __init__
self.__postinit__()
File "C:\python3\lib\site-packages\PyInstaller\building\datastruct.py", line 184, in __postinit__
self.assemble()
File "C:\python3\lib\site-packages\PyInstaller\building\build_main.py", line 736, in assemble
isolated.call(find_binary_dependencies, self.binaries, self.binding_redirects, collected_packages)
File "C:\python3\lib\site-packages\PyInstaller\isolated\_parent.py", line 372, in call
return isolated.call(function, *args, **kwargs)
File "C:\python3\lib\site-packages\PyInstaller\isolated\_parent.py", line 302, in call
raise RuntimeError(f"Child process call to {function.__name__}() failed with:\n" + output)
RuntimeError: Child process call to find_binary_dependencies() failed with:
File "C:\python3\lib\site-packages\PyInstaller\isolated\_child.py", line 63, in run_next_command
output = function(*args, **kwargs)
File "C:\python3\lib\site-packages\PyInstaller\building\build_main.py", line 177, in find_binary_dependencies
__import__(package)
File "C:\python3\lib\site-packages\electrum\__init__.py", line 20, in <module>
from .wallet import Wallet
File "C:\python3\lib\site-packages\electrum\wallet.py", line 53, in <module>
from .bip32 import BIP32Node, convert_bip32_intpath_to_strpath, convert_bip32_strpath_to_intpath
File "C:\python3\lib\site-packages\electrum\bip32.py", line 11, in <module>
from . import constants
File "C:\python3\lib\site-packages\electrum\constants.py", line 30, in <module>
from . import bitcoin
File "C:\python3\lib\site-packages\electrum\bitcoin.py", line 35, in <module>
from . import ecc
File "C:\python3\lib\site-packages\electrum\ecc.py", line 39, in <module>
from .ecc_fast import _libsecp256k1, SECP256K1_EC_UNCOMPRESSED
File "C:\python3\lib\site-packages\electrum\ecc_fast.py", line 151, in <module>
sys.exit(f"Error: Failed to load libsecp256k1.")
SystemExit: Error: Failed to load libsecp256k1.
🗯 ERROR: build-electrum-git failed
```
Also, the -OO flag is removed from wine python, for similar reasons:
pyinstaller imports electrum, and in electrum/__init__.py, we raise
if -O is used: 9b1fb0e5fe/electrum/__init__.py (L40)