From 060560ce1887717c4ecbc21d88276b06938869ad Mon Sep 17 00:00:00 2001 From: Sambhav Kothari Date: Wed, 31 Jan 2018 21:37:37 +0530 Subject: [PATCH 1/5] Search for fpcalc in MEIPASS if packaged --- picard/util/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/picard/util/__init__.py b/picard/util/__init__.py index 66b7da21a..810f0c9dc 100644 --- a/picard/util/__init__.py +++ b/picard/util/__init__.py @@ -197,6 +197,9 @@ def find_executable(*executables): executables = [e + '.exe' for e in executables] paths = [os.path.dirname(sys.executable)] if sys.executable else [] paths += os.environ.get('PATH', '').split(os.pathsep) + # This is for searching for executables bundled in packaged builds + if getattr(sys, 'frozen', False): + paths += sys._MEIPASS for path in paths: for executable in executables: f = os.path.join(path, executable) From bb0b04ec16b79d04a38684186811f911d4663a83 Mon Sep 17 00:00:00 2001 From: Sambhav Kothari Date: Wed, 31 Jan 2018 21:51:28 +0530 Subject: [PATCH 2/5] Add fpcalc to data files --- picard.spec | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/picard.spec b/picard.spec index 9e057bbee..792388b51 100644 --- a/picard.spec +++ b/picard.spec @@ -2,6 +2,7 @@ import os import glob +import platform def _picard_get_locale_files(): @@ -28,9 +29,17 @@ def get_locale_messages(): return data_files - block_cipher = None data_files = get_locale_messages() +os_name = platform.system() +fpcalc_name = 'fpcalc' + +if os_name == 'Windows': + fpcalc_name += '.exe' + +if os.path.isfile(fpcalc_name): + data_files += [(fpcalc_name, fpcalc_name)] + a = Analysis(['tagger.py'], pathex=['picard'], From f5632873e3e8a3784b552f9c3687c8749007f9c5 Mon Sep 17 00:00:00 2001 From: Sambhav Kothari Date: Wed, 31 Jan 2018 21:51:47 +0530 Subject: [PATCH 3/5] Use 64 bit binaries for fpcalc --- appveyor.yml | 4 ++-- picard.spec | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 28ffb1e0a..8382f2d2c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,13 +23,13 @@ environment: PYTHON_ARCH: 64 build_script: - cmd: >- - appveyor DownloadFile https://github.com/acoustid/chromaprint/releases/download/v%CHROMAPRINT_FPCALC_VERSION%/chromaprint-fpcalc-%CHROMAPRINT_FPCALC_VERSION%-windows-i686.zip -FileName fpcalc.zip + appveyor DownloadFile https://github.com/acoustid/chromaprint/releases/download/v%CHROMAPRINT_FPCALC_VERSION%/chromaprint-fpcalc-%CHROMAPRINT_FPCALC_VERSION%-windows-x86_64.zip -FileName fpcalc.zip appveyor DownloadFile https://indy.fulgan.com/SSL/openssl-%OPENSSL_VERSION%-x64_86-win64.zip -FileName openssl.zip 7z x fpcalc.zip -y - copy /Y chromaprint-fpcalc-%CHROMAPRINT_FPCALC_VERSION%-windows-i686\fpcalc.exe %PYTHON% + copy /Y chromaprint-fpcalc-%CHROMAPRINT_FPCALC_VERSION%-windows-x86_64\fpcalc.exe %PYTHON% 7z x openssl.zip -y diff --git a/picard.spec b/picard.spec index 792388b51..57c1708e1 100644 --- a/picard.spec +++ b/picard.spec @@ -35,7 +35,7 @@ os_name = platform.system() fpcalc_name = 'fpcalc' if os_name == 'Windows': - fpcalc_name += '.exe' + fpcalc_name = 'fpcalc.exe' if os.path.isfile(fpcalc_name): data_files += [(fpcalc_name, fpcalc_name)] From 9f3cb9ced8f504b8edcad812af3c76d414d15153 Mon Sep 17 00:00:00 2001 From: Sambhav Kothari Date: Wed, 31 Jan 2018 22:47:09 +0530 Subject: [PATCH 4/5] Re-search for fpcalc path on each execution if running as a packaged distributable --- appveyor.yml | 2 +- picard.spec | 10 ++++++---- picard/acoustid/__init__.py | 6 +++++- picard/util/__init__.py | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8382f2d2c..82613ab47 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -29,7 +29,7 @@ build_script: 7z x fpcalc.zip -y - copy /Y chromaprint-fpcalc-%CHROMAPRINT_FPCALC_VERSION%-windows-x86_64\fpcalc.exe %PYTHON% + copy /Y chromaprint-fpcalc-%CHROMAPRINT_FPCALC_VERSION%-windows-x86_64\fpcalc.exe fpcalc.exe 7z x openssl.zip -y diff --git a/picard.spec b/picard.spec index 57c1708e1..e739cb426 100644 --- a/picard.spec +++ b/picard.spec @@ -30,20 +30,22 @@ def get_locale_messages(): block_cipher = None -data_files = get_locale_messages() os_name = platform.system() -fpcalc_name = 'fpcalc' +binaries = [] +data_files = get_locale_messages() + +fpcalc_name = 'fpcalc' if os_name == 'Windows': fpcalc_name = 'fpcalc.exe' if os.path.isfile(fpcalc_name): - data_files += [(fpcalc_name, fpcalc_name)] + binaries += [(fpcalc_name, '')] a = Analysis(['tagger.py'], pathex=['picard'], - binaries=[], + binaries=binaries, datas=data_files, hiddenimports=[], hookspath=[], diff --git a/picard/acoustid/__init__.py b/picard/acoustid/__init__.py index ccd867f38..10d5a2d94 100644 --- a/picard/acoustid/__init__.py +++ b/picard/acoustid/__init__.py @@ -19,6 +19,7 @@ from collections import deque from functools import partial +import sys from PyQt5 import QtCore from picard import config, log from picard.const import FPCALC_NAMES @@ -34,7 +35,10 @@ class AcoustIDClient(QtCore.QObject): self._running = 0 self._max_processes = 2 - if not config.setting["acoustid_fpcalc"]: + # The second condition is checked because in case of a packaged build of picard + # the temp directory that pyinstaller decompresses picard into changes on every + # launch, thus we need to ignore the existing config values. + if not config.setting["acoustid_fpcalc"] or getattr(sys, 'frozen', False): fpcalc_path = find_executable(*FPCALC_NAMES) if fpcalc_path: config.setting["acoustid_fpcalc"] = fpcalc_path diff --git a/picard/util/__init__.py b/picard/util/__init__.py index 810f0c9dc..b86a3c300 100644 --- a/picard/util/__init__.py +++ b/picard/util/__init__.py @@ -199,7 +199,7 @@ def find_executable(*executables): paths += os.environ.get('PATH', '').split(os.pathsep) # This is for searching for executables bundled in packaged builds if getattr(sys, 'frozen', False): - paths += sys._MEIPASS + paths += [sys._MEIPASS] for path in paths: for executable in executables: f = os.path.join(path, executable) From 62efdb1c48fffccfcce2eff1280f0d6b0ddb41fc Mon Sep 17 00:00:00 2001 From: Sambhav Kothari Date: Wed, 31 Jan 2018 23:17:29 +0530 Subject: [PATCH 5/5] Move pyinstaller related env variables to utils and add documentation --- picard/acoustid/__init__.py | 5 ++--- picard/util/__init__.py | 9 +++++++-- tagger.py | 6 ++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/picard/acoustid/__init__.py b/picard/acoustid/__init__.py index 10d5a2d94..25b60f9f1 100644 --- a/picard/acoustid/__init__.py +++ b/picard/acoustid/__init__.py @@ -19,11 +19,10 @@ from collections import deque from functools import partial -import sys from PyQt5 import QtCore from picard import config, log from picard.const import FPCALC_NAMES -from picard.util import find_executable +from picard.util import find_executable, is_frozen from picard.acoustid.json_helpers import parse_recording @@ -38,7 +37,7 @@ class AcoustIDClient(QtCore.QObject): # The second condition is checked because in case of a packaged build of picard # the temp directory that pyinstaller decompresses picard into changes on every # launch, thus we need to ignore the existing config values. - if not config.setting["acoustid_fpcalc"] or getattr(sys, 'frozen', False): + if not config.setting["acoustid_fpcalc"] or is_frozen: fpcalc_path = find_executable(*FPCALC_NAMES) if fpcalc_path: config.setting["acoustid_fpcalc"] = fpcalc_path diff --git a/picard/util/__init__.py b/picard/util/__init__.py index b86a3c300..0e27f1154 100644 --- a/picard/util/__init__.py +++ b/picard/util/__init__.py @@ -34,6 +34,11 @@ from string import Template # Required for compatibility with lastfmplus which imports this from here rather than loading it direct. from picard.const import MUSICBRAINZ_SERVERS +# These variables are set by pyinstaller if running from a packaged build +# See http://pyinstaller.readthedocs.io/en/stable/runtime-information.html +is_frozen = getattr(sys, 'frozen', False) +frozen_temp_path = getattr(sys, '_MEIPASS', '') + class LockableObject(QtCore.QObject): @@ -198,8 +203,8 @@ def find_executable(*executables): paths = [os.path.dirname(sys.executable)] if sys.executable else [] paths += os.environ.get('PATH', '').split(os.pathsep) # This is for searching for executables bundled in packaged builds - if getattr(sys, 'frozen', False): - paths += [sys._MEIPASS] + if is_frozen: + paths += [frozen_temp_path] for path in paths: for executable in executables: f = os.path.join(path, executable) diff --git a/tagger.py b/tagger.py index e6c5321d1..8885c3e3d 100755 --- a/tagger.py +++ b/tagger.py @@ -6,10 +6,12 @@ import sys sys.path.insert(0, '.') from picard.tagger import main +from picard.util import is_frozen, frozen_temp_path + # This is needed to find resources when using pyinstaller -if getattr(sys, 'frozen', False): - basedir = sys._MEIPASS +if is_frozen: + basedir = frozen_temp_path else: basedir = os.path.dirname(os.path.abspath(__file__))