diff --git a/.github/workflows/installers-conda.yml b/.github/workflows/installers-conda.yml index e754f8f82c3..b146b8b6b27 100644 --- a/.github/workflows/installers-conda.yml +++ b/.github/workflows/installers-conda.yml @@ -54,6 +54,7 @@ name: Nightly conda-based installers env: IS_RELEASE: ${{ github.event_name == 'release' }} + IS_PRE_RELEASE: ${{ github.event_name == 'workflow_dispatch' && inputs.pre }} ENABLE_SSH: ${{ github.event_name == 'workflow_dispatch' && inputs.ssh }} BUILD_MAC: ${{ github.event_name != 'workflow_dispatch' || inputs.macos-x86_64 }} BUILD_ARM: ${{ github.event_name != 'workflow_dispatch' || inputs.macos-arm64 }} @@ -125,7 +126,6 @@ jobs: MACOS_INSTALLER_CERTIFICATE: ${{ secrets.MACOS_INSTALLER_CERTIFICATE }} APPLICATION_PWD: ${{ secrets.APPLICATION_PWD }} CONSTRUCTOR_TARGET_PLATFORM: ${{ matrix.target-platform }} - NSIS_USING_LOG_BUILD: 1 steps: - name: Checkout Code @@ -193,11 +193,17 @@ jobs: cache-environment: true - name: Env Variables - run: env | sort + run: | + NSIS_USING_LOG_BUILD=1 + [[ "$IS_RELEASE" == "true" || "$IS_PRE_RELEASE" == "true" ]] && NSIS_USING_LOG_BUILD=0 + CONDA_BLD_PATH=${RUNNER_TEMP}/conda-bld + + echo "NSIS_USING_LOG_BUILD=$NSIS_USING_LOG_BUILD" >> $GITHUB_ENV + echo "CONDA_BLD_PATH=$CONDA_BLD_PATH" >> $GITHUB_ENV + + env | sort - name: Build ${{ matrix.target-platform }} spyder Conda Package - env: - CONDA_BLD_PATH: ${{ runner.temp }}/conda-bld run: | # Copy built packages to new build location because spyder cannot be # built in workspace @@ -206,8 +212,6 @@ jobs: python build_conda_pkgs.py --build spyder - name: Create Local Conda Channel - env: - CONDA_BLD_PATH: ${{ runner.temp }}/conda-bld run: | conda config --set bld_path $CONDA_BLD_PATH conda index $CONDA_BLD_PATH diff --git a/installers-conda/build_installers.py b/installers-conda/build_installers.py index d9c6c658325..2bb85537766 100644 --- a/installers-conda/build_installers.py +++ b/installers-conda/build_installers.py @@ -33,7 +33,7 @@ from pathlib import Path import platform import re -from subprocess import check_call +from subprocess import run import sys from textwrap import dedent, indent from time import time @@ -217,6 +217,14 @@ def _get_condarc(): return str(file) +def _get_conda_bld_path_url(): + bld_path_url = "file://" + if WINDOWS: + bld_path_url += "/" + bld_path_url += Path(os.getenv('CONDA_BLD_PATH')).as_posix() + return bld_path_url + + def _definitions(): condarc = _get_condarc() definitions = { @@ -246,6 +254,12 @@ def _definitions(): "specs": [k + v for k, v in specs.items()], }, }, + "channels_remap": [ + { + "src": _get_conda_bld_path_url(), + "dest": "https://conda.anaconda.org/conda-forge" + } + ] } if not args.no_local: @@ -371,7 +385,7 @@ def _constructor(): yaml.dump(definitions, BUILD / "construct.yaml") - check_call(cmd_args, env=env) + run(cmd_args, check=True, env=env) def licenses(): diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000000..edd2d210dc2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,9 @@ +[build-system] +requires = [ + "setuptools>=42", + "packaging", +] + +# We're not ready yet to build Spyder with the setuptools backend, but we're +# leaving this for the future. +# build-backend = "setuptools.build_meta" diff --git a/spyder/__init__.py b/spyder/__init__.py index 708a699ce5b..efd0b842837 100644 --- a/spyder/__init__.py +++ b/spyder/__init__.py @@ -29,9 +29,11 @@ OTHER DEALINGS IN THE SOFTWARE. """ -version_info = (6, 0, 0, "dev0") +from packaging.version import parse -__version__ = '.'.join(map(str, version_info)) +version_info = (6, 0, 0, "a5", "dev0") + +__version__ = str(parse('.'.join(map(str, version_info)))) __installer_version__ = __version__ __title__ = 'Spyder' __author__ = 'Spyder Project Contributors and others' diff --git a/spyder/plugins/updatemanager/container.py b/spyder/plugins/updatemanager/container.py index 211fea8df91..0105dfce250 100644 --- a/spyder/plugins/updatemanager/container.py +++ b/spyder/plugins/updatemanager/container.py @@ -20,10 +20,7 @@ from spyder.api.translations import _ from spyder.api.widgets.main_container import PluginMainContainer from spyder.plugins.updatemanager.widgets.status import UpdateManagerStatus -from spyder.plugins.updatemanager.widgets.update import ( - UpdateManagerWidget, - NO_STATUS -) +from spyder.plugins.updatemanager.widgets.update import UpdateManagerWidget from spyder.utils.qthelpers import DialogManager # Logger setup @@ -65,6 +62,9 @@ def setup(self): self.update_manager_status.blockSignals) self.update_manager.sig_download_progress.connect( self.update_manager_status.set_download_progress) + self.update_manager.sig_exception_occurred.connect( + self.sig_exception_occurred + ) self.update_manager.sig_install_on_close.connect( self.set_install_on_close) self.update_manager.sig_quit_requested.connect(self.sig_quit_requested) @@ -75,8 +75,6 @@ def setup(self): self.update_manager_status.sig_show_progress_dialog.connect( self.update_manager.show_progress_dialog) - self.set_status(NO_STATUS) - def update_actions(self): pass diff --git a/spyder/plugins/updatemanager/plugin.py b/spyder/plugins/updatemanager/plugin.py index 39e6c4cb8e7..22d7a2dcfe9 100644 --- a/spyder/plugins/updatemanager/plugin.py +++ b/spyder/plugins/updatemanager/plugin.py @@ -9,14 +9,12 @@ """ # Local imports -from spyder import __version__ from spyder.api.plugins import Plugins, SpyderPluginV2 from spyder.api.translations import _ from spyder.api.plugin_registration.decorators import ( on_plugin_available, on_plugin_teardown ) -from spyder.config.base import DEV from spyder.plugins.updatemanager.container import ( UpdateManagerActions, UpdateManagerContainer @@ -95,12 +93,12 @@ def on_mainwindow_visible(self): """Actions after the mainwindow in visible.""" container = self.get_container() + # Initialize status. + # Note that NO_STATUS also hides the statusbar widget. + container.update_manager_status.set_no_status() + # Check for updates on startup - if ( - DEV is None # Not bootstrap - and 'dev' not in __version__ # Not dev version - and self.get_conf('check_updates_on_startup') - ): + if self.get_conf('check_updates_on_startup'): container.start_check_update(startup=True) # ---- Private API diff --git a/spyder/plugins/updatemanager/scripts/install.bat b/spyder/plugins/updatemanager/scripts/install.bat index 4bdb5533469..3969f20059b 100644 --- a/spyder/plugins/updatemanager/scripts/install.bat +++ b/spyder/plugins/updatemanager/scripts/install.bat @@ -23,6 +23,8 @@ echo IMPORTANT: Do not close this window until it has finished echo ========================================================= echo. +call :wait_for_spyder_quit + IF not "%conda%"=="" IF not "%spy_ver%"=="" ( call :update_subroutine call :launch_spyder @@ -40,8 +42,6 @@ exit %ERRORLEVEL% :install_subroutine echo Installing Spyder from: %install_exe% - call :wait_for_spyder_quit - :: Uninstall Spyder for %%I in ("%prefix%\..\..") do set "conda_root=%%~fI" @@ -69,16 +69,14 @@ exit %ERRORLEVEL% :update_subroutine echo Updating Spyder - call :wait_for_spyder_quit - %conda% install -p %prefix% -y spyder=%spy_ver% - set /P CONT=Press any key to exit... + set /P =Press return to exit... goto :EOF :wait_for_spyder_quit echo Waiting for Spyder to quit... :loop - tasklist /fi "ImageName eq spyder.exe" /fo csv 2>NUL | find /i "spyder.exe">NUL + tasklist /v /fi "ImageName eq pythonw.exe" /fo csv 2>NUL | find "Spyder">NUL IF "%ERRORLEVEL%"=="0" ( timeout /t 1 /nobreak > nul goto loop @@ -87,10 +85,11 @@ exit %ERRORLEVEL% goto :EOF :launch_spyder - echo %prefix% | findstr /b "%USERPROFILE%" > nul && ( - set shortcut_root=%APPDATA% - ) || ( - set shortcut_root=%ALLUSERSPROFILE% - ) - start "" /B "%shortcut_root%\Microsoft\Windows\Start Menu\Programs\spyder\Spyder.lnk" + for %%C in ("%conda%") do set scripts=%%~dpC + set pythonexe=%scripts%..\python.exe + set menuinst=%scripts%menuinst_cli.py + if exist "%prefix%\.nonadmin" (set mode=user) else set mode=system + for /f "delims=" %%s in ('%pythonexe% %menuinst% shortcut --mode=%mode%') do set "shortcut_path=%%~s" + + start "" /B "%shortcut_path%" goto :EOF diff --git a/spyder/plugins/updatemanager/scripts/install.sh b/spyder/plugins/updatemanager/scripts/install.sh index 75b894ad8ec..e5bee00d239 100755 --- a/spyder/plugins/updatemanager/scripts/install.sh +++ b/spyder/plugins/updatemanager/scripts/install.sh @@ -14,15 +14,20 @@ shift $(($OPTIND - 1)) update_spyder(){ $conda install -p $prefix -y spyder=$spy_ver - read -p "Press any key to exit..." + read -p "Press return to exit..." } launch_spyder(){ + root=$(dirname $conda) + pythonexe=$root/python + menuinst=$root/menuinst_cli.py + mode=$([[ -e "${prefix}/.nonadmin" ]] && echo "user" || echo "system") + shortcut_path=$($pythonexe $menuinst shortcut --mode=$mode) + if [[ "$OSTYPE" = "darwin"* ]]; then - shortcut=/Applications/Spyder.app - [[ "$prefix" = "$HOME"* ]] && open -a $HOME$shortcut || open -a $shortcut + open -a $shortcut elif [[ -n "$(which gtk-launch)" ]]; then - gtk-launch spyder_spyder + gtk-launch $(basename ${shortcut_path%.*}) else nohup $prefix/bin/spyder &>/dev/null & fi diff --git a/spyder/plugins/updatemanager/widgets/status.py b/spyder/plugins/updatemanager/widgets/status.py index 7d7468635cd..f3cbedb4ed9 100644 --- a/spyder/plugins/updatemanager/widgets/status.py +++ b/spyder/plugins/updatemanager/widgets/status.py @@ -10,10 +10,9 @@ # Standard library imports import logging -import os # Third party imports -from qtpy.QtCore import QPoint, Qt, Signal, Slot +from qtpy.QtCore import Qt, Signal, Slot from qtpy.QtWidgets import QLabel # Local imports @@ -29,7 +28,6 @@ PENDING ) from spyder.utils.icon_manager import ima -from spyder.utils.qthelpers import add_actions, create_action # Setup logger @@ -38,7 +36,6 @@ class UpdateManagerStatus(StatusBarWidget): """Status bar widget for update manager.""" - BASE_TOOLTIP = _("Application update status") ID = 'update_manager_status' sig_check_update = Signal() @@ -61,8 +58,8 @@ class UpdateManagerStatus(StatusBarWidget): def __init__(self, parent): - self.tooltip = self.BASE_TOOLTIP - super().__init__(parent, show_spinner=True) + self.tooltip = "" + super().__init__(parent) # Check for updates action menu self.menu = SpyderMenu(self) @@ -81,30 +78,23 @@ def set_value(self, value): "Downloading the update will continue in the background.\n" "Click here to show the download dialog again." ) - self.spinner.hide() - self.spinner.stop() self.custom_widget.show() + self.show() elif value == CHECKING: - self.tooltip = self.BASE_TOOLTIP + self.tooltip = value self.custom_widget.hide() - self.spinner.show() - self.spinner.start() + self.hide() elif value == PENDING: self.tooltip = value self.custom_widget.hide() - self.spinner.hide() - self.spinner.stop() + self.show() else: - self.tooltip = self.BASE_TOOLTIP + self.tooltip = "" if self.custom_widget: self.custom_widget.hide() - if self.spinner: - self.spinner.hide() - self.spinner.stop() + self.hide() - self.setVisible(True) self.update_tooltip() - value = f"Spyder: {value}" logger.debug(f"Update manager status: {value}") super().set_value(value) @@ -126,23 +116,7 @@ def set_download_progress(self, percent_progress): @Slot() def show_dialog_or_menu(self): """Show download dialog or status bar menu.""" - value = self.value.split(":")[-1].strip() - if value == DOWNLOADING_INSTALLER: + if self.value == DOWNLOADING_INSTALLER: self.sig_show_progress_dialog.emit(True) - elif value in (PENDING, DOWNLOAD_FINISHED, INSTALL_ON_CLOSE): + elif self.value in (PENDING, DOWNLOAD_FINISHED, INSTALL_ON_CLOSE): self.sig_start_update.emit() - elif value == NO_STATUS: - self.menu.clear() - check_for_updates_action = create_action( - self, - text=_("Check for updates..."), - triggered=self.sig_check_update.emit - ) - - add_actions(self.menu, [check_for_updates_action]) - rect = self.contentsRect() - os_height = 7 if os.name == 'nt' else 12 - pos = self.mapToGlobal( - rect.topLeft() + QPoint(-10, -rect.height() - os_height) - ) - self.menu.popup(pos) diff --git a/spyder/plugins/updatemanager/widgets/update.py b/spyder/plugins/updatemanager/widgets/update.py index 9ca760e0c12..007c929c4f1 100644 --- a/spyder/plugins/updatemanager/widgets/update.py +++ b/spyder/plugins/updatemanager/widgets/update.py @@ -10,9 +10,10 @@ import logging import os import os.path as osp -import sys -import subprocess import platform +import shutil +import subprocess +import sys # Third-party imports from packaging.version import parse @@ -36,15 +37,12 @@ # Logger setup logger = logging.getLogger(__name__) -# Update installation process statuses +# Update manager process statuses NO_STATUS = __version__ DOWNLOADING_INSTALLER = _("Downloading update") DOWNLOAD_FINISHED = _("Download finished") -INSTALLING = _("Installing update") -FINISHED = _("Installation finished") PENDING = _("Update available") CHECKING = _("Checking for updates") -CANCELLED = _("Cancelled update") INSTALL_ON_CLOSE = _("Install on close") HEADER = _("