diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c531c5e84..2f245c9f0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -456,9 +456,10 @@ jobs: shell: bash run: | cd "application/target/installer/Swift Console.app" + for f in $(find Contents/Resources/lib/ -name '*.dylib' -or -name '*.so') do - codesign \ + codesign -vvvv \ -s "${{ secrets.APPLE_DEVELOPER_ID }}" \ --timestamp \ "$f" @@ -466,14 +467,15 @@ jobs: for f in $(ls Contents/Resources/lib/python3.9/site-packages/**/Qt/lib/*.framework/Versions/5/*) do - codesign \ + codesign -vvvv \ -s "${{ secrets.APPLE_DEVELOPER_ID }}" \ --timestamp \ "$f" done cd ../../../ - codesign \ + + codesign -vvvv \ -s "${{ secrets.APPLE_DEVELOPER_ID }}" --deep \ --entitlements installers/macOS/entitlements.plist \ --timestamp \ @@ -626,11 +628,14 @@ jobs: shell: bash run: | cd installer - codesign \ + + codesign -vvvv \ -s "${{ secrets.APPLE_DEVELOPER_ID }}" \ -f --timestamp \ $(cat installer-archive.filename) + xcrun altool \ + --verbose \ --notarize-app \ --file $(cat installer-archive.filename) \ --primary-bundle-id ${{ env.APP_BUNDLE_ID }} \ @@ -654,6 +659,7 @@ jobs: cd installer xcrun altool \ + --verbose \ --notarization-info ${{ env.REQUEST_UUID }} \ --apiKey ${{ secrets.APPLE_KEY_ID }} \ --apiIssuer ${{ secrets.APPLE_ISSUER_ID }} | tee notarize_status.log @@ -666,7 +672,7 @@ jobs: exit 1 fi - xcrun stapler staple "$(cat installer-archive.filename)" + xcrun stapler staple -v "$(cat installer-archive.filename)" - name: Add archive to path. shell: bash @@ -743,7 +749,7 @@ jobs: shell: bash working-directory: binaries run: | - codesign \ + codesign -vvvv \ -s "${{ secrets.APPLE_DEVELOPER_ID }}" \ --timestamp \ --options=runtime \ @@ -840,10 +846,13 @@ jobs: shell: bash working-directory: binaries-all run: | - codesign \ + + codesign -vvvv \ -s "${{ secrets.APPLE_DEVELOPER_ID }}" \ -f --timestamp "swift-binaries_${{ matrix.os.short_name }}_${{ env.VERSION }}-all.zip" + xcrun altool \ + --verbose \ --notarize-app \ --file swift-binaries_${{ matrix.os.short_name }}_${{ env.VERSION }}-all.zip\ --primary-bundle-id ${{ env.APP_BUNDLE_ID }} \ diff --git a/Makefile.toml b/Makefile.toml index 135551065..fae25868f 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -419,7 +419,9 @@ app_name = get_env APP_NAME cp target/release/${app_name} py39-dist/${app_name} os = os_family if eq ${os} mac - exec --fail-on-error install_name_tool -change /install/lib/libpython3.9.dylib @executable_path/lib/libpython3.9.dylib py39-dist/${app_name} + exec --fail-on-error install_name_tool -change /install/lib/libpython3.9.dylib @rpath/libpython3.9.dylib py39-dist/${app_name} + exec --fail-on-error install_name_tool -add_rpath @executable_path/../Resources/lib py39-dist/${app_name} + exec --fail-on-error install_name_tool -add_rpath @executable_path/lib py39-dist/${app_name} elseif eq ${os} linux cp target/release/windowpos py39-dist/windowpos end @@ -482,6 +484,7 @@ py_folders = array test tests examples __pycache__ demos turtledemo translations qt_folders = array plugins/geoservices plugins/virtualkeyboard plugins/sqldrivers lib/Tix8.4.3 tcl/tix8.4.3 Qt/resources PySide2/resources qml_folders = array qml/QtWeb* qml/QtBluetooth* qml/QtNfc* qml/QtGamepad qml/QtTest qml/QtQuick3D qml/Qt3D qml/QtSensors qml/QtLocation qml/QtPositioning all_folders = array_concat ${py_folders} ${qt_folders} ${qml_folders} + for name in ${all_folders} folders = glob_array **/${name}/ for folder in ${folders} @@ -490,6 +493,7 @@ for name in ${all_folders} end file_exts = array pyc pyi tcl gif png + for ext in ${file_exts} files = glob_array **/*.${ext} for file in ${files} @@ -505,6 +509,7 @@ for ext in ${file_exts} end libs = array QtSensors QtLocation Qt5Location QtPositioning Qt3D Qt53D Qt5Nfc Qt5Web QtWeb Qt5Pdf Qt5Designer Qt5DesignerComponents Qt5VirtualKeyboard Qt5Bluetooth Qt5Quick3D + for lib in ${libs} files = glob_array ./**/*${lib}* for file in ${files} @@ -514,6 +519,7 @@ for lib in ${libs} end os = os_family + if eq ${os} windows rm -r ./Scripts @@ -580,6 +586,18 @@ else end endif +if eq ${os} mac + rm -r lib/python3.9/site-packages/PySide2/Designer.app/ + + rm lib/python3.9/lib-dynload/_testcapi.cpython-39-darwin.so + rm lib/python3.9/lib-dynload/xxlimited.cpython-39-darwin.so + + rm -r lib/python3.9/venv/ + + rm -r lib/pkgconfig/ + rm -r lib/thread2.8.5/ +endif + py_internal_libs = array Lib/email Lib/distutils Lib/http Lib/multiprocessing Lib/msilib Lib/http Lib/dbm Lib/curses Lib/xml Lib/xmlrpc Lib/urllib Lib/ensurepip Lib/venv Lib/wsgiref Lib/lib2to3 for name in ${py_internal_libs} @@ -590,6 +608,7 @@ for name in ${py_internal_libs} end files = glob_array ./**/*.py + for file in ${files} rm ${file} end @@ -671,7 +690,7 @@ set_env BACKGROUND_PATH "resources/images/LogoBackground.jpg" [tasks.dist-to-installer-app] [tasks.dist-to-installer-app.mac] -dependencies = ["dist-to-installer-env"] +dependencies = ["dist-to-installer-env", "store-version"] script_runner = "@duckscript" script = ''' final_dir = get_env FINAL_DIR @@ -686,6 +705,9 @@ contents_resources_dir = get_env CONTENTS_RESOURCES_DIR contents_resources_dir = set ${contents_dir}/${contents_resources_dir} info_plist_path = get_env INFO_PLIST_PATH icns_path = get_env ICNS_PATH +version_path = get_env VERSION_PATH +version = readfile ${version_path} +version = trim_end ${version} if is_path_exists ${tmp_dir} rm -r ${tmp_dir} @@ -695,10 +717,8 @@ mkdir ${contents_dir} mkdir ${contents_mac_os} exec --fail-on-error cp -r py39-dist "${contents_resources_dir}" exec --fail-on-error mv ./${contents_resources_dir}/${app_original_name} "./${contents_mac_os}/${app_file_prefix}" -exec --fail-on-error ln -s "../Resources/lib" ${contents_mac_os}/lib -exec --fail-on-error ln -s "../Resources/.frozen" ${contents_mac_os}/.frozen -exec --fail-on-error ln -s "../Resources/resources" ${contents_mac_os}/resources cp ./${info_plist_path} ./${contents_dir}/Info.plist +exec --fail-on-error sed -i "" -e "s/@@VERSION@@/${version}/g" "${contents_dir}/Info.plist" mkdir ${contents_resources_dir} cp ${icns_path} ./${contents_resources_dir}/${app_file_prefix}.icns ''' diff --git a/entrypoint/src/main.rs b/entrypoint/src/main.rs index aec3e363f..b4276cf17 100644 --- a/entrypoint/src/main.rs +++ b/entrypoint/src/main.rs @@ -1,11 +1,14 @@ -#![cfg_attr(target_os = "windows", windows_subsystem = "windows")] +#![cfg_attr(target_os = "windows", windows_subsystem = "windows")] + +use std::path::{Path, PathBuf}; use pyo3::prelude::*; use pyo3::types::PyTuple; use entrypoint::attach_console; -type Result = std::result::Result>; +type Error = Box; +type Result = std::result::Result; fn handle_wayland() { #[cfg(target_os = "linux")] @@ -34,14 +37,38 @@ fn handle_splash() { } } +fn app_dir() -> Result { + let current_exe = std::env::current_exe()?; + current_exe + .parent() + .ok_or("no parent directory".into()) + .map(Path::to_path_buf) +} + +fn pythonhome_dir() -> Result { + let app_dir = app_dir()?.to_path_buf(); + if cfg!(target_os = "macos") { + if let Some(parent) = app_dir.parent() { + let resources = parent.join("Resources/lib"); + if resources.exists() { + Ok(parent.join("Resources")) + } else { + Ok(app_dir) + } + } else { + Ok(app_dir) + } + } else { + Ok(app_dir) + } +} + fn main() -> Result<()> { attach_console(); handle_wayland(); - let current_exe = std::env::current_exe()?; - let parent = current_exe.parent().ok_or("no parent directory")?; let args: Vec<_> = std::env::args().collect(); - std::env::set_var("SWIFTNAV_CONSOLE_FROZEN", parent); - std::env::set_var("PYTHONHOME", parent); + std::env::set_var("SWIFTNAV_CONSOLE_FROZEN", app_dir()?); + std::env::set_var("PYTHONHOME", pythonhome_dir()?); std::env::set_var("PYTHONDONTWRITEBYTECODE", "1"); handle_splash(); let exit_code = Python::with_gil(|py| { diff --git a/installers/macOS/Info.plist b/installers/macOS/Info.plist index bcda6edbe..67ff63106 100644 --- a/installers/macOS/Info.plist +++ b/installers/macOS/Info.plist @@ -2,11 +2,34 @@ - CFBundleIconFile - Swift Console.icns - NSHighResolutionCapable - True - CFBundlePackageType - APPL + CFBundleIconFile + Swift Console.icns + + NSHighResolutionCapable + True + + CFBundlePackageType + APPL + + CFBundleExecutable + Swift Console + + CFBundleDisplayName + Swift Console + + CFBundleInfoDictionaryVersion + 6.0 + + CFBundleIdentifier + com.swift-nav.SwiftConsole + + CFBundleName + Swift Console + + CFBundleShortVersionString + @@VERSION@@ + + CFBundleVersion + @@VERSION@@ - + \ No newline at end of file diff --git a/installers/macOS/entitlements.plist b/installers/macOS/entitlements.plist index 5b61965e5..a2a990521 100644 --- a/installers/macOS/entitlements.plist +++ b/installers/macOS/entitlements.plist @@ -15,5 +15,7 @@ com.apple.security.cs.disable-executable-page-protection + com.apple.security.app-sandbox + diff --git a/swiftnav_console/main.py b/swiftnav_console/main.py index 186e998bf..2850dab0d 100644 --- a/swiftnav_console/main.py +++ b/swiftnav_console/main.py @@ -557,15 +557,27 @@ def is_frozen() -> bool: Returns: bool: Whether the application is frozen. """ - me = os.path.dirname(sys.executable) + me = get_app_dir() var_frozen = os.environ.get("SWIFTNAV_CONSOLE_FROZEN", "") != "" path_frozen = os.path.exists(os.path.join(me, ".frozen")) return var_frozen or path_frozen -def get_app_dir() -> str: +def get_app_dir(alt: bool = False) -> str: + """Fetches the application resources directory. + + Args: + alt (bool): fetch an alternate data directory (only valid on macOS) + + Returns: + str: path to the resoure dir (accounting for OS differences) + """ var_frozen = os.environ.get("SWIFTNAV_CONSOLE_FROZEN", "") if var_frozen != "": + if platform.system() == "Darwin": + if alt: + return var_frozen + return os.path.join(var_frozen, "../Resources") return var_frozen return os.path.dirname(sys.executable) @@ -576,10 +588,11 @@ def get_capnp_path() -> str: Returns: str: The path to the capnp file. """ - d = get_app_dir() path = "" if is_frozen(): - path = os.path.join(d, "resources/base", CONSOLE_BACKEND_CAPNP_PATH) + path = os.path.join(get_app_dir(), "resources/base", CONSOLE_BACKEND_CAPNP_PATH) + if not os.path.exists(path): + path = os.path.join(get_app_dir(alt=True), "resources/base", CONSOLE_BACKEND_CAPNP_PATH) else: path = os.path.join( os.path.dirname(os.path.dirname(__file__)), "src/main/resources/base", CONSOLE_BACKEND_CAPNP_PATH