From 9eff02a5accebdd42cf6d91f5e7783508be9054e Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 30 Aug 2024 07:56:09 -0300 Subject: [PATCH 01/61] separated build workflow from test workflow with more scrutinity --- .github/workflows/build.yml | 271 ++++++++++++++++++++++++++++++++++++ .github/workflows/tests.yml | 256 ---------------------------------- 2 files changed, 271 insertions(+), 256 deletions(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..02c9f1da --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,271 @@ +name: Build + +on: + push: + branches: + - main + - develop + + pull_request: + branches: + - main + + workflow_run: + workflows: + - Tests + types: + - success + - completed + +jobs: + + build: + + strategy: + matrix: + include: + - os: ubuntu-latest + arch: x64 + + - os: windows-latest + arch: x64 + + - os: macos-13 + arch: x64 + + - os: macos-14 + arch: arm64 + + runs-on: ${{ matrix.os }} + + steps: + + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install poetry + run: pipx install poetry + + - uses: actions/setup-python@v5 + if: ${{ matrix.arch != 'arm64' }} + with: + python-version: '3.12' + cache: 'poetry' + cache-dependency-path: './poetry.lock' + architecture: ${{ matrix.arch }} + + - uses: actions/setup-python@v5 + if: ${{ matrix.arch == 'arm64' }} + with: + python-version: '3.12' + + - name: Setup (Linux) + if: ${{ runner.os == 'Linux' }} + id: setup-linux + run: | + sudo apt-get install tree rpm + mkdir -p ./release + NAME="$(poetry run python -c 'from src.utils.constants import get_name; print(get_name())')" + VERSION="$(poetry run python -c 'from src.utils.constants import get_version; print(get_version())')" + DESCRIPTION="$(poetry run python -c 'from src.utils.constants import get_description; print(get_description())')" + echo "name=${NAME}" >> $GITHUB_OUTPUT + echo "version=${VERSION}" >> $GITHUB_OUTPUT + echo "description=${DESCRIPTION}" >> $GITHUB_OUTPUT + + - name: Setup (MacOS) + if: ${{ runner.os == 'macOS' }} + id: setup-macos + run: | + brew install create-dmg + brew reinstall openssl@3 + brew unlink openssl@3 && brew link openssl@3 + #OPENSSL_MAJOR_VERSION=`$(which openssl) -version | awk '{ print $2}' | cut -d . -f1` + OPENSSL_FULL_VERSION=`$(which openssl) -version | awk '{ print $2}'` + OPENSSL_PATH="/opt/homebrew/Cellar/openssl@3/${OPENSSL_FULL_VERSION}" + echo "dyld-path=${OPENSSL_PATH}/lib" >> $GITHUB_OUTPUT + + - name: Install project and its dependencies + run: poetry install + + - name: Patch pyinstaller_hook for kivy in Unix + if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }} + run: poetry run poe patch-nix + + - name: Patch pyinstaller_hook for kivy in Windows + if: ${{ runner.os == 'Windows' }} + run: poetry run poe patch-win + + - name: Build dist (Linux) + if: ${{ runner.os == 'Linux' }} + uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a + with: + run: | + poetry add pytest-xvfb + poetry run python .ci/create-spec.py + poetry run python -m PyInstaller krux-installer.spec + + - name: Build dist (MacOS) + if: ${{ runner.os == 'macOS' }} + env: + DYLD_LIBRARY_PATH: ${{ steps.setup-macos.outputs.dyld-path }} + run: | + poetry run poe clean-mac + poetry run python .ci/create-spec.py + poetry run python -m PyInstaller krux-installer.spec + + - name: Build dist (Windows) + if: ${{ runner.os == 'Windows' }} + env: + KIVY_GL_BACKEND: 'angle_sdl2' + run: | + poetry run python .ci/create-spec.py + .\.ci\edit-spec.ps1 + poetry run python -m PyInstaller krux-installer.spec + + - name: Build release deb (Linux) + if: ${{ runner.os == 'Linux' }} + id: release-deb + env: + NAME: ${{ steps.setup-linux.outputs.name }} + VERSION: ${{ steps.setup-linux.outputs.version }} + DESCRIPTION: ${{ steps.setup-linux.outputs.description }} + run: | + sh .ci/create-deb.sh \ + -a "${NAME}" \ + -o ./release \ + -v $VERSION \ + -A amd64 \ + -m qlrd \ + -e qlrddev@gmail.com \ + -d "${DESCRIPTION}" \ + -b "./dist/${NAME}" \ + -i ./assets/icon.png + tree ./release + echo "build-path=$(pwd)/release" >> $GITHUB_OUTPUT + echo "pkg=${NAME}_${VERSION}_amd64.deb" >> $GITHUB_OUTPUT + + - name: Build release rpm (Linux) + if: ${{ runner.os == 'Linux' }} + id: release-rpm + env: + NAME: ${{ steps.setup-linux.outputs.name }} + VERSION: ${{ steps.setup-linux.outputs.version }} + DESCRIPTION: ${{ steps.setup-linux.outputs.description }} + run: | + RPM_VERSION=$(sed -e 's/-/_/g' <<< $VERSION) + sh .ci/create-rpm.sh \ + -a "${NAME}" \ + -v $RPM_VERSION \ + -m qlrd \ + -e qlrddev@gmail.com \ + -d "${DESCRIPTION}" \ + -c ./CHANGELOG.md \ + -r ./README.md \ + -b "./dist/${NAME}" \ + -i ./assets/icon.png + tree ./release + rpmbuild -vv -bb --define "_bindir /usr/local/bin" $HOME/rpmbuild/SPECS/$NAME.spec + cp $HOME/rpmbuild/RPMS/x86_64/${NAME}-${RPM_VERSION}-1.x86_64.rpm ./release/${NAME}-${RPM_VERSION}-1.x86_64.rpm4 + echo "build-path=${HOME}/rpmbuild/RPMS/x86_64" >> $GITHUB_OUTPUT + echo "pkg=${NAME}-${RPM_VERSION}-1.x86_64.rpm" >> $GITHUB_OUTPUT + + - name: Build release dmg (MacOS) + if: ${{ runner.os == 'macOS' }} + id: release-macos + run: | + NAME="$(poetry run python -c 'from src.utils.constants import get_name; print(get_name())')" + VER="$(poetry run python -c 'from src.utils.constants import get_version; print(get_version())')" + ARCH="$(uname -m)" + mkdir -p ./release + create-dmg --volname "${NAME}" --volicon ./assets/icon.icns --window-pos 200 120 --window-size 800 400 --icon-size 100 --icon "${NAME}.app" 200 190 --app-drop-link 600 185 "./release/${NAME}_${VER}_${ARCH}.dmg" "./dist/${NAME}.app" + echo "build-path=$(pwd)/release" >> $GITHUB_OUTPUT + echo "pkg=${NAME}_${VER}_${ARCH}.dmg" >> $GITHUB_OUTPUT + + - name: Build release NSIS (Windows) + if: ${{ runner.os == 'Windows' }} + id: release-windows + shell: pwsh + run: | + choco --yes install nsis + New-Item ".\release" -Type Directory + $name = poetry run python -c 'from src.utils.constants import get_name; print(get_name())' + $version = poetry run python -c 'from src.utils.constants import get_version; print(get_version())' + $description = poetry run python -c 'from src.utils.constants import get_description; print(get_description())' + poetry run python .ci/create-nsis.py -a $name -b .\dist\krux-installer.exe -o selfcustody -V $version -d "$description" -l .\LICENSE -i .\assets\icon.ico -O . + makensis.exe .\krux-installer.nsi + Move-Item -Path ".\krux-installer Setup.exe" -Destination ".\release\krux-installer_v$version Setup.exe" + echo "build-path=$pwd\release" | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append + echo "pkg=krux-installer_v$version Setup.exe" | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append + + - name: Hash (Linux deb) + if: ${{ runner.os == 'Linux' }} + uses: qlrd/sha256sum-action@v3 + id: hash-deb + with: + working-directory: ${{ steps.release-deb.outputs.build-path }} + file: ${{ steps.release-deb.outputs.pkg }} + ext: 'sha256.txt' + + - name: Hash (Linux rpm) + if: ${{ runner.os == 'Linux' }} + uses: qlrd/sha256sum-action@v3 + id: hash-rpm + with: + working-directory: ${{ steps.release-rpm.outputs.build-path }} + file: ${{ steps.release-rpm.outputs.pkg }} + ext: 'sha256.txt' + + - name: Hash (MacOS) + if: ${{ runner.os == 'macOS' }} + uses: qlrd/sha256sum-action@v3 + id: hash-macos + with: + working-directory: ${{ steps.release-macos.outputs.build-path }} + file: ${{ steps.release-macos.outputs.pkg }} + ext: 'sha256.txt' + + - name: Hash (Windows) + if: ${{ runner.os == 'Windows' }} + uses: qlrd/sha256sum-action@v3 + id: hash-win + with: + working-directory: ${{ steps.release-windows.outputs.build-path }} + file: ${{ steps.release-windows.outputs.pkg }} + ext: 'sha256.txt' + + - name: Upload artifact deb (Linux) + if: ${{ runner.os == 'Linux' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.release-deb.outputs.pkg }} + path: | + ${{ steps.release-deb.outputs.build-path}}/${{ steps.release-deb.outputs.pkg }} + ${{ steps.release-deb.outputs.build-path}}/${{ steps.release-deb.outputs.pkg }}.sha256.txt + + - name: Upload artifact rpm (Linux) + if: ${{ runner.os == 'Linux' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.release-rpm.outputs.pkg }} + path: | + ${{ steps.release-rpm.outputs.build-path}}/${{ steps.release-rpm.outputs.pkg }} + ${{ steps.release-rpm.outputs.build-path}}/${{ steps.release-rpm.outputs.pkg }}.sha256.txt + + - name: Upload artifacts (MacOS) + if: ${{ runner.os == 'macOS' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.release-macos.outputs.pkg }} + path: | + ${{ steps.release-macos.outputs.build-path}}/${{ steps.release-macos.outputs.pkg }} + ${{ steps.release-macos.outputs.build-path}}/${{ steps.release-macos.outputs.pkg }}.sha256.txt + + - name: Upload artifacts (Windows) + if: ${{ runner.os == 'Windows' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.release-windows.outputs.pkg }} + path: | + ${{ steps.release-windows.outputs.build-path}}/${{ steps.release-windows.outputs.pkg }} + ${{ steps.release-windows.outputs.build-path}}/${{ steps.release-windows.outputs.pkg }}.sha256.txt diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6cafd6d9..3c23a109 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,9 +2,6 @@ name: Tests on: push: - branches: - - main - pull_request: jobs: @@ -150,256 +147,3 @@ jobs: # KIVY_GL_DEBUG: 1 # KIVY_GL_BACKEND: 'gl' # run: poetry run poe test - - build: - - needs: pytest - - strategy: - matrix: - include: - - os: ubuntu-latest - arch: x64 - - - os: windows-latest - arch: x64 - - - os: macos-13 - arch: x64 - - - os: macos-14 - arch: arm64 - - runs-on: ${{ matrix.os }} - - steps: - - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install poetry - run: pipx install poetry - - - uses: actions/setup-python@v5 - if: ${{ matrix.arch != 'arm64' }} - with: - python-version: '3.12' - cache: 'poetry' - cache-dependency-path: './poetry.lock' - architecture: ${{ matrix.arch }} - - - uses: actions/setup-python@v5 - if: ${{ matrix.arch == 'arm64' }} - with: - python-version: '3.12' - - - name: Setup (Linux) - if: ${{ runner.os == 'Linux' }} - id: setup-linux - run: | - sudo apt-get install tree rpm - mkdir -p ./release - NAME="$(poetry run python -c 'from src.utils.constants import get_name; print(get_name())')" - VERSION="$(poetry run python -c 'from src.utils.constants import get_version; print(get_version())')" - DESCRIPTION="$(poetry run python -c 'from src.utils.constants import get_description; print(get_description())')" - echo "name=${NAME}" >> $GITHUB_OUTPUT - echo "version=${VERSION}" >> $GITHUB_OUTPUT - echo "description=${DESCRIPTION}" >> $GITHUB_OUTPUT - - - name: Setup (MacOS) - if: ${{ runner.os == 'macOS' }} - id: setup-macos - run: | - brew install create-dmg - brew reinstall openssl@3 - brew unlink openssl@3 && brew link openssl@3 - #OPENSSL_MAJOR_VERSION=`$(which openssl) -version | awk '{ print $2}' | cut -d . -f1` - OPENSSL_FULL_VERSION=`$(which openssl) -version | awk '{ print $2}'` - OPENSSL_PATH="/opt/homebrew/Cellar/openssl@3/${OPENSSL_FULL_VERSION}" - echo "dyld-path=${OPENSSL_PATH}/lib" >> $GITHUB_OUTPUT - - - name: Install project and its dependencies - run: poetry install - - - name: Patch pyinstaller_hook for kivy in Unix - if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }} - run: poetry run poe patch-nix - - - name: Patch pyinstaller_hook for kivy in Windows - if: ${{ runner.os == 'Windows' }} - run: poetry run poe patch-win - - - name: Build dist (Linux) - if: ${{ runner.os == 'Linux' }} - uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a - with: - run: | - poetry add pytest-xvfb - poetry run python .ci/create-spec.py - poetry run python -m PyInstaller krux-installer.spec - - - name: Build dist (MacOS) - if: ${{ runner.os == 'macOS' }} - env: - DYLD_LIBRARY_PATH: ${{ steps.setup-macos.outputs.dyld-path }} - run: | - poetry run poe clean-mac - poetry run python .ci/create-spec.py - poetry run python -m PyInstaller krux-installer.spec - - - name: Build dist (Windows) - if: ${{ runner.os == 'Windows' }} - env: - KIVY_GL_BACKEND: 'angle_sdl2' - run: | - poetry run python .ci/create-spec.py - .\.ci\edit-spec.ps1 - poetry run python -m PyInstaller krux-installer.spec - - - name: Build release deb (Linux) - if: ${{ runner.os == 'Linux' }} - id: release-deb - env: - NAME: ${{ steps.setup-linux.outputs.name }} - VERSION: ${{ steps.setup-linux.outputs.version }} - DESCRIPTION: ${{ steps.setup-linux.outputs.description }} - run: | - sh .ci/create-deb.sh \ - -a "${NAME}" \ - -o ./release \ - -v $VERSION \ - -A amd64 \ - -m qlrd \ - -e qlrddev@gmail.com \ - -d "${DESCRIPTION}" \ - -b "./dist/${NAME}" \ - -i ./assets/icon.png - tree ./release - echo "build-path=$(pwd)/release" >> $GITHUB_OUTPUT - echo "pkg=${NAME}_${VERSION}_amd64.deb" >> $GITHUB_OUTPUT - - - name: Build release rpm (Linux) - if: ${{ runner.os == 'Linux' }} - id: release-rpm - env: - NAME: ${{ steps.setup-linux.outputs.name }} - VERSION: ${{ steps.setup-linux.outputs.version }} - DESCRIPTION: ${{ steps.setup-linux.outputs.description }} - run: | - RPM_VERSION=$(sed -e 's/-/_/g' <<< $VERSION) - sh .ci/create-rpm.sh \ - -a "${NAME}" \ - -v $RPM_VERSION \ - -m qlrd \ - -e qlrddev@gmail.com \ - -d "${DESCRIPTION}" \ - -c ./CHANGELOG.md \ - -r ./README.md \ - -b "./dist/${NAME}" \ - -i ./assets/icon.png - tree ./release - rpmbuild -vv -bb --define "_bindir /usr/local/bin" $HOME/rpmbuild/SPECS/$NAME.spec - cp $HOME/rpmbuild/RPMS/x86_64/${NAME}-${RPM_VERSION}-1.x86_64.rpm ./release/${NAME}-${RPM_VERSION}-1.x86_64.rpm4 - echo "build-path=${HOME}/rpmbuild/RPMS/x86_64" >> $GITHUB_OUTPUT - echo "pkg=${NAME}-${RPM_VERSION}-1.x86_64.rpm" >> $GITHUB_OUTPUT - - - name: Build release dmg (MacOS) - if: ${{ runner.os == 'macOS' }} - id: release-macos - run: | - NAME="$(poetry run python -c 'from src.utils.constants import get_name; print(get_name())')" - VER="$(poetry run python -c 'from src.utils.constants import get_version; print(get_version())')" - ARCH="$(uname -m)" - mkdir -p ./release - create-dmg --volname "${NAME}" --volicon ./assets/icon.icns --window-pos 200 120 --window-size 800 400 --icon-size 100 --icon "${NAME}.app" 200 190 --app-drop-link 600 185 "./release/${NAME}_${VER}_${ARCH}.dmg" "./dist/${NAME}.app" - echo "build-path=$(pwd)/release" >> $GITHUB_OUTPUT - echo "pkg=${NAME}_${VER}_${ARCH}.dmg" >> $GITHUB_OUTPUT - - - name: Build release NSIS (Windows) - if: ${{ runner.os == 'Windows' }} - id: release-windows - shell: pwsh - run: | - choco --yes install nsis - New-Item ".\release" -Type Directory - $name = poetry run python -c 'from src.utils.constants import get_name; print(get_name())' - $version = poetry run python -c 'from src.utils.constants import get_version; print(get_version())' - $description = poetry run python -c 'from src.utils.constants import get_description; print(get_description())' - poetry run python .ci/create-nsis.py -a $name -b .\dist\krux-installer.exe -o selfcustody -V $version -d "$description" -l .\LICENSE -i .\assets\icon.ico -O . - makensis.exe .\krux-installer.nsi - Move-Item -Path ".\krux-installer Setup.exe" -Destination ".\release\krux-installer_v$version Setup.exe" - echo "build-path=$pwd\release" | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append - echo "pkg=krux-installer_v$version Setup.exe" | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append - - - name: Hash (Linux deb) - if: ${{ runner.os == 'Linux' }} - uses: qlrd/sha256sum-action@v3 - id: hash-deb - with: - working-directory: ${{ steps.release-deb.outputs.build-path }} - file: ${{ steps.release-deb.outputs.pkg }} - ext: 'sha256.txt' - - - name: Hash (Linux rpm) - if: ${{ runner.os == 'Linux' }} - uses: qlrd/sha256sum-action@v3 - id: hash-rpm - with: - working-directory: ${{ steps.release-rpm.outputs.build-path }} - file: ${{ steps.release-rpm.outputs.pkg }} - ext: 'sha256.txt' - - - name: Hash (MacOS) - if: ${{ runner.os == 'macOS' }} - uses: qlrd/sha256sum-action@v3 - id: hash-macos - with: - working-directory: ${{ steps.release-macos.outputs.build-path }} - file: ${{ steps.release-macos.outputs.pkg }} - ext: 'sha256.txt' - - - name: Hash (Windows) - if: ${{ runner.os == 'Windows' }} - uses: qlrd/sha256sum-action@v3 - id: hash-win - with: - working-directory: ${{ steps.release-windows.outputs.build-path }} - file: ${{ steps.release-windows.outputs.pkg }} - ext: 'sha256.txt' - - - name: Upload artifact deb (Linux) - if: ${{ runner.os == 'Linux' }} - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.release-deb.outputs.pkg }} - path: | - ${{ steps.release-deb.outputs.build-path}}/${{ steps.release-deb.outputs.pkg }} - ${{ steps.release-deb.outputs.build-path}}/${{ steps.release-deb.outputs.pkg }}.sha256.txt - - - name: Upload artifact rpm (Linux) - if: ${{ runner.os == 'Linux' }} - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.release-rpm.outputs.pkg }} - path: | - ${{ steps.release-rpm.outputs.build-path}}/${{ steps.release-rpm.outputs.pkg }} - ${{ steps.release-rpm.outputs.build-path}}/${{ steps.release-rpm.outputs.pkg }}.sha256.txt - - - name: Upload artifacts (MacOS) - if: ${{ runner.os == 'macOS' }} - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.release-macos.outputs.pkg }} - path: | - ${{ steps.release-macos.outputs.build-path}}/${{ steps.release-macos.outputs.pkg }} - ${{ steps.release-macos.outputs.build-path}}/${{ steps.release-macos.outputs.pkg }}.sha256.txt - - - name: Upload artifacts (Windows) - if: ${{ runner.os == 'Windows' }} - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.release-windows.outputs.pkg }} - path: | - ${{ steps.release-windows.outputs.build-path}}/${{ steps.release-windows.outputs.pkg }} - ${{ steps.release-windows.outputs.build-path}}/${{ steps.release-windows.outputs.pkg }}.sha256.txt From fa35a9ab9be0e25c90ec7a982bbb0cfbcb0aea5a Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 30 Aug 2024 08:03:00 -0300 Subject: [PATCH 02/61] separated build workflow from test workflow with more scrutinity II --- .github/workflows/build.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 02c9f1da..41054005 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,21 +1,18 @@ name: Build on: - push: - branches: - - main - - develop - - pull_request: - branches: - - main - workflow_run: workflows: - Tests types: - success - completed + branches: + - main + - develop + pull_request: + branches: + - main jobs: From cf3d221fca3b5c9f3c69fbab8c21108b2cf6bdb5 Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 30 Aug 2024 08:35:12 -0300 Subject: [PATCH 03/61] separated build workflow from test workflow with more scrutinity III --- .github/workflows/build.yml | 8 +------- .github/workflows/tests.yml | 7 +++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 41054005..1ef7ed70 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,14 +5,7 @@ on: workflows: - Tests types: - - success - completed - branches: - - main - - develop - pull_request: - branches: - - main jobs: @@ -34,6 +27,7 @@ jobs: arch: arm64 runs-on: ${{ matrix.os }} + if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3c23a109..d83e42b4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,7 +2,14 @@ name: Tests on: push: + branches: + - main + - develop + pull_request: + branches: + - main + - develop jobs: From d5edd7cf7a30db8c65b5c778730a8e25e8a97a3a Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 30 Aug 2024 11:30:11 -0300 Subject: [PATCH 04/61] coveraged 100% stream_downloader module on_data function defined dynamically --- src/utils/downloader/asset_downloader.py | 14 ++++++++++- src/utils/downloader/stream_downloader.py | 29 +++++++---------------- tests/test_006_stream_downloader.py | 3 ++- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/utils/downloader/asset_downloader.py b/src/utils/downloader/asset_downloader.py index db619b23..a0050635 100644 --- a/src/utils/downloader/asset_downloader.py +++ b/src/utils/downloader/asset_downloader.py @@ -76,11 +76,19 @@ def download(self, on_data: typing.Callable) -> str: # Before the download the file stream, # you can define some method to be called # after the buffer is wrote + # it will need to be a local defined function + # because it will need a different behaviour + # for different assets. + # For example, a kboot.kfpkg will need a different + # to update different graphical definition (in app/screens) + # if compared to a zip file def local_on_data(data: bytes): self.buffer.write(data) on_data(data) - self.on_data = local_on_data + setattr(self, "on_data", local_on_data) + + # Now you can start the download process self.download_file_stream(url=self.url) # Once the data is downloaded, you can @@ -89,11 +97,15 @@ def local_on_data(data: bytes): self.debug(f"download::destfile={destfile}") self.debug(f"download::write::{self.write_mode}={self.buffer.getvalue()}") + # If its a binary file (a zip in our case) + # open the file in wb mode if self.write_mode == "wb": # pylint: disable=unspecified-encoding with open(destfile, self.write_mode) as file: file.write(self.buffer.getvalue()) + # If its a text file (a txt or sig file in our case) + # open the file in w mode with utf8 encode if self._write_mode == "w": with open(destfile, self.write_mode, encoding="utf8") as file: value = self.buffer.getvalue() diff --git a/src/utils/downloader/stream_downloader.py b/src/utils/downloader/stream_downloader.py index 757fbbe1..ff3ba2a9 100644 --- a/src/utils/downloader/stream_downloader.py +++ b/src/utils/downloader/stream_downloader.py @@ -23,7 +23,6 @@ stream_downloader.py """ import os -import typing import requests from .trigger_downloader import TriggerDownloader @@ -33,22 +32,10 @@ class StreamDownloader(TriggerDownloader): Download files in a stream mode """ - @property - def on_data(self) -> typing.Callable: - """Getter for callback to be used in each increment of downloaded stream""" - self.debug(f"on_data::getter={self._on_data}") - return self._on_data - - @on_data.setter - def on_data(self, value: typing.Callable): - """Setter for the callback to be used in each increment of downloaded stream""" - self.debug(f"on_data::setter={value}") - self._on_data = value - def download_file_stream(self, url: str): """ Given a :attr:`url`, download a large file in a streaming manner to given - destination folder (:attr:`dest_dir`) + destination folder (:attr: `dest_dir`) When a chunk of received data is write to buffer, you can intercept some information with :attr:`on_data` as function (total_len, downloaded_len, start_time) @@ -103,14 +90,16 @@ def download_file_stream(self, url: str): # Get the chunks of bytes data # and pass it to a post-processing # method defined as `on_data` + on_data = getattr(self, "on_data") + for chunk in res.iter_content(chunk_size=self.chunk_size): self.downloaded_len += len(chunk) self.debug(f"download_file_stream::downloaded_len={self.downloaded_len}") - if self.on_data is not None: - self.on_data(data=chunk) # pylint: disable=not-callable - else: - raise RuntimeError("on_data cannot be empty") - # Now you can close connection - self.debug("downloaded_file_stream::closing_connection") + # pylint: disable=not-callable + on_data(data=chunk) + + # Now you can close connection + self.debug("downloaded_file_stream::closing_connection") + res.close() diff --git a/tests/test_006_stream_downloader.py b/tests/test_006_stream_downloader.py index 6ca263d3..95cadef6 100644 --- a/tests/test_006_stream_downloader.py +++ b/tests/test_006_stream_downloader.py @@ -32,7 +32,7 @@ def test_init_on_data(self): # strange hack to allow it be # registered as coveraged - s.on_data = MagicMock() + setattr(s, "on_data", MagicMock()) on_data = getattr(s, "on_data") calls = [] @@ -52,6 +52,7 @@ def test_download_file_stream(self, mock_requests): mock_requests.get.return_value = mock_response sd = StreamDownloader(url=URL) + setattr(sd, "on_data", MagicMock()) sd.download_file_stream(url="https://any.call/test.zip") mock_requests.get.assert_called_once_with( From b2ddb356dcab7a790eaac4a062b9ef93903df23a Mon Sep 17 00:00:00 2001 From: qlrd Date: Sun, 1 Sep 2024 09:14:23 -0300 Subject: [PATCH 05/61] refactored startup removed check screens startup checks go to GreetingsScreen removed markup arguments on some widgets linted many files --- .pylint/src | 14 +- assets/error.png | Bin 8843 -> 0 bytes e2e/test_000_base_screen.py | 7 +- e2e/test_001_greetings_screen.py | 290 ++------ e2e/test_002_ask_permission_dialout_screen.py | 219 ++++++ e2e/test_002_check_permissions_screen.py | 685 ------------------ e2e/test_016_unzip_stable_screen.py | 3 +- e2e/test_020_app_init.py | 110 +-- pyproject.toml | 6 +- src/app/__init__.py | 74 +- src/app/screens/__init__.py | 1 + src/app/screens/about_screen.py | 1 - .../screens/ask_permission_dialout_screen.py | 208 ++++++ src/app/screens/base_download_screen.py | 3 +- src/app/screens/base_screen.py | 42 +- .../check_internet_connection_screen.py | 130 ---- src/app/screens/check_permissions_screen.py | 313 -------- src/app/screens/download_beta_screen.py | 5 +- .../download_selfcustody_pem_screen.py | 4 +- src/app/screens/download_stable_zip_screen.py | 5 +- .../download_stable_zip_sha256_screen.py | 4 +- .../screens/download_stable_zip_sig_screen.py | 30 +- src/app/screens/error_screen.py | 21 +- src/app/screens/flash_screen.py | 6 +- src/app/screens/greetings_screen.py | 173 +++-- src/app/screens/main_screen.py | 3 +- src/app/screens/select_device_screen.py | 3 +- src/app/screens/select_old_version_screen.py | 6 +- src/app/screens/select_version_screen.py | 13 +- src/app/screens/unzip_stable_screen.py | 6 +- .../warning_already_downloaded_screen.py | 1 - src/app/screens/warning_beta_screen.py | 3 +- src/app/screens/warning_wipe_screen.py | 1 - src/app/screens/wipe_screen.py | 5 +- src/i18n/en_US.UTF-8.json | 4 - 35 files changed, 748 insertions(+), 1651 deletions(-) delete mode 100644 assets/error.png create mode 100644 e2e/test_002_ask_permission_dialout_screen.py delete mode 100644 e2e/test_002_check_permissions_screen.py create mode 100644 src/app/screens/__init__.py create mode 100644 src/app/screens/ask_permission_dialout_screen.py delete mode 100644 src/app/screens/check_internet_connection_screen.py delete mode 100644 src/app/screens/check_permissions_screen.py diff --git a/.pylint/src b/.pylint/src index fd2d1378..4a745a1b 100644 --- a/.pylint/src +++ b/.pylint/src @@ -25,13 +25,13 @@ clear-cache-post-run=no # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. -extension-pkg-allow-list= +extension-pkg-allow-list=cv2 # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. (This is an alternative name to extension-pkg-allow-list # for backward compatibility.) -extension-pkg-whitelist=cv2 +extension-pkg-whitelist= # Return non-zero exit code if any of these messages/categories are detected, # even if score is above --fail-under value. Syntax same as enable. Messages @@ -63,7 +63,7 @@ ignore-patterns=^\.# # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis). It # supports qualified module names, as well as Unix pattern matching. -ignored-modules= +ignored-modules=kivy # see https://github.com/pylint-dev/pylint/issues/1524#issuecomment-508934142 # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). @@ -285,10 +285,10 @@ exclude-too-few-public-methods= ignored-parents= # Maximum number of arguments for function / method. -max-args=5 +max-args=7 # Maximum number of attributes for a class (see R0902). -max-attributes=8 +max-attributes=20 # Maximum number of boolean expressions in an if statement (see R0916). max-bool-expr=5 @@ -303,7 +303,7 @@ max-locals=16 max-parents=8 # Maximum number of public methods for a class (see R0904). -max-public-methods=20 +max-public-methods=25 # Maximum number of return / yield for function / method body. max-returns=6 @@ -563,7 +563,7 @@ contextmanager-decorators=contextlib.contextmanager # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. -generated-members=cv2 +generated-members=cv2,kivy # Tells whether to warn about missing members when the owner of the attribute # is inferred to be None. diff --git a/assets/error.png b/assets/error.png deleted file mode 100644 index 56ef80667cc93c0b749c821210cdd2dd733193a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8843 zcmbVyc|4SD)c-w98e3)t8HCx;BAOvY#f)i;LLSN*G8ockYq8bPU@*f>M3#!uDp6Dv z<*|#REFsksDiv*%l=xluG%h9D^t{0}7qW*)E9ybk`84P|*mK#(C27?Kc&&s!Y?lj@P1+#_A~b0QD+F*y%T(LvV%WN#gMO|yL`@h&%HF5dkZMaFoIZp~zK=_b?of3Qg98)4HH`Ae6V zh?o=o2rGVg#?K!6%e|%1&tp2Pr;q5EoWCB#e136r_x+7!(QjY3=Pc@SQ2TYxZ)T0) zX!Y!e+OH%348A;a@*kI2*CPc+zrUq@9f^Eb_BPFTDDH^qw193_OJWw@ED9@EQH^=Z z9w~3|{TW_oAoV&DLk+B~`TQQDNNrPFHgf(S_eSQAZ(8RjU4tl&Z<^j#tbQAKsX$W$ zO{$xCe4Q_BD*L3K>$!gQHIC~e|EqizG^wj(3?&W=ov?`OCBecqR`3l}L)ZxR(N@JxJIte~tZ*(2kK zg;#23wK;+!b)dQB>+$wDQi5dA(y}J0Tt2Co6r z5!5=*RCK=6yJJmnp60r&<6~HA_=c~q%w_l`Pv2GOQ#Owq(FE2u80v~^-{Y5QC?0;u zKH7GUYX3-aF&lYBQREl4Rvt@iq$*rp`l8FIBfCRk5gU0hO=Rb{6nW6^7Lp?6g={VV zG0VDEi+4H&@ZKazQKZalS%=+*%2g)of~`yIF|T&L`W=QQefHojYeHRDk$xz*#XKXm zWB~hD0VI=?ofNqjV3{#EejZCOA@ z=PAffALA}ZQ0Qk-xl0|JC65i58}8{*!6w#OTpVE&uU}c}EV2TK|s2HuuWUj5a#qnf?j6^s3Cdl03hl`r ze!eKDjPf(&j^l8)cpossZ?+ZMW$#0iYL*g5hC@snk1KSUY%$}DPusTo2t>b_(yZ3Y zniL{4T7&3k$MH1Rl^z|jo1sv)5Se2~K){;Y;$ssPulWtU5f`CJk;aUUBxo*a7BRxwkdLKrT)G~RIV*Q z#)iAGN8sp=Kc)Z_)SCxWQ&k?uY9`m;EW97Qoc?#t()X14L69%6^-Guz|p#-ter|2F}8DEo_5uh2H+R2;-1 zXP`ZXbchTn55qZgR6D21uA_ssk-+wl!3$dsojH?&r963tmNlB&Dnwd`o8Hn3$kp@a z+b5!|O_yqVB`2MY;xM1^TCaYdqeAQCG`(701aB2YuA>*6LmsTxq}m&^EFNr8DBdVr7l9r-TT^trx{4n7+3&xCg4vBi9GUt%kR z523KG74|N^{3;t{Va%h{l5_VBZA(PC7=l#Y&w3g!YCRzZhamzrN&*^zCi8)Si^q`Y z64OQiXD#|OM-!kh5OP8J{}*h-5^d>7?&^e5v7h@x&DW(%#K-FIev&G$g)`uw&@j;f z8^8ZnID3R@tiT4?A`4c!V#7m&?xAJG7zzVa1Xr&1(Dcke#~Rq3_2!p`$3`31#6F@v z%;x}Xi~F68r4V0i)}+Xs79ydwaxs_&EwYUbfq5;N)$cx4$AY??Lkt!&?}wF>NjFy2$eD2ObJJtUf1&m4~SzT|u;1rlxk^a=lN;<1nIVMMF_{*2l0 zQJerh2GsiQm$NSzQJD|)V?534<*j|9W9ly)qBw7CvwhuQQx*kLBaJ{R-W}xg-j(G( zwSd$u4etAXd!H4w-?V(NT+X_E>W#yQFSJy-JhB`*-ccay^|_zEiR)-MfgSP7k) zLEJ6*Wow~M`ogYIs@aDa6S--6HnA+})zRl&x)}ZGBb$%Q&g-~48y!P8q1ozbQ z_L-03f*@wSMvmnss8D0z#fIa7g2tPri+#)>r`*rdbK3-0_rG5&4V`EYH{N}af;9?W zHx-TGdIlWonLd?clzo5nnWfeq{q?TIHn`sH=#Sdr z_D@HVk?{4V&U`U$d>-h~=*onz=YM@t^Ua-OiA0$J%E)6Ik30_D zz<4q9Q>XUlhtJDd!9>PVq^x>%PRK#BogmA14+>L33{WM?C-5%N86r^;S$UDLg;gUz z-#_V)P9U;^Ef`4ITsx}eaWr2_#`>y2%FP z@NFkmi**0BRL?!Qj(Op<@1P11c(4H;QkX%u8flp6)UG}>hHRn*=Iu>P43uP17aq-@hZw21$=b_xK`^!?BdXbq;%eb4!N(@@@Jnm=}Q_eYU8`j|MFsY z_qDLVdTA*v7_ydkq$_x7lD=eGO|5^@^siH1$SHSRy1j}y ztpB@i()KAJ3;W*Ma}XEU)x1?BTpmLsf?(MU0iJP#z=C<4``B|p)^jxlYvr+@Z~F;k z5H@M)r9NI0+^sLa7mQ#NEz>I_*vbd~#j|83xtxN>lYj)!?efbU_b*;iT~*#qI#6HRy7cYcl zy4syLBFJMMo;0flLA8&(*)48TLwCV2CK}l^feN_o$M> zQkuVgT3}h6BCfxR`om3X|6s^vCRh_-OA|Sr7i#*A;8N61d7Op$0m66(fr_Dp&7Z+P z2dDG-m@Os?Ktmzj(^u5@{4kpKS(r+}`ua57K{ytP+1SW+*I_@)B)z$O8AnZ#^vR{d8h?5h>_cKjiWls({4qScp* zxqS`P1;8m8fkJe* zWE}bZTnC3rIPq!tuA@L8BqhKV%R@c$y!n9Y{zd7olr{|xiq7-it3x_3J(7$Em5L{Oa>GWF*HBl(8}020ble) zV(aRzMf%eJP|H6N@7FDv>07fyon-dg0nc(*g=478YyQyK+HX!^_5b0ZSaaQe@=-fz z|G#t$zuW4+Ziw^Wbn4#hoLO3#{m}rtHNR`?(O7VPnHe@R=oazRv1sDd;O^2e7lA;4 zNkH;YJ;AZN1w)bF)sV6%%%%R%eYh0{kMS&PzV$GU0=OXvQU@$mNGM<^lTbXYTVmGS z+VxqYAiYnB(cgt8;~9mri}yFSevOoc)to9`X;Pfs&(cI(bo`rTLnb zc*BSUQ&Ii73d#S^vxCRDn-)$ECcqjMf&$WmVMJ7>HH=_F3BPWop{XPhFC|GlzsH5O zpkVeUd-tzn4pAhK4w@+#iP9sgA}k|=*WIE#UX>-F}c?PlAt!9s=7fFDT&Dj$2 z_{+3@b2bi+1MeYFN&hAxYq20KMU!kAxUeZ338ViE4$hU4K;F>@wFPWeT>JwQC8!EQ z!jj|7D6rz-+)9y3KuYXVKm+395MVBTu8H4mf@gvFOqk3h1X31|YevBncn~k1VJ(0b zjDV!^|0Dp#`JZd>vLVqRX~FfM=3if=BSQpY;|8er*YMq=9JIx#{L#6bCbfIt6r~Ys zn_A_8(`);xC=6=bXwShNdRo`DcSb-v)hD zhwo?iWDb@$naG-O~YAJgacm+cQnAz)!?TJQ_ihYGZ>sL19}7%+ngm@Dm6DECC!q zuBK!n_yN$~-^jnql-REbO7k^n`EO(d3OZs0tTatZG50=(ly*QnY|RY@+vwgrJj9JF?`$tzk?s{25Lw&24_ks;nOp@xuDkpK58Vf z@>&!IO?J9Ca|O4~j463O*S(#>zAS-%A07o>@3id{s+primT9K9p#$tOAd1X4tNh81 zr*>$pg0U|B?P*Lhn-l&K0ex4A{`L0PyZ>=(0Et$i5eL>9% z@Ni}24xi8y#@Scl#gn2eY^4M?eqx5V&thk_zHQ%@)>FPd@=B zwCK&V=GGy}b6t9UV31cQygdVM{k>i>!=)7VOVH1^&wc(hzXuI61cHwvp)mWV?&_aW zx&QOSeWN4BztjH)$=D726X?8r`smY_zyB`ro&TQc3*I@Y+fg5mV8BmCzqe=)(3Fw4 zCio{7Pzgj9fYkT{`9cHi{UYn;SYr=(T(3A{2IcUqOfa zDki&khlUGyt-$VpG+k3>z%;!K78>5vvHitbrYYiT3fOkRDF?XNZE^S4?D(c$3LB&m zK2jy{9^Cbtz@;3B;Oqgu7$Q82g(W@i=m+%*P9~!A`icYTQ~NYY*&z~4(Ch>6wY{wQ zOOSOULOY}dNBX1pd8wv@kHY&oMeyRluEtJ;eh8VMP>mna;k|~IfPb}g(qTSc=uh6q zy1tFX04EwGt=_@Zho-(~M)RTYCfMarSfuO<|HgY50(_K1VXwv9_*hzE*}@t+IV_yC z2J)Q)u9>RGE*!NPToEfR|FRXJ@D9|>_8wK6pFDKbYxb4zeD_Yi*wa6N)3Hbv4u`?N z<#~2s1@pnnP#^Q{B+$x02dh6(>Six<`G`O0aPZD;F+vR#bO`QCj$%C4r&D|GGAbej zRgeQnB7q2uR4lJ$DXjc~)Q(!RU=#ge;KHX(F1CVxGmu&MyhZ2D4OUAZOc&osdeokL z@w7b114trtV;Z;={j`|mUv)uU{VEgI~@0PW5v zkJyYm2L9x$S_7@AfB@`t?+M3^+cZdF6Rk|w1-kq412stpdaxiP@M*>4@}7~9y%en3 zjXPr11@QcpXCiSuQz?(uyGb&^L!EMI6P5@YSvBHsxo;H~)LcRaQYn|dD4&jcw7|h) z#G_zO@ODA}e+0BD?#wmaY+?=V`qdu+4nz`GvNs*53L$fi7f)L*km@U$HQ(<~aXvEq zHqrmyg44ZjA4cm7Cww6g2}lO&W;9k`Z4mqz5k_{TFJ!0EWn!_jjA9(YxKkIX0ZaOa z^`&2*M`bqiw{$Jg^4vApxSu*UsKx^XU=`idYbmRq1Pf07oAuxm&3YIa@89*ng12!o zI4auS^!|N%J+mXd3qD4{xugmmwH5BnErPQaCkId#X`E8E!;(0*V=jMIGq|W(Ur{D* zh7Om7AwVf23OiHDX_yL9!-w=w;A&zZuAehcm07M=1E?dRZ^rXYaZ(2WtLkR$qkgq>JPF6%voNMy5)+tI4 zucdkYCkponxUrordR%BfQfJ)jxQq? z=PEurSHCGZKm+j5JI3HURlEZml~H4>;&7dPEwgnsKyUyd7IC(^c>j8lic6tkWm^C8 zy#Yd`XTmH51oe( zs}A z<>K<`@RJ{W#EG;mGTjfaLgm$V9|=zYQ|WbI^59P~`L0_BKd0OZM!JjN+=RO}jd{YM6AKd%Zez!k4 zPbGUd^v@mF)t!|VOoOLTou=pQ_1*75`qZGwNTfC*SU$VI~LEI zf=i&Vna>erHc<3RgHFM-*+rFcoPaR(!4{u1Xv)c5%RJsAEZ4PW z+TMuW_)Y_g9t-n&5pzL}f;~1`8T+Gaw=!27Rf1^oo?(05kNW7_`;hx|{cpcj~1+fpP*yZ4>m}Mb zFEcoC+FaU8UqsmEJ;R++kSs6LxOQIK+(ao)oirW9A^+t<+!hv=BRH+qi!P?xBD z!%p07`Ki;nV%@MSGppWctsg7uDlg~4HO{(d>9WhW@+`g+yG@z2#BcHpcEGLod+TfqE~-u6Zw;*jsdX@AZ-UP?^`VXR5^2{+!~b z;TsRH&YGKOSZ8=-V@LsL-R}BbnuTWy;DHJmTz+Mbo_-8P*WaBu$lE~D!Wd1;-o6!G zv7zw8=@U9f35+`p9jwLR8$x<&i3j%3amahJxXNPn$VW7VE}uZ&p{w(ee7#zAETJ7o z&`+WZy6!EP?LOIEZy?*{!?9^ZX`zn$y+W<&+9(+auoYx$uak-xQlvR6>9tLj@PK9yTn~Dm*lxN}5{3s!z$^^~zzITUlRA$UN+eW%Eum+p4NO@2IOQ7W(O& zz)-<8MC0;u{_)Q`yz;i*CyGwDFE;h=X{|1@7KCnKC4t*H>$v*k9oH4F@G*TU$HQI; zr@0|XFEQ3zd&KD2u(gkGr>^36-lU2j4Nam4}wDFCPpP zh;jj-lUtTR-ZnlypG2O${r5d|BTBfbt+>kb-t{)s(3q8MUh!Y-%vDpC^b4jJiOg04 zt6uNvNd5U;U20pwYAG&aBma`(11mljO#t6@bh#*+fV({Y5$g7ZjaUL7b4NqhHj(tV zXw^l3G-+z3yGD^4u{-oyobHy*sp};&>Ud~eM*_Xp+-k zSqlDHJf#ZVa!>O-&1|+Ke2;uZNx4Edw4%wNwc|3b5oMyR+b|qbQBtcr^?U?}kFbfy z#Yg&uqt7+kE&Dm#n{x8&NTUx3YgA1yJ8bMq#d&C*8Mp&)wc5PYty4!<+0$TLS~lM) zD1DU3v_8p&z_0HU$!%5TExh#wP0%_F9^9<^78oR_xU4f-F|>$kG>)KwpH=R1na6Ot z1ji*plxoZ^e#Yl96$LP>su#1x53Bt!uUvR>%NM_yMUAL&75#?YVeB&5+f6O&n_DFJ z`W7Pr*NZC-n?w*dHZBI&>l&~MmAdj&L^Ueo>&UiPaQAPDd=Os1v#rpdkjv=abhz<{ zxtRgDsh{4{ra@tI^sB7)>d)ZM8sgHk(7Fxht<_VrJPkOOj{dO*^$i#=G^uX2 zm@4q2rq8<^9#USpdr`}bb7)QZed$J&Q`{wk?AWClP0p1(?z{JMSr@;AVKj}h6B;&X z 0: - for screen in self.screens: - msg = f"adding screen '{screen.name}'" - self.debug(msg) - self.screen_manager.add_widget(screen) - - else: - raise RuntimeError("Cannot setup screen_manager: screen list is empty") - - def setup_screens(self): - """Configure all screens given an OS""" - self.screens.append(GreetingsScreen()) + screens = [] + screens.append(GreetingsScreen()) if sys.platform == "linux": - self.screens.append(CheckPermissionsScreen()) + screens.append(AskPermissionDialoutScreen()) - self.screens = self.screens + [ - CheckInternetConnectionScreen(), + screens = screens + [ MainScreen(), SelectDeviceScreen(), SelectVersionScreen(), @@ -118,17 +94,9 @@ def setup_screens(self): ErrorScreen(), ] - def on_greetings(self): - """ - When application start, after greeting user with the krux logo, it will need to check if - user is running app in linux or non-linux. If running in linux, the user will be - redirect to CheckPermissionsScreen and then to MainScreen. Win32 and Mac will be - redirect to MainScreen. - """ - - greetings_screen = self.screen_manager.get_screen("GreetingsScreen") + for screen in screens: + msg = f"adding screen '{screen.name}'" + self.debug(msg) + self.screen_manager.add_widget(screen) - fn = partial( - greetings_screen.update, name="KruxInstallerApp", key="check_permissions" - ) - Clock.schedule_once(fn, 0) + return self.screen_manager diff --git a/src/app/screens/__init__.py b/src/app/screens/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/app/screens/__init__.py @@ -0,0 +1 @@ + diff --git a/src/app/screens/about_screen.py b/src/app/screens/about_screen.py index 5399e750..41dc4c19 100644 --- a/src/app/screens/about_screen.py +++ b/src/app/screens/about_screen.py @@ -46,7 +46,6 @@ def __init__(self, **kwargs): wid=f"{self.id}_label", text="", root_widget=f"{self.id}_grid", - markup=True, halign="justify", ) diff --git a/src/app/screens/ask_permission_dialout_screen.py b/src/app/screens/ask_permission_dialout_screen.py new file mode 100644 index 00000000..40014126 --- /dev/null +++ b/src/app/screens/ask_permission_dialout_screen.py @@ -0,0 +1,208 @@ +# The MIT License (MIT) + +# Copyright (c) 2021-2024 Krux contributors + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +check_permissions_screen.py +""" +from functools import partial +from pysudoer import SudoerLinux +from kivy.clock import Clock +from kivy.app import App +from kivy.graphics.context_instructions import Color +from kivy.graphics.vertex_instructions import Rectangle +from kivy.core.window import Window +from src.app.screens.base_screen import BaseScreen +from src.i18n import T + + +class AskPermissionDialoutScreen(BaseScreen): + """ + AskPermissionDialoutScreen ask for user permission + to register in dialout group in linux + """ + + def __init__(self, **kwargs): + super().__init__( + wid="ask_permission_dialout_screen", + name="AskPermissionDialoutScreen", + **kwargs, + ) + + # Build grid where buttons will be placed + self.make_grid(wid=f"{self.id}_grid", rows=1) + + # These variables will setup the inclusion + # in dialout group, if necessary + self._bin = "/usr/bin/usermod" + self._bin_args = ["-a", "-G"] + + def _on_ref_press(*args): + if args[1] == "Allow": + # If user isnt in the dialout group, + # but the configuration was done correctly + # create the command + cmd = ( + [self._bin] + + [a for a in self._bin_args] + + [self.group] + + [self.user] + ) + + try: + self.debug(f"cmd={cmd}") + sudoer = SudoerLinux(name=f"Add {self.user} to {self.group}") + sudoer.exec(cmd=cmd, env={}, callback=self.on_permission_created) + except Exception as err: + self.redirect_error(msg=str(err.__traceback__)) + + if args[1] == "Deny": + App.get_running_app().stop() + + self.make_label( + wid=f"{self.id}_label", + text="", + root_widget=f"{self.id}_grid", + halign="justify", + ) + + setattr( + AskPermissionDialoutScreen, f"on_ref_press_{self.id}_label", _on_ref_press + ) + self.ids[f"{self.id}_label"].bind(on_ref_press=_on_ref_press) + + fn = partial(self.update, name=self.name, key="canvas") + Clock.schedule_once(fn, 0) + + def update(self, *args, **kwargs): + """ + In linux, will check for user permission on group + dialout (debian-li ke) and uucp (archlinux-like) and + add user to that group to allow sudoless flash + """ + name = kwargs.get("name") + key = kwargs.get("key") + value = kwargs.get("value") + + if name in ( + "ConfigKruxInstaller", + "GreetingsScreen", + "AskPermissionDialoutScreen", + "ErrorScreen", + ): + self.debug(f"Updating {self.name} from {name}...") + else: + self.redirect_error(msg=f"Invalid screen: '{name}'") + return + + if key == "locale": + if value is None or value.strip() == "": + self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") + else: + self.locale = value + + elif key == "canvas": + # prepare background + with self.canvas.before: + Color(0, 0, 0, 1) + Rectangle(size=(Window.width, Window.height)) + + elif key == "user": + if value is None: + self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") + else: + self.user = value + + elif key == "group": + if value is None: + self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") + else: + self.group = value + + elif key == "distro": + if value is None: + self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") + else: + self.distro = value + + elif key == "screen": + if self.user is None: + self.redirect_error("user not defined") + + elif self.group is None: + self.redirect_error("group not defined") + + elif self.distro is None: + self.redirect_error("distro not defined") + + else: + warn_msg = self.translate("WARNING") + first_msg = self.translate("This is the first run of KruxInstaller in") + access_msg = self.translate( + "and it appears that you do not have privileged access to make flash procedures" + ) + proceed_msg = self.translate( + "To proceed, click in the Allow button and a prompt will ask for your password" + ) + exec_msg = self.translate("to execute the following command") + + self.ids[f"{self.id}_label"].text = "".join( + [ + f"[size={self.SIZE_G}sp][color=#efcc00]{warn_msg}[/color][/size]", + "\n", + f'[size={self.SIZE_MP}sp]{first_msg} "{self.distro}"', + f"{access_msg}.", + proceed_msg, + f"{exec_msg}:", + "\n", + "[color=#00ff00]", + f"{self._bin} {" ".join(self._bin_args or [])} {self.group} {self.user}", + "[/color]", + "[/size]", + "\n", + "\n", + f"[size={self.SIZE_M}]", + "[color=#00FF00][ref=Allow]Allow[/ref][/color]", + " ", + "[color=#FF0000][ref=Deny]Deny[/ref][/color]", + "[/size]", + ] + ) + + else: + self.redirect_error(msg=f"Invalid key: '{key}'") + + def on_permission_created(self): + """ + When user is added to dialout group + ask for user to reboot to apply the changes + and the ability to flash take place + """ + logout_msg = self.translate("You may need to logout (or even reboot)") + backin_msg = self.translate("and back in for the new group to take effect") + not_worry_msg = self.translate("Do not worry, this message won't appear again") + + self.ids[f"{self.id}_label"].text = "\n".join( + [ + f"[size={self.SIZE_M}sp]{logout_msg}", + f"{backin_msg}.", + "", + f"{not_worry_msg}.[/size]", + ] + ) diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index 06d1e553..cf625a56 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -153,8 +153,9 @@ def on_enter(self): self.trigger = getattr(self.__class__, "on_trigger") # on progress should be defined on inherited classes + download = getattr(self.downloader, "download") on_progress = getattr(self.__class__, "on_progress") - _fn = partial(self.downloader.download, on_data=on_progress) + _fn = partial(download, on_data=on_progress) # Now run it as a partial function # on parallel thread to not block diff --git a/src/app/screens/base_screen.py b/src/app/screens/base_screen.py index ecaa7b46..341f9ee2 100644 --- a/src/app/screens/base_screen.py +++ b/src/app/screens/base_screen.py @@ -34,12 +34,10 @@ from kivy.uix.button import Button from kivy.uix.gridlayout import GridLayout from kivy.uix.image import Image -from kivy.core.window import Window -from kivy.weakproxy import WeakProxy from kivy.uix.screenmanager import Screen -from src.utils.trigger import Trigger +from kivy.weakproxy import WeakProxy from src.i18n import T -from src.utils.selector import VALID_DEVICES +from src.utils.trigger import Trigger class BaseScreen(Screen, Trigger): @@ -128,6 +126,7 @@ def locale(self, value: bool): self._locale = value def translate(self, key: str) -> str: + """Translate some message as key""" msg = T(key, locale=self.locale, module=self.id) self.debug(f"Translated '{key}' to '{msg}'") return msg @@ -165,12 +164,10 @@ def make_subgrid(self, wid: str, rows: int, root_widget: str): self.ids[root_widget].add_widget(grid) self.ids[wid] = WeakProxy(grid) - def make_label( - self, wid: str, text: str, root_widget: str, markup: bool, halign: str - ): + def make_label(self, wid: str, text: str, root_widget: str, halign: str): """Build grid where buttons will be placed""" self.debug(f"Building GridLayout::{wid}") - label = Label(text=text, markup=markup, halign=halign) + label = Label(text=text, markup=True, halign=halign) label.id = wid self.ids[root_widget].add_widget(label) self.ids[wid] = WeakProxy(label) @@ -191,30 +188,29 @@ def clear_grid(self, wid: str): def make_button( self, root_widget: str, - id: str, + wid: str, text: str, - markup: bool, row: int, on_press: typing.Callable, on_release: typing.Callable, ): """Create buttons in a dynamic way""" - self.debug(f"{id} -> {root_widget}") + self.debug(f"{wid} -> {root_widget}") total = self.ids[root_widget].rows btn = Button( text=text, - markup=markup, + markup=True, halign="center", font_size=Window.size[0] // 25, background_color=(0, 0, 0, 1), color=(1, 1, 1, 1), ) - btn.id = id + btn.id = wid # define button methods to be callable in classes - setattr(self, f"on_press_{id}", on_press) - setattr(self, f"on_release_{id}", on_release) + setattr(self, f"on_press_{wid}", on_press) + setattr(self, f"on_release_{wid}", on_release) btn.bind(on_press=on_press) btn.bind(on_release=on_release) @@ -237,6 +233,7 @@ def make_stack_button( on_release: typing.Callable, size_hint: typing.Tuple[float, float], ): + """Create a button on StackLayout""" btn = Button( markup=True, font_size=Window.size[0] // 30, @@ -252,10 +249,12 @@ def make_stack_button( setattr(self, f"on_release_{wid}", on_release) def redirect_error(self, msg: str): + """Create a RuntimeError and give it to redirect_exception""" exception = RuntimeError(msg) self.redirect_exception(exception=exception) def redirect_exception(self, exception: Exception): + """Get an exception and prepare a ErrorScreen rendering""" screen = self.manager.get_screen("ErrorScreen") fns = [ partial(screen.update, name=self.name, key="error", value=exception), @@ -269,16 +268,19 @@ def redirect_exception(self, exception: Exception): @staticmethod def get_destdir_assets() -> str: + """Return the current selected path of destination assets directory""" app = App.get_running_app() return app.config.get("destdir", "assets") @staticmethod def get_baudrate() -> int: + """Return the current selected baudrate""" app = App.get_running_app() return int(app.config.get("flash", "baudrate")) @staticmethod def get_locale() -> str: + """Return the current locale""" app = App.get_running_app() locale = app.config.get("locale", "lang") @@ -286,18 +288,22 @@ def get_locale() -> str: locale = locale.split(".") return f"{locale[0].replace("-", "_")}.{locale[1]}" - elif sys.platform == "win32": + if sys.platform == "win32": return f"{locale}.UTF-8" - else: - raise RuntimeError(f"Not implemented for '{sys.platform}'") + raise RuntimeError(f"Not implemented for '{sys.platform}'") @staticmethod def open_settings(): + """Open the Settings screen""" app = App.get_running_app() app.open_settings() @staticmethod def sanitize_markup(msg: str) -> str: + """ + Sanitize a message that come with [ ] + and clean it (used in FlashScreen and WipeScreen) + """ cleanr = re.compile("\\[.*?\\]") return re.sub(cleanr, "", msg) diff --git a/src/app/screens/check_internet_connection_screen.py b/src/app/screens/check_internet_connection_screen.py deleted file mode 100644 index 5f6f7d5d..00000000 --- a/src/app/screens/check_internet_connection_screen.py +++ /dev/null @@ -1,130 +0,0 @@ -# The MIT License (MIT) - -# Copyright (c) 2021-2024 Krux contributors - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -""" -check_internet_connection_screen.py -""" -from functools import partial -from kivy.clock import Clock -from kivy.core.window import Window -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color -from kivy.app import App -from kivy.cache import Cache -from src.app.screens.base_screen import BaseScreen -from src.utils.selector import Selector - - -class CheckInternetConnectionScreen(BaseScreen): - """ - CheckInternetConnectionScreen will check internet connection and get the - latest release if ok - """ - - def __init__(self, **kwargs): - super().__init__( - wid="check_internet_connection_screen", - name="CheckInternetConnectionScreen", - **kwargs, - ) - - # Build grid where buttons will be placed - self.make_grid(wid=f"{self.id}_grid", rows=1) - - # START of on_press buttons - def _press(instance): - self.debug(f"Calling Button::{instance.id}::on_press") - self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) - - def _release(instance): - self.debug(f"Calling Button::{instance.id}::on_release") - self.set_background(wid=f"{instance.id}", rgba=(0, 0, 0, 1)) - - self.make_button( - row=0, - id=f"{self.id}_button", - root_widget=f"{self.id}_grid", - text="".join( - [ - f"[size={self.SIZE_MM}sp]", - "[color=#efcc00]", - self.translate("Checking your internet connection"), - "[/color]", - "[/size]", - ] - ), - markup=True, - on_press=_press, - on_release=_release, - ) - - def update(self, *args, **kwargs): - """ - In linux, will check for user permission on group - dialout (debian-li ke) and uucp (archlinux-like) and - add user to that group to allow sudoless flash - """ - name = kwargs.get("name") - key = kwargs.get("key") - value = kwargs.get("value") - - if name in ("ConfigKruxInstaller", "CheckInternetConnectionScreen"): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen: {name}") - - if key == "locale": - # Setup - self.locale = value - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - elif key == "check-connection": - try: - selector = Selector() - main_screen = self.manager.get_screen("MainScreen") - fn = partial( - main_screen.update, - name="KruxInstallerApp", - key="version", - value=selector.releases[0], - ) - Clock.schedule_once(fn, 0) - self.set_screen(name="MainScreen", direction="left") - - except Exception as exc: - self.redirect_exception(exception=exc) - - else: - self.redirect_error(f"Invalid key: '{key}'") - - def on_enter(self): - """Simple update your canvas""" - partials = [ - partial(self.update, name=self.name, key="canvas"), - partial(self.update, name=self.name, key="check-connection"), - ] - - for fn in partials: - Clock.schedule_once(fn, 0) diff --git a/src/app/screens/check_permissions_screen.py b/src/app/screens/check_permissions_screen.py deleted file mode 100644 index 5ec3825e..00000000 --- a/src/app/screens/check_permissions_screen.py +++ /dev/null @@ -1,313 +0,0 @@ -# The MIT License (MIT) - -# Copyright (c) 2021-2024 Krux contributors - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -""" -check_permissions_screen.py -""" -import os -import re -import typing -import sys -import time -from functools import partial -from kivy.clock import Clock -from kivy.app import App -from kivy.graphics.context_instructions import Color -from kivy.graphics.vertex_instructions import Rectangle -from kivy.core.window import Window -from .base_screen import BaseScreen -from src.i18n import T -from pysudoer import SudoerLinux - -if not sys.platform.startswith("win"): - import distro - import grp - - -class CheckPermissionsScreen(BaseScreen): - """GreetingsScreen show Krux logo and check if user is in dialout group in linux""" - - def __init__(self, **kwargs): - super().__init__( - wid="check_permissions_screen", - name="CheckPermissionsScreen", - **kwargs, - ) - - # Build grid where buttons will be placed - self.make_grid(wid=f"{self.id}_grid", rows=1) - - # These variables will setup the inclusion - # in dialout group, if necessary - self.bin = None - self.bin_args = None - self.group = None - self.user = None - self.in_dialout = False - self.on_permission_created = None - - def _on_ref_press(*args): - print(args) - if args[1] == "Allow": - # If user isnt in the dialout group, - # but the configuration was done correctly - # create the command - - if self.on_permission_created and self.bin_args: - try: - cmd = ( - [self.bin] - + [a for a in self.bin_args] - + [self.group] - + [self.user] - ) - self.debug(f"cmd={cmd}") - sudoer = SudoerLinux(name=f"Add {self.user} to {self.group}") - sudoer.exec( - cmd=cmd, env={}, callback=self.on_permission_created - ) - except Exception as err: - self.redirect_error(msg=str(err.__traceback__)) - else: - self.redirect_error( - msg=f"Invalid on_permission_created: {self.on_permission_created}" - ) - - if args[1] == "Deny": - App.get_running_app().stop() - - self.make_label( - wid=f"{self.id}_label", - text="", - root_widget=f"{self.id}_grid", - markup=True, - halign="justify", - ) - - setattr(CheckPermissionsScreen, f"on_ref_press_{self.id}_label", _on_ref_press) - self.ids[f"{self.id}_label"].bind(on_ref_press=_on_ref_press) - - fn = partial(self.update, name=self.name, key="canvas") - Clock.schedule_once(fn, 0) - - def update(self, *args, **kwargs): - """ - In linux, will check for user permission on group - dialout (debian-li ke) and uucp (archlinux-like) and - add user to that group to allow sudoless flash - """ - name = kwargs.get("name") - key = kwargs.get("key") - value = kwargs.get("value") - - if name in ( - "ConfigKruxInstaller", - "CheckPermissionsScreen", - "CheckPermissionsScreen", - ): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(msg=f"Invalid screen: '{name}'") - return - - if key == "locale": - if value is None or value.strip() == "": - self.redirect_error(msg=f"Invalid locale: '{value}'") - else: - self.locale = value - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - elif key == "check_user": - - # Here's where the check process start - # first get the current user, then verify - # the linux distribution used and use the - # proper command to add the user in 'dialout' ( - # group (in some distros, can be 'uucp') - self.user = os.environ.get("USER") - self.debug(f"Checking permissions for {self.user}") - - setup_msg = self.translate("Setup") - for_msg = self.translate("for") - - self.ids[f"{self.id}_label"].text = "".join( - [ - f"[size={self.SIZE_MM}sp]", - "[color=#efcc00]", - f"{setup_msg} {self.user} {for_msg} {distro.name()}", - "[/color]", - "[/size]", - ] - ) - - if distro.id() in ("ubuntu", "fedora", "linuxmint"): - self.bin = "/usr/bin/usermod" - self.bin_arg = ["-a", "-G"] - self.group = "dialout" - - elif distro.id() in ("arch", "manjaro", "slackware", "gentoo"): - self.bin = "/usr/bin/usermod" - self.bin_args = ["-a", "-G"] - self.group = "uucp" - - elif distro.like() == "debian": - self.bin = "/usr/bin/usermod" - self.bin_args = ["-a", "-G"] - self.group = "dialout" - - else: - self.redirect_error( - msg=f"Not implemented for '{distro.name(pretty=True)}'" - ) - return - - fn = partial(self.update, name=self.name, key="check_group") - Clock.schedule_once(fn, 2.1) - - elif key == "check_group": - - # Here is where we check if the user belongs to group - # 'dialout' (in some distros, will be 'uucp') - self.debug(f"Checking {self.group} permissions for {self.user}") - check_msg = self.translate("Checking") - perm_msg = self.translate("permissions for") - - self.ids[f"{self.id}_label"].text = "".join( - [ - f"[size={self.SIZE_G}sp]", - "[color=#efcc00]", - f"{check_msg} {self.group} {perm_msg} {self.user}", - "[/color]", - "[/size]", - ] - ) - - # loop throug all groups and check - for group in grp.getgrall(): - if self.group == group.gr_name: - self.debug(f"Found {group.gr_name}") - for user in group[3]: - if user == self.user: - self.debug(f"'{self.user}' already in group '{self.group}'") - self.in_dialout = True - - self.debug(f"in_dialout={self.in_dialout}") - - # if not in group, warn user - # and then ask for click in screen - # to proceed with the operation - if not self.in_dialout: - self.debug(f"Creating permission for {self.user}") - warn_msg = self.translate("WARNING") - first_msg = self.translate("This is the first run of KruxInstaller in") - access_msg = self.translate( - "and it appears that you do not have privileged access to make flash procedures" - ) - proceed_msg = self.translate( - "To proceed, click in the Allow button and a prompt will ask for your password" - ) - exec_msg = self.translate("to execute the following command") - - self.ids[f"{self.id}_label"].text = "\n".join( - [ - f"[size={self.SIZE_G}sp][color=#efcc00]{warn_msg}[/color][/size]", - "", - f'[size={self.SIZE_MP}sp]{first_msg} "{distro.name(pretty=True)}"', - f"{access_msg}.", - proceed_msg, - f"{exec_msg}:", - "", - "[color=#00ff00]", - f"{self.bin} {" ".join(self.bin_args or [])} {self.group} {self.user}", - "[/color]", - "[/size]", - "", - "", - f"[size={self.SIZE_M}]", - " ".join( - [ - "[color=#00FF00][ref=Allow]Allow[/ref][/color]", - "[color=#FF0000][ref=Deny]Deny[/ref][/color]", - ] - ), - "[/size]", - ] - ) - - # Check if callback is created and create if isnt exist - # (in tests you can mock it and the conditional below will not be called) - if self.on_permission_created is None: - fn = partial( - self.update, name=self.name, key="make_on_permission_created" - ) - Clock.schedule_once(fn, 2.1) - - else: - self.set_screen(name="CheckInternetConnectionScreen", direction="left") - - elif key == "make_on_permission_created": - - # When user is added to dialout group - # ask for user to reboot to apply the changes - # and the ability to flash take place - def on_permission_created(output: str): - self.debug(f"output={output}") - logout_msg = self.translate("You may need to logout (or even reboot)") - backin_msg = self.translate( - "and back in for the new group to take effect" - ) - not_worry_msg = self.translate( - "Do not worry, this message won't appear again" - ) - - self.ids[f"{self.id}_label"].text = "\n".join( - [ - f"[size={self.SIZE_M}sp][color=#efcc00]{output}[/color][/size]", - "", - f"[size={self.SIZE_M}sp]{logout_msg}", - f"{backin_msg}.", - "", - f"{not_worry_msg}.[/size]", - ] - ) - - self.bin = None - self.bin_args = None - self.group = None - self.user = None - - setattr(self, "on_permission_created", on_permission_created) - - else: - self.redirect_error(msg=f"Invalid key: '{key}'") - - def on_enter(self): - """ - check if user belongs to dialout|uucp group - (groups that manage /tty/USB files) - if belongs, add user to it - """ - fn = partial(self.update, name=self.name, key="check_user") - Clock.schedule_once(fn, 0) diff --git a/src/app/screens/download_beta_screen.py b/src/app/screens/download_beta_screen.py index 9e7b123d..0323c8db 100644 --- a/src/app/screens/download_beta_screen.py +++ b/src/app/screens/download_beta_screen.py @@ -175,6 +175,9 @@ def update(self, *args, **kwargs): self.redirect_error("Downloader already initialized") elif key == "progress": + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + # calculate percentage of download if value is not None and self.downloader is not None: lens = [value["downloaded_len"], value["content_len"]] @@ -207,7 +210,7 @@ def update(self, *args, **kwargs): # When finish, change the label, wait some seconds # and then change screen - self.trigger() + callback_trigger() else: self.redirect_error(f'Invalid key: "{key}"') diff --git a/src/app/screens/download_selfcustody_pem_screen.py b/src/app/screens/download_selfcustody_pem_screen.py index 0415eb5f..2c365453 100644 --- a/src/app/screens/download_selfcustody_pem_screen.py +++ b/src/app/screens/download_selfcustody_pem_screen.py @@ -175,7 +175,9 @@ def update(self, *args, **kwargs): # When finish, change the label, wait some seconds # and then change screen - self.trigger() + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + callback_trigger() else: self.redirect_error(f'Invalid key: "{key}"') diff --git a/src/app/screens/download_stable_zip_screen.py b/src/app/screens/download_stable_zip_screen.py index 72deb462..98747752 100644 --- a/src/app/screens/download_stable_zip_screen.py +++ b/src/app/screens/download_stable_zip_screen.py @@ -153,6 +153,7 @@ def update(self, *args, **kwargs): elif key == "progress": if value is not None: + # calculate percentage of download lens = [value["downloaded_len"], value["content_len"]] percent = lens[0] / lens[1] @@ -194,7 +195,9 @@ def update(self, *args, **kwargs): ) # When finish, change the label, wait some seconds # and then change screen - self.trigger() + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + callback_trigger() else: self.redirect_error(f"Invalid downloader: {self.downloader}") diff --git a/src/app/screens/download_stable_zip_sha256_screen.py b/src/app/screens/download_stable_zip_sha256_screen.py index 4baf9085..ebbac02f 100644 --- a/src/app/screens/download_stable_zip_sha256_screen.py +++ b/src/app/screens/download_stable_zip_sha256_screen.py @@ -179,7 +179,9 @@ def update(self, *args, **kwargs): ) # When finish, change the label, wait some seconds # and then change screen - self.trigger() + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + callback_trigger() else: self.redirect_error(f"Invalid downloader: {self.downloader}") diff --git a/src/app/screens/download_stable_zip_sig_screen.py b/src/app/screens/download_stable_zip_sig_screen.py index a576d781..c7160859 100644 --- a/src/app/screens/download_stable_zip_sig_screen.py +++ b/src/app/screens/download_stable_zip_sig_screen.py @@ -119,19 +119,19 @@ def update(self, *args, **kwargs): to = self.translate("to") filepath = os.path.join(destdir, f"krux-{self.version}.zip.sig") - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - downloading, - "\n", - f"[color=#00AABB][ref={url}]{url}[/ref][/color]", - "\n", - to, - "\n", - filepath, - "[/size]", - ] - ) + self.ids[f"{self.id}_info"].text = "".join( + [ + f"[size={self.SIZE_MP}sp]", + downloading, + "\n", + f"[color=#00AABB][ref={url}]{url}[/ref][/color]", + "\n", + to, + "\n", + filepath, + "[/size]", + ] + ) else: self.redirect_error(f"Invalid value for key '{key}': '{value}'") @@ -175,7 +175,9 @@ def update(self, *args, **kwargs): # When finish, change the label, wait some seconds # and then change screen - self.trigger() + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + callback_trigger() else: self.redirect_error(f"Invalid value for key '{key}': '{value}'") diff --git a/src/app/screens/error_screen.py b/src/app/screens/error_screen.py index 91babf31..cfdecae5 100644 --- a/src/app/screens/error_screen.py +++ b/src/app/screens/error_screen.py @@ -64,10 +64,9 @@ def _release(instance): self.make_button( row=0, - id=f"{self.id}_button", + wid=f"{self.id}_button", root_widget=f"{self.id}_grid", text="", - markup=True, on_press=_press, on_release=_release, ) @@ -84,23 +83,7 @@ def update(self, *args, **kwargs): key = kwargs.get("key") value = kwargs.get("value") - if name in ( - "CheckPermissionsScreen", - "ConfigKruxInstaller", - "CheckInternetConnectionScreen", - "SelectDeviceScreen", - "SelectVersionScreen", - "SelectOldVersionScreen", - "DownloadBetaScreen", - "DownloadSelfcustodyPemScreen", - "FlashScreen", - "WipeScreen", - "AboutScreen", - "ErrorScreen", - ): - self.debug(f"Updating {self.name} from {name}...") - else: - raise ValueError(f"Invalid screen: {name}") + self.debug(f"Updating {self.name} from {name}...") if key == "locale": self.locale = value diff --git a/src/app/screens/flash_screen.py b/src/app/screens/flash_screen.py index 7af64da6..aa1dec67 100644 --- a/src/app/screens/flash_screen.py +++ b/src/app/screens/flash_screen.py @@ -45,6 +45,8 @@ def __init__(self, **kwargs): def on_pre_enter(self): self.ids[f"{self.id}_grid"].clear_widgets() + callback_trigger = getattr(self, "trigger") + def on_print_callback(*args, **kwargs): text = " ".join(str(x) for x in args) self.info(text) @@ -71,7 +73,7 @@ def on_print_callback(*args, **kwargs): if "INFO" in text: self.output.append(text) if "Rebooting" in text: - self.trigger() + callback_trigger() elif "Programming BIN" in text: self.output[-1] = text @@ -180,7 +182,6 @@ def on_trigger_callback(dt): wid=f"{self.id}_progress", text="", root_widget=f"{self.id}_subgrid", - markup=True, halign="center", ) @@ -188,7 +189,6 @@ def on_trigger_callback(dt): wid=f"{self.id}_info", text="", root_widget=f"{self.id}_grid", - markup=True, halign="justify", ) diff --git a/src/app/screens/greetings_screen.py b/src/app/screens/greetings_screen.py index ab401e8c..9bc3740a 100644 --- a/src/app/screens/greetings_screen.py +++ b/src/app/screens/greetings_screen.py @@ -21,13 +21,15 @@ """ greetings_screen.py """ +import os import sys from functools import partial from kivy.clock import Clock from kivy.graphics import Color from kivy.graphics import Rectangle from kivy.core.window import Window -from .base_screen import BaseScreen +from src.utils.selector import Selector +from src.app.screens.base_screen import BaseScreen class GreetingsScreen(BaseScreen): @@ -48,61 +50,148 @@ def __init__(self, **kwargs): wid=f"{self.id}_logo", root_widget=f"{self.id}_grid", source=self.logo_img ) + fn = partial(self.update, name="KruxInstallerApp", key="canvas") + Clock.schedule_once(fn, 0) + + def on_enter(self): + """ + When application start, after greeting user with the krux logo, it will need to check if + user is running app in linux or non-linux. If running in linux, the user will be + redirect to CheckPermissionsScreen and then to MainScreen. Win32 and Mac will be + redirect to MainScreen. + """ + # screen = self.screen_manager.get_screen("GreetingsScreen") + # print(screen) + + fns = [ + partial(self.update, name=self.name, key="check-permission-screen"), + partial(self.update, name=self.name, key="check-internet-connection"), + ] + + for fn in fns: + Clock.schedule_once(fn, 2.1) + def update(self, *args, **kwargs): - """Update to go to some screen (MainScreen or CheckPermissionsScreen)""" name = kwargs.get("name") key = kwargs.get("key") value = kwargs.get("value") - if name in ("GreetingsScreen", "KruxInstallerApp"): - self.debug(f"Updating {self.name} from {name}") + if name in ("KruxInstallerApp", "GreetingsScreen"): + self.debug(f"Updating {self.name} from {name}...") else: - raise ValueError(f"Invalid screen: {name}") - - if key == "change_screen": - if value is not None and value in ( - "MainScreen", - "CheckPermissionsScreen", - "CheckInternetConnectionScreen", - ): - self.set_screen(name=value, direction="left") + self.redirect_error(msg=f"Invalid screen: '{name}'") + return + + if key == "locale": + if value is None or value.strip() == "": + self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") else: - raise ValueError(f"Invalid value for '{key}': {value}") + self.locale = value elif key == "canvas": - + # prepare background with self.canvas.before: - Color(0, 0, 0) - Rectangle(pos=(0, 0), size=Window.size) - - elif key == "check_permissions": - # check platform and if is linux, go to CheckPermissionsScreen, - # otherwise, go to MainScreen + Color(0, 0, 0, 1) + Rectangle(size=(Window.width, Window.height)) + elif key == "check-permission-screen": if sys.platform == "linux": - fn = partial( - self.update, - name=self.name, - key="change_screen", - value="CheckPermissionsScreen", - ) - - elif sys.platform == "darwin" or sys.platform == "win32": - fn = partial( - self.update, - name=self.name, - key="change_screen", - value="CheckInternetConnectionScreen", - ) - + self.check_permissions_for_dialout_group() else: - raise RuntimeError(f"Not implemented for {sys.platform}") + self.warning(f"Skipping permissions check for {sys.platform}") - Clock.schedule_once(fn, 2.1) + elif key == "check-internet-connection": + self.check_internet_connection() else: - raise ValueError(f"Invalid key: '{key}'") + self.redirect_error(msg=f'Invalid key: "{key}"') + + def check_permissions_for_dialout_group(self): + """ + Here's where the check process start + first get the current user, then verify + the linux distribution used and use the + proper command to add the user in 'dialout' + group (in some distros, can be 'uucp') + """ + if sys.platform.startswith("linux"): + import distro + import grp + + # get current user + _user = os.environ.get("USER") + _in_dialout = False + _group = None + + # detect linux distro + if distro.id() in ("ubuntu", "fedora", "linuxmint"): + _group = "dialout" + + elif distro.like() == "debian": + _group = "dialout" + + elif distro.id() in ("arch", "manjaro", "slackware", "gentoo"): + _group = "uucp" - def on_enter(self): - fn = partial(self.update, name=self.name, key="canvas") - Clock.schedule_once(fn, 0) + else: + self.redirect_error(msg=f"{distro.name(pretty=True)} not supported") + return + + self.debug(f"Checking {_group} permissions for {_user}") + + # loop throug all linux groups and check + # if the user is registered in the "dialout" group + for _group in grp.getgrall(): + if _group == _group.gr_name: + self.debug(f"Found {_group.gr_name}") + for _grpuser in _group[3]: + if _grpuser == _user: + self.debug(f"'{_user}' already in group '{_group}'") + _in_dialout = True + + self.debug(f"user {_user} in dialout group={_in_dialout}") + + # if user is not in dialout group, warn user + # and then redirect to a screen that will + # proceed with the proper operation + if not _in_dialout: + ask_screen = self.manager.get_screen("AskPermissionDialoutScreen") + _distro = distro.name(pretty=True) + + fns = [ + partial(ask_screen.update, name=self.name, key="user", value=_user), + partial( + ask_screen.update, name=self.name, key="group", value=_group + ), + partial( + ask_screen.update, name=self.name, key="distro", value=_distro + ), + partial(ask_screen, name=self.name, key="screen"), + ] + + for fn in fns: + Clock.schedule_once(fn, 0) + + self.set_screen(name="AskPermissionsDialoutScreen", direction="left") + + def check_internet_connection(self): + """ + In reality, this method get the latest version and set to + select version button on main_screen. But it can work as + internet connection check + """ + try: + selector = Selector() + main_screen = self.manager.get_screen("MainScreen") + fn = partial( + main_screen.update, + name="KruxInstallerApp", + key="version", + value=selector.releases[0], + ) + Clock.schedule_once(fn, 0) + self.set_screen(name="MainScreen", direction="left") + + except Exception as exc: + self.error(str(exc)) + self.redirect_exception(exception=exc) diff --git a/src/app/screens/main_screen.py b/src/app/screens/main_screen.py index 26d3952f..e2946caf 100644 --- a/src/app/screens/main_screen.py +++ b/src/app/screens/main_screen.py @@ -237,10 +237,9 @@ def _release(instance): self.make_button( row=row, - id=_tuple[0], + wid=_tuple[0], root_widget="main_screen_grid", text=_tuple[1], - markup=True, on_press=_press, on_release=_release, ) diff --git a/src/app/screens/select_device_screen.py b/src/app/screens/select_device_screen.py index 7e5d02f4..f94ef40e 100644 --- a/src/app/screens/select_device_screen.py +++ b/src/app/screens/select_device_screen.py @@ -71,10 +71,9 @@ def _on_release(instance): self.make_button( row=row, - id=f"select_device_{device}", + wid=f"select_device_{device}", root_widget="select_device_screen_grid", text="", - markup=True, on_press=_on_press, on_release=_on_release, ) diff --git a/src/app/screens/select_old_version_screen.py b/src/app/screens/select_old_version_screen.py index 3d4b0445..1ada04de 100644 --- a/src/app/screens/select_old_version_screen.py +++ b/src/app/screens/select_old_version_screen.py @@ -76,10 +76,9 @@ def _release(instance): self.make_button( row=row, - id=wid, + wid=wid, root_widget="select_old_version_screen_grid", text=text, - markup=True, on_press=_press, on_release=_release, ) @@ -99,10 +98,9 @@ def _release_back(instance): back = self.translate("Back") self.make_button( row=len(old_versions) + 1, - id="select_old_version_back", + wid="select_old_version_back", root_widget="select_old_version_screen_grid", text=back, - markup=True, on_press=_press_back, on_release=_release_back, ) diff --git a/src/app/screens/select_version_screen.py b/src/app/screens/select_version_screen.py index efb4f460..c088e3a7 100644 --- a/src/app/screens/select_version_screen.py +++ b/src/app/screens/select_version_screen.py @@ -28,7 +28,8 @@ from kivy.weakproxy import WeakProxy from kivy.core.window import Window from kivy.uix.button import Button -from kivy.graphics import Color, Line +from kivy.graphics import Color +from kivy.graphics import Rectangle from src.utils.selector import Selector from src.app.screens.base_screen import BaseScreen @@ -141,15 +142,15 @@ def _release(instance): # END of on_release buttons self.make_button( row=row, - id=_tuple[0], + wid=_tuple[0], root_widget="select_version_screen_grid", text=_tuple[1], - markup=True, on_press=_press, on_release=_release, ) except Exception as exc: + self.error(str(exc)) self.redirect_exception(exception=exc) def update(self, *args, **kwargs): @@ -176,6 +177,12 @@ def update(self, *args, **kwargs): back = self.translate("Back") self.ids["select_version_back"].text = back + elif key == "canvas": + # prepare background + with self.canvas.before: + Color(0, 0, 0, 1) + Rectangle(size=(Window.width, Window.height)) + else: self.redirect_error(f"Invalid value for key '{key}': '{value}'") diff --git a/src/app/screens/unzip_stable_screen.py b/src/app/screens/unzip_stable_screen.py index 9e598ca0..39c5cbc3 100644 --- a/src/app/screens/unzip_stable_screen.py +++ b/src/app/screens/unzip_stable_screen.py @@ -180,7 +180,7 @@ def _release(instance): p = os.path.join(rel_path, "kboot.kfpkg") self.make_button( - id=f"{self.id}_flash_button", + wid=f"{self.id}_flash_button", root_widget=f"{self.id}_grid", text="".join( [ @@ -195,7 +195,6 @@ def _release(instance): "[/size]", ] ), - markup=True, row=0, on_press=getattr(UnzipStableScreen, f"on_press_{self.id}_flash_button"), on_release=getattr(UnzipStableScreen, f"on_release_{self.id}_flash_button"), @@ -276,7 +275,7 @@ def _release(instance): p = os.path.join(rel_path, "firmware.bin") self.make_button( - id=f"{self.id}_airgap_button", + wid=f"{self.id}_airgap_button", root_widget=f"{self.id}_grid", text="".join( [ @@ -293,7 +292,6 @@ def _release(instance): "[/size]", ] ), - markup=True, row=0, on_press=getattr(UnzipStableScreen, f"on_press_{self.id}_airgap_button"), on_release=getattr( diff --git a/src/app/screens/warning_already_downloaded_screen.py b/src/app/screens/warning_already_downloaded_screen.py index 2a19eb42..b86304aa 100644 --- a/src/app/screens/warning_already_downloaded_screen.py +++ b/src/app/screens/warning_already_downloaded_screen.py @@ -58,7 +58,6 @@ def __init__(self, **kwargs): wid=f"{self.id}_label", text="", root_widget=f"{self.id}_grid", - markup=True, halign="justify", ) diff --git a/src/app/screens/warning_beta_screen.py b/src/app/screens/warning_beta_screen.py index af105d57..187df022 100644 --- a/src/app/screens/warning_beta_screen.py +++ b/src/app/screens/warning_beta_screen.py @@ -91,10 +91,9 @@ def _release(instance): self.make_button( row=0, - id="warning_beta_screen_warn", + wid="warning_beta_screen_warn", root_widget="warning_beta_screen_grid", text=text, - markup=True, on_press=_press, on_release=_release, ) diff --git a/src/app/screens/warning_wipe_screen.py b/src/app/screens/warning_wipe_screen.py index 538bd34b..cf47da11 100644 --- a/src/app/screens/warning_wipe_screen.py +++ b/src/app/screens/warning_wipe_screen.py @@ -58,7 +58,6 @@ def __init__(self, **kwargs): wid=f"{self.id}_label", text=self.make_label_text(), root_widget=f"{self.id}_grid", - markup=True, halign="justify", ) diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index 0a029776..07e2c89e 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -46,6 +46,7 @@ def __init__(self, **kwargs): def on_pre_enter(self): self.ids[f"{self.id}_grid"].clear_widgets() + callback_trigger = getattr(self, "trigger") def on_print_callback(*args, **kwargs): text = " ".join(str(x) for x in args) @@ -84,7 +85,7 @@ def on_print_callback(*args, **kwargs): del self.output[:1] if "SPI Flash erased." in text: - self.trigger() + callback_trigger() self.ids[f"{self.id}_info"].text = "\n".join(self.output) @@ -144,7 +145,6 @@ def on_trigger_callback(dt): wid=f"{self.id}_progress", text="", root_widget=f"{self.id}_subgrid", - markup=True, halign="center", ) @@ -152,7 +152,6 @@ def on_trigger_callback(dt): wid=f"{self.id}_info", text="", root_widget=f"{self.id}_grid", - markup=True, halign="justify", ) diff --git a/src/i18n/en_US.UTF-8.json b/src/i18n/en_US.UTF-8.json index 841f406b..dc98c484 100644 --- a/src/i18n/en_US.UTF-8.json +++ b/src/i18n/en_US.UTF-8.json @@ -1,9 +1,5 @@ { "check_permissions_screen": { - "Setup": "Setup", - "for": "for", - "Checking": "Checking", - "permissions for": "permissions for", "WARNING": "WARNING", "This is the first run of KruxInstaller in": "This is the first run of KruxInstaller in", "and it appears that you do not have privileged access to make flash procedures": "and it appears that you do not have privileged access to make flash procedures", From acbf274b84c7e34396108fe988e01e0f642aa8fa Mon Sep 17 00:00:00 2001 From: qlrd Date: Sun, 1 Sep 2024 22:09:50 -0300 Subject: [PATCH 06/61] fixed flash and wipe screens changed some methods to standardized name ones, on_data, on_process, on_done --- e2e/test_001_greetings_screen.py | 3 +- e2e/test_002_ask_permission_dialout_screen.py | 2 +- e2e/test_020_app_init.py | 2 +- e2e/test_021_base_flash_screen.py | 81 +++--- e2e/test_022_flash_screen.py | 230 ++++++++---------- e2e/test_023_wipe_screen.py | 54 ++-- pyproject.toml | 4 +- src/app/screens/base_flash_screen.py | 30 ++- src/app/screens/flash_screen.py | 111 ++++----- src/app/screens/wipe_screen.py | 128 +++++----- 10 files changed, 306 insertions(+), 339 deletions(-) diff --git a/e2e/test_001_greetings_screen.py b/e2e/test_001_greetings_screen.py index 1f4a5053..04f1e2e1 100644 --- a/e2e/test_001_greetings_screen.py +++ b/e2e/test_001_greetings_screen.py @@ -1,7 +1,6 @@ import os -import sys from pathlib import Path -from unittest.mock import patch, MagicMock +from unittest.mock import patch from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest from src.app.screens.greetings_screen import GreetingsScreen diff --git a/e2e/test_002_ask_permission_dialout_screen.py b/e2e/test_002_ask_permission_dialout_screen.py index 8bdca0a0..32486172 100644 --- a/e2e/test_002_ask_permission_dialout_screen.py +++ b/e2e/test_002_ask_permission_dialout_screen.py @@ -1,6 +1,6 @@ import os import sys -from unittest.mock import patch, MagicMock, call +from unittest.mock import patch, MagicMock from pytest import mark from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest diff --git a/e2e/test_020_app_init.py b/e2e/test_020_app_init.py index 15c53917..3075504a 100644 --- a/e2e/test_020_app_init.py +++ b/e2e/test_020_app_init.py @@ -1,5 +1,5 @@ import os -from unittest.mock import patch, MagicMock, call +from unittest.mock import patch from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest from kivy.uix.screenmanager import ScreenManager diff --git a/e2e/test_021_base_flash_screen.py b/e2e/test_021_base_flash_screen.py index 262bd2b2..4015f7c9 100644 --- a/e2e/test_021_base_flash_screen.py +++ b/e2e/test_021_base_flash_screen.py @@ -11,8 +11,10 @@ def teardown_class(cls): EventLoop.exit() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_init(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_init(self, mock_get_locale): screen = BaseFlashScreen(wid="mock_screen", name="MockScreen") self.render(screen) @@ -27,18 +29,19 @@ def test_init(self, mock_get_running_app): self.assertEqual(screen.firmware, None) self.assertEqual(screen.baudrate, None) self.assertEqual(screen.thread, None) - self.assertEqual(screen.trigger, None) - self.assertEqual(screen.output, None) + self.assertEqual(screen.is_done, False) + self.assertEqual(screen.done, None) + self.assertEqual(screen.output, []) # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.base_flash_screen.os.path.exists", side_effect=[True]) - def test_set_firmware(self, mock_exists, mock_get_running_app): + def test_set_firmware(self, mock_exists, mock_get_locale): screen = BaseFlashScreen(wid="mock_screen", name="MockScreen") screen.firmware = "mock.kfpkg" self.assertEqual(screen.firmware, "mock.kfpkg") @@ -46,14 +49,14 @@ def test_set_firmware(self, mock_exists, mock_get_running_app): mock_exists.assert_called_once_with("mock.kfpkg") # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.base_flash_screen.os.path.exists", side_effect=[False]) - def test_fail_set_firmware(self, mock_exists, mock_get_running_app): + def test_fail_set_firmware(self, mock_exists, mock_get_locale): screen = BaseFlashScreen(wid="mock_screen", name="MockScreen") with self.assertRaises(ValueError) as exc_info: @@ -61,58 +64,58 @@ def test_fail_set_firmware(self, mock_exists, mock_get_running_app): self.assertEqual(str(exc_info.exception), "Firmware not exist: mock.kfpkg") # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) - + mock_get_locale.assert_called() mock_exists.assert_called_once_with("mock.kfpkg") @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_set_baudrate(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_set_baudrate(self, mock_get_locale): screen = BaseFlashScreen(wid="mock_screen", name="MockScreen") screen.baudrate = "1500000" self.assertEqual(screen.baudrate, "1500000") + # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_set_thread(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_set_thread(self, mock_get_locale): screen = BaseFlashScreen(wid="mock_screen", name="MockScreen") screen.thread = MagicMock() screen.thread.start = MagicMock() screen.thread.start() screen.thread.start.assert_called_once() + # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.base_flash_screen.Clock.create_trigger") - def test_set_trigger(self, mock_create_trigger, mock_get_running_app): + def test_set_done(self, mock_create_trigger, mock_get_locale): mock_trigger = MagicMock() screen = BaseFlashScreen(wid="mock_screen", name="MockScreen") - screen.trigger = mock_trigger + screen.done = mock_trigger # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() mock_create_trigger.assert_has_calls([call(mock_trigger)], any_order=True) @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_set_output(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_set_output(self, mock_get_locale): screen = BaseFlashScreen(wid="mock_screen", name="MockScreen") screen.output = ["mock", "this", "test"] self.assertEqual(len(screen.output), 3) + # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() diff --git a/e2e/test_022_flash_screen.py b/e2e/test_022_flash_screen.py index be139452..f80b7914 100644 --- a/e2e/test_022_flash_screen.py +++ b/e2e/test_022_flash_screen.py @@ -12,10 +12,12 @@ def teardown_class(cls): EventLoop.exit() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.flash_screen.partial") @patch("src.app.screens.flash_screen.Clock.schedule_once") - def test_init(self, mock_schedule_once, mock_partial, mock_get_running_app): + def test_init(self, mock_schedule_once, mock_partial, mock_get_locale): screen = FlashScreen() self.render(screen) @@ -30,21 +32,22 @@ def test_init(self, mock_schedule_once, mock_partial, mock_get_running_app): self.assertEqual(screen.firmware, None) self.assertEqual(screen.baudrate, None) self.assertEqual(screen.thread, None) - self.assertEqual(screen.trigger, None) - self.assertEqual(screen.output, None) + self.assertEqual(screen.is_done, False) + self.assertEqual(screen.done, None) + self.assertEqual(screen.output, []) # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() mock_partial.assert_called_once_with( screen.update, name=screen.name, key="canvas" ) mock_schedule_once.assert_has_calls([call(mock_partial(), 0)], any_order=True) @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_fail_update_wrong_name(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_fail_update_wrong_name(self, mock_get_locale): screen = FlashScreen() self.render(screen) @@ -57,9 +60,7 @@ def test_fail_update_wrong_name(self, mock_get_running_app): self.assertEqual(str(exc_info.exception), "Invalid screen name: MockScreen") # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( @@ -80,8 +81,10 @@ def test_fail_update_wrong_key(self, mock_redirect_error, mock_get_locale): mock_redirect_error.assert_called_once_with('Invalid key: "mock"') @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_update_locale(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_update_locale(self, mock_get_locale): screen = FlashScreen() self.render(screen) @@ -92,15 +95,15 @@ def test_update_locale(self, mock_get_running_app): self.assertEqual(screen.locale, "en_US.UTF8") # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.flash_screen.Rectangle") @patch("src.app.screens.flash_screen.Color") - def test_update_canvas(self, mock_color, mock_rectangle, mock_get_running_app): + def test_update_canvas(self, mock_color, mock_rectangle, mock_get_locale): screen = FlashScreen() self.render(screen) @@ -109,9 +112,7 @@ def test_update_canvas(self, mock_color, mock_rectangle, mock_get_running_app): window = EventLoop.window # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() mock_color.assert_called_once_with(0, 0, 0, 1) # Check why the below happens: In linux, it will set window @@ -122,8 +123,10 @@ def test_update_canvas(self, mock_color, mock_rectangle, mock_get_running_app): mock_rectangle.assert_called_once_with(size=window.size) @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_update_baudrate(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_update_baudrate(self, mock_get_locale): screen = FlashScreen() self.render(screen) @@ -134,14 +137,14 @@ def test_update_baudrate(self, mock_get_running_app): self.assertEqual(screen.baudrate, 1500000) # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.utils.flasher.base_flasher.os.path.exists", side_effect=[True]) - def test_update_firmware(self, mock_exists, mock_get_running_app): + def test_update_firmware(self, mock_exists, mock_get_locale): screen = FlashScreen() self.render(screen) @@ -153,14 +156,14 @@ def test_update_firmware(self, mock_exists, mock_get_running_app): mock_exists.assert_called_once_with("mock.kfpkg") # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.utils.flasher.base_flasher.os.path.exists", side_effect=[True, True]) - def test_update_flasher(self, mock_exists, mock_get_running_app): + def test_update_flasher(self, mock_exists, mock_get_locale): screen = FlashScreen() screen.firmware = "mock.kfpkg" screen.baudrate = 1500000 @@ -174,14 +177,14 @@ def test_update_flasher(self, mock_exists, mock_get_running_app): self.assertEqual(screen.flasher.baudrate, 1500000) # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() mock_exists.assert_has_calls([call("mock.kfpkg"), call("mock.kfpkg")]) @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_on_pre_enter(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_on_pre_enter(self, mock_get_locale): screen = FlashScreen() screen.on_pre_enter() self.render(screen) @@ -189,22 +192,22 @@ def test_on_pre_enter(self, mock_get_running_app): # get your Window instance safely EventLoop.ensure_window() - self.assertTrue(hasattr(FlashScreen, "on_print_callback")) - self.assertTrue(hasattr(FlashScreen, "on_process_callback")) - self.assertTrue(hasattr(FlashScreen, "on_trigger_callback")) + self.assertTrue(hasattr(FlashScreen, "on_data")) + self.assertTrue(hasattr(FlashScreen, "on_process")) + self.assertTrue(hasattr(FlashScreen, "on_done")) self.assertIn(f"{screen.id}_subgrid", screen.ids) self.assertIn(f"{screen.id}_loader", screen.ids) self.assertIn(f"{screen.id}_progress", screen.ids) self.assertIn(f"{screen.id}_info", screen.ids) # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_on_print_callback(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_on_data_mock(self, mock_get_locale): screen = FlashScreen() screen.output = [] screen.on_pre_enter() @@ -213,18 +216,19 @@ def test_on_print_callback(self, mock_get_running_app): # get your Window instance safely EventLoop.ensure_window() - on_print_callback = getattr(FlashScreen, "on_print_callback") - on_print_callback("[color=#00ff00] INFO [/color] mock") + on_data = getattr(FlashScreen, "on_data") + on_data("[color=#00ff00] INFO [/color] mock") self.assertEqual(screen.output, ["[color=#00ff00] INFO [/color] mock"]) + # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_on_print_callback_programming_bin(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_on_data_programming_bin(self, mock_get_locale): screen = FlashScreen() screen.output = [] screen.on_pre_enter() @@ -233,28 +237,28 @@ def test_on_print_callback_programming_bin(self, mock_get_running_app): # get your Window instance safely EventLoop.ensure_window() - on_print_callback = getattr(FlashScreen, "on_print_callback") + on_data = getattr(FlashScreen, "on_data") # Let's "print" some previous infos for i in range(19): - on_print_callback(f"[color=#00ff00] INFO [/color] mock test message {i}") + on_data(f"[color=#00ff00] INFO [/color] mock test message {i}") self.assertEqual(len(screen.output), 18) # Now print programming BIN - on_print_callback("Programming BIN: |=----------| 0.21% at 21 KiB/s") + on_data("Programming BIN: |=----------| 0.21% at 21 KiB/s") self.assertEqual( screen.output[-1], "Programming BIN: |=----------| 0.21% at 21 KiB/s" ) # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_on_print_callback_separator(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_on_data(self, mock_get_locale): screen = FlashScreen() screen.output = [] screen.on_pre_enter() @@ -263,27 +267,27 @@ def test_on_print_callback_separator(self, mock_get_running_app): # get your Window instance safely EventLoop.ensure_window() - on_print_callback = getattr(FlashScreen, "on_print_callback") + on_data = getattr(FlashScreen, "on_data") # Let's "print" some previous infos for i in range(19): - on_print_callback(f"[color=#00ff00] INFO [/color] mock test message {i}") + on_data(f"[color=#00ff00] INFO [/color] mock test message {i}") self.assertEqual(len(screen.output), 18) # Now print programming BIN - on_print_callback("*") + on_data("*") self.assertEqual(screen.output[-2], "*") self.assertEqual(screen.output[-1], "") # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_on_print_callback_message_not_recognized(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_on_data_message_not_recognized(self, mock_get_locale): screen = FlashScreen() screen.output = [] screen.on_pre_enter() @@ -292,21 +296,19 @@ def test_on_print_callback_message_not_recognized(self, mock_get_running_app): # get your Window instance safely EventLoop.ensure_window() - on_print_callback = getattr(FlashScreen, "on_print_callback") + on_data = getattr(FlashScreen, "on_data") # Let's "print" some previous infos - - warn = "[WARN] mock test" - on_print_callback(warn) + on_data("[WARN] mock test") # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - def test_on_print_callback_pop_ouput(self, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_on_data_pop_ouput(self, mock_get_locale): screen = FlashScreen() screen.output = [] screen.on_pre_enter() @@ -315,22 +317,22 @@ def test_on_print_callback_pop_ouput(self, mock_get_running_app): # get your Window instance safely EventLoop.ensure_window() - on_print_callback = getattr(FlashScreen, "on_print_callback") + on_data = getattr(FlashScreen, "on_data") for i in range(19): - on_print_callback(f"[color=#00ff00] INFO [/color] mock test message {i}") + on_data(f"[color=#00ff00] INFO [/color] mock test message {i}") self.assertEqual(len(screen.output), 18) # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") - @patch("src.app.screens.flash_screen.FlashScreen.trigger") - def test_on_print_callback_rebooting(self, mock_trigger, mock_get_running_app): + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.flash_screen.FlashScreen.done") + def test_on_print_callback_rebooting(self, mock_done, mock_get_locale): screen = FlashScreen() screen.output = [] screen.on_pre_enter() @@ -339,23 +341,21 @@ def test_on_print_callback_rebooting(self, mock_trigger, mock_get_running_app): # get your Window instance safely EventLoop.ensure_window() - on_print_callback = getattr(FlashScreen, "on_print_callback") + on_print_callback = getattr(FlashScreen, "on_data") on_print_callback("[color=#00ff00] INFO [/color] Rebooting...\n") self.assertEqual( screen.output, ["[color=#00ff00] INFO [/color] Rebooting...\n"] ) # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) - mock_trigger.assert_called_once() + mock_get_locale.assert_called() + mock_done.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - def test_on_process_callback(self, mock_get_locale): + def test_on_process(self, mock_get_locale): screen = FlashScreen() screen.output = [] screen.on_pre_enter() @@ -383,21 +383,20 @@ def test_on_process_callback(self, mock_get_locale): "[/size]", ] ) - on_process_callback = getattr(FlashScreen, "on_process_callback") - on_process_callback( - file_type="firmware.bin", iteration=1, total=21, suffix="21 KiB/s" - ) + on_process = getattr(FlashScreen, "on_process") + on_process(file_type="firmware.bin", iteration=1, total=21, suffix="21 KiB/s") + # default assertions self.assertEqual(screen.ids[f"{screen.id}_progress"].text, text) - # patch assertions + # patch assertions mock_get_locale.assert_any_call() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - def test_on_trigger_callback(self, mock_get_locale): + def test_on_done(self, mock_get_locale): screen = FlashScreen() screen.output = [] screen.on_pre_enter() @@ -428,8 +427,8 @@ def test_on_trigger_callback(self, mock_get_locale): ] ) - on_trigger_callback = getattr(FlashScreen, "on_trigger_callback") - on_trigger_callback(0) + on_done = getattr(FlashScreen, "on_done") + on_done(0) self.assertEqual(screen.ids[f"{screen.id}_progress"].text, text) @@ -440,29 +439,10 @@ def test_on_trigger_callback(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_on_enter(self, mock_redirect_error, mock_get_locale): - screen = FlashScreen() - screen.on_pre_enter() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.on_enter() - - # patch assertions - mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with("Flasher isnt configured") - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.App.get_running_app") @patch("src.app.screens.flash_screen.partial") @patch("src.app.screens.flash_screen.threading.Thread") @patch("src.utils.flasher.Flasher") - def test_on_enter( - self, mock_flasher, mock_thread, mock_partial, mock_get_running_app - ): + def test_on_enter(self, mock_flasher, mock_thread, mock_partial, mock_get_locale): mock_flasher.__class__.print_callback = MagicMock() screen = FlashScreen() @@ -478,16 +458,14 @@ def test_on_enter( EventLoop.ensure_window() # prepare assertions - on_process_callback = getattr(FlashScreen, "on_process_callback") + on_process = getattr(FlashScreen, "on_process") # patch assertions - mock_get_running_app.assert_has_calls( - [call().config.get("locale", "lang")], any_order=True - ) + mock_get_locale.assert_called() mock_partial.assert_has_calls( [ call(screen.update, name=screen.name, key="canvas"), - call(screen.flasher.flash, callback=on_process_callback), + call(screen.flasher.flash, callback=on_process), ], any_order=True, ) diff --git a/e2e/test_023_wipe_screen.py b/e2e/test_023_wipe_screen.py index 7ce6f4a0..d12bebef 100644 --- a/e2e/test_023_wipe_screen.py +++ b/e2e/test_023_wipe_screen.py @@ -39,8 +39,9 @@ def test_init(self, mock_schedule_once, mock_partial, mock_get_locale): self.assertEqual(len(grid.children), 0) self.assertEqual(screen.baudrate, None) self.assertEqual(screen.thread, None) - self.assertEqual(screen.trigger, None) - self.assertEqual(screen.output, None) + self.assertEqual(screen.is_done, False) + self.assertEqual(screen.done, None) + self.assertEqual(screen.output, []) # patch assertions mock_get_locale.assert_called_once() @@ -165,8 +166,8 @@ def test_on_pre_enter(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - self.assertTrue(hasattr(WipeScreen, "on_print_callback")) - self.assertTrue(hasattr(WipeScreen, "on_trigger_callback")) + self.assertTrue(hasattr(WipeScreen, "on_data")) + self.assertTrue(hasattr(WipeScreen, "on_done")) self.assertIn(f"{screen.id}_subgrid", screen.ids) self.assertIn(f"{screen.id}_loader", screen.ids) self.assertIn(f"{screen.id}_progress", screen.ids) @@ -179,7 +180,7 @@ def test_on_pre_enter(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - def test_on_print_callback(self, mock_get_locale): + def test_on_data(self, mock_get_locale): screen = WipeScreen() screen.output = [] screen.on_pre_enter() @@ -188,8 +189,8 @@ def test_on_print_callback(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - on_print_callback = getattr(WipeScreen, "on_print_callback") - on_print_callback("[color=#00ff00] INFO [/color] mock") + on_data = getattr(WipeScreen, "on_data") + on_data("[color=#00ff00] INFO [/color] mock") self.assertEqual(screen.output, ["[color=#00ff00] INFO [/color] mock"]) # patch assertions @@ -208,10 +209,10 @@ def test_on_print_callback_pop_ouput(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - on_print_callback = getattr(WipeScreen, "on_print_callback") + on_data = getattr(WipeScreen, "on_data") for i in range(19): - on_print_callback(f"[color=#00ff00] INFO [/color] mock test message {i}") + on_data(f"[color=#00ff00] INFO [/color] mock test message {i}") self.assertEqual(len(screen.output), 18) @@ -222,8 +223,8 @@ def test_on_print_callback_pop_ouput(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.wipe_screen.WipeScreen.trigger") - def test_on_print_callback_erased(self, mock_trigger, mock_get_locale): + @patch("src.app.screens.wipe_screen.WipeScreen.done") + def test_on_data_erased(self, mock_done, mock_get_locale): screen = WipeScreen() screen.output = [] screen.on_pre_enter() @@ -232,21 +233,21 @@ def test_on_print_callback_erased(self, mock_trigger, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - on_print_callback = getattr(WipeScreen, "on_print_callback") - on_print_callback("[color=#00ff00] INFO [/color] SPI Flash erased.") + on_data = getattr(WipeScreen, "on_data") + on_data("[color=#00ff00] INFO [/color] SPI Flash erased.") self.assertEqual( screen.output, ["[color=#00ff00] INFO [/color] SPI Flash erased."] ) # patch assertions mock_get_locale.assert_any_call() - mock_trigger.assert_called_once() + mock_done.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - def test_on_trigger_callback(self, mock_get_locale): + def test_on_done(self, mock_get_locale): screen = WipeScreen() screen.output = [] screen.on_pre_enter() @@ -275,8 +276,8 @@ def test_on_trigger_callback(self, mock_get_locale): "[/color]", ] ) - on_trigger_callback = getattr(WipeScreen, "on_trigger_callback") - on_trigger_callback(0) + on_done = getattr(WipeScreen, "on_done") + on_done(0) self.assertEqual(screen.ids[f"{screen.id}_progress"].text, text) self.assertEqual(screen.ids[f"{screen.id}_progress"].text, text) @@ -284,25 +285,6 @@ def test_on_trigger_callback(self, mock_get_locale): # patch assertions mock_get_locale.assert_any_call() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_on_enter(self, mock_redirect_error, mock_get_locale): - screen = WipeScreen() - screen.on_pre_enter() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.on_enter() - - # patch assertions - mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with("Wiper isnt configured") - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/pyproject.toml b/pyproject.toml index 1d2a1118..ff2c8780 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,8 +56,8 @@ clean-mac = "find . -name '.DS_Store' -delete" lint.sequence = [ { cmd = "jsonlint src/i18n/*.json"}, { cmd = "pylint -E --rcfile .pylint/src ./src" }, - { cmd = "pylint -E --rcfile .pylint/tests ./tests"}, - { cmd = "pylint -E --rcfile=.pylint/tests ./e2e"} + { cmd = "pylint --rcfile .pylint/tests ./tests"}, + { cmd = "pylint --rcfile=.pylint/tests ./e2e"} ] build-nix.sequence = [ diff --git a/src/app/screens/base_flash_screen.py b/src/app/screens/base_flash_screen.py index ff2d6363..35047ca5 100644 --- a/src/app/screens/base_flash_screen.py +++ b/src/app/screens/base_flash_screen.py @@ -41,9 +41,9 @@ def __init__(self, wid: str, name: str, **kwargs): self._firmware = None self._baudrate = None self._thread = None - self._trigger = None - self._output = None + self._output = [] self._progress = None + self._done = None self._is_done = False @property @@ -91,16 +91,16 @@ def thread(self, value: Thread): self._thread = value @property - def trigger(self) -> ClockEvent: + def done(self) -> ClockEvent: """Trigger is a `ClockEvent` that should be triggered after download is done""" - self.debug(f"getter::trigger={self._thread}") - return self._trigger + self.debug(f"getter::done={self._done}") + return self._done - @trigger.setter - def trigger(self, value: typing.Callable): + @done.setter + def done(self, value: typing.Callable): """Create a `ClockEvent` given a callback""" - self.debug(f"getter::trigger={self._trigger}") - self._trigger = Clock.create_trigger(value) + self.debug(f"getter::trigger={self._done}") + self._done = Clock.create_trigger(value) @property def output(self) -> typing.List[str]: @@ -113,3 +113,15 @@ def output(self, value: typing.List[str]): """Setter for info""" self.debug(f"setter::output={value}") self._output = value + + @property + def is_done(self) -> bool: + """Getter for is_done""" + self.debug(f"getter::is_done={self._is_done}") + return self._is_done + + @is_done.setter + def is_done(self, value: bool): + """Setter for info""" + self.debug(f"setter::is_done={value}") + self._is_done = value diff --git a/src/app/screens/flash_screen.py b/src/app/screens/flash_screen.py index aa1dec67..93bf3244 100644 --- a/src/app/screens/flash_screen.py +++ b/src/app/screens/flash_screen.py @@ -42,38 +42,42 @@ def __init__(self, **kwargs): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) + @staticmethod + def parse_output(text: str) -> str: + """Parses KTool.print_callback output to make it more readable on GUI""" + text = text.replace( + "\x1b[32m\x1b[1m[INFO]\x1b[0m", "[color=#00ff00]INFO[/color]" + ) + text = text.replace("\x1b[33mISP loaded", "[color=#efcc00]ISP loaded[/color]") + text = text.replace( + "\x1b[33mInitialize K210 SPI Flash", + "[color=#efcc00]Initialize K210 SPI Flash[/color]", + ) + text = text.replace("Flash ID: \x1b[33m", "Flash ID: [color=#efcc00]") + text = text.replace( + "\x1b[0m, unique ID: \x1b[33m", "[/color], unique ID: [color=#efcc00]" + ) + text = text.replace("\x1b[0m, size: \x1b[33m", "[/color], size: ") + text = text.replace("\x1b[0m MB", "[/color] MB") + text = text.replace("\x1b[0m", "") + text = text.replace("\x1b[33m", "") + text = text.replace("\rProgramming", "Programming") + return text + def on_pre_enter(self): self.ids[f"{self.id}_grid"].clear_widgets() - callback_trigger = getattr(self, "trigger") - - def on_print_callback(*args, **kwargs): + def on_data(*args, **kwargs): text = " ".join(str(x) for x in args) self.info(text) - text = text.replace( - "\x1b[32m\x1b[1m[INFO]\x1b[0m", "[color=#00ff00]INFO[/color]" - ) - text = text.replace( - "\x1b[33mISP loaded", "[color=#efcc00]ISP loaded[/color]" - ) - text = text.replace( - "\x1b[33mInitialize K210 SPI Flash", - "[color=#efcc00]Initialize K210 SPI Flash[/color]", - ) - text = text.replace("Flash ID: \x1b[33m", "Flash ID: [color=#efcc00]") - text = text.replace( - "\x1b[0m, unique ID: \x1b[33m", "[/color], unique ID: [color=#efcc00]" - ) - text = text.replace("\x1b[0m, size: \x1b[33m", "[/color], size: ") - text = text.replace("\x1b[0m MB", "[/color] MB") - text = text.replace("\x1b[0m", "") - text = text.replace("\x1b[33m", "") - text = text.replace("\rProgramming", "Programming") + text = FlashScreen.parse_output(text) if "INFO" in text: self.output.append(text) if "Rebooting" in text: - callback_trigger() + self.is_done = True + # pylint: disable=not-callable + self.done() elif "Programming BIN" in text: self.output[-1] = text @@ -87,9 +91,7 @@ def on_print_callback(*args, **kwargs): self.ids[f"{self.id}_info"].text = "\n".join(self.output) - def on_process_callback( - file_type: str, iteration: int, total: int, suffix: str - ): + def on_process(file_type: str, iteration: int, total: int, suffix: str): percent = (iteration / total) * 100 if sys.platform in ("linux", "win32"): @@ -134,7 +136,7 @@ def on_ref_press(*args): else: self.redirect_error(f"Invalid ref: {args[1]}") - def on_trigger_callback(dt): + def on_done(dt): del self.output[4:] self.ids[f"{self.id}_loader"].source = self.done_img self.ids[f"{self.id}_loader"].reload() @@ -164,9 +166,9 @@ def on_trigger_callback(dt): ) self.ids[f"{self.id}_progress"].bind(on_ref_press=on_ref_press) - setattr(FlashScreen, "on_print_callback", on_print_callback) - setattr(FlashScreen, "on_process_callback", on_process_callback) - setattr(FlashScreen, "on_trigger_callback", on_trigger_callback) + setattr(FlashScreen, "on_data", on_data) + setattr(FlashScreen, "on_process", on_process) + setattr(FlashScreen, "on_done", on_done) self.make_subgrid( wid=f"{self.id}_subgrid", rows=2, root_widget=f"{self.id}_grid" @@ -196,30 +198,25 @@ def on_enter(self): """ Event fired when the screen is displayed and the entering animation is complete. """ - if hasattr(self, "flasher"): - self.output = [] - self.trigger = getattr(self.__class__, "on_trigger_callback") - self.flasher.ktool.__class__.print_callback = getattr( - self.__class__, "on_print_callback" - ) - on_process_callback = partial( - self.flasher.flash, - callback=getattr(self.__class__, "on_process_callback"), - ) - self.thread = threading.Thread(name=self.name, target=on_process_callback) + self.done = getattr(FlashScreen, "on_done") + self.flasher.ktool.__class__.print_callback = getattr(FlashScreen, "on_data") + on_process = partial( + self.flasher.flash, callback=getattr(self.__class__, "on_process") + ) + self.thread = threading.Thread(name=self.name, target=on_process) - if sys.platform in ("linux", "win32"): - sizes = [self.SIZE_M, self.SIZE_P] - else: - sizes = [self.SIZE_MM, self.SIZE_MP] - - # if anything wrong happen, show it - def hook(err): - msg = "".join( - traceback.format_exception( - err.exc_type, err.exc_value, err.exc_traceback - ) + if sys.platform in ("linux", "win32"): + sizes = [self.SIZE_M, self.SIZE_P] + else: + sizes = [self.SIZE_MM, self.SIZE_MP] + + # if anything wrong happen, show it + def hook(err): + if not self.is_done: + trace = traceback.format_exception( + err.exc_type, err.exc_value, err.exc_traceback ) + msg = "".join(trace) self.error(msg) back = self.translate("Back") @@ -246,13 +243,11 @@ def hook(err): [f"[size={sizes[1]}]", msg, "[/size]"] ) - # hook what happened - threading.excepthook = hook + # hook what happened + threading.excepthook = hook - # start thread - self.thread.start() - else: - self.redirect_error("Flasher isnt configured") + # start thread + self.thread.start() def update(self, *args, **kwargs): """Update screen with firmware key. Should be called before `on_enter`""" diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index 07e2c89e..0879ae09 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -44,48 +44,51 @@ def __init__(self, **kwargs): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) + @staticmethod + def parse_output(text: str) -> str: + """Parses KTool.print_callback output to make it more readable on GUI""" + text = text.replace( + "\x1b[32m\x1b[1m[INFO]\x1b[0m", "[color=#00ff00]INFO[/color]" + ) + text = text.replace("\x1b[33mISP loaded", "[color=#efcc00]ISP loaded[/color]") + text = text.replace( + "\x1b[33mInitialize K210 SPI Flash", + "[color=#efcc00]Initialize K210 SPI Flash[/color]", + ) + text = text.replace("Flash ID: \x1b[33m", "Flash ID: [color=#efcc00]") + text = text.replace( + "\x1b[0m, unique ID: \x1b[33m", "[/color], unique ID: [color=#efcc00]" + ) + text = text.replace("\x1b[0m, size: \x1b[33m", "[/color], size: ") + text = text.replace("\x1b[0m MB", "[/color] MB") + text = text.replace("\x1b[0m", "") + text = text.replace("\x1b[33m", "") + text = text.replace( + "[INFO] Erasing the whole SPI Flash", + "[color=#00ff00]INFO[/color][color=#efcc00] Erasing the whole SPI Flash [/color]", + ) + + text = text.replace( + "\x1b[31m\x1b[1m[ERROR]\x1b[0m", "[color=#ff0000]ERROR[/color]" + ) + return text + def on_pre_enter(self): self.ids[f"{self.id}_grid"].clear_widgets() - callback_trigger = getattr(self, "trigger") - def on_print_callback(*args, **kwargs): + def on_data(*args, **kwargs): text = " ".join(str(x) for x in args) self.info(text) - - text = text.replace( - "\x1b[32m\x1b[1m[INFO]\x1b[0m", "[color=#00ff00]INFO[/color]" - ) - text = text.replace( - "\x1b[33mISP loaded", "[color=#efcc00]ISP loaded[/color]" - ) - text = text.replace( - "\x1b[33mInitialize K210 SPI Flash", - "[color=#efcc00]Initialize K210 SPI Flash[/color]", - ) - text = text.replace("Flash ID: \x1b[33m", "Flash ID: [color=#efcc00]") - text = text.replace( - "\x1b[0m, unique ID: \x1b[33m", "[/color], unique ID: [color=#efcc00]" - ) - text = text.replace("\x1b[0m, size: \x1b[33m", "[/color], size: ") - text = text.replace("\x1b[0m MB", "[/color] MB") - text = text.replace("\x1b[0m", "") - text = text.replace("\x1b[33m", "") - text = text.replace( - "[INFO] Erasing the whole SPI Flash", - "[color=#00ff00]INFO[/color][color=#efcc00] Erasing the whole SPI Flash [/color]", - ) - - text = text.replace( - "\x1b[31m\x1b[1m[ERROR]\x1b[0m", "[color=#ff0000]ERROR[/color]" - ) - + text = WipeScreen.parse_output(text) self.output.append(text) if len(self.output) > 18: del self.output[:1] if "SPI Flash erased." in text: - callback_trigger() + self.is_done = True + # pylint: disable=not-callable + self.done() self.ids[f"{self.id}_info"].text = "\n".join(self.output) @@ -99,14 +102,15 @@ def on_ref_press(*args): else: self.redirect_error(f"Invalid ref: {args[1]}") - def on_trigger_callback(dt): - self.success = True + def on_done(dt): + self.is_done = True del self.output[4:] self.ids[f"{self.id}_loader"].source = self.done_img self.ids[f"{self.id}_loader"].reload() done = self.translate("DONE") back = self.translate("Back") quit = self.translate("Quit") + if sys.platform in ("linux", "win32"): size = self.SIZE_M else: @@ -128,8 +132,8 @@ def on_trigger_callback(dt): ) self.ids[f"{self.id}_progress"].bind(on_ref_press=on_ref_press) - setattr(WipeScreen, "on_print_callback", on_print_callback) - setattr(WipeScreen, "on_trigger_callback", on_trigger_callback) + setattr(WipeScreen, "on_data", on_data) + setattr(WipeScreen, "on_done", on_done) self.make_subgrid( wid=f"{self.id}_subgrid", rows=3, root_widget=f"{self.id}_grid" @@ -159,33 +163,29 @@ def on_enter(self): """ Event fired when the screen is displayed and the entering animation is complete. """ - self.debug("Staring wipe...") - if self.wiper is not None: - please = self.translate("PLEASE DO NOT UNPLUG YOUR DEVICE") - if sys.platform in ("linux", "win32"): - sizes = [self.SIZE_M, self.SIZE_PP] - else: - sizes = [self.SIZE_MM, self.SIZE_MP] - - self.ids[f"{self.id}_progress"].text = f"[size={sizes[0]}sp][b]{please}[/b]" - self.output = [] - self.progress = "" - self.is_done = False - self.trigger = getattr(self.__class__, "on_trigger_callback") - self.wiper.ktool.__class__.print_callback = getattr( - self.__class__, "on_print_callback" - ) - on_process_callback = partial(self.wiper.wipe, device=self.device) - self.thread = threading.Thread(name=self.name, target=on_process_callback) - - # if anything wrong happen, show it - def hook(err): - msg = "".join( - traceback.format_exception( - err.exc_type, err.exc_value, err.exc_traceback - ) + self.done = getattr(WipeScreen, "on_done") + self.wiper.ktool.__class__.print_callback = getattr(WipeScreen, "on_data") + on_process = partial(self.wiper.wipe, device=self.device) + self.thread = threading.Thread(name=self.name, target=on_process) + + please = self.translate("PLEASE DO NOT UNPLUG YOUR DEVICE") + if sys.platform in ("linux", "win32"): + sizes = [self.SIZE_M, self.SIZE_PP] + else: + sizes = [self.SIZE_MM, self.SIZE_MP] + + self.ids[f"{self.id}_progress"].text = f"[size={sizes[0]}sp][b]{please}[/b]" + self.progress = "" + + # if anything wrong happen, show it + def hook(err): + if not self.is_done: + trace = traceback.format_exception( + err.exc_type, err.exc_value, err.exc_traceback ) + msg = "".join(trace) self.error(msg) + done = self.translate("DONE") back = self.translate("Back") quit = self.translate("Quit") @@ -216,11 +216,9 @@ def hook(err): ] ) - # hook what happened - threading.excepthook = hook - self.thread.start() - else: - self.redirect_error("Wiper isnt configured") + # hook what happened + threading.excepthook = hook + self.thread.start() def update(self, *args, **kwargs): """Update screen with firmware key. Should be called before `on_enter`""" From db2f9cf6da2fec68ad9cfdc0b12da58b4b8df72d Mon Sep 17 00:00:00 2001 From: qlrd Date: Mon, 2 Sep 2024 13:02:55 -0300 Subject: [PATCH 07/61] fixed issues on config initializer and greentins screen --- e2e/test_019_config_krux_installer.py | 4 ++-- src/app/config_krux_installer.py | 4 ++-- src/app/screens/greetings_screen.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/e2e/test_019_config_krux_installer.py b/e2e/test_019_config_krux_installer.py index 544e5c9c..70943eda 100644 --- a/e2e/test_019_config_krux_installer.py +++ b/e2e/test_019_config_krux_installer.py @@ -455,7 +455,7 @@ def test_on_config_change_linux(self, mock_partial): MagicMock(name="WarningBetaScreen"), MagicMock(name="VerifyStableZipScreen"), MagicMock(name="UnzipStableScreen"), - MagicMock(name="CheckPermissionsScreen"), + MagicMock(name="AskPermissionDialoutScreen"), ] # Do tests @@ -470,7 +470,7 @@ def test_on_config_change_linux(self, mock_partial): call("WarningBetaScreen"), call("VerifyStableZipScreen"), call("UnzipStableScreen"), - call("CheckPermissionsScreen"), + call("AskPermissionDialoutScreen"), ] calls_partial = [ diff --git a/src/app/config_krux_installer.py b/src/app/config_krux_installer.py index 3565517d..40b19d4f 100644 --- a/src/app/config_krux_installer.py +++ b/src/app/config_krux_installer.py @@ -295,10 +295,10 @@ def on_config_change(self, config, section, key, value): ] if sys.platform == "linux": - check = self.screen_manager.get_screen("CheckPermissionsScreen") + ask = self.screen_manager.get_screen("AskPermissionDialoutScreen") partials.append( partial( - check.update, + ask.update, name="ConfigKruxInstaller", key="locale", value=value, diff --git a/src/app/screens/greetings_screen.py b/src/app/screens/greetings_screen.py index 9bc3740a..18e18d6c 100644 --- a/src/app/screens/greetings_screen.py +++ b/src/app/screens/greetings_screen.py @@ -166,13 +166,13 @@ def check_permissions_for_dialout_group(self): partial( ask_screen.update, name=self.name, key="distro", value=_distro ), - partial(ask_screen, name=self.name, key="screen"), + partial(ask_screen.update, name=self.name, key="screen"), ] for fn in fns: Clock.schedule_once(fn, 0) - self.set_screen(name="AskPermissionsDialoutScreen", direction="left") + self.set_screen(name="AskPermissionDialoutScreen", direction="left") def check_internet_connection(self): """ From d4cf818c391a4c4f648478b8a60a0f4991a11cd7 Mon Sep 17 00:00:00 2001 From: qlrd Date: Mon, 2 Sep 2024 13:58:28 -0300 Subject: [PATCH 08/61] updated pyinstaller to 6.10 re-structured build process on CI --- .ci/patch-pyinstaller-kivy-hook.sh | 14 ++++++++--- .github/workflows/build.yml | 23 +++-------------- poetry.lock | 40 +++++++++++++++--------------- pyproject.toml | 21 ++++++++++------ 4 files changed, 48 insertions(+), 50 deletions(-) diff --git a/.ci/patch-pyinstaller-kivy-hook.sh b/.ci/patch-pyinstaller-kivy-hook.sh index 78ce7de3..de343a7c 100755 --- a/.ci/patch-pyinstaller-kivy-hook.sh +++ b/.ci/patch-pyinstaller-kivy-hook.sh @@ -14,15 +14,23 @@ PYHOOK_PATH="site-packages/kivy/tools/packaging/pyinstaller_hooks/__init__.py" FULL_PATH=$PYENV_PATH/lib/python$PYENV_VERSION/$PYHOOK_PATH echo "env FULL_PATH=$FULL_PATH" -wget $PATCHURL -O pyinstaller_hook_patch.py -echo "RUN wget $PATCHURL -O pyinstaller_hook_patch.py" +if which curl >/dev/null ; then + echo "RUN curl --output pyinstaller_hook_patch.py $PATCHURL" + curl --output pyinstaller_hook_patch.py $PATCHURL +elif which wget >/dev/null ; then + echo "RUN wget $PATCHURL -O pyinstaller_hook_patch.py" + wget $PATCHURL -O pyinstaller_hook_patch.py +else + echo "Cannot download, neither wget nor curl is available." +fi + echo "RUN diff -u $FULL_PATH pyinstaller_hook_patch.py > pyinstaller_hook.patch" diff -u $FULL_PATH pyinstaller_hook_patch.py > pyinstaller_hook.patch # patch it echo "RUN patch $FULL_PATH < pyinstaller_hook.patch" -patch $FULL_PATH < pyinstaller_hook.patch +patch --verbose $FULL_PATH < pyinstaller_hook.patch # remove remaining files rm pyinstaller_hook_patch.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1ef7ed70..9e1dfdf4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,41 +78,26 @@ jobs: - name: Install project and its dependencies run: poetry install - - - name: Patch pyinstaller_hook for kivy in Unix - if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }} - run: poetry run poe patch-nix - - - name: Patch pyinstaller_hook for kivy in Windows - if: ${{ runner.os == 'Windows' }} - run: poetry run poe patch-win - + - name: Build dist (Linux) if: ${{ runner.os == 'Linux' }} uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a with: run: | poetry add pytest-xvfb - poetry run python .ci/create-spec.py - poetry run python -m PyInstaller krux-installer.spec + poetry run poe build-linux - name: Build dist (MacOS) if: ${{ runner.os == 'macOS' }} env: DYLD_LIBRARY_PATH: ${{ steps.setup-macos.outputs.dyld-path }} - run: | - poetry run poe clean-mac - poetry run python .ci/create-spec.py - poetry run python -m PyInstaller krux-installer.spec + run: poetry run poe build-macos - name: Build dist (Windows) if: ${{ runner.os == 'Windows' }} env: KIVY_GL_BACKEND: 'angle_sdl2' - run: | - poetry run python .ci/create-spec.py - .\.ci\edit-spec.ps1 - poetry run python -m PyInstaller krux-installer.spec + run: poetry run poe build-win - name: Build release deb (Linux) if: ${{ runner.os == 'Linux' }} diff --git a/poetry.lock b/poetry.lock index dc37f835..dacd3412 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1224,23 +1224,23 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyinstaller" -version = "6.9.0" +version = "6.10.0" description = "PyInstaller bundles a Python application and all its dependencies into a single package." optional = false -python-versions = "<3.13,>=3.8" +python-versions = "<3.14,>=3.8" files = [ - {file = "pyinstaller-6.9.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:5ced2e83acf222b936ea94abc5a5cc96588705654b39138af8fb321d9cf2b954"}, - {file = "pyinstaller-6.9.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:f18a3d551834ef8fb7830d48d4cc1527004d0e6b51ded7181e78374ad6111846"}, - {file = "pyinstaller-6.9.0-py3-none-manylinux2014_i686.whl", hash = "sha256:f2fc568de3d6d2a176716a3fc9f20da06d351e8bea5ddd10ecb5659fce3a05b0"}, - {file = "pyinstaller-6.9.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:a0f378f64ad0655d11ade9fde7877e7573fd3d5066231608ce7dfa9040faecdd"}, - {file = "pyinstaller-6.9.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:7bf0c13c5a8560c89540746ae742f4f4b82290e95a6b478374d9f34959fe25d6"}, - {file = "pyinstaller-6.9.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:da994aba14c5686db88796684de265a8665733b4df09b939f7ebdf097d18df72"}, - {file = "pyinstaller-6.9.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:4e3e50743c091a06e6d01c59bdd6d03967b453ee5384a9e790759be4129db4a4"}, - {file = "pyinstaller-6.9.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:b041be2fe78da47a269604d62c940d68c62f9a3913bdf64af4123f7689d47099"}, - {file = "pyinstaller-6.9.0-py3-none-win32.whl", hash = "sha256:2bf4de17a1c63c0b797b38e13bfb4d03b5ee7c0a68e28b915a7eaacf6b76087f"}, - {file = "pyinstaller-6.9.0-py3-none-win_amd64.whl", hash = "sha256:43709c70b1da8441a730327a8ed362bfcfdc3d42c1bf89f3e2b0a163cc4e7d33"}, - {file = "pyinstaller-6.9.0-py3-none-win_arm64.whl", hash = "sha256:f15c1ef11ed5ceb32447dfbdab687017d6adbef7fc32aa359d584369bfe56eda"}, - {file = "pyinstaller-6.9.0.tar.gz", hash = "sha256:f4a75c552facc2e2a370f1e422b971b5e5cdb4058ff38cea0235aa21fc0b378f"}, + {file = "pyinstaller-6.10.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:d60fb22859e11483af735aec115fdde09467cdbb29edd9844839f2c920b748c0"}, + {file = "pyinstaller-6.10.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:46d75359668993ddd98630a3669dc5249f3c446e35239b43bc7f4155bc574748"}, + {file = "pyinstaller-6.10.0-py3-none-manylinux2014_i686.whl", hash = "sha256:3398a98fa17d47ccb31f8779ecbdacec025f7adb2f22757a54b706ac8b4fe906"}, + {file = "pyinstaller-6.10.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e9989f354ae4ed8a3bec7bdb37ae0d170751d6520e500f049c7cd0632d31d5c3"}, + {file = "pyinstaller-6.10.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:b7c90c91921b3749083115b28f30f40abf2bb481ceff196d2b2ce0eaa2b3d429"}, + {file = "pyinstaller-6.10.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6cf876d7d93b8b4f28d1ad57fa24645cf43119c79e985dd5e5f7a801245e6f53"}, + {file = "pyinstaller-6.10.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:db05e3f2f10f9f78c56f1fb163d9cb453433429fe4281218ebaf1ebfd39ba942"}, + {file = "pyinstaller-6.10.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:28eca3817f176fdc19747e1afcf434f13bb9f17a644f611be2c5a61b1f498ed7"}, + {file = "pyinstaller-6.10.0-py3-none-win32.whl", hash = "sha256:703e041718987e46ba0568a2c71ecf2459fddef57cf9edf3efeed4a53e3dae3f"}, + {file = "pyinstaller-6.10.0-py3-none-win_amd64.whl", hash = "sha256:95b55966e563e8b8f31a43882aea10169e9a11fdf38e626d86a2907b640c0701"}, + {file = "pyinstaller-6.10.0-py3-none-win_arm64.whl", hash = "sha256:308e0a8670c9c9ac0cebbf1bbb492e71b6675606f2ec78bc4adfc830d209e087"}, + {file = "pyinstaller-6.10.0.tar.gz", hash = "sha256:143840f8056ff7b910bf8f16f6cd92cc10a6c2680bb76d0a25d558d543d21270"}, ] [package.dependencies] @@ -1249,7 +1249,7 @@ importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""} macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""} packaging = ">=22.0" pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""} -pyinstaller-hooks-contrib = ">=2024.7" +pyinstaller-hooks-contrib = ">=2024.8" pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""} setuptools = ">=42.0.0" @@ -1259,13 +1259,13 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"] [[package]] name = "pyinstaller-hooks-contrib" -version = "2024.7" +version = "2024.8" description = "Community maintained hooks for PyInstaller" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pyinstaller_hooks_contrib-2024.7-py2.py3-none-any.whl", hash = "sha256:8bf0775771fbaf96bcd2f4dfd6f7ae6c1dd1b1efe254c7e50477b3c08e7841d8"}, - {file = "pyinstaller_hooks_contrib-2024.7.tar.gz", hash = "sha256:fd5f37dcf99bece184e40642af88be16a9b89613ecb958a8bd1136634fc9fac5"}, + {file = "pyinstaller_hooks_contrib-2024.8-py3-none-any.whl", hash = "sha256:0057fe9a5c398d3f580e73e58793a1d4a8315ca91c3df01efea1c14ed557825a"}, + {file = "pyinstaller_hooks_contrib-2024.8.tar.gz", hash = "sha256:29b68d878ab739e967055b56a93eb9b58e529d5b054fbab7a2f2bacf80cef3e2"}, ] [package.dependencies] @@ -1753,4 +1753,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.13" -content-hash = "abb2c241218a5b801639d4f91faef9b04ffae0c1d5e53dbf4d41d328724ac170" +content-hash = "4af81669663fb0a58b3caf2743245a17072c9f7916439270ae9311cc3e34f30d" diff --git a/pyproject.toml b/pyproject.toml index ff2c8780..9f562c1b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ easy-i18n = "^1.2.0" pysudoer = {git = "https://github.com/qlrd/pysudoer.git"} distro = "^1.9.0" pillow = "^10.4.0" +pyinstaller = "^6.10.0" [tool.poetry.group.dev.dependencies] black = "^24.8.0" @@ -48,24 +49,28 @@ coverage-unit = "pytest --cache-clear --cov=src/utils/constants --cov=src/utils/ coverage-e2e = "pytest --cov-append --cov=src/app --cov-branch --cov-report xml ./e2e" coverage = ["coverage-unit", "coverage-e2e"] -patch-nix = "sh .ci/patch-pyinstaller-kivy-hook.sh" -patch-win = "powershell.exe -File .ci/patch-pyinstaller-kivy-hook.ps1" - -clean-mac = "find . -name '.DS_Store' -delete" - lint.sequence = [ { cmd = "jsonlint src/i18n/*.json"}, - { cmd = "pylint -E --rcfile .pylint/src ./src" }, - { cmd = "pylint --rcfile .pylint/tests ./tests"}, + { cmd = "pylint -E --rcfile=.pylint/src ./src" }, + { cmd = "pylint --rcfile=.pylint/tests ./tests"}, { cmd = "pylint --rcfile=.pylint/tests ./e2e"} ] -build-nix.sequence = [ +build-linux.sequence = [ + { cmd = "sh .ci/patch-pyinstaller-kivy-hook.sh" }, + { cmd = "python .ci/create-spec.py"}, + { cmd = "python -m PyInstaller krux-installer.spec"} +] + +build-macos.sequence = [ + { cmd = "find . -name '.DS_Store' -delete" }, + { cmd = "sh .ci/patch-pyinstaller-kivy-hook.sh" }, { cmd = "python .ci/create-spec.py"}, { cmd = "python -m PyInstaller krux-installer.spec"} ] build-win.sequence = [ + { cmd = "powershell.exe -File .ci/patch-pyinstaller-kivy-hook.ps1" }, { cmd = "python .ci/create-spec.py"}, { interpreter = ["powershell", "pwsh"], shell = "& .ci/edit-spec.ps1"}, { cmd = "python -m PyInstaller krux-installer.spec"} From 569d83ec857bdbdf98e7676c5af572762f5efec2 Mon Sep 17 00:00:00 2001 From: qlrd Date: Mon, 2 Sep 2024 16:52:08 -0300 Subject: [PATCH 09/61] added build job only to main branch --- .github/workflows/build.yml | 7 +++---- .github/workflows/tests.yml | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9e1dfdf4..6c8bb2f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,10 +2,9 @@ name: Build on: workflow_run: - workflows: - - Tests - types: - - completed + workflows: Tests + types: completed + branches: main jobs: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d83e42b4..72ddac2b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,7 +9,6 @@ on: pull_request: branches: - main - - develop jobs: From 6453b4c79608ad3e405fd61f9284d299462b51b4 Mon Sep 17 00:00:00 2001 From: qlrd Date: Mon, 2 Sep 2024 23:20:57 -0300 Subject: [PATCH 10/61] fixed transition of ask_permission_dialout_screen and flash back and quit buttons --- e2e/test_001_greetings_screen.py | 33 +++++++---- e2e/test_002_ask_permission_dialout_screen.py | 5 +- .../screens/ask_permission_dialout_screen.py | 48 ++++++++-------- src/app/screens/flash_screen.py | 2 +- src/app/screens/greetings_screen.py | 55 +++++++------------ src/app/screens/wipe_screen.py | 1 + 6 files changed, 74 insertions(+), 70 deletions(-) diff --git a/e2e/test_001_greetings_screen.py b/e2e/test_001_greetings_screen.py index 04f1e2e1..cf28c136 100644 --- a/e2e/test_001_greetings_screen.py +++ b/e2e/test_001_greetings_screen.py @@ -16,14 +16,7 @@ def teardown_class(cls): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.greetings_screen.partial") - @patch("src.app.screens.greetings_screen.Clock.schedule_once") - def test_init( - self, - mock_schedule_once, - mock_partial, - mock_get_locale, - ): + def test_init(self, mock_get_locale): screen = GreetingsScreen() self.render(screen) @@ -40,11 +33,27 @@ def test_init( self.assertEqual(screen.name, "GreetingsScreen") self.assertEqual(screen.id, "greetings_screen") self.assertEqual(image.source, asset) + mock_get_locale.assert_called() - # patch assertions - mock_get_locale.assert_called_once() - mock_partial.assert_called() - mock_schedule_once.assert_called() + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.greetings_screen.partial") + @patch("src.app.screens.greetings_screen.Clock.schedule_once") + def test_on_enter(self, mock_schedule_once, mock_partial, mock_get_locale): + screen = GreetingsScreen() + self.render(screen) + screen.on_enter() + + # get your Window instance safely + EventLoop.ensure_window() + + mock_get_locale.assert_called() + mock_partial.assert_called_once_with( + screen.update, name=screen.name, key="canvas" + ) + mock_schedule_once.assert_called_once_with(mock_partial(), 0) @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( diff --git a/e2e/test_002_ask_permission_dialout_screen.py b/e2e/test_002_ask_permission_dialout_screen.py index 32486172..87f654c6 100644 --- a/e2e/test_002_ask_permission_dialout_screen.py +++ b/e2e/test_002_ask_permission_dialout_screen.py @@ -211,9 +211,12 @@ def test_press_allow(self, mock_exec, mock_get_locale): action("Allow") # patch assertions + on_permission_created = getattr( + AskPermissionDialoutScreen, "on_permission_created" + ) mock_get_locale.assert_called_once() mock_exec.assert_called_once_with( cmd=["/usr/bin/usermod", "-a", "-G", "mockedgroup", "mockeduser"], env={}, - callback=screen.on_permission_created, + callback=on_permission_created, ) diff --git a/src/app/screens/ask_permission_dialout_screen.py b/src/app/screens/ask_permission_dialout_screen.py index 40014126..ed366877 100644 --- a/src/app/screens/ask_permission_dialout_screen.py +++ b/src/app/screens/ask_permission_dialout_screen.py @@ -53,6 +53,26 @@ def __init__(self, **kwargs): self._bin = "/usr/bin/usermod" self._bin_args = ["-a", "-G"] + def on_permission_created(output: str): + logout_msg = self.translate("You may need to logout (or even reboot)") + backin_msg = self.translate("and back in for the new group to take effect") + not_worry_msg = self.translate( + "Do not worry, this message won't appear again" + ) + + self.ids[f"{self.id}_label"].text = "\n".join( + [ + f"[size={self.SIZE_M}sp]{logout_msg}", + f"{backin_msg}.", + "", + f"{not_worry_msg}.[/size]", + ] + ) + + setattr( + AskPermissionDialoutScreen, "on_permission_created", on_permission_created + ) + def _on_ref_press(*args): if args[1] == "Allow": # If user isnt in the dialout group, @@ -68,9 +88,10 @@ def _on_ref_press(*args): try: self.debug(f"cmd={cmd}") sudoer = SudoerLinux(name=f"Add {self.user} to {self.group}") - sudoer.exec(cmd=cmd, env={}, callback=self.on_permission_created) + sudoer.exec(cmd=cmd, env={}, callback=on_permission_created) except Exception as err: - self.redirect_error(msg=str(err.__traceback__)) + self.error(str(err)) + self.redirect_exception(exception=err) if args[1] == "Deny": App.get_running_app().stop() @@ -167,9 +188,11 @@ def update(self, *args, **kwargs): f"[size={self.SIZE_G}sp][color=#efcc00]{warn_msg}[/color][/size]", "\n", f'[size={self.SIZE_MP}sp]{first_msg} "{self.distro}"', + "\n", f"{access_msg}.", + "\n", proceed_msg, - f"{exec_msg}:", + "\n" f"{exec_msg}:", "\n", "[color=#00ff00]", f"{self._bin} {" ".join(self._bin_args or [])} {self.group} {self.user}", @@ -187,22 +210,3 @@ def update(self, *args, **kwargs): else: self.redirect_error(msg=f"Invalid key: '{key}'") - - def on_permission_created(self): - """ - When user is added to dialout group - ask for user to reboot to apply the changes - and the ability to flash take place - """ - logout_msg = self.translate("You may need to logout (or even reboot)") - backin_msg = self.translate("and back in for the new group to take effect") - not_worry_msg = self.translate("Do not worry, this message won't appear again") - - self.ids[f"{self.id}_label"].text = "\n".join( - [ - f"[size={self.SIZE_M}sp]{logout_msg}", - f"{backin_msg}.", - "", - f"{not_worry_msg}.[/size]", - ] - ) diff --git a/src/app/screens/flash_screen.py b/src/app/screens/flash_screen.py index 93bf3244..1d0319bd 100644 --- a/src/app/screens/flash_screen.py +++ b/src/app/screens/flash_screen.py @@ -164,7 +164,6 @@ def on_done(dt): "[/color]", ] ) - self.ids[f"{self.id}_progress"].bind(on_ref_press=on_ref_press) setattr(FlashScreen, "on_data", on_data) setattr(FlashScreen, "on_process", on_process) @@ -186,6 +185,7 @@ def on_done(dt): root_widget=f"{self.id}_subgrid", halign="center", ) + self.ids[f"{self.id}_progress"].bind(on_ref_press=on_ref_press) self.make_label( wid=f"{self.id}_info", diff --git a/src/app/screens/greetings_screen.py b/src/app/screens/greetings_screen.py index 18e18d6c..ed834b78 100644 --- a/src/app/screens/greetings_screen.py +++ b/src/app/screens/greetings_screen.py @@ -50,9 +50,6 @@ def __init__(self, **kwargs): wid=f"{self.id}_logo", root_widget=f"{self.id}_grid", source=self.logo_img ) - fn = partial(self.update, name="KruxInstallerApp", key="canvas") - Clock.schedule_once(fn, 0) - def on_enter(self): """ When application start, after greeting user with the krux logo, it will need to check if @@ -60,16 +57,8 @@ def on_enter(self): redirect to CheckPermissionsScreen and then to MainScreen. Win32 and Mac will be redirect to MainScreen. """ - # screen = self.screen_manager.get_screen("GreetingsScreen") - # print(screen) - - fns = [ - partial(self.update, name=self.name, key="check-permission-screen"), - partial(self.update, name=self.name, key="check-internet-connection"), - ] - - for fn in fns: - Clock.schedule_once(fn, 2.1) + fn = partial(self.update, name=self.name, key="canvas") + Clock.schedule_once(fn, 0) def update(self, *args, **kwargs): name = kwargs.get("name") @@ -94,11 +83,11 @@ def update(self, *args, **kwargs): Color(0, 0, 0, 1) Rectangle(size=(Window.width, Window.height)) + fn = partial(self.update, name=self.name, key="check-permission-screen") + Clock.schedule_once(fn, 2.1) + elif key == "check-permission-screen": - if sys.platform == "linux": - self.check_permissions_for_dialout_group() - else: - self.warning(f"Skipping permissions check for {sys.platform}") + self.check_permissions_for_dialout_group() elif key == "check-internet-connection": self.check_internet_connection() @@ -137,42 +126,40 @@ def check_permissions_for_dialout_group(self): self.redirect_error(msg=f"{distro.name(pretty=True)} not supported") return - self.debug(f"Checking {_group} permissions for {_user}") - # loop throug all linux groups and check # if the user is registered in the "dialout" group - for _group in grp.getgrall(): - if _group == _group.gr_name: - self.debug(f"Found {_group.gr_name}") - for _grpuser in _group[3]: + for _grp in grp.getgrall(): + if _group == _grp.gr_name: + self.debug(f"Found {_grp.gr_name}") + for _grpuser in _grp[3]: + self.debug(_grpuser) if _grpuser == _user: self.debug(f"'{_user}' already in group '{_group}'") _in_dialout = True - self.debug(f"user {_user} in dialout group={_in_dialout}") - # if user is not in dialout group, warn user # and then redirect to a screen that will # proceed with the proper operation if not _in_dialout: - ask_screen = self.manager.get_screen("AskPermissionDialoutScreen") + ask = self.manager.get_screen("AskPermissionDialoutScreen") _distro = distro.name(pretty=True) fns = [ - partial(ask_screen.update, name=self.name, key="user", value=_user), - partial( - ask_screen.update, name=self.name, key="group", value=_group - ), - partial( - ask_screen.update, name=self.name, key="distro", value=_distro - ), - partial(ask_screen.update, name=self.name, key="screen"), + partial(ask.update, name=self.name, key="user", value=_user), + partial(ask.update, name=self.name, key="group", value=_group), + partial(ask.update, name=self.name, key="distro", value=_distro), + partial(ask.update, name=self.name, key="screen"), ] for fn in fns: Clock.schedule_once(fn, 0) self.set_screen(name="AskPermissionDialoutScreen", direction="left") + else: + fn = partial( + self.update, name=self.name, key="check-internet-connection" + ) + Clock.schedule_once(fn, 0) def check_internet_connection(self): """ diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index 0879ae09..73bbea8f 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -151,6 +151,7 @@ def on_done(dt): root_widget=f"{self.id}_subgrid", halign="center", ) + self.ids[f"{self.id}_progress"].bind(on_ref_press=on_ref_press) self.make_label( wid=f"{self.id}_info", From cd036ebe86d917c788d62cac281f0f8f328a83a1 Mon Sep 17 00:00:00 2001 From: qlrd Date: Tue, 3 Sep 2024 10:25:24 -0300 Subject: [PATCH 11/61] trying to fix checking_permissions on later calls in tests --- e2e/test_001_greetings_screen.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/e2e/test_001_greetings_screen.py b/e2e/test_001_greetings_screen.py index cf28c136..33d6d750 100644 --- a/e2e/test_001_greetings_screen.py +++ b/e2e/test_001_greetings_screen.py @@ -139,7 +139,16 @@ def test_update_locale(self, mock_get_locale): ) @patch("src.app.screens.greetings_screen.Color") @patch("src.app.screens.greetings_screen.Rectangle") - def test_update_canvas(self, mock_rectangle, mock_color, mock_get_locale): + @patch("src.app.screens.greetings_screen.partial") + @patch("src.app.screens.greetings_screen.Clock.schedule_once") + def test_update_canvas( + self, + mock_schedule_once, + mock_partial, + mock_rectangle, + mock_color, + mock_get_locale + ): screen = GreetingsScreen() self.render(screen) @@ -153,3 +162,5 @@ def test_update_canvas(self, mock_rectangle, mock_color, mock_get_locale): mock_get_locale.assert_called_once() mock_color.assert_called() mock_rectangle.assert_called() + mock_partial.assert_called() + mock_schedule_once.assert_called() From 45b8bf4610ee260acb1b23de9a9636f8ff085e3c Mon Sep 17 00:00:00 2001 From: qlrd Date: Tue, 3 Sep 2024 10:30:44 -0300 Subject: [PATCH 12/61] trying to fix checking_permissions on later calls in tests II --- e2e/test_001_greetings_screen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/test_001_greetings_screen.py b/e2e/test_001_greetings_screen.py index 33d6d750..3d4cf227 100644 --- a/e2e/test_001_greetings_screen.py +++ b/e2e/test_001_greetings_screen.py @@ -147,7 +147,7 @@ def test_update_canvas( mock_partial, mock_rectangle, mock_color, - mock_get_locale + mock_get_locale, ): screen = GreetingsScreen() self.render(screen) From bb6114afac28e94242b7be96139ff9ac759edf21 Mon Sep 17 00:00:00 2001 From: qlrd Date: Tue, 3 Sep 2024 22:51:24 -0300 Subject: [PATCH 13/61] linted many codes after pylint update refactored part of main_screen due to linting refactored many tests after linting --- .pylint/src | 8 +- e2e/test_004_select_device_screen.py | 119 ++-- e2e/test_017_verify_stable_zip_screen.py | 82 +-- src/app/screens/__init__.py | 1 - src/app/screens/about_screen.py | 3 +- .../screens/ask_permission_dialout_screen.py | 92 +-- src/app/screens/base_download_screen.py | 6 +- src/app/screens/base_flash_screen.py | 4 - src/app/screens/download_beta_screen.py | 139 +++-- .../download_selfcustody_pem_screen.py | 9 +- src/app/screens/download_stable_zip_screen.py | 152 ++--- .../download_stable_zip_sha256_screen.py | 5 +- .../screens/download_stable_zip_sig_screen.py | 5 +- src/app/screens/error_screen.py | 12 +- src/app/screens/flash_screen.py | 69 ++- src/app/screens/greetings_screen.py | 22 +- src/app/screens/main_screen.py | 560 ++++++++++-------- src/app/screens/select_device_screen.py | 6 +- src/app/screens/select_old_version_screen.py | 7 +- src/app/screens/select_version_screen.py | 5 +- src/app/screens/unzip_stable_screen.py | 12 +- src/app/screens/verify_stable_zip_screen.py | 81 +-- .../warning_already_downloaded_screen.py | 7 +- src/app/screens/warning_beta_screen.py | 71 +-- src/app/screens/warning_wipe_screen.py | 15 +- src/app/screens/wipe_screen.py | 17 +- 26 files changed, 772 insertions(+), 737 deletions(-) diff --git a/.pylint/src b/.pylint/src index 4a745a1b..3c1301fa 100644 --- a/.pylint/src +++ b/.pylint/src @@ -194,7 +194,7 @@ good-names=i, # Good variable names regexes, separated by a comma. If names match any regex, # they will always be accepted -good-names-rgxs= +good-names-rgxs=SIZE\_[A-Z]+ # Include a hint for the correct naming format with invalid-name. include-naming-hint=no @@ -294,13 +294,13 @@ max-attributes=20 max-bool-expr=5 # Maximum number of branch for function / method body. -max-branches=12 +max-branches=25 # Maximum number of locals for function / method body. -max-locals=16 +max-locals=20 # Maximum number of parents for a class (see R0901). -max-parents=8 +max-parents=10 # Maximum number of public methods for a class (see R0904). max-public-methods=25 diff --git a/e2e/test_004_select_device_screen.py b/e2e/test_004_select_device_screen.py index c6aa608b..b32c6704 100644 --- a/e2e/test_004_select_device_screen.py +++ b/e2e/test_004_select_device_screen.py @@ -11,11 +11,10 @@ def teardown_class(cls): EventLoop.exit() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.main_screen.App.get_running_app") - def test_render_main_screen(self, mock_get_running_app): - mock_get_running_app.config = MagicMock() - mock_get_running_app.config.get = MagicMock(return_value="en-US") - + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_render_main_screen(self, mock_get_locale): screen = SelectDeviceScreen() self.render(screen) @@ -27,14 +26,13 @@ def test_render_main_screen(self, mock_get_running_app): self.assertEqual(screen.name, "SelectDeviceScreen") self.assertEqual(screen.id, "select_device_screen") - mock_get_running_app.assert_called_once() + mock_get_locale.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.main_screen.App.get_running_app") - def test_render_grid_layout(self, mock_get_running_app): - mock_get_running_app.config = MagicMock() - mock_get_running_app.config.get = MagicMock(return_value="en-US") - + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_render_grid_layout(self, mock_get_locale): screen = SelectDeviceScreen() self.render(screen) @@ -44,14 +42,13 @@ def test_render_grid_layout(self, mock_get_running_app): grid = window.children[0].children[0] self.assertEqual(grid.id, "select_device_screen_grid") - mock_get_running_app.assert_called_once() + mock_get_locale.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.main_screen.App.get_running_app") - def test_render_buttons(self, mock_get_running_app): - mock_get_running_app.config = MagicMock() - mock_get_running_app.config.get = MagicMock(return_value="en-US") - + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_render_buttons(self, mock_get_locale): screen = SelectDeviceScreen() self.render(screen) @@ -69,15 +66,14 @@ def test_render_buttons(self, mock_get_running_app): self.assertEqual(buttons[2].id, "select_device_yahboom") self.assertEqual(buttons[1].id, "select_device_cube") self.assertEqual(buttons[0].id, "select_device_wonder_mv") - mock_get_running_app.assert_called_once() + mock_get_locale.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.main_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update(self, mock_redirect_error, mock_get_running_app): - mock_get_running_app.config = MagicMock() - mock_get_running_app.config.get = MagicMock(return_value="en-US") - + def test_fail_update(self, mock_redirect_error, mock_get_locale): screen = SelectDeviceScreen() self.render(screen) @@ -85,18 +81,15 @@ def test_fail_update(self, mock_redirect_error, mock_get_running_app): EventLoop.ensure_window() screen.update(name=screen.name, key="mock", value="mock") - mock_get_running_app.assert_called_once() + mock_get_locale.assert_called_once() mock_redirect_error.assert_called_once_with("Invalid key: mock") @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.main_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_background") - def test_on_press_with_latest_version( - self, mock_set_background, mock_get_running_app - ): - mock_get_running_app.config = MagicMock() - mock_get_running_app.config.get = MagicMock(return_value="en-US") - + def test_on_press_with_latest_version(self, mock_set_background, mock_get_locale): screen = SelectDeviceScreen() self.render(screen) screen.update(name=screen.name, key="version", value="v24.07.0") @@ -121,17 +114,14 @@ def test_on_press_with_latest_version( calls.append(call(wid=button.id, rgba=(0.25, 0.25, 0.25, 1))) mock_set_background.assert_has_calls(calls) - mock_get_running_app.assert_called_once() + mock_get_locale.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.main_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_background") - def test_on_press_with_older_version( - self, mock_set_background, mock_get_running_app - ): - mock_get_running_app.config = MagicMock() - mock_get_running_app.config.get = MagicMock(return_value="en-US") - + def test_on_press_with_older_version(self, mock_set_background, mock_get_locale): screen = SelectDeviceScreen() self.render(screen) screen.update(name=screen.name, key="version", value="v24.03.0") @@ -155,17 +145,14 @@ def test_on_press_with_older_version( calls.append(call(wid=button.id, rgba=(0.25, 0.25, 0.25, 1))) mock_set_background.assert_has_calls(calls) - mock_get_running_app.assert_called_once() + mock_get_locale.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.main_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_background") - def test_on_press_with_beta_version( - self, mock_set_background, mock_get_running_app - ): - mock_get_running_app.config = MagicMock() - mock_get_running_app.config.get = MagicMock(return_value="en-US") - + def test_on_press_with_beta_version(self, mock_set_background, mock_get_locale): screen = SelectDeviceScreen() self.render(screen) screen.update(name=screen.name, key="version", value="odudex/krux_binaries") @@ -191,21 +178,19 @@ def test_on_press_with_beta_version( calls.append(call(wid=button.id, rgba=(0.25, 0.25, 0.25, 1))) mock_set_background.assert_has_calls(calls) - mock_get_running_app.assert_called_once() + mock_get_locale.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.main_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_background") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.manager") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_screen") def test_on_release_with_latest_version( - self, mock_set_screen, mock_manager, mock_set_background, mock_get_running_app + self, mock_set_screen, mock_manager, mock_set_background, mock_get_locale ): mock_manager.get_screen = MagicMock() - - mock_get_running_app.config = MagicMock() - mock_get_running_app.config.get = MagicMock(return_value="en-US") - screen = SelectDeviceScreen() screen.update(key="version", value="v24.03.0") self.render(screen) @@ -237,21 +222,19 @@ def test_on_release_with_latest_version( mock_set_background.assert_has_calls(calls_set_background) mock_manager.get_screen.assert_has_calls(calls_manager) mock_set_screen.assert_has_calls(calls_set_screen) - mock_get_running_app.assert_called_once() + mock_get_locale.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.main_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_background") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.manager") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_screen") def test_on_release_with_beta_version( - self, mock_set_screen, mock_manager, mock_set_background, mock_get_running_app + self, mock_set_screen, mock_manager, mock_set_background, mock_get_locale ): mock_manager.get_screen = MagicMock() - - mock_get_running_app.config = MagicMock() - mock_get_running_app.config.get = MagicMock(return_value="en-US") - screen = SelectDeviceScreen() screen.update(key="version", value="odudex/krux_binaries") self.render(screen) @@ -284,21 +267,19 @@ def test_on_release_with_beta_version( mock_set_background.assert_has_calls(calls_set_background) mock_manager.get_screen.assert_has_calls(calls_manager) mock_set_screen.assert_has_calls(calls_set_screen) - mock_get_running_app.assert_called_once() + mock_get_locale.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.main_screen.App.get_running_app") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_background") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.manager") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_screen") def test_on_release_with_v22_03_0_version( - self, mock_set_screen, mock_manager, mock_set_background, mock_get_running_app + self, mock_set_screen, mock_manager, mock_set_background, mock_get_locale ): mock_manager.get_screen = MagicMock() - - mock_get_running_app.config = MagicMock() - mock_get_running_app.config.get = MagicMock(return_value="en-US") - screen = SelectDeviceScreen() screen.update(key="version", value="v22.03.0") self.render(screen) @@ -324,4 +305,4 @@ def test_on_release_with_v22_03_0_version( mock_set_background.assert_has_calls(calls_set_background) mock_manager.get_screen.assert_has_calls(calls_manager) mock_set_screen.assert_has_calls(calls_set_screen) - mock_get_running_app.assert_called_once() + mock_get_locale.assert_called_once() diff --git a/e2e/test_017_verify_stable_zip_screen.py b/e2e/test_017_verify_stable_zip_screen.py index d262308f..c929e774 100644 --- a/e2e/test_017_verify_stable_zip_screen.py +++ b/e2e/test_017_verify_stable_zip_screen.py @@ -1,5 +1,5 @@ import sys -from unittest.mock import patch, call, MagicMock +from unittest.mock import patch, call from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest from src.app.screens.verify_stable_zip_screen import ( @@ -132,86 +132,6 @@ def test_on_pre_enter(self, mock_get_locale): # patch assertions mock_get_locale.assert_called() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.manager") - @patch( - "src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.get_destdir_assets" - ) - @patch( - "src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.verify_sha256" - ) - @patch( - "src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.verify_signature" - ) - def test_on_enter( - self, - mock_verify_signature, - mock_verify_sha256, - mock_get_destdir_assets, - mock_manager, - mock_get_locale, - ): - sha_text = "\n".join( - [ - "[size=20sp][color=#efcc00]Integrity verification:[/color][/size]", - "", - "[size=16sp][b]mockdir/krux-v0.0.1.zip[/b][/size]", - "[size=14sp][color=#00FF00]mocksha2560123456789abcdef[/color][/size]", - "", - "[size=16sp][b]mockdir/krux-v0.0.1.zip.sha256.txt[/b][/size]", - "[size=14sp][color=#00FF00]mocksha2560123456789abcdef[/color][/size]", - "[size=14sp]Result: SUCCESS[/b][/size]", - "", - "", - ] - ) - - sig_text = "\n".join( - [ - "[size=20sp][color=#efcc00]Authenticity verification:[/color][/size]", - "", - "[size=16sp]Result: [b]GOOD SIGNATURE[/b][/size]", - "", - "[size=16sp]If you have openssl installed on your system[/size]", - "[size=16sp]you can check manually with the following command:[/size]", - "", - "[color=#00ff00][size=14sp]openssl sha256< mockdir/krux-v0.0.1.zip -binary | \\", - "openssl pkeyutl -verify -pubin -inkey mockdir/selfcustody.pem \\", - "-sigfile mockdir/krux-v0.0.0.1.zip.sig[/size][/color]", - ] - ) - mock_manager.get_screen = MagicMock() - mock_get_destdir_assets.return_value = "mockdir" - mock_verify_sha256.return_value = sha_text - mock_verify_signature.return_value = sig_text - - screen = VerifyStableZipScreen() - screen.version = "v0.0.1" - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.on_pre_enter() - screen.on_enter() - - full_text = sha_text + sig_text - self.assertEqual(screen.ids["verify_stable_zip_screen_label"].text, full_text) - - # patch assertions - mock_get_locale.assert_called() - mock_get_destdir_assets.assert_called_once() - mock_manager.get_screen.assert_called_once_with("MainScreen") - mock_verify_sha256.assert_called_once_with( - assets_dir="mockdir", version=mock_manager.get_screen().version - ) - mock_verify_signature.assert_called_once_with( - assets_dir="mockdir", version=mock_manager.get_screen().version - ) - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/src/app/screens/__init__.py b/src/app/screens/__init__.py index 8b137891..e69de29b 100644 --- a/src/app/screens/__init__.py +++ b/src/app/screens/__init__.py @@ -1 +0,0 @@ - diff --git a/src/app/screens/about_screen.py b/src/app/screens/about_screen.py index 41dc4c19..6e3dfa94 100644 --- a/src/app/screens/about_screen.py +++ b/src/app/screens/about_screen.py @@ -27,7 +27,7 @@ from kivy.core.window import Window from kivy.graphics.vertex_instructions import Rectangle from kivy.graphics.context_instructions import Color -from src.utils.constants import get_name, get_version +from src.utils.constants import get_version from src.app.screens.base_screen import BaseScreen @@ -76,6 +76,7 @@ def _on_ref_press(*args): for fn in fns: Clock.schedule_once(fn, 0) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons from selected device/versions on related screens""" name = kwargs.get("name") diff --git a/src/app/screens/ask_permission_dialout_screen.py b/src/app/screens/ask_permission_dialout_screen.py index ed366877..302cda78 100644 --- a/src/app/screens/ask_permission_dialout_screen.py +++ b/src/app/screens/ask_permission_dialout_screen.py @@ -29,7 +29,6 @@ from kivy.graphics.vertex_instructions import Rectangle from kivy.core.window import Window from src.app.screens.base_screen import BaseScreen -from src.i18n import T class AskPermissionDialoutScreen(BaseScreen): @@ -45,6 +44,10 @@ def __init__(self, **kwargs): **kwargs, ) + self.user = "" + self.group = "" + self.distro = "" + # Build grid where buttons will be placed self.make_grid(wid=f"{self.id}_grid", rows=1) @@ -53,6 +56,7 @@ def __init__(self, **kwargs): self._bin = "/usr/bin/usermod" self._bin_args = ["-a", "-G"] + # pylint: disable=unused-argument def on_permission_created(output: str): logout_msg = self.translate("You may need to logout (or even reboot)") backin_msg = self.translate("and back in for the new group to take effect") @@ -78,17 +82,18 @@ def _on_ref_press(*args): # If user isnt in the dialout group, # but the configuration was done correctly # create the command - cmd = ( - [self._bin] - + [a for a in self._bin_args] - + [self.group] - + [self.user] - ) + cmd = [self._bin] + for a in self._bin_args: + cmd.append(a) + cmd.append(self.group) + cmd.append(self.user) try: self.debug(f"cmd={cmd}") sudoer = SudoerLinux(name=f"Add {self.user} to {self.group}") sudoer.exec(cmd=cmd, env={}, callback=on_permission_created) + + # pylint: disable=broad-exception-caught except Exception as err: self.error(str(err)) self.redirect_exception(exception=err) @@ -111,6 +116,7 @@ def _on_ref_press(*args): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """ In linux, will check for user permission on group @@ -173,40 +179,44 @@ def update(self, *args, **kwargs): self.redirect_error("distro not defined") else: - warn_msg = self.translate("WARNING") - first_msg = self.translate("This is the first run of KruxInstaller in") - access_msg = self.translate( - "and it appears that you do not have privileged access to make flash procedures" - ) - proceed_msg = self.translate( - "To proceed, click in the Allow button and a prompt will ask for your password" - ) - exec_msg = self.translate("to execute the following command") - - self.ids[f"{self.id}_label"].text = "".join( - [ - f"[size={self.SIZE_G}sp][color=#efcc00]{warn_msg}[/color][/size]", - "\n", - f'[size={self.SIZE_MP}sp]{first_msg} "{self.distro}"', - "\n", - f"{access_msg}.", - "\n", - proceed_msg, - "\n" f"{exec_msg}:", - "\n", - "[color=#00ff00]", - f"{self._bin} {" ".join(self._bin_args or [])} {self.group} {self.user}", - "[/color]", - "[/size]", - "\n", - "\n", - f"[size={self.SIZE_M}]", - "[color=#00FF00][ref=Allow]Allow[/ref][/color]", - " ", - "[color=#FF0000][ref=Deny]Deny[/ref][/color]", - "[/size]", - ] - ) + self.show_warning() else: self.redirect_error(msg=f"Invalid key: '{key}'") + + def show_warning(self): + """Show a warning in relation to operational system""" + warn_msg = self.translate("WARNING") + first_msg = self.translate("This is the first run of KruxInstaller in") + access_msg = self.translate( + "and it appears that you do not have privileged access to make flash procedures" + ) + proceed_msg = self.translate( + "To proceed, click in the Allow button and a prompt will ask for your password" + ) + exec_msg = self.translate("to execute the following command") + + self.ids[f"{self.id}_label"].text = "".join( + [ + f"[size={self.SIZE_G}sp][color=#efcc00]{warn_msg}[/color][/size]", + "\n", + f'[size={self.SIZE_MP}sp]{first_msg} "{self.distro}"', + "\n", + f"{access_msg}.", + "\n", + proceed_msg, + "\n" f"{exec_msg}:", + "\n", + "[color=#00ff00]", + f"{self._bin} {" ".join(self._bin_args or [])} {self.group} {self.user}", + "[/color]", + "[/size]", + "\n", + "\n", + f"[size={self.SIZE_M}]", + "[color=#00FF00][ref=Allow]Allow[/ref][/color]", + " ", + "[color=#FF0000][ref=Deny]Deny[/ref][/color]", + "[/size]", + ] + ) diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index cf625a56..08cd4f37 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -81,11 +81,13 @@ def __init__(self, wid: str, name: str, **kwargs): @property def to_screen(self) -> str: + """Get where the current screen will go""" self.debug(f"getter::to_screen={self._to_screen}") return self._to_screen @to_screen.setter def to_screen(self, value: str): + """Set where the current screen will go""" self.debug(f"setter::to_screen={value}") self._to_screen = value @@ -109,6 +111,7 @@ def downloader(self): @property def thread(self) -> Thread | None: + """Return a Thread""" self.debug(f"getter::thread={self._thread}") return self._thread @@ -141,7 +144,8 @@ def trigger(self): self.debug(f"deleter::trigger={self._trigger}") del self._trigger - def on_enter(self): + # pylint: disable=unused-argument + def on_enter(self, *args): """ Event fired when the screen is displayed and the entering animation is complete. diff --git a/src/app/screens/base_flash_screen.py b/src/app/screens/base_flash_screen.py index 35047ca5..cb88385b 100644 --- a/src/app/screens/base_flash_screen.py +++ b/src/app/screens/base_flash_screen.py @@ -22,13 +22,9 @@ main_screen.py """ import os -import math import typing -from pathlib import Path -from functools import partial from threading import Thread from kivy.clock import Clock, ClockEvent -from src.utils.flasher import Flasher from src.app.screens.base_screen import BaseScreen diff --git a/src/app/screens/download_beta_screen.py b/src/app/screens/download_beta_screen.py index 0323c8db..c515bffe 100644 --- a/src/app/screens/download_beta_screen.py +++ b/src/app/screens/download_beta_screen.py @@ -24,7 +24,6 @@ import os import time from functools import partial -from kivy.app import App from kivy.clock import Clock from kivy.core.window import Window from kivy.graphics.vertex_instructions import Rectangle @@ -46,6 +45,7 @@ def __init__(self, **kwargs): # Define some staticmethods in dynamic way # (so they can be called in tests) + # pylint: disable=unused-argument def on_trigger(dt): time.sleep(2.1) screen = self.manager.get_screen(self.to_screen) @@ -91,6 +91,7 @@ def on_progress(data: bytes): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" name = kwargs.get("name") @@ -140,77 +141,87 @@ def update(self, *args, **kwargs): elif key == "downloader": if self.downloader is None: - destdir = DownloadBetaScreen.get_destdir_assets() - destdir = os.path.join( - destdir, "krux_binaries", f"maixpy_{self.device}" - ) + self.build_downloader() + else: + self.redirect_error("Downloader already initialized") - self.downloader = BetaDownloader( - device=self.device, - binary_type=self.firmware, - destdir=destdir, - ) + elif key == "progress": + if value is not None: + self.on_download_progress(value) + + else: + self.redirect_error(f'Invalid key: "{key}"') + + def build_downloader(self): + """Build the downloader for beta firmware before the download itself""" + destdir = DownloadBetaScreen.get_destdir_assets() + destdir = os.path.join(destdir, "krux_binaries", f"maixpy_{self.device}") + + self.downloader = BetaDownloader( + device=self.device, + binary_type=self.firmware, + destdir=destdir, + ) - downloading = self.translate("Downloading") - to = self.translate("to") + downloading = self.translate("Downloading") + to = self.translate("to") + + self.ids[f"{self.id}_info"].text = "".join( + [ + f"[size={self.SIZE_MP}sp]", + downloading, + "\n", + "[color=#00AABB]", + f"[ref={self.downloader.url}]{self.downloader.url}[/ref]", + "[/color]", + "\n", + to, + "\n", + self.downloader.destdir, + "\n", + "[/size]", + ] + ) + + def on_download_progress(self, value): + """ + In each iteration of downloaded chunks, update the GUI with a ratio between + it's downloaded length and content length + """ + # trigger is defined in superclass + + callback_trigger = getattr(self, "trigger") + + # calculate percentage of download + if value is not None and self.downloader is not None: + lens = [value["downloaded_len"], value["content_len"]] + percent = lens[0] / lens[1] + + # Format bytes (one liner) in MB + # https://stackoverflow.com/questions/ + # 5194057/better-way-to-convert-file-sizes-in-python#answer-52684562 + downs = [f"{lens[0]/(1<<20):,.2f}", f"{lens[1]/(1<<20):,.2f}"] + self.ids[f"{self.id}_progress"].text = "".join( + [ + f"[size={self.SIZE_G}sp][b]{ percent * 100:,.2f} %[/b][/size]", + "\n", + f"[size={self.SIZE_MP}sp]{downs[0]} of {downs[1]} MB[/size]", + ] + ) + if percent == 1.0: + downloaded = self.translate("downloaded") + destdir = os.path.join(self.downloader.destdir, "kboot.kfpkg") self.ids[f"{self.id}_info"].text = "".join( [ f"[size={self.SIZE_MP}sp]", - downloading, - "\n", - "[color=#00AABB]", - f"[ref={self.downloader.url}]{self.downloader.url}[/ref]", - "[/color]", - "\n", - to, - "\n", - self.downloader.destdir, + destdir, "\n", + downloaded, "[/size]", ] ) - else: - self.redirect_error("Downloader already initialized") - - elif key == "progress": - # trigger is defined in superclass - callback_trigger = getattr(self, "trigger") - - # calculate percentage of download - if value is not None and self.downloader is not None: - lens = [value["downloaded_len"], value["content_len"]] - percent = lens[0] / lens[1] - - # Format bytes (one liner) in MB - # https://stackoverflow.com/questions/ - # 5194057/better-way-to-convert-file-sizes-in-python#answer-52684562 - downs = [f"{lens[0]/(1<<20):,.2f}", f"{lens[1]/(1<<20):,.2f}"] - self.ids[f"{self.id}_progress"].text = "".join( - [ - f"[size={self.SIZE_G}sp][b]{ percent * 100:,.2f} %[/b][/size]", - "\n", - f"[size={self.SIZE_MP}sp]{downs[0]} of {downs[1]} MB[/size]", - ] - ) - - if percent == 1.0: - downloaded = self.translate("downloaded") - destdir = os.path.join(self.downloader.destdir, "kboot.kfpkg") - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - destdir, - "\n", - downloaded, - "[/size]", - ] - ) - - # When finish, change the label, wait some seconds - # and then change screen - callback_trigger() - - else: - self.redirect_error(f'Invalid key: "{key}"') + # When finish, change the label, wait some seconds + # and then change screen + callback_trigger() diff --git a/src/app/screens/download_selfcustody_pem_screen.py b/src/app/screens/download_selfcustody_pem_screen.py index 2c365453..a1e5bc29 100644 --- a/src/app/screens/download_selfcustody_pem_screen.py +++ b/src/app/screens/download_selfcustody_pem_screen.py @@ -24,12 +24,10 @@ import os import time from functools import partial -from kivy.app import App from kivy.clock import Clock from kivy.core.window import Window from kivy.graphics.vertex_instructions import Rectangle from kivy.graphics.context_instructions import Color -from src.app.screens.base_screen import BaseScreen from src.app.screens.base_download_screen import BaseDownloadScreen from src.utils.downloader.pem_downloader import PemDownloader @@ -48,11 +46,14 @@ def __init__(self, **kwargs): # Define some staticmethods in dynamic way # (so they can be called in tests) + # pylint: disable=unused-argument def on_trigger(dt): time.sleep(2.1) self.set_screen(name=self.to_screen, direction="left") def on_progress(data: bytes): + self.debug(f"Chunck length: {len(data)}") + # calculate downloaded percentage fn = partial( self.update, @@ -74,6 +75,7 @@ def on_progress(data: bytes): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" name = kwargs.get("name") @@ -138,8 +140,7 @@ def update(self, *args, **kwargs): # for some unknow reason (yet) # the screen show that downloaded # 130B of 128B, so limit it to 128 - if percent > 1.0: - percent = 1.0 + percent = 1.0 if percent >= 1.0 else percent if lens[0] > lens[1]: lens[0] = lens[1] diff --git a/src/app/screens/download_stable_zip_screen.py b/src/app/screens/download_stable_zip_screen.py index 98747752..06704562 100644 --- a/src/app/screens/download_stable_zip_screen.py +++ b/src/app/screens/download_stable_zip_screen.py @@ -24,7 +24,6 @@ import os import time from functools import partial -from kivy.app import App from kivy.clock import Clock from kivy.core.window import Window from kivy.graphics.vertex_instructions import Rectangle @@ -50,6 +49,7 @@ def __init__(self, **kwargs): # This is a function that will be called # when the download thread is finished def on_trigger(dt): + self.debug(f"latter call timed {dt}ms") time.sleep(2.1) screen = self.manager.get_screen(self.to_screen) fn = partial( @@ -61,6 +61,7 @@ def on_trigger(dt): # This is a function that will be called # when a bunch of data are streamed from github def on_progress(data: bytes): + self.debug(f"Chunck size: {len(data)}") if self.downloader is not None: fn = partial( self.update, @@ -87,6 +88,7 @@ def on_progress(data: bytes): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" name = kwargs.get("name") @@ -118,89 +120,95 @@ def update(self, *args, **kwargs): elif key == "version": if value is not None: - self.version = value - self.downloader = ZipDownloader( - version=self.version, - destdir=DownloadStableZipScreen.get_destdir_assets(), - ) - - if self.downloader is not None: - url = getattr(self.downloader, "url") - destdir = getattr(self.downloader, "destdir") - downloading = self.translate("Downloading") - to = self.translate("to") - filepath = os.path.join(destdir, f"krux-{self.version}.zip") - - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - downloading, - "\n", - f"[color=#00AABB][ref={url}]{url}[/ref][/color]", - "\n", - to, - "\n", - filepath, - "[/size]", - ] - ) - - else: - self.redirect_error("Invalid downloader") - + self.build_downloader(value) else: self.redirect_error(f"Invalid value for key '{key}': '{value}'") elif key == "progress": if value is not None: + self.on_download_progress(value) + + else: + self.redirect_error(f'Invalid key: "{key}"') - # calculate percentage of download - lens = [value["downloaded_len"], value["content_len"]] - percent = lens[0] / lens[1] + def build_downloader(self, version: str): + """Creates a Downloader given a firmware version""" + self.version = version + self.downloader = ZipDownloader( + version=self.version, + destdir=DownloadStableZipScreen.get_destdir_assets(), + ) - # Format bytes (one liner) in MB - # https://stackoverflow.com/questions/ - # 5194057/better-way-to-convert-file-sizes-in-python#answer-52684562 - downs = [f"{lens[0]/(1<<20):,.2f}", f"{lens[1]/(1<<20):,.2f}"] + if self.downloader is not None: + url = getattr(self.downloader, "url") + destdir = getattr(self.downloader, "destdir") + downloading = self.translate("Downloading") + to = self.translate("to") + filepath = os.path.join(destdir, f"krux-{self.version}.zip") + + self.ids[f"{self.id}_info"].text = "".join( + [ + f"[size={self.SIZE_MP}sp]", + downloading, + "\n", + f"[color=#00AABB][ref={url}]{url}[/ref][/color]", + "\n", + to, + "\n", + filepath, + "[/size]", + ] + ) - of = self.translate("of") - self.ids[f"{self.id}_progress"].text = "".join( + else: + self.redirect_error("Invalid downloader") + + def on_download_progress(self, value: dict): + """update GUI given a ratio between what is downloaded and its total length""" + # calculate percentage of download + lens = [value["downloaded_len"], value["content_len"]] + percent = lens[0] / lens[1] + + # Format bytes (one liner) in MB + # https://stackoverflow.com/questions/ + # 5194057/better-way-to-convert-file-sizes-in-python#answer-52684562 + downs = [f"{lens[0]/(1<<20):,.2f}", f"{lens[1]/(1<<20):,.2f}"] + + of = self.translate("of") + self.ids[f"{self.id}_progress"].text = "".join( + [ + f"[size={self.SIZE_G}sp][b]{ percent * 100:,.2f} %[/b][/size]", + "\n", + f"[size={self.SIZE_MP}sp]", + downs[0], + f" {of} ", + downs[1], + " MB", + "[/size]", + ] + ) + + # When finish, change the label + # and then change screen + if percent == 1.00: + if self.downloader is not None: + destdir = getattr(self.downloader, "destdir") + downloaded = self.translate("downloaded") + filepath = os.path.join(destdir, f"krux-{self.version}.zip") + self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_G}sp][b]{ percent * 100:,.2f} %[/b][/size]", - "\n", f"[size={self.SIZE_MP}sp]", - downs[0], - f" {of} ", - downs[1], - " MB", + filepath, + "\n", + downloaded, "[/size]", ] ) - - # When finish, change the label + # When finish, change the label, wait some seconds # and then change screen - if percent == 1.00: - if self.downloader is not None: - destdir = getattr(self.downloader, "destdir") - downloaded = self.translate("downloaded") - filepath = os.path.join(destdir, f"krux-{self.version}.zip") - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - filepath, - "\n", - downloaded, - "[/size]", - ] - ) - # When finish, change the label, wait some seconds - # and then change screen - # trigger is defined in superclass - callback_trigger = getattr(self, "trigger") - callback_trigger() - - else: - self.redirect_error(f"Invalid downloader: {self.downloader}") + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + callback_trigger() - else: - self.redirect_error(f'Invalid key: "{key}"') + else: + self.redirect_error(f"Invalid downloader: {self.downloader}") diff --git a/src/app/screens/download_stable_zip_sha256_screen.py b/src/app/screens/download_stable_zip_sha256_screen.py index ebbac02f..7b972f07 100644 --- a/src/app/screens/download_stable_zip_sha256_screen.py +++ b/src/app/screens/download_stable_zip_sha256_screen.py @@ -24,12 +24,10 @@ import os import time from functools import partial -from kivy.app import App from kivy.clock import Clock from kivy.core.window import Window from kivy.graphics.vertex_instructions import Rectangle from kivy.graphics.context_instructions import Color -from src.app.screens.base_screen import BaseScreen from src.app.screens.base_download_screen import BaseDownloadScreen from src.utils.downloader.sha256_downloader import Sha256Downloader @@ -47,6 +45,7 @@ def __init__(self, **kwargs): # Define some staticmethods in dynamic way # (so they can be called in tests) + # pylint: disable=unused-argument def on_trigger(dt): time.sleep(2.1) screen = self.manager.get_screen(self.to_screen) @@ -56,6 +55,7 @@ def on_trigger(dt): Clock.schedule_once(fn, 0) self.set_screen(name=self.to_screen, direction="left") + # pylint: disable=unused-argument def on_progress(data: bytes): # calculate downloaded percentage fn = partial( @@ -78,6 +78,7 @@ def on_progress(data: bytes): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" name = kwargs.get("name") diff --git a/src/app/screens/download_stable_zip_sig_screen.py b/src/app/screens/download_stable_zip_sig_screen.py index c7160859..b6c9d9d7 100644 --- a/src/app/screens/download_stable_zip_sig_screen.py +++ b/src/app/screens/download_stable_zip_sig_screen.py @@ -24,12 +24,10 @@ import os import time from functools import partial -from kivy.app import App from kivy.clock import Clock from kivy.core.window import Window from kivy.graphics.vertex_instructions import Rectangle from kivy.graphics.context_instructions import Color -from src.app.screens.base_screen import BaseScreen from src.app.screens.base_download_screen import BaseDownloadScreen from src.utils.downloader.sig_downloader import SigDownloader @@ -48,6 +46,7 @@ def __init__(self, **kwargs): # Define some staticmethods in dynamic way # (so they can be called in tests) def on_trigger(dt): + self.debug(f"latter call timed {dt}ms") time.sleep(2.1) screen = self.manager.get_screen(self.to_screen) fn = partial(screen.update, name=self.name, key="public-key-certificate") @@ -56,6 +55,7 @@ def on_trigger(dt): def on_progress(data: bytes): # calculate downloaded percentage + self.debug(f"Chunck size: {len(data)}") fn = partial( self.update, name=self.name, @@ -76,6 +76,7 @@ def on_progress(data: bytes): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" name = kwargs.get("name") diff --git a/src/app/screens/error_screen.py b/src/app/screens/error_screen.py index cfdecae5..c78ebe84 100644 --- a/src/app/screens/error_screen.py +++ b/src/app/screens/error_screen.py @@ -21,18 +21,12 @@ """ error_screen.py """ -import traceback from functools import partial -from typing import Text from kivy.clock import Clock from kivy.core.window import Window from kivy.graphics.vertex_instructions import Rectangle from kivy.graphics.context_instructions import Color -from kivy.app import App -from kivy.cache import Cache from src.app.screens.base_screen import BaseScreen -from src.utils.selector import Selector -from src.i18n import T class ErrorScreen(BaseScreen): @@ -73,6 +67,7 @@ def _release(instance): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """ In linux, will check for user permission on group @@ -121,8 +116,3 @@ def update(self, *args, **kwargs): exc_info = ValueError(f"Invalid key: '{key}'") fn = partial(self.update, name=self.name, key="error", value=exc_info) Clock.schedule_once(fn, 0) - - def on_enter(self): - """Simple update your canvas""" - fn = partial(self.update, name=self.name, key="canvas") - Clock.schedule_once(fn, 0) diff --git a/src/app/screens/flash_screen.py b/src/app/screens/flash_screen.py index 1d0319bd..926f7c53 100644 --- a/src/app/screens/flash_screen.py +++ b/src/app/screens/flash_screen.py @@ -39,6 +39,7 @@ class FlashScreen(BaseFlashScreen): def __init__(self, **kwargs): super().__init__(wid="flash_screen", name="FlashScreen", **kwargs) + self.flasher = Flasher() fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) @@ -64,9 +65,16 @@ def parse_output(text: str) -> str: text = text.replace("\rProgramming", "Programming") return text - def on_pre_enter(self): - self.ids[f"{self.id}_grid"].clear_widgets() + def build_on_data(self): + """ + Build a streaming IO static method using + some instance variables for flash procedure + when KTool.print_callback is called + (useful for to be used in tests) + """ + + # pylint: disable=unused-argument def on_data(*args, **kwargs): text = " ".join(str(x) for x in args) self.info(text) @@ -91,6 +99,16 @@ def on_data(*args, **kwargs): self.ids[f"{self.id}_info"].text = "\n".join(self.output) + setattr(FlashScreen, "on_data", on_data) + + def build_on_process(self): + """ + Build a streaming IO static method using + some instance variables for flash procedure + + (useful for to be used in tests) + """ + def on_process(file_type: str, iteration: int, total: int, suffix: str): percent = (iteration / total) * 100 @@ -126,23 +144,24 @@ def on_process(file_type: str, iteration: int, total: int, suffix: str): ] ) - def on_ref_press(*args): - if args[1] == "Back": - self.set_screen(name="MainScreen", direction="right") + setattr(FlashScreen, "on_process", on_process) - elif args[1] == "Quit": - App.get_running_app().stop() + def build_on_done(self): + """ + Build a streaming IO static method using + some instance variables when flash procedure is done - else: - self.redirect_error(f"Invalid ref: {args[1]}") + (useful for to be used in tests) + """ + # pylint: disable=unused-argument def on_done(dt): del self.output[4:] self.ids[f"{self.id}_loader"].source = self.done_img self.ids[f"{self.id}_loader"].reload() done = self.translate("DONE") back = self.translate("Back") - quit = self.translate("Quit") + _quit = self.translate("Quit") if sys.platform in ("linux", "win32"): size = self.SIZE_M @@ -160,15 +179,30 @@ def on_done(dt): "[/color]", " ", "[color=#EFCC00]", - f"[ref=Quit][u]{quit}[/u][/ref]", + f"[ref=Quit][u]{_quit}[/u][/ref]", "[/color]", ] ) - setattr(FlashScreen, "on_data", on_data) - setattr(FlashScreen, "on_process", on_process) setattr(FlashScreen, "on_done", on_done) + # pylint: disable=unused-argument + def on_pre_enter(self, *args): + self.ids[f"{self.id}_grid"].clear_widgets() + self.build_on_data() + self.build_on_process() + self.build_on_done() + + def on_ref_press(*args): + if args[1] == "Back": + self.set_screen(name="MainScreen", direction="right") + + elif args[1] == "Quit": + App.get_running_app().stop() + + else: + self.redirect_error(f"Invalid ref: {args[1]}") + self.make_subgrid( wid=f"{self.id}_subgrid", rows=2, root_widget=f"{self.id}_grid" ) @@ -194,7 +228,8 @@ def on_done(dt): halign="justify", ) - def on_enter(self): + # pylint: disable=unused-argument + def on_enter(self, *args): """ Event fired when the screen is displayed and the entering animation is complete. """ @@ -220,7 +255,7 @@ def hook(err): self.error(msg) back = self.translate("Back") - quit = self.translate("Quit") + _quit = self.translate("Quit") self.ids[f"{self.id}_progress"].text = "".join( [ f"[size={sizes[0]}]", @@ -233,7 +268,7 @@ def hook(err): f"[ref=Back][u]{back}[/u][/ref][/color]", " ", "[color=#EFCC00]", - f"[ref=Quit][u]{quit}[/u][/ref]", + f"[ref=Quit][u]{_quit}[/u][/ref]", "[/color]", "[/size]", ] @@ -249,6 +284,7 @@ def hook(err): # start thread self.thread.start() + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with firmware key. Should be called before `on_enter`""" name = kwargs.get("name") @@ -293,7 +329,6 @@ def update(self, *args, **kwargs): self.redirect_error(f"Invalid value for key '{key}': '{value}'") elif key == "flasher": - self.flasher = Flasher() self.flasher.firmware = self.firmware self.flasher.baudrate = self.baudrate diff --git a/src/app/screens/greetings_screen.py b/src/app/screens/greetings_screen.py index ed834b78..09897ede 100644 --- a/src/app/screens/greetings_screen.py +++ b/src/app/screens/greetings_screen.py @@ -31,6 +31,10 @@ from src.utils.selector import Selector from src.app.screens.base_screen import BaseScreen +if sys.platform.startswith("linux"): + import distro + import grp + class GreetingsScreen(BaseScreen): """GreetingsScreen show Krux logo""" @@ -50,7 +54,8 @@ def __init__(self, **kwargs): wid=f"{self.id}_logo", root_widget=f"{self.id}_grid", source=self.logo_img ) - def on_enter(self): + # pylint: disable=unused-argument + def on_enter(self, *args): """ When application start, after greeting user with the krux logo, it will need to check if user is running app in linux or non-linux. If running in linux, the user will be @@ -60,7 +65,14 @@ def on_enter(self): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) + # pylint: disable=unused-argument def update(self, *args, **kwargs): + """ + After show krux logo, verify: + - in linux, if the current user is in dialout group to allow sudoless flash + - check the internet connection + - if have, update the firmware version to the latest + """ name = kwargs.get("name") key = kwargs.get("key") value = kwargs.get("value") @@ -104,9 +116,6 @@ def check_permissions_for_dialout_group(self): group (in some distros, can be 'uucp') """ if sys.platform.startswith("linux"): - import distro - import grp - # get current user _user = os.environ.get("USER") _in_dialout = False @@ -161,6 +170,10 @@ def check_permissions_for_dialout_group(self): ) Clock.schedule_once(fn, 0) + else: + fn = partial(self.update, name=self.name, key="check-internet-connection") + Clock.schedule_once(fn, 0) + def check_internet_connection(self): """ In reality, this method get the latest version and set to @@ -179,6 +192,7 @@ def check_internet_connection(self): Clock.schedule_once(fn, 0) self.set_screen(name="MainScreen", direction="left") + # pylint: disable=broad-exception-caught except Exception as exc: self.error(str(exc)) self.redirect_exception(exception=exc) diff --git a/src/app/screens/main_screen.py b/src/app/screens/main_screen.py index e2946caf..c2737254 100644 --- a/src/app/screens/main_screen.py +++ b/src/app/screens/main_screen.py @@ -23,14 +23,10 @@ """ import os import re -import typing -import sys from functools import partial from kivy.clock import Clock -from kivy.app import App -from .base_screen import BaseScreen from src.utils.selector import VALID_DEVICES -from src.i18n import T +from src.app.screens.base_screen import BaseScreen class MainScreen(BaseScreen): @@ -51,200 +47,12 @@ def __init__(self, **kwargs): # Build grid where buttons will be placed self.make_grid(wid="main_screen_grid", rows=6) - - def on_change(instance, value): - self.debug(f"Updating text for {instance}") - instance.refresh() - - # Buttons will be defined in dynamic way - # so you will need to keep in mind that - # some binded methods need a special - # treatment in loops - buttons = [ - ( - "main_select_version", - "".join( - [ - f"{self.translate("Version")}: ", - "[color=#00AABB]", - self.translate(self.version), - "[/color]", - ] - ), - ), - ( - "main_select_device", - "".join( - [ - f"{self.translate("Device")}: ", - "[color=#00AABB]", - self.translate(self.device), - "[/color]", - ] - ), - ), - ("main_flash", f"[color=#333333]{self.translate("Flash")}[/color]"), - ("main_wipe", f"[color=#333333]{self.translate("Wipe")}[/color]"), - ("main_settings", self.translate("Settings")), - ("main_about", self.translate("About")), - ] - - # START of buttons - for row, _tuple in enumerate(buttons): - - # START of on_press buttons - def _press(instance): - self.debug(f"Calling Button::{instance.id}::on_press") - if instance.id == "main_flash": - if self.will_flash: - self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) - else: - self.warning(f"Button::{instance.id} disabled") - - if instance.id == "main_wipe": - if self.will_wipe: - self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) - else: - self.warning(f"Button::{instance.id} disabled") - - if instance.id == "main_select_version": - url = "https://api.github.com/repos/selfcustody/krux/releases" - self.ids[instance.id].text = "".join( - [ - f"[size={self.SIZE_M}sp]", - "[color=#efcc00]", - f"[b]{self.translate("Fetching data from")}[/b]", - "\n", - f"[size={self.SIZE_MP}sp]", - url, - "[/size]", - "[/color]", - ] - ) - - if instance.id in ( - "main_select_device", - "main_select_version", - "main_settings", - "main_about", - ): - self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) - - # END of on_press buttons - - # START of on_release_buttons - def _release(instance): - self.debug(f"Calling Button::{instance.id}::on_release") - if instance.id == "main_select_device": - select_device = self.manager.get_screen("SelectDeviceScreen") - fn = partial( - select_device.update, - name=self.name, - key="version", - value=self.version, - ) - Clock.schedule_once(fn, 0) - self.set_background(wid="main_select_device", rgba=(0, 0, 0, 1)) - self.set_screen(name="SelectDeviceScreen", direction="left") - - elif instance.id == "main_select_version": - select_version = self.manager.get_screen("SelectVersionScreen") - select_version.clear() - select_version.fetch_releases() - self.set_background(wid="main_select_version", rgba=(0, 0, 0, 1)) - self.set_screen(name="SelectVersionScreen", direction="left") - self.update(name=self.name, key="version", value=self.version) - - elif instance.id == "main_flash": - if self.will_flash: - # do a click effect - self.set_background(wid="main_flash", rgba=(0, 0, 0, 1)) - - # partials are functions that call `update` - # method in screen before go to them - partials = [] - - # Check if any release file exists - if re.findall(r"^v\d+\.\d+\.\d$", self.version): - resources = MainScreen.get_destdir_assets() - zipfile = os.path.join( - resources, f"krux-{self.version}.zip" - ) - if os.path.isfile(zipfile): - to_screen = "WarningAlreadyDownloadedScreen" - else: - to_screen = "DownloadStableZipScreen" - - screen = self.manager.get_screen(to_screen) - partials.append( - partial( - screen.update, - name=self.name, - key="version", - value=self.version, - ) - ) - - # check if release is beta - elif re.findall("^odudex/krux_binaries", self.version): - to_screen = "DownloadBetaScreen" - screen = self.manager.get_screen(to_screen) - partials.append( - partial( - screen.update, - name=self.name, - key="firmware", - value="kboot.kfpkg", - ) - ) - partials.append( - partial( - screen.update, - name=self.name, - key="device", - value=self.device, - ) - ) - partials.append( - partial(screen.update, name=self.name, key="downloader") - ) - - # Execute the partials - for fn in partials: - Clock.schedule_once(fn, 0) - - # Goto the selected screen - self.set_screen(name=to_screen, direction="left") - else: - self.debug(f"Button::{instance.id} disabled") - - elif instance.id == "main_wipe": - if self.will_wipe: - self.set_background(wid="main_wipe", rgba=(0, 0, 0, 1)) - self.set_screen(name="WarningWipeScreen", direction="left") - else: - self.debug(f"Button::{instance.id} disabled") - - elif instance.id == "main_settings": - self.set_background(wid="main_settings", rgba=(0, 0, 0, 1)) - MainScreen.open_settings() - - elif instance.id == "main_about": - self.set_background(wid="main_about", rgba=(0, 0, 0, 1)) - self.set_screen(name="AboutScreen", direction="left") - - # END of on_release buttons - - self.make_button( - row=row, - wid=_tuple[0], - root_widget="main_screen_grid", - text=_tuple[1], - on_press=_press, - on_release=_release, - ) - - # END of buttons + self.build_select_version_button() + self.build_select_device_button() + self.build_flash_button() + self.build_wipe_button() + self.build_settings_button() + self.build_about_button() @property def device(self) -> str: @@ -289,6 +97,313 @@ def will_wipe(self, value: bool): self.debug(f"will_wipe = {value}") self._will_wipe = value + def build_select_version_button(self): + """Create a staticmethod using instance variables to control the select_version button""" + url = "https://api.github.com/repos/selfcustody/krux/releases" + wid = "main_select_version" + msg = self.translate("Version") + + def on_press_select_version(instance): + self.debug(f"Calling {instance.id}::on_press") + self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + self.ids[instance.id].text = "".join( + [ + f"[size={self.SIZE_M}sp]", + "[color=#efcc00]", + f"[b]{self.translate("Fetching data from")}[/b]", + "\n", + f"[size={self.SIZE_MP}sp]", + url, + "[/size]", + "[/color]", + ] + ) + + def on_release_select_version(instance): + self.debug(f"Calling {instance.id}::on_release") + select_version = self.manager.get_screen("SelectVersionScreen") + select_version.clear() + select_version.fetch_releases() + self.set_background(wid="main_select_version", rgba=(0, 0, 0, 1)) + self.set_screen(name="SelectVersionScreen", direction="left") + self.update(name=self.name, key="version", value=self.version) + + setattr(MainScreen, "on_press_select_version", on_press_select_version) + setattr(MainScreen, "on_release_select_version", on_release_select_version) + + self.make_button( + row=0, + wid=wid, + root_widget="main_screen_grid", + text="".join( + [ + f"{msg}: ", + "[color=#00AABB]", + self.translate(self.version), + "[/color]", + ] + ), + on_press=getattr(MainScreen, "on_press_select_version"), + on_release=getattr(MainScreen, "on_release_select_version"), + ) + + def build_select_device_button(self): + """Create staticmethods using instance variables to control the select_device button""" + wid = "main_select_device" + msg = self.translate("Device") + + def on_press_select_device(instance): + self.debug(f"Calling {instance.id}::on_press") + self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + + def on_release_select_device(instance): + self.debug(f"Calling {instance.id}::on_release") + select_device = self.manager.get_screen("SelectDeviceScreen") + fn = partial( + select_device.update, + name=self.name, + key="version", + value=self.version, + ) + Clock.schedule_once(fn, 0) + self.set_background(wid="main_select_device", rgba=(0, 0, 0, 1)) + self.set_screen(name="SelectDeviceScreen", direction="left") + + setattr(MainScreen, "on_press_select_device", on_press_select_device) + setattr(MainScreen, "on_release_select_device", on_release_select_device) + + self.make_button( + row=1, + wid=wid, + root_widget="main_screen_grid", + text="".join( + [ + f"{msg}: ", + "[color=#00AABB]", + self.translate(self.device), + "[/color]", + ] + ), + on_press=getattr(MainScreen, "on_press_select_device"), + on_release=getattr(MainScreen, "on_release_select_device"), + ) + + def build_flash_button(self): + """Create staticmethods using instance variables to control the flash button""" + wid = "main_flash" + + def on_press_flash(instance): + self.debug(f"Calling {instance.id}::on_press") + if self.will_flash: + self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + else: + self.warning(f"Button::{instance.id} disabled") + + def on_release_flash(instance): + self.debug(f"Calling {instance.id}::on_release") + if not self.will_flash: + self.warning(f"Button::{instance.id} disabled") + else: + # do a click effect + self.set_background(wid="main_flash", rgba=(0, 0, 0, 1)) + + # partials are functions that call `update` + # method in screen before go to them + partials = [] + + # Check if any official release file exists + if re.findall(r"^v\d+\.\d+\.\d$", self.version): + resources = MainScreen.get_destdir_assets() + zipfile = os.path.join(resources, f"krux-{self.version}.zip") + + if os.path.isfile(zipfile): + to_screen = "WarningAlreadyDownloadedScreen" + else: + to_screen = "DownloadStableZipScreen" + + screen = self.manager.get_screen(to_screen) + partials.append( + partial( + screen.update, + name=self.name, + key="version", + value=self.version, + ) + ) + + # check if release is beta + elif re.findall("^odudex/krux_binaries", self.version): + to_screen = "DownloadBetaScreen" + screen = self.manager.get_screen(to_screen) + partials.append( + partial( + screen.update, + name=self.name, + key="firmware", + value="kboot.kfpkg", + ) + ) + partials.append( + partial( + screen.update, + name=self.name, + key="device", + value=self.device, + ) + ) + partials.append( + partial(screen.update, name=self.name, key="downloader") + ) + + # Execute the partials + for fn in partials: + Clock.schedule_once(fn, 0) + + # Goto the selected screen + self.set_screen(name=to_screen, direction="left") + + setattr(MainScreen, "on_press_flash", on_press_flash) + setattr(MainScreen, "on_release_flash", on_release_flash) + + self.make_button( + row=2, + wid=wid, + root_widget="main_screen_grid", + text=f"[color=#333333]{self.translate("Flash")}[/color]", + on_press=getattr(MainScreen, "on_press_flash"), + on_release=getattr(MainScreen, "on_release_flash"), + ) + + def build_wipe_button(self): + """Create staticmethods using instance variables to control the wipe button""" + wid = "main_wipe" + + def on_press_wipe(instance): + self.debug(f"Calling {instance.id}::on_press") + if self.will_wipe: + self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + else: + self.warning(f"Button::{instance.id} disabled") + + def on_release_wipe(instance): + self.debug(f"Calling {instance.id}::on_release") + if self.will_wipe: + self.set_background(wid="main_wipe", rgba=(0, 0, 0, 1)) + self.set_screen(name="WarningWipeScreen", direction="left") + else: + self.debug(f"Button::{instance.id} disabled") + + setattr(MainScreen, "on_press_wipe", on_press_wipe) + setattr(MainScreen, "on_release_wipe", on_release_wipe) + + self.make_button( + row=3, + wid=wid, + root_widget="main_screen_grid", + text=f"[color=#333333]{self.translate("Wipe")}[/color]", + on_press=getattr(MainScreen, "on_press_wipe"), + on_release=getattr(MainScreen, "on_release_wipe"), + ) + + def build_settings_button(self): + """Create staticmethods using instance variables to control the settings button""" + wid = "main_settings" + + def on_press_settings(instance): + self.debug(f"Calling {instance.id}::on_press") + self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + + def on_release_settings(instance): + self.debug(f"Calling {instance.id}::on_release") + self.set_background(wid="main_settings", rgba=(0, 0, 0, 1)) + MainScreen.open_settings() + + setattr(MainScreen, "on_press_settings", on_press_settings) + setattr(MainScreen, "on_release_settings", on_release_settings) + + self.make_button( + row=4, + wid=wid, + root_widget="main_screen_grid", + text=self.translate("Settings"), + on_press=getattr(MainScreen, "on_press_settings"), + on_release=getattr(MainScreen, "on_release_settings"), + ) + + def build_about_button(self): + """Create staticmethods using instance variables to control the about button""" + wid = "main_about" + + def on_press_about(instance): + self.debug(f"Calling Button::{instance.id}::on_press") + self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + + def on_release_about(instance): + self.debug(f"Calling Button::{instance.id}::on_release") + self.set_background(wid="main_about", rgba=(0, 0, 0, 1)) + self.set_screen(name="AboutScreen", direction="left") + + setattr(MainScreen, "on_press_about", on_press_about) + setattr(MainScreen, "on_release_about", on_release_about) + + self.make_button( + row=5, + wid=wid, + root_widget="main_screen_grid", + text=self.translate("About"), + on_press=getattr(MainScreen, "on_press_about"), + on_release=getattr(MainScreen, "on_release_about"), + ) + + def update_version(self, value: str): + """Update the version shown in button. To be used on update method""" + self.version = MainScreen.sanitize_markup(value) + self.ids["main_select_version"].text = "".join( + [ + f"{self.translate("Version")}: ", + "[color=#00AABB]", + self.version, + "[/color]", + ] + ) + + def update_device(self, value: str): + """Update the device shown in button. To be used on update method""" + self.device = MainScreen.sanitize_markup(value) + + # check if update to given values + if value in VALID_DEVICES: + self.device = value + self.will_flash = True + self.will_wipe = True + self.ids["main_flash"].text = self.translate("Flash") + self.ids["main_wipe"].text = self.translate("Wipe") + + else: + self.will_flash = False + self.will_wipe = False + self.ids["main_flash"].markup = True + self.ids["main_wipe"].markup = True + self.ids["main_flash"].text = "".join( + ["[color=#333333]", self.translate("Flash"), "[/color]"] + ) + self.ids["main_wipe"].text = "".join( + ["[color=#333333]", self.translate("Wipe"), "[/color]"] + ) + + if value == "select a new one": + self.device = self.translate("select a new one") + + self.ids["main_select_device"].text = "".join( + [ + f"{self.translate("Device")}: ", + "[color=#00AABB]", + self.device, + "[/color]", + ] + ) + + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons from selected device/versions on related screens""" name = kwargs.get("name") @@ -312,62 +427,19 @@ def update(self, *args, **kwargs): if key == "locale": if value is not None: self.locale = value - else: self.redirect_error(f"Invalid value for key {key}: {value}") # Check if update to given key elif key == "version": - if value is not None: - self.version = MainScreen.sanitize_markup(value) - self.ids["main_select_version"].text = "".join( - [ - f"{self.translate("Version")}: ", - "[color=#00AABB]", - self.version, - "[/color]", - ] - ) + self.update_version(value) else: self.redirect_error(f"Invalid value for key '{key}': '{value}'") elif key == "device": - if value is not None: - value = MainScreen.sanitize_markup(value) - - # check if update to given values - if value in VALID_DEVICES: - self.device = value - self.will_flash = True - self.will_wipe = True - self.ids["main_flash"].text = self.translate("Flash") - self.ids["main_wipe"].text = self.translate("Wipe") - - else: - self.will_flash = False - self.will_wipe = False - self.ids["main_flash"].markup = True - self.ids["main_wipe"].markup = True - self.ids["main_flash"].text = "".join( - ["[color=#333333]", self.translate("Flash"), "[/color]"] - ) - self.ids["main_wipe"].text = "".join( - ["[color=#333333]", self.translate("Wipe"), "[/color]"] - ) - - if value == "select a new one": - value = self.translate("select a new one") - - self.ids["main_select_device"].text = "".join( - [ - f"{self.translate("Device")}: ", - "[color=#00AABB]", - value, - "[/color]", - ] - ) + self.update_device(value) else: self.redirect_error(f"Invalid value for key '{key}': '{value}'") diff --git a/src/app/screens/select_device_screen.py b/src/app/screens/select_device_screen.py index f94ef40e..3101c260 100644 --- a/src/app/screens/select_device_screen.py +++ b/src/app/screens/select_device_screen.py @@ -24,11 +24,6 @@ import re from functools import partial from kivy.clock import Clock -from kivy.cache import Cache -from kivy.weakproxy import WeakProxy -from kivy.core.window import Window -from kivy.uix.button import Button -from kivy.graphics import Color, Line from src.utils.constants import VALID_DEVICES_VERSIONS from src.app.screens.base_screen import BaseScreen @@ -78,6 +73,7 @@ def _on_release(instance): on_release=_on_release, ) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons according the valid devices for each version""" name = kwargs.get("name") diff --git a/src/app/screens/select_old_version_screen.py b/src/app/screens/select_old_version_screen.py index 1ada04de..8e57ef9a 100644 --- a/src/app/screens/select_old_version_screen.py +++ b/src/app/screens/select_old_version_screen.py @@ -22,15 +22,9 @@ select_old_version_screen.py """ # pylint: disable=no-name-in-module -import re import typing from functools import partial from kivy.clock import Clock -from kivy.weakproxy import WeakProxy -from kivy.core.window import Window -from kivy.uix.button import Button -from kivy.graphics import Color, Line -from src.utils.selector import Selector from .base_screen import BaseScreen @@ -105,6 +99,7 @@ def _release_back(instance): on_release=_release_back, ) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" name = kwargs.get("name") diff --git a/src/app/screens/select_version_screen.py b/src/app/screens/select_version_screen.py index c088e3a7..07ddbcc9 100644 --- a/src/app/screens/select_version_screen.py +++ b/src/app/screens/select_version_screen.py @@ -22,12 +22,9 @@ select_version_screen.py """ # pylint: disable=no-name-in-module -import re from functools import partial from kivy.clock import Clock -from kivy.weakproxy import WeakProxy from kivy.core.window import Window -from kivy.uix.button import Button from kivy.graphics import Color from kivy.graphics import Rectangle from src.utils.selector import Selector @@ -149,10 +146,12 @@ def _release(instance): on_release=_release, ) + # pylint: disable=broad-exception-caught except Exception as exc: self.error(str(exc)) self.redirect_exception(exception=exc) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" name = kwargs.get("name") diff --git a/src/app/screens/unzip_stable_screen.py b/src/app/screens/unzip_stable_screen.py index 39c5cbc3..53776c4b 100644 --- a/src/app/screens/unzip_stable_screen.py +++ b/src/app/screens/unzip_stable_screen.py @@ -22,18 +22,9 @@ verify_stable_zip_screen.py """ import os -import sys import time from functools import partial from kivy.clock import Clock -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color -from kivy.app import App -from kivy.core.window import Window -from kivy.weakproxy import WeakProxy -from kivy.uix.stacklayout import StackLayout -from kivy.uix.button import Button -from src.utils.constants import get_name, get_version from src.app.screens.base_screen import BaseScreen from src.utils.unzip.kboot_unzip import KbootUnzip from src.utils.unzip.firmware_unzip import FirmwareUnzip @@ -49,6 +40,7 @@ def __init__(self, **kwargs): self.device = None self.version = None + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update widget from other screens""" @@ -99,6 +91,7 @@ def update(self, *args, **kwargs): self.redirect_error(f'Invalid key: "{key}"') def build_extract_to_flash_button(self): + """Builds an upper button for flash firmware""" self.debug("Building flash button") zip_file = os.path.join(self.assets_dir, f"krux-{self.version}.zip") base_path = os.path.join(f"krux-{self.version}", f"maixpy_{self.device}") @@ -201,6 +194,7 @@ def _release(instance): ) def build_extract_to_airgap_button(self): + """Build a lower button to airgap update""" self.debug("Building airgap button") zip_file = os.path.join(self.assets_dir, f"krux-{self.version}.zip") base_path = os.path.join(f"krux-{self.version}", f"maixpy_{self.device}") diff --git a/src/app/screens/verify_stable_zip_screen.py b/src/app/screens/verify_stable_zip_screen.py index 8bb83ef4..4b052270 100644 --- a/src/app/screens/verify_stable_zip_screen.py +++ b/src/app/screens/verify_stable_zip_screen.py @@ -23,18 +23,14 @@ """ import os import sys -import time from functools import partial +import typing from kivy.clock import Clock from kivy.graphics.vertex_instructions import Rectangle from kivy.graphics.context_instructions import Color -from kivy.app import App from kivy.core.window import Window from kivy.weakproxy import WeakProxy from kivy.uix.label import Label -from kivy.uix.stacklayout import StackLayout -from kivy.uix.button import Button -from src.utils.constants import get_name, get_version from src.app.screens.base_screen import BaseScreen from src.utils.verifyer.sha256_check_verifyer import Sha256CheckVerifyer from src.utils.verifyer.sha256_verifyer import Sha256Verifyer @@ -92,6 +88,7 @@ def _on_ref_press(*args): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update widget from other screens""" @@ -121,7 +118,8 @@ def update(self, *args, **kwargs): else: self.redirect_error(f'Invalid key: "{key}"') - def on_pre_enter(self): + # pylint: disable=unused-argument + def on_pre_enter(self, *args): self.ids[f"{self.id}_grid"].clear_widgets() verifying_msg = self.translate("Verifying integrity and authenticity") @@ -146,36 +144,53 @@ def on_pre_enter(self): on_ref_press=getattr(VerifyStableZipScreen, f"on_ref_press_{self.id}") ) - def on_enter(self): + # pylint: disable=unused-argument + def on_enter(self, *args): assets_dir = VerifyStableZipScreen.get_destdir_assets() main_screen = self.manager.get_screen("MainScreen") - result_sha256 = self.verify_sha256( + self.ids[f"{self.id}_label"].text = self.build_message_verify_sha256( assets_dir=assets_dir, version=main_screen.version ) - self.ids[f"{self.id}_label"].text = result_sha256 - result_sign = self.verify_signature( + self.ids[f"{self.id}_label"].text += self.build_message_verify_signature( assets_dir=assets_dir, version=main_screen.version ) - self.ids[f"{self.id}_label"].text += result_sign - def verify_sha256(self, assets_dir: str, version: str) -> str: + def verify_sha256( + self, assets_dir: str, version: str + ) -> typing.Tuple[str, str, bool]: """Do the verification when entering on screen""" # verify integrity - sha256_data_0 = Sha256Verifyer(filename=f"{assets_dir}/krux-{version}.zip") - sha256_data_1 = Sha256CheckVerifyer( + sha256_0 = Sha256Verifyer(filename=f"{assets_dir}/krux-{version}.zip") + sha256_1 = Sha256CheckVerifyer( filename=f"{assets_dir}/krux-{version}.zip.sha256.txt" ) - sha256_data_0.load() - sha256_data_1.load() - txt_hash_0 = sha256_data_0.data.split(" ")[0] - txt_hash_1 = sha256_data_1.data.split(" ")[0] - checksum = sha256_data_0.verify(txt_hash_1) + sha256_0.load() + sha256_1.load() + hash_0 = sha256_0.data.split(" ", maxsplit=1)[0] + hash_1 = sha256_1.data.split(" ", maxsplit=1)[0] + return (hash_0, hash_1, sha256_0.verify(hash_1)) + + @staticmethod + def prettyfy_hash(msg: str) -> str: + """Slice strings, two by two, to better visualization""" + splitted = [msg[i : i + 2] for i in range(0, len(msg), 2)] + subsets = [ + " ".join(splitted[i : i + 16]) for i in range(0, len(splitted), 16) + ] + return "\n".join(subsets) + def build_message_verify_sha256(self, assets_dir: str, version: str) -> str: + """Create a message which user can assert the integrity verification""" # memorize result - self.success = checksum + verify = self.verify_sha256(assets_dir=assets_dir, version=version) + hash_0 = verify[0] + hash_1 = verify[1] + checksummed = verify[2] + + self.success = checksummed filepath = os.path.join(assets_dir, f"krux-{version}.zip") integrity_msg = self.translate("Integrity verification") @@ -189,23 +204,10 @@ def verify_sha256(self, assets_dir: str, version: str) -> str: else: size = [self.SIZE_M, self.SIZE_MP, self.SIZE_P] - # slice strings, two by two, to better visualization - chunk_sha_0 = [txt_hash_0[i : i + 2] for i in range(0, len(txt_hash_0), 2)] - chunk_sha_1 = [txt_hash_1[i : i + 2] for i in range(0, len(txt_hash_1), 2)] + sha_0 = VerifyStableZipScreen.prettyfy_hash(hash_0) + sha_1 = VerifyStableZipScreen.prettyfy_hash(hash_1) - # if strings is greater than 16, split in a 2 subsets - subset_sha_0 = [ - " ".join(chunk_sha_0[i : i + 16]) for i in range(0, len(chunk_sha_0), 16) - ] - subset_sha_1 = [ - " ".join(chunk_sha_1[i : i + 16]) for i in range(0, len(chunk_sha_1), 16) - ] - - # join the 2 subsets with \n (next line) string - sha_0 = "\n".join(subset_sha_0) - sha_1 = "\n".join(subset_sha_1) - - if checksum: + if checksummed: hash_color = "#00FF00" hash_msg = self.translate("SUCCESS") else: @@ -239,6 +241,7 @@ def verify_sha256(self, assets_dir: str, version: str) -> str: ) def verify_signature(self, assets_dir: str, version: str) -> bool | str: + """Verify official release's signature""" # verify signature signature = SigCheckVerifyer(filename=f"{assets_dir}/krux-{version}.zip.sig") publickey = PemCheckVerifyer(filename=f"{assets_dir}/selfcustody.pem") @@ -251,9 +254,11 @@ def verify_signature(self, assets_dir: str, version: str) -> bool | str: pubkey=publickey.data, ) sig_verifyer.load() - checksig = sig_verifyer.verify() + return sig_verifyer.verify() - # memorize result + def build_message_verify_signature(self, assets_dir: str, version: str) -> str: + """Create a message which user can assert authenticity the verification""" + checksig = self.verify_signature(assets_dir=assets_dir, version=version) self.success = self.success and checksig authenticity_msg = self.translate("Authenticity verification") diff --git a/src/app/screens/warning_already_downloaded_screen.py b/src/app/screens/warning_already_downloaded_screen.py index b86304aa..045328df 100644 --- a/src/app/screens/warning_already_downloaded_screen.py +++ b/src/app/screens/warning_already_downloaded_screen.py @@ -27,13 +27,7 @@ from kivy.graphics.vertex_instructions import Rectangle from kivy.graphics.context_instructions import Color from kivy.core.window import Window -from kivy.weakproxy import WeakProxy -from kivy.uix.label import Label -from kivy.uix.stacklayout import StackLayout -from kivy.uix.button import Button -from src.utils.constants import get_name, get_version from src.app.screens.base_screen import BaseScreen -from src.i18n import T class WarningAlreadyDownloadedScreen(BaseScreen): @@ -86,6 +80,7 @@ def _on_ref_press(*args): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" name = kwargs.get("name") diff --git a/src/app/screens/warning_beta_screen.py b/src/app/screens/warning_beta_screen.py index 187df022..db3f56a4 100644 --- a/src/app/screens/warning_beta_screen.py +++ b/src/app/screens/warning_beta_screen.py @@ -21,10 +21,7 @@ """ about_screen.py """ - -from src.utils.constants import get_name, get_version from src.app.screens.base_screen import BaseScreen -from src.i18n import T class WarningBetaScreen(BaseScreen): @@ -98,6 +95,7 @@ def _release(instance): on_release=_release, ) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" name = kwargs.get("name") @@ -114,39 +112,46 @@ def update(self, *args, **kwargs): if key == "locale": if value is not None: self.locale = value - warning = self.translate("WARNING") - test_repo = self.translate("This is our test repository") - unsg_bin = self.translate( - "These are unsigned binaries for the latest and most experimental features" - ) - just_try = self.translate( - "and it's just for trying new things and providing feedback." - ) - proceed = self.translate("Proceed") - back = self.translate("Back") - - text = "".join( - [ - f"[size={self.SIZE_MM}sp][color=#efcc00][b]{warning}[/b][/color][/size]", - "\n", - "\n", - f"[size={self.SIZE_M}sp][color=#efcc00]{test_repo}[/color][/size]", - "\n", - f"[size={self.SIZE_MP}sp]{unsg_bin}[/size]", - "\n", - f"[size={self.SIZE_MP}sp]{just_try}[/size]", - "\n", - "\n", - f"[size={self.SIZE_MM}sp]", - f"[color=#00ff00]{proceed}[/color] [color=#ff0000]{back}[/color]", - "[/size]", - ] - ) - - self.ids["warning_beta_screen_warn"].text = text + self.show_warning() else: self.redirect_error(f"Invalid value for key {key}: {value}") else: self.redirect_error(f'Invalid key: "{key}"') + + def show_warning(self): + """ + Create a warning message where it's content is about + the beta (and unsigned) firmware + """ + warning = self.translate("WARNING") + test_repo = self.translate("This is our test repository") + unsg_bin = self.translate( + "These are unsigned binaries for the latest and most experimental features" + ) + just_try = self.translate( + "and it's just for trying new things and providing feedback." + ) + proceed = self.translate("Proceed") + back = self.translate("Back") + + text = "".join( + [ + f"[size={self.SIZE_MM}sp][color=#efcc00][b]{warning}[/b][/color][/size]", + "\n", + "\n", + f"[size={self.SIZE_M}sp][color=#efcc00]{test_repo}[/color][/size]", + "\n", + f"[size={self.SIZE_MP}sp]{unsg_bin}[/size]", + "\n", + f"[size={self.SIZE_MP}sp]{just_try}[/size]", + "\n", + "\n", + f"[size={self.SIZE_MM}sp]", + f"[color=#00ff00]{proceed}[/color] [color=#ff0000]{back}[/color]", + "[/size]", + ] + ) + + self.ids["warning_beta_screen_warn"].text = text diff --git a/src/app/screens/warning_wipe_screen.py b/src/app/screens/warning_wipe_screen.py index cf47da11..7ac0eea1 100644 --- a/src/app/screens/warning_wipe_screen.py +++ b/src/app/screens/warning_wipe_screen.py @@ -27,12 +27,6 @@ from kivy.graphics.vertex_instructions import Rectangle from kivy.graphics.context_instructions import Color from kivy.core.window import Window -from kivy.weakproxy import WeakProxy -from kivy.uix.label import Label -from kivy.uix.stacklayout import StackLayout -from kivy.uix.button import Button -from src.app.screens import main_screen -from src.utils.constants import get_name, get_version from src.app.screens.base_screen import BaseScreen @@ -99,9 +93,12 @@ def _on_ref_press(*args): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) - def on_enter(self): + # pylint: disable=unused-argument + def on_enter(self, *args): + """Invoke make_label_text""" self.ids[f"{self.id}_label"].text = self.make_label_text() + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" name = kwargs.get("name") @@ -136,6 +133,7 @@ def update(self, *args, **kwargs): self.redirect_error(f'Invalid key: "{key}"') def make_label_text(self): + """Make a warning message about wipe procedure""" full_wipe = self.translate( "You are about to initiate a FULL WIPE of this device" ) @@ -160,7 +158,8 @@ def make_label_text(self): f"[size={sizes[0]}]", full_wipe, "[/size]", - "[/color]" "\n", + "[/color]", + "\n", "\n", f"[size={sizes[1]}]", f"{operation}:", diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index 73bbea8f..ae583cca 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -41,6 +41,8 @@ def __init__(self, **kwargs): super().__init__(wid="wipe_screen", name="WipeScreen", **kwargs) self.wiper = None self.success = False + self.progress = "" + self.device = None fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) @@ -73,7 +75,8 @@ def parse_output(text: str) -> str: ) return text - def on_pre_enter(self): + # pylint: disable=unused-argument + def on_pre_enter(self, *args): self.ids[f"{self.id}_grid"].clear_widgets() def on_data(*args, **kwargs): @@ -109,7 +112,7 @@ def on_done(dt): self.ids[f"{self.id}_loader"].reload() done = self.translate("DONE") back = self.translate("Back") - quit = self.translate("Quit") + _quit = self.translate("Quit") if sys.platform in ("linux", "win32"): size = self.SIZE_M @@ -126,7 +129,7 @@ def on_done(dt): "[/color]", " ", "[color=#EFCC00]", - f"[ref=Quit][u]{quit}[/u][/ref]", + f"[ref=Quit][u]{_quit}[/u][/ref]", "[/color]", ] ) @@ -160,7 +163,8 @@ def on_done(dt): halign="justify", ) - def on_enter(self): + # pylint: disable=unused-argument + def on_enter(self, *args): """ Event fired when the screen is displayed and the entering animation is complete. """ @@ -176,7 +180,6 @@ def on_enter(self): sizes = [self.SIZE_MM, self.SIZE_MP] self.ids[f"{self.id}_progress"].text = f"[size={sizes[0]}sp][b]{please}[/b]" - self.progress = "" # if anything wrong happen, show it def hook(err): @@ -189,7 +192,7 @@ def hook(err): done = self.translate("DONE") back = self.translate("Back") - quit = self.translate("Quit") + _quit = self.translate("Quit") self.ids[f"{self.id}_progress"].text = "".join( [ @@ -203,7 +206,7 @@ def hook(err): "[/color]", " ", "[color=#EFCC00]", - f"[ref=Quit][u]{quit}[/u][/ref]", + f"[ref=Quit][u]{_quit}[/u][/ref]", "[/color]", "[/size]", ] From dd326badff6587917408894098b5990f39d7c6b4 Mon Sep 17 00:00:00 2001 From: qlrd Date: Thu, 5 Sep 2024 10:07:40 -0300 Subject: [PATCH 14/61] linted and refactored some codes that manages GUI updates on download screens --- src/app/screens/base_download_screen.py | 91 ++++++++++ src/app/screens/download_stable_zip_screen.py | 41 +---- .../download_stable_zip_sha256_screen.py | 159 +++++++----------- .../screens/download_stable_zip_sig_screen.py | 151 +++++++---------- 4 files changed, 213 insertions(+), 229 deletions(-) diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index 08cd4f37..1e360109 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -27,6 +27,9 @@ from kivy.clock import Clock, ClockEvent from kivy.weakproxy import WeakProxy from kivy.uix.label import Label +from kivy.core.window import Window +from kivy.graphics.vertex_instructions import Rectangle +from kivy.graphics.context_instructions import Color from src.app.screens.base_screen import BaseScreen from src.utils.downloader.asset_downloader import AssetDownloader @@ -168,3 +171,91 @@ def on_enter(self, *args): self.thread.start() else: self.redirect_error("Downloader isnt configured. Use `update` method first") + + def update_screen(self, **kwargs): + """Update a screen in accord with the valid ones""" + name = kwargs.get("name") + key = kwargs.get("key") + value = kwargs.get("value") + screens = kwargs.get("screens") + + if name in screens: + self.debug(f"Updating {self.name} from {name}...") + else: + self.redirect_error(f"Invalid screen name: {name}") + return + + if key == "locale": + if value is not None: + self.locale = value + else: + self.redirect_error(f"Invalid value for key '{key}': '{value}'") + + elif key == "canvas": + with self.canvas.before: + Color(0, 0, 0, 1) + Rectangle(size=(Window.width, Window.height)) + + elif key == "version": + if value is not None: + build_downloader = getattr(self, "build_downloader") + build_downloader(value) + else: + self.redirect_error(f"Invalid value for key '{key}': '{value}'") + + elif key == "progress": + if value is not None: + on_download_progress = getattr(self, "on_download_progress") + on_download_progress(value) + else: + self.redirect_error(f"Invalid value for key '{key}': '{value}'") + + else: + self.redirect_error(f'Invalid key: "{key}"') + + @staticmethod + def make_download_info( + size: int, download_msg: str, from_url: str, to_msg: str, to_path: str + ) -> str: + """ + download_stable_zip_sha256_screen and download_stable_zip_sig_screen + use same procedure to update informational content of downloaded file + """ + return "".join( + [ + f"[size={size}sp]", + download_msg, + "\n", + f"[color=#00AABB][ref={from_url}]{from_url}[/ref][/color]", + "\n", + to_msg, + "\n", + to_path, + "[/size]", + ] + ) + + @staticmethod + def make_progress_info( + sizes: typing.Tuple[str, str], + of_msg: str, + percent: float, + downloaded_len: float, + content_len: float, + ) -> str: + """ + download_stable_zip_sha256_screen and download_stable_zip_sig_screen + use same procedure to update its progress content of downloaded file + """ + return "".join( + [ + f"[size={sizes[0]}sp][b]{percent * 100:,.2f} %[/b][/size]", + "\n", + f"[size={sizes[1]}sp]", + str(downloaded_len), + f" {of_msg} ", + str(content_len), + " B", + "[/size]", + ] + ) diff --git a/src/app/screens/download_stable_zip_screen.py b/src/app/screens/download_stable_zip_screen.py index 06704562..b24c14ca 100644 --- a/src/app/screens/download_stable_zip_screen.py +++ b/src/app/screens/download_stable_zip_screen.py @@ -25,9 +25,6 @@ import time from functools import partial from kivy.clock import Clock -from kivy.core.window import Window -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color from src.app.screens.base_download_screen import BaseDownloadScreen from src.utils.downloader.zip_downloader import ZipDownloader @@ -91,45 +88,13 @@ def on_progress(data: bytes): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" - name = kwargs.get("name") - key = kwargs.get("key") - value = kwargs.get("value") - - if name in ( + kwargs["screens"] = ( "ConfigKruxInstaller", "MainScreen", "WarningAlreadyDownloadedScreen", "DownloadStableZipScreen", - ): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen name: {name}") - return - - if key == "locale": - if value is not None: - self.locale = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - elif key == "version": - if value is not None: - self.build_downloader(value) - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "progress": - if value is not None: - self.on_download_progress(value) - - else: - self.redirect_error(f'Invalid key: "{key}"') + ) + self.update_screen(**kwargs) def build_downloader(self, version: str): """Creates a Downloader given a firmware version""" diff --git a/src/app/screens/download_stable_zip_sha256_screen.py b/src/app/screens/download_stable_zip_sha256_screen.py index 7b972f07..a3c60fa1 100644 --- a/src/app/screens/download_stable_zip_sha256_screen.py +++ b/src/app/screens/download_stable_zip_sha256_screen.py @@ -25,9 +25,6 @@ import time from functools import partial from kivy.clock import Clock -from kivy.core.window import Window -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color from src.app.screens.base_download_screen import BaseDownloadScreen from src.utils.downloader.sha256_downloader import Sha256Downloader @@ -81,113 +78,79 @@ def on_progress(data: bytes): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" - name = kwargs.get("name") - key = kwargs.get("key") - value = kwargs.get("value") - - if name in ( + kwargs["screens"] = ( "ConfigKruxInstaller", "DownloadStableZipScreen", "DownloadStableZipSha256Screen", - ): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen name: {name}") - return - - if key == "locale": - if value is not None: - self.locale = value - else: - self.redirect_error("Invalid value for 'key': '{value}'") - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - elif key == "version": - if value is not None: - self.version = value - self.downloader = Sha256Downloader( - version=value, - destdir=DownloadStableZipSha256Screen.get_destdir_assets(), - ) + ) + self.update_screen(**kwargs) + + def build_downloader(self, value: str): + """Creates a downloader for sha256sum file for a given firmware version""" + self.version = value + self.downloader = Sha256Downloader( + version=value, + destdir=DownloadStableZipSha256Screen.get_destdir_assets(), + ) - if self.downloader is not None: - url = getattr(self.downloader, "url") - destdir = getattr(self.downloader, "destdir") - downloading = self.translate("Downloading") - to = self.translate("to") - filepath = os.path.join( + if self.downloader is not None: + url = getattr(self.downloader, "url") + destdir = getattr(self.downloader, "destdir") + + self.ids[f"{self.id}_info"].text = ( + DownloadStableZipSha256Screen.make_download_info( + size=self.SIZE_MP, + download_msg=self.translate("Downloading"), + from_url=url, + to_msg=self.translate("to"), + to_path=os.path.join( destdir, f"krux-{self.version}.zip.sha256.txt" - ) - - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - downloading, - "\n", - f"[color=#00AABB][ref={url}]{url}[/ref][/color]", - "\n", - to, - "\n", - filepath, - "[/size]", - ] - ) - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") + ), + ) + ) - elif key == "progress": - if value is not None: - # calculate percentage of download - lens = [value["downloaded_len"], value["content_len"]] - percent = lens[0] / lens[1] + else: + self.redirect_error("Invalid downloader") + + def on_download_progress(self, value: dict): + """update GUI given a ratio between what is downloaded and its total length""" + # calculate percentage of download + downloaded_len = value["downloaded_len"] + content_len = value["content_len"] + percent = downloaded_len / content_len + + self.ids[f"{self.id}_progress"].text = ( + DownloadStableZipSha256Screen.make_progress_info( + sizes=(self.SIZE_G, self.SIZE_MP), + of_msg=self.translate("of"), + percent=percent, + downloaded_len=downloaded_len, + content_len=content_len, + ) + ) - of = self.translate("of") - self.ids[f"{self.id}_progress"].text = "".join( + # When finish, change the label + # and then change screen + if percent == 1.00: + if self.downloader is not None: + destdir = getattr(self.downloader, "destdir") + downloaded = self.translate("downloaded") + filepath = os.path.join(destdir, f"krux-{self.version}.zip.sha256.txt") + self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_G}sp][b]{percent * 100:,.2f} %[/b][/size]", - "\n", f"[size={self.SIZE_MP}sp]", - str(lens[0]), - f" {of} ", - str(lens[1]), - " B", + filepath, + "\n", + downloaded, "[/size]", ] ) - # When finish, change the label + # When finish, change the label, wait some seconds # and then change screen - if percent == 1.00: - if self.downloader is not None: - destdir = getattr(self.downloader, "destdir") - downloaded = self.translate("downloaded") - filepath = os.path.join( - destdir, f"krux-{self.version}.zip.sha256.txt" - ) - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - filepath, - "\n", - downloaded, - "[/size]", - ] - ) - # When finish, change the label, wait some seconds - # and then change screen - # trigger is defined in superclass - callback_trigger = getattr(self, "trigger") - callback_trigger() - - else: - self.redirect_error(f"Invalid downloader: {self.downloader}") - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + callback_trigger() - else: - self.redirect_error(f'Invalid key: "{key}"') + else: + self.redirect_error(f"Invalid downloader: {self.downloader}") diff --git a/src/app/screens/download_stable_zip_sig_screen.py b/src/app/screens/download_stable_zip_sig_screen.py index b6c9d9d7..1e7fbfcc 100644 --- a/src/app/screens/download_stable_zip_sig_screen.py +++ b/src/app/screens/download_stable_zip_sig_screen.py @@ -25,9 +25,6 @@ import time from functools import partial from kivy.clock import Clock -from kivy.core.window import Window -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color from src.app.screens.base_download_screen import BaseDownloadScreen from src.utils.downloader.sig_downloader import SigDownloader @@ -79,109 +76,77 @@ def on_progress(data: bytes): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" - name = kwargs.get("name") - key = kwargs.get("key") - value = kwargs.get("value") - - if name in ( + kwargs["screens"] = ( "ConfigKruxInstaller", "DownloadStableZipSha256Screen", "DownloadStableZipSigScreen", - ): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen name: {name}") - return + ) + self.update_screen(**kwargs) + + def build_downloader(self, value: str): + """Creates a Downloader for signature file given a firmware version""" + self.version = value + self.downloader = SigDownloader( + version=self.version, + destdir=DownloadStableZipSigScreen.get_destdir_assets(), + ) - if key == "locale": - if value is not None: - self.locale = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - elif key == "version": - if value is not None: - self.version = value - self.downloader = SigDownloader( - version=self.version, - destdir=DownloadStableZipSigScreen.get_destdir_assets(), + if self.downloader is not None: + url = getattr(self.downloader, "url") + destdir = getattr(self.downloader, "destdir") + + self.ids[f"{self.id}_info"].text = ( + DownloadStableZipSigScreen.make_download_info( + size=self.SIZE_MP, + download_msg=self.translate("Downloading"), + from_url=url, + to_msg=self.translate("to"), + to_path=os.path.join(destdir, f"krux-{self.version}.zip.sig"), ) + ) - if self.downloader is not None: - url = getattr(self.downloader, "url") - destdir = getattr(self.downloader, "destdir") - downloading = self.translate("Downloading") - to = self.translate("to") - filepath = os.path.join(destdir, f"krux-{self.version}.zip.sig") - - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - downloading, - "\n", - f"[color=#00AABB][ref={url}]{url}[/ref][/color]", - "\n", - to, - "\n", - filepath, - "[/size]", - ] - ) - - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "progress": - if value is not None: - # calculate percentage of download - lens = [value["downloaded_len"], value["content_len"]] - percent = lens[0] / lens[1] + else: + self.redirect_error("Invalid downloader") + + def on_download_progress(self, value: dict): + """update GUI given a ration between what is downloaded and its total length""" + # calculate percentage of download + downloaded_len = value["downloaded_len"] + content_len = value["content_len"] + percent = downloaded_len / content_len + + self.ids[f"{self.id}_progress"].text = ( + DownloadStableZipSigScreen.make_progress_info( + sizes=(self.SIZE_G, self.SIZE_MP), + of_msg=self.translate("of"), + percent=percent, + downloaded_len=downloaded_len, + content_len=content_len, + ) + ) - of = self.translate("of") - self.ids[f"{self.id}_progress"].text = "".join( + # When finish, change the label + # and then change screen + if percent == 1.00: + if self.downloader is not None: + destdir = getattr(self.downloader, "destdir") + downloaded = self.translate("downloaded") + filepath = os.path.join(destdir, f"krux-{self.version}.zip.sig") + self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_G}sp][b]{percent * 100:,.2f} %[/b][/size]", - "\n", f"[size={self.SIZE_MP}sp]", - str(lens[0]), - f" {of} ", - str(lens[1]), - " B", + filepath, + "\n", + downloaded, "[/size]", ] ) - # When finish, change the label + # When finish, change the label, wait some seconds # and then change screen - if percent == 1.00: - if self.downloader is not None: - destdir = getattr(self.downloader, "destdir") - downloaded = self.translate("downloaded") - filepath = os.path.join(destdir, f"krux-{self.version}.zip.sig") - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - filepath, - "\n", - downloaded, - "[/size]", - ] - ) - - # When finish, change the label, wait some seconds - # and then change screen - # trigger is defined in superclass - callback_trigger = getattr(self, "trigger") - callback_trigger() + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + callback_trigger() else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - else: - self.redirect_error(f'Invalid key: "{key}"') + self.redirect_error("Invalid downloader") From 59f00981a840fe17dd36eefcbf275c654737ec4c Mon Sep 17 00:00:00 2001 From: qlrd Date: Thu, 5 Sep 2024 12:16:53 -0300 Subject: [PATCH 15/61] linted some flash's related screens --- src/app/screens/base_flash_screen.py | 23 ++++++++++++++- src/app/screens/flash_screen.py | 25 ++-------------- src/app/screens/wipe_screen.py | 43 +++++++++------------------- 3 files changed, 37 insertions(+), 54 deletions(-) diff --git a/src/app/screens/base_flash_screen.py b/src/app/screens/base_flash_screen.py index cb88385b..5335ac8b 100644 --- a/src/app/screens/base_flash_screen.py +++ b/src/app/screens/base_flash_screen.py @@ -19,7 +19,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """ -main_screen.py +base_flash__screen.py """ import os import typing @@ -121,3 +121,24 @@ def is_done(self, value: bool): """Setter for info""" self.debug(f"setter::is_done={value}") self._is_done = value + + @staticmethod + def parse_general_output(text: str) -> str: + """Parses KTool.print_callback output to make it more readable on GUI""" + text = text.replace( + "\x1b[32m\x1b[1m[INFO]\x1b[0m", "[color=#00ff00]INFO[/color]" + ) + text = text.replace("\x1b[33mISP loaded", "[color=#efcc00]ISP loaded[/color]") + text = text.replace( + "\x1b[33mInitialize K210 SPI Flash", + "[color=#efcc00]Initialize K210 SPI Flash[/color]", + ) + text = text.replace("Flash ID: \x1b[33m", "Flash ID: [color=#efcc00]") + text = text.replace( + "\x1b[0m, unique ID: \x1b[33m", "[/color], unique ID: [color=#efcc00]" + ) + text = text.replace("\x1b[0m, size: \x1b[33m", "[/color], size: ") + text = text.replace("\x1b[0m MB", "[/color] MB") + text = text.replace("\x1b[0m", "") + text = text.replace("\x1b[33m", "") + return text diff --git a/src/app/screens/flash_screen.py b/src/app/screens/flash_screen.py index 926f7c53..e3acb990 100644 --- a/src/app/screens/flash_screen.py +++ b/src/app/screens/flash_screen.py @@ -43,28 +43,6 @@ def __init__(self, **kwargs): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) - @staticmethod - def parse_output(text: str) -> str: - """Parses KTool.print_callback output to make it more readable on GUI""" - text = text.replace( - "\x1b[32m\x1b[1m[INFO]\x1b[0m", "[color=#00ff00]INFO[/color]" - ) - text = text.replace("\x1b[33mISP loaded", "[color=#efcc00]ISP loaded[/color]") - text = text.replace( - "\x1b[33mInitialize K210 SPI Flash", - "[color=#efcc00]Initialize K210 SPI Flash[/color]", - ) - text = text.replace("Flash ID: \x1b[33m", "Flash ID: [color=#efcc00]") - text = text.replace( - "\x1b[0m, unique ID: \x1b[33m", "[/color], unique ID: [color=#efcc00]" - ) - text = text.replace("\x1b[0m, size: \x1b[33m", "[/color], size: ") - text = text.replace("\x1b[0m MB", "[/color] MB") - text = text.replace("\x1b[0m", "") - text = text.replace("\x1b[33m", "") - text = text.replace("\rProgramming", "Programming") - return text - def build_on_data(self): """ Build a streaming IO static method using @@ -78,7 +56,8 @@ def build_on_data(self): def on_data(*args, **kwargs): text = " ".join(str(x) for x in args) self.info(text) - text = FlashScreen.parse_output(text) + text = FlashScreen.parse_general_output(text) + text = text.replace("\rProgramming", "Programming") if "INFO" in text: self.output.append(text) diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index ae583cca..af736255 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -46,35 +46,6 @@ def __init__(self, **kwargs): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) - @staticmethod - def parse_output(text: str) -> str: - """Parses KTool.print_callback output to make it more readable on GUI""" - text = text.replace( - "\x1b[32m\x1b[1m[INFO]\x1b[0m", "[color=#00ff00]INFO[/color]" - ) - text = text.replace("\x1b[33mISP loaded", "[color=#efcc00]ISP loaded[/color]") - text = text.replace( - "\x1b[33mInitialize K210 SPI Flash", - "[color=#efcc00]Initialize K210 SPI Flash[/color]", - ) - text = text.replace("Flash ID: \x1b[33m", "Flash ID: [color=#efcc00]") - text = text.replace( - "\x1b[0m, unique ID: \x1b[33m", "[/color], unique ID: [color=#efcc00]" - ) - text = text.replace("\x1b[0m, size: \x1b[33m", "[/color], size: ") - text = text.replace("\x1b[0m MB", "[/color] MB") - text = text.replace("\x1b[0m", "") - text = text.replace("\x1b[33m", "") - text = text.replace( - "[INFO] Erasing the whole SPI Flash", - "[color=#00ff00]INFO[/color][color=#efcc00] Erasing the whole SPI Flash [/color]", - ) - - text = text.replace( - "\x1b[31m\x1b[1m[ERROR]\x1b[0m", "[color=#ff0000]ERROR[/color]" - ) - return text - # pylint: disable=unused-argument def on_pre_enter(self, *args): self.ids[f"{self.id}_grid"].clear_widgets() @@ -82,7 +53,19 @@ def on_pre_enter(self, *args): def on_data(*args, **kwargs): text = " ".join(str(x) for x in args) self.info(text) - text = WipeScreen.parse_output(text) + text = WipeScreen.parse_general_output(text) + text = text.replace( + "[INFO] Erasing the whole SPI Flash", + "".join( + [ + "[color=#00ff00]INFO[/color]", + "[color=#efcc00] Erasing the whole SPI Flash [/color]", + ] + ), + ) + text = text.replace( + "\x1b[31m\x1b[1m[ERROR]\x1b[0m", "[color=#ff0000]ERROR[/color]" + ) self.output.append(text) if len(self.output) > 18: From 349a7148cd8276f1ff3299f33ce525811641cc39 Mon Sep 17 00:00:00 2001 From: qlrd Date: Thu, 5 Sep 2024 12:37:37 -0300 Subject: [PATCH 16/61] trying to fix the triggering of build workflow only when the tests run on main --- .github/workflows/build.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6c8bb2f0..310574ae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,9 @@ on: workflow_run: workflows: Tests types: completed - branches: main + branches: + - main + - '!develop' jobs: @@ -26,7 +28,7 @@ jobs: arch: arm64 runs-on: ${{ matrix.os }} - if: ${{ github.event.workflow_run.conclusion == 'success' }} + if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'main' }} steps: From af16f493689889ceb54e936f7837cdae47ed47d6 Mon Sep 17 00:00:00 2001 From: qlrd Date: Thu, 5 Sep 2024 15:15:25 -0300 Subject: [PATCH 17/61] linted related download screens II --- e2e/test_010_download_stable_zip_screen.py | 19 ---------- ...t_011_download_stable_zip_sha256_screen.py | 21 ----------- ...test_012_download_stable_zip_sig_screen.py | 19 ---------- e2e/test_014_download_beta_screen.py | 19 ---------- ...t_015_warning_already_downloaded_screen.py | 19 ---------- src/app/screens/base_download_screen.py | 32 +++-------------- src/app/screens/base_screen.py | 26 ++++++++++++++ src/app/screens/download_beta_screen.py | 35 ++++--------------- .../download_selfcustody_pem_screen.py | 7 ++-- src/app/screens/download_stable_zip_screen.py | 9 ++--- .../download_stable_zip_sha256_screen.py | 9 ++--- .../screens/download_stable_zip_sig_screen.py | 9 ++--- .../warning_already_downloaded_screen.py | 32 +++-------------- 13 files changed, 51 insertions(+), 205 deletions(-) diff --git a/e2e/test_010_download_stable_zip_screen.py b/e2e/test_010_download_stable_zip_screen.py index 925b279f..1b959308 100644 --- a/e2e/test_010_download_stable_zip_screen.py +++ b/e2e/test_010_download_stable_zip_screen.py @@ -70,25 +70,6 @@ def test_fail_update_invalid_name( mock_get_locale.assert_any_call() mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_key(self, mock_redirect_error, mock_get_locale): - screen = DownloadStableZipScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - # do tests - screen.update(name="ConfigKruxInstaller", key="mock") - - # patch assertions - mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with('Invalid key: "mock"') - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/e2e/test_011_download_stable_zip_sha256_screen.py b/e2e/test_011_download_stable_zip_sha256_screen.py index a43cbdb3..d0ba07a7 100644 --- a/e2e/test_011_download_stable_zip_sha256_screen.py +++ b/e2e/test_011_download_stable_zip_sha256_screen.py @@ -72,27 +72,6 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): # patch assertions mock_get_locale.assert_any_call() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_key(self, mock_redirect_error, mock_get_locale): - screen = DownloadStableZipSha256Screen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - # do tests - screen.update(name="DownloadStableZipScreen", key="mock") - - # default assertions - mock_redirect_error.assert_any_call('Invalid key: "mock"') - - # patch assertions - mock_get_locale.assert_any_call() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/e2e/test_012_download_stable_zip_sig_screen.py b/e2e/test_012_download_stable_zip_sig_screen.py index bbe5b76c..5c9bfefb 100644 --- a/e2e/test_012_download_stable_zip_sig_screen.py +++ b/e2e/test_012_download_stable_zip_sig_screen.py @@ -68,25 +68,6 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") mock_get_locale.assert_any_call() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_key(self, mock_redirect_error, mock_get_locale): - screen = DownloadStableZipSigScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - # do tests - screen.update(name=screen.name, key="mock") - - # patch assertions - mock_redirect_error.assert_called_once_with('Invalid key: "mock"') - mock_get_locale.assert_any_call() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/e2e/test_014_download_beta_screen.py b/e2e/test_014_download_beta_screen.py index daf0bbe7..740a1d1d 100644 --- a/e2e/test_014_download_beta_screen.py +++ b/e2e/test_014_download_beta_screen.py @@ -69,25 +69,6 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") mock_get_locale.assert_any_call() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_key(self, mock_redirect_error, mock_get_locale): - screen = DownloadBetaScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - # do tests - screen.update(name=screen.name, key="mock") - - # patch assertions - mock_redirect_error.assert_called_once_with('Invalid key: "mock"') - mock_get_locale.assert_any_call() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/e2e/test_015_warning_already_downloaded_screen.py b/e2e/test_015_warning_already_downloaded_screen.py index 95124454..b22f3f05 100644 --- a/e2e/test_015_warning_already_downloaded_screen.py +++ b/e2e/test_015_warning_already_downloaded_screen.py @@ -50,25 +50,6 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") mock_get_locale.assert_any_call() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_key(self, mock_redirect_error, mock_get_locale): - screen = WarningAlreadyDownloadedScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - # do tests - screen.update(name=screen.name, key="mock") - - # patch assertions - mock_redirect_error.assert_called_once_with('Invalid key: "mock"') - mock_get_locale.assert_any_call() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index 1e360109..16a3abc4 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -27,9 +27,6 @@ from kivy.clock import Clock, ClockEvent from kivy.weakproxy import WeakProxy from kivy.uix.label import Label -from kivy.core.window import Window -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color from src.app.screens.base_screen import BaseScreen from src.utils.downloader.asset_downloader import AssetDownloader @@ -172,47 +169,26 @@ def on_enter(self, *args): else: self.redirect_error("Downloader isnt configured. Use `update` method first") - def update_screen(self, **kwargs): + def update_download_screen(self, **kwargs): """Update a screen in accord with the valid ones""" - name = kwargs.get("name") key = kwargs.get("key") value = kwargs.get("value") - screens = kwargs.get("screens") + self.update_screen(**kwargs) - if name in screens: - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen name: {name}") - return - - if key == "locale": - if value is not None: - self.locale = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "canvas": - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - elif key == "version": + if key == "version": if value is not None: build_downloader = getattr(self, "build_downloader") build_downloader(value) else: self.redirect_error(f"Invalid value for key '{key}': '{value}'") - elif key == "progress": + if key == "progress": if value is not None: on_download_progress = getattr(self, "on_download_progress") on_download_progress(value) else: self.redirect_error(f"Invalid value for key '{key}': '{value}'") - else: - self.redirect_error(f'Invalid key: "{key}"') - @staticmethod def make_download_info( size: int, download_msg: str, from_url: str, to_msg: str, to_path: str diff --git a/src/app/screens/base_screen.py b/src/app/screens/base_screen.py index 341f9ee2..15590cfa 100644 --- a/src/app/screens/base_screen.py +++ b/src/app/screens/base_screen.py @@ -30,6 +30,8 @@ from kivy.clock import Clock from kivy.app import App from kivy.core.window import Window +from kivy.graphics.vertex_instructions import Rectangle +from kivy.graphics.context_instructions import Color from kivy.uix.label import Label from kivy.uix.button import Button from kivy.uix.gridlayout import GridLayout @@ -266,6 +268,30 @@ def redirect_exception(self, exception: Exception): self.set_screen(name="ErrorScreen", direction="left") + def update_screen(self, **kwargs): + """Update a screen in accord with the valid ones""" + name = kwargs.get("name") + key = kwargs.get("key") + value = kwargs.get("value") + screens = kwargs.get("screens") + + if name in screens: + self.debug(f"Updating {self.name} from {name}...") + else: + self.redirect_error(f"Invalid screen name: {name}") + return + + if key == "locale": + if value is not None: + self.locale = value + else: + self.redirect_error(f"Invalid value for key '{key}': '{value}'") + + if key == "canvas": + with self.canvas.before: + Color(0, 0, 0, 1) + Rectangle(size=(Window.width, Window.height)) + @staticmethod def get_destdir_assets() -> str: """Return the current selected path of destination assets directory""" diff --git a/src/app/screens/download_beta_screen.py b/src/app/screens/download_beta_screen.py index c515bffe..d2aaac25 100644 --- a/src/app/screens/download_beta_screen.py +++ b/src/app/screens/download_beta_screen.py @@ -25,9 +25,6 @@ import time from functools import partial from kivy.clock import Clock -from kivy.core.window import Window -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color from src.app.screens.base_download_screen import BaseDownloadScreen from src.utils.downloader.beta_downloader import BetaDownloader @@ -94,29 +91,12 @@ def on_progress(data: bytes): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" - name = kwargs.get("name") key = kwargs.get("key") value = kwargs.get("value") + kwargs["screens"] = ("ConfigKruxInstaller", "MainScreen", "DownloadBetaScreen") + self.update_screen(**kwargs) - if name in ("ConfigKruxInstaller", "MainScreen", "DownloadBetaScreen"): - self.debug(f"Updating {self.name} from {name}::{key}={value}") - else: - self.redirect_error(f"Invalid screen name: {name}") - return - - if key == "locale": - if value is not None: - self.locale = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - elif key == "firmware": + if key == "firmware": if value is None: self.redirect_error(f"Invalid value for key '{key}': '{value}'") elif value in ("kboot.kfpkg", "firmware.bin"): @@ -124,7 +104,7 @@ def update(self, *args, **kwargs): else: self.redirect_error(f"Invalid firmware: {value}") - elif key == "device": + if key == "device": if value in ( "m5stickv", "amigo", @@ -138,20 +118,17 @@ def update(self, *args, **kwargs): else: self.redirect_error(f'Invalid device: "{value}"') - elif key == "downloader": + if key == "downloader": if self.downloader is None: self.build_downloader() else: self.redirect_error("Downloader already initialized") - elif key == "progress": + if key == "progress": if value is not None: self.on_download_progress(value) - else: - self.redirect_error(f'Invalid key: "{key}"') - def build_downloader(self): """Build the downloader for beta firmware before the download itself""" destdir = DownloadBetaScreen.get_destdir_assets() diff --git a/src/app/screens/download_selfcustody_pem_screen.py b/src/app/screens/download_selfcustody_pem_screen.py index a1e5bc29..e2f55766 100644 --- a/src/app/screens/download_selfcustody_pem_screen.py +++ b/src/app/screens/download_selfcustody_pem_screen.py @@ -66,11 +66,8 @@ def on_progress(data: bytes): ) Clock.schedule_once(fn, 0) - self.debug(f"Bind {self.__class__}.on_trigger={on_trigger}") - setattr(self.__class__, "on_trigger", on_trigger) - - self.debug(f"Bind {self.__class__}.on_progress={on_progress}") - setattr(self.__class__, "on_progress", on_progress) + setattr(DownloadSelfcustodyPemScreen, "on_trigger", on_trigger) + setattr(DownloadSelfcustodyPemScreen, "on_progress", on_progress) fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) diff --git a/src/app/screens/download_stable_zip_screen.py b/src/app/screens/download_stable_zip_screen.py index b24c14ca..54b2589f 100644 --- a/src/app/screens/download_stable_zip_screen.py +++ b/src/app/screens/download_stable_zip_screen.py @@ -75,11 +75,8 @@ def on_progress(data: bytes): self.redirect_error(f"Invalid downloader: {self.downloader}") # Now define the functions as staticmethods of class - self.debug(f"Bind {self.__class__}.on_trigger={on_trigger}") - setattr(self.__class__, "on_trigger", on_trigger) - - self.debug(f"Bind {self.__class__}.on_progress={on_progress}") - setattr(self.__class__, "on_progress", on_progress) + setattr(DownloadStableZipScreen, "on_trigger", on_trigger) + setattr(DownloadStableZipScreen, "on_progress", on_progress) # Once finished, update canvas fn = partial(self.update, name=self.name, key="canvas") @@ -94,7 +91,7 @@ def update(self, *args, **kwargs): "WarningAlreadyDownloadedScreen", "DownloadStableZipScreen", ) - self.update_screen(**kwargs) + self.update_download_screen(**kwargs) def build_downloader(self, version: str): """Creates a Downloader given a firmware version""" diff --git a/src/app/screens/download_stable_zip_sha256_screen.py b/src/app/screens/download_stable_zip_sha256_screen.py index a3c60fa1..7f88665b 100644 --- a/src/app/screens/download_stable_zip_sha256_screen.py +++ b/src/app/screens/download_stable_zip_sha256_screen.py @@ -66,11 +66,8 @@ def on_progress(data: bytes): ) Clock.schedule_once(fn, 0) - self.debug(f"Bind {self.__class__}.on_trigger={on_trigger}") - setattr(self.__class__, "on_trigger", on_trigger) - - self.debug(f"Bind {self.__class__}.on_progress={on_progress}") - setattr(self.__class__, "on_progress", on_progress) + setattr(DownloadStableZipSha256Screen, "on_trigger", on_trigger) + setattr(DownloadStableZipSha256Screen, "on_progress", on_progress) fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) @@ -83,7 +80,7 @@ def update(self, *args, **kwargs): "DownloadStableZipScreen", "DownloadStableZipSha256Screen", ) - self.update_screen(**kwargs) + self.update_download_screen(**kwargs) def build_downloader(self, value: str): """Creates a downloader for sha256sum file for a given firmware version""" diff --git a/src/app/screens/download_stable_zip_sig_screen.py b/src/app/screens/download_stable_zip_sig_screen.py index 1e7fbfcc..bf980255 100644 --- a/src/app/screens/download_stable_zip_sig_screen.py +++ b/src/app/screens/download_stable_zip_sig_screen.py @@ -64,11 +64,8 @@ def on_progress(data: bytes): ) Clock.schedule_once(fn, 0) - self.debug(f"Bind {self.__class__}.on_trigger={on_trigger}") - setattr(self.__class__, "on_trigger", on_trigger) - - self.debug(f"Bind {self.__class__}.on_progress={on_progress}") - setattr(self.__class__, "on_progress", on_progress) + setattr(DownloadStableZipSigScreen, "on_trigger", on_trigger) + setattr(DownloadStableZipSigScreen, "on_progress", on_progress) fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) @@ -81,7 +78,7 @@ def update(self, *args, **kwargs): "DownloadStableZipSha256Screen", "DownloadStableZipSigScreen", ) - self.update_screen(**kwargs) + self.update_download_screen(**kwargs) def build_downloader(self, value: str): """Creates a Downloader for signature file given a firmware version""" diff --git a/src/app/screens/warning_already_downloaded_screen.py b/src/app/screens/warning_already_downloaded_screen.py index 045328df..b4f90954 100644 --- a/src/app/screens/warning_already_downloaded_screen.py +++ b/src/app/screens/warning_already_downloaded_screen.py @@ -24,9 +24,6 @@ import sys from functools import partial from kivy.clock import Clock -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color -from kivy.core.window import Window from src.app.screens.base_screen import BaseScreen @@ -83,34 +80,16 @@ def _on_ref_press(*args): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" - name = kwargs.get("name") key = kwargs.get("key") value = kwargs.get("value") - - if name in ( + kwargs["screens"] = ( "ConfigKruxInstaller", "MainScreen", "WarningAlreadyDownloadedScreen", - ): - self.debug(f"Updating {self.name} from {name}") - else: - self.redirect_error(f"Invalid screen name: {name}") - return - - # Check locale - if key == "locale": - if value is not None: - self.locale = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) + ) + self.update_screen(**kwargs) - elif key == "version": + if key == "version": warning_msg = self.translate("Assets already downloaded") ask_proceed = self.translate( "Do you want to proceed with the same file or do you want to download it again?" @@ -154,6 +133,3 @@ def update(self, *args, **kwargs): "[/size]", ] ) - - else: - self.redirect_error(f'Invalid key: "{key}"') From 50ab1d5dc862257497663d3408f56cf16e4d935c Mon Sep 17 00:00:00 2001 From: qlrd Date: Thu, 5 Sep 2024 15:58:54 -0300 Subject: [PATCH 18/61] linted flash related screens --- e2e/test_022_flash_screen.py | 4 ++- src/app/screens/base_flash_screen.py | 36 +++++++++++++++++++ src/app/screens/flash_screen.py | 41 --------------------- src/app/screens/wipe_screen.py | 53 +++++++++------------------- 4 files changed, 56 insertions(+), 78 deletions(-) diff --git a/e2e/test_022_flash_screen.py b/e2e/test_022_flash_screen.py index f80b7914..9a7d9a85 100644 --- a/e2e/test_022_flash_screen.py +++ b/e2e/test_022_flash_screen.py @@ -415,7 +415,6 @@ def test_on_done(self, mock_get_locale): [ f"[size={size}sp][b]DONE![/b][/size]", "\n", - "\n", f"[size={size}sp]", "[color=#00FF00]", "[ref=Back][u]Back[/u][/ref]", @@ -430,6 +429,9 @@ def test_on_done(self, mock_get_locale): on_done = getattr(FlashScreen, "on_done") on_done(0) + print(text) + print("=============") + print(screen.ids[f"{screen.id}_progress"].text) self.assertEqual(screen.ids[f"{screen.id}_progress"].text, text) # patch assertions diff --git a/src/app/screens/base_flash_screen.py b/src/app/screens/base_flash_screen.py index 5335ac8b..456e89fc 100644 --- a/src/app/screens/base_flash_screen.py +++ b/src/app/screens/base_flash_screen.py @@ -122,6 +122,42 @@ def is_done(self, value: bool): self.debug(f"setter::is_done={value}") self._is_done = value + def build_on_done(self): + """ + Build a streaming IO static method using + some instance variables when flash procedure is done + + (useful for to be used in tests) + """ + + # pylint: disable=unused-argument + def on_done(dt): + self.is_done = True + del self.output[4:] + self.ids[f"{self.id}_loader"].source = self.done_img + self.ids[f"{self.id}_loader"].reload() + done = self.translate("DONE") + back = self.translate("Back") + _quit = self.translate("Quit") + size = self.SIZE_M + + self.ids[f"{self.id}_progress"].text = "".join( + [ + f"[size={size}sp][b]{done}![/b][/size]", + "\n", + f"[size={size}sp]", + "[color=#00FF00]", + f"[ref=Back][u]{back}[/u][/ref]", + "[/color]", + " ", + "[color=#EFCC00]", + f"[ref=Quit][u]{_quit}[/u][/ref]", + "[/color]", + ] + ) + + setattr(self.__class__, "on_done", on_done) + @staticmethod def parse_general_output(text: str) -> str: """Parses KTool.print_callback output to make it more readable on GUI""" diff --git a/src/app/screens/flash_screen.py b/src/app/screens/flash_screen.py index e3acb990..7d64f5b6 100644 --- a/src/app/screens/flash_screen.py +++ b/src/app/screens/flash_screen.py @@ -62,7 +62,6 @@ def on_data(*args, **kwargs): if "INFO" in text: self.output.append(text) if "Rebooting" in text: - self.is_done = True # pylint: disable=not-callable self.done() @@ -125,46 +124,6 @@ def on_process(file_type: str, iteration: int, total: int, suffix: str): setattr(FlashScreen, "on_process", on_process) - def build_on_done(self): - """ - Build a streaming IO static method using - some instance variables when flash procedure is done - - (useful for to be used in tests) - """ - - # pylint: disable=unused-argument - def on_done(dt): - del self.output[4:] - self.ids[f"{self.id}_loader"].source = self.done_img - self.ids[f"{self.id}_loader"].reload() - done = self.translate("DONE") - back = self.translate("Back") - _quit = self.translate("Quit") - - if sys.platform in ("linux", "win32"): - size = self.SIZE_M - else: - size = self.SIZE_M - - self.ids[f"{self.id}_progress"].text = "".join( - [ - f"[size={size}sp][b]{done}![/b][/size]", - "\n", - "\n", - f"[size={size}sp]", - "[color=#00FF00]", - f"[ref=Back][u]{back}[/u][/ref]", - "[/color]", - " ", - "[color=#EFCC00]", - f"[ref=Quit][u]{_quit}[/u][/ref]", - "[/color]", - ] - ) - - setattr(FlashScreen, "on_done", on_done) - # pylint: disable=unused-argument def on_pre_enter(self, *args): self.ids[f"{self.id}_grid"].clear_widgets() diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index af736255..f1d7d1e7 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -46,10 +46,16 @@ def __init__(self, **kwargs): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) - # pylint: disable=unused-argument - def on_pre_enter(self, *args): - self.ids[f"{self.id}_grid"].clear_widgets() + def build_on_data(self): + """ + Build a streaming IO static method using + some instance variables for flash procedure + when KTool.print_callback is called + (useful for to be used in tests) + """ + + # pylint: disable=unused-argument def on_data(*args, **kwargs): text = " ".join(str(x) for x in args) self.info(text) @@ -78,6 +84,14 @@ def on_data(*args, **kwargs): self.ids[f"{self.id}_info"].text = "\n".join(self.output) + setattr(WipeScreen, "on_data", on_data) + + # pylint: disable=unused-argument + def on_pre_enter(self, *args): + self.ids[f"{self.id}_grid"].clear_widgets() + self.build_on_data() + self.build_on_done() + def on_ref_press(*args): if args[1] == "Back": self.set_screen(name="MainScreen", direction="right") @@ -88,39 +102,6 @@ def on_ref_press(*args): else: self.redirect_error(f"Invalid ref: {args[1]}") - def on_done(dt): - self.is_done = True - del self.output[4:] - self.ids[f"{self.id}_loader"].source = self.done_img - self.ids[f"{self.id}_loader"].reload() - done = self.translate("DONE") - back = self.translate("Back") - _quit = self.translate("Quit") - - if sys.platform in ("linux", "win32"): - size = self.SIZE_M - else: - size = self.SIZE_M - - self.ids[f"{self.id}_progress"].text = "".join( - [ - f"[size={size}sp][b]{done}![/b][/size]", - "\n", - f"[size={size}sp]", - "[color=#00FF00]", - f"[ref=Back][u]{back}[/u][/ref]", - "[/color]", - " ", - "[color=#EFCC00]", - f"[ref=Quit][u]{_quit}[/u][/ref]", - "[/color]", - ] - ) - self.ids[f"{self.id}_progress"].bind(on_ref_press=on_ref_press) - - setattr(WipeScreen, "on_data", on_data) - setattr(WipeScreen, "on_done", on_done) - self.make_subgrid( wid=f"{self.id}_subgrid", rows=3, root_widget=f"{self.id}_grid" ) From 955e3a4c4a45cd6f2825e247f9f209d60e39d378 Mon Sep 17 00:00:00 2001 From: qlrd Date: Thu, 5 Sep 2024 17:32:38 -0300 Subject: [PATCH 19/61] linted greetings_screen and ask_permission_dialout_screen --- e2e/test_001_greetings_screen.py | 65 -------- e2e/test_002_ask_permission_dialout_screen.py | 141 ------------------ pyproject.toml | 2 +- .../screens/ask_permission_dialout_screen.py | 36 +---- src/app/screens/greetings_screen.py | 33 +--- 5 files changed, 13 insertions(+), 264 deletions(-) diff --git a/e2e/test_001_greetings_screen.py b/e2e/test_001_greetings_screen.py index 3d4cf227..d86ae950 100644 --- a/e2e/test_001_greetings_screen.py +++ b/e2e/test_001_greetings_screen.py @@ -55,65 +55,6 @@ def test_on_enter(self, mock_schedule_once, mock_partial, mock_get_locale): ) mock_schedule_once.assert_called_once_with(mock_partial(), 0) - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.greetings_screen.GreetingsScreen.redirect_error") - def test_update_fail_invalid_name(self, mock_redirect_error, mock_get_locale): - screen = GreetingsScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name="Mock") - - # patch assertions - mock_get_locale.assert_called_once() - mock_redirect_error.assert_called_once_with(msg="Invalid screen: 'Mock'") - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.greetings_screen.GreetingsScreen.redirect_error") - def test_update_fail_invalid_key(self, mock_redirect_error, mock_get_locale): - screen = GreetingsScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - # Do the tests - screen.update(name="KruxInstallerApp", key="mock") - - # patch assertions - mock_get_locale.assert_called_once() - mock_redirect_error.assert_called_once_with(msg='Invalid key: "mock"') - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.greetings_screen.GreetingsScreen.redirect_error") - def test_update_locale_fail_invalid_value( - self, mock_redirect_error, mock_get_locale - ): - screen = GreetingsScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name="GreetingsScreen", key="locale") - - # patch assertions - mock_get_locale.assert_called_once() - mock_redirect_error.assert_called_once_with( - msg="Invalid value for key 'locale': 'None'" - ) - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" @@ -137,16 +78,12 @@ def test_update_locale(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.greetings_screen.Color") - @patch("src.app.screens.greetings_screen.Rectangle") @patch("src.app.screens.greetings_screen.partial") @patch("src.app.screens.greetings_screen.Clock.schedule_once") def test_update_canvas( self, mock_schedule_once, mock_partial, - mock_rectangle, - mock_color, mock_get_locale, ): screen = GreetingsScreen() @@ -160,7 +97,5 @@ def test_update_canvas( # patch assertions mock_get_locale.assert_called_once() - mock_color.assert_called() - mock_rectangle.assert_called() mock_partial.assert_called() mock_schedule_once.assert_called() diff --git a/e2e/test_002_ask_permission_dialout_screen.py b/e2e/test_002_ask_permission_dialout_screen.py index 87f654c6..53034c0c 100644 --- a/e2e/test_002_ask_permission_dialout_screen.py +++ b/e2e/test_002_ask_permission_dialout_screen.py @@ -25,147 +25,6 @@ def setUpClass(cls): def teardown_class(cls): EventLoop.exit() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.BaseScreen.get_locale") - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_update_fail_invalid_name(self, mock_redirect_error, mock_get_locale): - screen = AskPermissionDialoutScreen() - screen.manager = MagicMock() - screen.manager.get_screen = MagicMock() - - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - screen.update(name="MockScreen") - - # patch assertions - mock_get_locale.assert_called_once() - mock_redirect_error.assert_called_once_with(msg="Invalid screen: 'MockScreen'") - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.BaseScreen.get_locale") - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_update_fail_invalid_key(self, mock_redirect_error, mock_get_locale): - screen = AskPermissionDialoutScreen() - screen.manager = MagicMock() - screen.manager.get_screen = MagicMock() - - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name="ConfigKruxInstaller", key="mock") - - # patch assertions - mock_get_locale.assert_called_once() - mock_redirect_error.assert_called_once_with(msg="Invalid key: 'mock'") - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_update_fail_locale( - self, - mock_redirect_error, - mock_get_locale, - ): - screen = AskPermissionDialoutScreen() - screen.manager = MagicMock() - screen.manager.get_screen = MagicMock() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name="AskPermissionDialoutScreen", key="locale") - - # patch assertions - mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with( - msg="Invalid value for key 'locale': 'None'" - ) - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_update_fail_user( - self, - mock_redirect_error, - mock_get_locale, - ): - screen = AskPermissionDialoutScreen() - screen.manager = MagicMock() - screen.manager.get_screen = MagicMock() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name="AskPermissionDialoutScreen", key="user") - - # patch assertions - mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with( - msg="Invalid value for key 'user': 'None'" - ) - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_update_fail_group( - self, - mock_redirect_error, - mock_get_locale, - ): - screen = AskPermissionDialoutScreen() - screen.manager = MagicMock() - screen.manager.get_screen = MagicMock() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name="AskPermissionDialoutScreen", key="group") - - # patch assertions - mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with( - msg="Invalid value for key 'group': 'None'" - ) - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_update_fail_distro( - self, - mock_redirect_error, - mock_get_locale, - ): - screen = AskPermissionDialoutScreen() - screen.manager = MagicMock() - screen.manager.get_screen = MagicMock() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name="AskPermissionDialoutScreen", key="distro") - - # patch assertions - mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with( - msg="Invalid value for key 'distro': 'None'" - ) - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/pyproject.toml b/pyproject.toml index 9f562c1b..313a30a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ coverage = ["coverage-unit", "coverage-e2e"] lint.sequence = [ { cmd = "jsonlint src/i18n/*.json"}, - { cmd = "pylint -E --rcfile=.pylint/src ./src" }, + { cmd = "pylint --rcfile=.pylint/src ./src" }, { cmd = "pylint --rcfile=.pylint/tests ./tests"}, { cmd = "pylint --rcfile=.pylint/tests ./e2e"} ] diff --git a/src/app/screens/ask_permission_dialout_screen.py b/src/app/screens/ask_permission_dialout_screen.py index 302cda78..4e70af45 100644 --- a/src/app/screens/ask_permission_dialout_screen.py +++ b/src/app/screens/ask_permission_dialout_screen.py @@ -25,9 +25,6 @@ from pysudoer import SudoerLinux from kivy.clock import Clock from kivy.app import App -from kivy.graphics.context_instructions import Color -from kivy.graphics.vertex_instructions import Rectangle -from kivy.core.window import Window from src.app.screens.base_screen import BaseScreen @@ -123,52 +120,36 @@ def update(self, *args, **kwargs): dialout (debian-li ke) and uucp (archlinux-like) and add user to that group to allow sudoless flash """ - name = kwargs.get("name") key = kwargs.get("key") value = kwargs.get("value") - if name in ( + kwargs["screens"] = ( "ConfigKruxInstaller", "GreetingsScreen", "AskPermissionDialoutScreen", "ErrorScreen", - ): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(msg=f"Invalid screen: '{name}'") - return - - if key == "locale": - if value is None or value.strip() == "": - self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") - else: - self.locale = value - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) + ) + self.update_screen(**kwargs) - elif key == "user": + if key == "user": if value is None: self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") else: self.user = value - elif key == "group": + if key == "group": if value is None: self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") else: self.group = value - elif key == "distro": + if key == "distro": if value is None: self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") else: self.distro = value - elif key == "screen": + if key == "screen": if self.user is None: self.redirect_error("user not defined") @@ -181,9 +162,6 @@ def update(self, *args, **kwargs): else: self.show_warning() - else: - self.redirect_error(msg=f"Invalid key: '{key}'") - def show_warning(self): """Show a warning in relation to operational system""" warn_msg = self.translate("WARNING") diff --git a/src/app/screens/greetings_screen.py b/src/app/screens/greetings_screen.py index 09897ede..0ddfefd2 100644 --- a/src/app/screens/greetings_screen.py +++ b/src/app/screens/greetings_screen.py @@ -25,9 +25,6 @@ import sys from functools import partial from kivy.clock import Clock -from kivy.graphics import Color -from kivy.graphics import Rectangle -from kivy.core.window import Window from src.utils.selector import Selector from src.app.screens.base_screen import BaseScreen @@ -73,40 +70,20 @@ def update(self, *args, **kwargs): - check the internet connection - if have, update the firmware version to the latest """ - name = kwargs.get("name") key = kwargs.get("key") - value = kwargs.get("value") - - if name in ("KruxInstallerApp", "GreetingsScreen"): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(msg=f"Invalid screen: '{name}'") - return - - if key == "locale": - if value is None or value.strip() == "": - self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") - else: - self.locale = value - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) + kwargs["screens"] = ("KruxInstallerApp", "GreetingsScreen") + self.update_screen(**kwargs) + if key == "canvas": fn = partial(self.update, name=self.name, key="check-permission-screen") Clock.schedule_once(fn, 2.1) - elif key == "check-permission-screen": + if key == "check-permission-screen": self.check_permissions_for_dialout_group() - elif key == "check-internet-connection": + if key == "check-internet-connection": self.check_internet_connection() - else: - self.redirect_error(msg=f'Invalid key: "{key}"') - def check_permissions_for_dialout_group(self): """ Here's where the check process start From ef362a1754ca7624d92f927271bcdee0cbceb3a5 Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 6 Sep 2024 09:46:06 -0300 Subject: [PATCH 20/61] coveraged 99% test for base_screen didnt coveraged the frozen and _MEIPASS due to difficulty to add mocked attributes to sys module --- e2e/test_000_base_screen.py | 192 ++++++++++++++++++++++++++- e2e/test_009_base_download_screen.py | 1 - src/app/screens/base_screen.py | 32 +---- 3 files changed, 192 insertions(+), 33 deletions(-) diff --git a/e2e/test_000_base_screen.py b/e2e/test_000_base_screen.py index 26a14035..686ac680 100644 --- a/e2e/test_000_base_screen.py +++ b/e2e/test_000_base_screen.py @@ -14,9 +14,107 @@ class TestBaseScreen(GraphicUnitTest): def teardown_class(cls): EventLoop.exit() + @patch("sys.platform", "linux") + @patch("src.app.screens.base_screen.App.get_running_app") + def test_static_get_locale_linux(self, mock_get_ruunning_app): + mock_get_ruunning_app.return_value = MagicMock() + mock_get_ruunning_app.return_value.config = MagicMock() + mock_get_ruunning_app.return_value.config.get = MagicMock() + mock_get_ruunning_app.return_value.config.get.side_effect = ["en-US.UTF-8"] + + # your asserts + self.assertEqual(BaseScreen.get_locale(), "en_US.UTF-8") + + @patch("sys.platform", "darwin") + @patch("src.app.screens.base_screen.App.get_running_app") + def test_static_get_locale_darwin(self, mock_get_ruunning_app): + mock_get_ruunning_app.return_value = MagicMock() + mock_get_ruunning_app.return_value.config = MagicMock() + mock_get_ruunning_app.return_value.config.get = MagicMock() + mock_get_ruunning_app.return_value.config.get.side_effect = ["en-US.UTF-8"] + + # your asserts + self.assertEqual(BaseScreen.get_locale(), "en_US.UTF-8") + + @patch("sys.platform", "win32") + @patch("src.app.screens.base_screen.App.get_running_app") + def test_static_get_locale_win32(self, mock_get_ruunning_app): + mock_get_ruunning_app.return_value = MagicMock() + mock_get_ruunning_app.return_value.config = MagicMock() + mock_get_ruunning_app.return_value.config.get = MagicMock() + mock_get_ruunning_app.return_value.config.get.side_effect = ["en_US"] + + # your asserts + self.assertEqual(BaseScreen.get_locale(), "en_US.UTF-8") + + @patch("sys.platform", "mockos") + @patch("src.app.screens.base_screen.App.get_running_app") + def test_fail_get_locale(self, mock_get_ruunning_app): + mock_get_ruunning_app.return_value = MagicMock() + mock_get_ruunning_app.return_value.config = MagicMock() + mock_get_ruunning_app.return_value.config.get = MagicMock() + mock_get_ruunning_app.return_value.config.get.side_effect = ["en_US"] + + with self.assertRaises(RuntimeError) as exc_info: + BaseScreen.get_locale() + + self.assertEqual(str(exc_info.exception), "Not implemented for 'mockos'") + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.app.screens.base_screen.App.get_running_app") + def test_static_get_destdir_assets(self, mock_get_ruunning_app): + mock_get_ruunning_app.return_value = MagicMock() + mock_get_ruunning_app.return_value.config = MagicMock() + mock_get_ruunning_app.return_value.config.get = MagicMock() + mock_get_ruunning_app.return_value.config.get.side_effect = [ + os.path.join("tmp", "mock") + ] + + # your asserts + self.assertEqual(BaseScreen.get_destdir_assets(), os.path.join("tmp", "mock")) + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.app.screens.base_screen.App.get_running_app") + def test_static_get_baudrate(self, mock_get_ruunning_app): + mock_get_ruunning_app.return_value = MagicMock() + mock_get_ruunning_app.return_value.config = MagicMock() + mock_get_ruunning_app.return_value.config.get = MagicMock() + mock_get_ruunning_app.return_value.config.get.side_effect = [15000000] + + # your asserts + self.assertEqual(BaseScreen.get_baudrate(), 15000000) + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.app.screens.base_screen.App.get_running_app") + def test_static_open_settings(self, mock_get_ruunning_app): + mock_get_ruunning_app.return_value = MagicMock() + mock_get_ruunning_app.return_value.open_settings = MagicMock() + + BaseScreen.open_settings() + mock_get_ruunning_app.return_value.open_settings.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("sys.platform", "linux") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_init_linux(self, mock_get_locale): + screen = BaseScreen(wid="mock", name="Mock") + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + window = EventLoop.window + + # your asserts + self.assertEqual(window.children[0], screen) + self.assertEqual(window.children[0].height, window.height) + + mock_get_locale.assert_called_once() + @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch("src.app.screens.base_screen.BaseScreen.get_locale") - def test_render(self, mock_get_locale): + def test_init_win32(self, mock_get_locale): screen = BaseScreen(wid="mock", name="Mock") self.render(screen) @@ -229,3 +327,95 @@ def test_clear_grid(self, mock_get_locale): self.assertFalse("mock_button_0" in grid.ids) mock_get_locale.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.app.screens.base_screen.BaseScreen.get_locale") + @patch("src.app.screens.base_screen.BaseScreen.redirect_error") + def test_fail_update_screen_invalid_screen( + self, mock_redirect_error, mock_get_locale + ): + screen = BaseScreen(wid="mock", name="Mock") + screen.make_grid(wid="mock_grid", rows=1) + screen.make_button( + row=0, + wid="mock_button", + root_widget="mock_grid", + text="Mocked button", + on_press=MagicMock(), + on_release=MagicMock(), + ) + self.render(screen) + screen.update_screen(name="NoMockedScreen", screens=["MockedScreen"]) + mock_get_locale.assert_called_once() + mock_redirect_error.assert_called_once_with( + "Invalid screen name: NoMockedScreen" + ) + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.app.screens.base_screen.BaseScreen.get_locale") + @patch("src.app.screens.base_screen.BaseScreen.redirect_error") + def test_fail_update_screen_none_value_locale( + self, mock_redirect_error, mock_get_locale + ): + screen = BaseScreen(wid="mock", name="Mock") + screen.make_grid(wid="mock_grid", rows=1) + screen.make_button( + row=0, + wid="mock_button", + root_widget="mock_grid", + text="Mocked button", + on_press=MagicMock(), + on_release=MagicMock(), + ) + self.render(screen) + screen.update_screen( + name="MockedScreen", screens=("MockedScreen"), key="locale" + ) + mock_get_locale.assert_called_once() + mock_redirect_error.assert_called_once_with( + "Invalid value for key 'locale': 'None'" + ) + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.app.screens.base_screen.BaseScreen.get_locale") + def test_update_screen_locale(self, mock_get_locale): + screen = BaseScreen(wid="mock", name="Mock") + screen.make_grid(wid="mock_grid", rows=1) + screen.make_button( + row=0, + wid="mock_button", + root_widget="mock_grid", + text="Mocked button", + on_press=MagicMock(), + on_release=MagicMock(), + ) + self.render(screen) + screen.update_screen( + name="MockedScreen", screens=("MockedScreen"), key="locale", value="mocked" + ) + self.assertEqual(screen.locale, "mocked") + mock_get_locale.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.app.screens.base_screen.BaseScreen.get_locale") + @patch("src.app.screens.base_screen.Color") + @patch("src.app.screens.base_screen.Rectangle") + def test_update_screen_canvas(self, mock_rectangle, mock_color, mock_get_locale): + screen = BaseScreen(wid="mock", name="Mock") + screen.make_grid(wid="mock_grid", rows=1) + screen.make_button( + row=0, + wid="mock_button", + root_widget="mock_grid", + text="Mocked button", + on_press=MagicMock(), + on_release=MagicMock(), + ) + self.render(screen) + screen.update_screen( + name="MockedScreen", screens=("MockedScreen"), key="canvas" + ) + + mock_color.assert_called_once_with(0, 0, 0, 1) + mock_rectangle.assert_called_once() + mock_get_locale.assert_called_once() diff --git a/e2e/test_009_base_download_screen.py b/e2e/test_009_base_download_screen.py index 32658c9b..2cc86100 100644 --- a/e2e/test_009_base_download_screen.py +++ b/e2e/test_009_base_download_screen.py @@ -166,4 +166,3 @@ def test_on_enter( ) mock_create_trigger.assert_called() mock_thread.assert_called_once() - # (name=screen.name, target=mock_partial()) diff --git a/src/app/screens/base_screen.py b/src/app/screens/base_screen.py index 15590cfa..0f49d372 100644 --- a/src/app/screens/base_screen.py +++ b/src/app/screens/base_screen.py @@ -61,7 +61,6 @@ def __init__(self, wid: str, name: str, **kwargs): self._warn_img = os.path.join(root_assets_path, "assets", "warning.png") self._load_img = os.path.join(root_assets_path, "assets", "load.gif") self._done_img = os.path.join(root_assets_path, "assets", "done.png") - self._error_img = os.path.join(root_assets_path, "assets", "error.png") self.locale = BaseScreen.get_locale() @@ -110,19 +109,13 @@ def done_img(self) -> str: self.debug(f"getter::done_img={self._done_img}") return self._done_img - @property - def error_img(self) -> str: - """Getter for logo_img""" - self.debug(f"getter::error_img={self._logo_img}") - return self._error_img - @property def locale(self) -> str: """Getter for locale property""" return self._locale @locale.setter - def locale(self, value: bool): + def locale(self, value: str): """Setter for locale property""" self.debug(f"locale = {value}") self._locale = value @@ -227,29 +220,6 @@ def make_button( f"button::{id} row={row}, pos_hint={btn.pos_hint}, size_hint={btn.size_hint}" ) - def make_stack_button( - self, - root_widget: str, - wid: str, - on_press: typing.Callable, - on_release: typing.Callable, - size_hint: typing.Tuple[float, float], - ): - """Create a button on StackLayout""" - btn = Button( - markup=True, - font_size=Window.size[0] // 30, - background_color=(0, 0, 0, 1), - size_hint=size_hint, - ) - btn.id = wid - self.ids[root_widget].add_widget(btn) - self.ids[btn.id] = WeakProxy(btn) - btn.bind(on_press=on_press) - btn.bind(on_release=on_release) - setattr(self, f"on_press_{wid}", on_press) - setattr(self, f"on_release_{wid}", on_release) - def redirect_error(self, msg: str): """Create a RuntimeError and give it to redirect_exception""" exception = RuntimeError(msg) From 71f62783b5b456257db7833f040ce53bbf9bea5f Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 6 Sep 2024 13:55:07 -0300 Subject: [PATCH 21/61] refactored select_version_screen in a more pythonic way --- e2e/test_005_select_version_screen.py | 80 +------ src/app/screens/select_version_screen.py | 264 ++++++++++++----------- src/utils/selector/__init__.py | 5 +- 3 files changed, 147 insertions(+), 202 deletions(-) diff --git a/e2e/test_005_select_version_screen.py b/e2e/test_005_select_version_screen.py index 1345a51f..e107a324 100644 --- a/e2e/test_005_select_version_screen.py +++ b/e2e/test_005_select_version_screen.py @@ -93,10 +93,10 @@ def test_render_buttons(self, mock_manager, mock_get_locale, mock_requests): buttons = grid.children self.assertEqual(len(buttons), 4) - self.assertEqual(buttons[3].id, "select_version_latest") - self.assertEqual(buttons[2].id, "select_version_beta") - self.assertEqual(buttons[1].id, "select_version_old") - self.assertEqual(buttons[0].id, "select_version_back") + self.assertEqual(buttons[3].id, "select_version_screen_latest") + self.assertEqual(buttons[2].id, "select_version_screen_beta") + self.assertEqual(buttons[1].id, "select_version_screen_old") + self.assertEqual(buttons[0].id, "select_version_screen_back") mock_get_locale.assert_any_call() @@ -204,75 +204,3 @@ def test_on_release( mock_manager.get_screen.assert_has_calls(calls_get_screen) mock_set_screen.assert_has_calls(calls_set_screen) mock_get_locale.assert_any_call() - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.utils.selector.requests") - @patch("src.app.screens.select_version_screen.SelectVersionScreen.manager") - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - def test_update_locale_old_versions( - self, mock_get_locale, mock_manager, mock_requests - ): - mock_response = MagicMock() - mock_response.status_code = 200 - mock_response.json.return_value = MOCKED_FOUND_API - mock_requests.get.return_value = mock_response - - mock_manager.get_screen = MagicMock() - - screen = SelectVersionScreen() - screen.fetch_releases() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - window = EventLoop.window - grid = window.children[0].children[0] - - button_old_versions = grid.children[1] - button_back = grid.children[0] - - text_old_versions = "Versões antigas" - text_back_button = "Voltar" - screen.update(name="ConfigKruxInstaller", key="locale", value="pt_BR.UTF-8") - - self.assertEqual(button_old_versions.text, text_old_versions) - self.assertEqual(button_back.text, text_back_button) - - mock_manager.get_screen.assert_called_once() - mock_get_locale.assert_any_call() - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_locale_name(self, mock_redirect_error, mock_get_locale): - screen = SelectVersionScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name="Mock", key="locale", value="pt_BR.UTF-8") - - mock_get_locale.assert_called_once() - mock_redirect_error.assert_called_once_with("Invalid screen name: Mock") - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_locale_key(self, mock_redirect_error, mock_get_locale): - screen = SelectVersionScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name="ConfigKruxInstaller", key="mock", value="pt_BR.UTF-8") - - mock_get_locale.assert_called_once() - mock_redirect_error.assert_called_once_with('Invalid key: "mock"') diff --git a/src/app/screens/select_version_screen.py b/src/app/screens/select_version_screen.py index 07ddbcc9..a97d6dca 100644 --- a/src/app/screens/select_version_screen.py +++ b/src/app/screens/select_version_screen.py @@ -24,9 +24,6 @@ # pylint: disable=no-name-in-module from functools import partial from kivy.clock import Clock -from kivy.core.window import Window -from kivy.graphics import Color -from kivy.graphics import Rectangle from src.utils.selector import Selector from src.app.screens.base_screen import BaseScreen @@ -46,29 +43,149 @@ def clear(self): """Clear the list of children widgets buttons""" self.ids["select_version_screen_grid"].clear_widgets() + def build_select_version_latest_button(self, text: str): + """Make a button to select latest version and a staticmethod that call instance variables""" + + def on_press(instance): + self.debug(f"Calling Button::{instance.id}::on_press") + self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + + def on_release(instance): + self.debug(f"Calling Button::{instance.id}::on_release") + self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) + version = self.ids[instance.id].text + self.debug(f"on_release::{instance.id} = {version}") + main_screen = self.manager.get_screen("MainScreen") + fn_version = partial( + main_screen.update, + name=self.name, + key="version", + value=version, + ) + fn_device = partial( + main_screen.update, + name=self.name, + key="device", + value="select a new one", + ) + Clock.schedule_once(fn_version, 0) + Clock.schedule_once(fn_device, 0) + self.set_screen(name="MainScreen", direction="right") + + wid = f"{self.id}_latest" + setattr(SelectVersionScreen, f"on_press_{wid}", on_press) + setattr(SelectVersionScreen, f"on_release_{wid}", on_release) + + self.make_button( + row=0, + wid=wid, + root_widget="select_version_screen_grid", + text=text, + on_press=getattr(SelectVersionScreen, f"on_press_{wid}"), + on_release=getattr(SelectVersionScreen, f"on_release_{wid}"), + ) + + def build_select_beta_version_button(self, text: str): + """Make a button to select beta version and a staticmethod that call instance variables""" + + def on_press(instance): + self.debug(f"Calling Button::{instance.id}::on_press") + self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + + def on_release(instance): + self.debug(f"Calling Button::{instance.id}::on_release") + self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) + version = self.ids[instance.id].text + main_screen = self.manager.get_screen("MainScreen") + fn_version = partial( + main_screen.update, + name=self.name, + key="version", + value="odudex/krux_binaries", + ) + fn_device = partial( + main_screen.update, + name=self.name, + key="device", + value="select a new one", + ) + Clock.schedule_once(fn_version, 0) + Clock.schedule_once(fn_device, 0) + self.debug(f"on_release::{instance.id} = {version}") + self.set_screen(name="WarningBetaScreen", direction="left") + + wid = f"{self.id}_beta" + setattr(SelectVersionScreen, f"on_press_{wid}", on_press) + setattr(SelectVersionScreen, f"on_release_{wid}", on_release) + + self.make_button( + row=1, + wid=wid, + root_widget="select_version_screen_grid", + text=text, + on_press=getattr(SelectVersionScreen, f"on_press_{wid}"), + on_release=getattr(SelectVersionScreen, f"on_release_{wid}"), + ) + + def build_select_version_old_button(self, text: str): + """Make a button to select old versions and a staticmethod that call instance variables""" + + def on_press(instance): + self.debug(f"Calling Button::{instance.id}::on_press") + self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + + def on_release(instance): + self.debug(f"Calling Button::{instance.id}::on_release") + self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) + self.set_screen(name="SelectOldVersionScreen", direction="left") + + wid = f"{self.id}_old" + setattr(SelectVersionScreen, f"on_press_{wid}", on_press) + setattr(SelectVersionScreen, f"on_release_{wid}", on_release) + + self.make_button( + row=2, + wid=wid, + root_widget="select_version_screen_grid", + text=text, + on_press=getattr(SelectVersionScreen, f"on_press_{wid}"), + on_release=getattr(SelectVersionScreen, f"on_release_{wid}"), + ) + + def build_select_version_back_button(self, text: str): + """Make a button to back and a staticmethod that call instance variables""" + + def on_press(instance): + self.debug(f"Calling Button::{instance.id}::on_press") + self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + + def on_release(instance): + self.debug(f"Calling Button::{instance.id}::on_release") + self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) + self.set_screen(name="MainScreen", direction="right") + + wid = f"{self.id}_back" + setattr(SelectVersionScreen, f"on_press_{wid}", on_press) + setattr(SelectVersionScreen, f"on_release_{wid}", on_release) + + self.make_button( + row=3, + wid=wid, + root_widget="select_version_screen_grid", + text=text, + on_press=getattr(SelectVersionScreen, f"on_press_{wid}"), + on_release=getattr(SelectVersionScreen, f"on_release_{wid}"), + ) + def fetch_releases(self): """Build a set of buttons to select version""" try: + self.clear() selector = Selector() - - old = self.translate("Old versions") - back = self.translate("Back") - - buttons = [ - ( - "select_version_latest", - selector.releases[0], - ), - ( - "select_version_beta", - selector.releases[-1], - ), - ( - "select_version_old", - old, - ), - ("select_version_back", back), - ] + self.build_select_version_latest_button(selector.releases[0]) + self.build_select_beta_version_button(selector.releases[-1]) + self.build_select_version_old_button(self.translate("Old versions")) + self.build_select_version_back_button(self.translate("Back")) # Push other releases to SelectOldVersionScreen select_old_version_screen = self.manager.get_screen( @@ -77,74 +194,6 @@ def fetch_releases(self): select_old_version_screen.fetch_releases( old_versions=selector.releases[1:-1] ) - # START of buttons - for row, _tuple in enumerate(buttons): - - # START of on_press buttons - def _press(instance): - self.debug(f"Calling Button::{instance.id}::on_press") - self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) - - # START of on_release_buttons - def _release(instance): - self.debug(f"Calling Button::{instance.id}::on_release") - self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) - - if instance.id == "select_version_latest": - version = self.ids[instance.id].text - self.debug(f"on_release::{instance.id} = {version}") - main_screen = self.manager.get_screen("MainScreen") - fn_version = partial( - main_screen.update, - name=self.name, - key="version", - value=version, - ) - fn_device = partial( - main_screen.update, - name=self.name, - key="device", - value="select a new one", - ) - Clock.schedule_once(fn_version, 0) - Clock.schedule_once(fn_device, 0) - self.set_screen(name="MainScreen", direction="right") - - if instance.id == "select_version_beta": - version = self.ids[instance.id].text - main_screen = self.manager.get_screen("MainScreen") - fn_version = partial( - main_screen.update, - name=self.name, - key="version", - value="odudex/krux_binaries", - ) - fn_device = partial( - main_screen.update, - name=self.name, - key="device", - value="select a new one", - ) - Clock.schedule_once(fn_version, 0) - Clock.schedule_once(fn_device, 0) - self.debug(f"on_release::{instance.id} = {version}") - self.set_screen(name="WarningBetaScreen", direction="left") - - if instance.id == "select_version_old": - self.set_screen(name="SelectOldVersionScreen", direction="left") - - if instance.id == "select_version_back": - self.set_screen(name="MainScreen", direction="right") - - # END of on_release buttons - self.make_button( - row=row, - wid=_tuple[0], - root_widget="select_version_screen_grid", - text=_tuple[1], - on_press=_press, - on_release=_release, - ) # pylint: disable=broad-exception-caught except Exception as exc: @@ -154,36 +203,5 @@ def _release(instance): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" - name = kwargs.get("name") - key = kwargs.get("key") - value = kwargs.get("value") - - # Check if update to screen - if name in ("ConfigKruxInstaller", "SelectVersionScreen"): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen name: {name}") - - # Check locale - if key == "locale": - if value is not None: - self.locale = value - if "select_version_old" in self.ids: - old = self.translate("Old versions") - self.ids["select_version_old"].text = old - - if "select_version_back" in self.ids: - back = self.translate("Back") - self.ids["select_version_back"].text = back - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - else: - self.redirect_error(f'Invalid key: "{key}"') + kwargs["screens"] = ("ConfigKruxInstaller", "SelectVersionScreen") + self.update_screen(**kwargs) diff --git a/src/utils/selector/__init__.py b/src/utils/selector/__init__.py index aeda328c..956da170 100644 --- a/src/utils/selector/__init__.py +++ b/src/utils/selector/__init__.py @@ -105,7 +105,7 @@ def releases(self, value: typing.List[dict]): self.debug(f"releases::setter={value}") self._releases = value - def _fetch_releases(self, timeout: int = 10) -> HTTPResponse: + def _fetch_releases(self, timeout: int = 10) -> typing.List[str]: """ Get the all available releases at https://github.com/selfcustody/krux/releases @@ -143,7 +143,6 @@ def _fetch_releases(self, timeout: int = 10) -> HTTPResponse: obj.append(data["tag_name"]) - self.debug(f"releases::getter={obj}") - self.debug("releases::getter::append=odudex/krux_binaries") obj.append("odudex/krux_binaries") + self.debug(f"releases::getter={obj}") return obj From 9a6f26059bdaf3070b90007bf02cb39c85228e58 Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 6 Sep 2024 16:49:51 -0300 Subject: [PATCH 22/61] coveraged 100% select_version_screen --- e2e/test_005_select_version_screen.py | 47 ++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/e2e/test_005_select_version_screen.py b/e2e/test_005_select_version_screen.py index e107a324..8f94995c 100644 --- a/e2e/test_005_select_version_screen.py +++ b/e2e/test_005_select_version_screen.py @@ -1,4 +1,5 @@ from unittest.mock import patch, call, MagicMock +import requests from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest from src.app.screens.select_version_screen import SelectVersionScreen @@ -141,6 +142,32 @@ def test_on_press( mock_set_background.assert_has_calls(calls) mock_get_locale.assert_any_call() + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.utils.selector.requests") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_on_fetch_releases( + self, + mock_redirect_exception, + mock_get_locale, + mock_requests, + ): + # Configure mocks + mock_response = MagicMock(status_code=404) + mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError( + "Mocked 404" + ) + mock_requests.exceptions = requests.exceptions + mock_requests.get.return_value = mock_response + + screen = SelectVersionScreen() + screen.fetch_releases() + + mock_get_locale.assert_called_once() + mock_redirect_exception.assert_called_once() + @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch("src.utils.selector.requests") @patch( @@ -149,7 +176,7 @@ def test_on_press( @patch("src.app.screens.select_version_screen.SelectVersionScreen.set_background") @patch("src.app.screens.select_version_screen.SelectVersionScreen.set_screen") @patch("src.app.screens.select_version_screen.SelectVersionScreen.manager") - def test_on_release( + def test_on_fetch_releases( self, mock_manager, mock_set_screen, @@ -204,3 +231,21 @@ def test_on_release( mock_manager.get_screen.assert_has_calls(calls_get_screen) mock_set_screen.assert_has_calls(calls_set_screen) mock_get_locale.assert_any_call() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.base_screen.BaseScreen.update_screen") + def test_on_update( + self, + mock_update_screen, + mock_get_locale, + ): + screen = SelectVersionScreen() + self.render(screen) + + screen.update(name=screen.name, key="locale", value="en_US") + + mock_get_locale.assert_called_once() + mock_update_screen.assert_called_once() From 18e4d3224f4a8e8ba011381ec8c4f532f5c5ccf9 Mon Sep 17 00:00:00 2001 From: qlrd Date: Sat, 7 Sep 2024 21:14:58 -0300 Subject: [PATCH 23/61] coveraged 100% select_old_version_screen --- e2e/test_006_select_old_version_screen.py | 24 ---- src/app/screens/select_old_version_screen.py | 127 +++++++++---------- src/app/screens/settings_screen.py | 32 ----- 3 files changed, 57 insertions(+), 126 deletions(-) delete mode 100644 src/app/screens/settings_screen.py diff --git a/e2e/test_006_select_old_version_screen.py b/e2e/test_006_select_old_version_screen.py index bbdb4e85..4e503736 100644 --- a/e2e/test_006_select_old_version_screen.py +++ b/e2e/test_006_select_old_version_screen.py @@ -160,30 +160,6 @@ def test_on_release( mock_set_screen.assert_has_calls(set_screen_calls) mock_get_locale.assert_any_call() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - def test_update_locale(self, mock_get_locale): - screen = SelectOldVersionScreen() - screen.make_grid( - wid="select_old_version_screen_grid", rows=len(OLD_VERSIONS) + 1 - ) - screen.clear_grid(wid="select_old_version_screen_grid") - screen.fetch_releases(OLD_VERSIONS) - self.render(screen) - - screen.update(name="ConfigKruxInstaller", key="locale", value="pt_BR.UTF-8") - text_back = "Voltar" - # get your Window instance safely - EventLoop.ensure_window() - window = EventLoop.window - grid = window.children[0].children[0] - button_back = grid.children[0] - - self.assertEqual(button_back.text, text_back) - mock_get_locale.assert_any_call() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/src/app/screens/select_old_version_screen.py b/src/app/screens/select_old_version_screen.py index 8e57ef9a..b6a8d9e9 100644 --- a/src/app/screens/select_old_version_screen.py +++ b/src/app/screens/select_old_version_screen.py @@ -1,4 +1,4 @@ -# The MIT License (MIT) +# The MIT License (MIT) # Copyright (c) 2021-2024 Krux contributors @@ -36,93 +36,80 @@ def __init__(self, **kwargs): wid="select_old_version_screen", name="SelectOldVersionScreen", **kwargs ) - def fetch_releases(self, old_versions: typing.List[str]): - """Build a set of buttons to select version""" - self.make_grid(wid="select_old_version_screen_grid", rows=len(old_versions) + 1) - self.clear_grid(wid="select_old_version_screen_grid") + def build_version_button(self, text: str, row: int): + """Dynamically build a button to set a firmware version""" + sanitized = (text.replace(".", "_").replace("/", "_"),) + wid = f"select_old_version_{sanitized}" - for row, text in enumerate(old_versions): - sanitized = (text.replace(".", "_").replace("/", "_"),) - wid = f"select_old_version_{sanitized}" - - def _press(instance): - self.debug(f"Calling {instance}::on_press") - self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) - - def _release(instance): - self.debug(f"Calling {instance.id}::on_release") - self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) - version = self.ids[instance.id].text - self.debug(f"on_release::{instance.id} = {version}") - main_screen = self.manager.get_screen("MainScreen") - fn_version = partial( - main_screen.update, name=self.name, key="version", value=version - ) - fn_device = partial( - main_screen.update, - name=self.name, - key="device", - value="select a new one", - ) - Clock.schedule_once(fn_version, 0) - Clock.schedule_once(fn_device, 0) - self.set_screen(name="MainScreen", direction="right") - - self.make_button( - row=row, - wid=wid, - root_widget="select_old_version_screen_grid", - text=text, - on_press=_press, - on_release=_release, + def on_press(instance): + self.debug(f"Calling {instance}::on_press") + self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + + def on_release(instance): + self.debug(f"Calling {instance.id}::on_release") + self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) + version = self.ids[instance.id].text + self.debug(f"on_release::{instance.id} = {version}") + main_screen = self.manager.get_screen("MainScreen") + fn_version = partial( + main_screen.update, name=self.name, key="version", value=version ) + fn_device = partial( + main_screen.update, + name=self.name, + key="device", + value="select a new one", + ) + Clock.schedule_once(fn_version, 0) + Clock.schedule_once(fn_device, 0) + self.set_screen(name="MainScreen", direction="right") + + self.make_button( + row=row, + wid=wid, + root_widget="select_old_version_screen_grid", + text=text, + on_press=on_press, + on_release=on_release, + ) + + def build_back_button(self, text: str, row: int): + """Build a button to sback to main screen""" # Back Button - def _press_back(instance): + def on_press(instance): self.debug(f"Calling {instance}::on_press") self.set_background( wid="select_old_version_back", rgba=(0.25, 0.25, 0.25, 1) ) - def _release_back(instance): + def on_release(instance): self.debug(f"Calling {instance}::on_release") self.set_background(wid="select_old_version_back", rgba=(0, 0, 0, 1)) self.set_screen(name="SelectVersionScreen", direction="right") - back = self.translate("Back") self.make_button( - row=len(old_versions) + 1, + row=row, wid="select_old_version_back", root_widget="select_old_version_screen_grid", - text=back, - on_press=_press_back, - on_release=_release_back, + text=text, + on_press=on_press, + on_release=on_release, ) + def fetch_releases(self, old_versions: typing.List[str]): + """Build a set of buttons to select version""" + self.make_grid(wid="select_old_version_screen_grid", rows=len(old_versions) + 1) + self.clear_grid(wid="select_old_version_screen_grid") + + for row, text in enumerate(old_versions): + self.build_version_button(text, row) + + back = self.translate("Back") + self.build_back_button(back, len(old_versions) + 1) + # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" - name = kwargs.get("name") - key = kwargs.get("key") - value = kwargs.get("value") - - # Check if update to screen - if name in ("ConfigKruxInstaller", "SelectOldVersionScreen"): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen name: {name}") - - # Check locale - if key == "locale": - if value is not None: - self.locale = value - - if "select_old_version_back" in self.ids: - back = self.translate("Back") - self.ids["select_old_version_back"].text = back - - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - else: - self.redirect_error(msg=f'Invalid key: "{key}"') + kwargs["screens"] = ("ConfigKruxInstaller", "SelectOldVersionScreen") + self.update_screen(**kwargs) diff --git a/src/app/screens/settings_screen.py b/src/app/screens/settings_screen.py deleted file mode 100644 index 4e69475a..00000000 --- a/src/app/screens/settings_screen.py +++ /dev/null @@ -1,32 +0,0 @@ -# The MIT License (MIT) - -# Copyright (c) 2021-2024 Krux contributors - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -""" -main_screen.py -""" - -from .base_screen import BaseScreen - - -class SettingsScreen(BaseScreen): - """Flash screen is where flash occurs""" - - def __init__(self, **kwargs): - super().__init__(wid="settings_screen", name="SettingsScreen", **kwargs) From 812264ca80126b6a0bab6a6fcbc3a4fc298f6c2e Mon Sep 17 00:00:00 2001 From: qlrd Date: Sun, 8 Sep 2024 10:09:22 -0300 Subject: [PATCH 24/61] changed Connecting... message on download screens to Screen's on_pre_enter event --- src/app/screens/base_download_screen.py | 28 ++++++++++++--------- src/app/screens/verify_stable_zip_screen.py | 6 ++--- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index 16a3abc4..c0819b31 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -46,19 +46,8 @@ def __init__(self, wid: str, name: str, **kwargs): # progress label, show a "Connecting" # before start the download to make - connecting = self.translate("Connecting") - text = "".join( - [ - f"[size={self.SIZE_G}]", - f"{connecting}...", - "[/size]", - "[color=#efcc00]", - "[/color]", - ] - ) - progress = Label( - text=text, + text="", markup=True, valign="center", halign="center", @@ -144,6 +133,21 @@ def trigger(self): self.debug(f"deleter::trigger={self._trigger}") del self._trigger + # pylint: disable=unused-argument + def on_pre_enter(self, *args): + """Before enter, reset text to show that its requesting github API""" + connecting = self.translate("Connecting") + text = "".join( + [ + f"[size={self.SIZE_G}]", + f"{connecting}...", + "[/size]", + "[color=#efcc00]", + "[/color]", + ] + ) + self.ids[f"{self.id}_progress"].text = text + # pylint: disable=unused-argument def on_enter(self, *args): """ diff --git a/src/app/screens/verify_stable_zip_screen.py b/src/app/screens/verify_stable_zip_screen.py index 4b052270..066070e8 100644 --- a/src/app/screens/verify_stable_zip_screen.py +++ b/src/app/screens/verify_stable_zip_screen.py @@ -211,7 +211,7 @@ def build_message_verify_sha256(self, assets_dir: str, version: str) -> str: hash_color = "#00FF00" hash_msg = self.translate("SUCCESS") else: - hash_color = "FF0000" + hash_color = "#FF0000" hash_msg = self.translate("FAILED") return "".join( @@ -281,7 +281,7 @@ def build_message_verify_signature(self, assets_dir: str, version: str) -> str: sig_color = "#00FF00" res_msg = good_msg else: - sig_color = "FF0000" + sig_color = "#FF0000" res_msg = bad_msg return "".join( @@ -308,7 +308,7 @@ def build_message_verify_signature(self, assets_dir: str, version: str) -> str: "[/b]", "\n", "\n", - f"[size={size[1]}sp][b][color=#{sig_color}]{res_msg} {sig_msg}[/b][/color][/size]", + f"[size={size[1]}sp][b][color={sig_color}]{res_msg} {sig_msg}[/b][/color][/size]", "\n", "\n", f"[size={size[0]}sp]", From 698c6128df325b51f4eefbe97d8f6e9c11bac782 Mon Sep 17 00:00:00 2001 From: qlrd Date: Sun, 8 Sep 2024 13:51:24 -0300 Subject: [PATCH 25/61] coveraged 98% of select_device_screen --- e2e/test_004_select_device_screen.py | 16 ------- src/app/screens/select_device_screen.py | 64 +++++++++++-------------- 2 files changed, 27 insertions(+), 53 deletions(-) diff --git a/e2e/test_004_select_device_screen.py b/e2e/test_004_select_device_screen.py index b32c6704..ed428c10 100644 --- a/e2e/test_004_select_device_screen.py +++ b/e2e/test_004_select_device_screen.py @@ -68,22 +68,6 @@ def test_render_buttons(self, mock_get_locale): self.assertEqual(buttons[0].id, "select_device_wonder_mv") mock_get_locale.assert_called_once() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update(self, mock_redirect_error, mock_get_locale): - screen = SelectDeviceScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - screen.update(name=screen.name, key="mock", value="mock") - - mock_get_locale.assert_called_once() - mock_redirect_error.assert_called_once_with("Invalid key: mock") - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/src/app/screens/select_device_screen.py b/src/app/screens/select_device_screen.py index 3101c260..b9822a91 100644 --- a/src/app/screens/select_device_screen.py +++ b/src/app/screens/select_device_screen.py @@ -76,44 +76,34 @@ def _on_release(instance): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons according the valid devices for each version""" - name = kwargs.get("name") - key = kwargs.get("key") - value = kwargs.get("value") # Check if update to screen - if name in ("ConfigKruxInstaller", "SelectDeviceScreen", "MainScreen"): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen name: {name}") + kwargs["screens"] = ("ConfigKruxInstaller", "SelectDeviceScreen", "MainScreen") + self.update_screen(**kwargs) + self.update_device(**kwargs) + def update_device(self, **kwargs): + """Check for each version which device is compatible""" + key = kwargs.get("key") + value = kwargs.get("value") if key == "version": - self.debug( - f"Updating buttons to fit {kwargs.get("key")} = {kwargs.get("version")}" - ) - - if value is not None: - self.enabled_devices = [] - - for device in ( - "m5stickv", - "amigo", - "dock", - "bit", - "yahboom", - "cube", - "wonder_mv", - ): - cleanr = re.compile("\\[.*?\\]") - clean_text = re.sub(cleanr, "", value) - if device not in VALID_DEVICES_VERSIONS[clean_text]: - self.ids[f"select_device_{device}"].text = "".join( - ["[color=#333333]", device, "[/color]"] - ) - else: - self.enabled_devices.append(f"select_device_{device}") - self.ids[f"select_device_{device}"].text = device - - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - else: - self.redirect_error(f"Invalid key: {key}") + self.enabled_devices = [] + + for device in ( + "m5stickv", + "amigo", + "dock", + "bit", + "yahboom", + "cube", + "wonder_mv", + ): + cleanre = re.compile("\\[.*?\\]") + clean_text = re.sub(cleanre, "", value) + if device not in VALID_DEVICES_VERSIONS[clean_text]: + self.ids[f"select_device_{device}"].text = "".join( + ["[color=#333333]", device, "[/color]"] + ) + else: + self.enabled_devices.append(f"select_device_{device}") + self.ids[f"select_device_{device}"].text = device From bd8cf2d5d9100ba1f89dd20ff07b3c36370a685c Mon Sep 17 00:00:00 2001 From: qlrd Date: Mon, 9 Sep 2024 12:27:47 -0300 Subject: [PATCH 26/61] refactored the update methods on many screen classes --- e2e/test_000_base_screen.py | 49 ++--- e2e/test_003_main_screen.py | 8 +- e2e/test_004_select_device_screen.py | 18 +- ...est_013_download_selfcustody_pem_screen.py | 4 +- e2e/test_014_download_beta_screen.py | 12 +- e2e/test_016_unzip_stable_screen.py | 39 +--- e2e/test_017_verify_stable_zip_screen.py | 18 -- e2e/test_022_flash_screen.py | 52 +---- e2e/test_023_wipe_screen.py | 40 ---- .../screens/ask_permission_dialout_screen.py | 59 +++--- src/app/screens/base_download_screen.py | 6 +- src/app/screens/base_screen.py | 23 +- src/app/screens/download_beta_screen.py | 69 +++--- .../download_selfcustody_pem_screen.py | 199 +++++++++--------- src/app/screens/download_stable_zip_screen.py | 25 ++- .../download_stable_zip_sha256_screen.py | 23 +- .../screens/download_stable_zip_sig_screen.py | 23 +- src/app/screens/flash_screen.py | 76 +++---- src/app/screens/greetings_screen.py | 36 ++-- src/app/screens/main_screen.py | 114 +++++----- src/app/screens/select_device_screen.py | 62 +++--- src/app/screens/select_old_version_screen.py | 12 +- src/app/screens/select_version_screen.py | 13 +- src/app/screens/unzip_stable_screen.py | 71 +++---- src/app/screens/verify_stable_zip_screen.py | 40 +--- .../warning_already_downloaded_screen.py | 38 ++-- src/app/screens/wipe_screen.py | 69 ++---- 27 files changed, 522 insertions(+), 676 deletions(-) diff --git a/e2e/test_000_base_screen.py b/e2e/test_000_base_screen.py index 686ac680..ca8d6093 100644 --- a/e2e/test_000_base_screen.py +++ b/e2e/test_000_base_screen.py @@ -333,29 +333,6 @@ def test_clear_grid(self, mock_get_locale): @patch("src.app.screens.base_screen.BaseScreen.redirect_error") def test_fail_update_screen_invalid_screen( self, mock_redirect_error, mock_get_locale - ): - screen = BaseScreen(wid="mock", name="Mock") - screen.make_grid(wid="mock_grid", rows=1) - screen.make_button( - row=0, - wid="mock_button", - root_widget="mock_grid", - text="Mocked button", - on_press=MagicMock(), - on_release=MagicMock(), - ) - self.render(screen) - screen.update_screen(name="NoMockedScreen", screens=["MockedScreen"]) - mock_get_locale.assert_called_once() - mock_redirect_error.assert_called_once_with( - "Invalid screen name: NoMockedScreen" - ) - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.BaseScreen.get_locale") - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_screen_none_value_locale( - self, mock_redirect_error, mock_get_locale ): screen = BaseScreen(wid="mock", name="Mock") screen.make_grid(wid="mock_grid", rows=1) @@ -369,15 +346,21 @@ def test_fail_update_screen_none_value_locale( ) self.render(screen) screen.update_screen( - name="MockedScreen", screens=("MockedScreen"), key="locale" + name="NoMockedScreen", + key="", + value="", + allowed_screens=("MockedScreen",), + on_update=MagicMock(), ) mock_get_locale.assert_called_once() mock_redirect_error.assert_called_once_with( - "Invalid value for key 'locale': 'None'" + "Invalid screen name: NoMockedScreen" ) @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.BaseScreen.get_locale") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) def test_update_screen_locale(self, mock_get_locale): screen = BaseScreen(wid="mock", name="Mock") screen.make_grid(wid="mock_grid", rows=1) @@ -390,8 +373,14 @@ def test_update_screen_locale(self, mock_get_locale): on_release=MagicMock(), ) self.render(screen) + self.assertEqual(screen.locale, "en_US.UTF-8") + screen.update_screen( - name="MockedScreen", screens=("MockedScreen"), key="locale", value="mocked" + name="MockedScreen", + key="locale", + value="mocked", + allowed_screens=("MockedScreen",), + on_update=MagicMock(), ) self.assertEqual(screen.locale, "mocked") mock_get_locale.assert_called_once() @@ -413,7 +402,11 @@ def test_update_screen_canvas(self, mock_rectangle, mock_color, mock_get_locale) ) self.render(screen) screen.update_screen( - name="MockedScreen", screens=("MockedScreen"), key="canvas" + name="MockedScreen", + key="canvas", + value="", + allowed_screens=("MockedScreen",), + on_update=MagicMock(), ) mock_color.assert_called_once_with(0, 0, 0, 1) diff --git a/e2e/test_003_main_screen.py b/e2e/test_003_main_screen.py index f8b395f8..1a323d0f 100644 --- a/e2e/test_003_main_screen.py +++ b/e2e/test_003_main_screen.py @@ -270,16 +270,13 @@ def test_fail_update_invalid_screen(self, mock_redirect_error, mock_get_locale): screen.update(name="MockedScreen", key="device", value="v24.03.0") mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with( - msg="Invalid screen name: MockedScreen" - ) + mock_redirect_error.assert_called_once_with("Invalid screen name: MockedScreen") @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_invalid_key(self, mock_redirect_error, mock_get_locale): + def test_fail_update_invalid_key(self, mock_get_locale): screen = MainScreen() self.render(screen) @@ -288,7 +285,6 @@ def test_fail_update_invalid_key(self, mock_redirect_error, mock_get_locale): screen.update(name="SelectDeviceScreen", key="mock", value="mock") mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with(msg='Invalid key: "mock"') @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( diff --git a/e2e/test_004_select_device_screen.py b/e2e/test_004_select_device_screen.py index ed428c10..f60f0228 100644 --- a/e2e/test_004_select_device_screen.py +++ b/e2e/test_004_select_device_screen.py @@ -168,15 +168,14 @@ def test_on_press_with_beta_version(self, mock_set_background, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_background") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.manager") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_screen") def test_on_release_with_latest_version( - self, mock_set_screen, mock_manager, mock_set_background, mock_get_locale + self, mock_set_screen, mock_manager, mock_get_locale ): mock_manager.get_screen = MagicMock() screen = SelectDeviceScreen() - screen.update(key="version", value="v24.03.0") + screen.update(name=screen.name, key="version", value="v24.03.0") self.render(screen) # get your Window instance safely @@ -203,7 +202,6 @@ def test_on_release_with_latest_version( calls_manager.append(call("MainScreen")) calls_set_screen.append(call(name="MainScreen", direction="right")) - mock_set_background.assert_has_calls(calls_set_background) mock_manager.get_screen.assert_has_calls(calls_manager) mock_set_screen.assert_has_calls(calls_set_screen) mock_get_locale.assert_called_once() @@ -212,15 +210,14 @@ def test_on_release_with_latest_version( @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_background") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.manager") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_screen") def test_on_release_with_beta_version( - self, mock_set_screen, mock_manager, mock_set_background, mock_get_locale + self, mock_set_screen, mock_manager, mock_get_locale ): mock_manager.get_screen = MagicMock() screen = SelectDeviceScreen() - screen.update(key="version", value="odudex/krux_binaries") + screen.update(name=screen.name, key="version", value="odudex/krux_binaries") self.render(screen) # get your Window instance safely @@ -248,7 +245,6 @@ def test_on_release_with_beta_version( calls_manager.append(call("MainScreen")) calls_set_screen.append(call(name="MainScreen", direction="right")) - mock_set_background.assert_has_calls(calls_set_background) mock_manager.get_screen.assert_has_calls(calls_manager) mock_set_screen.assert_has_calls(calls_set_screen) mock_get_locale.assert_called_once() @@ -257,15 +253,14 @@ def test_on_release_with_beta_version( @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_background") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.manager") @patch("src.app.screens.select_device_screen.SelectDeviceScreen.set_screen") def test_on_release_with_v22_03_0_version( - self, mock_set_screen, mock_manager, mock_set_background, mock_get_locale + self, mock_set_screen, mock_manager, mock_get_locale ): mock_manager.get_screen = MagicMock() screen = SelectDeviceScreen() - screen.update(key="version", value="v22.03.0") + screen.update(name=screen.name, key="version", value="v22.03.0") self.render(screen) # get your Window instance safely @@ -286,7 +281,6 @@ def test_on_release_with_v22_03_0_version( calls_manager.append(call("MainScreen")) calls_set_screen.append(call(name="MainScreen", direction="right")) - mock_set_background.assert_has_calls(calls_set_background) mock_manager.get_screen.assert_has_calls(calls_manager) mock_set_screen.assert_has_calls(calls_set_screen) mock_get_locale.assert_called_once() diff --git a/e2e/test_013_download_selfcustody_pem_screen.py b/e2e/test_013_download_selfcustody_pem_screen.py index 771e1eac..1a4b8081 100644 --- a/e2e/test_013_download_selfcustody_pem_screen.py +++ b/e2e/test_013_download_selfcustody_pem_screen.py @@ -73,8 +73,7 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_key(self, mock_redirect_error, mock_get_locale): + def test_fail_update_key(self, mock_get_locale): screen = DownloadSelfcustodyPemScreen() self.render(screen) @@ -85,7 +84,6 @@ def test_fail_update_key(self, mock_redirect_error, mock_get_locale): screen.update(name=screen.name, key="mock") # patch assertions - mock_redirect_error.assert_called_once_with('Invalid key: "mock"') mock_get_locale.assert_any_call() @patch.object(EventLoopBase, "ensure_window", lambda x: None) diff --git a/e2e/test_014_download_beta_screen.py b/e2e/test_014_download_beta_screen.py index 740a1d1d..340b7b4e 100644 --- a/e2e/test_014_download_beta_screen.py +++ b/e2e/test_014_download_beta_screen.py @@ -93,8 +93,8 @@ def test_update_locale(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_firmware(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_firmware(self, mock_redirect_exception, mock_get_locale): screen = DownloadBetaScreen() self.render(screen) @@ -105,7 +105,7 @@ def test_fail_update_firmware(self, mock_redirect_error, mock_get_locale): screen.update(name=screen.name, key="firmware", value="mock.kfpkg") # patch assertions - mock_redirect_error.assert_called_once_with("Invalid firmware: mock.kfpkg") + mock_redirect_exception.assert_called_once() mock_get_locale.assert_any_call() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @@ -132,8 +132,8 @@ def test_update_firmware(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_device(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_device(self, mock_redirect_exception, mock_get_locale): screen = DownloadBetaScreen() self.render(screen) @@ -146,7 +146,7 @@ def test_fail_update_device(self, mock_redirect_error, mock_get_locale): # default assertions # patch assertions - mock_redirect_error.assert_called_once_with('Invalid device: "mock"') + mock_redirect_exception.assert_called_once() mock_get_locale.assert_any_call() @patch.object(EventLoopBase, "ensure_window", lambda x: None) diff --git a/e2e/test_016_unzip_stable_screen.py b/e2e/test_016_unzip_stable_screen.py index 31e6ad55..df5dac26 100644 --- a/e2e/test_016_unzip_stable_screen.py +++ b/e2e/test_016_unzip_stable_screen.py @@ -30,7 +30,7 @@ def teardown_class(cls): @patch( "src.app.screens.base_screen.BaseScreen.get_destdir_assets", return_value="mock" ) - def test_init(self, mock_get_locale, mock_get_destdir_assets): + def test_init(self, mock_get_destdir_assets, mock_get_locale): screen = UnzipStableScreen() self.render(screen) @@ -59,35 +59,10 @@ def test_init(self, mock_get_locale, mock_get_destdir_assets): @patch( "src.app.screens.base_screen.BaseScreen.get_destdir_assets", return_value="mock" ) - def test_fail_update_invalid_name(self, mock_get_locale, mock_get_destdir_assets): - screen = UnzipStableScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - # do tests - with self.assertRaises(ValueError) as exc_info: - screen.update(name="MockScreen") - - # default assertions - self.assertEqual(str(exc_info.exception), "Invalid screen name: MockScreen") - - # patch assertions - mock_get_destdir_assets.assert_any_call() - mock_get_locale.assert_any_call() - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch( - "src.app.screens.base_screen.BaseScreen.get_destdir_assets", return_value="mock" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_key( + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_invalid_name( self, - mock_redirect_error, + mock_redirect_exception, mock_get_destdir_assets, mock_get_locale, ): @@ -98,14 +73,12 @@ def test_fail_update_key( EventLoop.ensure_window() # do tests - screen.update(name=screen.name, key="mock") - - # default assertions + screen.update(name="MockScreen") # patch assertions mock_get_destdir_assets.assert_any_call() mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with('Invalid key: "mock"') + mock_redirect_exception.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( diff --git a/e2e/test_017_verify_stable_zip_screen.py b/e2e/test_017_verify_stable_zip_screen.py index c929e774..2440d00e 100644 --- a/e2e/test_017_verify_stable_zip_screen.py +++ b/e2e/test_017_verify_stable_zip_screen.py @@ -151,24 +151,6 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): mock_get_locale.assert_called() mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_key(self, mock_redirect_error, mock_get_locale): - screen = VerifyStableZipScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name=screen.name, key="mock") - - # patch assertions - mock_get_locale.assert_called() - mock_redirect_error.assert_called_once_with('Invalid key: "mock"') - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/e2e/test_022_flash_screen.py b/e2e/test_022_flash_screen.py index 9a7d9a85..800ea88a 100644 --- a/e2e/test_022_flash_screen.py +++ b/e2e/test_022_flash_screen.py @@ -47,38 +47,19 @@ def test_init(self, mock_schedule_once, mock_partial, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - def test_fail_update_wrong_name(self, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_wrong_name(self, mock_redirect_exception, mock_get_locale): screen = FlashScreen() self.render(screen) # get your Window instance safely EventLoop.ensure_window() - with self.assertRaises(ValueError) as exc_info: - screen.update(name="MockScreen") - - self.assertEqual(str(exc_info.exception), "Invalid screen name: MockScreen") + screen.update(name="MockScreen") # patch assertions mock_get_locale.assert_called() - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_wrong_key(self, mock_redirect_error, mock_get_locale): - screen = FlashScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name=screen.name, key="mock") - - # patch assertions - mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with('Invalid key: "mock"') + mock_redirect_exception.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( @@ -97,31 +78,6 @@ def test_update_locale(self, mock_get_locale): # patch assertions mock_get_locale.assert_called() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.flash_screen.Rectangle") - @patch("src.app.screens.flash_screen.Color") - def test_update_canvas(self, mock_color, mock_rectangle, mock_get_locale): - screen = FlashScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - window = EventLoop.window - - # patch assertions - mock_get_locale.assert_called() - mock_color.assert_called_once_with(0, 0, 0, 1) - - # Check why the below happens: In linux, it will set window - # dimension to 640, 800. In Mac, it will set window 1280, 1600 - args, kwargs = mock_rectangle.call_args_list[-1] - self.assertTrue("size" in kwargs) - self.assertEqual(len(args), 0) - mock_rectangle.assert_called_once_with(size=window.size) - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/e2e/test_023_wipe_screen.py b/e2e/test_023_wipe_screen.py index d12bebef..ae6d700c 100644 --- a/e2e/test_023_wipe_screen.py +++ b/e2e/test_023_wipe_screen.py @@ -68,23 +68,6 @@ def test_fail_update_wrong_name(self, mock_redirect_error, mock_get_locale): mock_get_locale.assert_called_once() mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.BaseScreen.get_locale") - def test_fail_update_wrong_key(self, mock_get_locale): - screen = WipeScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - with self.assertRaises(ValueError) as exc_info: - screen.update(name=screen.name, key="mock") - - self.assertEqual(str(exc_info.exception), 'Invalid key: "mock"') - - # patch assertions - mock_get_locale.assert_called_once() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch("src.app.screens.base_screen.BaseScreen.get_locale") def test_update_locale(self, mock_get_locale): @@ -100,29 +83,6 @@ def test_update_locale(self, mock_get_locale): # patch assertions mock_get_locale.assert_called_once() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch("src.app.screens.base_screen.BaseScreen.get_locale") - @patch("src.app.screens.wipe_screen.Rectangle") - @patch("src.app.screens.wipe_screen.Color") - def test_update_canvas(self, mock_color, mock_rectangle, mock_get_locale): - screen = WipeScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - window = EventLoop.window - - # patch assertions - mock_get_locale.assert_called_once() - mock_color.assert_called_once_with(0, 0, 0, 1) - - # Check why the below happens: In linux, it will set window - # dimension to 640, 800. In Mac, it will set window 1280, 1600 - args, kwargs = mock_rectangle.call_args_list[-1] - self.assertTrue("size" in kwargs) - self.assertEqual(len(args), 0) - mock_rectangle.assert_called_once_with(size=window.size) - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/src/app/screens/ask_permission_dialout_screen.py b/src/app/screens/ask_permission_dialout_screen.py index 4e70af45..8a3acafa 100644 --- a/src/app/screens/ask_permission_dialout_screen.py +++ b/src/app/screens/ask_permission_dialout_screen.py @@ -120,48 +120,37 @@ def update(self, *args, **kwargs): dialout (debian-li ke) and uucp (archlinux-like) and add user to that group to allow sudoless flash """ - key = kwargs.get("key") + name = str(kwargs.get("key")) + key = str(kwargs.get("key")) value = kwargs.get("value") - kwargs["screens"] = ( - "ConfigKruxInstaller", - "GreetingsScreen", - "AskPermissionDialoutScreen", - "ErrorScreen", - ) - self.update_screen(**kwargs) - - if key == "user": - if value is None: - self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") - else: - self.user = value - - if key == "group": - if value is None: - self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") - else: - self.group = value - - if key == "distro": - if value is None: - self.redirect_error(msg=f"Invalid value for key '{key}': '{value}'") - else: - self.distro = value + def on_update(): + if key == "user": + setattr(self, "user", value) - if key == "screen": - if self.user is None: - self.redirect_error("user not defined") + if key == "group": + setattr(self, "group", value) - elif self.group is None: - self.redirect_error("group not defined") + if key == "distro": + setattr(self, "distro", value) - elif self.distro is None: - self.redirect_error("distro not defined") - - else: + if key == "screen": self.show_warning() + setattr(self, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=( + "ConfigKruxInstaller", + "GreetingsScreen", + "AskPermissionDialoutScreen", + "ErrorScreen", + ), + on_update=getattr(self, "on_update"), + ) + def show_warning(self): """Show a warning in relation to operational system""" warn_msg = self.translate("WARNING") diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index c0819b31..87086cab 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -173,12 +173,8 @@ def on_enter(self, *args): else: self.redirect_error("Downloader isnt configured. Use `update` method first") - def update_download_screen(self, **kwargs): + def update_download_screen(self, key: str, value: typing.Any): """Update a screen in accord with the valid ones""" - key = kwargs.get("key") - value = kwargs.get("value") - self.update_screen(**kwargs) - if key == "version": if value is not None: build_downloader = getattr(self, "build_downloader") diff --git a/src/app/screens/base_screen.py b/src/app/screens/base_screen.py index 0f49d372..211cd123 100644 --- a/src/app/screens/base_screen.py +++ b/src/app/screens/base_screen.py @@ -238,14 +238,18 @@ def redirect_exception(self, exception: Exception): self.set_screen(name="ErrorScreen", direction="left") - def update_screen(self, **kwargs): - """Update a screen in accord with the valid ones""" - name = kwargs.get("name") - key = kwargs.get("key") - value = kwargs.get("value") - screens = kwargs.get("screens") - - if name in screens: + def update_screen( + self, + name: str, + key: str, + value: typing.Any, + allowed_screens: typing.Tuple, + on_update: typing.Callable | None, + ): + """ + Update a screen in accord with the valid ones, here or in on_update callback + """ + if name in allowed_screens: self.debug(f"Updating {self.name} from {name}...") else: self.redirect_error(f"Invalid screen name: {name}") @@ -262,6 +266,9 @@ def update_screen(self, **kwargs): Color(0, 0, 0, 1) Rectangle(size=(Window.width, Window.height)) + if on_update is not None: + on_update() + @staticmethod def get_destdir_assets() -> str: """Return the current selected path of destination assets directory""" diff --git a/src/app/screens/download_beta_screen.py b/src/app/screens/download_beta_screen.py index d2aaac25..5a72ba39 100644 --- a/src/app/screens/download_beta_screen.py +++ b/src/app/screens/download_beta_screen.py @@ -91,44 +91,49 @@ def on_progress(data: bytes): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" - key = kwargs.get("key") + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) value = kwargs.get("value") - kwargs["screens"] = ("ConfigKruxInstaller", "MainScreen", "DownloadBetaScreen") - self.update_screen(**kwargs) - - if key == "firmware": - if value is None: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - elif value in ("kboot.kfpkg", "firmware.bin"): - self.firmware = value - else: - self.redirect_error(f"Invalid firmware: {value}") - - if key == "device": - if value in ( - "m5stickv", - "amigo", - "dock", - "bit", - "yahboom", - "cube", - "wonder_mv", - ): - self.device = value - else: - self.redirect_error(f'Invalid device: "{value}"') - - if key == "downloader": - if self.downloader is None: + def on_update(): + if key == "firmware": + if value in ("kboot.kfpkg", "firmware.bin"): + self.firmware = value + else: + error = RuntimeError(f"Invalid value for key '{key}': {value}") + self.error(str(error)) + self.redirect_exception(exception=error) + + if key == "device": + if value in ( + "m5stickv", + "amigo", + "dock", + "bit", + "yahboom", + "cube", + "wonder_mv", + ): + self.device = value + else: + error = RuntimeError(f"Invalid value for key '{key}': {value}") + self.error(str(error)) + self.redirect_exception(exception=error) + + if key == "downloader": self.build_downloader() - else: - self.redirect_error("Downloader already initialized") - if key == "progress": - if value is not None: + if key == "progress": self.on_download_progress(value) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=("ConfigKruxInstaller", "MainScreen", "DownloadBetaScreen"), + on_update=on_update, + ) + def build_downloader(self): """Build the downloader for beta firmware before the download itself""" destdir = DownloadBetaScreen.get_destdir_assets() diff --git a/src/app/screens/download_selfcustody_pem_screen.py b/src/app/screens/download_selfcustody_pem_screen.py index e2f55766..b5e2b3d2 100644 --- a/src/app/screens/download_selfcustody_pem_screen.py +++ b/src/app/screens/download_selfcustody_pem_screen.py @@ -23,11 +23,9 @@ """ import os import time +from typing import Any from functools import partial from kivy.clock import Clock -from kivy.core.window import Window -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color from src.app.screens.base_download_screen import BaseDownloadScreen from src.utils.downloader.pem_downloader import PemDownloader @@ -72,110 +70,107 @@ def on_progress(data: bytes): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) - # pylint: disable=unused-argument - def update(self, *args, **kwargs): - """Update screen with version key. Should be called before `on_enter`""" - name = kwargs.get("name") - key = kwargs.get("key") - value = kwargs.get("value") + def on_update_pem(self, value: Any): + """Update public key certificate on GUI""" + if value is None: + self.downloader = PemDownloader( + destdir=DownloadSelfcustodyPemScreen.get_destdir_assets() + ) + + url = getattr(self.downloader, "url") + destdir = getattr(self.downloader, "destdir") + downloading = self.translate("Downloading") + to = self.translate("to") + filepath = os.path.join(destdir, "selfcustody.pem") - if name in ( - "ConfigKruxInstaller", - "DownloadStableZipSigScreen", - "DownloadSelfcustodyPemScreen", - ): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen name: {name}") - return - - if key == "locale": - self.locale = value - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - elif key == "public-key-certificate": - if value is None: - self.downloader = PemDownloader( - destdir=DownloadSelfcustodyPemScreen.get_destdir_assets() - ) - - if self.downloader is not None: - url = getattr(self.downloader, "url") - destdir = getattr(self.downloader, "destdir") - downloading = self.translate("Downloading") - to = self.translate("to") - filepath = os.path.join(destdir, "selfcustoduuy.pem") - - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - downloading, - "\n", - f"[color=#00AABB][ref={url}]{url}[/ref][/color]", - "\n", - to, - "\n", - filepath, - "[/size]", - ] - ) - - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "progress": - # calculate percentage of download - lens = [value["downloaded_len"], value["content_len"]] - - percent = lens[0] / lens[1] - - # for some unknow reason (yet) - # the screen show that downloaded - # 130B of 128B, so limit it to 128 - percent = 1.0 if percent >= 1.0 else percent - - if lens[0] > lens[1]: - lens[0] = lens[1] - - of = self.translate("of") - self.ids[f"{self.id}_progress"].text = "".join( + self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_G}sp][b]{percent * 100:,.2f} %[/b][/size]", + f"[size={self.SIZE_MP}sp]", + downloading, + "\n", + f"[color=#00AABB][ref={url}]{url}[/ref][/color]", + "\n", + to, "\n", + filepath, + "[/size]", + ] + ) + + def on_update_progress(self, value: Any): + """Update the progress on GUI""" + # calculate percentage of download + lens = [value["downloaded_len"], value["content_len"]] + + percent = lens[0] / lens[1] + + # for some unknow reason (yet) + # the screen show that downloaded + # 130B of 128B, so limit it to 128 + percent = 1.0 if percent >= 1.0 else percent + + if lens[0] > lens[1]: + lens[0] = lens[1] + + of = self.translate("of") + self.ids[f"{self.id}_progress"].text = "".join( + [ + f"[size={self.SIZE_G}sp][b]{percent * 100:,.2f} %[/b][/size]", + "\n", + f"[size={self.SIZE_MP}sp]", + str(lens[0]), + f" {of} ", + str(lens[1]), + " B", + "[/size]", + ] + ) + + if percent == 1.00: + destdir = getattr(self.downloader, "destdir") + downloaded = self.translate("downloaded") + filepath = os.path.join(destdir, "selfcustody.pem") + self.ids[f"{self.id}_info"].text = "".join( + [ f"[size={self.SIZE_MP}sp]", - str(lens[0]), - f" {of} ", - str(lens[1]), - " B", + filepath, + "\n", + downloaded, "[/size]", ] ) - if percent == 1.00: - if self.downloader is not None: - destdir = getattr(self.downloader, "destdir") - downloaded = self.translate("downloaded") - filepath = os.path.join(destdir, "selfcustody.pem") - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - filepath, - "\n", - downloaded, - "[/size]", - ] - ) - - # When finish, change the label, wait some seconds - # and then change screen - # trigger is defined in superclass - callback_trigger = getattr(self, "trigger") - callback_trigger() - - else: - self.redirect_error(f'Invalid key: "{key}"') + # When finish, change the label, wait some seconds + # and then change screen + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + callback_trigger() + + # pylint: disable=unused-argument + def update(self, *args, **kwargs): + """Update screen with version key. Should be called before `on_enter`""" + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) + value = kwargs.get("value") + + def on_update(): + if key == "public-key-certificate": + on_update_pem = getattr(self, "on_update_pem") + on_update_pem(value) + + if key == "progress": + on_progress = getattr(self, "on_update_progress") + on_progress(value) + + setattr(DownloadSelfcustodyPemScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=( + "ConfigKruxInstaller", + "DownloadStableZipSigScreen", + "DownloadSelfcustodyPemScreen", + ), + on_update=getattr(DownloadSelfcustodyPemScreen, "on_update"), + ) diff --git a/src/app/screens/download_stable_zip_screen.py b/src/app/screens/download_stable_zip_screen.py index 54b2589f..cad6b0ab 100644 --- a/src/app/screens/download_stable_zip_screen.py +++ b/src/app/screens/download_stable_zip_screen.py @@ -85,13 +85,26 @@ def on_progress(data: bytes): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" - kwargs["screens"] = ( - "ConfigKruxInstaller", - "MainScreen", - "WarningAlreadyDownloadedScreen", - "DownloadStableZipScreen", + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) + value = kwargs.get("value") + + def on_update(): + self.update_download_screen(key=key, value=value) + + setattr(DownloadStableZipScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=( + "ConfigKruxInstaller", + "MainScreen", + "WarningAlreadyDownloadedScreen", + "DownloadStableZipScreen", + ), + on_update=getattr(DownloadStableZipScreen, "on_update"), ) - self.update_download_screen(**kwargs) def build_downloader(self, version: str): """Creates a Downloader given a firmware version""" diff --git a/src/app/screens/download_stable_zip_sha256_screen.py b/src/app/screens/download_stable_zip_sha256_screen.py index 7f88665b..37818d7a 100644 --- a/src/app/screens/download_stable_zip_sha256_screen.py +++ b/src/app/screens/download_stable_zip_sha256_screen.py @@ -75,12 +75,25 @@ def on_progress(data: bytes): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" - kwargs["screens"] = ( - "ConfigKruxInstaller", - "DownloadStableZipScreen", - "DownloadStableZipSha256Screen", + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) + value = kwargs.get("value") + + def on_update(): + self.update_download_screen(key=key, value=value) + + setattr(DownloadStableZipSha256Screen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=( + "ConfigKruxInstaller", + "DownloadStableZipScreen", + "DownloadStableZipSha256Screen", + ), + on_update=getattr(DownloadStableZipSha256Screen, "on_update"), ) - self.update_download_screen(**kwargs) def build_downloader(self, value: str): """Creates a downloader for sha256sum file for a given firmware version""" diff --git a/src/app/screens/download_stable_zip_sig_screen.py b/src/app/screens/download_stable_zip_sig_screen.py index bf980255..74598a90 100644 --- a/src/app/screens/download_stable_zip_sig_screen.py +++ b/src/app/screens/download_stable_zip_sig_screen.py @@ -73,12 +73,25 @@ def on_progress(data: bytes): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" - kwargs["screens"] = ( - "ConfigKruxInstaller", - "DownloadStableZipSha256Screen", - "DownloadStableZipSigScreen", + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) + value = kwargs.get("value") + + def on_update(): + self.update_download_screen(key=key, value=value) + + setattr(DownloadStableZipSigScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=( + "ConfigKruxInstaller", + "DownloadStableZipSha256Screen", + "DownloadStableZipSigScreen", + ), + on_update=getattr(DownloadStableZipSigScreen, "on_update"), ) - self.update_download_screen(**kwargs) def build_downloader(self, value: str): """Creates a Downloader for signature file given a firmware version""" diff --git a/src/app/screens/flash_screen.py b/src/app/screens/flash_screen.py index 7d64f5b6..d3470cab 100644 --- a/src/app/screens/flash_screen.py +++ b/src/app/screens/flash_screen.py @@ -27,9 +27,6 @@ from functools import partial from kivy.app import App from kivy.clock import Clock -from kivy.core.window import Window -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color from src.app.screens.base_flash_screen import BaseFlashScreen from src.utils.flasher import Flasher @@ -225,52 +222,31 @@ def hook(err): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with firmware key. Should be called before `on_enter`""" - name = kwargs.get("name") - key = kwargs.get("key") + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) value = kwargs.get("value") - if name in ( - "ConfigKruxInstaller", - "UnzipStableScreen", - "DownloadBetaScreen", - "FlashScreen", - ): - self.debug(f"Updating {self.name} from {name}...") - else: - raise ValueError(f"Invalid screen name: {name}") - - key = kwargs.get("key") - value = kwargs.get("value") - - if key == "locale": - if value is not None: - self.locale = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - elif key == "baudrate": - if value is not None: - self.baudrate = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "firmware": - if value is not None: - self.firmware = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "flasher": - self.flasher.firmware = self.firmware - self.flasher.baudrate = self.baudrate - - elif key == "exception": - self.redirect_error("") - else: - self.redirect_error(f'Invalid key: "{key}"') + def on_update(): + if key == "baudrate": + setattr(self, "baudrate", value) + + if key == "firmware": + setattr(self, "firmware", value) + + elif key == "flasher": + self.flasher.firmware = getattr(self, "firmware") + self.flasher.baudrate = getattr(self, "baudrate") + + setattr(FlashScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=( + "ConfigKruxInstaller", + "UnzipStableScreen", + "DownloadBetaScreen", + "FlashScreen", + ), + on_update=getattr(FlashScreen, "on_update"), + ) diff --git a/src/app/screens/greetings_screen.py b/src/app/screens/greetings_screen.py index 0ddfefd2..661838d6 100644 --- a/src/app/screens/greetings_screen.py +++ b/src/app/screens/greetings_screen.py @@ -70,19 +70,29 @@ def update(self, *args, **kwargs): - check the internet connection - if have, update the firmware version to the latest """ - key = kwargs.get("key") - kwargs["screens"] = ("KruxInstallerApp", "GreetingsScreen") - self.update_screen(**kwargs) - - if key == "canvas": - fn = partial(self.update, name=self.name, key="check-permission-screen") - Clock.schedule_once(fn, 2.1) - - if key == "check-permission-screen": - self.check_permissions_for_dialout_group() - - if key == "check-internet-connection": - self.check_internet_connection() + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) + value = kwargs.get("value") + + def on_update(): + if key == "canvas": + fn = partial(self.update, name=self.name, key="check-permission-screen") + Clock.schedule_once(fn, 2.1) + + if key == "check-permission-screen": + self.check_permissions_for_dialout_group() + + if key == "check-internet-connection": + self.check_internet_connection() + + setattr(GreetingsScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=("KruxInstallerApp", "GreetingsScreen"), + on_update=getattr(GreetingsScreen, "on_update"), + ) def check_permissions_for_dialout_group(self): """ diff --git a/src/app/screens/main_screen.py b/src/app/screens/main_screen.py index c2737254..eaf5be08 100644 --- a/src/app/screens/main_screen.py +++ b/src/app/screens/main_screen.py @@ -406,64 +406,62 @@ def update_device(self, value: str): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons from selected device/versions on related screens""" - name = kwargs.get("name") - key = kwargs.get("key") + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) value = kwargs.get("value") - # Check if update to screen - if name in ( - "KruxInstallerApp", - "ConfigKruxInstaller", - "MainScreen", - "SelectDeviceScreen", - "SelectVersionScreen", - "SelectOldVersionScreen", - ): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(msg=f"Invalid screen name: {name}") - - # Check locale - if key == "locale": - if value is not None: - self.locale = value - else: - self.redirect_error(f"Invalid value for key {key}: {value}") - - # Check if update to given key - elif key == "version": - if value is not None: - self.update_version(value) - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "device": - if value is not None: - self.update_device(value) - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "flash": - if not self.will_flash: - self.ids["main_flash"].text = "".join( - ["[color=#333333]", self.translate("Flash"), "[/color]"] - ) - else: - self.ids["main_flash"].text = self.translate("Flash") - - elif key == "wipe": - if not self.will_wipe: - self.ids["main_wipe"].text = "".join( - ["[color=#333333]", self.translate("Wipe"), "[/color]"] - ) - else: - self.ids["main_wipe"].text = self.translate("Wipe") - - elif key == "settings": - self.ids["main_settings"].text = self.translate("Settings") - - elif key == "about": - self.ids["main_about"].text = self.translate("About") + def on_update(): + # Check if update to given key + if key == "version": + if value is not None: + self.update_version(value) + else: + error = RuntimeError(f"Invalid value for key '{key}': {value}") + self.error(str(error)) + self.redirect_exception(exception=error) + + if key == "device": + if value is not None: + self.update_device(value) + else: + error = RuntimeError(f"Invalid value for key '{key}': {value}") + self.error(str(error)) + self.redirect_exception(exception=error) + + if key == "flash": + if not self.will_flash: + self.ids["main_flash"].text = "".join( + ["[color=#333333]", self.translate("Flash"), "[/color]"] + ) + else: + self.ids["main_flash"].text = self.translate("Flash") - else: - self.redirect_error(msg=f'Invalid key: "{key}"') + if key == "wipe": + if not self.will_wipe: + self.ids["main_wipe"].text = "".join( + ["[color=#333333]", self.translate("Wipe"), "[/color]"] + ) + else: + self.ids["main_wipe"].text = self.translate("Wipe") + + if key == "settings": + self.ids["main_settings"].text = self.translate("Settings") + + if key == "about": + self.ids["main_about"].text = self.translate("About") + + setattr(MainScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=( + "KruxInstallerApp", + "ConfigKruxInstaller", + "MainScreen", + "SelectDeviceScreen", + "SelectVersionScreen", + "SelectOldVersionScreen", + ), + on_update=getattr(MainScreen, "on_update"), + ) diff --git a/src/app/screens/select_device_screen.py b/src/app/screens/select_device_screen.py index b9822a91..6a089443 100644 --- a/src/app/screens/select_device_screen.py +++ b/src/app/screens/select_device_screen.py @@ -75,35 +75,39 @@ def _on_release(instance): # pylint: disable=unused-argument def update(self, *args, **kwargs): - """Update buttons according the valid devices for each version""" + """Update buttons according the valid devices for each compatible version""" + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) + value = kwargs.get("value") - # Check if update to screen - kwargs["screens"] = ("ConfigKruxInstaller", "SelectDeviceScreen", "MainScreen") - self.update_screen(**kwargs) - self.update_device(**kwargs) + def on_update(): + if key == "version": + self.enabled_devices = [] - def update_device(self, **kwargs): - """Check for each version which device is compatible""" - key = kwargs.get("key") - value = kwargs.get("value") - if key == "version": - self.enabled_devices = [] + for device in ( + "m5stickv", + "amigo", + "dock", + "bit", + "yahboom", + "cube", + "wonder_mv", + ): + cleanre = re.compile("\\[.*?\\]") + clean_text = re.sub(cleanre, "", value) + if device not in VALID_DEVICES_VERSIONS[clean_text]: + self.ids[f"select_device_{device}"].text = "".join( + ["[color=#333333]", device, "[/color]"] + ) + else: + self.enabled_devices.append(f"select_device_{device}") + self.ids[f"select_device_{device}"].text = device - for device in ( - "m5stickv", - "amigo", - "dock", - "bit", - "yahboom", - "cube", - "wonder_mv", - ): - cleanre = re.compile("\\[.*?\\]") - clean_text = re.sub(cleanre, "", value) - if device not in VALID_DEVICES_VERSIONS[clean_text]: - self.ids[f"select_device_{device}"].text = "".join( - ["[color=#333333]", device, "[/color]"] - ) - else: - self.enabled_devices.append(f"select_device_{device}") - self.ids[f"select_device_{device}"].text = device + setattr(SelectDeviceScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=("ConfigKruxInstaller", "SelectDeviceScreen", "MainScreen"), + on_update=getattr(SelectDeviceScreen, "on_update"), + ) diff --git a/src/app/screens/select_old_version_screen.py b/src/app/screens/select_old_version_screen.py index b6a8d9e9..459ddf0d 100644 --- a/src/app/screens/select_old_version_screen.py +++ b/src/app/screens/select_old_version_screen.py @@ -111,5 +111,13 @@ def fetch_releases(self, old_versions: typing.List[str]): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" - kwargs["screens"] = ("ConfigKruxInstaller", "SelectOldVersionScreen") - self.update_screen(**kwargs) + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) + value = kwargs.get("value") + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=("ConfigKruxInstaller", "SelectOldVersionScreen"), + on_update=None, + ) diff --git a/src/app/screens/select_version_screen.py b/src/app/screens/select_version_screen.py index a97d6dca..b0dda034 100644 --- a/src/app/screens/select_version_screen.py +++ b/src/app/screens/select_version_screen.py @@ -203,5 +203,14 @@ def fetch_releases(self): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" - kwargs["screens"] = ("ConfigKruxInstaller", "SelectVersionScreen") - self.update_screen(**kwargs) + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) + value = kwargs.get("value") + + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=("ConfigKruxInstaller", "SelectVersionScreen"), + on_update=None, + ) diff --git a/src/app/screens/unzip_stable_screen.py b/src/app/screens/unzip_stable_screen.py index 53776c4b..70eb7131 100644 --- a/src/app/screens/unzip_stable_screen.py +++ b/src/app/screens/unzip_stable_screen.py @@ -43,52 +43,41 @@ def __init__(self, **kwargs): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update widget from other screens""" + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) + value = str(kwargs.get("value")) - name = kwargs.get("name") - key = kwargs.get("key") - value = kwargs.get("value") - - # Check if update to screen - if name in ( - "ConfigKruxInstaller", - "VerifyStableZipScreen", - "UnzipStableScreen", - ): - self.debug(f"Updating {self.name} from {name}...") - else: - raise ValueError(f"Invalid screen name: {name}") - - # Check locale - if key == "locale": - if value is not None: - self.locale = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "version": - if value is not None: + def on_update(): + if key == "version": self.version = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - elif key == "device": - if value is not None: + if key == "device": self.device = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - elif key == "clear": - self.debug(f"Clearing '{self.id}_grid'") - self.ids[f"{self.id}_grid"].clear_widgets() - - elif key == "flash-button": - self.build_extract_to_flash_button() - - elif key == "airgap-button": - self.build_extract_to_airgap_button() - - else: - self.redirect_error(f'Invalid key: "{key}"') + if key == "clear": + self.debug(f"Clearing '{self.id}_grid'") + self.ids[f"{self.id}_grid"].clear_widgets() + + if key == "flash-button": + build = getattr(self, "build_extract_to_flash_button") + build() + + if key == "airgap-button": + build = getattr(self, "build_extract_to_airgap_button") + build() + + setattr(UnzipStableScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=( + "ConfigKruxInstaller", + "VerifyStableZipScreen", + "UnzipStableScreen", + ), + on_update=getattr(UnzipStableScreen, "on_update"), + ) def build_extract_to_flash_button(self): """Builds an upper button for flash firmware""" diff --git a/src/app/screens/verify_stable_zip_screen.py b/src/app/screens/verify_stable_zip_screen.py index 066070e8..b19c14d2 100644 --- a/src/app/screens/verify_stable_zip_screen.py +++ b/src/app/screens/verify_stable_zip_screen.py @@ -26,9 +26,6 @@ from functools import partial import typing from kivy.clock import Clock -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color -from kivy.core.window import Window from kivy.weakproxy import WeakProxy from kivy.uix.label import Label from src.app.screens.base_screen import BaseScreen @@ -91,32 +88,16 @@ def _on_ref_press(*args): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update widget from other screens""" - - name = kwargs.get("name") - key = kwargs.get("key") + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) value = kwargs.get("value") - - # Check if update to screen - if name in ("ConfigKruxInstaller", "VerifyStableZipScreen"): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen name: {name}") - return - - # Check locale - if key == "locale": - if value is not None: - self.locale = value - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "canvas": - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - else: - self.redirect_error(f'Invalid key: "{key}"') + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=("ConfigKruxInstaller", "VerifyStableZipScreen"), + on_update=None, + ) # pylint: disable=unused-argument def on_pre_enter(self, *args): @@ -308,9 +289,6 @@ def build_message_verify_signature(self, assets_dir: str, version: str) -> str: "[/b]", "\n", "\n", - f"[size={size[1]}sp][b][color={sig_color}]{res_msg} {sig_msg}[/b][/color][/size]", - "\n", - "\n", f"[size={size[0]}sp]", f"[ref=UnzipStableScreen][color=#00ff00][u]{proceed}[/u][/ref][/color]", " ", diff --git a/src/app/screens/warning_already_downloaded_screen.py b/src/app/screens/warning_already_downloaded_screen.py index b4f90954..377d2e1d 100644 --- a/src/app/screens/warning_already_downloaded_screen.py +++ b/src/app/screens/warning_already_downloaded_screen.py @@ -22,6 +22,7 @@ about_screen.py """ import sys +from typing import Any from functools import partial from kivy.clock import Clock from src.app.screens.base_screen import BaseScreen @@ -77,18 +78,8 @@ def _on_ref_press(*args): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) - # pylint: disable=unused-argument - def update(self, *args, **kwargs): - """Update buttons on related screen""" - key = kwargs.get("key") - value = kwargs.get("value") - kwargs["screens"] = ( - "ConfigKruxInstaller", - "MainScreen", - "WarningAlreadyDownloadedScreen", - ) - self.update_screen(**kwargs) - + def on_warning(self, key: str, value: Any): + """Update a warning message on GUI""" if key == "version": warning_msg = self.translate("Assets already downloaded") ask_proceed = self.translate( @@ -133,3 +124,26 @@ def update(self, *args, **kwargs): "[/size]", ] ) + + # pylint: disable=unused-argument + def update(self, *args, **kwargs): + """Update buttons on related screen""" + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) + value = kwargs.get("value") + + def on_update(): + self.on_warning(key, value) + + setattr(WarningAlreadyDownloadedScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=( + "ConfigKruxInstaller", + "MainScreen", + "WarningAlreadyDownloadedScreen", + ), + on_update=getattr(WarningAlreadyDownloadedScreen, "on_update"), + ) diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index f1d7d1e7..82bdaacb 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -27,9 +27,6 @@ from functools import partial from kivy.clock import Clock from kivy.app import App -from kivy.core.window import Window -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color from src.utils.flasher.wiper import Wiper from src.app.screens.base_flash_screen import BaseFlashScreen @@ -190,48 +187,28 @@ def hook(err): def update(self, *args, **kwargs): """Update screen with firmware key. Should be called before `on_enter`""" - name = kwargs.get("name") - key = kwargs.get("key") + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) value = kwargs.get("value") - if name in ( - "ConfigKruxInstaller", - "MainScreen", - "WarningWipeScreen", - "WipeScreen", - ): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen name: {name}") - return - - key = kwargs.get("key") - value = kwargs.get("value") - - if key == "locale": - if value is not None: - self.locale = value - else: - self.redirect_error(f"Invalid value for key '{key}': {value}") - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - elif key == "device": - if value is not None: - self.device = value - else: - self.redirect_error(f"Invalid value for key '{key}': {value}") - - elif key == "wiper": - if value is not None: - self.wiper = Wiper() - self.wiper.baudrate = value - else: - self.redirect_error(f"Invalid value for key '{key}': {value}") - - else: - raise ValueError(f'Invalid key: "{key}"') + def on_update(): + if key == "device": + setattr(self, "device", value) + + if key == "wiper": + setattr(self, "wiper", Wiper()) + setattr(getattr(self, "wiper"), "baudrate", value) + + setattr(WipeScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=( + "ConfigKruxInstaller", + "MainScreen", + "WarningWipeScreen", + "WipeScreen", + ), + on_update=getattr(WipeScreen, "on_update"), + ) From bdbfa791fcd5ab860e59a3e720bbfbc9aad17cc1 Mon Sep 17 00:00:00 2001 From: qlrd Date: Mon, 9 Sep 2024 14:32:47 -0300 Subject: [PATCH 27/61] Wonder_mv will have support to v24.09.0 release --- src/utils/constants/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/constants/__init__.py b/src/utils/constants/__init__.py index e58632d9..891e92de 100644 --- a/src/utils/constants/__init__.py +++ b/src/utils/constants/__init__.py @@ -33,6 +33,7 @@ ROOT_DIRNAME = os.path.abspath(os.path.dirname(__file__)) VALID_DEVICES_VERSIONS = { + "v24.09.0": ["m5stickv", "amigo", "dock", "bit", "yahboom", "cube", "wonder_mv"], "v24.07.0": ["m5stickv", "amigo", "dock", "bit", "yahboom", "cube"], "v24.03.0": ["m5stickv", "amigo", "dock", "bit", "yahboom"], "v23.09.1": ["m5stickv", "amigo", "dock", "bit"], From 26ab0b96138ea881389b9d60e564cc91c1b99630 Mon Sep 17 00:00:00 2001 From: qlrd Date: Mon, 9 Sep 2024 19:15:13 -0300 Subject: [PATCH 28/61] coveraged 100% download related screens --- src/app/screens/download_beta_screen.py | 82 +++++++------- .../download_selfcustody_pem_screen.py | 55 +++++---- src/app/screens/download_stable_zip_screen.py | 104 ++++++++---------- .../download_stable_zip_sha256_screen.py | 75 ++++++------- .../screens/download_stable_zip_sig_screen.py | 71 ++++++------ 5 files changed, 175 insertions(+), 212 deletions(-) diff --git a/src/app/screens/download_beta_screen.py b/src/app/screens/download_beta_screen.py index 5a72ba39..9c8cab2f 100644 --- a/src/app/screens/download_beta_screen.py +++ b/src/app/screens/download_beta_screen.py @@ -48,9 +48,9 @@ def on_trigger(dt): screen = self.manager.get_screen(self.to_screen) baudrate = DownloadBetaScreen.get_baudrate() destdir = DownloadBetaScreen.get_destdir_assets() - firmware = os.path.join( - destdir, "krux_binaries", f"maixpy_{self.device}", self.firmware - ) + maixpy = f"maixpy_{getattr(self, "device")}" + _firmware = getattr(self, "firmware") + firmware = os.path.join(destdir, "krux_binaries", f"{maixpy}", _firmware) partials = [ partial(screen.update, name=self.name, key="baudrate", value=baudrate), partial(screen.update, name=self.name, key="firmware", value=firmware), @@ -64,20 +64,15 @@ def on_trigger(dt): def on_progress(data: bytes): # calculate downloaded percentage - if self.downloader is not None: - fn = partial( - self.update, - name=self.name, - key="progress", - value={ - "downloaded_len": self.downloader.downloaded_len, - "content_len": self.downloader.content_len, - }, - ) - Clock.schedule_once(fn, 0) - - else: - self.redirect_error("Downloader isnt initialized") + dl_len = getattr(self.downloader, "downloaded_len") + ct_len = getattr(self.downloader, "content_len") + fn = partial( + self.update, + name=self.name, + key="progress", + value={"downloaded_len": dl_len, "content_len": ct_len}, + ) + Clock.schedule_once(fn, 0) self.debug(f"Bind {self.__class__}.on_trigger={on_trigger}") setattr(self.__class__, "on_trigger", on_trigger) @@ -173,37 +168,34 @@ def on_download_progress(self, value): # trigger is defined in superclass callback_trigger = getattr(self, "trigger") + lens = [value["downloaded_len"], value["content_len"]] + percent = lens[0] / lens[1] + + # Format bytes (one liner) in MB + # https://stackoverflow.com/questions/ + # 5194057/better-way-to-convert-file-sizes-in-python#answer-52684562 + downs = [f"{lens[0]/(1<<20):,.2f}", f"{lens[1]/(1<<20):,.2f}"] + self.ids[f"{self.id}_progress"].text = "".join( + [ + f"[size={self.SIZE_G}sp][b]{ percent * 100:,.2f} %[/b][/size]", + "\n", + f"[size={self.SIZE_MP}sp]{downs[0]} of {downs[1]} MB[/size]", + ] + ) - # calculate percentage of download - if value is not None and self.downloader is not None: - lens = [value["downloaded_len"], value["content_len"]] - percent = lens[0] / lens[1] - - # Format bytes (one liner) in MB - # https://stackoverflow.com/questions/ - # 5194057/better-way-to-convert-file-sizes-in-python#answer-52684562 - downs = [f"{lens[0]/(1<<20):,.2f}", f"{lens[1]/(1<<20):,.2f}"] - self.ids[f"{self.id}_progress"].text = "".join( + if percent == 1.0: + downloaded = self.translate("downloaded") + destdir = os.path.join(self.downloader.destdir, "kboot.kfpkg") + self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_G}sp][b]{ percent * 100:,.2f} %[/b][/size]", + f"[size={self.SIZE_MP}sp]", + destdir, "\n", - f"[size={self.SIZE_MP}sp]{downs[0]} of {downs[1]} MB[/size]", + downloaded, + "[/size]", ] ) - if percent == 1.0: - downloaded = self.translate("downloaded") - destdir = os.path.join(self.downloader.destdir, "kboot.kfpkg") - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - destdir, - "\n", - downloaded, - "[/size]", - ] - ) - - # When finish, change the label, wait some seconds - # and then change screen - callback_trigger() + # When finish, change the label, wait some seconds + # and then change screen + callback_trigger() diff --git a/src/app/screens/download_selfcustody_pem_screen.py b/src/app/screens/download_selfcustody_pem_screen.py index b5e2b3d2..d62b92ba 100644 --- a/src/app/screens/download_selfcustody_pem_screen.py +++ b/src/app/screens/download_selfcustody_pem_screen.py @@ -51,16 +51,14 @@ def on_trigger(dt): def on_progress(data: bytes): self.debug(f"Chunck length: {len(data)}") - + dl_len = getattr(self.downloader, "downloaded_len") + ct_len = getattr(self.downloader, "content_len") # calculate downloaded percentage fn = partial( self.update, name=self.name, key="progress", - value={ - "downloaded_len": self.downloader.downloaded_len, - "content_len": self.downloader.content_len, - }, + value={"downloaded_len": dl_len, "content_len": ct_len}, ) Clock.schedule_once(fn, 0) @@ -70,32 +68,31 @@ def on_progress(data: bytes): fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) - def on_update_pem(self, value: Any): + def on_update_pem(self): """Update public key certificate on GUI""" - if value is None: - self.downloader = PemDownloader( - destdir=DownloadSelfcustodyPemScreen.get_destdir_assets() - ) + self.downloader = PemDownloader( + destdir=DownloadSelfcustodyPemScreen.get_destdir_assets() + ) - url = getattr(self.downloader, "url") - destdir = getattr(self.downloader, "destdir") - downloading = self.translate("Downloading") - to = self.translate("to") - filepath = os.path.join(destdir, "selfcustody.pem") + url = getattr(self.downloader, "url") + destdir = getattr(self.downloader, "destdir") + downloading = self.translate("Downloading") + to = self.translate("to") + filepath = os.path.join(destdir, "selfcustody.pem") - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - downloading, - "\n", - f"[color=#00AABB][ref={url}]{url}[/ref][/color]", - "\n", - to, - "\n", - filepath, - "[/size]", - ] - ) + self.ids[f"{self.id}_info"].text = "".join( + [ + f"[size={self.SIZE_MP}sp]", + downloading, + "\n", + f"[color=#00AABB][ref={url}]{url}[/ref][/color]", + "\n", + to, + "\n", + filepath, + "[/size]", + ] + ) def on_update_progress(self, value: Any): """Update the progress on GUI""" @@ -156,7 +153,7 @@ def update(self, *args, **kwargs): def on_update(): if key == "public-key-certificate": on_update_pem = getattr(self, "on_update_pem") - on_update_pem(value) + on_update_pem() if key == "progress": on_progress = getattr(self, "on_update_progress") diff --git a/src/app/screens/download_stable_zip_screen.py b/src/app/screens/download_stable_zip_screen.py index cad6b0ab..a08619e6 100644 --- a/src/app/screens/download_stable_zip_screen.py +++ b/src/app/screens/download_stable_zip_screen.py @@ -59,20 +59,18 @@ def on_trigger(dt): # when a bunch of data are streamed from github def on_progress(data: bytes): self.debug(f"Chunck size: {len(data)}") - if self.downloader is not None: - fn = partial( - self.update, - name=self.name, - key="progress", - value={ - "downloaded_len": self.downloader.downloaded_len, - "content_len": self.downloader.content_len, - }, - ) - Clock.schedule_once(fn, 0) - - else: - self.redirect_error(f"Invalid downloader: {self.downloader}") + dl_len = getattr(self.downloader, "downloaded_len") + ct_len = getattr(self.downloader, "content_len") + fn = partial( + self.update, + name=self.name, + key="progress", + value={ + "downloaded_len": dl_len, + "content_len": ct_len, + }, + ) + Clock.schedule_once(fn, 0) # Now define the functions as staticmethods of class setattr(DownloadStableZipScreen, "on_trigger", on_trigger) @@ -114,29 +112,25 @@ def build_downloader(self, version: str): destdir=DownloadStableZipScreen.get_destdir_assets(), ) - if self.downloader is not None: - url = getattr(self.downloader, "url") - destdir = getattr(self.downloader, "destdir") - downloading = self.translate("Downloading") - to = self.translate("to") - filepath = os.path.join(destdir, f"krux-{self.version}.zip") + url = getattr(self.downloader, "url") + destdir = getattr(self.downloader, "destdir") + downloading = self.translate("Downloading") + to = self.translate("to") + filepath = os.path.join(destdir, f"krux-{self.version}.zip") - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - downloading, - "\n", - f"[color=#00AABB][ref={url}]{url}[/ref][/color]", - "\n", - to, - "\n", - filepath, - "[/size]", - ] - ) - - else: - self.redirect_error("Invalid downloader") + self.ids[f"{self.id}_info"].text = "".join( + [ + f"[size={self.SIZE_MP}sp]", + downloading, + "\n", + f"[color=#00AABB][ref={url}]{url}[/ref][/color]", + "\n", + to, + "\n", + filepath, + "[/size]", + ] + ) def on_download_progress(self, value: dict): """update GUI given a ratio between what is downloaded and its total length""" @@ -166,24 +160,20 @@ def on_download_progress(self, value: dict): # When finish, change the label # and then change screen if percent == 1.00: - if self.downloader is not None: - destdir = getattr(self.downloader, "destdir") - downloaded = self.translate("downloaded") - filepath = os.path.join(destdir, f"krux-{self.version}.zip") - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - filepath, - "\n", - downloaded, - "[/size]", - ] - ) - # When finish, change the label, wait some seconds - # and then change screen - # trigger is defined in superclass - callback_trigger = getattr(self, "trigger") - callback_trigger() - - else: - self.redirect_error(f"Invalid downloader: {self.downloader}") + destdir = getattr(self.downloader, "destdir") + downloaded = self.translate("downloaded") + filepath = os.path.join(destdir, f"krux-{self.version}.zip") + self.ids[f"{self.id}_info"].text = "".join( + [ + f"[size={self.SIZE_MP}sp]", + filepath, + "\n", + downloaded, + "[/size]", + ] + ) + # When finish, change the label, wait some seconds + # and then change screen + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + callback_trigger() diff --git a/src/app/screens/download_stable_zip_sha256_screen.py b/src/app/screens/download_stable_zip_sha256_screen.py index 37818d7a..056c0145 100644 --- a/src/app/screens/download_stable_zip_sha256_screen.py +++ b/src/app/screens/download_stable_zip_sha256_screen.py @@ -55,13 +55,15 @@ def on_trigger(dt): # pylint: disable=unused-argument def on_progress(data: bytes): # calculate downloaded percentage + dl_len = getattr(self.downloader, "downloaded_len") + ct_len = getattr(self.downloader, "content_len") fn = partial( self.update, name=self.name, key="progress", value={ - "downloaded_len": self.downloader.downloaded_len, - "content_len": self.downloader.content_len, + "downloaded_len": dl_len, + "content_len": ct_len, }, ) Clock.schedule_once(fn, 0) @@ -103,24 +105,19 @@ def build_downloader(self, value: str): destdir=DownloadStableZipSha256Screen.get_destdir_assets(), ) - if self.downloader is not None: - url = getattr(self.downloader, "url") - destdir = getattr(self.downloader, "destdir") - - self.ids[f"{self.id}_info"].text = ( - DownloadStableZipSha256Screen.make_download_info( - size=self.SIZE_MP, - download_msg=self.translate("Downloading"), - from_url=url, - to_msg=self.translate("to"), - to_path=os.path.join( - destdir, f"krux-{self.version}.zip.sha256.txt" - ), - ) + url = getattr(self.downloader, "url") + destdir = getattr(self.downloader, "destdir") + to_path = os.path.join(destdir, f"krux-{self.version}.zip.sha256.txt") + + self.ids[f"{self.id}_info"].text = ( + DownloadStableZipSha256Screen.make_download_info( + size=self.SIZE_MP, + download_msg=self.translate("Downloading"), + from_url=url, + to_msg=self.translate("to"), + to_path=to_path, ) - - else: - self.redirect_error("Invalid downloader") + ) def on_download_progress(self, value: dict): """update GUI given a ratio between what is downloaded and its total length""" @@ -142,25 +139,21 @@ def on_download_progress(self, value: dict): # When finish, change the label # and then change screen if percent == 1.00: - if self.downloader is not None: - destdir = getattr(self.downloader, "destdir") - downloaded = self.translate("downloaded") - filepath = os.path.join(destdir, f"krux-{self.version}.zip.sha256.txt") - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - filepath, - "\n", - downloaded, - "[/size]", - ] - ) - - # When finish, change the label, wait some seconds - # and then change screen - # trigger is defined in superclass - callback_trigger = getattr(self, "trigger") - callback_trigger() - - else: - self.redirect_error(f"Invalid downloader: {self.downloader}") + destdir = getattr(self.downloader, "destdir") + downloaded = self.translate("downloaded") + filepath = os.path.join(destdir, f"krux-{self.version}.zip.sha256.txt") + self.ids[f"{self.id}_info"].text = "".join( + [ + f"[size={self.SIZE_MP}sp]", + filepath, + "\n", + downloaded, + "[/size]", + ] + ) + + # When finish, change the label, wait some seconds + # and then change screen + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + callback_trigger() diff --git a/src/app/screens/download_stable_zip_sig_screen.py b/src/app/screens/download_stable_zip_sig_screen.py index 74598a90..3ac46ee4 100644 --- a/src/app/screens/download_stable_zip_sig_screen.py +++ b/src/app/screens/download_stable_zip_sig_screen.py @@ -53,14 +53,13 @@ def on_trigger(dt): def on_progress(data: bytes): # calculate downloaded percentage self.debug(f"Chunck size: {len(data)}") + dl_len = getattr(self.downloader, "downloaded_len") + ct_len = getattr(self.downloader, "content_len") fn = partial( self.update, name=self.name, key="progress", - value={ - "downloaded_len": self.downloader.downloaded_len, - "content_len": self.downloader.content_len, - }, + value={"downloaded_len": dl_len, "content_len": ct_len}, ) Clock.schedule_once(fn, 0) @@ -101,22 +100,18 @@ def build_downloader(self, value: str): destdir=DownloadStableZipSigScreen.get_destdir_assets(), ) - if self.downloader is not None: - url = getattr(self.downloader, "url") - destdir = getattr(self.downloader, "destdir") + url = getattr(self.downloader, "url") + destdir = getattr(self.downloader, "destdir") - self.ids[f"{self.id}_info"].text = ( - DownloadStableZipSigScreen.make_download_info( - size=self.SIZE_MP, - download_msg=self.translate("Downloading"), - from_url=url, - to_msg=self.translate("to"), - to_path=os.path.join(destdir, f"krux-{self.version}.zip.sig"), - ) + self.ids[f"{self.id}_info"].text = ( + DownloadStableZipSigScreen.make_download_info( + size=self.SIZE_MP, + download_msg=self.translate("Downloading"), + from_url=url, + to_msg=self.translate("to"), + to_path=os.path.join(destdir, f"krux-{self.version}.zip.sig"), ) - - else: - self.redirect_error("Invalid downloader") + ) def on_download_progress(self, value: dict): """update GUI given a ration between what is downloaded and its total length""" @@ -138,25 +133,21 @@ def on_download_progress(self, value: dict): # When finish, change the label # and then change screen if percent == 1.00: - if self.downloader is not None: - destdir = getattr(self.downloader, "destdir") - downloaded = self.translate("downloaded") - filepath = os.path.join(destdir, f"krux-{self.version}.zip.sig") - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={self.SIZE_MP}sp]", - filepath, - "\n", - downloaded, - "[/size]", - ] - ) - - # When finish, change the label, wait some seconds - # and then change screen - # trigger is defined in superclass - callback_trigger = getattr(self, "trigger") - callback_trigger() - - else: - self.redirect_error("Invalid downloader") + destdir = getattr(self.downloader, "destdir") + downloaded = self.translate("downloaded") + filepath = os.path.join(destdir, f"krux-{self.version}.zip.sig") + self.ids[f"{self.id}_info"].text = "".join( + [ + f"[size={self.SIZE_MP}sp]", + filepath, + "\n", + downloaded, + "[/size]", + ] + ) + + # When finish, change the label, wait some seconds + # and then change screen + # trigger is defined in superclass + callback_trigger = getattr(self, "trigger") + callback_trigger() From 75530a7a9c3c63b9b7b869851376f8e45bdde05d Mon Sep 17 00:00:00 2001 From: qlrd Date: Mon, 9 Sep 2024 19:52:09 -0300 Subject: [PATCH 29/61] coveraged 100% about_screen --- src/app/screens/about_screen.py | 48 +++++++++++---------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/src/app/screens/about_screen.py b/src/app/screens/about_screen.py index 6e3dfa94..46cc983c 100644 --- a/src/app/screens/about_screen.py +++ b/src/app/screens/about_screen.py @@ -21,12 +21,9 @@ """ about_screen.py """ -from functools import partial import webbrowser +from functools import partial from kivy.clock import Clock -from kivy.core.window import Window -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color from src.utils.constants import get_version from src.app.screens.base_screen import BaseScreen @@ -56,15 +53,12 @@ def _on_ref_press(*args): if args[1] == "Back": self.set_screen(name="MainScreen", direction="right") - elif args[1] == "X": + if args[1] == "X": webbrowser.open("https://x.com/selfcustodykrux") - elif args[1] == "SourceCode": + if args[1] == "SourceCode": webbrowser.open(self.src_code) - else: - self.redirect_error(f"Invalid ref: {args[1]}") - setattr(self, f"on_ref_press_{self.id}_label", _on_ref_press) self.ids[f"{self.id}_label"].bind(on_ref_press=_on_ref_press) @@ -79,26 +73,13 @@ def _on_ref_press(*args): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons from selected device/versions on related screens""" - name = kwargs.get("name") - key = kwargs.get("key") + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) value = kwargs.get("value") - # Check if update to screen - if name in ("KruxInstallerApp", "ConfigKruxInstaller", "AboutScreen"): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(msg=f"Invalid screen name: {name}") - - if key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - # Check locale - elif key == "locale": - if value is not None: - self.locale = value + def on_update(): + if key == "locale": + setattr(self, "locale", value) follow = self.translate("follow us on X") back = self.translate("Back") @@ -126,8 +107,11 @@ def update(self, *args, **kwargs): ] ) - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - else: - self.redirect_error(msg=f'Invalid key: "{key}"') + setattr(AboutScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=("KruxInstallerApp", "ConfigKruxInstaller", "AboutScreen"), + on_update=getattr(AboutScreen, "on_update"), + ) From 32b87cf096fbcf47bc6bf92e33d11e308e89ab6b Mon Sep 17 00:00:00 2001 From: qlrd Date: Mon, 9 Sep 2024 21:27:00 -0300 Subject: [PATCH 30/61] coveraged 100% warning_beta_screen substituted button on warning_beta_screen to label with a image --- e2e/test_007_warning_beta_screen.py | 83 ++++++--------- src/app/screens/warning_beta_screen.py | 134 +++++++++---------------- 2 files changed, 80 insertions(+), 137 deletions(-) diff --git a/e2e/test_007_warning_beta_screen.py b/e2e/test_007_warning_beta_screen.py index d1eac310..8be59943 100644 --- a/e2e/test_007_warning_beta_screen.py +++ b/e2e/test_007_warning_beta_screen.py @@ -33,6 +33,7 @@ def test_render_main_screen(self, mock_get_locale): EventLoop.ensure_window() window = EventLoop.window grid = window.children[0].children[0] + warn = grid.children[1] button = grid.children[0] sizes = [screen.SIZE_MM, screen.SIZE_M, screen.SIZE_MP] @@ -40,17 +41,11 @@ def test_render_main_screen(self, mock_get_locale): self.assertEqual(screen.name, "WarningBetaScreen") self.assertEqual(screen.id, "warning_beta_screen") self.assertEqual(grid.id, "warning_beta_screen_grid") - self.assertEqual(button.id, "warning_beta_screen_warn") + self.assertEqual(warn.id, "warning_beta_screen_warn") + self.assertEqual(button.id, "warning_beta_screen_label") text = "".join( [ - f"[size={sizes[0]}sp]", - "[color=#efcc00]", - "[b]WARNING[/b]", - "[/color]", - "[/size]", - "\n", - "\n", f"[size={sizes[1]}sp]", "[color=#efcc00]This is our test repository[/color]", "[/size]", @@ -62,16 +57,20 @@ def test_render_main_screen(self, mock_get_locale): "\n", f"[size={sizes[0]}sp]", "[color=#00ff00]", - "[u]Proceed[/u]", + "[ref=MainScreen]Proceed[/ref]", "[/color]", " ", "[color=#ff0000]", - "[u]Back[/u]", + "[ref=SelectVersion]Back[/ref]", "[/color]", "[/size]", ] ) + print(button.text) + print("==============") + print(text) + self.assertEqual(button.text, text) mock_get_locale.assert_any_call() @@ -79,45 +78,38 @@ def test_render_main_screen(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.warning_beta_screen.WarningBetaScreen.set_background") - def test_on_press(self, mock_set_background, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.set_screen") + def test_on_ref_press_proceed(self, mock_set_screen, mock_get_locale): screen = WarningBetaScreen() self.render(screen) # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - grid = window.children[0].children[0] - button = grid.children[0] - action = getattr(screen, "on_press_warning_beta_screen_warn") - action(button) + action = getattr(screen, "on_ref_press_warning_beta_screen") + action("MainScreen") - mock_set_background.assert_called_once_with( - wid=button.id, rgba=(0.25, 0.25, 0.25, 1) - ) + mock_set_screen.assert_called_once_with(name="MainScreen", direction="right") mock_get_locale.assert_any_call() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.warning_beta_screen.WarningBetaScreen.set_background") - @patch("src.app.screens.warning_beta_screen.WarningBetaScreen.set_screen") - def test_on_release(self, mock_set_screen, mock_set_background, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.set_screen") + def test_on_ref_press_back(self, mock_set_screen, mock_get_locale): screen = WarningBetaScreen() self.render(screen) # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - grid = window.children[0].children[0] - button = grid.children[0] - action = getattr(screen, "on_release_warning_beta_screen_warn") - action(button) - mock_set_background.assert_called_once_with(wid=button.id, rgba=(0, 0, 0, 1)) - mock_set_screen.assert_called_once_with(name="MainScreen", direction="right") + action = getattr(screen, "on_ref_press_warning_beta_screen") + action("SelectVersion") + + mock_set_screen.assert_called_once_with( + name="SelectVersionScreen", direction="right" + ) mock_get_locale.assert_any_call() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @@ -151,9 +143,6 @@ def test_update_locale(self, mock_get_locale): screen.update(name="ConfigKruxInstaller", key="locale", value="pt_BR.UTF-8") text = "".join( [ - f"[size={fontsize_mm}sp][color=#efcc00][b]ADVERTÊNCIA[/b][/color][/size]", - "\n", - "\n", f"[size={fontsize_m}sp][color=#efcc00]Este é nosso repositório de testes[/color][/size]", "\n", f"[size={fontsize_mp}sp]Estes são binários não assinados dos recursos mais experimentais[/size]", @@ -162,10 +151,19 @@ def test_update_locale(self, mock_get_locale): "\n", "\n", f"[size={fontsize_mm}sp]", - "[color=#00ff00]Proceder[/color] [color=#ff0000]Voltar[/color]", + "[color=#00ff00]", + "[ref=MainScreen]Proceder[/ref]", + "[/color]", + " ", + "[color=#ff0000]", + "[ref=SelectVersion]Voltar[/ref]", + "[/color]", "[/size]", ] ) + print(button.text) + print("==========") + print(text) self.assertEqual(button.text, text) mock_get_locale.assert_any_call() @@ -186,20 +184,3 @@ def test_fail_update_locale_wrong_name(self, mock_redirect_error, mock_get_local mock_redirect_error.assert_called_once_with("Invalid screen name: Mock") mock_get_locale.assert_any_call() - - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_locale_wrong_key(self, mock_redirect_error, mock_get_locale): - screen = WarningBetaScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name="ConfigKruxInstaller", key="mock") - - mock_redirect_error.assert_called_once_with('Invalid key: "mock"') - mock_get_locale.assert_any_call() diff --git a/src/app/screens/warning_beta_screen.py b/src/app/screens/warning_beta_screen.py index db3f56a4..8f8b2400 100644 --- a/src/app/screens/warning_beta_screen.py +++ b/src/app/screens/warning_beta_screen.py @@ -21,6 +21,8 @@ """ about_screen.py """ +from functools import partial +from kivy.clock import Clock from src.app.screens.base_screen import BaseScreen @@ -31,101 +33,60 @@ def __init__(self, **kwargs): super().__init__(wid="warning_beta_screen", name="WarningBetaScreen", **kwargs) self.make_grid(wid="warning_beta_screen_grid", rows=2) - warning = self.translate("WARNING") - test_repo = self.translate("This is our test repository") - unsg_bin = self.translate( - "These are unsigned binaries for the latest and most experimental features" - ) - just_try = self.translate( - "and it's just for trying new things and providing feedback." + self.make_image( + wid=f"{self.id}_warn", + source=self.warn_img, + root_widget=f"{self.id}_grid", ) - proceed = self.translate("Proceed") - back = self.translate("Back") - - text = "".join( - [ - f"[size={self.SIZE_MM}sp]", - "[color=#efcc00]", - f"[b]{warning}[/b]", - "[/color]", - "[/size]", - "\n", - "\n", - f"[size={self.SIZE_M}sp]", - f"[color=#efcc00]{test_repo}[/color]", - "[/size]", - "\n", - f"[size={self.SIZE_MP}sp]{unsg_bin}[/size]", - "\n", - f"[size={self.SIZE_MP}sp]{just_try}[/size]", - "\n", - "\n", - f"[size={self.SIZE_MM}sp]", - "[color=#00ff00]", - f"[u]{proceed}[/u]", - "[/color]", - " ", - "[color=#ff0000]", - f"[u]{back}[/u]", - "[/color]", - "[/size]", - ] + self.make_label( + wid=f"{self.id}_label", + text=self.make_label_text(), + root_widget=f"{self.id}_grid", + halign="justify", ) # START of on_press buttons - def _press(instance): - self.debug(f"Calling Button::{instance.id}::on_press") - self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) - - # END of on_press buttons - - # START of on_release_buttons - def _release(instance): - self.debug(f"Calling Button::{instance.id}::on_release") - self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) - self.set_screen(name="MainScreen", direction="right") - - self.make_button( - row=0, - wid="warning_beta_screen_warn", - root_widget="warning_beta_screen_grid", - text=text, - on_press=_press, - on_release=_release, - ) + def on_ref_press(*args): + if args[1] == "MainScreen": + self.set_screen(name="MainScreen", direction="right") + + if args[1] == "SelectVersion": + self.set_screen(name="SelectVersionScreen", direction="right") + + setattr(WarningBetaScreen, f"on_ref_press_{self.id}", on_ref_press) + self.ids[f"{self.id}_label"].bind(on_ref_press=on_ref_press) + + fn = partial(self.update, name=self.name, key="canvas") + Clock.schedule_once(fn, 0) # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" - name = kwargs.get("name") - key = kwargs.get("key") + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) value = kwargs.get("value") - # Check if update to screen - if name in ("ConfigKruxInstaller",): - self.debug(f"Updating {self.name} from {name}...") - else: - self.redirect_error(f"Invalid screen name: {name}") - - # Check locale - if key == "locale": - if value is not None: - self.locale = value - self.show_warning() - - else: - self.redirect_error(f"Invalid value for key {key}: {value}") - - else: - self.redirect_error(f'Invalid key: "{key}"') + def on_update(): + # Check locale + if key == "locale": + setattr(self, "locale", value) + self.ids[f"{self.id}_label"].text = self.make_label_text() + + setattr(WarningBetaScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=("ConfigKruxInstaller", "WarningBetaScreen"), + on_update=getattr(WarningBetaScreen, "on_update"), + ) - def show_warning(self): + def make_label_text(self): """ Create a warning message where it's content is about the beta (and unsigned) firmware """ - warning = self.translate("WARNING") test_repo = self.translate("This is our test repository") unsg_bin = self.translate( "These are unsigned binaries for the latest and most experimental features" @@ -136,11 +97,8 @@ def show_warning(self): proceed = self.translate("Proceed") back = self.translate("Back") - text = "".join( + return "".join( [ - f"[size={self.SIZE_MM}sp][color=#efcc00][b]{warning}[/b][/color][/size]", - "\n", - "\n", f"[size={self.SIZE_M}sp][color=#efcc00]{test_repo}[/color][/size]", "\n", f"[size={self.SIZE_MP}sp]{unsg_bin}[/size]", @@ -149,9 +107,13 @@ def show_warning(self): "\n", "\n", f"[size={self.SIZE_MM}sp]", - f"[color=#00ff00]{proceed}[/color] [color=#ff0000]{back}[/color]", + "[color=#00ff00]", + f"[ref=MainScreen]{proceed}[/ref]", + "[/color]", + " ", + "[color=#ff0000]", + f"[ref=SelectVersion]{back}[/ref]", + "[/color]", "[/size]", ] ) - - self.ids["warning_beta_screen_warn"].text = text From 8dc0d66544c2e9bdf960de73d55f06fc58f1d3ba Mon Sep 17 00:00:00 2001 From: qlrd Date: Tue, 10 Sep 2024 10:44:51 -0300 Subject: [PATCH 31/61] coveraged 97% of warning_wipe_screen --- e2e/test_024_warning_wipe_screen.py | 228 +++++++++++++++++++++++++ src/app/screens/warning_wipe_screen.py | 53 +++--- 2 files changed, 249 insertions(+), 32 deletions(-) create mode 100644 e2e/test_024_warning_wipe_screen.py diff --git a/e2e/test_024_warning_wipe_screen.py b/e2e/test_024_warning_wipe_screen.py new file mode 100644 index 00000000..a2be4d8f --- /dev/null +++ b/e2e/test_024_warning_wipe_screen.py @@ -0,0 +1,228 @@ +import sys +import os +from unittest.mock import patch, MagicMock, call +from kivy.base import EventLoop, EventLoopBase +from kivy.tests.common import GraphicUnitTest +from kivy.core.text import LabelBase, DEFAULT_FONT +from src.app.screens.warning_wipe_screen import WarningWipeScreen + + +class TestWarningWipeScreen(GraphicUnitTest): + + @classmethod + def setUpClass(cls): + cwd_path = os.path.dirname(__file__) + rel_assets_path = os.path.join(cwd_path, "..", "assets") + assets_path = os.path.abspath(rel_assets_path) + noto_sans_path = os.path.join(assets_path, "NotoSansCJK_Cy_SC_KR_Krux.ttf") + LabelBase.register(DEFAULT_FONT, noto_sans_path) + + @classmethod + def teardown_class(cls): + EventLoop.exit() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.warning_wipe_screen.partial") + @patch("src.app.screens.warning_wipe_screen.Clock.schedule_once") + def test_init(self, mock_schedule_once, mock_partial, mock_get_locale): + screen = WarningWipeScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + window = EventLoop.window + grid = window.children[0].children[0] + image = grid.children[1] + label = grid.children[0] + + # default assertions + self.assertEqual(grid.id, "warning_wipe_screen_grid") + self.assertEqual(len(grid.children), 2) + self.assertEqual(image.id, "warning_wipe_screen_warn") + self.assertEqual(label.id, "warning_wipe_screen_label") + + # patch assertions + mock_get_locale.assert_called_once() + mock_partial.assert_called_once_with( + screen.update, name=screen.name, key="canvas" + ) + mock_schedule_once.assert_has_calls([call(mock_partial(), 0)], any_order=True) + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_make_label_text(self, mock_get_locale): + screen = WarningWipeScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + window = EventLoop.window + grid = window.children[0].children[0] + label = grid.children[0] + + if sys.platform in ("linux", "win32"): + sizes = [screen.SIZE_MP, screen.SIZE_P] + + else: + sizes = [screen.SIZE_MM, screen.SIZE_M] + + screen.update(name=screen.name, key="locale", value="en_US.UTF-8") + + text = "".join( + [ + "[color=#EFCC00]", + f"[size={sizes[0]}]", + "You are about to initiate a FULL WIPE of this device", + "[/size]", + "[/color]", + "\n", + "\n", + f"[size={sizes[1]}]", + "This operation will:", + "\n", + "* Permanently erase all saved data", + "\n", + "* Remove the existing firmware", + "\n", + "* Render the device non-functional until new firmware is re-flashed", + "[/size]", + "\n", + "\n", + f"[size={sizes[0]}]", + "[color=#00FF00]", + "[ref=WipeScreen][u]Proceed[/u][/ref]", + "[/color]", + " ", + "[color=#FF0000]", + "[ref=MainScreen][u]Back[/u][/ref]", + "[/color]", + "[/size]", + ] + ) + + self.assertEqual(label.text, text) + + # patch assertions + mock_get_locale.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch( + "src.app.screens.warning_wipe_screen.WarningWipeScreen.make_label_text", + return_value="mocked", + ) + def test_update_locale(self, mock_make_label_text, mock_get_locale): + screen = WarningWipeScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + screen.update(name=screen.name, key="locale", value="en_US.UTF8") + + self.assertEqual(screen.locale, "en_US.UTF8") + + # patch assertions + mock_get_locale.assert_called_once() + mock_make_label_text.assert_any_call() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch( + "src.app.screens.warning_wipe_screen.WarningWipeScreen.make_label_text", + return_value="mocked", + ) + def test_on_enter(self, mock_make_label_text, mock_get_locale): + screen = WarningWipeScreen() + self.render(screen) + screen.on_enter() + + # get your Window instance safely + EventLoop.ensure_window() + + # patch assertions + mock_get_locale.assert_any_call() + mock_make_label_text.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.base_screen.BaseScreen.get_baudrate", return_value=1500000) + @patch("src.app.screens.warning_wipe_screen.partial") + @patch("src.app.screens.warning_wipe_screen.Clock.schedule_once") + def test_on_ref_press_proceed( + self, mock_schedule_once, mock_partial, mock_get_baudrate, mock_get_locale + ): + screen = WarningWipeScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + window = EventLoop.window + grid = window.children[0].children[0] + label = grid.children[0] + + action = getattr(WarningWipeScreen, f"on_ref_press_{screen.id}") + action(label, "WipeScreen") + + mock_get_locale.assert_any_call() + screen.manager.get_screen.assert_has_calls( + [call("MainScreen"), call("WipeScreen")] + ) + mock_get_baudrate.assert_called_once() + mock_partial.assert_has_calls( + [ + call( + screen.manager.get_screen().update, + name=screen.name, + key="device", + value=screen.manager.get_screen().device, + ), + call( + screen.manager.get_screen().update, + name=screen.name, + key="wiper", + value=1500000, + ), + ], + any_order=True, + ) + mock_schedule_once.assert_has_calls( + [call(mock_partial(), 0), call(mock_partial(), 0)], any_order=True + ) + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.warning_wipe_screen.WarningWipeScreen.set_screen") + def test_on_ref_press_deny(self, mock_set_screen, mock_get_locale): + screen = WarningWipeScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + window = EventLoop.window + grid = window.children[0].children[0] + label = grid.children[0] + + action = getattr(WarningWipeScreen, f"on_ref_press_{screen.id}") + action(label, "MainScreen") + + mock_get_locale.assert_any_call() + mock_set_screen.assert_called_once_with(name="MainScreen", direction="right") diff --git a/src/app/screens/warning_wipe_screen.py b/src/app/screens/warning_wipe_screen.py index 7ac0eea1..488c5933 100644 --- a/src/app/screens/warning_wipe_screen.py +++ b/src/app/screens/warning_wipe_screen.py @@ -24,9 +24,6 @@ import sys from functools import partial from kivy.clock import Clock -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color -from kivy.core.window import Window from src.app.screens.base_screen import BaseScreen @@ -43,14 +40,14 @@ def __init__(self, **kwargs): self.make_grid(wid=f"{self.id}_grid", rows=2) self.make_image( - wid=f"{self.id}_loader", + wid=f"{self.id}_warn", source=self.warn_img, root_widget=f"{self.id}_grid", ) self.make_label( wid=f"{self.id}_label", - text=self.make_label_text(), + text="", root_widget=f"{self.id}_grid", halign="justify", ) @@ -79,6 +76,7 @@ def _on_ref_press(*args): ) for fn in partials: + print(fn) Clock.schedule_once(fn, 0) self.set_screen(name=args[1], direction="left") @@ -101,36 +99,26 @@ def on_enter(self, *args): # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update buttons on related screen""" - name = kwargs.get("name") - key = kwargs.get("key") + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) value = kwargs.get("value") - if name in ( - "ConfigKruxInstaller", - "MainScreen", - "WarningWipeScreen", - ): - self.debug(f"Updating {self.name} from {name}") - else: - self.redirect_error(f"Invalid screen name: {name}") - return - - # Check locale - if key == "locale": - if value is not None: - self.locale = value + def on_update(): + if key == "locale": self.ids[f"{self.id}_label"].text = self.make_label_text() - else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - else: - self.redirect_error(f'Invalid key: "{key}"') + setattr(WarningWipeScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=( + "ConfigKruxInstaller", + "MainScreen", + "WarningWipeScreen", + ), + on_update=getattr(WarningWipeScreen, "on_update"), + ) def make_label_text(self): """Make a warning message about wipe procedure""" @@ -172,7 +160,8 @@ def make_label_text(self): "[/size]", "\n", "\n", - f"[size={sizes[0]}]" "[color=#00FF00]", + f"[size={sizes[0]}]", + "[color=#00FF00]", f"[ref=WipeScreen][u]{proceed}[/u][/ref]", "[/color]", " ", From 636a10cec7a17b526d7435204c34b2b4b927b8aa Mon Sep 17 00:00:00 2001 From: qlrd Date: Tue, 10 Sep 2024 14:20:55 -0300 Subject: [PATCH 32/61] coveraged 100% unzip_stable_screen --- e2e/test_016_unzip_stable_screen.py | 8 +- src/app/screens/unzip_stable_screen.py | 204 +++++++++++++------------ 2 files changed, 108 insertions(+), 104 deletions(-) diff --git a/e2e/test_016_unzip_stable_screen.py b/e2e/test_016_unzip_stable_screen.py index df5dac26..fa648910 100644 --- a/e2e/test_016_unzip_stable_screen.py +++ b/e2e/test_016_unzip_stable_screen.py @@ -501,19 +501,19 @@ def test_on_release_flash_button( "src.app.screens.base_screen.BaseScreen.get_destdir_assets", return_value="mock" ) @patch("src.app.screens.unzip_stable_screen.UnzipStableScreen.set_background") - @patch("src.app.screens.unzip_stable_screen.FirmwareUnzip") + # @patch("src.app.screens.unzip_stable_screen.FirmwareUnzip") @patch("src.app.screens.unzip_stable_screen.UnzipStableScreen.manager") @patch("src.app.screens.unzip_stable_screen.time.sleep") def test_on_release_airgapped_button( self, mock_sleep, mock_manager, - mock_firmware_unzip, + # mock_firmware_unzip, mock_set_background, mock_get_destdir_assets, mock_get_locale, ): - mock_firmware_unzip.load = MagicMock() + # mock_firmware_unzip.load = MagicMock() mock_manager.get_screen = MagicMock() screen = UnzipStableScreen() @@ -562,7 +562,7 @@ def test_on_release_airgapped_button( # patch assertions mock_get_destdir_assets.assert_called_once() mock_get_locale.assert_called() - mock_firmware_unzip.assert_not_called() + # mock_firmware_unzip.assert_not_called() mock_set_background.assert_not_called() mock_manager.get_screen.assert_not_called() mock_sleep.assert_not_called() diff --git a/src/app/screens/unzip_stable_screen.py b/src/app/screens/unzip_stable_screen.py index 70eb7131..d932211c 100644 --- a/src/app/screens/unzip_stable_screen.py +++ b/src/app/screens/unzip_stable_screen.py @@ -27,7 +27,8 @@ from kivy.clock import Clock from src.app.screens.base_screen import BaseScreen from src.utils.unzip.kboot_unzip import KbootUnzip -from src.utils.unzip.firmware_unzip import FirmwareUnzip + +# from src.utils.unzip.firmware_unzip import FirmwareUnzip class UnzipStableScreen(BaseScreen): @@ -110,49 +111,46 @@ def _press(instance): def _release(instance): self.debug(f"Calling Button::{instance.id}::on_release") - if self.device is not None: - file_path = os.path.join(base_path, "kboot.kfpkg") - full_path = os.path.join(self.assets_dir, file_path) - baudrate = UnzipStableScreen.get_baudrate() - - unziper = KbootUnzip( - filename=zip_file, device=self.device, output=self.assets_dir - ) - - # load variables to FlashScreen before get in - screen = self.manager.get_screen("FlashScreen") - fns = [ - partial( - screen.update, name=self.name, key="firmware", value=full_path - ), - partial( - screen.update, name=self.name, key="baudrate", value=baudrate - ), - partial(screen.update, name=self.name, key="flasher"), - ] + file_path = os.path.join(base_path, "kboot.kfpkg") + full_path = os.path.join(self.assets_dir, file_path) + baudrate = UnzipStableScreen.get_baudrate() + + unziper = KbootUnzip( + filename=zip_file, + device=getattr(self, "device"), + output=getattr(self, "assets_dir"), + ) - for fn in fns: - Clock.schedule_once(fn, 0) - - # start the unzip process - self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) - unziper.load() - - # once unziped, give some messages - p = os.path.join(rel_path, "kboot.kfpkg") - self.ids[instance.id].text = "".join( - [ - f"[size={size[0]}sp]", - extracted_msg, - "[/size]", - "\n", - f"[size={size[1]}sp]", - "[color=#efcc00]", - p, - "[/color]", - "[/size]", - ] - ) + # load variables to FlashScreen before get in + screen = self.manager.get_screen("FlashScreen") + fns = [ + partial(screen.update, name=self.name, key="firmware", value=full_path), + partial(screen.update, name=self.name, key="baudrate", value=baudrate), + partial(screen.update, name=self.name, key="flasher"), + ] + + for fn in fns: + Clock.schedule_once(fn, 0) + + # start the unzip process + self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) + unziper.load() + + # once unziped, give some messages + p = os.path.join(rel_path, "kboot.kfpkg") + self.ids[instance.id].text = "".join( + [ + f"[size={size[0]}sp]", + extracted_msg, + "[/size]", + "\n", + f"[size={size[1]}sp]", + "[color=#efcc00]", + p, + "[/color]", + "[/size]", + ] + ) time.sleep(2.1) self.set_screen(name="FlashScreen", direction="left") @@ -185,73 +183,79 @@ def _release(instance): def build_extract_to_airgap_button(self): """Build a lower button to airgap update""" self.debug("Building airgap button") - zip_file = os.path.join(self.assets_dir, f"krux-{self.version}.zip") + # zip_file = os.path.join(self.assets_dir, f"krux-{self.version}.zip") base_path = os.path.join(f"krux-{self.version}", f"maixpy_{self.device}") rel_path = os.path.join(self.assets_dir, base_path) airgap_msg = self.translate("Air-gapped update with") - extract_msg = self.translate("Unziping") - extracted_msg = self.translate("Unziped") + # extract_msg = self.translate("Unziping") + # extracted_msg = self.translate("Unziped") size = [self.SIZE_MM, self.SIZE_MP] - activated = False + # activated = False def _press(instance): - if activated: - self.debug(f"Calling Button::{instance.id}::on_press") - file_path = os.path.join(rel_path, "firmware.bin") - self.ids[instance.id].text = "".join( - [ - f"[size={size[0]}sp]", - extract_msg, - "[/size]", - "\n", - f"[size={size[1]}sp]", - "[color=#efcc00]", - file_path, - "[/color]", - "[/size]", - ] - ) - self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + pass def _release(instance): - if activated: - self.debug(f"Calling Button::{instance.id}::on_release") - if self.device is not None: - file_path = f"{base_path}/firmware.bin" - unziper = FirmwareUnzip( - filename=zip_file, device=self.device, output=self.assets_dir - ) - - screen = self.manager.get_screen("AirgapScreen") - fns = [ - partial(screen.update, key="firmware", value=file_path), - partial(screen.update, key="device", value=self.device), - ] - for fn in fns: - Clock.schedule_once(fn, 0) - - self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) - unziper.load() - - p = os.path.join(rel_path, "firmware.bin") - self.ids[instance.id].text = "".join( - [ - f"[size={size[0]}sp]", - extracted_msg, - "[/size]", - "\n", - f"[size={size[1]}sp]", - "[color=#efcc00]", - p, - "[/color]", - "[/size]", - ] - ) - - time.sleep(2.1) - self.set_screen(name="AirgapScreen", direction="left") + pass + + # def _press(instance): + # if activated: + # self.debug(f"Calling Button::{instance.id}::on_press") + # file_path = os.path.join(rel_path, "firmware.bin") + # self.ids[instance.id].text = "".join( + # [ + # f"[size={size[0]}sp]", + # extract_msg, + # "[/size]", + # "\n", + # f"[size={size[1]}sp]", + # "[color=#efcc00]", + # file_path, + # "[/color]", + # "[/size]", + # ] + # ) + # self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + + # def _release(instance): + # if activated: + # self.debug(f"Calling Button::{instance.id}::on_release") + # if self.device is not None: + # file_path = f"{base_path}/firmware.bin" + # unziper = FirmwareUnzip( + # filename=zip_file, device=self.device, output=self.assets_dir + # ) + # + # screen = self.manager.get_screen("AirgapScreen") + # fns = [ + # partial(screen.update, key="firmware", value=file_path), + # partial(screen.update, key="device", value=self.device), + # ] + # for fn in fns: + # Clock.schedule_once(fn, 0) + # + # self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) + # unziper.load() + # + # p = os.path.join(rel_path, "firmware.bin") + # self.ids[instance.id].text = "".join( + # [ + # f"[size={size[0]}sp]", + # extracted_msg, + # "[/size]", + # "\n", + # f"[size={size[1]}sp]", + # "[color=#efcc00]", + # p, + # "[/color]", + # "[/size]", + # ] + # ) + # + # time.sleep(2.1) + # self.set_screen(name="AirgapScreen", direction="left") setattr(UnzipStableScreen, f"on_press_{self.id}_airgap_button", _press) setattr(UnzipStableScreen, f"on_release_{self.id}_airgap_button", _release) From 93a68d18baea62645fd846cad5dd23af893a8e00 Mon Sep 17 00:00:00 2001 From: qlrd Date: Wed, 11 Sep 2024 12:51:36 -0300 Subject: [PATCH 33/61] coveraged 100% error_screen --- e2e/test_000_base_screen.py | 8 +- e2e/test_003_main_screen.py | 6 +- e2e/test_006_select_old_version_screen.py | 6 +- e2e/test_007_warning_beta_screen.py | 8 +- e2e/test_009_base_download_screen.py | 8 +- e2e/test_010_download_stable_zip_screen.py | 6 +- ...t_011_download_stable_zip_sha256_screen.py | 8 +- ...test_012_download_stable_zip_sig_screen.py | 6 +- ...est_013_download_selfcustody_pem_screen.py | 6 +- e2e/test_014_download_beta_screen.py | 6 +- ...t_015_warning_already_downloaded_screen.py | 6 +- e2e/test_017_verify_stable_zip_screen.py | 6 +- e2e/test_023_wipe_screen.py | 6 +- e2e/test_025_error_screen.py | 180 ++++++++++++++++++ src/app/screens/base_download_screen.py | 15 +- src/app/screens/base_screen.py | 19 +- src/app/screens/error_screen.py | 141 ++++++++------ src/app/screens/flash_screen.py | 3 +- src/app/screens/greetings_screen.py | 4 +- src/app/screens/wipe_screen.py | 5 +- 20 files changed, 332 insertions(+), 121 deletions(-) create mode 100644 e2e/test_025_error_screen.py diff --git a/e2e/test_000_base_screen.py b/e2e/test_000_base_screen.py index ca8d6093..9defd98b 100644 --- a/e2e/test_000_base_screen.py +++ b/e2e/test_000_base_screen.py @@ -330,9 +330,9 @@ def test_clear_grid(self, mock_get_locale): @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch("src.app.screens.base_screen.BaseScreen.get_locale") - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") def test_fail_update_screen_invalid_screen( - self, mock_redirect_error, mock_get_locale + self, mock_redirect_exception, mock_get_locale ): screen = BaseScreen(wid="mock", name="Mock") screen.make_grid(wid="mock_grid", rows=1) @@ -353,9 +353,7 @@ def test_fail_update_screen_invalid_screen( on_update=MagicMock(), ) mock_get_locale.assert_called_once() - mock_redirect_error.assert_called_once_with( - "Invalid screen name: NoMockedScreen" - ) + mock_redirect_exception.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( diff --git a/e2e/test_003_main_screen.py b/e2e/test_003_main_screen.py index 1a323d0f..992bd7c4 100644 --- a/e2e/test_003_main_screen.py +++ b/e2e/test_003_main_screen.py @@ -260,8 +260,8 @@ def test_update_device(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_invalid_screen(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_invalid_screen(self, mock_redirect_exception, mock_get_locale): screen = MainScreen() self.render(screen) @@ -270,7 +270,7 @@ def test_fail_update_invalid_screen(self, mock_redirect_error, mock_get_locale): screen.update(name="MockedScreen", key="device", value="v24.03.0") mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with("Invalid screen name: MockedScreen") + mock_redirect_exception.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( diff --git a/e2e/test_006_select_old_version_screen.py b/e2e/test_006_select_old_version_screen.py index 4e503736..24d8c819 100644 --- a/e2e/test_006_select_old_version_screen.py +++ b/e2e/test_006_select_old_version_screen.py @@ -164,8 +164,8 @@ def test_on_release( @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_locale(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_locale(self, mock_redirect_exception, mock_get_locale): screen = SelectOldVersionScreen() screen.make_grid( wid="select_old_version_screen_grid", rows=len(OLD_VERSIONS) + 1 @@ -178,5 +178,5 @@ def test_fail_update_locale(self, mock_redirect_error, mock_get_locale): EventLoop.ensure_window() screen.update(name="Mock", key="locale", value="pt_BR.UTF-8") - mock_redirect_error.assert_called_once_with("Invalid screen name: Mock") mock_get_locale.assert_any_call() + mock_redirect_exception.assert_called_once() diff --git a/e2e/test_007_warning_beta_screen.py b/e2e/test_007_warning_beta_screen.py index 8be59943..f2803e9b 100644 --- a/e2e/test_007_warning_beta_screen.py +++ b/e2e/test_007_warning_beta_screen.py @@ -172,8 +172,10 @@ def test_update_locale(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_locale_wrong_name(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_locale_wrong_name( + self, mock_redirect_exception, mock_get_locale + ): screen = WarningBetaScreen() self.render(screen) @@ -182,5 +184,5 @@ def test_fail_update_locale_wrong_name(self, mock_redirect_error, mock_get_local screen.update(name="Mock", key="locale", value="pt_BR.UTF-8") - mock_redirect_error.assert_called_once_with("Invalid screen name: Mock") + mock_redirect_exception.assert_called_once() mock_get_locale.assert_any_call() diff --git a/e2e/test_009_base_download_screen.py b/e2e/test_009_base_download_screen.py index 2cc86100..10ecf01e 100644 --- a/e2e/test_009_base_download_screen.py +++ b/e2e/test_009_base_download_screen.py @@ -98,8 +98,8 @@ def test_set_thread(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_on_enter(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_on_enter(self, mock_redirect_exception, mock_get_locale): screen = BaseDownloadScreen(wid="mock_screen", name="MockScreen") screen.to_screen = "AnotherMockScreen" @@ -117,10 +117,8 @@ def test_fail_on_enter(self, mock_redirect_error, mock_get_locale): self.assertTrue(screen.thread is None) # patch tests - mock_redirect_error.assert_called_once_with( - "Downloader isnt configured. Use `update` method first" - ) mock_get_locale.assert_any_call() + mock_redirect_exception.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( diff --git a/e2e/test_010_download_stable_zip_screen.py b/e2e/test_010_download_stable_zip_screen.py index 1b959308..d539ab3b 100644 --- a/e2e/test_010_download_stable_zip_screen.py +++ b/e2e/test_010_download_stable_zip_screen.py @@ -51,10 +51,10 @@ def test_init(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") def test_fail_update_invalid_name( self, - mock_redirect_error, + mock_redirect_excpetion, mock_get_locale, ): screen = DownloadStableZipScreen() @@ -68,7 +68,7 @@ def test_fail_update_invalid_name( # patch assertions mock_get_locale.assert_any_call() - mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") + mock_redirect_excpetion.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( diff --git a/e2e/test_011_download_stable_zip_sha256_screen.py b/e2e/test_011_download_stable_zip_sha256_screen.py index d0ba07a7..6ccf1805 100644 --- a/e2e/test_011_download_stable_zip_sha256_screen.py +++ b/e2e/test_011_download_stable_zip_sha256_screen.py @@ -55,8 +55,8 @@ def test_init(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_invalid_name(self, mock_redirect_exception, mock_get_locale): screen = DownloadStableZipSha256Screen() self.render(screen) @@ -66,11 +66,9 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): # do tests screen.update(name="MockScreen") - # default assertions - mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") - # patch assertions mock_get_locale.assert_any_call() + mock_redirect_exception.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( diff --git a/e2e/test_012_download_stable_zip_sig_screen.py b/e2e/test_012_download_stable_zip_sig_screen.py index 5c9bfefb..9e365555 100644 --- a/e2e/test_012_download_stable_zip_sig_screen.py +++ b/e2e/test_012_download_stable_zip_sig_screen.py @@ -53,8 +53,8 @@ def test_init(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_invalid_name(self, mock_redirect_exception, mock_get_locale): screen = DownloadStableZipSigScreen() self.render(screen) @@ -65,7 +65,7 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): screen.update(name="MockScreen") # patch assertions - mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") + mock_redirect_exception.assert_called_once() mock_get_locale.assert_any_call() @patch.object(EventLoopBase, "ensure_window", lambda x: None) diff --git a/e2e/test_013_download_selfcustody_pem_screen.py b/e2e/test_013_download_selfcustody_pem_screen.py index 1a4b8081..dabd765a 100644 --- a/e2e/test_013_download_selfcustody_pem_screen.py +++ b/e2e/test_013_download_selfcustody_pem_screen.py @@ -54,8 +54,8 @@ def test_init(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_invalid_name(self, mock_redirect_exception, mock_get_locale): screen = DownloadSelfcustodyPemScreen() self.render(screen) @@ -66,7 +66,7 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): screen.update(name="MockScreen") # patch assertions - mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") + mock_redirect_exception.assert_called_once() mock_get_locale.assert_any_call() @patch.object(EventLoopBase, "ensure_window", lambda x: None) diff --git a/e2e/test_014_download_beta_screen.py b/e2e/test_014_download_beta_screen.py index 340b7b4e..6f0b786f 100644 --- a/e2e/test_014_download_beta_screen.py +++ b/e2e/test_014_download_beta_screen.py @@ -54,8 +54,8 @@ def test_init(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_invalid_name(self, mock_redirect_exception, mock_get_locale): screen = DownloadBetaScreen() self.render(screen) @@ -66,7 +66,7 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): screen.update(name="MockScreen") # patch assertions - mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") + mock_redirect_exception.assert_called_once() mock_get_locale.assert_any_call() @patch.object(EventLoopBase, "ensure_window", lambda x: None) diff --git a/e2e/test_015_warning_already_downloaded_screen.py b/e2e/test_015_warning_already_downloaded_screen.py index b22f3f05..dfef5d33 100644 --- a/e2e/test_015_warning_already_downloaded_screen.py +++ b/e2e/test_015_warning_already_downloaded_screen.py @@ -35,8 +35,8 @@ def test_init(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_invalid_name(self, mock_redirect_exception, mock_get_locale): screen = WarningAlreadyDownloadedScreen() self.render(screen) @@ -47,7 +47,7 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): screen.update(name="MockScreen") # patch assertions - mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") + mock_redirect_exception.assert_called_once() mock_get_locale.assert_any_call() @patch.object(EventLoopBase, "ensure_window", lambda x: None) diff --git a/e2e/test_017_verify_stable_zip_screen.py b/e2e/test_017_verify_stable_zip_screen.py index 2440d00e..ce56c045 100644 --- a/e2e/test_017_verify_stable_zip_screen.py +++ b/e2e/test_017_verify_stable_zip_screen.py @@ -136,8 +136,8 @@ def test_on_pre_enter(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_invalid_name(self, mock_redirect_exception, mock_get_locale): screen = VerifyStableZipScreen() self.render(screen) @@ -149,7 +149,7 @@ def test_fail_update_invalid_name(self, mock_redirect_error, mock_get_locale): # patch assertions mock_get_locale.assert_called() - mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") + mock_redirect_exception.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( diff --git a/e2e/test_023_wipe_screen.py b/e2e/test_023_wipe_screen.py index ae6d700c..dc70883c 100644 --- a/e2e/test_023_wipe_screen.py +++ b/e2e/test_023_wipe_screen.py @@ -54,8 +54,8 @@ def test_init(self, mock_schedule_once, mock_partial, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_error") - def test_fail_update_wrong_name(self, mock_redirect_error, mock_get_locale): + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_update_wrong_name(self, mock_redirect_exception, mock_get_locale): screen = WipeScreen() self.render(screen) @@ -66,7 +66,7 @@ def test_fail_update_wrong_name(self, mock_redirect_error, mock_get_locale): # patch assertions mock_get_locale.assert_called_once() - mock_redirect_error.assert_called_once_with("Invalid screen name: MockScreen") + mock_redirect_exception.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch("src.app.screens.base_screen.BaseScreen.get_locale") diff --git a/e2e/test_025_error_screen.py b/e2e/test_025_error_screen.py new file mode 100644 index 00000000..37b94d15 --- /dev/null +++ b/e2e/test_025_error_screen.py @@ -0,0 +1,180 @@ +import os +from unittest.mock import patch, MagicMock +from kivy.base import EventLoop, EventLoopBase +from kivy.tests.common import GraphicUnitTest +from kivy.core.text import LabelBase, DEFAULT_FONT +from src.app.screens.error_screen import ErrorScreen + + +class TestErrorScreen(GraphicUnitTest): + + @classmethod + def setUpClass(cls): + cwd_path = os.path.dirname(__file__) + rel_assets_path = os.path.join(cwd_path, "..", "assets") + assets_path = os.path.abspath(rel_assets_path) + noto_sans_path = os.path.join(assets_path, "NotoSansCJK_Cy_SC_KR_Krux.ttf") + LabelBase.register(DEFAULT_FONT, noto_sans_path) + + @classmethod + def teardown_class(cls): + EventLoop.exit() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_init(self, mock_get_locale): + screen = ErrorScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + window = EventLoop.window + grid = window.children[0].children[0] + label = grid.children[0] + + # default assertions + self.assertEqual(grid.id, "error_screen_grid") + self.assertEqual(len(grid.children), 1) + self.assertEqual(label.id, "error_screen_label") + + # patch assertions + mock_get_locale.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_make_label_text(self, mock_get_locale): + screen = ErrorScreen() + screen.manager = MagicMock() + screen.manager.screen_names = ["KruxInstallerApp", screen.name] + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + label = screen.ids[f"{screen.id}_label"] + + error = RuntimeError("Error: mocked error: at test") + screen.update(name=screen.name, key="error", value=error) + + text = "".join( + [ + f"[size={screen.SIZE_M}sp]", + "[color=#ff0000]Error[/color]", + "[/size]", + "\n", + "\n", + " mocked error", + "\n", + " at test", + "[/size]", + "\n", + "\n", + f"[size={screen.SIZE_P}sp]", + "Report issue at ", + "[color=#00aabb]", + "[ref=ReportIssue]", + f"{screen.src_code}/issues", + "[/ref]", + "[/color]", + "[/size]", + "\n", + "\n", + f"[size={screen.SIZE_MP}sp]", + "[color=#00FF00]", + "[ref=Back]", + "[u]Back[/u]", + "[/ref]", + "[/color]", + " ", + "[color=#FF0000]", + "[ref=Quit]", + "[u]Quit[/u]", + "[/ref]", + "[/size]", + ] + ) + + print(label.text) + print("============") + print(text) + self.assertEqual(label.text, text) + + # patch assertions + mock_get_locale.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.error_screen.ErrorScreen.set_screen") + def test_on_ref_press_back(self, mock_set_screen, mock_get_locale): + screen = ErrorScreen() + + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + window = EventLoop.window + grid = window.children[0].children[0] + label = grid.children[0] + + action = getattr(ErrorScreen, f"on_ref_press_{screen.id}") + action(label, "Back") + + mock_get_locale.assert_any_call() + mock_set_screen.assert_called_once_with( + name="GreetingsScreen", direction="right" + ) + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.error_screen.BaseScreen.quit_app") + def test_on_ref_press_quit(self, mock_quit_app, mock_get_locale): + screen = ErrorScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + window = EventLoop.window + grid = window.children[0].children[0] + label = grid.children[0] + + action = getattr(ErrorScreen, f"on_ref_press_{screen.id}") + action(label, "Quit") + + mock_get_locale.assert_any_call() + mock_quit_app.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.error_screen.webbrowser.open") + def test_on_ref_press_report(self, mock_web_open, mock_get_locale): + screen = ErrorScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + window = EventLoop.window + grid = window.children[0].children[0] + label = grid.children[0] + + action = getattr(ErrorScreen, f"on_ref_press_{screen.id}") + action(label, "ReportIssue") + + mock_get_locale.assert_any_call() + mock_web_open.assert_called_once_with( + "https://github.com/selfcustody/krux-installer/issues" + ) diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index 87086cab..b533b940 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -171,7 +171,10 @@ def on_enter(self, *args): self.thread = Thread(name=self.name, target=_fn) self.thread.start() else: - self.redirect_error("Downloader isnt configured. Use `update` method first") + msg = "Downloader isnt configured. Use `update` method first" + exc = RuntimeError(msg) + self.error(msg) + self.redirect_exception(exception=exc) def update_download_screen(self, key: str, value: typing.Any): """Update a screen in accord with the valid ones""" @@ -180,14 +183,20 @@ def update_download_screen(self, key: str, value: typing.Any): build_downloader = getattr(self, "build_downloader") build_downloader(value) else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") + msg = f"Invalid value for key '{key}': '{value}'" + exc = RuntimeError(msg) + self.error(msg) + self.redirect_exception(exception=exc) if key == "progress": if value is not None: on_download_progress = getattr(self, "on_download_progress") on_download_progress(value) else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") + msg = f"Invalid value for key '{key}': '{value}'" + exc = RuntimeError(msg) + self.error(msg) + self.redirect_exception(exception=exc) @staticmethod def make_download_info( diff --git a/src/app/screens/base_screen.py b/src/app/screens/base_screen.py index 211cd123..b6c5c2eb 100644 --- a/src/app/screens/base_screen.py +++ b/src/app/screens/base_screen.py @@ -220,17 +220,12 @@ def make_button( f"button::{id} row={row}, pos_hint={btn.pos_hint}, size_hint={btn.size_hint}" ) - def redirect_error(self, msg: str): - """Create a RuntimeError and give it to redirect_exception""" - exception = RuntimeError(msg) - self.redirect_exception(exception=exception) - def redirect_exception(self, exception: Exception): """Get an exception and prepare a ErrorScreen rendering""" screen = self.manager.get_screen("ErrorScreen") fns = [ - partial(screen.update, name=self.name, key="error", value=exception), partial(screen.update, name=self.name, key="canvas"), + partial(screen.update, name=self.name, key="error", value=exception), ] for fn in fns: @@ -252,14 +247,16 @@ def update_screen( if name in allowed_screens: self.debug(f"Updating {self.name} from {name}...") else: - self.redirect_error(f"Invalid screen name: {name}") + exc = RuntimeError(f"Invalid screen name: {name}") + self.redirect_exception(exception=exc) return if key == "locale": if value is not None: self.locale = value else: - self.redirect_error(f"Invalid value for key '{key}': '{value}'") + exc = RuntimeError(f"Invalid value for key '{key}': '{value}'") + self.redirect_exception(exception=exc) if key == "canvas": with self.canvas.before: @@ -269,6 +266,12 @@ def update_screen( if on_update is not None: on_update() + @staticmethod + def quit_app(): + """Stop the kivy process""" + app = App.get_running_app() + app.stop() + @staticmethod def get_destdir_assets() -> str: """Return the current selected path of destination assets directory""" diff --git a/src/app/screens/error_screen.py b/src/app/screens/error_screen.py index c78ebe84..9b024c75 100644 --- a/src/app/screens/error_screen.py +++ b/src/app/screens/error_screen.py @@ -21,11 +21,7 @@ """ error_screen.py """ -from functools import partial -from kivy.clock import Clock -from kivy.core.window import Window -from kivy.graphics.vertex_instructions import Rectangle -from kivy.graphics.context_instructions import Color +import webbrowser from src.app.screens.base_screen import BaseScreen @@ -47,25 +43,30 @@ def __init__(self, **kwargs): self.make_grid(wid=f"{self.id}_grid", rows=1) # START of on_press buttons - def _press(instance): - self.debug(f"Calling Button::{instance.id}::on_press") - self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) - - def _release(instance): - self.debug(f"Calling Button::{instance.id}::on_release") - self.set_background(wid=f"{instance.id}", rgba=(0, 0, 0, 1)) - self.set_screen(name="GreetingsScreen", direction="right") - - self.make_button( - row=0, - wid=f"{self.id}_button", + def on_ref_press(*args): + if args[1] == "Back": + self.set_screen(name="GreetingsScreen", direction="right") + + if args[1] == "Quit": + ErrorScreen.quit_app() + + if args[1] == "ReportIssue": + webbrowser.open(f"{self.src_code}/issues") + + self.make_label( + wid=f"{self.id}_label", root_widget=f"{self.id}_grid", text="", - on_press=_press, - on_release=_release, + halign="center", ) - fn = partial(self.update, name=self.name, key="canvas") - Clock.schedule_once(fn, 0) + + setattr(ErrorScreen, f"on_ref_press_{self.id}", on_ref_press) + self.ids[f"{self.id}_label"].bind(on_ref_press=on_ref_press) + + @staticmethod + def chunkstring(string, length): + """Split a long string into multiline string with equal lengths""" + return (string[0 + i : length + i] for i in range(0, len(string), length)) # pylint: disable=unused-argument def update(self, *args, **kwargs): @@ -74,45 +75,63 @@ def update(self, *args, **kwargs): dialout (debian-li ke) and uucp (archlinux-like) and add user to that group to allow sudoless flash """ - name = kwargs.get("name") - key = kwargs.get("key") + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) value = kwargs.get("value") - self.debug(f"Updating {self.name} from {name}...") - - if key == "locale": - self.locale = value - - elif key == "canvas": - # prepare background - with self.canvas.before: - Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) - - elif key == "error": - self.error(str(value.__context__)) - stack = [msg for msg in str(value.__context__).split(":") if len(msg) < 120] - - self.ids[f"{self.id}_button"].text = "\n".join( - [ - f"[size={self.SIZE_M}sp][color=#ff0000]{stack[0]}[/color][/size]", - f"[size={self.SIZE_MP}sp][color=#efcc00]{"\n".join(stack[1:])}[/color][/size]", - "", - "", - f"[size={self.SIZE_P}sp]Report issue at", - "".join( - [ - "[color=#00aabb]", - f"[ref={self.src_code}/issues/]", - f"{self.src_code}/issues", - "[/ref]", - "[/color]", - ] - ), - "[/size]", - ] - ) - else: - exc_info = ValueError(f"Invalid key: '{key}'") - fn = partial(self.update, name=self.name, key="error", value=exc_info) - Clock.schedule_once(fn, 0) + def on_update(): + if key == "error": + self.error(str(value)) + stack = str(value).split(":") + title = stack[0] + reason = [] + + for r in stack[1:]: + c = list(ErrorScreen.chunkstring(r, 80)) + d = "\n".join(c) + reason.append(d) + + self.ids[f"{self.id}_label"].text = "".join( + [ + f"[size={self.SIZE_M}sp]", + f"[color=#ff0000]{title}[/color]", + "[/size]", + "\n", + "\n", + "\n".join(reason), + "[/size]", + "\n", + "\n", + f"[size={self.SIZE_P}sp]", + "Report issue at ", + "[color=#00aabb]", + "[ref=ReportIssue]", + f"{self.src_code}/issues", + "[/ref]", + "[/color]", + "[/size]", + "\n", + "\n", + f"[size={self.SIZE_MP}sp]", + "[color=#00FF00]", + "[ref=Back]", + "[u]Back[/u]", + "[/ref]", + "[/color]", + " ", + "[color=#FF0000]", + "[ref=Quit]", + "[u]Quit[/u]", + "[/ref]", + "[/size]", + ] + ) + + setattr(ErrorScreen, "on_update", on_update) + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=tuple(self.manager.screen_names), + on_update=getattr(ErrorScreen, "on_update"), + ) diff --git a/src/app/screens/flash_screen.py b/src/app/screens/flash_screen.py index d3470cab..2d6cf122 100644 --- a/src/app/screens/flash_screen.py +++ b/src/app/screens/flash_screen.py @@ -136,7 +136,8 @@ def on_ref_press(*args): App.get_running_app().stop() else: - self.redirect_error(f"Invalid ref: {args[1]}") + exc = RuntimeError(f"Invalid ref: {args[1]}") + self.redirect_exception(exception=exc) self.make_subgrid( wid=f"{self.id}_subgrid", rows=2, root_widget=f"{self.id}_grid" diff --git a/src/app/screens/greetings_screen.py b/src/app/screens/greetings_screen.py index 661838d6..7e02de8a 100644 --- a/src/app/screens/greetings_screen.py +++ b/src/app/screens/greetings_screen.py @@ -119,8 +119,8 @@ def check_permissions_for_dialout_group(self): _group = "uucp" else: - self.redirect_error(msg=f"{distro.name(pretty=True)} not supported") - return + exc = RuntimeError(f"{distro.name(pretty=True)} not supported") + self.redirect_exception(exception=exc) # loop throug all linux groups and check # if the user is registered in the "dialout" group diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index 82bdaacb..60ace97f 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -97,7 +97,10 @@ def on_ref_press(*args): App.get_running_app().stop() else: - self.redirect_error(f"Invalid ref: {args[1]}") + msg = f"Invalid ref: {args[1]}" + exc = RuntimeError(msg) + self.error(msg) + self.redirect_exception(exception=exc) self.make_subgrid( wid=f"{self.id}_subgrid", rows=3, root_widget=f"{self.id}_grid" From cba128df4af253382dca80201356c6c022a7f767 Mon Sep 17 00:00:00 2001 From: qlrd Date: Wed, 11 Sep 2024 16:43:30 -0300 Subject: [PATCH 34/61] coveraged 100% base_download_screen --- e2e/test_009_base_download_screen.py | 67 +++++++++++++++++++++++++ src/app/screens/base_download_screen.py | 20 ++------ 2 files changed, 71 insertions(+), 16 deletions(-) diff --git a/e2e/test_009_base_download_screen.py b/e2e/test_009_base_download_screen.py index 10ecf01e..1bb63d07 100644 --- a/e2e/test_009_base_download_screen.py +++ b/e2e/test_009_base_download_screen.py @@ -94,6 +94,33 @@ def test_set_thread(self, mock_get_locale): # patch tests mock_get_locale.assert_any_call() + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_on_pre_enter(self, mock_get_locale): + screen = BaseDownloadScreen(wid="mock_screen", name="MockScreen") + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + # do tests + screen.on_pre_enter() + text = "".join( + [ + f"[size={screen.SIZE_G}]", + "Connecting...", + "[/size]", + "[color=#efcc00]", + "[/color]", + ] + ) + + self.assertTrue("mock_screen_progress" in screen.ids) + self.assertEqual(screen.ids[f"{screen.id}_progress"].text, text) + mock_get_locale.assert_any_call() + @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" @@ -164,3 +191,43 @@ def test_on_enter( ) mock_create_trigger.assert_called() mock_thread.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_update_download_screen_version(self, mock_get_locale): + screen = BaseDownloadScreen(wid="mock_screen", name="MockScreen") + build_downloader = MagicMock() + setattr(screen, "build_downloader", build_downloader) + + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + # do tests + screen.update_download_screen(key="version", value="0.0.1") + + mock_get_locale.assert_any_call() + build_downloader.assert_called_once_with("0.0.1") + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_update_download_screen_progress(self, mock_get_locale): + screen = BaseDownloadScreen(wid="mock_screen", name="MockScreen") + on_download_progress = MagicMock() + setattr(screen, "on_download_progress", on_download_progress) + + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + # do tests + screen.update_download_screen(key="progress", value="mock") + + mock_get_locale.assert_any_call() + on_download_progress.assert_called_once_with("mock") diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index b533b940..9ed49eb5 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -179,24 +179,12 @@ def on_enter(self, *args): def update_download_screen(self, key: str, value: typing.Any): """Update a screen in accord with the valid ones""" if key == "version": - if value is not None: - build_downloader = getattr(self, "build_downloader") - build_downloader(value) - else: - msg = f"Invalid value for key '{key}': '{value}'" - exc = RuntimeError(msg) - self.error(msg) - self.redirect_exception(exception=exc) + build_downloader = getattr(self, "build_downloader") + build_downloader(value) if key == "progress": - if value is not None: - on_download_progress = getattr(self, "on_download_progress") - on_download_progress(value) - else: - msg = f"Invalid value for key '{key}': '{value}'" - exc = RuntimeError(msg) - self.error(msg) - self.redirect_exception(exception=exc) + on_download_progress = getattr(self, "on_download_progress") + on_download_progress(value) @staticmethod def make_download_info( From da698d92aa7bed26c0956dfb5a082cd3b7c5cdde Mon Sep 17 00:00:00 2001 From: qlrd Date: Wed, 11 Sep 2024 21:12:33 -0300 Subject: [PATCH 35/61] coveraged 100% ask_permission_dialout_screen --- e2e/test_002_ask_permission_dialout_screen.py | 236 +++++++++++++++++- .../screens/ask_permission_dialout_screen.py | 21 +- 2 files changed, 243 insertions(+), 14 deletions(-) diff --git a/e2e/test_002_ask_permission_dialout_screen.py b/e2e/test_002_ask_permission_dialout_screen.py index 53034c0c..ad30cb01 100644 --- a/e2e/test_002_ask_permission_dialout_screen.py +++ b/e2e/test_002_ask_permission_dialout_screen.py @@ -10,7 +10,7 @@ # WARNING: Do not run these tests on windows # they will break because it do not have the builtin 'grp' module -@mark.skipif(sys.platform == "win32", reason="does not run on windows") +@mark.skipif(sys.platform == "win32", reason="does not run on windows or macos") class TestAskPermissionDialoutScreen(GraphicUnitTest): @classmethod @@ -38,15 +38,138 @@ def test_render_label(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - screen.update(name="AskPermissionDialoutScreen", key="user", value="mockeduser") - screen.update(name="AskPermissionDialoutScreen", key="group", value="dialout") - screen.update(name="AskPermissionDialoutScreen", key="distro", value="mockos") - screen.update(name="AskPermissionDialoutScreen", key="screen") self.assertTrue("ask_permission_dialout_screen_label" in screen.ids) # patch assertions mock_get_locale.assert_called_once() + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_on_update_user(self, mock_get_locale): + screen = AskPermissionDialoutScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + screen.update(name=screen.name, key="user", value="mockeduser") + self.assertEqual(screen.user, "mockeduser") + + # patch assertions + mock_get_locale.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_on_update_distro(self, mock_get_locale): + screen = AskPermissionDialoutScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + screen.update(name=screen.name, key="distro", value="mockos") + self.assertEqual(screen.distro, "mockos") + + # patch assertions + mock_get_locale.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch( + "src.app.screens.ask_permission_dialout_screen.AskPermissionDialoutScreen.show_warning" + ) + def test_on_update_screen(self, mock_show_warning, mock_get_locale): + screen = AskPermissionDialoutScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + screen.update(name=screen.name, key="screen") + + # patch assertions + mock_get_locale.assert_called_once() + mock_show_warning.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_on_update_group(self, mock_get_locale): + screen = AskPermissionDialoutScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + screen.update(name=screen.name, key="group", value="mockedgroup") + self.assertEqual(screen.group, "mockedgroup") + + # patch assertions + mock_get_locale.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_show_warning(self, mock_get_locale): + screen = AskPermissionDialoutScreen() + screen.user = "user" + screen.group = "group" + screen.distro = "mockos" + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + text = "".join( + [ + f"[size={screen.SIZE_G}sp][color=#efcc00]WARNING[/color][/size]", + "\n", + f'[size={screen.SIZE_MP}sp]This is the first run of KruxInstaller in "mockos"', + "\n", + "and it appears that you do not have privileged access to make flash procedures.", + "\n", + "To proceed, click in the Allow button and a prompt will ask for your password", + "\n", + "to execute the following command:", + "\n", + "[color=#00ff00]", + "/usr/bin/usermod -a -G group user", + "[/color]", + "[/size]", + "\n", + "\n", + f"[size={screen.SIZE_M}]", + "[color=#00FF00][ref=Allow]Allow[/ref][/color]", + " ", + "[color=#FF0000][ref=Deny]Deny[/ref][/color]", + "[/size]", + ] + ) + + screen.show_warning() + self.assertEqual(screen.ids[f"{screen.id}_label"].text, text) + + # patch assertions + mock_get_locale.assert_called_once() + @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch("sys.platform", "linux") @patch( @@ -79,3 +202,106 @@ def test_press_allow(self, mock_exec, mock_get_locale): env={}, callback=on_permission_created, ) + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("sys.platform", "linux") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.ask_permission_dialout_screen.SudoerLinux.exec") + @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") + def test_fail_press_allow( + self, mock_redirect_exception, mock_exec, mock_get_locale + ): + screen = AskPermissionDialoutScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + screen.bin = "mock" + screen.bin_args = ["-a", "-G"] + screen.group = "mockedgroup" + screen.user = "mockeduser" + + mock_exec.side_effect = RuntimeError("Mocked error") + + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + action = getattr(screen, f"on_ref_press_{screen.id}_label") + action("Allow") + + # patch assertions + on_permission_created = getattr( + AskPermissionDialoutScreen, "on_permission_created" + ) + mock_get_locale.assert_called_once() + mock_exec.assert_called_once_with( + cmd=["/usr/bin/usermod", "-a", "-G", "mockedgroup", "mockeduser"], + env={}, + callback=on_permission_created, + ) + mock_redirect_exception.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("sys.platform", "linux") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.base_screen.BaseScreen.quit_app") + def test_press_deny(self, mock_quit_app, mock_get_locale): + screen = AskPermissionDialoutScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + screen.bin = "mock" + screen.bin_args = ["-a", "-G"] + screen.group = "mockedgroup" + screen.user = "mockeduser" + + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + action = getattr(screen, f"on_ref_press_{screen.id}_label") + action("Deny") + + mock_get_locale.assert_called_once() + mock_quit_app.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("sys.platform", "linux") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + def test_on_permission_created(self, mock_get_locale): + screen = AskPermissionDialoutScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() + screen.bin = "mock" + screen.bin_args = ["-a", "-G"] + screen.group = "mockedgroup" + screen.user = "mockeduser" + + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + action = getattr(AskPermissionDialoutScreen, "on_permission_created") + action("ok") + + text = "".join( + [ + f"[size={screen.SIZE_M}sp]", + "You may need to logout (or even reboot)", + "\n", + "and back in for the new group to take effect.", + "\n", + "\n", + "Do not worry, this message won't appear again.", + "[/size]", + ] + ) + + self.assertEqual(screen.ids[f"{screen.id}_label"].text, text) + + # patch assertions + mock_get_locale.assert_called_once() diff --git a/src/app/screens/ask_permission_dialout_screen.py b/src/app/screens/ask_permission_dialout_screen.py index 8a3acafa..c724b0c2 100644 --- a/src/app/screens/ask_permission_dialout_screen.py +++ b/src/app/screens/ask_permission_dialout_screen.py @@ -24,7 +24,6 @@ from functools import partial from pysudoer import SudoerLinux from kivy.clock import Clock -from kivy.app import App from src.app.screens.base_screen import BaseScreen @@ -61,12 +60,16 @@ def on_permission_created(output: str): "Do not worry, this message won't appear again" ) - self.ids[f"{self.id}_label"].text = "\n".join( + self.ids[f"{self.id}_label"].text = "".join( [ - f"[size={self.SIZE_M}sp]{logout_msg}", + f"[size={self.SIZE_M}sp]", + logout_msg, + "\n", f"{backin_msg}.", - "", - f"{not_worry_msg}.[/size]", + "\n", + "\n", + f"{not_worry_msg}.", + "[/size]", ] ) @@ -96,7 +99,7 @@ def _on_ref_press(*args): self.redirect_exception(exception=err) if args[1] == "Deny": - App.get_running_app().stop() + AskPermissionDialoutScreen.quit_app() self.make_label( wid=f"{self.id}_label", @@ -120,7 +123,7 @@ def update(self, *args, **kwargs): dialout (debian-li ke) and uucp (archlinux-like) and add user to that group to allow sudoless flash """ - name = str(kwargs.get("key")) + name = str(kwargs.get("name")) key = str(kwargs.get("key")) value = kwargs.get("value") @@ -137,7 +140,7 @@ def on_update(): if key == "screen": self.show_warning() - setattr(self, "on_update", on_update) + setattr(AskPermissionDialoutScreen, "on_update", on_update) self.update_screen( name=name, key=key, @@ -148,7 +151,7 @@ def on_update(): "AskPermissionDialoutScreen", "ErrorScreen", ), - on_update=getattr(self, "on_update"), + on_update=getattr(AskPermissionDialoutScreen, "on_update"), ) def show_warning(self): From 158bbf651f2ddfe136a7ea32c85bdf3e00962342 Mon Sep 17 00:00:00 2001 From: qlrd Date: Thu, 12 Sep 2024 10:19:00 -0300 Subject: [PATCH 36/61] coveraged 97% of verify_stable_zip_screen --- e2e/test_017_verify_stable_zip_screen.py | 283 ++++++++++++++++++-- src/app/screens/verify_stable_zip_screen.py | 14 +- src/i18n/en_US.UTF-8.json | 2 +- 3 files changed, 272 insertions(+), 27 deletions(-) diff --git a/e2e/test_017_verify_stable_zip_screen.py b/e2e/test_017_verify_stable_zip_screen.py index ce56c045..21ca3661 100644 --- a/e2e/test_017_verify_stable_zip_screen.py +++ b/e2e/test_017_verify_stable_zip_screen.py @@ -1,5 +1,5 @@ import sys -from unittest.mock import patch, call +from unittest.mock import MagicMock, patch, call from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest from src.app.screens.verify_stable_zip_screen import ( @@ -136,42 +136,289 @@ def test_on_pre_enter(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") - def test_fail_update_invalid_name(self, mock_redirect_exception, mock_get_locale): + @patch( + "src.app.screens.base_screen.BaseScreen.get_destdir_assets", + return_value="mockdir", + ) + @patch( + "src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.build_message_verify_sha256", + return_value="mock", + ) + @patch( + "src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.build_message_verify_signature", + return_value="mock", + ) + def test_on_enter( + self, + mock_build_message_verify_signature, + mock_build_message_verify_sha256, + mock_get_destdir_assets, + mock_get_locale, + ): screen = VerifyStableZipScreen() + screen.manager = MagicMock() + screen.manager.get_screen = MagicMock() self.render(screen) # get your Window instance safely EventLoop.ensure_window() - - # do tests - screen.update(name="MockScreen") + screen.on_pre_enter() + screen.on_enter() # patch assertions mock_get_locale.assert_called() - mock_redirect_exception.assert_called_once() + mock_get_destdir_assets.assert_called_once() + mock_build_message_verify_sha256.assert_called_once_with( + assets_dir="mockdir", version=screen.manager.get_screen().version + ) + mock_build_message_verify_signature.assert_called_once_with( + assets_dir="mockdir", version=screen.manager.get_screen().version + ) + + def test_prettyfy_hash(self): + _hash = "f254692f766dc6b009c8ca7f43b674d088062685bb203b850f8b702f641b5935" + pretty = VerifyStableZipScreen.prettyfy_hash(_hash) + expected = "".join( + [ + "f2 54 69 2f 76 6d c6 b0 09 c8 ca 7f 43 b6 74 d0", + "\n", + "88 06 26 85 bb 20 3b 85 0f 8b 70 2f 64 1b 59 35", + ] + ) + + self.assertEqual(pretty, expected) @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - def test_update_locale(self, mock_get_locale): + @patch( + "src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.verify_sha256", + return_value=tuple(["mockhash", "mockhash", True]), + ) + def test_build_message_verify_sha256(self, mock_verify_sha256, mock_get_locale): screen = VerifyStableZipScreen() - old_loc = screen.locale self.render(screen) # get your Window instance safely EventLoop.ensure_window() - # do tests - screen.update(name="ConfigKruxInstaller", key="locale", value="pt_BR.UTF-8") + if sys.platform in ("linux", "win32"): + size = [screen.SIZE_MP, screen.SIZE_P, screen.SIZE_PP] + else: + size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] - # default assertions - self.assertEqual(screen.locale, "pt_BR.UTF-8") - self.assertFalse(screen.locale == old_loc) + expected = "".join( + [ + f"[size={size[0]}sp]", + "[u]INTEGRITY VERIFICATION[/u]: ", + "[b][color=#00FF00]SUCCESS[/color][/b]", + "[/size]", + "\n", + "\n", + f"[size={size[1]}sp]", + "[b]computed hash from [color=#777777]mock/krux-v0.0.1.zip[/color][/b]", + "[/size]", + "\n", + f"[size={size[1]}sp]mo ck ha sh[/size]", + "\n", + "\n", + f"[size={size[1]}sp]", + "[b]provided hash from [color=#777777]mock/krux-v0.0.1.zip.sha256.txt[/color][/b]", + "[/size]", + "\n", + f"[size={size[1]}sp]mo ck ha sh[/size]", + "\n", + "\n", + "\n", + ] + ) - # patch assertions - mock_get_locale.assert_called() + actual = screen.build_message_verify_sha256(assets_dir="mock", version="v0.0.1") + self.assertEqual(actual, expected) + mock_get_locale.assert_any_call() + mock_verify_sha256.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch( + "src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.verify_sha256", + return_value=tuple(["mockhash", "nomockhash", False]), + ) + def test_failed_build_message_verify_sha256( + self, mock_verify_sha256, mock_get_locale + ): + screen = VerifyStableZipScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + if sys.platform in ("linux", "win32"): + size = [screen.SIZE_MP, screen.SIZE_P, screen.SIZE_PP] + else: + size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] + + expected = "".join( + [ + f"[size={size[0]}sp]", + "[u]INTEGRITY VERIFICATION[/u]: ", + "[b][color=#FF0000]FAILED[/color][/b]", + "[/size]", + "\n", + "\n", + f"[size={size[1]}sp]", + "[b]computed hash from [color=#777777]mock/krux-v0.0.1.zip[/color][/b]", + "[/size]", + "\n", + f"[size={size[1]}sp]mo ck ha sh[/size]", + "\n", + "\n", + f"[size={size[1]}sp]", + "[b]provided hash from [color=#777777]mock/krux-v0.0.1.zip.sha256.txt[/color][/b]", + "[/size]", + "\n", + f"[size={size[1]}sp]no mo ck ha sh[/size]", + "\n", + "\n", + "\n", + ] + ) + + actual = screen.build_message_verify_sha256(assets_dir="mock", version="v0.0.1") + self.assertEqual(actual, expected) + mock_get_locale.assert_any_call() + mock_verify_sha256.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch( + "src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.verify_signature", + return_value=True, + ) + def test_build_message_verify_signature(self, mock_verify_sig, mock_get_locale): + screen = VerifyStableZipScreen() + screen.success = True + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + if sys.platform in ("linux", "win32"): + size = [screen.SIZE_MP, screen.SIZE_P, screen.SIZE_PP] + else: + size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] + + expected = "".join( + [ + f"[size={size[0]}sp]", + "[u]AUTHENTICITY VERIFICATION[/u]: ", + "[b][color=#00FF00]GOOD SIGNATURE[/color][/b]", + "[/size]", + "\n", + "\n", + "\n", + f"[size={size[1]}sp]If you have openssl installed on your system[/size]", + "\n", + f"[size={size[1]}sp]you can check manually with the following command:[/size]", + "\n", + "\n", + f"[size={size[1]}sp]", + "[b]", + "openssl sha256< [color=#777777]mock/krux-v0.0.1.zip[/color] -binary | \\", + "\n", + "openssl pkeyutl -verify -pubin -inkey [color=#777777]mock/selfcustody.pem[/color] \\", + "\n", + "-sigfile [color=#777777]mock/krux-v0.0.1.zip.sig[/color]", + "[/size]", + "[/b]", + "\n", + "\n", + f"[size={size[0]}sp]", + "[ref=Proceed][color=#00ff00][u]Proceed[/u][/ref][/color]", + " ", + "[ref=Back][color=#ff0000][u]Back[/u][/ref][/color]", + "[/b]", + "[/size]", + ] + ) + + actual = screen.build_message_verify_signature( + assets_dir="mock", version="v0.0.1" + ) + + self.assertEqual(actual, expected) + mock_get_locale.assert_any_call() + mock_verify_sig.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch( + "src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.verify_signature", + return_value=False, + ) + def test_failed_build_message_verify_signature( + self, mock_verify_sig, mock_get_locale + ): + screen = VerifyStableZipScreen() + screen.success = True + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + if sys.platform in ("linux", "win32"): + size = [screen.SIZE_MP, screen.SIZE_P, screen.SIZE_PP] + else: + size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] + + expected = "".join( + [ + f"[size={size[0]}sp]", + "[u]AUTHENTICITY VERIFICATION[/u]: ", + "[b][color=#FF0000]BAD SIGNATURE[/color][/b]", + "[/size]", + "\n", + "\n", + "\n", + f"[size={size[1]}sp]If you have openssl installed on your system[/size]", + "\n", + f"[size={size[1]}sp]you can check manually with the following command:[/size]", + "\n", + "\n", + f"[size={size[1]}sp]", + "[b]", + "openssl sha256< [color=#777777]mock/krux-v0.0.1.zip[/color] -binary | \\", + "\n", + "openssl pkeyutl -verify -pubin -inkey [color=#777777]mock/selfcustody.pem[/color] \\", + "\n", + "-sigfile [color=#777777]mock/krux-v0.0.1.zip.sig[/color]", + "[/size]", + "[/b]", + "\n", + "\n", + f"[size={size[0]}sp]", + "[ref=Proceed][color=#00ff00][u]Proceed[/u][/ref][/color]", + " ", + "[ref=Back][color=#ff0000][u]Back[/u][/ref][/color]", + "[/b]", + "[/size]", + ] + ) + + actual = screen.build_message_verify_signature( + assets_dir="mock", version="v0.0.1" + ) + + self.assertEqual(actual, expected) + mock_get_locale.assert_any_call() + mock_verify_sig.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( @@ -198,7 +445,7 @@ def test_on_press_proceed( # DO tests screen.on_pre_enter() action = getattr(VerifyStableZipScreen, f"on_ref_press_{screen.id}") - action("Mock", "UnzipStableScreen") + action(None, "Proceed") # patch assertions mock_get_locale.assert_called() @@ -257,7 +504,7 @@ def test_on_press_back(self, mock_set_screen, mock_get_locale): # DO tests screen.on_pre_enter() action = getattr(VerifyStableZipScreen, f"on_ref_press_{screen.id}") - action("Mock", "MainScreen") + action(None, "Back") # patch assertions mock_get_locale.assert_called() diff --git a/src/app/screens/verify_stable_zip_screen.py b/src/app/screens/verify_stable_zip_screen.py index b19c14d2..4e8eb7e8 100644 --- a/src/app/screens/verify_stable_zip_screen.py +++ b/src/app/screens/verify_stable_zip_screen.py @@ -50,10 +50,7 @@ def __init__(self, **kwargs): # create a ref text that instead redirect # to a web page, redirect to a screen def _on_ref_press(*args): - self.debug(f"Calling ref::{args[0]}::on_ref_press") - self.debug(f"Opening {args[1]}") - - if args[1] == "UnzipStableScreen": + if args[1] == "Proceed": main_screen = self.manager.get_screen("MainScreen") u = self.manager.get_screen("UnzipStableScreen") @@ -77,7 +74,7 @@ def _on_ref_press(*args): self.set_screen(name="UnzipStableScreen", direction="left") - elif args[1] == "MainScreen": + if args[1] == "Back": self.set_screen(name="MainScreen", direction="right") setattr(VerifyStableZipScreen, f"on_ref_press_{self.id}", _on_ref_press) @@ -275,7 +272,8 @@ def build_message_verify_signature(self, assets_dir: str, version: str) -> str: "\n", "\n", f"[size={size[1]}sp]{installed_msg}[/size]", - "\n" f"[size={size[1]}sp]{check_msg}:[/size]", + "\n", + f"[size={size[1]}sp]{check_msg}:[/size]", "\n", "\n", f"[size={size[1]}sp]", @@ -290,9 +288,9 @@ def build_message_verify_signature(self, assets_dir: str, version: str) -> str: "\n", "\n", f"[size={size[0]}sp]", - f"[ref=UnzipStableScreen][color=#00ff00][u]{proceed}[/u][/ref][/color]", + f"[ref=Proceed][color=#00ff00][u]{proceed}[/u][/ref][/color]", " ", - f"[ref=MainScreen][color=#ff0000][u]{back}[/u][/ref][/color]", + f"[ref=Back][color=#ff0000][u]{back}[/u][/ref][/color]", "[/b]", "[/size]", ] diff --git a/src/i18n/en_US.UTF-8.json b/src/i18n/en_US.UTF-8.json index dc98c484..bac934cc 100644 --- a/src/i18n/en_US.UTF-8.json +++ b/src/i18n/en_US.UTF-8.json @@ -92,7 +92,7 @@ "BAD": "BAD", "SIGNATURE": "SIGNATURE", "If you have openssl installed on your system": "If you have openssl installed on your system", - "you can check manually with the following command": "you can check with the following command", + "you can check manually with the following command": "you can check manually with the following command", "Proceed": "Proceed", "Back": "Back" }, From 3ea346e133d6ff868137e1bfaa32b64f774e3c33 Mon Sep 17 00:00:00 2001 From: qlrd Date: Thu, 12 Sep 2024 10:32:37 -0300 Subject: [PATCH 37/61] coveraged 97% of verify_stable_zip_screen II --- e2e/test_017_verify_stable_zip_screen.py | 27 +++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/e2e/test_017_verify_stable_zip_screen.py b/e2e/test_017_verify_stable_zip_screen.py index 21ca3661..2badd478 100644 --- a/e2e/test_017_verify_stable_zip_screen.py +++ b/e2e/test_017_verify_stable_zip_screen.py @@ -1,3 +1,4 @@ +import os import sys from unittest.mock import MagicMock, patch, call from kivy.base import EventLoop, EventLoopBase @@ -208,6 +209,7 @@ def test_build_message_verify_sha256(self, mock_verify_sha256, mock_get_locale): else: size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] + p = os.path.join("mock", "krux-v0.0.1.zip") expected = "".join( [ f"[size={size[0]}sp]", @@ -217,14 +219,14 @@ def test_build_message_verify_sha256(self, mock_verify_sha256, mock_get_locale): "\n", "\n", f"[size={size[1]}sp]", - "[b]computed hash from [color=#777777]mock/krux-v0.0.1.zip[/color][/b]", + f"[b]computed hash from [color=#777777]{p}[/color][/b]", "[/size]", "\n", f"[size={size[1]}sp]mo ck ha sh[/size]", "\n", "\n", f"[size={size[1]}sp]", - "[b]provided hash from [color=#777777]mock/krux-v0.0.1.zip.sha256.txt[/color][/b]", + f"[b]provided hash from [color=#777777]{p}.sha256.txt[/color][/b]", "[/size]", "\n", f"[size={size[1]}sp]mo ck ha sh[/size]", @@ -261,6 +263,7 @@ def test_failed_build_message_verify_sha256( else: size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] + p = os.path.join("mock", "krux-v0.0.1.zip") expected = "".join( [ f"[size={size[0]}sp]", @@ -270,14 +273,14 @@ def test_failed_build_message_verify_sha256( "\n", "\n", f"[size={size[1]}sp]", - "[b]computed hash from [color=#777777]mock/krux-v0.0.1.zip[/color][/b]", + f"[b]computed hash from [color=#777777]{p}[/color][/b]", "[/size]", "\n", f"[size={size[1]}sp]mo ck ha sh[/size]", "\n", "\n", f"[size={size[1]}sp]", - "[b]provided hash from [color=#777777]mock/krux-v0.0.1.zip.sha256.txt[/color][/b]", + f"[b]provided hash from [color=#777777]{p}.sha256.txt[/color][/b]", "[/size]", "\n", f"[size={size[1]}sp]no mo ck ha sh[/size]", @@ -313,6 +316,8 @@ def test_build_message_verify_signature(self, mock_verify_sig, mock_get_locale): else: size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] + p = os.path.join("mock", "krux-v0.0.1.zip") + s = os.path.join("mock", "selfcustody.pem") expected = "".join( [ f"[size={size[0]}sp]", @@ -329,11 +334,11 @@ def test_build_message_verify_signature(self, mock_verify_sig, mock_get_locale): "\n", f"[size={size[1]}sp]", "[b]", - "openssl sha256< [color=#777777]mock/krux-v0.0.1.zip[/color] -binary | \\", + f"openssl sha256< [color=#777777]{p}[/color] -binary | \\", "\n", - "openssl pkeyutl -verify -pubin -inkey [color=#777777]mock/selfcustody.pem[/color] \\", + f"openssl pkeyutl -verify -pubin -inkey [color=#777777]{s}[/color] \\", "\n", - "-sigfile [color=#777777]mock/krux-v0.0.1.zip.sig[/color]", + f"-sigfile [color=#777777]{p}.sig[/color]", "[/size]", "[/b]", "\n", @@ -378,6 +383,8 @@ def test_failed_build_message_verify_signature( else: size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] + p = os.path.join("mock", "krux-v0.0.1.zip") + s = os.path.join("mock", "selfcustody.pem") expected = "".join( [ f"[size={size[0]}sp]", @@ -394,11 +401,11 @@ def test_failed_build_message_verify_signature( "\n", f"[size={size[1]}sp]", "[b]", - "openssl sha256< [color=#777777]mock/krux-v0.0.1.zip[/color] -binary | \\", + f"openssl sha256< [color=#777777]{p}[/color] -binary | \\", "\n", - "openssl pkeyutl -verify -pubin -inkey [color=#777777]mock/selfcustody.pem[/color] \\", + f"openssl pkeyutl -verify -pubin -inkey [color=#777777]{s}[/color] \\", "\n", - "-sigfile [color=#777777]mock/krux-v0.0.1.zip.sig[/color]", + f"-sigfile [color=#777777]{p}.sig[/color]", "[/size]", "[/b]", "\n", From a6af392905161a6acdc29ed6b614889dba55ebe6 Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 13 Sep 2024 07:41:21 -0300 Subject: [PATCH 38/61] added line on create-deb to add user on input group for systems that require permission for /dev/eventX --- .ci/create-deb.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.ci/create-deb.sh b/.ci/create-deb.sh index d3b8693c..ab1be580 100755 --- a/.ci/create-deb.sh +++ b/.ci/create-deb.sh @@ -160,13 +160,15 @@ echo " !!!WARNING!!!" echo " -------------" echo "" if [ -n "\$SUDO_USER" ] && [ "\$SUDO_USER" != "root" ]; then - echo "Adding user \$SUDO_USER to 'dialout' group to enable flash procedure..." + echo "Adding user \$SUDO_USER to 'dialout' and 'input' groups to enable flash procedure..." echo "You'll need to reboot your system to enable changes" usermod -a -G dialout \$SUDO_USER + usermod -a -G input \$SUDO_USER elif [ -n "\$USER" ] && [ "\$USER" != "root"]; then - echo "Adding user \$USER to 'dialout' group to enable flash procedure..." + echo "Adding user \$USER to 'dialout' and 'input' groups to enable flash procedure..." echo "You'll need to reboot your system to enable changes" usermod -a -G dialout \$USER + usermod -a -G input \$SUDO_USER fi echo "" echo "" From f75b3c532643d497e0d31da73ff55d622ae62248 Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 13 Sep 2024 07:51:17 -0300 Subject: [PATCH 39/61] Updated README.md --- README.md | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 3fa3cd85..9f2aaf3e 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # Krux Installer -[![Build main branch](https://github.com/selfcustody/krux-installer/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/selfcustody/krux-installer/actions/workflows/build.yml) -[![codecov](https://codecov.io/gh/qlrd/krux-installer/tree/kivy/graph/badge.svg?token=KD41H20MYS)](https://codecov.io/gh/qlrd/krux-installer) +[![Build](https://github.com/selfcustody/krux-installer/actions/workflows/build.yml/badge.svg)](https://github.com/qlrd/krux-installer/actions/workflows/build.yml) +[![codecov](https://codecov.io/gh/selfcustody/krux-installer/graph/badge.svg?token=T4LMZtPa5H)](https://codecov.io/gh/selfcustody/krux-installer) [![created at](https://img.shields.io/github/created-at/selfcustody/krux-installer)](https://github.com/selfcustody/krux-installer/commit/5d177795fe3df380c54d424ccfd0f23fc7e62c41) [![downloads](https://img.shields.io/github/downloads/selfcustody/krux-installer/total)](https://github.com/selfcustody/krux-installer/releases) [![downloads (latest release)](https://img.shields.io/github/downloads/selfcustody/krux-installer/latest/total)](https://github.com/selfcustody/krux-installer/releases) -[![commits (since latest release)](https://img.shields.io/github/commits-since/selfcustody/krux-installer/latest/main)](https://github.com/qlrd/krux-installer/compare/main...kivy) +[![commits (since latest release)](https://img.shields.io/github/commits-since/selfcustody/krux-installer/latest/main)](https://github.com/qlrd/krux-installer/compare/main...develop) Krux Installer is a GUI based tool to flash [Krux](https://github.com/selfcustody/krux) without typing any command in terminal for [flash the firmware onto the device](https://selfcustody.github.io/krux/getting-started/installing/#flash-the-firmware-onto-the-device). @@ -16,12 +16,12 @@ There are pre-built [releases](https://github.com/selfcustody/krux-installer/releases) for: * Linux: - * Debian-like - * Fedora-like -* Windows + * Debian-like; + * Fedora-like; +* Windows; * MacOS: - * intel processors - * arm64 processors (M1/M2/M3) + * intel processors; + * arm64 processors (M1/M2/M3). To build it from the source, please follow the steps below: @@ -187,36 +187,27 @@ poetry run poe test For systems without a window manager: ```bash +# Linux only poetry run poe test --no-xvfb ``` ### Build -At the moment, you'll need to [patch some code on `kivy`](https://github.com/kivy/kivy/issues/8653#issuecomment-2028509695) -to build the Graphical User Interface: - -#### Build for Debian, Fedora, MacOS - -Make sure you have the `wget` tool to download a -[specific commit](https://raw.githubusercontent.com/ikus060/kivy/21c7110ee79f355d6a42da0a274d2426b1e18665/kivy/tools/packaging/pyinstaller_hooks/__init__.py). - -If you not have: +* Linux: -* Debian: `sudo apt-get install wget`; -* Fedora: `sudo dnf install wget`; -* MacOS: `brew install wget`. +```bash +poetry run poe build-linux +``` -Then you can patch PyInstaller hook for kivy and build an executable: +* MacOS: ```bash -poetry run poe patch-nix -poetry run poe build-nix +poetry run poe build-macos ``` -#### Build for Windows +* Windows: ```bash -poetry run poe patch-win poetry run poe build-win ``` @@ -227,5 +218,5 @@ It will export all project in a * macOS: `./dist/krux-installer.app/Contents/MacOS/krux-installer` * windows: `./dist/krux-installer.exe` -To more options see [.ci/create-spec.py](./.ci/create-spec.py) -against the PyInstaller [options](https://pyinstaller.org). +To more options see [.ci/create-spec.py](./.ci/create-spec.py) against the PyInstaller +[options](https://pyinstaller.org). From 0f5149f42a6f7ce31b0dae68ef93c2f0a81c108e Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 13 Sep 2024 09:18:46 -0300 Subject: [PATCH 40/61] Updated the README to be more readable --- README.md | 62 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 9f2aaf3e..d13c3840 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Krux Installer -[![Build](https://github.com/selfcustody/krux-installer/actions/workflows/build.yml/badge.svg)](https://github.com/qlrd/krux-installer/actions/workflows/build.yml) +[![Build](https://github.com/selfcustody/krux-installer/actions/workflows/build.yml/badge.svg)](https://github.com/selfcustody/krux-installer/actions/workflows/build.yml) [![codecov](https://codecov.io/gh/selfcustody/krux-installer/graph/badge.svg?token=T4LMZtPa5H)](https://codecov.io/gh/selfcustody/krux-installer) [![created at](https://img.shields.io/github/created-at/selfcustody/krux-installer)](https://github.com/selfcustody/krux-installer/commit/5d177795fe3df380c54d424ccfd0f23fc7e62c41) [![downloads](https://img.shields.io/github/downloads/selfcustody/krux-installer/total)](https://github.com/selfcustody/krux-installer/releases) @@ -29,18 +29,10 @@ To build it from the source, please follow the steps below: * [Linux](/#linux) * [Windows](/#windows) * [MacOS](/#macos) - * [Install brew package manager](/#install-brew-package-manager) - * [Install latest python](/#install-latest-python) - * [Ensure openssl have a correct link](/#ensure-openssl-have-a-correct-link) - * [Patch your zshrc](/#patch-your-zshrc) * [Install poetry](/#install-poetry) * [Download sources](/#download-sources) * [Update code](/#update-code) * [Developing](/#developing) - * [Format code](/#format-code) - * [Lint](/#lint) - * [Test](/#test) - * [Build](/#build) ## System setup @@ -62,13 +54,16 @@ Follow the instructions at [python.org](https://www.python.org/downloads/windows Before installing `krux-installer` source code, you will need prepare the system: -#### Install `brew` package manager +
+Install `brew` package manager ```bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` +
-#### Install latest `python` +
+Install latest python ```bash brew install python @@ -79,8 +74,10 @@ and add this line to your `~/.zshrc`: ```bash alias python=python3 ``` +
-#### Ensure `openssl` have a correct link +
+ Ensure openssl have a correct link Python's `ssl` module relies on OpenSSL for cryptographic operations. Ensure that OpenSSL is installed on your system and is compatible with the @@ -102,8 +99,10 @@ brew link --force openssl This ensures that the OpenSSL libraries are available in the expected locations that Python can find and use. +
-#### Patch your zshrc +
+Patch your zshrc Library paths on MacOS involves verifying that the environment variables and system configurationsare correctyly set to find the necessary libraries, such as OpenSSL, @@ -123,6 +122,8 @@ OPENSSL_FULL_VERSION=`openssl --version | awk ' { print $2}'` export DYLD_LIBRARY_PATH="/opt/homebrew/Cellar/openssl@$OPENSSL_MAJOR_VERSION/$OPENSSL_FULL_VERSION/lib:$DYLD_LIBRARY_PATH" ``` +
+ ### Install poetry Make sure you have `poetry` installed: @@ -160,30 +161,40 @@ git submodule update --init ## Developing Krux-Installer uses `poe` task manager for formatting, linting, -tests and coverage. To see all available tasks, run: +tests, coverage and build. + +
+See all available tasks ```bash poetry run poe ``` +
-### Format code +
+Format code ```bash poetry run poe format ``` +
-### Lint +
+Lint ```bash poetry run poe lint ``` +
-### Test +
+Test and coverage ```bash poetry run poe test ``` + For systems without a window manager: ```bash @@ -191,21 +202,29 @@ For systems without a window manager: poetry run poe test --no-xvfb ``` -### Build +You can see all coverage results opening you browser and type +`file:////krux-installer/htmlcov/index.html` (assuming `folder` is where you placed the +`krux-installer` project). +
-* Linux: +
+Build for any Linux distribution ```bash poetry run poe build-linux ``` +
-* MacOS: +
+Build for MacOS ```bash poetry run poe build-macos ``` +
-* Windows: +
+Build for Windows ```bash poetry run poe build-win @@ -220,3 +239,4 @@ It will export all project in a To more options see [.ci/create-spec.py](./.ci/create-spec.py) against the PyInstaller [options](https://pyinstaller.org). +
From 3bf1950bcb710b62186c14a99ecab6b0dc55f9bb Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 13 Sep 2024 09:39:37 -0300 Subject: [PATCH 41/61] Sketching CHANGELOG and changed version to 0.0.20-alpha-2 --- CHANGELOG.md | 16 ++++++++++++++++ pyproject.toml | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dea23d9..9409c94b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # CHANGELOG +## 0.0.20-alpha-2 + +- Changed the version from `0.0.2-alpha` to `0.0.20-alpha-2` as suggested by @odudex; +- Removed startup messages as suggested by @tadeubas: + * On linux the `GreetingsScreen` class will check: + * if user is on `dialout`/`uucp` group; + * internet connection + * On MacOS an Windows the `GreetingsScreen` class will check: + * internet connection +- Added a line on `.ci/create-deb` for add user to `input` on debian-based systems where + require permissions for `/dev/input/eventX` (thanks to @theautumnbridge); +- Refactored the code a little bit to be more pythonic one; +- Added more tests: + - ask_permissions_dialout_screen; + - error_screen. + ## 0.0.2-alpha - code refactoration from `nodejs` to `python`; diff --git a/pyproject.toml b/pyproject.toml index 313a30a0..d879ff4e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "krux-installer" -version = "0.0.2-alpha" +version = "0.0.20-alpha-2" description = "A GUI based application to flash Krux firmware on K210 based devices" authors = [ "qlrd " From 6e8e982290099b9886b2c60a942ac97ca9ee671f Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 13 Sep 2024 10:18:42 -0300 Subject: [PATCH 42/61] Sketching CHANGELOG and changed version to 0.0.20-alpha-2 II --- e2e/test_008_about_screen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/test_008_about_screen.py b/e2e/test_008_about_screen.py index 0e21c35c..6ea1b06f 100644 --- a/e2e/test_008_about_screen.py +++ b/e2e/test_008_about_screen.py @@ -43,7 +43,7 @@ def test_render_main_screen(self, mock_get_locale): text = "".join( [ f"[size={screen.SIZE_G}sp]", - "[ref=SourceCode][b]v0.0.2-alpha[/b][/ref]", + "[ref=SourceCode][b]v0.0.20-alpha-2[/b][/ref]", "[/size]", "\n", "\n", @@ -87,7 +87,7 @@ def test_update_locale(self, mock_get_locale): text = "".join( [ f"[size={screen.SIZE_G}sp]", - "[ref=SourceCode][b]v0.0.2-alpha[/b][/ref]", + "[ref=SourceCode][b]v0.0.20-alpha-2[/b][/ref]", "[/size]", "\n", "\n", From 61bb567717d1c5ce1e0fdeb0fa8b18927f924692 Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 13 Sep 2024 14:17:09 -0300 Subject: [PATCH 43/61] reverted CHANGELOG.md --- CHANGELOG.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9409c94b..0dea23d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,21 +1,5 @@ # CHANGELOG -## 0.0.20-alpha-2 - -- Changed the version from `0.0.2-alpha` to `0.0.20-alpha-2` as suggested by @odudex; -- Removed startup messages as suggested by @tadeubas: - * On linux the `GreetingsScreen` class will check: - * if user is on `dialout`/`uucp` group; - * internet connection - * On MacOS an Windows the `GreetingsScreen` class will check: - * internet connection -- Added a line on `.ci/create-deb` for add user to `input` on debian-based systems where - require permissions for `/dev/input/eventX` (thanks to @theautumnbridge); -- Refactored the code a little bit to be more pythonic one; -- Added more tests: - - ask_permissions_dialout_screen; - - error_screen. - ## 0.0.2-alpha - code refactoration from `nodejs` to `python`; From 11189e6e7f1d82880f7b93ee7f94d0be61205c64 Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 13 Sep 2024 14:25:17 -0300 Subject: [PATCH 44/61] enabled MD033 on markdownlint --- .github/workflows/ci.yml | 2 +- README.md | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 347d1357..53afb846 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,4 +82,4 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - name: Lint markdown - run: npx markdownlint-cli ${{ needs.job1.outputs.markdown_files }} --ignore node_modules + run: npx markdownlint-cli --disable MD033 --ignore node_modules ${{ needs.job1.outputs.markdown_files }} diff --git a/README.md b/README.md index d13c3840..356b9f7e 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ Before installing `krux-installer` source code, you will need prepare the system ```bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` +
@@ -74,6 +75,7 @@ and add this line to your `~/.zshrc`: ```bash alias python=python3 ``` +
@@ -160,8 +162,8 @@ git submodule update --init ## Developing -Krux-Installer uses `poe` task manager for formatting, linting, -tests, coverage and build. +Krux-Installer uses `poe` task manager for formatting, linting, tests, +coverage and build.
See all available tasks @@ -169,6 +171,7 @@ tests, coverage and build. ```bash poetry run poe ``` +
@@ -177,6 +180,7 @@ poetry run poe ```bash poetry run poe format ``` +
@@ -185,6 +189,7 @@ poetry run poe format ```bash poetry run poe lint ``` +
@@ -194,7 +199,6 @@ poetry run poe lint poetry run poe test ``` - For systems without a window manager: ```bash @@ -202,9 +206,9 @@ For systems without a window manager: poetry run poe test --no-xvfb ``` -You can see all coverage results opening you browser and type -`file:////krux-installer/htmlcov/index.html` (assuming `folder` is where you placed the -`krux-installer` project). +You can see all coverage results opening you browser and type +`file:////krux-installer/htmlcov/index.html` (assuming +`folder` is where you placed the `krux-installer` project).
@@ -213,6 +217,7 @@ You can see all coverage results opening you browser and type ```bash poetry run poe build-linux ``` +
@@ -221,6 +226,7 @@ poetry run poe build-linux ```bash poetry run poe build-macos ``` +
From d463fd7a1bd2c9ed2c516cf8d8d15c233a4eab73 Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 13 Sep 2024 14:46:02 -0300 Subject: [PATCH 45/61] fixing CHANGELOG.md --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dea23d9..ce14686f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # CHANGELOG +## 0.0.20-alpha-2 + +- Changed the version from `0.0.2-alpha` to `0.0.20-alpha-2` as suggested by @odudex; +- Removed startup messages as suggested by @tadeubas: + - On linux the `GreetingsScreen` class will check: + - if user is on `dialout`/`uucp` group; + - internet connection + - On MacOS an Windows the `GreetingsScreen` class will check: + - internet connection +- Added a line on `.ci/create-deb` for add user to `input` on debian-based systems where + require permissions for `/dev/input/eventX` (thanks to @theautumnbridge); +- Refactored the code a little bit to be more pythonic one; +- Added more tests: + - ask_permissions_dialout_screen; + - error_screen. + ## 0.0.2-alpha - code refactoration from `nodejs` to `python`; From 6e3cb443e7d87f5a09cc4f16eec393372a4827a3 Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 13 Sep 2024 14:49:18 -0300 Subject: [PATCH 46/61] fixed .ci/create-deb.sh if user is already sudo --- .ci/create-deb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/create-deb.sh b/.ci/create-deb.sh index ab1be580..9cf1e200 100755 --- a/.ci/create-deb.sh +++ b/.ci/create-deb.sh @@ -168,7 +168,7 @@ elif [ -n "\$USER" ] && [ "\$USER" != "root"]; then echo "Adding user \$USER to 'dialout' and 'input' groups to enable flash procedure..." echo "You'll need to reboot your system to enable changes" usermod -a -G dialout \$USER - usermod -a -G input \$SUDO_USER + usermod -a -G input \$USER fi echo "" echo "" From c59261931c0121f53e273fb71512e296a3920086 Mon Sep 17 00:00:00 2001 From: qlrd Date: Sun, 15 Sep 2024 22:09:48 -0300 Subject: [PATCH 47/61] huge refactoration of text sizes and resize window behaviour --- .pylint/src | 2 +- e2e/test_000_base_screen.py | 10 ++ e2e/test_002_ask_permission_dialout_screen.py | 17 +- e2e/test_003_main_screen.py | 32 ++-- e2e/test_004_select_device_screen.py | 12 +- e2e/test_005_select_version_screen.py | 4 +- e2e/test_006_select_old_version_screen.py | 4 +- e2e/test_007_warning_beta_screen.py | 39 +---- e2e/test_008_about_screen.py | 26 +-- e2e/test_010_download_stable_zip_screen.py | 35 +--- ...t_011_download_stable_zip_sha256_screen.py | 36 +--- ...test_012_download_stable_zip_sig_screen.py | 36 +--- ...est_013_download_selfcustody_pem_screen.py | 35 +--- e2e/test_014_download_beta_screen.py | 56 +----- ...t_015_warning_already_downloaded_screen.py | 37 ++-- e2e/test_016_unzip_stable_screen.py | 159 +++++------------- e2e/test_017_verify_stable_zip_screen.py | 145 +++++++--------- e2e/test_022_flash_screen.py | 39 +---- e2e/test_023_wipe_screen.py | 15 +- e2e/test_024_warning_wipe_screen.py | 21 +-- e2e/test_025_error_screen.py | 22 +-- src/app/__init__.py | 5 +- src/app/screens/about_screen.py | 30 ++-- .../screens/ask_permission_dialout_screen.py | 23 ++- src/app/screens/base_download_screen.py | 41 +++-- src/app/screens/base_flash_screen.py | 4 +- src/app/screens/base_screen.py | 62 ++++--- src/app/screens/download_beta_screen.py | 11 +- .../download_selfcustody_pem_screen.py | 8 +- src/app/screens/download_stable_zip_screen.py | 8 +- .../download_stable_zip_sha256_screen.py | 2 - .../screens/download_stable_zip_sig_screen.py | 2 - src/app/screens/error_screen.py | 22 +-- src/app/screens/flash_screen.py | 60 ++----- src/app/screens/main_screen.py | 41 +++-- src/app/screens/select_device_screen.py | 10 +- src/app/screens/select_old_version_screen.py | 4 + src/app/screens/select_version_screen.py | 35 ++-- src/app/screens/unzip_stable_screen.py | 56 ++---- src/app/screens/verify_stable_zip_screen.py | 143 ++++++---------- .../warning_already_downloaded_screen.py | 51 +++--- src/app/screens/warning_beta_screen.py | 17 +- src/app/screens/warning_wipe_screen.py | 38 ++--- src/app/screens/wipe_screen.py | 58 ++----- src/i18n/pt_BR.UTF-8.json | 2 +- 45 files changed, 498 insertions(+), 1017 deletions(-) diff --git a/.pylint/src b/.pylint/src index 3c1301fa..e596ce0a 100644 --- a/.pylint/src +++ b/.pylint/src @@ -285,7 +285,7 @@ exclude-too-few-public-methods= ignored-parents= # Maximum number of arguments for function / method. -max-args=7 +max-args=10 # Maximum number of attributes for a class (see R0902). max-attributes=20 diff --git a/e2e/test_000_base_screen.py b/e2e/test_000_base_screen.py index 9defd98b..6a870c32 100644 --- a/e2e/test_000_base_screen.py +++ b/e2e/test_000_base_screen.py @@ -275,8 +275,10 @@ def test_make_button(self, mock_get_locale): wid="mock_button", root_widget="mock_grid", text="Mocked button", + halign=None, on_press=MagicMock(), on_release=MagicMock(), + on_ref_press=MagicMock(), ) self.render(screen_0) @@ -313,8 +315,10 @@ def test_clear_grid(self, mock_get_locale): wid=f"mock_button_{i}", root_widget="mock_grid", text="Mocked button", + halign=None, on_press=MagicMock(), on_release=MagicMock(), + on_ref_press=MagicMock(), ) self.render(screen_0) @@ -341,8 +345,10 @@ def test_fail_update_screen_invalid_screen( wid="mock_button", root_widget="mock_grid", text="Mocked button", + halign=None, on_press=MagicMock(), on_release=MagicMock(), + on_ref_press=MagicMock(), ) self.render(screen) screen.update_screen( @@ -367,8 +373,10 @@ def test_update_screen_locale(self, mock_get_locale): wid="mock_button", root_widget="mock_grid", text="Mocked button", + halign=None, on_press=MagicMock(), on_release=MagicMock(), + on_ref_press=MagicMock(), ) self.render(screen) self.assertEqual(screen.locale, "en_US.UTF-8") @@ -395,8 +403,10 @@ def test_update_screen_canvas(self, mock_rectangle, mock_color, mock_get_locale) wid="mock_button", root_widget="mock_grid", text="Mocked button", + halign=None, on_press=MagicMock(), on_release=MagicMock(), + on_ref_press=MagicMock(), ) self.render(screen) screen.update_screen( diff --git a/e2e/test_002_ask_permission_dialout_screen.py b/e2e/test_002_ask_permission_dialout_screen.py index ad30cb01..5be8e5dc 100644 --- a/e2e/test_002_ask_permission_dialout_screen.py +++ b/e2e/test_002_ask_permission_dialout_screen.py @@ -140,9 +140,9 @@ def test_show_warning(self, mock_get_locale): text = "".join( [ - f"[size={screen.SIZE_G}sp][color=#efcc00]WARNING[/color][/size]", + "[color=#efcc00]WARNING[/color]", "\n", - f'[size={screen.SIZE_MP}sp]This is the first run of KruxInstaller in "mockos"', + 'This is the first run of KruxInstaller in "mockos"', "\n", "and it appears that you do not have privileged access to make flash procedures.", "\n", @@ -153,14 +153,11 @@ def test_show_warning(self, mock_get_locale): "[color=#00ff00]", "/usr/bin/usermod -a -G group user", "[/color]", - "[/size]", "\n", "\n", - f"[size={screen.SIZE_M}]", "[color=#00FF00][ref=Allow]Allow[/ref][/color]", " ", "[color=#FF0000][ref=Deny]Deny[/ref][/color]", - "[/size]", ] ) @@ -227,8 +224,9 @@ def test_fail_press_allow( # get your Window instance safely EventLoop.ensure_window() - action = getattr(screen, f"on_ref_press_{screen.id}_label") - action("Allow") + button = screen.ids[f"{screen.id}_label"] + action = getattr(screen.__class__, f"on_ref_press_{button.id}") + action(button, "Allow") # patch assertions on_permission_created = getattr( @@ -261,8 +259,9 @@ def test_press_deny(self, mock_quit_app, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - action = getattr(screen, f"on_ref_press_{screen.id}_label") - action("Deny") + button = screen.ids[f"{screen.id}_label"] + action = getattr(screen.__class__, f"on_ref_press_{button.id}") + action(button, "Deny") mock_get_locale.assert_called_once() mock_quit_app.assert_called_once() diff --git a/e2e/test_003_main_screen.py b/e2e/test_003_main_screen.py index 992bd7c4..83ddf381 100644 --- a/e2e/test_003_main_screen.py +++ b/e2e/test_003_main_screen.py @@ -95,7 +95,7 @@ def test_on_press_cant_flash_or_wipe(self, mock_get_locale, mock_set_background) calls = [] for button in grid.children: - action = getattr(screen, f"on_press_{button.id}") + action = getattr(screen.__class__, f"on_press_{button.id}") action(button) if button.id in ( "main_select_device", @@ -139,7 +139,7 @@ def test_on_release_cant_flash_or_wipe( calls_manager = [] for button in grid.children: - action = getattr(screen, f"on_release_{button.id}") + action = getattr(screen.__class__, f"on_release_{button.id}") action(button) if button.id in ( @@ -508,8 +508,8 @@ def test_on_press_can_flash_or_wipe(self, mock_get_locale, mock_set_background): for device in ("m5stickv", "amigo", "dock", "bit", "yahboom", "cube"): screen.update(name="SelectVersionScreen", key="device", value=device) - flash_action = getattr(screen, "on_press_main_flash") - wipe_action = getattr(screen, "on_press_main_wipe") + flash_action = getattr(screen.__class__, f"on_press_{flash_button.id}") + wipe_action = getattr(screen.__class__, f"on_press_{wipe_button.id}") flash_action(flash_button) wipe_action(wipe_button) background_calls.append(call(wid="main_flash", rgba=(0.25, 0.25, 0.25, 1))) @@ -548,11 +548,11 @@ def test_on_release_flash_to_download_stable_zip_screen( EventLoop.ensure_window() window = EventLoop.window grid = window.children[0].children[0] - flash_button = grid.children[3] + button = grid.children[3] screen.update(name="SelectVersionScreen", key="device", value="m5stickv") - flash_action = getattr(screen, "on_release_main_flash") - flash_action(flash_button) + action = getattr(screen.__class__, f"on_release_{button.id}") + action(button) mock_get_locale.assert_any_call() mock_get_destdir_assets.assert_called_once() @@ -594,11 +594,11 @@ def test_on_release_flash_to_warning_already_downloaded_zip_screen( EventLoop.ensure_window() window = EventLoop.window grid = window.children[0].children[0] - flash_button = grid.children[3] + button = grid.children[3] screen.update(name="SelectVersionScreen", key="device", value="m5stickv") - flash_action = getattr(screen, "on_release_main_flash") - flash_action(flash_button) + action = getattr(screen.__class__, f"on_release_{button.id}") + action(button) mock_get_locale.assert_any_call() mock_get_destdir_assets.assert_called_once() @@ -636,11 +636,11 @@ def test_on_release_flash_to_download_beta_screen( EventLoop.ensure_window() window = EventLoop.window grid = window.children[0].children[0] - flash_button = grid.children[3] + button = grid.children[3] screen.update(name="SelectVersionScreen", key="device", value="m5stickv") - flash_action = getattr(screen, "on_release_main_flash") - flash_action(flash_button) + action = getattr(screen.__class__, f"on_release_{button.id}") + action(button) mock_get_locale.assert_any_call() mock_findall.assert_has_calls( @@ -677,15 +677,15 @@ def test_on_release_wipe( EventLoop.ensure_window() window = EventLoop.window grid = window.children[0].children[0] - wipe_button = grid.children[2] + button = grid.children[2] calls_set_background = [] calls_set_screen = [] for device in ("m5stickv", "amigo", "dock", "bit", "yahboom", "cube"): screen.update(name="SelectVersionScreen", key="device", value=device) - wipe_action = getattr(screen, "on_release_main_wipe") - wipe_action(wipe_button) + action = getattr(screen.__class__, f"on_release_{button.id}") + action(button) calls_set_background.append(call(wid="main_wipe", rgba=(0, 0, 0, 1))) calls_set_screen.append(call(name="WarningWipeScreen", direction="left")) diff --git a/e2e/test_004_select_device_screen.py b/e2e/test_004_select_device_screen.py index f60f0228..0d2bfe7a 100644 --- a/e2e/test_004_select_device_screen.py +++ b/e2e/test_004_select_device_screen.py @@ -86,7 +86,7 @@ def test_on_press_with_latest_version(self, mock_set_background, mock_get_locale calls = [] for button in grid.children: - action = getattr(screen, f"on_press_{button.id}") + action = getattr(screen.__class__, f"on_press_{button.id}") action(button) if button.id in ( "select_device_m5stickv", @@ -118,7 +118,7 @@ def test_on_press_with_older_version(self, mock_set_background, mock_get_locale) calls = [] for button in grid.children: - action = getattr(screen, f"on_press_{button.id}") + action = getattr(screen.__class__, f"on_press_{button.id}") action(button) if button.id in ( "select_device_m5stickv", @@ -149,7 +149,7 @@ def test_on_press_with_beta_version(self, mock_set_background, mock_get_locale): calls = [] for button in grid.children: - action = getattr(screen, f"on_press_{button.id}") + action = getattr(screen.__class__, f"on_press_{button.id}") action(button) if button.id in ( "select_device_m5stickv", @@ -188,7 +188,7 @@ def test_on_release_with_latest_version( calls_set_screen = [] for button in grid.children: - action = getattr(screen, f"on_release_{button.id}") + action = getattr(screen.__class__, f"on_release_{button.id}") action(button) if button.id in ( @@ -230,7 +230,7 @@ def test_on_release_with_beta_version( calls_set_screen = [] for button in grid.children: - action = getattr(screen, f"on_release_{button.id}") + action = getattr(screen.__class__, f"on_release_{button.id}") action(button) if button.id in ( @@ -273,7 +273,7 @@ def test_on_release_with_v22_03_0_version( calls_set_screen = [] for button in grid.children: - action = getattr(screen, f"on_release_{button.id}") + action = getattr(screen.__class__, f"on_release_{button.id}") action(button) if button.id in ("select_device_m5stickv"): diff --git a/e2e/test_005_select_version_screen.py b/e2e/test_005_select_version_screen.py index 8f94995c..78b15a26 100644 --- a/e2e/test_005_select_version_screen.py +++ b/e2e/test_005_select_version_screen.py @@ -129,7 +129,7 @@ def test_on_press( calls = [] for button in grid.children: - action = getattr(screen, f"on_press_{button.id}") + action = getattr(screen.__class__, f"on_press_{button.id}") action(button) if button.id in ( "main_select_device", @@ -205,7 +205,7 @@ def test_on_fetch_releases( calls_get_screen = [] for button in grid.children: - action = getattr(screen, f"on_release_{button.id}") + action = getattr(screen.__class__, f"on_release_{button.id}") action(button) calls_set_background.append(call(wid=button.id, rgba=(0, 0, 0, 1))) diff --git a/e2e/test_006_select_old_version_screen.py b/e2e/test_006_select_old_version_screen.py index 24d8c819..97dc3fb4 100644 --- a/e2e/test_006_select_old_version_screen.py +++ b/e2e/test_006_select_old_version_screen.py @@ -103,7 +103,7 @@ def test_on_press(self, mock_set_background, mock_get_locale): calls = [] for button in grid.children: - on_press = getattr(screen, f"on_press_{button.id}") + on_press = getattr(screen.__class__, f"on_press_{button.id}") on_press(button) calls.append(call(wid=button.id, rgba=(0.25, 0.25, 0.25, 1))) @@ -145,7 +145,7 @@ def test_on_release( set_screen_calls = [] for button in grid.children: - on_release = getattr(screen, f"on_release_{button.id}") + on_release = getattr(screen.__class__, f"on_release_{button.id}") on_release(button) set_background_calls.append(call(wid=button.id, rgba=(0, 0, 0, 1))) diff --git a/e2e/test_007_warning_beta_screen.py b/e2e/test_007_warning_beta_screen.py index f2803e9b..56a20d2b 100644 --- a/e2e/test_007_warning_beta_screen.py +++ b/e2e/test_007_warning_beta_screen.py @@ -1,5 +1,4 @@ import os -import sys from unittest.mock import patch from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest @@ -35,7 +34,6 @@ def test_render_main_screen(self, mock_get_locale): grid = window.children[0].children[0] warn = grid.children[1] button = grid.children[0] - sizes = [screen.SIZE_MM, screen.SIZE_M, screen.SIZE_MP] self.assertEqual(window.children[0], screen) self.assertEqual(screen.name, "WarningBetaScreen") @@ -46,16 +44,13 @@ def test_render_main_screen(self, mock_get_locale): text = "".join( [ - f"[size={sizes[1]}sp]", "[color=#efcc00]This is our test repository[/color]", - "[/size]", "\n", - f"[size={sizes[2]}sp]These are unsigned binaries for the latest and most experimental features[/size]", + "These are unsigned binaries for the latest and most experimental features", "\n", - f"[size={sizes[2]}sp]and it's just for trying new things and providing feedback.[/size]", + "and it's just for trying new things and providing feedback.", "\n", "\n", - f"[size={sizes[0]}sp]", "[color=#00ff00]", "[ref=MainScreen]Proceed[/ref]", "[/color]", @@ -63,14 +58,9 @@ def test_render_main_screen(self, mock_get_locale): "[color=#ff0000]", "[ref=SelectVersion]Back[/ref]", "[/color]", - "[/size]", ] ) - print(button.text) - print("==============") - print(text) - self.assertEqual(button.text, text) mock_get_locale.assert_any_call() @@ -126,31 +116,16 @@ def test_update_locale(self, mock_get_locale): grid = window.children[0].children[0] button = grid.children[0] - fontsize_mm = 0 - fontsize_m = 0 - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_mm = window.size[0] // 24 - fontsize_m = window.size[0] // 32 - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_mm = window.size[0] // 48 - fontsize_m = window.size[0] // 64 - fontsize_mp = window.size[0] // 128 - screen.update(name="ConfigKruxInstaller", key="locale", value="pt_BR.UTF-8") text = "".join( [ - f"[size={fontsize_m}sp][color=#efcc00]Este é nosso repositório de testes[/color][/size]", + "[color=#efcc00]Este é nosso repositório de testes[/color]", "\n", - f"[size={fontsize_mp}sp]Estes são binários não assinados dos recursos mais experimentais[/size]", + "Estes são binários não assinados dos recursos mais experimentais", "\n", - f"[size={fontsize_mp}sp]e serve apenas para experimentar coisas novas e dar opiniões.[/size]", + "e serve apenas para experimentar coisas novas e dar opiniões.", "\n", "\n", - f"[size={fontsize_mm}sp]", "[color=#00ff00]", "[ref=MainScreen]Proceder[/ref]", "[/color]", @@ -158,12 +133,8 @@ def test_update_locale(self, mock_get_locale): "[color=#ff0000]", "[ref=SelectVersion]Voltar[/ref]", "[/color]", - "[/size]", ] ) - print(button.text) - print("==========") - print(text) self.assertEqual(button.text, text) mock_get_locale.assert_any_call() diff --git a/e2e/test_008_about_screen.py b/e2e/test_008_about_screen.py index 6ea1b06f..79c9d9be 100644 --- a/e2e/test_008_about_screen.py +++ b/e2e/test_008_about_screen.py @@ -42,26 +42,20 @@ def test_render_main_screen(self, mock_get_locale): text = "".join( [ - f"[size={screen.SIZE_G}sp]", "[ref=SourceCode][b]v0.0.20-alpha-2[/b][/ref]", - "[/size]", "\n", "\n", - f"[size={screen.SIZE_M}sp]", "follow us on X: ", "[color=#00AABB]", "[ref=X][u]@selfcustodykrux[/u][/ref]", "[/color]", - "[/size]", "\n", "\n", - f"[size={screen.SIZE_M}sp]", "[color=#00FF00]", "[ref=Back]", "[u]Back[/u]", "[/ref]", "[/color]", - "[/size]", ] ) @@ -86,33 +80,22 @@ def test_update_locale(self, mock_get_locale): text = "".join( [ - f"[size={screen.SIZE_G}sp]", "[ref=SourceCode][b]v0.0.20-alpha-2[/b][/ref]", - "[/size]", "\n", "\n", - f"[size={screen.SIZE_M}sp]", "siga-nos no X: ", "[color=#00AABB]", "[ref=X][u]@selfcustodykrux[/u][/ref]", "[/color]", - "[/size]", "\n", "\n", - f"[size={screen.SIZE_M}sp]", "[color=#00FF00]", "[ref=Back]", "[u]Voltar[/u]", "[/ref]", "[/color]", - "[/size]", ] ) - - print(text) - print("=========") - print(label.text) - self.assertEqual(label.text, text) mock_get_locale.assert_any_call() @@ -129,8 +112,9 @@ def test_on_press_version(self, mock_webbrowser, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() + button = screen.ids[f"{screen.id}_label"] - action = getattr(screen, "on_ref_press_about_screen_label") + action = getattr(screen.__class__, f"on_ref_press_{button.id}") action("Mock", "SourceCode") mock_get_locale.assert_any_call() @@ -153,8 +137,9 @@ def test_on_press_x_formerly_known_as_twitter( # get your Window instance safely EventLoop.ensure_window() + button = screen.ids[f"{screen.id}_label"] - action = getattr(screen, "on_ref_press_about_screen_label") + action = getattr(screen.__class__, f"on_ref_press_{button.id}") action("Mock", "X") mock_get_locale.assert_any_call() @@ -171,8 +156,9 @@ def test_on_press_back(self, mock_set_screen, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() + button = screen.ids[f"{screen.id}_label"] - action = getattr(screen, "on_ref_press_about_screen_label") + action = getattr(screen.__class__, f"on_ref_press_{button.id}") action("Mock", "Back") mock_get_locale.assert_any_call() diff --git a/e2e/test_010_download_stable_zip_screen.py b/e2e/test_010_download_stable_zip_screen.py index d539ab3b..32ae03d7 100644 --- a/e2e/test_010_download_stable_zip_screen.py +++ b/e2e/test_010_download_stable_zip_screen.py @@ -1,5 +1,4 @@ import os -import sys from unittest.mock import patch, call, MagicMock from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest @@ -131,18 +130,6 @@ def test_update_progress(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_g = 0 - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_g = window.size[0] // 16 - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_g = window.size[0] // 32 - fontsize_mp = window.size[0] // 128 # do tests screen.update( @@ -154,13 +141,11 @@ def test_update_progress(self, mock_get_locale): # do tests text = "".join( [ - f"[size={fontsize_g}sp][b]1.00 %[/b][/size]", + "[b]1.00 %[/b]", "\n", - f"[size={fontsize_mp}sp]", "0.20", " of ", "20.03 MB", - "[/size]", ] ) @@ -180,18 +165,6 @@ def test_update_progress_100_percent(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_g = 0 - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_g = window.size[0] // 16 - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_g = window.size[0] // 32 - fontsize_mp = window.size[0] // 128 # do tests with patch.object(screen, "trigger") as mock_trigger, patch.object( @@ -208,25 +181,21 @@ def test_update_progress_100_percent(self, mock_get_locale): # do tests text_progress = "".join( [ - f"[size={fontsize_g}sp][b]100.00 %[/b][/size]", + "[b]100.00 %[/b]", "\n", - f"[size={fontsize_mp}sp]", "20.03", " of ", "20.03", " MB", - "[/size]", ] ) filepath = os.path.join("mockdir", "krux-v24.07.0.zip") text_info = "".join( [ - f"[size={fontsize_mp}sp]", filepath, "\n", "downloaded", - "[/size]", ] ) diff --git a/e2e/test_011_download_stable_zip_sha256_screen.py b/e2e/test_011_download_stable_zip_sha256_screen.py index 6ccf1805..f0ab9fc9 100644 --- a/e2e/test_011_download_stable_zip_sha256_screen.py +++ b/e2e/test_011_download_stable_zip_sha256_screen.py @@ -1,5 +1,4 @@ import os -import sys from unittest.mock import patch, call, MagicMock from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest @@ -129,21 +128,8 @@ def test_update_progress(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_g = 0 - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_g = window.size[0] // 16 - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_g = window.size[0] // 32 - fontsize_mp = window.size[0] // 128 # do tests - screen.update( name="ConfigKruxInstaller", key="progress", @@ -153,14 +139,12 @@ def test_update_progress(self, mock_get_locale): # do tests text = "".join( [ - f"[size={fontsize_g}sp][b]1.00 %[/b][/size]", + "[b]1.00 %[/b]", "\n", - f"[size={fontsize_mp}sp]", "210000", " of ", "21000000", " B", - "[/size]", ] ) @@ -233,18 +217,6 @@ def test_update_progress_100_percent( # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_g = 0 - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_g = window.size[0] // 16 - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_g = window.size[0] // 32 - fontsize_mp = window.size[0] // 128 # do tests with patch.object(screen, "trigger") as mock_trigger, patch.object( @@ -261,25 +233,21 @@ def test_update_progress_100_percent( # do tests text_progress = "".join( [ - f"[size={fontsize_g}sp][b]100.00 %[/b][/size]", + "[b]100.00 %[/b]", "\n", - f"[size={fontsize_mp}sp]", "21", " of ", "21", " B", - "[/size]", ] ) filepath = os.path.join("mockdir", "krux-v24.07.0.zip.sha256.txt") text_info = "".join( [ - f"[size={fontsize_mp}sp]", filepath, "\n", "downloaded", - "[/size]", ] ) diff --git a/e2e/test_012_download_stable_zip_sig_screen.py b/e2e/test_012_download_stable_zip_sig_screen.py index 9e365555..f606020b 100644 --- a/e2e/test_012_download_stable_zip_sig_screen.py +++ b/e2e/test_012_download_stable_zip_sig_screen.py @@ -1,5 +1,4 @@ import os -import sys from unittest.mock import patch, call, MagicMock from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest @@ -124,21 +123,8 @@ def test_update_progress(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_g = 0 - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_g = window.size[0] // 16 - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_g = window.size[0] // 32 - fontsize_mp = window.size[0] // 128 # do tests - screen.update( name="ConfigKruxInstaller", key="progress", @@ -148,14 +134,12 @@ def test_update_progress(self, mock_get_locale): # do tests text = "".join( [ - f"[size={fontsize_g}sp][b]1.00 %[/b][/size]", + "[b]1.00 %[/b]", "\n", - f"[size={fontsize_mp}sp]", "210000", " of ", "21000000", " B", - "[/size]", ] ) @@ -225,18 +209,6 @@ def test_update_progress_100_percent(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_g = 0 - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_g = window.size[0] // 16 - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_g = window.size[0] // 32 - fontsize_mp = window.size[0] // 128 # do tests with patch.object(screen, "trigger") as mock_trigger, patch.object( @@ -253,25 +225,21 @@ def test_update_progress_100_percent(self, mock_get_locale): # do tests text_progress = "".join( [ - f"[size={fontsize_g}sp][b]100.00 %[/b][/size]", + "[b]100.00 %[/b]", "\n", - f"[size={fontsize_mp}sp]", "21", " of ", "21", " B", - "[/size]", ] ) filepath = os.path.join("mockdir", "krux-v24.07.0.zip.sig") text_info = "".join( [ - f"[size={fontsize_mp}sp]", filepath, "\n", "downloaded", - "[/size]", ] ) diff --git a/e2e/test_013_download_selfcustody_pem_screen.py b/e2e/test_013_download_selfcustody_pem_screen.py index dabd765a..1fd127b1 100644 --- a/e2e/test_013_download_selfcustody_pem_screen.py +++ b/e2e/test_013_download_selfcustody_pem_screen.py @@ -1,5 +1,4 @@ import os -import sys from unittest.mock import patch, call from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest @@ -142,18 +141,6 @@ def test_update_progress(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_g = 0 - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_g = window.size[0] // 16 - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_g = window.size[0] // 32 - fontsize_mp = window.size[0] // 128 # do tests screen.update( @@ -165,14 +152,12 @@ def test_update_progress(self, mock_get_locale): # do tests text = "".join( [ - f"[size={fontsize_g}sp][b]1.00 %[/b][/size]", + "[b]1.00 %[/b]", "\n", - f"[size={fontsize_mp}sp]", "210000", " of ", "21000000", " B", - "[/size]", ] ) @@ -240,18 +225,6 @@ def test_update_progress_100_percent(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_g = 0 - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_g = window.size[0] // 16 - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_g = window.size[0] // 32 - fontsize_mp = window.size[0] // 128 # do tests with patch.object(screen, "trigger") as mock_trigger, patch.object( @@ -268,25 +241,21 @@ def test_update_progress_100_percent(self, mock_get_locale): # do tests text_progress = "".join( [ - f"[size={fontsize_g}sp][b]100.00 %[/b][/size]", + "[b]100.00 %[/b]", "\n", - f"[size={fontsize_mp}sp]", "21", " of ", "21", " B", - "[/size]", ] ) filepath = os.path.join("mockdir", "selfcustody.pem") text_info = "".join( [ - f"[size={fontsize_mp}sp]", filepath, "\n", "downloaded", - "[/size]", ] ) diff --git a/e2e/test_014_download_beta_screen.py b/e2e/test_014_download_beta_screen.py index 6f0b786f..e7136c23 100644 --- a/e2e/test_014_download_beta_screen.py +++ b/e2e/test_014_download_beta_screen.py @@ -1,5 +1,4 @@ import os -import sys from unittest.mock import patch, call, MagicMock from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest @@ -185,15 +184,6 @@ def test_update_downloader(self, mock_destdir_assets, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_mp = window.size[0] // 128 # do tests screen.update(name=screen.name, key="downloader") @@ -203,7 +193,6 @@ def test_update_downloader(self, mock_destdir_assets, mock_get_locale): # do tests text = "".join( [ - f"[size={fontsize_mp}sp]", "Downloading", "\n", "[color=#00AABB]", @@ -216,7 +205,6 @@ def test_update_downloader(self, mock_destdir_assets, mock_get_locale): "\n", firmware_path, "\n", - "[/size]", ] ) # default assertions @@ -237,18 +225,6 @@ def test_update_progress(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_g = 0 - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_g = window.size[0] // 16 - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_g = window.size[0] // 32 - fontsize_mp = window.size[0] // 128 # do tests screen.update( @@ -260,9 +236,9 @@ def test_update_progress(self, mock_get_locale): # do tests text = "".join( [ - f"[size={fontsize_g}sp][b]1.00 %[/b][/size]", + "[b]1.00 %[/b]", "\n", - f"[size={fontsize_mp}sp]0.20 of 20.03 MB[/size]", + "0.20 of 20.03 MB", ] ) @@ -281,18 +257,6 @@ def test_update_progress_100_percent(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_g = 0 - fontsize_mp = 0 - - if sys.platform in ("linux", "win32"): - fontsize_g = window.size[0] // 16 - fontsize_mp = window.size[0] // 48 - - if sys.platform == "darwin": - fontsize_g = window.size[0] // 32 - fontsize_mp = window.size[0] // 128 # do tests with patch.object(screen, "trigger") as mock_trigger, patch.object( @@ -309,16 +273,14 @@ def test_update_progress_100_percent(self, mock_get_locale): # do tests text_progress = "".join( [ - f"[size={fontsize_g}sp][b]100.00 %[/b][/size]", + "[b]100.00 %[/b]", "\n", - f"[size={fontsize_mp}sp]20.03 of 20.03 MB[/size]", + "20.03 of 20.03 MB", ] ) kboot = os.path.join("mockdir", "kboot.kfpkg") - text_info = "".join( - [f"[size={fontsize_mp}sp]", kboot, "\n", "downloaded", "[/size]"] - ) + text_info = "".join([kboot, "\n", "downloaded"]) self.assertEqual( screen.ids["download_beta_screen_progress"].text, text_progress @@ -393,7 +355,6 @@ def test_on_trigger( ) mock_partial.assert_has_calls( [ - call(screen.update, name=screen.name, key="canvas"), call( mock_manager.get_screen().update, name=screen.name, @@ -418,8 +379,7 @@ def test_on_trigger( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) @patch("src.app.screens.download_beta_screen.partial") - @patch("src.app.screens.download_beta_screen.Clock.schedule_once") - def test_on_progress(self, mock_schedule_once, mock_partial, mock_get_locale): + def test_on_progress(self, mock_partial, mock_get_locale): # screen screen = DownloadBetaScreen() @@ -448,7 +408,6 @@ def test_on_progress(self, mock_schedule_once, mock_partial, mock_get_locale): mock_get_locale.assert_any_call() mock_partial.assert_has_calls( [ - call(screen.update, name=screen.name, key="canvas"), call( screen.update, name=screen.name, @@ -457,6 +416,3 @@ def test_on_progress(self, mock_schedule_once, mock_partial, mock_get_locale): ), ] ) - mock_schedule_once.assert_has_calls( - [call(mock_partial(), 0), call(mock_partial(), 0)], any_order=True - ) diff --git a/e2e/test_015_warning_already_downloaded_screen.py b/e2e/test_015_warning_already_downloaded_screen.py index dfef5d33..b1186105 100644 --- a/e2e/test_015_warning_already_downloaded_screen.py +++ b/e2e/test_015_warning_already_downloaded_screen.py @@ -1,4 +1,3 @@ -import sys from unittest.mock import patch, call, MagicMock from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest @@ -84,33 +83,20 @@ def test_update_version(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - size = [0, 0] - - if sys.platform in ("linux", "win32"): - size = [window.size[0] // 32, window.size[0] // 48, window.size[0] // 64] - - if sys.platform == "darwin": - size = [window.size[0] // 48, window.size[0] // 128, window.size[0] // 128] - label_text = "".join( [ - f"[size={size[0]}sp][b]Assets already downloaded[/b][/size]", - "\n", - f"[size={size[2]}sp]* krux-v0.0.1.zip[/size]", - "\n", - f"[size={size[2]}sp]* krux-v0.0.1.zip.sha256.txt[/size]", + "[color=#efcc00][b]Assets already downloaded[/b][/color]", "\n", - f"[size={size[2]}sp]* krux-v0.0.1.zip.sig[/size]", + "* krux-v0.0.1.zip", "\n", - f"[size={size[2]}sp]* selfcustody.pem[/size]", + "* krux-v0.0.1.zip.sha256.txt", "\n", + "* krux-v0.0.1.zip.sig", "\n", - f"[size={size[1]}sp]Do you want to proceed with the same file or do you want to download it again?[/size]", + "* selfcustody.pem", "\n", "\n", - f"[size={size[0]}]" f"[color=#00ff00]", + "[color=#00ff00]", "[ref=DownloadStableZipScreen]", "[u]Download again[/u]", "[/ref]", @@ -121,7 +107,6 @@ def test_update_version(self, mock_get_locale): "[u]Proceed with current file[/u]", "[/ref]", "[/color]", - "[/size]", ] ) @@ -155,9 +140,10 @@ def test_on_press_donwload_button( # get your Window instance safely EventLoop.ensure_window() + button = screen.ids[f"{screen.id}_label"] - action = getattr(WarningAlreadyDownloadedScreen, f"on_ref_press_{screen.id}") - action("Mock", "DownloadStableZipScreen") + action = getattr(screen.__class__, f"on_ref_press_{button.id}") + action(button, "DownloadStableZipScreen") mock_get_locale.assert_any_call() mock_manager.get_screen.assert_has_calls( @@ -194,9 +180,10 @@ def test_on_press_proceed(self, mock_set_screen, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() + button = screen.ids[f"{screen.id}_label"] - action = getattr(WarningAlreadyDownloadedScreen, f"on_ref_press_{screen.id}") - action("Mock", "VerifyStableZipScreen") + action = getattr(screen.__class__, f"on_ref_press_{button.id}") + action(button, "VerifyStableZipScreen") mock_get_locale.assert_any_call() mock_set_screen.assert_called_once_with( diff --git a/e2e/test_016_unzip_stable_screen.py b/e2e/test_016_unzip_stable_screen.py index fa648910..204f83d5 100644 --- a/e2e/test_016_unzip_stable_screen.py +++ b/e2e/test_016_unzip_stable_screen.py @@ -1,5 +1,4 @@ import os -import sys from unittest.mock import patch, MagicMock from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest @@ -171,8 +170,10 @@ def test_update_clear(self, mock_get_locale, mock_get_destdir_assets): root_widget=f"{screen.id}_grid", text="Mock", row=0, + halign=None, on_press=MagicMock(), on_release=MagicMock(), + on_ref_press=MagicMock(), ) # do tests @@ -199,15 +200,6 @@ def test_update_flash_button(self, mock_get_locale, mock_get_destdir_assets): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - size = [0, 0] - - if sys.platform in ("linux", "win32"): - size = [window.size[0] // 24, window.size[0] // 48] - - if sys.platform == "darwin": - size = [window.size[0] // 48, window.size[0] // 128] # do tests screen.update(name="VerifyStableZipScreen", key="device", value="mock") @@ -217,15 +209,11 @@ def test_update_flash_button(self, mock_get_locale, mock_get_destdir_assets): p = os.path.join("mock", "krux-v0.0.1", "maixpy_mock", "kboot.kfpkg") text = "".join( [ - f"[size={size[0]}sp]", "Flash with", - "[/size]", "\n", - f"[size={size[1]}sp]", "[color=#efcc00]", p, "[/color]", - "[/size]", ] ) @@ -249,46 +237,30 @@ def test_update_airgap_button(self, mock_get_locale, mock_get_destdir_assets): # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - size = [0, 0] - - if sys.platform in ("linux", "win32"): - size = [window.size[0] // 24, window.size[0] // 48] - - if sys.platform == "darwin": - size = [window.size[0] // 48, window.size[0] // 128] # do tests screen.update(name="VerifyStableZipScreen", key="device", value="mock") screen.update(name="VerifyStableZipScreen", key="version", value="v0.0.1") screen.update(name="VerifyStableZipScreen", key="airgap-button") - p = os.path.join("mock", "krux-v0.0.1", "maixpy_mock", "firmware.bin") - text = "".join( - [ - f"[size={size[0]}sp]", - "[color=#333333]", - "Air-gapped update with (soon)", - "[/color]", - "[/size]", - "\n", - f"[size={size[1]}sp]", - "[color=#333333]", - p, - "[/color]", - "[/size]", - ] - ) + # p = os.path.join("mock", "krux-v0.0.1", "maixpy_mock", "firmware.bin") + # text = "".join( + # [ + # "[color=#333333]", + # "Air-gapped update with (soon)", + # "[/color]", + # "\n", + # "[color=#333333]", + # p, + # "[/color]", + # ] + # ) # default assertions - self.assertEqual(screen.ids[f"{screen.id}_airgap_button"].text, text) - self.assertTrue( - hasattr(UnzipStableScreen, f"on_press_{screen.id}_airgap_button") - ) - self.assertTrue( - hasattr(UnzipStableScreen, f"on_release_{screen.id}_airgap_button") - ) + # button = screen.ids[f"{screen.id}_airgap_button"] + # self.assertEqual(screen.ids[f"{screen.id}_airgap_button"].text, text) + # self.assertTrue(hasattr(screen.__class__, f"on_press_{button.id}")) + # self.assertTrue(hasattr(screen.__class__, f"on_release_{button.id}")) # patch assertions mock_get_destdir_assets.assert_any_call() @@ -310,36 +282,23 @@ def test_on_press_flash_button( # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - size = [0, 0] - - if sys.platform in ("linux", "win32"): - size = [window.size[0] // 24, window.size[0] // 48] - - if sys.platform == "darwin": - size = [window.size[0] // 48, window.size[0] // 128] # DO tests screen.update(name="VerifyStableZipScreen", key="device", value="mock") screen.update(name="VerifyStableZipScreen", key="version", value="v0.0.1") screen.update(name="VerifyStableZipScreen", key="flash-button") button = screen.ids[f"{screen.id}_flash_button"] - action = getattr(screen, f"on_press_{screen.id}_flash_button") + action = getattr(screen.__class__, f"on_press_{button.id}") action(button) p = os.path.join("mock", "krux-v0.0.1", "maixpy_mock", "kboot.kfpkg") text = "".join( [ - f"[size={size[0]}sp]", "Extracting", - "[/size]", "\n", - f"[size={size[1]}sp]", "[color=#efcc00]", p, "[/color]", - "[/size]", ] ) @@ -369,43 +328,30 @@ def test_on_press_airgap_button( # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - size = [0, 0] - - if sys.platform in ("linux", "win32"): - size = [window.size[0] // 24, window.size[0] // 48] - - if sys.platform == "darwin": - size = [window.size[0] // 48, window.size[0] // 128] # DO tests screen.update(name="VerifyStableZipScreen", key="device", value="mock") screen.update(name="VerifyStableZipScreen", key="version", value="v0.0.1") screen.update(name="VerifyStableZipScreen", key="airgap-button") - button = screen.ids[f"{screen.id}_airgap_button"] - action = getattr(screen, f"on_press_{screen.id}_airgap_button") - action(button) - - p = os.path.join("mock", "krux-v0.0.1", "maixpy_mock", "firmware.bin") - text = "".join( - [ - f"[size={size[0]}sp]", - "[color=#333333]", - "Air-gapped update with (soon)", - "[/color]", - "[/size]", - "\n", - f"[size={size[1]}sp]", - "[color=#333333]", - p, - "[/color]", - "[/size]", - ] - ) + # button = screen.ids[f"{screen.id}_airgap_button"] + # action = getattr(screen.__class__, f"on_press_{button.id}") + # action(button) + + # p = os.path.join("mock", "krux-v0.0.1", "maixpy_mock", "firmware.bin") + # text = "".join( + # [ + # "[color=#333333]", + # "Air-gapped update with (soon)", + # "[/color]", + # "\n", + # "[color=#333333]", + # p, + # "[/color]", + # ] + # ) # default assertions - self.assertEqual(button.text, text) + # self.assertEqual(button.text, text) # patch assertions mock_get_destdir_assets.assert_called_once() @@ -442,36 +388,23 @@ def test_on_release_flash_button( # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - size = [0, 0] - - if sys.platform in ("linux", "win32"): - size = [window.size[0] // 24, window.size[0] // 48] - - if sys.platform == "darwin": - size = [window.size[0] // 48, window.size[0] // 128] # DO tests screen.update(name="VerifyStableZipScreen", key="device", value="mock") screen.update(name="VerifyStableZipScreen", key="version", value="v0.0.1") screen.update(name="VerifyStableZipScreen", key="flash-button") button = screen.ids[f"{screen.id}_flash_button"] - action = getattr(screen, f"on_release_{screen.id}_flash_button") + action = getattr(screen.__class__, f"on_release_{button.id}") action(button) p = os.path.join("mock", "krux-v0.0.1", "maixpy_mock", "kboot.kfpkg") text = "".join( [ - f"[size={size[0]}sp]", "Extracted", - "[/size]", "\n", - f"[size={size[1]}sp]", "[color=#efcc00]", p, "[/color]", - "[/size]", ] ) @@ -521,38 +454,26 @@ def test_on_release_airgapped_button( # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - size = [0, 0] - - if sys.platform in ("linux", "win32"): - size = [window.size[0] // 24, window.size[0] // 48] - - if sys.platform == "darwin": - size = [window.size[0] // 48, window.size[0] // 128] # DO tests screen.update(name="VerifyStableZipScreen", key="device", value="mock") screen.update(name="VerifyStableZipScreen", key="version", value="v0.0.1") screen.update(name="VerifyStableZipScreen", key="airgap-button") + button = screen.ids[f"{screen.id}_airgap_button"] - action = getattr(screen, f"on_release_{screen.id}_airgap_button") - action(button) + # action = getattr(screen.__class__, f"on_release_{button.id}") + # action(button) p = os.path.join("mock", "krux-v0.0.1", "maixpy_mock", "firmware.bin") text = "".join( [ - f"[size={size[0]}sp]", "[color=#333333]", "Air-gapped update with (soon)", "[/color]", - "[/size]", "\n", - f"[size={size[1]}sp]", "[color=#333333]", p, "[/color]", - "[/size]", ] ) diff --git a/e2e/test_017_verify_stable_zip_screen.py b/e2e/test_017_verify_stable_zip_screen.py index 2badd478..085c5960 100644 --- a/e2e/test_017_verify_stable_zip_screen.py +++ b/e2e/test_017_verify_stable_zip_screen.py @@ -1,5 +1,4 @@ import os -import sys from unittest.mock import MagicMock, patch, call from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest @@ -30,9 +29,6 @@ def test_init(self, mock_get_locale): # default assertions self.assertEqual(grid.id, f"{screen.id}_grid") self.assertFalse(screen.success) - self.assertTrue( - hasattr(VerifyStableZipScreen, "on_ref_press_verify_stable_zip_screen") - ) # patch assertions mock_get_locale.assert_any_call() @@ -43,7 +39,12 @@ def test_init(self, mock_get_locale): ) @patch("src.app.screens.verify_stable_zip_screen.Sha256Verifyer") @patch("src.app.screens.verify_stable_zip_screen.Sha256CheckVerifyer") - def test_verify_sha256(self, mock_check_verifyer, mock_verifyer, mock_get_locale): + def test_verify_sha256( + self, + mock_check_verifyer, + mock_verifyer, + mock_get_locale, + ): screen = VerifyStableZipScreen() self.render(screen) @@ -100,31 +101,22 @@ def test_verify_signature( @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - def test_on_pre_enter(self, mock_get_locale): + @patch("src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.manager") + def test_on_pre_enter(self, mock_manager, mock_get_locale): + mock_manager.get_screen = MagicMock() + mock_manager.get_screen.return_value = MagicMock(version="v0.0.1") screen = VerifyStableZipScreen() - self.render(screen) + screen.on_pre_enter() + # self.render(screen) # get your Window instance safely EventLoop.ensure_window() - window = EventLoop.window - - fontsize_mm = 0 - - if sys.platform in ("linux", "win32"): - fontsize_mm = window.size[0] // 24 - - if sys.platform == "darwin": - fontsize_mm = window.size[0] // 48 - - screen.on_pre_enter() text = "".join( [ - f"[size={fontsize_mm}sp]", "[color=#efcc00]", "Verifying integrity and authenticity", "[/color]", - "[/size]", ] ) self.assertEqual(len(screen.ids["verify_stable_zip_screen_grid"].children), 1) @@ -159,6 +151,8 @@ def test_on_enter( screen = VerifyStableZipScreen() screen.manager = MagicMock() screen.manager.get_screen = MagicMock() + screen.on_pre_enter() + screen.on_enter() self.render(screen) # get your Window instance safely @@ -168,7 +162,7 @@ def test_on_enter( # patch assertions mock_get_locale.assert_called() - mock_get_destdir_assets.assert_called_once() + mock_get_destdir_assets.assert_called() mock_build_message_verify_sha256.assert_called_once_with( assets_dir="mockdir", version=screen.manager.get_screen().version ) @@ -203,34 +197,21 @@ def test_build_message_verify_sha256(self, mock_verify_sha256, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - - if sys.platform in ("linux", "win32"): - size = [screen.SIZE_MP, screen.SIZE_P, screen.SIZE_PP] - else: - size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] - p = os.path.join("mock", "krux-v0.0.1.zip") expected = "".join( [ - f"[size={size[0]}sp]", "[u]INTEGRITY VERIFICATION[/u]: ", "[b][color=#00FF00]SUCCESS[/color][/b]", - "[/size]", "\n", "\n", - f"[size={size[1]}sp]", f"[b]computed hash from [color=#777777]{p}[/color][/b]", - "[/size]", "\n", - f"[size={size[1]}sp]mo ck ha sh[/size]", + "mo ck ha sh", "\n", "\n", - f"[size={size[1]}sp]", f"[b]provided hash from [color=#777777]{p}.sha256.txt[/color][/b]", - "[/size]", - "\n", - f"[size={size[1]}sp]mo ck ha sh[/size]", "\n", + "mo ck ha sh", "\n", "\n", ] @@ -257,34 +238,21 @@ def test_failed_build_message_verify_sha256( # get your Window instance safely EventLoop.ensure_window() - - if sys.platform in ("linux", "win32"): - size = [screen.SIZE_MP, screen.SIZE_P, screen.SIZE_PP] - else: - size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] - p = os.path.join("mock", "krux-v0.0.1.zip") expected = "".join( [ - f"[size={size[0]}sp]", "[u]INTEGRITY VERIFICATION[/u]: ", "[b][color=#FF0000]FAILED[/color][/b]", - "[/size]", "\n", "\n", - f"[size={size[1]}sp]", f"[b]computed hash from [color=#777777]{p}[/color][/b]", - "[/size]", "\n", - f"[size={size[1]}sp]mo ck ha sh[/size]", + "mo ck ha sh", "\n", "\n", - f"[size={size[1]}sp]", f"[b]provided hash from [color=#777777]{p}.sha256.txt[/color][/b]", - "[/size]", - "\n", - f"[size={size[1]}sp]no mo ck ha sh[/size]", "\n", + "no mo ck ha sh", "\n", "\n", ] @@ -311,44 +279,32 @@ def test_build_message_verify_signature(self, mock_verify_sig, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - if sys.platform in ("linux", "win32"): - size = [screen.SIZE_MP, screen.SIZE_P, screen.SIZE_PP] - else: - size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] - p = os.path.join("mock", "krux-v0.0.1.zip") s = os.path.join("mock", "selfcustody.pem") expected = "".join( [ - f"[size={size[0]}sp]", "[u]AUTHENTICITY VERIFICATION[/u]: ", "[b][color=#00FF00]GOOD SIGNATURE[/color][/b]", - "[/size]", - "\n", "\n", "\n", - f"[size={size[1]}sp]If you have openssl installed on your system[/size]", + "If you have openssl installed on your system", "\n", - f"[size={size[1]}sp]you can check manually with the following command:[/size]", + "you can check manually with the following command", "\n", "\n", - f"[size={size[1]}sp]", "[b]", f"openssl sha256< [color=#777777]{p}[/color] -binary | \\", "\n", f"openssl pkeyutl -verify -pubin -inkey [color=#777777]{s}[/color] \\", "\n", f"-sigfile [color=#777777]{p}.sig[/color]", - "[/size]", "[/b]", "\n", "\n", - f"[size={size[0]}sp]", "[ref=Proceed][color=#00ff00][u]Proceed[/u][/ref][/color]", " ", "[ref=Back][color=#ff0000][u]Back[/u][/ref][/color]", "[/b]", - "[/size]", ] ) @@ -377,45 +333,32 @@ def test_failed_build_message_verify_signature( # get your Window instance safely EventLoop.ensure_window() - - if sys.platform in ("linux", "win32"): - size = [screen.SIZE_MP, screen.SIZE_P, screen.SIZE_PP] - else: - size = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] - p = os.path.join("mock", "krux-v0.0.1.zip") s = os.path.join("mock", "selfcustody.pem") expected = "".join( [ - f"[size={size[0]}sp]", "[u]AUTHENTICITY VERIFICATION[/u]: ", "[b][color=#FF0000]BAD SIGNATURE[/color][/b]", - "[/size]", - "\n", "\n", "\n", - f"[size={size[1]}sp]If you have openssl installed on your system[/size]", + "If you have openssl installed on your system", "\n", - f"[size={size[1]}sp]you can check manually with the following command:[/size]", + "you can check manually with the following command", "\n", "\n", - f"[size={size[1]}sp]", "[b]", f"openssl sha256< [color=#777777]{p}[/color] -binary | \\", "\n", f"openssl pkeyutl -verify -pubin -inkey [color=#777777]{s}[/color] \\", "\n", f"-sigfile [color=#777777]{p}.sig[/color]", - "[/size]", "[/b]", "\n", "\n", - f"[size={size[0]}sp]", "[ref=Proceed][color=#00ff00][u]Proceed[/u][/ref][/color]", " ", "[ref=Back][color=#ff0000][u]Back[/u][/ref][/color]", "[/b]", - "[/size]", ] ) @@ -423,6 +366,9 @@ def test_failed_build_message_verify_signature( assets_dir="mock", version="v0.0.1" ) + print(actual) + print("========") + print(expected) self.assertEqual(actual, expected) mock_get_locale.assert_any_call() mock_verify_sig.assert_called_once() @@ -444,14 +390,16 @@ def test_on_press_proceed( mock_get_locale, ): screen = VerifyStableZipScreen() + screen.on_pre_enter() + screen.on_enter() self.render(screen) # get your Window instance safely EventLoop.ensure_window() + button = screen.ids[f"{screen.id}_label"] # DO tests - screen.on_pre_enter() - action = getattr(VerifyStableZipScreen, f"on_ref_press_{screen.id}") + action = getattr(screen.__class__, f"on_ref_press_{button.id}") action(None, "Proceed") # patch assertions @@ -500,19 +448,46 @@ def test_on_press_proceed( @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) + @patch( + "src.app.screens.base_screen.BaseScreen.get_destdir_assets", return_value="mock" + ) + @patch("src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.manager") @patch("src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.set_screen") - def test_on_press_back(self, mock_set_screen, mock_get_locale): + @patch( + "src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.verify_sha256", + return_value=tuple(["mock", "mock", True]), + ) + @patch( + "src.app.screens.verify_stable_zip_screen.VerifyStableZipScreen.verify_signature", + return_value=True, + ) + def test_on_press_back( + self, + mock_verify_signature, + mock_verify_sha256, + mock_set_screen, + mock_manager, + mock_get_destdir_assets, + mock_get_locale, + ): + mock_manager.get_screen = MagicMock() + mock_manager.get_screen.return_value = MagicMock(version="v0.0.1") screen = VerifyStableZipScreen() + screen.on_pre_enter() + screen.on_enter() self.render(screen) # get your Window instance safely EventLoop.ensure_window() + button = screen.ids[f"{screen.id}_label"] # DO tests - screen.on_pre_enter() - action = getattr(VerifyStableZipScreen, f"on_ref_press_{screen.id}") + action = getattr(screen.__class__, f"on_ref_press_{button.id}") action(None, "Back") # patch assertions mock_get_locale.assert_called() + mock_get_destdir_assets.assert_called() mock_set_screen.assert_called_once_with(name="MainScreen", direction="right") + mock_verify_sha256.assert_called() + mock_verify_signature.assert_called() diff --git a/e2e/test_022_flash_screen.py b/e2e/test_022_flash_screen.py index 800ea88a..f3a911a1 100644 --- a/e2e/test_022_flash_screen.py +++ b/e2e/test_022_flash_screen.py @@ -1,4 +1,3 @@ -import sys from unittest.mock import patch, MagicMock, call from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest @@ -196,10 +195,10 @@ def test_on_data_programming_bin(self, mock_get_locale): on_data = getattr(FlashScreen, "on_data") # Let's "print" some previous infos - for i in range(19): + for i in range(4): on_data(f"[color=#00ff00] INFO [/color] mock test message {i}") - self.assertEqual(len(screen.output), 18) + self.assertEqual(len(screen.output), 4) # Now print programming BIN on_data("Programming BIN: |=----------| 0.21% at 21 KiB/s") @@ -226,10 +225,10 @@ def test_on_data(self, mock_get_locale): on_data = getattr(FlashScreen, "on_data") # Let's "print" some previous infos - for i in range(19): + for i in range(4): on_data(f"[color=#00ff00] INFO [/color] mock test message {i}") - self.assertEqual(len(screen.output), 18) + self.assertEqual(len(screen.output), 4) # Now print programming BIN on_data("*") @@ -275,10 +274,10 @@ def test_on_data_pop_ouput(self, mock_get_locale): on_data = getattr(FlashScreen, "on_data") - for i in range(19): + for i in range(4): on_data(f"[color=#00ff00] INFO [/color] mock test message {i}") - self.assertEqual(len(screen.output), 18) + self.assertEqual(len(screen.output), 4) # patch assertions mock_get_locale.assert_called() @@ -319,24 +318,15 @@ def test_on_process(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - - if sys.platform in ("linux", "win32"): - sizes = [screen.SIZE_M, screen.SIZE_MP, screen.SIZE_P] - - else: - sizes = [screen.SIZE_MM, screen.SIZE_M, screen.SIZE_MP] - text = "".join( [ - f"[size={sizes[1]}sp][b]PLEASE DO NOT UNPLUG YOUR DEVICE[/b][/size]", + "[b]PLEASE DO NOT UNPLUG YOUR DEVICE[/b]", "\n", - f"[size={sizes[0]}sp]4.76 %[/size]", + "4.76 %", "\n", - f"[size={sizes[2]}sp]", "Flashing ", "[color=#efcc00][b]firmware.bin[/b][/color] at ", "[color=#efcc00][b]21 KiB/s[/b][/color]", - "[/size]", ] ) on_process = getattr(FlashScreen, "on_process") @@ -360,18 +350,10 @@ def test_on_done(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - - if sys.platform in ("linux", "win32"): - size = screen.SIZE_M - - else: - size = screen.SIZE_M - text = "".join( [ - f"[size={size}sp][b]DONE![/b][/size]", + "[b]DONE![/b]", "\n", - f"[size={size}sp]", "[color=#00FF00]", "[ref=Back][u]Back[/u][/ref]", "[/color]", @@ -385,9 +367,6 @@ def test_on_done(self, mock_get_locale): on_done = getattr(FlashScreen, "on_done") on_done(0) - print(text) - print("=============") - print(screen.ids[f"{screen.id}_progress"].text) self.assertEqual(screen.ids[f"{screen.id}_progress"].text, text) # patch assertions diff --git a/e2e/test_023_wipe_screen.py b/e2e/test_023_wipe_screen.py index dc70883c..bfa3a41e 100644 --- a/e2e/test_023_wipe_screen.py +++ b/e2e/test_023_wipe_screen.py @@ -1,4 +1,3 @@ -import sys import os from unittest.mock import patch, MagicMock, call from kivy.base import EventLoop, EventLoopBase @@ -171,10 +170,10 @@ def test_on_print_callback_pop_ouput(self, mock_get_locale): on_data = getattr(WipeScreen, "on_data") - for i in range(19): + for i in range(4): on_data(f"[color=#00ff00] INFO [/color] mock test message {i}") - self.assertEqual(len(screen.output), 18) + self.assertEqual(len(screen.output), 4) # patch assertions mock_get_locale.assert_any_call() @@ -215,18 +214,10 @@ def test_on_done(self, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - - if sys.platform in ("linux", "win32"): - size = screen.SIZE_M - - else: - size = screen.SIZE_M - text = "".join( [ - f"[size={size}sp][b]DONE![/b][/size]", + "[b]DONE![/b]", "\n", - f"[size={size}sp]", "[color=#00FF00]", "[ref=Back][u]Back[/u][/ref]", "[/color]", diff --git a/e2e/test_024_warning_wipe_screen.py b/e2e/test_024_warning_wipe_screen.py index a2be4d8f..e6c394a8 100644 --- a/e2e/test_024_warning_wipe_screen.py +++ b/e2e/test_024_warning_wipe_screen.py @@ -1,4 +1,3 @@ -import sys import os from unittest.mock import patch, MagicMock, call from kivy.base import EventLoop, EventLoopBase @@ -64,25 +63,15 @@ def test_make_label_text(self, mock_get_locale): window = EventLoop.window grid = window.children[0].children[0] label = grid.children[0] - - if sys.platform in ("linux", "win32"): - sizes = [screen.SIZE_MP, screen.SIZE_P] - - else: - sizes = [screen.SIZE_MM, screen.SIZE_M] - screen.update(name=screen.name, key="locale", value="en_US.UTF-8") text = "".join( [ "[color=#EFCC00]", - f"[size={sizes[0]}]", "You are about to initiate a FULL WIPE of this device", - "[/size]", "[/color]", "\n", "\n", - f"[size={sizes[1]}]", "This operation will:", "\n", "* Permanently erase all saved data", @@ -90,10 +79,8 @@ def test_make_label_text(self, mock_get_locale): "* Remove the existing firmware", "\n", "* Render the device non-functional until new firmware is re-flashed", - "[/size]", "\n", "\n", - f"[size={sizes[0]}]", "[color=#00FF00]", "[ref=WipeScreen][u]Proceed[/u][/ref]", "[/color]", @@ -101,7 +88,6 @@ def test_make_label_text(self, mock_get_locale): "[color=#FF0000]", "[ref=MainScreen][u]Back[/u][/ref]", "[/color]", - "[/size]", ] ) @@ -173,8 +159,9 @@ def test_on_ref_press_proceed( window = EventLoop.window grid = window.children[0].children[0] label = grid.children[0] + button = screen.ids[f"{screen.id}_label"] - action = getattr(WarningWipeScreen, f"on_ref_press_{screen.id}") + action = getattr(screen.__class__, f"on_ref_press_{button.id}") action(label, "WipeScreen") mock_get_locale.assert_any_call() @@ -220,8 +207,8 @@ def test_on_ref_press_deny(self, mock_set_screen, mock_get_locale): window = EventLoop.window grid = window.children[0].children[0] label = grid.children[0] - - action = getattr(WarningWipeScreen, f"on_ref_press_{screen.id}") + button = screen.ids[f"{screen.id}_label"] + action = getattr(screen.__class__, f"on_ref_press_{button.id}") action(label, "MainScreen") mock_get_locale.assert_any_call() diff --git a/e2e/test_025_error_screen.py b/e2e/test_025_error_screen.py index 37b94d15..a6316ef1 100644 --- a/e2e/test_025_error_screen.py +++ b/e2e/test_025_error_screen.py @@ -61,28 +61,19 @@ def test_make_label_text(self, mock_get_locale): text = "".join( [ - f"[size={screen.SIZE_M}sp]", "[color=#ff0000]Error[/color]", - "[/size]", - "\n", "\n", " mocked error", "\n", " at test", - "[/size]", - "\n", "\n", - f"[size={screen.SIZE_P}sp]", "Report issue at ", "[color=#00aabb]", "[ref=ReportIssue]", f"{screen.src_code}/issues", "[/ref]", "[/color]", - "[/size]", - "\n", "\n", - f"[size={screen.SIZE_MP}sp]", "[color=#00FF00]", "[ref=Back]", "[u]Back[/u]", @@ -93,13 +84,9 @@ def test_make_label_text(self, mock_get_locale): "[ref=Quit]", "[u]Quit[/u]", "[/ref]", - "[/size]", ] ) - print(label.text) - print("============") - print(text) self.assertEqual(label.text, text) # patch assertions @@ -120,8 +107,9 @@ def test_on_ref_press_back(self, mock_set_screen, mock_get_locale): window = EventLoop.window grid = window.children[0].children[0] label = grid.children[0] + button = screen.ids[f"{screen.id}_label"] - action = getattr(ErrorScreen, f"on_ref_press_{screen.id}") + action = getattr(ErrorScreen, f"on_ref_press_{button.id}") action(label, "Back") mock_get_locale.assert_any_call() @@ -146,8 +134,9 @@ def test_on_ref_press_quit(self, mock_quit_app, mock_get_locale): window = EventLoop.window grid = window.children[0].children[0] label = grid.children[0] + button = screen.ids[f"{screen.id}_label"] - action = getattr(ErrorScreen, f"on_ref_press_{screen.id}") + action = getattr(ErrorScreen, f"on_ref_press_{button.id}") action(label, "Quit") mock_get_locale.assert_any_call() @@ -170,8 +159,9 @@ def test_on_ref_press_report(self, mock_web_open, mock_get_locale): window = EventLoop.window grid = window.children[0].children[0] label = grid.children[0] + button = screen.ids[f"{screen.id}_label"] - action = getattr(ErrorScreen, f"on_ref_press_{screen.id}") + action = getattr(ErrorScreen, f"on_ref_press_{button.id}") action(label, "ReportIssue") mock_get_locale.assert_any_call() diff --git a/src/app/__init__.py b/src/app/__init__.py index 2d41c572..0f038f37 100644 --- a/src/app/__init__.py +++ b/src/app/__init__.py @@ -58,10 +58,9 @@ class KruxInstallerApp(ConfigKruxInstaller): def __init__(self, **kwargs): super().__init__(**kwargs) - Window.maximize() + # Window.maximize() # Window.fullscreen = 'auto' - print(Window.size) - # Window.size = (640, 800) + Window.size = (1000, 800) self.debug(f"Window.size={Window.size}") Window.clearcolor = (0.9, 0.9, 0.9, 1) diff --git a/src/app/screens/about_screen.py b/src/app/screens/about_screen.py index 46cc983c..e51e03ed 100644 --- a/src/app/screens/about_screen.py +++ b/src/app/screens/about_screen.py @@ -39,14 +39,7 @@ def __init__(self, **kwargs): self.make_grid(wid="about_screen_grid", rows=1) - self.make_label( - wid=f"{self.id}_label", - text="", - root_widget=f"{self.id}_grid", - halign="justify", - ) - - def _on_ref_press(*args): + def on_ref_press(*args): self.debug(f"Calling Button::{args[0]}::on_ref_press") self.debug(f"Opening {args[1]}") @@ -59,8 +52,18 @@ def _on_ref_press(*args): if args[1] == "SourceCode": webbrowser.open(self.src_code) - setattr(self, f"on_ref_press_{self.id}_label", _on_ref_press) - self.ids[f"{self.id}_label"].bind(on_ref_press=_on_ref_press) + self.make_button( + row=0, + wid=f"{self.id}_label", + text="", + root_widget=f"{self.id}_grid", + halign=None, + on_press=None, + on_release=None, + on_ref_press=on_ref_press, + ) + + self.ids[f"{self.id}_label"].halign = "justify" fns = [ partial(self.update, name=self.name, key="canvas"), @@ -85,25 +88,20 @@ def on_update(): self.ids[f"{self.id}_label"].text = "".join( [ - f"[size={self.SIZE_G}sp]", f"[ref=SourceCode][b]v{get_version()}[/b][/ref]", - "[/size]", "\n", - "\n" f"[size={self.SIZE_M}sp]", + "\n", f"{follow}: ", "[color=#00AABB]", "[ref=X][u]@selfcustodykrux[/u][/ref]", "[/color]", - "[/size]", "\n", "\n", - f"[size={self.SIZE_M}sp]", "[color=#00FF00]", "[ref=Back]", f"[u]{back}[/u]", "[/ref]", "[/color]", - "[/size]", ] ) diff --git a/src/app/screens/ask_permission_dialout_screen.py b/src/app/screens/ask_permission_dialout_screen.py index c724b0c2..c51b2fa9 100644 --- a/src/app/screens/ask_permission_dialout_screen.py +++ b/src/app/screens/ask_permission_dialout_screen.py @@ -77,7 +77,7 @@ def on_permission_created(output: str): AskPermissionDialoutScreen, "on_permission_created", on_permission_created ) - def _on_ref_press(*args): + def on_ref_press(*args): if args[1] == "Allow": # If user isnt in the dialout group, # but the configuration was done correctly @@ -101,18 +101,17 @@ def _on_ref_press(*args): if args[1] == "Deny": AskPermissionDialoutScreen.quit_app() - self.make_label( + self.make_button( + row=0, wid=f"{self.id}_label", text="", root_widget=f"{self.id}_grid", halign="justify", + on_press=None, + on_release=None, + on_ref_press=on_ref_press, ) - setattr( - AskPermissionDialoutScreen, f"on_ref_press_{self.id}_label", _on_ref_press - ) - self.ids[f"{self.id}_label"].bind(on_ref_press=_on_ref_press) - fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) @@ -168,25 +167,23 @@ def show_warning(self): self.ids[f"{self.id}_label"].text = "".join( [ - f"[size={self.SIZE_G}sp][color=#efcc00]{warn_msg}[/color][/size]", + f"[color=#efcc00]{warn_msg}[/color]", "\n", - f'[size={self.SIZE_MP}sp]{first_msg} "{self.distro}"', + f'{first_msg} "{self.distro}"', "\n", f"{access_msg}.", "\n", proceed_msg, - "\n" f"{exec_msg}:", + "\n", + f"{exec_msg}:", "\n", "[color=#00ff00]", f"{self._bin} {" ".join(self._bin_args or [])} {self.group} {self.user}", "[/color]", - "[/size]", "\n", "\n", - f"[size={self.SIZE_M}]", "[color=#00FF00][ref=Allow]Allow[/ref][/color]", " ", "[color=#FF0000][ref=Deny]Deny[/ref][/color]", - "[/size]", ] ) diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index 9ed49eb5..6e8bd2fd 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -25,8 +25,6 @@ from functools import partial from threading import Thread from kivy.clock import Clock, ClockEvent -from kivy.weakproxy import WeakProxy -from kivy.uix.label import Label from src.app.screens.base_screen import BaseScreen from src.utils.downloader.asset_downloader import AssetDownloader @@ -46,27 +44,30 @@ def __init__(self, wid: str, name: str, **kwargs): # progress label, show a "Connecting" # before start the download to make - progress = Label( + self.make_button( + row=0, + wid=f"{self.id}_progress", + root_widget=f"{self.id}_grid", + halign=None, text="", - markup=True, - valign="center", - halign="center", + on_press=None, + on_release=None, + on_ref_press=None, ) # information label # it has data about url # and downloaded paths - asset_label = Label(markup=True, valign="center", halign="center") - - # setup progress label - progress.id = f"{self.id}_progress" - self.ids[f"{self.id}_grid"].add_widget(progress) - self.ids[progress.id] = WeakProxy(progress) - - # setup information label - asset_label.id = f"{self.id}_info" - self.ids[f"{self.id}_grid"].add_widget(asset_label) - self.ids[asset_label.id] = WeakProxy(asset_label) + self.make_button( + row=1, + wid=f"{self.id}_info", + root_widget=f"{self.id}_grid", + halign=None, + text="", + on_press=None, + on_release=None, + on_ref_press=None, + ) @property def to_screen(self) -> str: @@ -196,7 +197,6 @@ def make_download_info( """ return "".join( [ - f"[size={size}sp]", download_msg, "\n", f"[color=#00AABB][ref={from_url}]{from_url}[/ref][/color]", @@ -204,7 +204,6 @@ def make_download_info( to_msg, "\n", to_path, - "[/size]", ] ) @@ -222,13 +221,11 @@ def make_progress_info( """ return "".join( [ - f"[size={sizes[0]}sp][b]{percent * 100:,.2f} %[/b][/size]", + f"[b]{percent * 100:,.2f} %[/b]", "\n", - f"[size={sizes[1]}sp]", str(downloaded_len), f" {of_msg} ", str(content_len), " B", - "[/size]", ] ) diff --git a/src/app/screens/base_flash_screen.py b/src/app/screens/base_flash_screen.py index 456e89fc..6a39451c 100644 --- a/src/app/screens/base_flash_screen.py +++ b/src/app/screens/base_flash_screen.py @@ -139,13 +139,11 @@ def on_done(dt): done = self.translate("DONE") back = self.translate("Back") _quit = self.translate("Quit") - size = self.SIZE_M self.ids[f"{self.id}_progress"].text = "".join( [ - f"[size={size}sp][b]{done}![/b][/size]", + f"[b]{done}![/b]", "\n", - f"[size={size}sp]", "[color=#00FF00]", f"[ref=Back][u]{back}[/u][/ref]", "[/color]", diff --git a/src/app/screens/base_screen.py b/src/app/screens/base_screen.py index b6c5c2eb..9f32deb7 100644 --- a/src/app/screens/base_screen.py +++ b/src/app/screens/base_screen.py @@ -25,6 +25,7 @@ import re import sys import typing +from math import sqrt from pathlib import Path from functools import partial from kivy.clock import Clock @@ -66,24 +67,18 @@ def __init__(self, wid: str, name: str, **kwargs): # Setup the correct font size if sys.platform in ("linux", "win32"): - self.SIZE_XG = Window.size[0] // 4 - self.SIZE_GG = Window.size[0] // 8 self.SIZE_G = Window.size[0] // 16 self.SIZE_MM = Window.size[0] // 24 self.SIZE_M = Window.size[0] // 32 self.SIZE_MP = Window.size[0] // 48 self.SIZE_P = Window.size[0] // 64 - self.SIZE_PP = Window.size[0] // 128 elif sys.platform == "darwin": - self.SIZE_XG = Window.size[0] // 16 - self.SIZE_GG = Window.size[0] // 24 self.SIZE_G = Window.size[0] // 32 self.SIZE_MM = Window.size[0] // 48 self.SIZE_M = Window.size[0] // 64 self.SIZE_MP = Window.size[0] // 128 self.SIZE_P = Window.size[0] // 192 - self.SIZE_PP = Window.size[0] // 256 @property def logo_img(self) -> str: @@ -159,11 +154,18 @@ def make_subgrid(self, wid: str, rows: int, root_widget: str): self.ids[root_widget].add_widget(grid) self.ids[wid] = WeakProxy(grid) - def make_label(self, wid: str, text: str, root_widget: str, halign: str): + def make_label( + self, + wid: str, + text: str, + root_widget: str, + halign: str, + ): """Build grid where buttons will be placed""" - self.debug(f"Building GridLayout::{wid}") + self.debug(f"Building Label::{wid}") label = Label(text=text, markup=True, halign=halign) label.id = wid + label.bind(texture_size=label.setter("size")) self.ids[root_widget].add_widget(label) self.ids[wid] = WeakProxy(label) @@ -186,11 +188,13 @@ def make_button( wid: str, text: str, row: int, - on_press: typing.Callable, - on_release: typing.Callable, + halign: str | None, + on_press: typing.Callable | None, + on_release: typing.Callable | None, + on_ref_press: typing.Callable | None, ): """Create buttons in a dynamic way""" - self.debug(f"{wid} -> {root_widget}") + self.debug(f"button::{wid} row={row}") total = self.ids[root_widget].rows btn = Button( @@ -203,12 +207,24 @@ def make_button( ) btn.id = wid + if halign is not None: + btn.halign = halign + # define button methods to be callable in classes - setattr(self, f"on_press_{wid}", on_press) - setattr(self, f"on_release_{wid}", on_release) + if on_press is not None: + btn.bind(on_press=on_press) + setattr(self.__class__, f"on_press_{wid}", on_press) + + if on_release is not None: + btn.bind(on_release=on_release) + setattr(self.__class__, f"on_release_{wid}", on_release) + + if on_ref_press is not None: + btn.bind(on_ref_press=on_ref_press) + setattr(self.__class__, f"on_ref_press_{wid}", on_ref_press) + + btn.bind(size=BaseScreen.on_resize) - btn.bind(on_press=on_press) - btn.bind(on_release=on_release) btn.x = 0 btn.y = (Window.size[1] / total) * row btn.width = Window.size[0] @@ -216,10 +232,6 @@ def make_button( self.ids[root_widget].add_widget(btn) self.ids[btn.id] = WeakProxy(btn) - self.debug( - f"button::{id} row={row}, pos_hint={btn.pos_hint}, size_hint={btn.size_hint}" - ) - def redirect_exception(self, exception: Exception): """Get an exception and prepare a ErrorScreen rendering""" screen = self.manager.get_screen("ErrorScreen") @@ -266,6 +278,18 @@ def update_screen( if on_update is not None: on_update() + @staticmethod + def get_half_diagonal_screen_size(factor: int): + """Get half of diagonal size""" + w_width, w_height = Window.size + return int(sqrt((w_width**2 + w_height**2) / 2)) // factor + + @staticmethod + # pylint: disable=unused-argument + def on_resize(instance, value): + """Redefine font size of a button when size changes""" + instance.font_size = BaseScreen.get_half_diagonal_screen_size(38) + @staticmethod def quit_app(): """Stop the kivy process""" diff --git a/src/app/screens/download_beta_screen.py b/src/app/screens/download_beta_screen.py index 9c8cab2f..0a7950f2 100644 --- a/src/app/screens/download_beta_screen.py +++ b/src/app/screens/download_beta_screen.py @@ -80,9 +80,6 @@ def on_progress(data: bytes): self.debug(f"Bind {self.__class__}.on_progress={on_progress}") setattr(self.__class__, "on_progress", on_progress) - fn = partial(self.update, name=self.name, key="canvas") - Clock.schedule_once(fn, 0) - # pylint: disable=unused-argument def update(self, *args, **kwargs): """Update screen with version key. Should be called before `on_enter`""" @@ -145,7 +142,6 @@ def build_downloader(self): self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_MP}sp]", downloading, "\n", "[color=#00AABB]", @@ -156,7 +152,6 @@ def build_downloader(self): "\n", self.downloader.destdir, "\n", - "[/size]", ] ) @@ -177,9 +172,9 @@ def on_download_progress(self, value): downs = [f"{lens[0]/(1<<20):,.2f}", f"{lens[1]/(1<<20):,.2f}"] self.ids[f"{self.id}_progress"].text = "".join( [ - f"[size={self.SIZE_G}sp][b]{ percent * 100:,.2f} %[/b][/size]", + f"[b]{ percent * 100:,.2f} %[/b]", "\n", - f"[size={self.SIZE_MP}sp]{downs[0]} of {downs[1]} MB[/size]", + f"{downs[0]} of {downs[1]} MB", ] ) @@ -188,11 +183,9 @@ def on_download_progress(self, value): destdir = os.path.join(self.downloader.destdir, "kboot.kfpkg") self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_MP}sp]", destdir, "\n", downloaded, - "[/size]", ] ) diff --git a/src/app/screens/download_selfcustody_pem_screen.py b/src/app/screens/download_selfcustody_pem_screen.py index d62b92ba..977a79bf 100644 --- a/src/app/screens/download_selfcustody_pem_screen.py +++ b/src/app/screens/download_selfcustody_pem_screen.py @@ -82,7 +82,6 @@ def on_update_pem(self): self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_MP}sp]", downloading, "\n", f"[color=#00AABB][ref={url}]{url}[/ref][/color]", @@ -90,7 +89,6 @@ def on_update_pem(self): to, "\n", filepath, - "[/size]", ] ) @@ -112,14 +110,12 @@ def on_update_progress(self, value: Any): of = self.translate("of") self.ids[f"{self.id}_progress"].text = "".join( [ - f"[size={self.SIZE_G}sp][b]{percent * 100:,.2f} %[/b][/size]", + f"[b]{percent * 100:,.2f} %[/b]", "\n", - f"[size={self.SIZE_MP}sp]", str(lens[0]), f" {of} ", str(lens[1]), " B", - "[/size]", ] ) @@ -129,11 +125,9 @@ def on_update_progress(self, value: Any): filepath = os.path.join(destdir, "selfcustody.pem") self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_MP}sp]", filepath, "\n", downloaded, - "[/size]", ] ) diff --git a/src/app/screens/download_stable_zip_screen.py b/src/app/screens/download_stable_zip_screen.py index a08619e6..a470f840 100644 --- a/src/app/screens/download_stable_zip_screen.py +++ b/src/app/screens/download_stable_zip_screen.py @@ -120,7 +120,6 @@ def build_downloader(self, version: str): self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_MP}sp]", downloading, "\n", f"[color=#00AABB][ref={url}]{url}[/ref][/color]", @@ -128,7 +127,6 @@ def build_downloader(self, version: str): to, "\n", filepath, - "[/size]", ] ) @@ -146,14 +144,12 @@ def on_download_progress(self, value: dict): of = self.translate("of") self.ids[f"{self.id}_progress"].text = "".join( [ - f"[size={self.SIZE_G}sp][b]{ percent * 100:,.2f} %[/b][/size]", + f"[b]{ percent * 100:,.2f} %[/b]", "\n", - f"[size={self.SIZE_MP}sp]", downs[0], f" {of} ", downs[1], " MB", - "[/size]", ] ) @@ -165,11 +161,9 @@ def on_download_progress(self, value: dict): filepath = os.path.join(destdir, f"krux-{self.version}.zip") self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_MP}sp]", filepath, "\n", downloaded, - "[/size]", ] ) # When finish, change the label, wait some seconds diff --git a/src/app/screens/download_stable_zip_sha256_screen.py b/src/app/screens/download_stable_zip_sha256_screen.py index 056c0145..ccac39d0 100644 --- a/src/app/screens/download_stable_zip_sha256_screen.py +++ b/src/app/screens/download_stable_zip_sha256_screen.py @@ -144,11 +144,9 @@ def on_download_progress(self, value: dict): filepath = os.path.join(destdir, f"krux-{self.version}.zip.sha256.txt") self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_MP}sp]", filepath, "\n", downloaded, - "[/size]", ] ) diff --git a/src/app/screens/download_stable_zip_sig_screen.py b/src/app/screens/download_stable_zip_sig_screen.py index 3ac46ee4..06dc4f69 100644 --- a/src/app/screens/download_stable_zip_sig_screen.py +++ b/src/app/screens/download_stable_zip_sig_screen.py @@ -138,11 +138,9 @@ def on_download_progress(self, value: dict): filepath = os.path.join(destdir, f"krux-{self.version}.zip.sig") self.ids[f"{self.id}_info"].text = "".join( [ - f"[size={self.SIZE_MP}sp]", filepath, "\n", downloaded, - "[/size]", ] ) diff --git a/src/app/screens/error_screen.py b/src/app/screens/error_screen.py index 9b024c75..32b61133 100644 --- a/src/app/screens/error_screen.py +++ b/src/app/screens/error_screen.py @@ -53,16 +53,17 @@ def on_ref_press(*args): if args[1] == "ReportIssue": webbrowser.open(f"{self.src_code}/issues") - self.make_label( + self.make_button( + row=0, wid=f"{self.id}_label", root_widget=f"{self.id}_grid", text="", halign="center", + on_press=None, + on_release=None, + on_ref_press=on_ref_press, ) - setattr(ErrorScreen, f"on_ref_press_{self.id}", on_ref_press) - self.ids[f"{self.id}_label"].bind(on_ref_press=on_ref_press) - @staticmethod def chunkstring(string, length): """Split a long string into multiline string with equal lengths""" @@ -93,26 +94,17 @@ def on_update(): self.ids[f"{self.id}_label"].text = "".join( [ - f"[size={self.SIZE_M}sp]", f"[color=#ff0000]{title}[/color]", - "[/size]", - "\n", "\n", "\n".join(reason), - "[/size]", "\n", - "\n", - f"[size={self.SIZE_P}sp]", "Report issue at ", "[color=#00aabb]", "[ref=ReportIssue]", f"{self.src_code}/issues", "[/ref]", "[/color]", - "[/size]", - "\n", "\n", - f"[size={self.SIZE_MP}sp]", "[color=#00FF00]", "[ref=Back]", "[u]Back[/u]", @@ -123,15 +115,13 @@ def on_update(): "[ref=Quit]", "[u]Quit[/u]", "[/ref]", - "[/size]", ] ) - setattr(ErrorScreen, "on_update", on_update) self.update_screen( name=name, key=key, value=value, allowed_screens=tuple(self.manager.screen_names), - on_update=getattr(ErrorScreen, "on_update"), + on_update=on_update, ) diff --git a/src/app/screens/flash_screen.py b/src/app/screens/flash_screen.py index 2d6cf122..13c73cfa 100644 --- a/src/app/screens/flash_screen.py +++ b/src/app/screens/flash_screen.py @@ -21,7 +21,6 @@ """ main_screen.py """ -import sys import threading import traceback from functools import partial @@ -69,7 +68,7 @@ def on_data(*args, **kwargs): self.output.append("*") self.output.append("") - if len(self.output) > 18: + if len(self.output) > 4: del self.output[:1] self.ids[f"{self.id}_info"].text = "\n".join(self.output) @@ -86,23 +85,16 @@ def build_on_process(self): def on_process(file_type: str, iteration: int, total: int, suffix: str): percent = (iteration / total) * 100 - - if sys.platform in ("linux", "win32"): - sizes = [self.SIZE_M, self.SIZE_MP, self.SIZE_P] - else: - sizes = [self.SIZE_MM, self.SIZE_M, self.SIZE_MP] - please = self.translate("PLEASE DO NOT UNPLUG YOUR DEVICE") flashing = self.translate("Flashing") at = self.translate("at") self.ids[f"{self.id}_progress"].text = "".join( [ - f"[size={sizes[1]}sp][b]{please}[/b][/size]", + f"[b]{please}[/b]", "\n", - f"[size={sizes[0]}sp]{percent:.2f} %[/size]", + f"{percent:.2f} %", "\n", - f"[size={sizes[2]}sp]", f"{flashing} ", "[color=#efcc00]", "[b]", @@ -115,7 +107,6 @@ def on_process(file_type: str, iteration: int, total: int, suffix: str): suffix, "[/b]", "[/color]", - "[/size]", ] ) @@ -149,19 +140,26 @@ def on_ref_press(*args): root_widget=f"{self.id}_subgrid", ) - self.make_label( + self.make_button( + row=1, wid=f"{self.id}_progress", text="", root_widget=f"{self.id}_subgrid", halign="center", + on_press=None, + on_release=None, + on_ref_press=on_ref_press, ) - self.ids[f"{self.id}_progress"].bind(on_ref_press=on_ref_press) - self.make_label( + self.make_button( + row=2, wid=f"{self.id}_info", text="", root_widget=f"{self.id}_grid", halign="justify", + on_press=None, + on_release=None, + on_ref_press=None, ) # pylint: disable=unused-argument @@ -176,43 +174,15 @@ def on_enter(self, *args): ) self.thread = threading.Thread(name=self.name, target=on_process) - if sys.platform in ("linux", "win32"): - sizes = [self.SIZE_M, self.SIZE_P] - else: - sizes = [self.SIZE_MM, self.SIZE_MP] - # if anything wrong happen, show it def hook(err): if not self.is_done: trace = traceback.format_exception( err.exc_type, err.exc_value, err.exc_traceback ) - msg = "".join(trace) + msg = "".join(trace[-2:]) self.error(msg) - - back = self.translate("Back") - _quit = self.translate("Quit") - self.ids[f"{self.id}_progress"].text = "".join( - [ - f"[size={sizes[0]}]", - "[color=#FF0000]Flash failed[/color]", - "[/size]", - "\n", - "\n", - f"[size={sizes[0]}]", - "[color=#00FF00]", - f"[ref=Back][u]{back}[/u][/ref][/color]", - " ", - "[color=#EFCC00]", - f"[ref=Quit][u]{_quit}[/u][/ref]", - "[/color]", - "[/size]", - ] - ) - - self.ids[f"{self.id}_info"].text = "".join( - [f"[size={sizes[1]}]", msg, "[/size]"] - ) + self.redirect_exception(exception=RuntimeError(f"Flash failed: {msg}")) # hook what happened threading.excepthook = hook diff --git a/src/app/screens/main_screen.py b/src/app/screens/main_screen.py index eaf5be08..6461e9bf 100644 --- a/src/app/screens/main_screen.py +++ b/src/app/screens/main_screen.py @@ -103,23 +103,20 @@ def build_select_version_button(self): wid = "main_select_version" msg = self.translate("Version") - def on_press_select_version(instance): + def on_press(instance): self.debug(f"Calling {instance.id}::on_press") self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) self.ids[instance.id].text = "".join( [ - f"[size={self.SIZE_M}sp]", "[color=#efcc00]", f"[b]{self.translate("Fetching data from")}[/b]", "\n", - f"[size={self.SIZE_MP}sp]", url, - "[/size]", "[/color]", ] ) - def on_release_select_version(instance): + def on_release(instance): self.debug(f"Calling {instance.id}::on_release") select_version = self.manager.get_screen("SelectVersionScreen") select_version.clear() @@ -128,9 +125,6 @@ def on_release_select_version(instance): self.set_screen(name="SelectVersionScreen", direction="left") self.update(name=self.name, key="version", value=self.version) - setattr(MainScreen, "on_press_select_version", on_press_select_version) - setattr(MainScreen, "on_release_select_version", on_release_select_version) - self.make_button( row=0, wid=wid, @@ -143,8 +137,10 @@ def on_release_select_version(instance): "[/color]", ] ), - on_press=getattr(MainScreen, "on_press_select_version"), - on_release=getattr(MainScreen, "on_release_select_version"), + halign=None, + on_press=on_press, + on_release=on_release, + on_ref_press=None, ) def build_select_device_button(self): @@ -184,9 +180,12 @@ def on_release_select_device(instance): "[/color]", ] ), + halign=None, on_press=getattr(MainScreen, "on_press_select_device"), on_release=getattr(MainScreen, "on_release_select_device"), + on_ref_press=None, ) + self.ids[wid].size_hint = (1, 1) def build_flash_button(self): """Create staticmethods using instance variables to control the flash button""" @@ -222,6 +221,13 @@ def on_release_flash(instance): to_screen = "DownloadStableZipScreen" screen = self.manager.get_screen(to_screen) + partials.append( + partial( + screen.update, + name=self.name, + key="canvas", + ) + ) partials.append( partial( screen.update, @@ -235,6 +241,13 @@ def on_release_flash(instance): elif re.findall("^odudex/krux_binaries", self.version): to_screen = "DownloadBetaScreen" screen = self.manager.get_screen(to_screen) + partials.append( + partial( + screen.update, + name=self.name, + key="canvas", + ) + ) partials.append( partial( screen.update, @@ -270,8 +283,10 @@ def on_release_flash(instance): wid=wid, root_widget="main_screen_grid", text=f"[color=#333333]{self.translate("Flash")}[/color]", + halign=None, on_press=getattr(MainScreen, "on_press_flash"), on_release=getattr(MainScreen, "on_release_flash"), + on_ref_press=None, ) def build_wipe_button(self): @@ -301,8 +316,10 @@ def on_release_wipe(instance): wid=wid, root_widget="main_screen_grid", text=f"[color=#333333]{self.translate("Wipe")}[/color]", + halign=None, on_press=getattr(MainScreen, "on_press_wipe"), on_release=getattr(MainScreen, "on_release_wipe"), + on_ref_press=None, ) def build_settings_button(self): @@ -326,8 +343,10 @@ def on_release_settings(instance): wid=wid, root_widget="main_screen_grid", text=self.translate("Settings"), + halign=None, on_press=getattr(MainScreen, "on_press_settings"), on_release=getattr(MainScreen, "on_release_settings"), + on_ref_press=None, ) def build_about_button(self): @@ -351,8 +370,10 @@ def on_release_about(instance): wid=wid, root_widget="main_screen_grid", text=self.translate("About"), + halign=None, on_press=getattr(MainScreen, "on_press_about"), on_release=getattr(MainScreen, "on_release_about"), + on_ref_press=None, ) def update_version(self, value: str): diff --git a/src/app/screens/select_device_screen.py b/src/app/screens/select_device_screen.py index 6a089443..cf7e4201 100644 --- a/src/app/screens/select_device_screen.py +++ b/src/app/screens/select_device_screen.py @@ -42,12 +42,12 @@ def __init__(self, **kwargs): ["m5stickv", "amigo", "dock", "bit", "yahboom", "cube", "wonder_mv"] ): - def _on_press(instance): + def on_press(instance): if instance.id in self.enabled_devices: self.debug(f"Calling Button::{instance.id}::on_press") self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) - def _on_release(instance): + def on_release(instance): if instance.id in self.enabled_devices: self.debug(f"Calling Button::{instance.id}::on_release") self.set_background(wid=instance.id, rgba=(0, 0, 0, 1)) @@ -69,8 +69,10 @@ def _on_release(instance): wid=f"select_device_{device}", root_widget="select_device_screen_grid", text="", - on_press=_on_press, - on_release=_on_release, + halign=None, + on_press=on_press, + on_release=on_release, + on_ref_press=None, ) # pylint: disable=unused-argument diff --git a/src/app/screens/select_old_version_screen.py b/src/app/screens/select_old_version_screen.py index 459ddf0d..ccc1abd9 100644 --- a/src/app/screens/select_old_version_screen.py +++ b/src/app/screens/select_old_version_screen.py @@ -69,8 +69,10 @@ def on_release(instance): wid=wid, root_widget="select_old_version_screen_grid", text=text, + halign=None, on_press=on_press, on_release=on_release, + on_ref_press=None, ) def build_back_button(self, text: str, row: int): @@ -93,8 +95,10 @@ def on_release(instance): wid="select_old_version_back", root_widget="select_old_version_screen_grid", text=text, + halign=None, on_press=on_press, on_release=on_release, + on_ref_press=None, ) def fetch_releases(self, old_versions: typing.List[str]): diff --git a/src/app/screens/select_version_screen.py b/src/app/screens/select_version_screen.py index b0dda034..432f10a2 100644 --- a/src/app/screens/select_version_screen.py +++ b/src/app/screens/select_version_screen.py @@ -73,16 +73,16 @@ def on_release(instance): self.set_screen(name="MainScreen", direction="right") wid = f"{self.id}_latest" - setattr(SelectVersionScreen, f"on_press_{wid}", on_press) - setattr(SelectVersionScreen, f"on_release_{wid}", on_release) self.make_button( row=0, wid=wid, root_widget="select_version_screen_grid", text=text, - on_press=getattr(SelectVersionScreen, f"on_press_{wid}"), - on_release=getattr(SelectVersionScreen, f"on_release_{wid}"), + halign=None, + on_press=on_press, + on_release=on_release, + on_ref_press=None, ) def build_select_beta_version_button(self, text: str): @@ -115,16 +115,15 @@ def on_release(instance): self.set_screen(name="WarningBetaScreen", direction="left") wid = f"{self.id}_beta" - setattr(SelectVersionScreen, f"on_press_{wid}", on_press) - setattr(SelectVersionScreen, f"on_release_{wid}", on_release) - self.make_button( row=1, wid=wid, root_widget="select_version_screen_grid", text=text, - on_press=getattr(SelectVersionScreen, f"on_press_{wid}"), - on_release=getattr(SelectVersionScreen, f"on_release_{wid}"), + halign=None, + on_press=on_press, + on_release=on_release, + on_ref_press=None, ) def build_select_version_old_button(self, text: str): @@ -140,16 +139,15 @@ def on_release(instance): self.set_screen(name="SelectOldVersionScreen", direction="left") wid = f"{self.id}_old" - setattr(SelectVersionScreen, f"on_press_{wid}", on_press) - setattr(SelectVersionScreen, f"on_release_{wid}", on_release) - self.make_button( row=2, wid=wid, root_widget="select_version_screen_grid", text=text, - on_press=getattr(SelectVersionScreen, f"on_press_{wid}"), - on_release=getattr(SelectVersionScreen, f"on_release_{wid}"), + halign=None, + on_press=on_press, + on_release=on_release, + on_ref_press=None, ) def build_select_version_back_button(self, text: str): @@ -165,16 +163,15 @@ def on_release(instance): self.set_screen(name="MainScreen", direction="right") wid = f"{self.id}_back" - setattr(SelectVersionScreen, f"on_press_{wid}", on_press) - setattr(SelectVersionScreen, f"on_release_{wid}", on_release) - self.make_button( row=3, wid=wid, root_widget="select_version_screen_grid", text=text, - on_press=getattr(SelectVersionScreen, f"on_press_{wid}"), - on_release=getattr(SelectVersionScreen, f"on_release_{wid}"), + halign=None, + on_press=on_press, + on_release=on_release, + on_ref_press=None, ) def fetch_releases(self): diff --git a/src/app/screens/unzip_stable_screen.py b/src/app/screens/unzip_stable_screen.py index d932211c..9e28e959 100644 --- a/src/app/screens/unzip_stable_screen.py +++ b/src/app/screens/unzip_stable_screen.py @@ -89,27 +89,22 @@ def build_extract_to_flash_button(self): flash_msg = self.translate("Flash with") extract_msg = self.translate("Unziping") extracted_msg = self.translate("Unziped") - size = [self.SIZE_MM, self.SIZE_MP] - def _press(instance): + def on_press(instance): self.debug(f"Calling Button::{instance.id}::on_press") file_path = os.path.join(rel_path, "kboot.kfpkg") self.ids[instance.id].text = "".join( [ - f"[size={size[0]}sp]", extract_msg, - "[/size]", "\n", - f"[size={size[1]}sp]", "[color=#efcc00]", file_path, "[/color]", - "[/size]", ] ) self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) - def _release(instance): + def on_release(instance): self.debug(f"Calling Button::{instance.id}::on_release") file_path = os.path.join(base_path, "kboot.kfpkg") full_path = os.path.join(self.assets_dir, file_path) @@ -140,44 +135,35 @@ def _release(instance): p = os.path.join(rel_path, "kboot.kfpkg") self.ids[instance.id].text = "".join( [ - f"[size={size[0]}sp]", extracted_msg, - "[/size]", "\n", - f"[size={size[1]}sp]", "[color=#efcc00]", p, "[/color]", - "[/size]", ] ) time.sleep(2.1) self.set_screen(name="FlashScreen", direction="left") - setattr(UnzipStableScreen, f"on_press_{self.id}_flash_button", _press) - setattr(UnzipStableScreen, f"on_release_{self.id}_flash_button", _release) - p = os.path.join(rel_path, "kboot.kfpkg") self.make_button( + row=0, wid=f"{self.id}_flash_button", root_widget=f"{self.id}_grid", text="".join( [ - f"[size={size[0]}sp]", flash_msg, - "[/size]", "\n", - f"[size={size[1]}sp]", "[color=#efcc00]", p, "[/color]", - "[/size]", ] ), - row=0, - on_press=getattr(UnzipStableScreen, f"on_press_{self.id}_flash_button"), - on_release=getattr(UnzipStableScreen, f"on_release_{self.id}_flash_button"), + halign=None, + on_press=on_press, + on_release=on_release, + on_ref_press=None, ) def build_extract_to_airgap_button(self): @@ -189,17 +175,6 @@ def build_extract_to_airgap_button(self): airgap_msg = self.translate("Air-gapped update with") # extract_msg = self.translate("Unziping") # extracted_msg = self.translate("Unziped") - - size = [self.SIZE_MM, self.SIZE_MP] - - # activated = False - - def _press(instance): - pass - - def _release(instance): - pass - # def _press(instance): # if activated: # self.debug(f"Calling Button::{instance.id}::on_press") @@ -257,31 +232,24 @@ def _release(instance): # time.sleep(2.1) # self.set_screen(name="AirgapScreen", direction="left") - setattr(UnzipStableScreen, f"on_press_{self.id}_airgap_button", _press) - setattr(UnzipStableScreen, f"on_release_{self.id}_airgap_button", _release) - p = os.path.join(rel_path, "firmware.bin") self.make_button( + row=1, wid=f"{self.id}_airgap_button", root_widget=f"{self.id}_grid", text="".join( [ - f"[size={size[0]}sp]", "[color=#333333]", airgap_msg, "[/color]", - "[/size]", "\n", - f"[size={size[1]}sp]", "[color=#333333]", p, "[/color]", - "[/size]", ] ), - row=0, - on_press=getattr(UnzipStableScreen, f"on_press_{self.id}_airgap_button"), - on_release=getattr( - UnzipStableScreen, f"on_release_{self.id}_airgap_button" - ), + halign=None, + on_press=None, + on_release=None, + on_ref_press=None, ) diff --git a/src/app/screens/verify_stable_zip_screen.py b/src/app/screens/verify_stable_zip_screen.py index 4e8eb7e8..e5ea6dbf 100644 --- a/src/app/screens/verify_stable_zip_screen.py +++ b/src/app/screens/verify_stable_zip_screen.py @@ -22,12 +22,9 @@ verify_stable_zip_screen.py """ import os -import sys from functools import partial import typing from kivy.clock import Clock -from kivy.weakproxy import WeakProxy -from kivy.uix.label import Label from src.app.screens.base_screen import BaseScreen from src.utils.verifyer.sha256_check_verifyer import Sha256CheckVerifyer from src.utils.verifyer.sha256_verifyer import Sha256Verifyer @@ -46,10 +43,44 @@ def __init__(self, **kwargs): self.success = False self.make_grid(wid=f"{self.id}_grid", rows=1) - # instead make a button - # create a ref text that instead redirect - # to a web page, redirect to a screen - def _on_ref_press(*args): + fn = partial(self.update, name=self.name, key="canvas") + Clock.schedule_once(fn) + + # pylint: disable=unused-argument + def update(self, *args, **kwargs): + """Update widget from other screens""" + name = str(kwargs.get("name")) + key = str(kwargs.get("key")) + value = kwargs.get("value") + + def on_update(): + if key == "verify": + assets_dir = VerifyStableZipScreen.get_destdir_assets() + main_screen = self.manager.get_screen("MainScreen") + + verified = self.build_message_verify_sha256( + assets_dir=assets_dir, version=main_screen.version + ) + + verified += self.build_message_verify_signature( + assets_dir=assets_dir, version=main_screen.version + ) + + self.ids[f"{self.id}_label"].text = verified + + self.update_screen( + name=name, + key=key, + value=value, + allowed_screens=("ConfigKruxInstaller", self.name), + on_update=on_update, + ) + + # pylint: disable=unused-argument + def on_pre_enter(self, *args): + self.ids[f"{self.id}_grid"].clear_widgets() + + def on_ref_press(*args): if args[1] == "Proceed": main_screen = self.manager.get_screen("MainScreen") u = self.manager.get_screen("UnzipStableScreen") @@ -77,63 +108,22 @@ def _on_ref_press(*args): if args[1] == "Back": self.set_screen(name="MainScreen", direction="right") - setattr(VerifyStableZipScreen, f"on_ref_press_{self.id}", _on_ref_press) - - fn = partial(self.update, name=self.name, key="canvas") - Clock.schedule_once(fn) - - # pylint: disable=unused-argument - def update(self, *args, **kwargs): - """Update widget from other screens""" - name = str(kwargs.get("name")) - key = str(kwargs.get("key")) - value = kwargs.get("value") - self.update_screen( - name=name, - key=key, - value=value, - allowed_screens=("ConfigKruxInstaller", "VerifyStableZipScreen"), - on_update=None, - ) - - # pylint: disable=unused-argument - def on_pre_enter(self, *args): - self.ids[f"{self.id}_grid"].clear_widgets() verifying_msg = self.translate("Verifying integrity and authenticity") - - warning = Label( - text="".join( - [ - f"[size={self.SIZE_MM}sp]", - "[color=#efcc00]", - verifying_msg, - "[/color]", - "[/size]", - ] - ), - markup=True, - valign="center", - halign="left", - ) - warning.id = f"{self.id}_label" - self.ids[f"{self.id}_grid"].add_widget(warning) - self.ids[warning.id] = WeakProxy(warning) - self.ids[warning.id].bind( - on_ref_press=getattr(VerifyStableZipScreen, f"on_ref_press_{self.id}") + self.make_button( + row=0, + wid=f"{self.id}_label", + root_widget=f"{self.id}_grid", + text=f"[color=#efcc00]{verifying_msg}[/color]", + halign="justify", + on_press=None, + on_release=None, + on_ref_press=on_ref_press, ) # pylint: disable=unused-argument - def on_enter(self, *args): - assets_dir = VerifyStableZipScreen.get_destdir_assets() - main_screen = self.manager.get_screen("MainScreen") - - self.ids[f"{self.id}_label"].text = self.build_message_verify_sha256( - assets_dir=assets_dir, version=main_screen.version - ) - - self.ids[f"{self.id}_label"].text += self.build_message_verify_signature( - assets_dir=assets_dir, version=main_screen.version - ) + def on_enter(self, *args, **kwargs): + fn = partial(self.update, name=self.name, key="verify") + Clock.schedule_once(fn) def verify_sha256( self, assets_dir: str, version: str @@ -176,12 +166,6 @@ def build_message_verify_sha256(self, assets_dir: str, version: str) -> str: provided_msg = self.translate("provided hash from") hash_color = "" hash_msg = "" - - if sys.platform in ("linux", "win32"): - size = [self.SIZE_MP, self.SIZE_P, self.SIZE_PP] - else: - size = [self.SIZE_M, self.SIZE_MP, self.SIZE_P] - sha_0 = VerifyStableZipScreen.prettyfy_hash(hash_0) sha_1 = VerifyStableZipScreen.prettyfy_hash(hash_1) @@ -194,25 +178,18 @@ def build_message_verify_sha256(self, assets_dir: str, version: str) -> str: return "".join( [ - f"[size={size[0]}sp]", f"[u]{integrity_msg.upper()}[/u]: ", f"[b][color={hash_color}]{hash_msg}[/color][/b]", - "[/size]", "\n", "\n", - f"[size={size[1]}sp]", f"[b]{computed_msg} [color=#777777]{filepath}[/color][/b]", - "[/size]", "\n", - f"[size={size[1]}sp]{sha_0}[/size]", + sha_0, "\n", "\n", - f"[size={size[1]}sp]", f"[b]{provided_msg} [color=#777777]{filepath}.sha256.txt[/color][/b]", - "[/size]", - "\n", - f"[size={size[1]}sp]{sha_1}[/size]", "\n", + sha_1, "\n", "\n", ] @@ -250,11 +227,6 @@ def build_message_verify_signature(self, assets_dir: str, version: str) -> str: filepath = os.path.join(assets_dir, f"krux-{version}.zip") pempath = os.path.join(assets_dir, "selfcustody.pem") - if sys.platform in ("linux", "win32"): - size = [self.SIZE_MP, self.SIZE_P] - else: - size = [self.SIZE_M, self.SIZE_MP] - if checksig: sig_color = "#00FF00" res_msg = good_msg @@ -264,34 +236,27 @@ def build_message_verify_signature(self, assets_dir: str, version: str) -> str: return "".join( [ - f"[size={size[0]}sp]", f"[u]{authenticity_msg.upper()}[/u]: ", f"[b][color={sig_color}]{res_msg} {sig_msg}[/color][/b]", - "[/size]", - "\n", "\n", "\n", - f"[size={size[1]}sp]{installed_msg}[/size]", + installed_msg, "\n", - f"[size={size[1]}sp]{check_msg}:[/size]", + check_msg, "\n", "\n", - f"[size={size[1]}sp]", "[b]", f"openssl sha256< [color=#777777]{filepath}[/color] -binary | \\", "\n" f"openssl pkeyutl -verify -pubin -inkey [color=#777777]{pempath}[/color] \\", "\n", f"-sigfile [color=#777777]{filepath}.sig[/color]", - "[/size]", "[/b]", "\n", "\n", - f"[size={size[0]}sp]", f"[ref=Proceed][color=#00ff00][u]{proceed}[/u][/ref][/color]", " ", f"[ref=Back][color=#ff0000][u]{back}[/u][/ref][/color]", "[/b]", - "[/size]", ] ) diff --git a/src/app/screens/warning_already_downloaded_screen.py b/src/app/screens/warning_already_downloaded_screen.py index 377d2e1d..72d37103 100644 --- a/src/app/screens/warning_already_downloaded_screen.py +++ b/src/app/screens/warning_already_downloaded_screen.py @@ -21,7 +21,6 @@ """ about_screen.py """ -import sys from typing import Any from functools import partial from kivy.clock import Clock @@ -46,14 +45,7 @@ def __init__(self, **kwargs): root_widget=f"{self.id}_grid", ) - self.make_label( - wid=f"{self.id}_label", - text="", - root_widget=f"{self.id}_grid", - halign="justify", - ) - - def _on_ref_press(*args): + def on_ref_press(*args): if args[1] == "DownloadStableZipScreen": main_screen = self.manager.get_screen("MainScreen") download_screen = self.manager.get_screen("DownloadStableZipScreen") @@ -69,11 +61,16 @@ def _on_ref_press(*args): if args[1] == "VerifyStableZipScreen": self.set_screen(name="VerifyStableZipScreen", direction="left") - # When [ref] markup text is clicked, do a action like a button - setattr( - WarningAlreadyDownloadedScreen, f"on_ref_press_{self.id}", _on_ref_press + self.make_button( + row=0, + wid=f"{self.id}_label", + text="", + halign=None, + root_widget=f"{self.id}_grid", + on_press=None, + on_release=None, + on_ref_press=on_ref_press, ) - self.ids[f"{self.id}_label"].bind(on_ref_press=_on_ref_press) fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) @@ -82,35 +79,26 @@ def on_warning(self, key: str, value: Any): """Update a warning message on GUI""" if key == "version": warning_msg = self.translate("Assets already downloaded") - ask_proceed = self.translate( - "Do you want to proceed with the same file or do you want to download it again?" - ) + # ask_proceed = self.translate( + # "Do you want to proceed with the same file or do you want to download it again?" + # ) download_msg = self.translate("Download again") proceed_msg = self.translate("Proceed with current file") - if sys.platform in ("linux", "win32"): - size = [self.SIZE_M, self.SIZE_MP, self.SIZE_P] - - else: - size = [self.SIZE_MM, self.SIZE_MP, self.SIZE_MP] - self.ids[f"{self.id}_label"].text = "".join( [ - f"[size={size[0]}sp][b]{warning_msg}[/b][/size]", - "\n", - f"[size={size[2]}sp]* krux-{value}.zip[/size]", - "\n", - f"[size={size[2]}sp]* krux-{value}.zip.sha256.txt[/size]", + f"[color=#efcc00][b]{warning_msg}[/b][/color]", "\n", - f"[size={size[2]}sp]* krux-{value}.zip.sig[/size]", + f"* krux-{value}.zip", "\n", - f"[size={size[2]}sp]* selfcustody.pem[/size]", + f"* krux-{value}.zip.sha256.txt", "\n", + f"* krux-{value}.zip.sig", "\n", - f"[size={size[1]}sp]{ask_proceed}[/size]", + "* selfcustody.pem", "\n", "\n", - f"[size={size[0]}]" f"[color=#00ff00]", + "[color=#00ff00]", "[ref=DownloadStableZipScreen]", f"[u]{download_msg}[/u]", "[/ref]", @@ -121,7 +109,6 @@ def on_warning(self, key: str, value: Any): f"[u]{proceed_msg}[/u]", "[/ref]", "[/color]", - "[/size]", ] ) diff --git a/src/app/screens/warning_beta_screen.py b/src/app/screens/warning_beta_screen.py index 8f8b2400..e2b26dd9 100644 --- a/src/app/screens/warning_beta_screen.py +++ b/src/app/screens/warning_beta_screen.py @@ -39,11 +39,15 @@ def __init__(self, **kwargs): root_widget=f"{self.id}_grid", ) - self.make_label( + self.make_button( + row=0, wid=f"{self.id}_label", text=self.make_label_text(), + halign=None, root_widget=f"{self.id}_grid", - halign="justify", + on_press=None, + on_release=None, + on_ref_press=None, ) # START of on_press buttons @@ -55,6 +59,7 @@ def on_ref_press(*args): self.set_screen(name="SelectVersionScreen", direction="right") setattr(WarningBetaScreen, f"on_ref_press_{self.id}", on_ref_press) + self.ids[f"{self.id}_label"].halign = "justify" self.ids[f"{self.id}_label"].bind(on_ref_press=on_ref_press) fn = partial(self.update, name=self.name, key="canvas") @@ -99,14 +104,13 @@ def make_label_text(self): return "".join( [ - f"[size={self.SIZE_M}sp][color=#efcc00]{test_repo}[/color][/size]", + f"[color=#efcc00]{test_repo}[/color]", "\n", - f"[size={self.SIZE_MP}sp]{unsg_bin}[/size]", + unsg_bin, "\n", - f"[size={self.SIZE_MP}sp]{just_try}[/size]", + just_try, "\n", "\n", - f"[size={self.SIZE_MM}sp]", "[color=#00ff00]", f"[ref=MainScreen]{proceed}[/ref]", "[/color]", @@ -114,6 +118,5 @@ def make_label_text(self): "[color=#ff0000]", f"[ref=SelectVersion]{back}[/ref]", "[/color]", - "[/size]", ] ) diff --git a/src/app/screens/warning_wipe_screen.py b/src/app/screens/warning_wipe_screen.py index 488c5933..0c17b2b0 100644 --- a/src/app/screens/warning_wipe_screen.py +++ b/src/app/screens/warning_wipe_screen.py @@ -21,7 +21,6 @@ """ about_screen.py """ -import sys from functools import partial from kivy.clock import Clock from src.app.screens.base_screen import BaseScreen @@ -45,14 +44,7 @@ def __init__(self, **kwargs): root_widget=f"{self.id}_grid", ) - self.make_label( - wid=f"{self.id}_label", - text="", - root_widget=f"{self.id}_grid", - halign="justify", - ) - - def _on_ref_press(*args): + def on_ref_press(*args): if args[1] == "WipeScreen": partials = [] main_screen = self.manager.get_screen("MainScreen") @@ -84,16 +76,22 @@ def _on_ref_press(*args): if args[1] == "MainScreen": self.set_screen(name="MainScreen", direction="right") - # When [ref] markup text is clicked, do a action like a button - setattr(WarningWipeScreen, f"on_ref_press_{self.id}", _on_ref_press) - self.ids[f"{self.id}_label"].bind(on_ref_press=_on_ref_press) + self.make_button( + row=0, + wid=f"{self.id}_label", + text="", + halign=None, + root_widget=f"{self.id}_grid", + on_press=None, + on_release=None, + on_ref_press=on_ref_press, + ) fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) # pylint: disable=unused-argument - def on_enter(self, *args): - """Invoke make_label_text""" + def on_enter(self, *args, **kwargs): self.ids[f"{self.id}_label"].text = self.make_label_text() # pylint: disable=unused-argument @@ -134,22 +132,13 @@ def make_label_text(self): proceed = self.translate("Proceed") back = self.translate("Back") - if sys.platform in ("linux", "win32"): - sizes = [self.SIZE_MP, self.SIZE_P] - - else: - sizes = [self.SIZE_MM, self.SIZE_M] - return "".join( [ "[color=#EFCC00]", - f"[size={sizes[0]}]", full_wipe, - "[/size]", "[/color]", "\n", "\n", - f"[size={sizes[1]}]", f"{operation}:", "\n", f"* {erase}", @@ -157,10 +146,8 @@ def make_label_text(self): f"* {remove}", "\n", f"* {render}", - "[/size]", "\n", "\n", - f"[size={sizes[0]}]", "[color=#00FF00]", f"[ref=WipeScreen][u]{proceed}[/u][/ref]", "[/color]", @@ -168,6 +155,5 @@ def make_label_text(self): "[color=#FF0000]", f"[ref=MainScreen][u]{back}[/u][/ref]", "[/color]", - "[/size]", ] ) diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index 60ace97f..f39a0c12 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -21,7 +21,6 @@ """ wipe_screen.py """ -import sys import threading import traceback from functools import partial @@ -71,7 +70,7 @@ def on_data(*args, **kwargs): ) self.output.append(text) - if len(self.output) > 18: + if len(self.output) > 4: del self.output[:1] if "SPI Flash erased." in text: @@ -112,19 +111,26 @@ def on_ref_press(*args): root_widget=f"{self.id}_subgrid", ) - self.make_label( + self.make_button( + row=1, wid=f"{self.id}_progress", text="", - root_widget=f"{self.id}_subgrid", halign="center", + root_widget=f"{self.id}_subgrid", + on_press=None, + on_release=None, + on_ref_press=on_ref_press, ) - self.ids[f"{self.id}_progress"].bind(on_ref_press=on_ref_press) - self.make_label( + self.make_button( + row=2, wid=f"{self.id}_info", text="", root_widget=f"{self.id}_grid", halign="justify", + on_press=None, + on_release=None, + on_ref_press=on_ref_press, ) # pylint: disable=unused-argument @@ -138,12 +144,7 @@ def on_enter(self, *args): self.thread = threading.Thread(name=self.name, target=on_process) please = self.translate("PLEASE DO NOT UNPLUG YOUR DEVICE") - if sys.platform in ("linux", "win32"): - sizes = [self.SIZE_M, self.SIZE_PP] - else: - sizes = [self.SIZE_MM, self.SIZE_MP] - - self.ids[f"{self.id}_progress"].text = f"[size={sizes[0]}sp][b]{please}[/b]" + self.ids[f"{self.id}_progress"].text = please # if anything wrong happen, show it def hook(err): @@ -151,38 +152,9 @@ def hook(err): trace = traceback.format_exception( err.exc_type, err.exc_value, err.exc_traceback ) - msg = "".join(trace) + msg = "".join(trace[-2:]) self.error(msg) - - done = self.translate("DONE") - back = self.translate("Back") - _quit = self.translate("Quit") - - self.ids[f"{self.id}_progress"].text = "".join( - [ - f"[size={sizes[0]}]", - f"[color=#FF0000]{"Wipe failed" if not self.success else done}[/color]", - "[/size]", - "\n", - "\n", - f"[size={sizes[0]}]" "[color=#00FF00]", - f"[ref=Back][u]{back}[/u][/ref]", - "[/color]", - " ", - "[color=#EFCC00]", - f"[ref=Quit][u]{_quit}[/u][/ref]", - "[/color]", - "[/size]", - ] - ) - - self.ids[f"{self.id}_info"].text = "".join( - [ - f"[size={sizes[1]}]", - msg, - "[/size]", - ] - ) + self.redirect_exception(exception=RuntimeError(f"Wipe failed: {msg}")) # hook what happened threading.excepthook = hook diff --git a/src/i18n/pt_BR.UTF-8.json b/src/i18n/pt_BR.UTF-8.json index d5184211..c80ef4da 100644 --- a/src/i18n/pt_BR.UTF-8.json +++ b/src/i18n/pt_BR.UTF-8.json @@ -22,7 +22,7 @@ "Version": "Versão", "Device": "Dispositivo", "select a new one": "selecione um novo", - "Flash": "Flash o firmware", + "Flash": "Programar o firmware", "Wipe": "Limpar dispositivo", "Settings": "Configurações", "About": "Sobre", From 8fbc3eb851d780d2b7b1dce9f3638dd8e6e34cd9 Mon Sep 17 00:00:00 2001 From: qlrd Date: Mon, 16 Sep 2024 21:05:17 -0300 Subject: [PATCH 48/61] fixed font_size redefinition when window resizes on many screens --- e2e/test_000_base_screen.py | 5 +++++ e2e/test_016_unzip_stable_screen.py | 1 + src/app/screens/about_screen.py | 1 + .../screens/ask_permission_dialout_screen.py | 1 + src/app/screens/base_download_screen.py | 2 ++ src/app/screens/base_screen.py | 21 ++++++++++++------- src/app/screens/error_screen.py | 1 + src/app/screens/flash_screen.py | 4 +++- src/app/screens/greetings_screen.py | 2 +- src/app/screens/main_screen.py | 6 ++++++ src/app/screens/select_device_screen.py | 1 + src/app/screens/select_old_version_screen.py | 2 ++ src/app/screens/select_version_screen.py | 4 ++++ src/app/screens/unzip_stable_screen.py | 2 ++ src/app/screens/verify_stable_zip_screen.py | 1 + .../warning_already_downloaded_screen.py | 1 + src/app/screens/warning_beta_screen.py | 1 + src/app/screens/warning_wipe_screen.py | 1 + src/app/screens/wipe_screen.py | 4 +++- 19 files changed, 50 insertions(+), 11 deletions(-) diff --git a/e2e/test_000_base_screen.py b/e2e/test_000_base_screen.py index 6a870c32..70bdf3b8 100644 --- a/e2e/test_000_base_screen.py +++ b/e2e/test_000_base_screen.py @@ -276,6 +276,7 @@ def test_make_button(self, mock_get_locale): root_widget="mock_grid", text="Mocked button", halign=None, + font_factor=32, on_press=MagicMock(), on_release=MagicMock(), on_ref_press=MagicMock(), @@ -316,6 +317,7 @@ def test_clear_grid(self, mock_get_locale): root_widget="mock_grid", text="Mocked button", halign=None, + font_factor=32, on_press=MagicMock(), on_release=MagicMock(), on_ref_press=MagicMock(), @@ -346,6 +348,7 @@ def test_fail_update_screen_invalid_screen( root_widget="mock_grid", text="Mocked button", halign=None, + font_factor=32, on_press=MagicMock(), on_release=MagicMock(), on_ref_press=MagicMock(), @@ -373,6 +376,7 @@ def test_update_screen_locale(self, mock_get_locale): wid="mock_button", root_widget="mock_grid", text="Mocked button", + font_factor=32, halign=None, on_press=MagicMock(), on_release=MagicMock(), @@ -403,6 +407,7 @@ def test_update_screen_canvas(self, mock_rectangle, mock_color, mock_get_locale) wid="mock_button", root_widget="mock_grid", text="Mocked button", + font_factor=32, halign=None, on_press=MagicMock(), on_release=MagicMock(), diff --git a/e2e/test_016_unzip_stable_screen.py b/e2e/test_016_unzip_stable_screen.py index 204f83d5..36ca3697 100644 --- a/e2e/test_016_unzip_stable_screen.py +++ b/e2e/test_016_unzip_stable_screen.py @@ -171,6 +171,7 @@ def test_update_clear(self, mock_get_locale, mock_get_destdir_assets): text="Mock", row=0, halign=None, + font_factor=32, on_press=MagicMock(), on_release=MagicMock(), on_ref_press=MagicMock(), diff --git a/src/app/screens/about_screen.py b/src/app/screens/about_screen.py index e51e03ed..b6215d22 100644 --- a/src/app/screens/about_screen.py +++ b/src/app/screens/about_screen.py @@ -57,6 +57,7 @@ def on_ref_press(*args): wid=f"{self.id}_label", text="", root_widget=f"{self.id}_grid", + font_factor=24, halign=None, on_press=None, on_release=None, diff --git a/src/app/screens/ask_permission_dialout_screen.py b/src/app/screens/ask_permission_dialout_screen.py index c51b2fa9..22e3c94a 100644 --- a/src/app/screens/ask_permission_dialout_screen.py +++ b/src/app/screens/ask_permission_dialout_screen.py @@ -106,6 +106,7 @@ def on_ref_press(*args): wid=f"{self.id}_label", text="", root_widget=f"{self.id}_grid", + font_factor=32, halign="justify", on_press=None, on_release=None, diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index 6e8bd2fd..3ad522ad 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -50,6 +50,7 @@ def __init__(self, wid: str, name: str, **kwargs): root_widget=f"{self.id}_grid", halign=None, text="", + font_factor=18, on_press=None, on_release=None, on_ref_press=None, @@ -62,6 +63,7 @@ def __init__(self, wid: str, name: str, **kwargs): row=1, wid=f"{self.id}_info", root_widget=f"{self.id}_grid", + font_factor=52, halign=None, text="", on_press=None, diff --git a/src/app/screens/base_screen.py b/src/app/screens/base_screen.py index 9f32deb7..8d49fead 100644 --- a/src/app/screens/base_screen.py +++ b/src/app/screens/base_screen.py @@ -189,6 +189,7 @@ def make_button( text: str, row: int, halign: str | None, + font_factor: int | None, on_press: typing.Callable | None, on_release: typing.Callable | None, on_ref_press: typing.Callable | None, @@ -196,12 +197,13 @@ def make_button( """Create buttons in a dynamic way""" self.debug(f"button::{wid} row={row}") + # define how many rows we have to distribute them on screen total = self.ids[root_widget].rows btn = Button( text=text, markup=True, halign="center", - font_size=Window.size[0] // 25, + font_size=BaseScreen.get_half_diagonal_screen_size(font_factor), background_color=(0, 0, 0, 1), color=(1, 1, 1, 1), ) @@ -223,12 +225,21 @@ def make_button( btn.bind(on_ref_press=on_ref_press) setattr(self.__class__, f"on_ref_press_{wid}", on_ref_press) - btn.bind(size=BaseScreen.on_resize) + # define dynamically a resize event with same value of defined font + # pylint: disable=unused-argument + def on_resize(instance, value): + instance.font_size = BaseScreen.get_half_diagonal_screen_size(font_factor) + btn.bind(size=on_resize) + setattr(self.__class__, f"on_resize_{wid}", on_ref_press) + + # configure button dimensions and positions btn.x = 0 btn.y = (Window.size[1] / total) * row btn.width = Window.size[0] btn.height = Window.size[1] / total + + # register button self.ids[root_widget].add_widget(btn) self.ids[btn.id] = WeakProxy(btn) @@ -284,12 +295,6 @@ def get_half_diagonal_screen_size(factor: int): w_width, w_height = Window.size return int(sqrt((w_width**2 + w_height**2) / 2)) // factor - @staticmethod - # pylint: disable=unused-argument - def on_resize(instance, value): - """Redefine font size of a button when size changes""" - instance.font_size = BaseScreen.get_half_diagonal_screen_size(38) - @staticmethod def quit_app(): """Stop the kivy process""" diff --git a/src/app/screens/error_screen.py b/src/app/screens/error_screen.py index 32b61133..2d4f6d74 100644 --- a/src/app/screens/error_screen.py +++ b/src/app/screens/error_screen.py @@ -58,6 +58,7 @@ def on_ref_press(*args): wid=f"{self.id}_label", root_widget=f"{self.id}_grid", text="", + font_factor=48, halign="center", on_press=None, on_release=None, diff --git a/src/app/screens/flash_screen.py b/src/app/screens/flash_screen.py index 13c73cfa..384d4487 100644 --- a/src/app/screens/flash_screen.py +++ b/src/app/screens/flash_screen.py @@ -68,7 +68,7 @@ def on_data(*args, **kwargs): self.output.append("*") self.output.append("") - if len(self.output) > 4: + if len(self.output) > 18: del self.output[:1] self.ids[f"{self.id}_info"].text = "\n".join(self.output) @@ -144,6 +144,7 @@ def on_ref_press(*args): row=1, wid=f"{self.id}_progress", text="", + font_factor=32, root_widget=f"{self.id}_subgrid", halign="center", on_press=None, @@ -155,6 +156,7 @@ def on_ref_press(*args): row=2, wid=f"{self.id}_info", text="", + font_factor=72, root_widget=f"{self.id}_grid", halign="justify", on_press=None, diff --git a/src/app/screens/greetings_screen.py b/src/app/screens/greetings_screen.py index 7e02de8a..3ee23f53 100644 --- a/src/app/screens/greetings_screen.py +++ b/src/app/screens/greetings_screen.py @@ -30,7 +30,7 @@ if sys.platform.startswith("linux"): import distro - import grp + import grp # pylint: disable=import-error class GreetingsScreen(BaseScreen): diff --git a/src/app/screens/main_screen.py b/src/app/screens/main_screen.py index 6461e9bf..ac906b60 100644 --- a/src/app/screens/main_screen.py +++ b/src/app/screens/main_screen.py @@ -138,6 +138,7 @@ def on_release(instance): ] ), halign=None, + font_factor=28, on_press=on_press, on_release=on_release, on_ref_press=None, @@ -180,6 +181,7 @@ def on_release_select_device(instance): "[/color]", ] ), + font_factor=28, halign=None, on_press=getattr(MainScreen, "on_press_select_device"), on_release=getattr(MainScreen, "on_release_select_device"), @@ -283,6 +285,7 @@ def on_release_flash(instance): wid=wid, root_widget="main_screen_grid", text=f"[color=#333333]{self.translate("Flash")}[/color]", + font_factor=28, halign=None, on_press=getattr(MainScreen, "on_press_flash"), on_release=getattr(MainScreen, "on_release_flash"), @@ -316,6 +319,7 @@ def on_release_wipe(instance): wid=wid, root_widget="main_screen_grid", text=f"[color=#333333]{self.translate("Wipe")}[/color]", + font_factor=28, halign=None, on_press=getattr(MainScreen, "on_press_wipe"), on_release=getattr(MainScreen, "on_release_wipe"), @@ -343,6 +347,7 @@ def on_release_settings(instance): wid=wid, root_widget="main_screen_grid", text=self.translate("Settings"), + font_factor=28, halign=None, on_press=getattr(MainScreen, "on_press_settings"), on_release=getattr(MainScreen, "on_release_settings"), @@ -370,6 +375,7 @@ def on_release_about(instance): wid=wid, root_widget="main_screen_grid", text=self.translate("About"), + font_factor=28, halign=None, on_press=getattr(MainScreen, "on_press_about"), on_release=getattr(MainScreen, "on_release_about"), diff --git a/src/app/screens/select_device_screen.py b/src/app/screens/select_device_screen.py index cf7e4201..d325b8e4 100644 --- a/src/app/screens/select_device_screen.py +++ b/src/app/screens/select_device_screen.py @@ -69,6 +69,7 @@ def on_release(instance): wid=f"select_device_{device}", root_widget="select_device_screen_grid", text="", + font_factor=28, halign=None, on_press=on_press, on_release=on_release, diff --git a/src/app/screens/select_old_version_screen.py b/src/app/screens/select_old_version_screen.py index ccc1abd9..1cd0f969 100644 --- a/src/app/screens/select_old_version_screen.py +++ b/src/app/screens/select_old_version_screen.py @@ -69,6 +69,7 @@ def on_release(instance): wid=wid, root_widget="select_old_version_screen_grid", text=text, + font_factor=28, halign=None, on_press=on_press, on_release=on_release, @@ -95,6 +96,7 @@ def on_release(instance): wid="select_old_version_back", root_widget="select_old_version_screen_grid", text=text, + font_factor=28, halign=None, on_press=on_press, on_release=on_release, diff --git a/src/app/screens/select_version_screen.py b/src/app/screens/select_version_screen.py index 432f10a2..b9b1162c 100644 --- a/src/app/screens/select_version_screen.py +++ b/src/app/screens/select_version_screen.py @@ -79,6 +79,7 @@ def on_release(instance): wid=wid, root_widget="select_version_screen_grid", text=text, + font_factor=28, halign=None, on_press=on_press, on_release=on_release, @@ -120,6 +121,7 @@ def on_release(instance): wid=wid, root_widget="select_version_screen_grid", text=text, + font_factor=28, halign=None, on_press=on_press, on_release=on_release, @@ -144,6 +146,7 @@ def on_release(instance): wid=wid, root_widget="select_version_screen_grid", text=text, + font_factor=28, halign=None, on_press=on_press, on_release=on_release, @@ -168,6 +171,7 @@ def on_release(instance): wid=wid, root_widget="select_version_screen_grid", text=text, + font_factor=28, halign=None, on_press=on_press, on_release=on_release, diff --git a/src/app/screens/unzip_stable_screen.py b/src/app/screens/unzip_stable_screen.py index 9e28e959..5e36ce99 100644 --- a/src/app/screens/unzip_stable_screen.py +++ b/src/app/screens/unzip_stable_screen.py @@ -160,6 +160,7 @@ def on_release(instance): "[/color]", ] ), + font_factor=32, halign=None, on_press=on_press, on_release=on_release, @@ -248,6 +249,7 @@ def build_extract_to_airgap_button(self): "[/color]", ] ), + font_factor=32, halign=None, on_press=None, on_release=None, diff --git a/src/app/screens/verify_stable_zip_screen.py b/src/app/screens/verify_stable_zip_screen.py index e5ea6dbf..27a41d03 100644 --- a/src/app/screens/verify_stable_zip_screen.py +++ b/src/app/screens/verify_stable_zip_screen.py @@ -114,6 +114,7 @@ def on_ref_press(*args): wid=f"{self.id}_label", root_widget=f"{self.id}_grid", text=f"[color=#efcc00]{verifying_msg}[/color]", + font_factor=48, halign="justify", on_press=None, on_release=None, diff --git a/src/app/screens/warning_already_downloaded_screen.py b/src/app/screens/warning_already_downloaded_screen.py index 72d37103..bad67fa6 100644 --- a/src/app/screens/warning_already_downloaded_screen.py +++ b/src/app/screens/warning_already_downloaded_screen.py @@ -66,6 +66,7 @@ def on_ref_press(*args): wid=f"{self.id}_label", text="", halign=None, + font_factor=32, root_widget=f"{self.id}_grid", on_press=None, on_release=None, diff --git a/src/app/screens/warning_beta_screen.py b/src/app/screens/warning_beta_screen.py index e2b26dd9..6c4e4e36 100644 --- a/src/app/screens/warning_beta_screen.py +++ b/src/app/screens/warning_beta_screen.py @@ -43,6 +43,7 @@ def __init__(self, **kwargs): row=0, wid=f"{self.id}_label", text=self.make_label_text(), + font_factor=36, halign=None, root_widget=f"{self.id}_grid", on_press=None, diff --git a/src/app/screens/warning_wipe_screen.py b/src/app/screens/warning_wipe_screen.py index 0c17b2b0..44097ac5 100644 --- a/src/app/screens/warning_wipe_screen.py +++ b/src/app/screens/warning_wipe_screen.py @@ -80,6 +80,7 @@ def on_ref_press(*args): row=0, wid=f"{self.id}_label", text="", + font_factor=48, halign=None, root_widget=f"{self.id}_grid", on_press=None, diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index f39a0c12..6f0f1e33 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -70,7 +70,7 @@ def on_data(*args, **kwargs): ) self.output.append(text) - if len(self.output) > 4: + if len(self.output) > 18: del self.output[:1] if "SPI Flash erased." in text: @@ -116,6 +116,7 @@ def on_ref_press(*args): wid=f"{self.id}_progress", text="", halign="center", + font_factor=32, root_widget=f"{self.id}_subgrid", on_press=None, on_release=None, @@ -126,6 +127,7 @@ def on_ref_press(*args): row=2, wid=f"{self.id}_info", text="", + font_factor=72, root_widget=f"{self.id}_grid", halign="justify", on_press=None, From 84dc3476dc0832ca7bdc401015625458d6854caf Mon Sep 17 00:00:00 2001 From: qlrd Date: Mon, 16 Sep 2024 21:13:07 -0300 Subject: [PATCH 49/61] removed linux's input group from deb configuration --- .ci/create-deb.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.ci/create-deb.sh b/.ci/create-deb.sh index 9cf1e200..d3b8693c 100755 --- a/.ci/create-deb.sh +++ b/.ci/create-deb.sh @@ -160,15 +160,13 @@ echo " !!!WARNING!!!" echo " -------------" echo "" if [ -n "\$SUDO_USER" ] && [ "\$SUDO_USER" != "root" ]; then - echo "Adding user \$SUDO_USER to 'dialout' and 'input' groups to enable flash procedure..." + echo "Adding user \$SUDO_USER to 'dialout' group to enable flash procedure..." echo "You'll need to reboot your system to enable changes" usermod -a -G dialout \$SUDO_USER - usermod -a -G input \$SUDO_USER elif [ -n "\$USER" ] && [ "\$USER" != "root"]; then - echo "Adding user \$USER to 'dialout' and 'input' groups to enable flash procedure..." + echo "Adding user \$USER to 'dialout' group to enable flash procedure..." echo "You'll need to reboot your system to enable changes" usermod -a -G dialout \$USER - usermod -a -G input \$USER fi echo "" echo "" From aeb31c48d99f0ea1233f0ef2342d59847f01d4e9 Mon Sep 17 00:00:00 2001 From: qlrd Date: Tue, 17 Sep 2024 14:14:32 -0300 Subject: [PATCH 50/61] fixed update canvas on resize some screens --- e2e/test_000_base_screen.py | 11 +++++-- e2e/test_001_greetings_screen.py | 12 ++----- e2e/test_005_select_version_screen.py | 3 -- e2e/test_007_warning_beta_screen.py | 4 +-- e2e/test_009_base_download_screen.py | 8 +++-- ...t_015_warning_already_downloaded_screen.py | 4 +-- e2e/test_021_base_flash_screen.py | 1 + e2e/test_022_flash_screen.py | 18 ---------- src/app/screens/about_screen.py | 1 - .../screens/ask_permission_dialout_screen.py | 2 +- src/app/screens/base_download_screen.py | 5 ++- src/app/screens/base_flash_screen.py | 2 +- src/app/screens/base_screen.py | 33 +++++++++++++++---- src/app/screens/greetings_screen.py | 14 ++++---- src/app/screens/unzip_stable_screen.py | 4 +-- src/app/screens/verify_stable_zip_screen.py | 2 +- .../warning_already_downloaded_screen.py | 2 +- src/app/screens/warning_beta_screen.py | 24 +++++++------- src/app/screens/warning_wipe_screen.py | 2 +- 19 files changed, 74 insertions(+), 78 deletions(-) diff --git a/e2e/test_000_base_screen.py b/e2e/test_000_base_screen.py index 70bdf3b8..04036149 100644 --- a/e2e/test_000_base_screen.py +++ b/e2e/test_000_base_screen.py @@ -213,8 +213,8 @@ def test_set_screen(self, mock_get_locale): def test_make_grid(self, mock_get_locale): screen_0 = BaseScreen(wid="mock", name="Mock") screen_0.make_grid(wid="mock_grid", rows=1) + setattr(screen_0, "update", MagicMock()) self.render(screen_0) - EventLoop.ensure_window() window = EventLoop.window screen = window.children[0] @@ -231,8 +231,8 @@ def test_make_subgrid(self, mock_get_locale): screen = BaseScreen(wid="mock", name="Mock") screen.make_grid(wid="mock_grid", rows=1) screen.make_subgrid(wid="mock_subgrid", rows=1, root_widget="mock_grid") + setattr(screen, "update", MagicMock()) self.render(screen) - EventLoop.ensure_window() self.assertTrue("mock_grid" in screen.ids) @@ -253,6 +253,7 @@ def test_make_label(self, mock_get_locale): halign="center", text="mock", ) + setattr(screen, "update", MagicMock()) self.render(screen) EventLoop.ensure_window() @@ -281,6 +282,7 @@ def test_make_button(self, mock_get_locale): on_release=MagicMock(), on_ref_press=MagicMock(), ) + setattr(screen_0, "update", MagicMock()) self.render(screen_0) EventLoop.ensure_window() @@ -322,6 +324,7 @@ def test_clear_grid(self, mock_get_locale): on_release=MagicMock(), on_ref_press=MagicMock(), ) + setattr(screen_0, "update", MagicMock()) self.render(screen_0) EventLoop.ensure_window() @@ -353,6 +356,8 @@ def test_fail_update_screen_invalid_screen( on_release=MagicMock(), on_ref_press=MagicMock(), ) + setattr(screen, "update", MagicMock()) + self.render(screen) screen.update_screen( name="NoMockedScreen", @@ -382,6 +387,7 @@ def test_update_screen_locale(self, mock_get_locale): on_release=MagicMock(), on_ref_press=MagicMock(), ) + setattr(screen, "update", MagicMock()) self.render(screen) self.assertEqual(screen.locale, "en_US.UTF-8") @@ -413,6 +419,7 @@ def test_update_screen_canvas(self, mock_rectangle, mock_color, mock_get_locale) on_release=MagicMock(), on_ref_press=MagicMock(), ) + setattr(screen, "update", MagicMock()) self.render(screen) screen.update_screen( name="MockedScreen", diff --git a/e2e/test_001_greetings_screen.py b/e2e/test_001_greetings_screen.py index d86ae950..ea018d90 100644 --- a/e2e/test_001_greetings_screen.py +++ b/e2e/test_001_greetings_screen.py @@ -50,10 +50,8 @@ def test_on_enter(self, mock_schedule_once, mock_partial, mock_get_locale): EventLoop.ensure_window() mock_get_locale.assert_called() - mock_partial.assert_called_once_with( - screen.update, name=screen.name, key="canvas" - ) - mock_schedule_once.assert_called_once_with(mock_partial(), 0) + mock_partial.assert_called() + mock_schedule_once.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( @@ -78,12 +76,8 @@ def test_update_locale(self, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.greetings_screen.partial") - @patch("src.app.screens.greetings_screen.Clock.schedule_once") def test_update_canvas( self, - mock_schedule_once, - mock_partial, mock_get_locale, ): screen = GreetingsScreen() @@ -97,5 +91,3 @@ def test_update_canvas( # patch assertions mock_get_locale.assert_called_once() - mock_partial.assert_called() - mock_schedule_once.assert_called() diff --git a/e2e/test_005_select_version_screen.py b/e2e/test_005_select_version_screen.py index 78b15a26..99137c0d 100644 --- a/e2e/test_005_select_version_screen.py +++ b/e2e/test_005_select_version_screen.py @@ -236,10 +236,8 @@ def test_on_fetch_releases( @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.base_screen.BaseScreen.update_screen") def test_on_update( self, - mock_update_screen, mock_get_locale, ): screen = SelectVersionScreen() @@ -248,4 +246,3 @@ def test_on_update( screen.update(name=screen.name, key="locale", value="en_US") mock_get_locale.assert_called_once() - mock_update_screen.assert_called_once() diff --git a/e2e/test_007_warning_beta_screen.py b/e2e/test_007_warning_beta_screen.py index 56a20d2b..dbf18bd6 100644 --- a/e2e/test_007_warning_beta_screen.py +++ b/e2e/test_007_warning_beta_screen.py @@ -76,7 +76,7 @@ def test_on_ref_press_proceed(self, mock_set_screen, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - action = getattr(screen, "on_ref_press_warning_beta_screen") + action = getattr(screen, "on_ref_press_warning_beta_screen_label") action("MainScreen") mock_set_screen.assert_called_once_with(name="MainScreen", direction="right") @@ -94,7 +94,7 @@ def test_on_ref_press_back(self, mock_set_screen, mock_get_locale): # get your Window instance safely EventLoop.ensure_window() - action = getattr(screen, "on_ref_press_warning_beta_screen") + action = getattr(screen, "on_ref_press_warning_beta_screen_label") action("SelectVersion") mock_set_screen.assert_called_once_with( diff --git a/e2e/test_009_base_download_screen.py b/e2e/test_009_base_download_screen.py index 1bb63d07..d42fab1c 100644 --- a/e2e/test_009_base_download_screen.py +++ b/e2e/test_009_base_download_screen.py @@ -30,6 +30,7 @@ def test_init( ): screen = BaseDownloadScreen(wid="mock_screen", name="MockScreen") screen.to_screen = "AnotherMockScreen" + setattr(screen, "update", MagicMock()) self.render(screen) # get your Window instance safely @@ -83,6 +84,7 @@ def test_set_thread(self, mock_get_locale): screen = BaseDownloadScreen(wid="mock_screen", name="MockScreen") screen.to_screen = "AnotherMockScreen" screen.thread = MagicMock(name="mock", target=mock_target) + setattr(screen, "update", MagicMock()) self.render(screen) # get your Window instance safely @@ -100,6 +102,7 @@ def test_set_thread(self, mock_get_locale): ) def test_on_pre_enter(self, mock_get_locale): screen = BaseDownloadScreen(wid="mock_screen", name="MockScreen") + setattr(screen, "update", MagicMock()) self.render(screen) # get your Window instance safely @@ -131,6 +134,7 @@ def test_fail_on_enter(self, mock_redirect_exception, mock_get_locale): screen = BaseDownloadScreen(wid="mock_screen", name="MockScreen") screen.to_screen = "AnotherMockScreen" screen.downloader = None + setattr(screen, "update", MagicMock()) self.render(screen) # get your Window instance safely @@ -200,7 +204,7 @@ def test_update_download_screen_version(self, mock_get_locale): screen = BaseDownloadScreen(wid="mock_screen", name="MockScreen") build_downloader = MagicMock() setattr(screen, "build_downloader", build_downloader) - + setattr(screen, "update", MagicMock()) self.render(screen) # get your Window instance safely @@ -220,7 +224,7 @@ def test_update_download_screen_progress(self, mock_get_locale): screen = BaseDownloadScreen(wid="mock_screen", name="MockScreen") on_download_progress = MagicMock() setattr(screen, "on_download_progress", on_download_progress) - + setattr(screen, "update", MagicMock()) self.render(screen) # get your Window instance safely diff --git a/e2e/test_015_warning_already_downloaded_screen.py b/e2e/test_015_warning_already_downloaded_screen.py index b1186105..cd6864b9 100644 --- a/e2e/test_015_warning_already_downloaded_screen.py +++ b/e2e/test_015_warning_already_downloaded_screen.py @@ -160,9 +160,7 @@ def test_on_press_donwload_button( ), ] ) - mock_schedule_once.assert_has_calls( - [call(mock_partial(), 0), call(mock_partial(), 0)] - ) + mock_schedule_once.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( diff --git a/e2e/test_021_base_flash_screen.py b/e2e/test_021_base_flash_screen.py index 4015f7c9..c82525a2 100644 --- a/e2e/test_021_base_flash_screen.py +++ b/e2e/test_021_base_flash_screen.py @@ -16,6 +16,7 @@ def teardown_class(cls): ) def test_init(self, mock_get_locale): screen = BaseFlashScreen(wid="mock_screen", name="MockScreen") + setattr(screen, "update", MagicMock()) self.render(screen) # get your Window instance safely diff --git a/e2e/test_022_flash_screen.py b/e2e/test_022_flash_screen.py index f3a911a1..5749ac9a 100644 --- a/e2e/test_022_flash_screen.py +++ b/e2e/test_022_flash_screen.py @@ -42,24 +42,6 @@ def test_init(self, mock_schedule_once, mock_partial, mock_get_locale): ) mock_schedule_once.assert_has_calls([call(mock_partial(), 0)], any_order=True) - @patch.object(EventLoopBase, "ensure_window", lambda x: None) - @patch( - "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" - ) - @patch("src.app.screens.base_screen.BaseScreen.redirect_exception") - def test_fail_update_wrong_name(self, mock_redirect_exception, mock_get_locale): - screen = FlashScreen() - self.render(screen) - - # get your Window instance safely - EventLoop.ensure_window() - - screen.update(name="MockScreen") - - # patch assertions - mock_get_locale.assert_called() - mock_redirect_exception.assert_called_once() - @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" diff --git a/src/app/screens/about_screen.py b/src/app/screens/about_screen.py index b6215d22..750fc7c9 100644 --- a/src/app/screens/about_screen.py +++ b/src/app/screens/about_screen.py @@ -63,7 +63,6 @@ def on_ref_press(*args): on_release=None, on_ref_press=on_ref_press, ) - self.ids[f"{self.id}_label"].halign = "justify" fns = [ diff --git a/src/app/screens/ask_permission_dialout_screen.py b/src/app/screens/ask_permission_dialout_screen.py index 22e3c94a..9066c457 100644 --- a/src/app/screens/ask_permission_dialout_screen.py +++ b/src/app/screens/ask_permission_dialout_screen.py @@ -45,7 +45,7 @@ def __init__(self, **kwargs): self.distro = "" # Build grid where buttons will be placed - self.make_grid(wid=f"{self.id}_grid", rows=1) + self.make_grid(wid=f"{self.id}_grid", rows=1, resize_canvas=True) # These variables will setup the inclusion # in dialout group, if necessary diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index 3ad522ad..a13371f5 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -34,7 +34,7 @@ class BaseDownloadScreen(BaseScreen): def __init__(self, wid: str, name: str, **kwargs): super().__init__(wid=wid, name=name, **kwargs) - self.make_grid(wid=f"{self.id}_grid", rows=2) + self.make_grid(wid=f"{self.id}_grid", rows=2, resize_screen=True) self._downloader = None self._thread = None @@ -42,8 +42,6 @@ def __init__(self, wid: str, name: str, **kwargs): self.version = None self._to_screen = "" - # progress label, show a "Connecting" - # before start the download to make self.make_button( row=0, wid=f"{self.id}_progress", @@ -59,6 +57,7 @@ def __init__(self, wid: str, name: str, **kwargs): # information label # it has data about url # and downloaded paths + # pylint: disable=unused-argument self.make_button( row=1, wid=f"{self.id}_info", diff --git a/src/app/screens/base_flash_screen.py b/src/app/screens/base_flash_screen.py index 6a39451c..86c21187 100644 --- a/src/app/screens/base_flash_screen.py +++ b/src/app/screens/base_flash_screen.py @@ -33,7 +33,7 @@ class BaseFlashScreen(BaseScreen): def __init__(self, wid: str, name: str, **kwargs): super().__init__(wid=wid, name=name, **kwargs) - self.make_grid(wid=f"{self.id}_grid", rows=2) + self.make_grid(wid=f"{self.id}_grid", rows=2, resize_canvas=True) self._firmware = None self._baudrate = None self._thread = None diff --git a/src/app/screens/base_screen.py b/src/app/screens/base_screen.py index 8d49fead..8137054b 100644 --- a/src/app/screens/base_screen.py +++ b/src/app/screens/base_screen.py @@ -115,6 +115,11 @@ def locale(self, value: str): self.debug(f"locale = {value}") self._locale = value + # pylint: disable=unused-argument + def update(self, *args, **kwargs): + """Function to be implemented on classes""" + pass # pylint: disable=unnecessary-pass + def translate(self, key: str) -> str: """Translate some message as key""" msg = T(key, locale=self.locale, module=self.id) @@ -135,12 +140,27 @@ def set_screen(self, name: str, direction: typing.Literal["left", "right"]): self.manager.transition.direction = direction self.manager.current = name - def make_grid(self, wid: str, rows: int): + def make_grid(self, wid: str, rows: int, **kwargs): """Build grid where buttons will be placed""" if wid not in self.ids: + self.debug(f"Building GridLayout::{wid}") grid = GridLayout(cols=1, rows=rows) grid.id = wid + + # define a default resize event + # with same value of defined font + resize_canvas = kwargs.get("resize_canvas") + + if resize_canvas: + # pylint: disable=unused-argument + def on_size(instance, value): + update = getattr(self, "update") + fn = partial(update, name=self.name, key="canvas") + Clock.schedule_once(fn, 0) + + grid.bind(size=on_size) + self.add_widget(grid) self.ids[wid] = WeakProxy(grid) else: @@ -225,13 +245,14 @@ def make_button( btn.bind(on_ref_press=on_ref_press) setattr(self.__class__, f"on_ref_press_{wid}", on_ref_press) - # define dynamically a resize event with same value of defined font + # define a default resize event + # with same value of defined font # pylint: disable=unused-argument - def on_resize(instance, value): + def on_size(instance, value): instance.font_size = BaseScreen.get_half_diagonal_screen_size(font_factor) - btn.bind(size=on_resize) - setattr(self.__class__, f"on_resize_{wid}", on_ref_press) + btn.bind(size=on_size) + setattr(self.__class__, f"on_resize_{wid}", on_size) # configure button dimensions and positions btn.x = 0 @@ -284,7 +305,7 @@ def update_screen( if key == "canvas": with self.canvas.before: Color(0, 0, 0, 1) - Rectangle(size=(Window.width, Window.height)) + Rectangle(size=(Window.width + 1, Window.height + 1)) if on_update is not None: on_update() diff --git a/src/app/screens/greetings_screen.py b/src/app/screens/greetings_screen.py index 3ee23f53..f47ade79 100644 --- a/src/app/screens/greetings_screen.py +++ b/src/app/screens/greetings_screen.py @@ -44,7 +44,7 @@ def __init__(self, **kwargs): ) # Build grid where buttons will be placed - self.make_grid(wid=f"{self.id}_grid", rows=1) + self.make_grid(wid=f"{self.id}_grid", rows=1, resize_canvas=True) # Build logo self.make_image( @@ -59,8 +59,10 @@ def on_enter(self, *args): redirect to CheckPermissionsScreen and then to MainScreen. Win32 and Mac will be redirect to MainScreen. """ - fn = partial(self.update, name=self.name, key="canvas") - Clock.schedule_once(fn, 0) + fn_0 = partial(self.update, name=self.name, key="canvas") + fn_1 = partial(self.update, name=self.name, key="check-permission-screen") + Clock.schedule_once(fn_0, 0) + Clock.schedule_once(fn_1, 2.1) # pylint: disable=unused-argument def update(self, *args, **kwargs): @@ -75,10 +77,6 @@ def update(self, *args, **kwargs): value = kwargs.get("value") def on_update(): - if key == "canvas": - fn = partial(self.update, name=self.name, key="check-permission-screen") - Clock.schedule_once(fn, 2.1) - if key == "check-permission-screen": self.check_permissions_for_dialout_group() @@ -90,7 +88,7 @@ def on_update(): name=name, key=key, value=value, - allowed_screens=("KruxInstallerApp", "GreetingsScreen"), + allowed_screens=("KruxInstallerApp", self.name), on_update=getattr(GreetingsScreen, "on_update"), ) diff --git a/src/app/screens/unzip_stable_screen.py b/src/app/screens/unzip_stable_screen.py index 5e36ce99..42d2972c 100644 --- a/src/app/screens/unzip_stable_screen.py +++ b/src/app/screens/unzip_stable_screen.py @@ -160,7 +160,7 @@ def on_release(instance): "[/color]", ] ), - font_factor=32, + font_factor=42, halign=None, on_press=on_press, on_release=on_release, @@ -249,7 +249,7 @@ def build_extract_to_airgap_button(self): "[/color]", ] ), - font_factor=32, + font_factor=42, halign=None, on_press=None, on_release=None, diff --git a/src/app/screens/verify_stable_zip_screen.py b/src/app/screens/verify_stable_zip_screen.py index 27a41d03..951ce268 100644 --- a/src/app/screens/verify_stable_zip_screen.py +++ b/src/app/screens/verify_stable_zip_screen.py @@ -41,7 +41,7 @@ def __init__(self, **kwargs): wid="verify_stable_zip_screen", name="VerifyStableZipScreen", **kwargs ) self.success = False - self.make_grid(wid=f"{self.id}_grid", rows=1) + self.make_grid(wid=f"{self.id}_grid", rows=1, resize_screen=True) fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn) diff --git a/src/app/screens/warning_already_downloaded_screen.py b/src/app/screens/warning_already_downloaded_screen.py index bad67fa6..fac0eb46 100644 --- a/src/app/screens/warning_already_downloaded_screen.py +++ b/src/app/screens/warning_already_downloaded_screen.py @@ -37,7 +37,7 @@ def __init__(self, **kwargs): **kwargs, ) - self.make_grid(wid=f"{self.id}_grid", rows=2) + self.make_grid(wid=f"{self.id}_grid", rows=2, resize_canvas=True) self.make_image( wid=f"{self.id}_loader", diff --git a/src/app/screens/warning_beta_screen.py b/src/app/screens/warning_beta_screen.py index 6c4e4e36..7b9fb2b1 100644 --- a/src/app/screens/warning_beta_screen.py +++ b/src/app/screens/warning_beta_screen.py @@ -31,7 +31,7 @@ class WarningBetaScreen(BaseScreen): def __init__(self, **kwargs): super().__init__(wid="warning_beta_screen", name="WarningBetaScreen", **kwargs) - self.make_grid(wid="warning_beta_screen_grid", rows=2) + self.make_grid(wid="warning_beta_screen_grid", rows=2, resize_canvas=True) self.make_image( wid=f"{self.id}_warn", @@ -39,6 +39,14 @@ def __init__(self, **kwargs): root_widget=f"{self.id}_grid", ) + # START of on_press buttons + def on_ref_press(*args): + if args[1] == "MainScreen": + self.set_screen(name="MainScreen", direction="right") + + if args[1] == "SelectVersion": + self.set_screen(name="SelectVersionScreen", direction="right") + self.make_button( row=0, wid=f"{self.id}_label", @@ -48,21 +56,11 @@ def __init__(self, **kwargs): root_widget=f"{self.id}_grid", on_press=None, on_release=None, - on_ref_press=None, + on_ref_press=on_ref_press, ) - - # START of on_press buttons - def on_ref_press(*args): - if args[1] == "MainScreen": - self.set_screen(name="MainScreen", direction="right") - - if args[1] == "SelectVersion": - self.set_screen(name="SelectVersionScreen", direction="right") - - setattr(WarningBetaScreen, f"on_ref_press_{self.id}", on_ref_press) self.ids[f"{self.id}_label"].halign = "justify" - self.ids[f"{self.id}_label"].bind(on_ref_press=on_ref_press) + # load canvas fn = partial(self.update, name=self.name, key="canvas") Clock.schedule_once(fn, 0) diff --git a/src/app/screens/warning_wipe_screen.py b/src/app/screens/warning_wipe_screen.py index 44097ac5..ad929056 100644 --- a/src/app/screens/warning_wipe_screen.py +++ b/src/app/screens/warning_wipe_screen.py @@ -36,7 +36,7 @@ def __init__(self, **kwargs): **kwargs, ) - self.make_grid(wid=f"{self.id}_grid", rows=2) + self.make_grid(wid=f"{self.id}_grid", rows=2, resize_canvas=True) self.make_image( wid=f"{self.id}_warn", From 7961ac8102428964fe0bd5c8b810a5a9e224f928 Mon Sep 17 00:00:00 2001 From: qlrd Date: Wed, 18 Sep 2024 09:57:30 -0300 Subject: [PATCH 51/61] fixed buggy canvas on download screens changed the max lines of kboot console on wipe/flash screen --- e2e/test_010_download_stable_zip_screen.py | 8 ++------ ...st_011_download_stable_zip_sha256_screen.py | 8 ++------ src/app/screens/base_download_screen.py | 18 +++++++++++++++++- src/app/screens/flash_screen.py | 2 +- src/app/screens/wipe_screen.py | 2 +- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/e2e/test_010_download_stable_zip_screen.py b/e2e/test_010_download_stable_zip_screen.py index 32ae03d7..24d8edb8 100644 --- a/e2e/test_010_download_stable_zip_screen.py +++ b/e2e/test_010_download_stable_zip_screen.py @@ -253,9 +253,7 @@ def test_on_progress( ), ] ) - mock_schedule_once.assert_has_calls( - [call(mock_partial(), 0), call(mock_partial(), 0)] - ) + mock_schedule_once.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( @@ -314,9 +312,7 @@ def test_on_trigger( ), ] ) - mock_schedule_once.assert_has_calls( - [call(mock_partial(), 0), call(mock_partial(), 0)] - ) + mock_schedule_once.assert_called() mock_set_screen.assert_called_once_with( name="DownloadStableZipSha256Screen", direction="left" ) diff --git a/e2e/test_011_download_stable_zip_sha256_screen.py b/e2e/test_011_download_stable_zip_sha256_screen.py index f0ab9fc9..e9c0678d 100644 --- a/e2e/test_011_download_stable_zip_sha256_screen.py +++ b/e2e/test_011_download_stable_zip_sha256_screen.py @@ -199,9 +199,7 @@ def test_on_progress( ] ) - mock_schedule_once.assert_has_calls( - [call(mock_partial(), 0), call(mock_partial(), 0)] - ) + mock_schedule_once.assert_called() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( @@ -322,9 +320,7 @@ def test_on_trigger( ), ] ) - mock_schedule_once.assert_has_calls( - [call(mock_partial(), 0), call(mock_partial(), 0)] - ) + mock_schedule_once.assert_called() mock_set_screen.assert_called_once_with( name="DownloadStableZipSigScreen", direction="left" ) diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index a13371f5..a9dfbc42 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -34,7 +34,7 @@ class BaseDownloadScreen(BaseScreen): def __init__(self, wid: str, name: str, **kwargs): super().__init__(wid=wid, name=name, **kwargs) - self.make_grid(wid=f"{self.id}_grid", rows=2, resize_screen=True) + self.make_grid(wid=f"{self.id}_grid", rows=2) self._downloader = None self._thread = None @@ -54,6 +54,22 @@ def __init__(self, wid: str, name: str, **kwargs): on_ref_press=None, ) + # A little ugly hacky way to join + # the methods: (1) resize the font; + # (2) resize canvas. This is needed because + # when more than one buttons are used, the + # canvas wasnt properly updated. + # the bind method is needed only in one + # of the buttons + # pylint: disable=unused-argument + def on_resize(instance, value): + instance.font_size = BaseScreen.get_half_diagonal_screen_size(18) + update = getattr(self, "update") + fn = partial(update, name=self.name, key="canvas") + Clock.schedule_once(fn, 0) + + self.ids[f"{self.id}_progress"].bind(size=on_resize) + # information label # it has data about url # and downloaded paths diff --git a/src/app/screens/flash_screen.py b/src/app/screens/flash_screen.py index 384d4487..28413ae8 100644 --- a/src/app/screens/flash_screen.py +++ b/src/app/screens/flash_screen.py @@ -68,7 +68,7 @@ def on_data(*args, **kwargs): self.output.append("*") self.output.append("") - if len(self.output) > 18: + if len(self.output) > 10: del self.output[:1] self.ids[f"{self.id}_info"].text = "\n".join(self.output) diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index 6f0f1e33..332fb329 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -70,7 +70,7 @@ def on_data(*args, **kwargs): ) self.output.append(text) - if len(self.output) > 18: + if len(self.output) > 10: del self.output[:1] if "SPI Flash erased." in text: From 3a173ce2141cec47575a8f35a9d994305daf3783 Mon Sep 17 00:00:00 2001 From: qlrd Date: Wed, 18 Sep 2024 15:37:33 -0300 Subject: [PATCH 52/61] fixing desktop's icon path for debian-based OS --- .ci/create-deb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/create-deb.sh b/.ci/create-deb.sh index d3b8693c..3d5c9000 100755 --- a/.ci/create-deb.sh +++ b/.ci/create-deb.sh @@ -187,7 +187,7 @@ Type=Application Terminal=false Exec=/usr/local/bin/${app_name} Name=${app_name} -Icon=/usr/share/icons/highcolor/512x512/apps/${app_name}.png +Icon=/usr/share/icons/hicolor/512x512/apps/${app_name}.png EOF echo "" From 7ee3d79ca49f60697ba27dc921192062d877a74b Mon Sep 17 00:00:00 2001 From: qlrd Date: Thu, 19 Sep 2024 11:48:56 -0300 Subject: [PATCH 53/61] fixed some malformed strings that cause errors when build with py3.10 --- e2e/test_002_ask_permission_dialout_screen.py | 2 -- e2e/test_009_base_download_screen.py | 4 ---- e2e/test_019_config_krux_installer.py | 21 ++++++++++--------- pyproject.toml | 3 +++ .../screens/ask_permission_dialout_screen.py | 14 +++---------- src/app/screens/base_download_screen.py | 13 ++---------- src/app/screens/base_screen.py | 19 +++-------------- src/app/screens/download_beta_screen.py | 3 ++- .../download_stable_zip_sha256_screen.py | 2 -- .../screens/download_stable_zip_sig_screen.py | 2 -- src/app/screens/main_screen.py | 15 ++++++++----- src/app/screens/wipe_screen.py | 1 + 12 files changed, 35 insertions(+), 64 deletions(-) diff --git a/e2e/test_002_ask_permission_dialout_screen.py b/e2e/test_002_ask_permission_dialout_screen.py index 5be8e5dc..71f4b61f 100644 --- a/e2e/test_002_ask_permission_dialout_screen.py +++ b/e2e/test_002_ask_permission_dialout_screen.py @@ -289,14 +289,12 @@ def test_on_permission_created(self, mock_get_locale): text = "".join( [ - f"[size={screen.SIZE_M}sp]", "You may need to logout (or even reboot)", "\n", "and back in for the new group to take effect.", "\n", "\n", "Do not worry, this message won't appear again.", - "[/size]", ] ) diff --git a/e2e/test_009_base_download_screen.py b/e2e/test_009_base_download_screen.py index d42fab1c..0bcac525 100644 --- a/e2e/test_009_base_download_screen.py +++ b/e2e/test_009_base_download_screen.py @@ -112,11 +112,7 @@ def test_on_pre_enter(self, mock_get_locale): screen.on_pre_enter() text = "".join( [ - f"[size={screen.SIZE_G}]", "Connecting...", - "[/size]", - "[color=#efcc00]", - "[/color]", ] ) diff --git a/e2e/test_019_config_krux_installer.py b/e2e/test_019_config_krux_installer.py index 70943eda..5b828973 100644 --- a/e2e/test_019_config_krux_installer.py +++ b/e2e/test_019_config_krux_installer.py @@ -390,6 +390,7 @@ def test_build_settings(self): app = ConfigKruxInstaller() app.build_settings(settings) + utf = ".UTF-8" if sys.platform in ("linux", "darwin") else "" json_data = [ { "type": "path", @@ -412,16 +413,16 @@ def test_build_settings(self): "section": "locale", "key": "lang", "options": [ - f"af_ZA{".UTF-8" if sys.platform in ("linux", "darwin") else ""}", - f"en_US{".UTF-8" if sys.platform in ("linux", "darwin") else ""}", - f"es_ES{".UTF-8" if sys.platform in ("linux", "darwin") else ""}", - f"fr_FR{".UTF-8" if sys.platform in ("linux", "darwin") else ""}", - f"it_IT{".UTF-8" if sys.platform in ("linux", "darwin") else ""}", - f"ko_KR{".UTF-8" if sys.platform in ("linux", "darwin") else ""}", - f"nl_NL{".UTF-8" if sys.platform in ("linux", "darwin") else ""}", - f"pt_BR{".UTF-8" if sys.platform in ("linux", "darwin") else ""}", - f"ru_RU{".UTF-8" if sys.platform in ("linux", "darwin") else ""}", - f"zh_CN{".UTF-8" if sys.platform in ("linux", "darwin") else ""}", + f"af_ZA{utf}", + f"en_US{utf}", + f"es_ES{utf}", + f"fr_FR{utf}", + f"it_IT{utf}", + f"ko_KR{utf}", + f"nl_NL{utf}", + f"pt_BR{utf}", + f"ru_RU{utf}", + f"zh_CN{utf}", ], }, ] diff --git a/pyproject.toml b/pyproject.toml index d879ff4e..1ce178ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,6 @@ +[virtualenvs] +prefer-active-python = true + [tool.poetry] name = "krux-installer" version = "0.0.20-alpha-2" diff --git a/src/app/screens/ask_permission_dialout_screen.py b/src/app/screens/ask_permission_dialout_screen.py index 9066c457..2b129969 100644 --- a/src/app/screens/ask_permission_dialout_screen.py +++ b/src/app/screens/ask_permission_dialout_screen.py @@ -61,16 +61,7 @@ def on_permission_created(output: str): ) self.ids[f"{self.id}_label"].text = "".join( - [ - f"[size={self.SIZE_M}sp]", - logout_msg, - "\n", - f"{backin_msg}.", - "\n", - "\n", - f"{not_worry_msg}.", - "[/size]", - ] + [logout_msg, "\n", f"{backin_msg}.", "\n", "\n", f"{not_worry_msg}."] ) setattr( @@ -166,6 +157,7 @@ def show_warning(self): ) exec_msg = self.translate("to execute the following command") + command_list_bins = " ".join(self._bin_args or []) self.ids[f"{self.id}_label"].text = "".join( [ f"[color=#efcc00]{warn_msg}[/color]", @@ -179,7 +171,7 @@ def show_warning(self): f"{exec_msg}:", "\n", "[color=#00ff00]", - f"{self._bin} {" ".join(self._bin_args or [])} {self.group} {self.user}", + f"{self._bin} {command_list_bins} {self.group} {self.user}", "[/color]", "\n", "\n", diff --git a/src/app/screens/base_download_screen.py b/src/app/screens/base_download_screen.py index a9dfbc42..ad7521be 100644 --- a/src/app/screens/base_download_screen.py +++ b/src/app/screens/base_download_screen.py @@ -155,15 +155,7 @@ def trigger(self): def on_pre_enter(self, *args): """Before enter, reset text to show that its requesting github API""" connecting = self.translate("Connecting") - text = "".join( - [ - f"[size={self.SIZE_G}]", - f"{connecting}...", - "[/size]", - "[color=#efcc00]", - "[/color]", - ] - ) + text = "".join([f"{connecting}..."]) self.ids[f"{self.id}_progress"].text = text # pylint: disable=unused-argument @@ -206,7 +198,7 @@ def update_download_screen(self, key: str, value: typing.Any): @staticmethod def make_download_info( - size: int, download_msg: str, from_url: str, to_msg: str, to_path: str + download_msg: str, from_url: str, to_msg: str, to_path: str ) -> str: """ download_stable_zip_sha256_screen and download_stable_zip_sig_screen @@ -226,7 +218,6 @@ def make_download_info( @staticmethod def make_progress_info( - sizes: typing.Tuple[str, str], of_msg: str, percent: float, downloaded_len: float, diff --git a/src/app/screens/base_screen.py b/src/app/screens/base_screen.py index 8137054b..e9b62dff 100644 --- a/src/app/screens/base_screen.py +++ b/src/app/screens/base_screen.py @@ -65,21 +65,6 @@ def __init__(self, wid: str, name: str, **kwargs): self.locale = BaseScreen.get_locale() - # Setup the correct font size - if sys.platform in ("linux", "win32"): - self.SIZE_G = Window.size[0] // 16 - self.SIZE_MM = Window.size[0] // 24 - self.SIZE_M = Window.size[0] // 32 - self.SIZE_MP = Window.size[0] // 48 - self.SIZE_P = Window.size[0] // 64 - - elif sys.platform == "darwin": - self.SIZE_G = Window.size[0] // 32 - self.SIZE_MM = Window.size[0] // 48 - self.SIZE_M = Window.size[0] // 64 - self.SIZE_MP = Window.size[0] // 128 - self.SIZE_P = Window.size[0] // 192 - @property def logo_img(self) -> str: """Getter for logo_img""" @@ -342,7 +327,9 @@ def get_locale() -> str: if sys.platform in ("linux", "darwin"): locale = locale.split(".") - return f"{locale[0].replace("-", "_")}.{locale[1]}" + sanitized = locale[0].replace("-", "_") + encoding = locale[1] + return f"{sanitized}.{encoding}" if sys.platform == "win32": return f"{locale}.UTF-8" diff --git a/src/app/screens/download_beta_screen.py b/src/app/screens/download_beta_screen.py index 0a7950f2..216774cc 100644 --- a/src/app/screens/download_beta_screen.py +++ b/src/app/screens/download_beta_screen.py @@ -48,7 +48,8 @@ def on_trigger(dt): screen = self.manager.get_screen(self.to_screen) baudrate = DownloadBetaScreen.get_baudrate() destdir = DownloadBetaScreen.get_destdir_assets() - maixpy = f"maixpy_{getattr(self, "device")}" + _device = getattr(self, "device") + maixpy = f"maixpy_{_device}" _firmware = getattr(self, "firmware") firmware = os.path.join(destdir, "krux_binaries", f"{maixpy}", _firmware) partials = [ diff --git a/src/app/screens/download_stable_zip_sha256_screen.py b/src/app/screens/download_stable_zip_sha256_screen.py index ccac39d0..bfff597e 100644 --- a/src/app/screens/download_stable_zip_sha256_screen.py +++ b/src/app/screens/download_stable_zip_sha256_screen.py @@ -111,7 +111,6 @@ def build_downloader(self, value: str): self.ids[f"{self.id}_info"].text = ( DownloadStableZipSha256Screen.make_download_info( - size=self.SIZE_MP, download_msg=self.translate("Downloading"), from_url=url, to_msg=self.translate("to"), @@ -128,7 +127,6 @@ def on_download_progress(self, value: dict): self.ids[f"{self.id}_progress"].text = ( DownloadStableZipSha256Screen.make_progress_info( - sizes=(self.SIZE_G, self.SIZE_MP), of_msg=self.translate("of"), percent=percent, downloaded_len=downloaded_len, diff --git a/src/app/screens/download_stable_zip_sig_screen.py b/src/app/screens/download_stable_zip_sig_screen.py index 06dc4f69..6a843c4a 100644 --- a/src/app/screens/download_stable_zip_sig_screen.py +++ b/src/app/screens/download_stable_zip_sig_screen.py @@ -105,7 +105,6 @@ def build_downloader(self, value: str): self.ids[f"{self.id}_info"].text = ( DownloadStableZipSigScreen.make_download_info( - size=self.SIZE_MP, download_msg=self.translate("Downloading"), from_url=url, to_msg=self.translate("to"), @@ -122,7 +121,6 @@ def on_download_progress(self, value: dict): self.ids[f"{self.id}_progress"].text = ( DownloadStableZipSigScreen.make_progress_info( - sizes=(self.SIZE_G, self.SIZE_MP), of_msg=self.translate("of"), percent=percent, downloaded_len=downloaded_len, diff --git a/src/app/screens/main_screen.py b/src/app/screens/main_screen.py index ac906b60..b95d77c4 100644 --- a/src/app/screens/main_screen.py +++ b/src/app/screens/main_screen.py @@ -106,10 +106,11 @@ def build_select_version_button(self): def on_press(instance): self.debug(f"Calling {instance.id}::on_press") self.set_background(wid=instance.id, rgba=(0.25, 0.25, 0.25, 1)) + fetch_msg = self.translate("Fetching data from") self.ids[instance.id].text = "".join( [ "[color=#efcc00]", - f"[b]{self.translate("Fetching data from")}[/b]", + f"[b]{fetch_msg}[/b]", "\n", url, "[/color]", @@ -280,11 +281,12 @@ def on_release_flash(instance): setattr(MainScreen, "on_press_flash", on_press_flash) setattr(MainScreen, "on_release_flash", on_release_flash) + flash_msg = self.translate("Flash") self.make_button( row=2, wid=wid, root_widget="main_screen_grid", - text=f"[color=#333333]{self.translate("Flash")}[/color]", + text=f"[color=#333333]{flash_msg}[/color]", font_factor=28, halign=None, on_press=getattr(MainScreen, "on_press_flash"), @@ -314,11 +316,12 @@ def on_release_wipe(instance): setattr(MainScreen, "on_press_wipe", on_press_wipe) setattr(MainScreen, "on_release_wipe", on_release_wipe) + wipe_msg = self.translate("Wipe") self.make_button( row=3, wid=wid, root_widget="main_screen_grid", - text=f"[color=#333333]{self.translate("Wipe")}[/color]", + text=f"[color=#333333]{wipe_msg}[/color]", font_factor=28, halign=None, on_press=getattr(MainScreen, "on_press_wipe"), @@ -384,10 +387,11 @@ def on_release_about(instance): def update_version(self, value: str): """Update the version shown in button. To be used on update method""" + version_msg = self.translate("Version") self.version = MainScreen.sanitize_markup(value) self.ids["main_select_version"].text = "".join( [ - f"{self.translate("Version")}: ", + f"{version_msg}: ", "[color=#00AABB]", self.version, "[/color]", @@ -421,9 +425,10 @@ def update_device(self, value: str): if value == "select a new one": self.device = self.translate("select a new one") + device_msg = self.translate("Device") self.ids["main_select_device"].text = "".join( [ - f"{self.translate("Device")}: ", + f"{device_msg}: ", "[color=#00AABB]", self.device, "[/color]", diff --git a/src/app/screens/wipe_screen.py b/src/app/screens/wipe_screen.py index 332fb329..5e8c5cfd 100644 --- a/src/app/screens/wipe_screen.py +++ b/src/app/screens/wipe_screen.py @@ -84,6 +84,7 @@ def on_data(*args, **kwargs): # pylint: disable=unused-argument def on_pre_enter(self, *args): + """When pre-enter the screen, clear widgets and build texts""" self.ids[f"{self.id}_grid"].clear_widgets() self.build_on_data() self.build_on_done() From e3f4ed5ec7a0077f9198224411acb77899cbe589 Mon Sep 17 00:00:00 2001 From: odudex Date: Thu, 19 Sep 2024 18:52:13 -0300 Subject: [PATCH 54/61] improve icons resolution --- assets/icon.ico | Bin 1150 -> 103646 bytes assets/icon.png | Bin 13652 -> 6724 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/icon.ico b/assets/icon.ico index c10eb05b0c96d40daf8d6749f40b4c08f9b2d49e..321920cc15157d87d5ab95554eafc4495e95cbf9 100644 GIT binary patch literal 103646 zcmeHQcWe~L7k)n5U@$huz4zXY!3J!=fGfBF#>Ryh+mK&Snn+WcB9Zn-q68&M6eUWJ zqJ;ELiW1U$qV(Q-FG^E-elz2pxxL%lv+r!qzP;~Brjb=#uNQ7l4#d1?YNz2cP=ZygqJVO4Whj}i3-^< z`%B8y&a=Q&f`Wo5I5?O>LP97kER5#NnL~5u&ZY41aGE!79z{k*QcO$?#mC1}Qc@D7 zrlwLxMh4~P=2Bi>9@W;?Qe9mgty{N_IyyS2v$K=By1J;hx0eP72We<%h<5JWNhhCt zGM#<)*|dB2ZaU|jbLgt8uA-~2zM8JN<{G;8+H2{qyY8aBd-u{k_uNDG-g__Y+qaJ% ze)wT}`st_X`RAXfS6_XV-gx5;dh^XU>Fu}Qrgz_cm)?K>efsF5kLcr%Kc-JU`Gmgu z>MQ!@n{Vj%-+!mS{`$*QXCwdtARrN#HHT);kq1PmwT!jg*@rbGp+alkNaPD!u_nxW)prk zG&EHC+4=M5Q*?ARB_<|PN=gc)r>6`5T2N3xMMXtaT3SjA7cQjg>T2O<8`#ZY_3G8M zX3ZLEY;2^arY34>X`%M^c3QuFJq-*D(3UM*XzSLkG%_+m2OfAJ?bxw{4nFu`I^>W; z=&-{Mqr(qBT=?YUk3XJHJn=+!KiMVx^C_pCLZ_W}8l8FOnRM1!XVFC$T|^gOd@)^m z>7{h}<(JbHS6m@{_4U_ZPdD6f1KoDpZFKwXw+o+r|NZyVLk~S9{PgRuzfSMG^A3IZ z;fKOMfBNaC!Y_aS{rB|44?oaPKm9~M|NJxk^2;yu+i$-KfBnZFf6$+Q{we(S-+%v2 z|NQe0{rm5~^xuE~xq}sHKp>zHn3I{47)0S&IkB$Qj$6}K9ZbnhZIw2c8RDBe7YENy zX>G4^lb*MHZB44qhwJ`{mk%jvUss?zr;qaV?4@mW8TymDI8R^H(VV2aBj{3zSb9xO z`)U*IczRcBYeTxJvt{XBT`QwpE5~YL|6gCr+fxNF0#U55;V`IhhU_wHI=(q6a!nCwB)pyCt z%A)M-Z1IekpPx^Kg@sg7QbJ{AWmH~XP8AguqEEAA$r4(=d^xRHv4U2vTuE(hZQ}W{ zyStk8GDg zXPj|{=(AjQ*=3^NBA+$)?Ab%tU3VSH{>zOw-bgpybQ9ft^UZY2Ew_li%pG^!A)Z6; zzWZ)^;DHC|!3Q6tM;>{E9)J9Cdg6&E=&7fkqUWA_j$U}-1$yzt7wMH(UZK}sdyROX zhd-0@J`aBu<$aznzx-14d%pelTl((1??m6{#~**BUw{2o^n1|fVT6PL0jnc0zmh$| zm5<$&6RKFe#H{<{8i};c>~U^Gl1R)MWbqEy-2>O9iPHN=M@Kg%i{#ubEZ!Momeu9? zsVg5Gnm3vHZDp$(hep=7);d1YyS!-KNp<}pb;Bd0!;8aByN|j;x~RQ;{mAI(@FLUR zrLK%VIz{DeQL!sVMn|?*ds%;6Q`e@^fn_!MuDka7D|U=)*PpzRQKvs6*wf;Ye`Dp- z9sheGM-KISTfRFht9x|#fS$C8)aaN;)IZeUKQy|wsKBIe?O4L`NR(&TjgB^ZHTX0m z$`AGS4vn@~l$t#oII8S$B(A?ZGn3&z)axz&8ZLt_wVjZ7K`_kI#Dg`P2A>TR-V~!Z%@N)`NtCsV>-FpQsS}yn(p!o+Sn6hztEqB zeXBjyKRAVr$ma*rh<&{^e zIZAxon7{AlW5xP$Vm?>t$tRx_W5Rr%(lgIIL(e|@EWPy7OJYp;t+(D1bCvkJ@b}(( zPs~^P;DZm;oFzU+{Ml!p(dVCkPG5ZSg%~g9W5x14IUg(L@5=djF`v_f@nTL+2oL}Q zKmZ5;0slcDgmsXFIL_S&lIKG_9n<$r^##jTX;S4d0-du`JKa#?)yT#~uOf95dx^eP+h*Lb!a{L=^&l9rj7 zS;Fma+wk!4(9-?t0A27ev5n0y8ra6_UsqmMR+{S-uP0i_Mg2(|B_&$<$2$90P`?CQ z*&pzikOUt8Z0s#y^7PqXSOpuxTHep_KcIc>+O-Xy&1Uh&Q#jgxcq8w1@#gQzVjuTK z?$@rLxLl|Dnohs+rQTE+qZA!uRDAts9)hOBf#HRBNdB?!VfTN}V+>@w z{)23Vg3duk!jTp1`;&!U%x3ha+3fW){u2DWIx>IiRKnnz_E>u1wTf`TyqB1sr{ z<1d^$X#c=&|AZ#ydW1}a|6%;I#WL3`#OMCkBiA`4nVtRbl>Dg&e}ej@v8(qF9-ue* ztO1JuTs8$&NOrHppFe*IiSzVR5YJn|R^7p$Hkot{$@<0fCqK2;Y>5!h>oF@4Tqg$k zWz~+M55`|mKk#=Xo$d(yGc(&MJ8xUOiI283=^d8Hi}81UYD2-4)nocc^VyVtA$iLG zwq$6hQXD3tnf}GpBn0UFPk{&hCI8X?Ql#)<1pEX4#t?x0`OxfCRj@zUAMB4K0RN+$ zf)69`Khx}gOuoPI6$Q+`Kk`-mB)_vVT|3ujSAvRw01yBIKmZ5;0U!VbfB+Bx0{(-5 z_;7~LS!JJWd$LX#TmM3=5ytlyW3C}z4Ji7403rVj3#rKEc>wVpN>#bt1t2^(!Q|wcC-+lKH-|vd=55e~- zXhP2?nfiJLsH+-4t zN$`ILKEwaHAuar$fiLiXZum0Oli>dhe1`vXLt6Mh17G0(-0)?lC&B+2`0T>}1;r(6 zQmn>52KqH=ji2d_?B@C=*8cMr^F{Z#tRK+u8dzGYNs%wtqH?2(S4k7oKXR3UCH-Y= z8RjwZs^S?^XcGF*5Dg}G8PMOrY#08|CI2S}{0u3L_DB0WAprgxY!mkH#F4?l{xSnf z{&)iZ&(N~4e*=+W{|1)8{tYbg#}n{>24=(m8HgO9{%^M2~pJeLjS%Z`C%j8|LAOBEE)jgzX3n~uhzc<|G|GJ1YrLGaQ~Ak!v3AuKZyC?nEx)V z!xEv({;$*w_7D4aLIC%FX&lxFVgF799~{Ky!dU-B>fI&`bQ(kwu~e}?`V0%(8f|5S+eKa_R& za|HfRF9sV4F{VPVx2<+cLX!t)#4i&=x8Cc?vC*c1Sqh$pC z&p_lr_kVNBwNWp75D4R6b{@=E_^w#xgm;f5m$l0sk$-?(r1?|0V5JXkq@# z58LcvOtaEkM(p3e*|UvLB!9>eQ6axYKGp-n02S;QjW ze?x!InqB2a`;Ti|{*VFuSB&;70{;60y~n*q@ZU4qtK8uKxZLuG4B)?Fv}Y0U-yi5b z?lpq{p3z?A2LH$9mOo?w{}rP>i&%vJ^A|N6q}PDNK)WGRW2QgQd)#Xbii~!a<=0ptJ1_E+m)`DvSaa@lBqw7(Mq7JmO_v<&dysrB{iUl`%C+!?e# z+TRHQ_&>{8xw%5He<$|C|HJ;x&Bbyluz%RU69TY*%UQX(La=`)_T&B!`!_ci%ca2n zVgF7D!2T^~<>m^({+-y5`#f00e*l5C8%|00;m9AOHk_01yBIKmZ5;0U!VbfB+Bx J0)dXe{{g~08s7i_ literal 1150 zcmd6lu?>ST5JfLi8ah{LNtu=fEU|!BpiRXD%;16n+|apm$sn{eOuz(}`;IK7NWoD= zF*;5<{O*7IAiBt749WXW&nwZ5h#nGBlFGX-iAcVESuC}`3+EhnU6*}XYq{@xuBz&= z&uN-C#>mDPp65A-mPZfhZrjH2qq(OL0@p@la4ge)bps(=J3QURY;hRFmX*~mu3$5Jg7#fqXn zjy}W%QCk#>v@U>%6+|n7R-RY{p%6vcQ4z(|_DevPQxA%#eSaBF&U|yfdw<`(zq^o` zjefq1rkGoqLl88@%hSUjg2sX6I0!!hTpnqw`oN_mIv_~pk3%%r}37H)kVtqI=Q+l;KX?%9dk$LZ5{9NU~-XwgPW9Zxh2hEuSX2@j1 zSNqC8MtxIKx;|Ldi|^_oU&zx}{>JI6N-K?z_jI~E`TE@3g!J3rPpNoTVzF$;XN}56 z+IF(1{-V0HiB(~mYMTB&?fN%s8u7V7;b`X9!Plx14<}}PduVCV*6yG?g{8qC1qMG% z*C*^xD>`1T-hJLP#A5MQf}86syB)~VRd)9d26Uz>Vw zRMg4d$DO-`an50o;y@MsznrB$x^zXeDB) zlB?wrjksK}Hi#)if>A{k!6OFo{Rr+d1xA3$FqukPpcQH8#QEj~Cxt-B_4imf00HiJ z#Bh~L&ZSVIqN2!A46;lSMxk*y914|Aq0>n~gQQ#|RUulERB3B~=*RHDl&C@^SBYd& zf&mi=m8n%cA`$EpUic@G^ZA4DQsn>(fDeimkyB`7Dn%lp47X6K7H9y-fI}~}PzHcD zrTAk?nOcEj3pAKiWjh=~fDYQr)e5mO905wf#FzxAD#59=5l1fa;`5)(GDWJH~K^I|9rHaYtysh~20RwD^3khYVF4-1G9_5e?^a1u|45;2M`O z913Hhs3S>071BvC3qeSsG>(wOV6bTz#%8iuC~Fv$msF`jq$p;90^np3z`+m(ok?Xg zNQgkdCc!i|jfB7)Hi^k%!>A(?3Nr+u!yuL@M4&1W@o=vUPyzr2Q&A?&a%7NLLVyQ5 zvVb>KA(O-u3K1He#b5~OLL-y_i66uC6axM3ii>+0vlBhty#A&H+D zQ3-(okLV+ksl2e9%q;M1^=DDhz;9=`fed;nFw( zG&UD@1PcoQyZ&3T$k<8*g0U&M z2-+Wl6477+qn`k)e+vyqq+uAC9s}k2LN0nqDX>^DOhZtV#AMJyNiYLplR`NR4hgV{ z3OQ^<$iT3X=t`MT6@@4;*D$~%;0lzdkt@Q7#zfhV)Q$?r3|Rn#k*FNfAYpXc0AZAY zfGLKV@gia;%AYuKGAaxkGQh5128I`yg_OZzIKY`{AMCWJ0tS#W-2fK0<(J)XUrncGWE2Z0o2;PJX`~`HSIOIi>qR+ zi@PhUeeYRs5mOz$yA+PkDh=0!Cw-Mz{13Nt`|W@Hh7evjCtNyl4lxm*x@^M)_r%rs zngkc!7C*l^g|h8kPSYxzX4FxhwwzfRSG*x-Z)e@p`EiF5FXEs_J8>U@M|TLqLy!w_ z1iYn~4ngr?WdcD2a2b7TjOs&&yb?X$IY(&P^=!6tto2E0okPcpoRw!b6-0IB6I`I; zz4Er3xomYyKx8vFR)6X;?y=4SvUcNyEgo>&1q#BwVMxHou`nicJ0KU|fjlU+Aw~UUf8neM7~bPa?Y;OB*ZH&-G75K;Ycqb1+Rr=+CBBeJ>XmtQO(KYTJ2AG2L~!sOLS z7`-(A6!1{Vjmq@%K<`WM)Y|&pc}621XZqzY%&_Q*K68X|CoSWDt4rH&olLq_{jj+b zl}fWuDJ5cY$=$n$Ea92^gr?Ret*x!OMMW!XPv_T3w>@jo6y)aTw~z+p;Y_KJ<+ zcpTIP9_|@5CiAmPM{O5v3D9IGBqV4b-sRin-MDdM1w0OF$eCbf)^zV$M(LicI%%0+ zUpQ%9y{>cRUs&hB%hzf&m-=sman?T`w|Osd#ysBu$4S$nV%$}+W5zGyccZd%RAFr`+8cz`?}yu zM^h=QF4WehU7mo0+WPu>BFZZ&meC_(V~dVM;jq=UaM)oN)5)prz<#smW-mtH8+bdS zZpK0rD9+#KW(Md^Yc!e_Qy+nzEnZpl@2Br1B_-`F=f?D@(s*l6qy%3PGNiSqKD~4_ z*~a;TPIvI~LI`RDFWIlH{=s2a52!EglP<(Aucarts

k$h4Yb$*=FmLpRS(OZ$TE ztWZ>t&HkR@G}^zWzJM#{@v*7?n|}TES8t(2A}M|R_(UcVf;7jD9xZwBK%q-po34JK zyY$`%9~{%I$jHdZ{q8$IFVDiYz2uJivz^B+K#J3OYv0XTb+&^8#p<6}EJ=6Tc>n%= z?+PZJ{*JA!?auNR6_;!UTCs9fZM&u*CAdyn?FO#|j9p~OQb^hNNS2Uo?0c4E%a%e}vL%#dLW9yE zTahix6bZ@Bc<#^ldA+``*Yh7d_Ybq&bDitH?sJ`U?(=@1GfAe#dMu2*i~s#mKVu8X zP+3p`04UtJqOD;OJhdL~guml=k1)e92r$51Ez2mZsf~YG-RY;1=WmRTPedJ$ZyaKV=^%uD6-v?e1cpV5 zN3&P)2Mr8Bl5z1Na-z02Ns*_5Qz)RU!H1hpJ$R$gpKRlmXj=Qq3xL9N3s-*GGZ+jU zRL||0moh+6Sq%}~eKS^9=4<8S^)C@>1PT7Eqwkc6IHY4bln)J{c-D?v=Qi#y%Cg4n z&00Ib*E-n%ghs4?A=@ne%6pzw7@-0#n|hRc64AofcaOW>e^&%TFnl=r}s8sDl0 zpr8q8i-MC(cXj>_dRHVzDK%#TaEuMNly^ZQec9(!M{Wtyhlu~Cy-D;(49Oi=_(mg=|o{0Hl+0^9sp%i8` zV`6s%Itqy;k#y^NIEKLCl|Cv@*U1F^LEz^r>Koo|^`q92O8$v1a*CFTt zUE2+&eE)4A30F>-q%Bq$)EhGb0MyTrD1Wl*hB;E=@8_YoX%v7$TCat5?A4;X1D_;F z>=+8mktArcfqtpEx604YK*zR;4-oaU)KBS?7vKZj&(i(#X&ErW>7y>yenLEkLg+ zi;K3~(MBztUz!`w|%wk`rc`t+lwSqU2QQ<+`Em}Zx)$I3X^?5)4 z{=ZsQeDF>s8#KP7q4|P+!@a(61x>;O!x))ginL)HR~jvtBi+C=Q_S%cX^mX88*nho z=^h6F^{?Y*9SH7E>o>az8)@=XG^bv;CFzzue-o7D+H+8*_b5@ zoAG4$lbP4u#i(31$q@T3poJ@n7nbwvq$`m5Dc%dmy^!HORXNG1;5kn z(p@9uz)@@X*6EeLN9w9JXkxx+k6!qirc0{HkN5G!h3pow8uR`@9tasu7y~?z%>(na(z`-VZxI1bMVal%HLuEk% ztF}K4Ln4YGpV$;>C(4&HxBhP4}NYb>X2o`blM5z%qu>+yUbqK|c|W zx_Ufve~tU+(b?$5!jRs(_tNJ`x^RG?ubl`)Gyi=b;1+tS+Hw&JWk;f~9jwl+t~G#> zf}KZLv*?iaZ^|!U29Av?f-pN0$>aY7SQ9JQuI|Q9-gDo- z&7;{f8zyW%Eg#0Lp2NEhhwspD4moJS>L<80?PbKwEBq9S8zy+4Ne#o;W?MPgt-Xr2 z8}Kq+Bo?b@EH(MdZ-#O%Y5*NhMNK3W9CR<4{I+@k;NIv6BHO(4n}2{J=#y+HC$i3^ zw)?NMuTCPXR3EBX>9#Ig+B3mWqE0nIv(|>df6vO??m->c!2V1Gf5Q9ov_2{jn5ff? z?876eCH8Hzt1r|^A0YNcvIFHni`OX&0w4ZnJ4UFzg)Yj_8g6O@>wmkoyyK$I8q-Aj z>AE0ElbE{G(;9lkG3?8?_v1A4jas7Gc;v`JbYA(w$q#uBKx2$bvQbK1RDN)mAvW;e zkpZw6f0BOM-ub)lJucLl_`$2JfxNL>XPwH1kr!e^Y>Mgts6kvgH&UC|l_<|qx^gEe zwISl``tG}#d1jesks)XR*A;rQH79i8-L-IFR(Vas>7+IEvu4D@m)Vb8yE&jhVs@b> zobKr_h`-5I!rP~MHO5Cf%Pw8pIfS;Q!W41@C*J9}H8T8UXf1;O_y_dWw~|!8`&juY z>~q^-F}#uJm^{4$88bKvi8J(2_B!r`DF*^RUpv~V`&*4dMG%Ra^8`Wg5l;y^%AK6d zotal;eeOj$(I>GuxxVh<_g~?iyV9}efIG)Y#$Bb?BZ^fT6E0}XWb-%`36W0LBB|RY zxkXB_!8Qp{0*wZ?z^+HVQwkl*X2<@^GnBL_hs7Qkn>pPI;p66!? zgod#oJSWHp4lR)gMJIz&Qc}>jy3C8psWJYZr(Revg^2;$&=s~^^uD~u z8i4>tkdCP^x}{>l=~?ADqGRL^aG~z>BvSph-i@ZHI2SaK)j$s2=xE9r{LGz^%Av8Q z+uS8Z9~&$Rllj+Pd--a&~U%spyFYKT(iU-tGWD;uU|8{74Qw(ti?^`AX* z;3m!Zw9I)RN?}&XkX(`3#r4ROG8jSkq>mRs)zAYra7mo?QZRQ%Q~X={ea8780GQ34 zr;T^uz63=@)x$R*T)#2N)b4g3hSDx;j)D!T;ZNfA--vp=$o~+(e%cEg?k;)@?7t8F zFAJ2Rou-?&V4aULJ6&$Hk6k_97yAZFtc(yGdFH$kV1Dp5P$^mb9MR9OdaGlPZ0(eK zu$kc`PIRihERk3+Rrh!<_#pq)m~c!^E!&U@@Jw$nX73eOtZndD%Bw1mu0{2_c`Jv% z<0U=n;4ABf&tjW%46Gmr%~ti<92(;gIfU%NXMM^-tL7$=+p9tSdcz z|1*>Nzr4F>;lG1|_6`7Y#IOH!!y2|_7xBLCJqL&Vz)0PGuD@I>{7M+On)Dw@4E2Iz zb<%b%ynY zr6epIs}yXe^i`%f9}pfa&n`6o*fyqe+j=NmW?PE<1z8i4u$-JM|w!IMa{PPxL^HRI_T8}vg5Zflo(a*gYpYb~XbnFJxN6)LA`1g9}X_k7hjmLg} z#D&{`nne817A1jLMa*(UP-zgo?AO4rfAkJ!y6Lc1!eDsYR>^Y%+u}{FJO{vYB`5Um ze~rugsQ2=rlP4Y_N%JQIKOrvt7QMYgbYw0St8T)nVA!(Dt&n(@UU zCF^?jv#{eYPzgY|&?#@6lKtiuk%ObuXOoF$3b7)a5W@PN@XS9B0Xg$X@eVU!Hp6=R zDFMDcu*&MY3gLpvQWQ)+wwV>&hk!AiHcNtp(8{BP_?b#UCVPE%mMl-d*&ww{i-_Z& z9%q?9&Q~>uzucApv=yP1dp!z$*#@IG-?Jcq=S$h$YDNh`CSttoGGb@BCboHDAQqtr zr~)0&>OMpZ54Oo{=+TXFn=R6d;aRtjhFW?QDhqGA61m_&`4VT(ai>tK_Fa7IQr4su zYi7-ML_bYRA|%@G&5oWdg;NWT6|jspegpZ$ZfaIoS)xA2>YrGyz)yQ88t4}LaNxV| zfi-!UVThBAV?FqmMsDI{I!J6z!Y7n885DVR;Y7C2cIp=7q81^m+c{~}p23-AktqevyVe&z7)^3#!_*$y<-W=`&zp^; zhN+K@{kZ0~s!xc6Y^%j(^RYrMY6A0FKeRJqltc^tKYE~n(t8o=Zn|C_d*8Sn+B4x_ z#O5h>>T{F~v(NBaYlrZ`ZUUzk^Gg@{dKM^3|H??|l08emnJ6hPg*BC%BD!>ph+mSD zPqKYR(8pk|CbX2CR>}}U2G0F@XX9xB4F~wJTd6$FJ7^p<&y&yTMCWoE=^$XJ5+?DCn&fpJl;I>y1o?`UY(IJMh5} z3t33zCn|Ch<+dMHF3P0vXkPsleEMm}++iWhjCotl$UHGWMGylJc_3B3VUIJY<*o=5 ziLx`geilOC+23dZum#Q5!PJj^U)!}GjU5{<@7JDZ$jx#BMJJ_7Y?J<`*ZxYe`hHEh z>b4g~CPSq&BGjMujRt^NfTH3|pK}WE1RQ$|h;wL9JS_I|BKQvAK5%QoUw(&g!GHnY zBaOnPR_ozWc=#>XvG#u?2@sUYLIIAlUB+;IvL)Xb_5HM-QnyNgq=#t8w#&#@mCV=4 z=3|GD6B{O`*Z1pX&)Wa!gdKAr@D6zUafb7@GR%ID%5^PH#eyU?{RR$-Pu5WElvIr` zE|Hlzm*3PbXBlEF7*U%Oe@@d7c%z#zT2t-)+|jntXydjSGRCma8WXoMcN$@(J0dLz z+G_$lW_^i?Actmw0zCMJJsBqq=}8&yU&{Fkgz2hNLk8+jT3`L>(};<1G6V+;fxC{BzYZ zkm2jP-R&SPF@ls);(17W(5y{Nw^%vLLvAom0o9FnPyU{J*e%ymXLX7AXW2!))c~*# z;u|b~o?W)rG_KOz`T@6Ci?HW8dB~;`rH6Me;v=0<1JzZY@rBROL!q+%WSnl16-%M{ z*B==p7vTgqyIH<}`|}bn#%X@r-R6RBe$h5NliFx9qUvSp$4t&&Pvh~40h0aWBHMTH z!OoK}%zyRWYl-A3(&6;hddWlolKuXOwO8qL*`q&@PIkS?)30h7N4t8$UL8U~?`Ft+ z(3dKK20%`?Sng7xVn5E9I%IV5`0NNXwSYTq4*)Lfs=gil5iT!;@{rag>=Z8zuP{;0W}eL` zCv$PhfYLz^h%QVSb*@_FYQoHZ%qyvQbfTeQSE1BfH^+Lr$hFnEY63R>Qr#6OMz$#peEGQy?Yjk?Vi_Rni(#Qzqr=tSRtEI9oyo}=sr>j--Q%M$%`JR zZh}19s{1j9Kuy7qmU73y*7X}#-yDm$rvRGob+fh{rk0*#qFNmOveQ$AS)C=!VS9ynnBmRV zUmt9An16mcy)07wW&a#*7y;Q_iY$qc{9&^y(hWE#fTW_}=J)CgM0x{c$r%ut0}*pa zB4{*nVp?E;^WpcFC>D^lCj(L5?Mp;{@0Gq_TPQpf`2bRtblJG z;ZPt^$nBM?0o7~-f1?I}OOI*Udl)?N@LwJEB$D0;IiG0K2xRtK-Fz38`1->Bvbs9x zEN@`ndvn}ADH;%lG(z!U3Xk(jLstu+)g#(}>uvmzg7`((QH?IAli-{0uqaC`VxvfY z!lsr!@&E)R9UY?^O)p^HBgdbS^GZ?8KrnZE5ZSu&BXBhNf#$nCaUl3e`Yqui!={HG z!MTPn{y)|gWXJX*`1g)Z{v2L5Jrna>>Vf=pq3qXlkjo6(auW~KAHFM6f!L))?JdsN zw3VsU=*3lWJeLccZi*BKfU(P_N~uRDKK$)_AO(6NE3+yq#AE7m4uEkzePPD7W z^pwITvT9ud#4UvC8EGBQm6PRIquJd49#zT#0EjBi-cM_5;8p!6Y|4poj*++`^-p4z z+)k-iZV@Mb&oKZ%AO{$v>eO%VNiushi}b!_`p{V>`998C5$XuXR-_r{gB&zLlCCK< z1jKT3tYjOl_|)c!uXY!s8h)Z1ZQa&sRr29xCGi z@I%ls+V=L}?TS;7tNIp}XcJSN?!coGzpD<#6&|-;L1LxuuXO+vuwa`{aA=v{2%2SQ zgabumNwqJ&$Oigcv#A&wL_aT7%7g!e0n!X(J%oGT(`Ks#EglyTn+CtgnQkU>cPkie z^E=J{$o>UtwEx!rHJ{r6&W%*u=>Nrne$jj`OPumXX|PE zFvtOz{7zRJ5hu$qwaQFz85%SBzMD`|{_NB2scAIkLk`UBLNt zcl(rDXI#8oMuA}C^DgGW-O~ZKn|N~PZIaP!C|53L#a_wjQCHV&MZw7>*7T20nj%5Q zb92;gOmy<4yxwG_Qu0|0hMZ6md9o3C*IYl}C11zJkIbjW=93JhYlv%dAf=sXCReCO zGGL0VECi;9;A38}TaFlj-YBw|oqnIWNxX0M=>_e1juZV|%0ZKMnSWMw^)= zZRi4kwo^@D1h-rtGce&L@PaFH<`<16-E)92ffeHugQqMEgcs1^MQ$E%M--TM zgI2!+shv{^v3W!c)Gy6`S9jPBQn7pD8XinUAG_h!LBa&vf8~-_#_-ON9hcQRASYf& zy>$vJ5FuW&7hvc}zbfNO_Znn{ev{s-hECG(Q&^ks_~`%C3A2Mb*I#zwlJnuVyG_>9 zw(DtN3-jlrp5OO@S*@zuu|H#a$%$WV-;HfMl8@BRsinGFKD|8u4r%`qV7ro<{<6Nb z!RKq&@4kgsoUz6%Rlhoo2}X{;psBQ}>238WYs%gQLy>)>Cax8m!?eWKj%y2N|5Ix| zEhPbq{fb@zBXF&d-ENB`F!CwK?1&gxcvYN8*U$^-3|Bmd$xft!`AuCgz_O2Uehhsv zx>#UE)5!-}Rp>{{Ph}f86d^*hp~~UEzc9RVi|wv)>$GHDs*Zf59s}yx;%o*_e}!!x z$d|9_tutJ@3$d!XAT@=^aJ-83pw|~+25%7%by_DvNy~$SUaqB{(Zz2df`Nb)KF^#OH;{R(enlVouS?cl?6e``P?D}Uao0a znG~}}Mww#?oS;|we|4oNx`gRL0aSi>b2O8eVFvaen(g_n31->i=)F@O+o-|~4B?!_ z<|PJvudDQY^|s^XWR1kc?5y0{(=yspGvH%fc@+xq>d6tNCvA<;F^4>_m?;}}|^VihWZe|!JZ!fHGUVh1JFN5im z9a3bx(@ix(;>py*qukNU!!0Fu9}H2<{H|bQt*4_^Ayc~J(2&!$x~^F^bVb?6QVa>9 zshVF31{iT~VcRkT$g$cW_KYi+46ZWIamrp~-$g-}pw6&R*b@+Zv=$lJF(i3vrUNyf zeJ=c6=d~8lw!b{rhVoC|{zu)W*xfZB)WNsJ7aC$}YXBCc{d=LN6xNu$%AV=zA&e^* z9>31wEc1jPc^|TloFCFK1RV1!J(BZjk=OKS@0c;n%c($KY2ov%O=!%oK}+GEt|w^U z?!IK*&f2SJQZs|!w-@x_bN@_pJfO;v{+trj2R+#gcCxoxrWGGRUUwz zJL}En=qi)Q+^%ye!|uOdWQVQR5@!C0#U!;QN{tG?;6&Vce_RA85ws`R-ko@Ht&6xI zUadR8zrbn0B|rzPKs4wW;M8BfX(qxIsI)(RcQd_|V_p(b%Xc5mCEIBX`_hAokr@0= zx(=S^Mf5AH|7j`}(7bAWzQ??tE~*W2v4KuOhoBy6vdRwn5UWO?7A3n(QNp%yV1`Cb zM6f=&rtzVh$w9d(JgH`=64sCTU~k$g`s9xRqYq6jXdtgCd$zo{KWS{y&?C|sE;oUQ z8pF&+7w7NSfINy+he|a?PNIK~MpIrnChJ$>G== z9ZJGZOf;yiU%Z6Z#+=fFasI|RrM=%m_Xv&07r`>!A1$}A4|!&ocKyq|UL8OduJ)e> z9*TeN$S7}!!SO_^v8DGL+@+O90z=fd&>aB#v;M9a0Xxxz%EY>TyCtfveXd7J%GN-x z{~GP`14OG)B1qfBthRHWNs=SE&dZf2o+ArBh+IhLN=*S7v%WBN?I^n*vv24|I7o7a3ZPI0!TX< z-b{EaU1QcDtSS0I)y-S=JU$fGs=AY8nCwtITZ!;@rPFqrA>t?O+z)gBTN1Opu$zEv z0^B`jqFq2q*8T8yZ!;0qgs!@D!v_~%W)>N*P6`Gx! zt>E@|z&Dchbl3VqdrAf}u-fBP?-#IeCFqNly|Cb;gKdPPB(r;sP-6yP_a$1ZBIWk) zr!zEn*lovXj*r*EA7bPYICag=^{B=4_Xm!RJTPRY19a1BQ<7v~_ge8P|T z_Ruq4hp)tFYJUR&uPE`-Pj*>>*$8UkiU9!|C2(61LA?e=cqVUxIh%U)3f#Agzf|hl zyu-u%s2an#W1ojxujm0Q3!OA9=}w62=6@sD3?+kA+J#m?=QxDkFVqUd@0A;uD3NT| zerpoq0&b=^w!6)Woot&mdt071KhO&`XQpC`iBA*|#L$W|iNN(O<)DATCW)2`kV6tX@0cN%`V1 zmjMLweouOTc8_IGDX7_HU(vPRDKP|dW&kJN+urfd-W*2UNvB7hEeWUmN_75SADU#H zS`x5WI+ck*N5k*dI=#j~`R{F9rplh&3hfqr%9<4z5jGHgKkqEVuR^m_7^=PFx9Kxj zD}$oC;Pg9_(C$C$(Ee73T%P`Pe_PjqUiT|0X&3tlV8|XesxdFixDFlbeMO=RD!xiO z$b{6gqgJvVQ=2q0%>M2&e&7`$YFX*RM*K>IvLV$(VR$K9~&7 zyWXtc2s*!BGJb#akxYHLTm4d2QG|KWzK~3uzH<>gYey>)OX4gmVToEQ{7rW=ep-}x z>zI9O9G!^~kD-Ia>IjKZx=RzC3*lg0sgK(!V1yS+#!N|1Fe>R2`nnI~6W=f`qp(K(n1xpR7=OW>%46d}3;Y)Z5vTUI4&Dy*#*)!unTYg2EZT z%EUHX1o(=I;oLyuwtDmStg_PiiLnI(V1d6Q9+)0Y`vn6`zvXeR4BT8Q1bc6+oCK;* ze%UJE5vKnX7W4`4ao#*L1xz3`c`*aU4$ewI3Y#b1c1tDp3j5_S0K+aoW+sAQ=tpjA z_6RTshXD{7u@AD=-C2)7luGe)fM^R}4*U&A!6nKJ@zz^Q z3B^OT`WXihgb83vi&;(cM4og!p$K4H$nr1rGM-ZfJESmY=@du>DbkDZ=v264N;65y zV?ON+ED#D1zsTQFtlTIHB8R9i3G0)rLfiBKMRvr+0@kStcYF+Nznwt==?*9OC$FA% z2$>^AFHyTp~`E>9KJ5f2fM8fq3=qcFa zIAwJWdq3KE+14F@|8EPVA-edgpvDFqlT8;B=1k|ezezx>wsWojESpx21&pxz2FM-I z9!h=#C!{yWA4j`{S!f7r3qN8KX=_OSIQLpT>v|$c5**Vu*8Y^3r9StK&xDgtg}wWE24`})xE!J?ixp8I7xlnd68gy&^Qj684GlND~Kj~L2T zF&aQE5HZXMk)-AcNjxvO5O!0|s?UIX?Km%`^xmRR0mXD$7h`$t8>KnY3%2hxd?qYk z_5qKjnf4_-2I_p$`lKSHn1X{j!LL~;{s_5+_kt1U254?W{W0fhd>%k*+(?NN2ltc& zDm?y@d9@5jx8x}a)51h8{~p1Z7yoX)g!(G2c4YQiWmXBwKa4RxBho$PZ#+~e0O}5S zz`04!T`E$+{{G$&x!o(|rn`~h}+WW7p6h0E6 zG3~*PGb@KMcyq^Bq3oCE@NR=Lj^>TAtYVaZ zOY2Y;6<_|U|)hp|0OR?4Na>hj6=}W|}m}eD}A|-nwmH(=E zkrWSE({`-BB(tz4-mMH0Sc8JX-^odR8L^Iwd4Slz`(uIa=oLrCl)`0`;@BodT}5;+ zPzo57MWWs{M7TIKwgX_ovFnW`uO^(}p|O&af7=>&Sew_DZ$>eY#aKp#y05TUENf z$Fa<+ciguXfmzkVph}nhY}ZR~RY!#E=V?^sJ#WxX>H?On~s2x2;LqP_)yXdmr3N3WJ6&@Q*V> z9wwi*u*JTP(L2BY`Lj8%WqPW^eO(4q1BX{boqj5@qT2D^4PnxYdJ!%i?02N33B)=%Cj`qQ@V(_J zB4>!gz@(q%AWkP{oLcS~&*Q{wcY)nn{F9AS+DpOtq!BuZfS6+&e}MbuLR=?Nq&u-w)FFXf7`vxT-gYiF7X z06-R&BqM*Wu7fD&5In;2%aGWWAjaH^q@New*|4Nz&Zrw(Pw|~7UdZ-C0+xwE2j^&< z1q`%z<~OU=v!~sYfJDj@Vm0%yG(i&bv6&?OzT8dCfEX(vZrKQmd)mJ@eDsqSSY7oEbjCmnud zF?qWgoK%2{*;X505Aa6ZHa+&B>FXcznxwTNrOf0$k(;z6K=Tt%r?7wTCVuZjy zzv$;t=*rBo`1n@ouJ;nBQz~}(Z$^l3_z!kmKg-b?%^HK8`ies*vk}7nV9cM4S*~&0 z%;h0AyId&eb}~cuzsrB?RDE|KBu$|1IW#|I7j`aOO1;I@ULN)$>XyMh>F!pG)B!Ib z&&(hnGXH?&uEFyAdi?U#kxp)%ogW#u%CzK`4xK^~UWAw>W2dH)oFr*r#=^UAFWyjf zyqsAt&^=r8C!C~1#ioUozvs4-)0pg3_L+4l-aY^;P7tl+fIq=h;D=YjJo)NsGp zPfrQb;xM8C0r5=mCnt3IRQRtSvm^dOF54wyj_^x*%)h|AH@# zQjX_um@#zybEmq6Ly9DI65VTdR4_Kl8jo2rT|5zM zh{Io-RPcz%Tj4JGPOG3nP}!9x&+?4lcaZsDS#+^OD+v)hsy2is(aRJ2J~3S|xS+3c zmdIYO2os0lGtA6D)@0%2#E1c5CYip>+X)8?tD(xSZoUIwS;TH?0!Dpn+8{N1)jtul zY~n-CGpwTYxz}uytu^l}&JN$#&_w)At9 zv26z{Utpq&FuqqnL2QfH3Y*#UFjfc>d84yd+3O#&I*~n!=jP^S!DEhX)S;lVlM5oMjUa1?G?~10LDG#dLh)h*9n1tO`S$I#$T-LZslJSY_$$V9d&;zfY^)MfnWC+=S70Q((!j-F1bZ$DBcfPK%#k+|l` z*Y!=00hPZR3`86mob}If3%99XYLh%n>`-wuz<{7^k}yu~KrPut!~LzBh`93kLaa)? z)))=28vIjPXyu?~RNl7HM@gCGJ{oWrhMVS@Gj1!42aIk{cOjvP@UuYelmxDFzE)B1 z+kI;WQ$NOS8XAYXE>4O&v%$mJF9w7u+A3xyhhj>`Luu`y!T;{4+pFU)21iRtEpYo* zIr;YTN}&@odin2@po;7)W(eg4)PBm6P)Q5c9k`AEoVvXM+cgk)qG2WTR!#%aY{AMERop`LCBZ z-@Ws9kRpC4lq7tV)E6dp>zqCsrw$E*UDBoNd5Ni(^qlFdcl>r`UnbE0Jz@qH%3wW< zJCkRty&Z&^`RY&ot8av@PFjhTR?Be6)Dqn?ru3=PWS(?`p0oeTa;-%J&wXHFdF!Sj z0wWl%;=QVO>HD3wg?-wG#jKM!?$*!l4tXCv{Qu+ViaKShnUU$8dcK?n!eFrg9jgFm zhX5B9CqEbP4Um(SQ;?Qbl9rRRz$&XKD5}UQoR^hVk(KpfaD4Uu2zcLh_HYgPUjeLw zg&bBz5fqU9zXBtkYFVIw#Q$C)z{A_cKfuA;_kU&N6fCexDhlBAxc@725W2by$^ch% LjJ02B+DHE%lD5V$ From ff0fee598f563bcc29016be44caafd9abcf3118e Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 20 Sep 2024 07:33:31 -0300 Subject: [PATCH 55/61] fixed icon desktop entry for fedora --- .ci/create-rpm.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.ci/create-rpm.sh b/.ci/create-rpm.sh index 10bda05a..92797fed 100755 --- a/.ci/create-rpm.sh +++ b/.ci/create-rpm.sh @@ -161,17 +161,17 @@ ${description} %{_bindir}/%{name} %{_datadir}/doc/%{name}/README %{_datarootdir}/applications/%{name}.desktop -%{_datarootdir}/icons/highcolor/512x512/apps/%{name}.png +%{_datarootdir}/icons/hicolor/512x512/apps/%{name}.png %install mkdir -p %{buildroot} mkdir -p %{buildroot}%{_bindir} mkdir -p %{buildroot}%{_datadir}/doc/%{name} mkdir -p %{buildroot}%{_datarootdir}/applications/%{name} -mkdir -p %{buildroot}%{_datarootdir}/icons/highcolor/512x512/apps +mkdir -p %{buildroot}%{_datarootdir}/icons/hicolor/512x512/apps cp %{name} %{buildroot}%{_bindir} cp README %{buildroot}%{_datadir}/doc/%{name}/README -cp %{name}.png %{buildroot}%{_datarootdir}/icons/highcolor/512x512/apps/%{name}.png +cp %{name}.png %{buildroot}%{_datarootdir}/icons/hicolor/512x512/apps/%{name}.png echo "[Desktop Entry]" > %{buildroot}%{_datarootdir}/applications/%{name}.desktop echo "Encoding=UTF-8" >> %{buildroot}%{_datarootdir}/applications/%{name}.desktop echo "Version=%{version}" >> %{buildroot}%{_datarootdir}/applications/%{name}.desktop @@ -179,7 +179,7 @@ echo "Type=Application" >> %{buildroot}%{_datarootdir}/applications/%{name}.desk echo "Terminal=false" >> %{buildroot}%{_datarootdir}/applications/%{name}.desktop echo "Exec=%{_bindir}/%{name}" >> %{buildroot}%{_datarootdir}/applications/%{name}.desktop echo "Name=%{name}" >> %{buildroot}%{_datarootdir}/applications/%{name}.desktop -echo "Icon=%{_datarootdir}/icons/highcolor/512x512/apps/%{name}.png" >> %{buildroot}%{_datarootdir}/applications/%{name}.desktop +echo "Icon=%{_datarootdir}/icons/hicolor/512x512/apps/%{name}.png" >> %{buildroot}%{_datarootdir}/applications/%{name}.desktop %clean rm -rf %{buildroot} @@ -208,7 +208,7 @@ echo "" %postun rm -v %{_datarootdir}/applications/%{name}.desktop -rm -v %{_datarootdir}/icons/highcolor/512x512/apps/%{name}.png +rm -v %{_datarootdir}/icons/hicolor/512x512/apps/%{name}.png echo "" echo " -------------" echo " !!!WARNING!!!" From 8392af09cb7346c63e5a1f37e1defa6de257e136 Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 20 Sep 2024 13:20:16 -0300 Subject: [PATCH 56/61] coveraged 46% of greetings screen --- e2e/test_001_greetings_screen.py | 139 ++++++++++++++++++++++++++-- src/app/screens/greetings_screen.py | 4 +- 2 files changed, 133 insertions(+), 10 deletions(-) diff --git a/e2e/test_001_greetings_screen.py b/e2e/test_001_greetings_screen.py index ea018d90..c59a3273 100644 --- a/e2e/test_001_greetings_screen.py +++ b/e2e/test_001_greetings_screen.py @@ -1,6 +1,8 @@ import os +import sys from pathlib import Path -from unittest.mock import patch +from unittest.mock import MagicMock, patch +from pytest import mark from kivy.base import EventLoop, EventLoopBase from kivy.tests.common import GraphicUnitTest from src.app.screens.greetings_screen import GreetingsScreen @@ -57,28 +59,147 @@ def test_on_enter(self, mock_schedule_once, mock_partial, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - def test_update_locale(self, mock_get_locale): + @patch( + "src.app.screens.greetings_screen.GreetingsScreen.check_permissions_for_dialout_group" + ) + def test_update_check_permission_screen( + self, mock_check_permissions, mock_get_locale + ): screen = GreetingsScreen() self.render(screen) # get your Window instance safely EventLoop.ensure_window() - screen.update(name="GreetingsScreen", key="locale", value="pt_BR.UTF-8") + screen.update(name=screen.name, key="check-permission") + + # patch assertions + mock_get_locale.assert_called_once() + mock_check_permissions.assert_called_once() + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.greetings_screen.GreetingsScreen.check_internet_connection") + def test_update_check_internet_connection( + self, mock_check_internet, mock_get_locale + ): + screen = GreetingsScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() - # default assertion - self.assertEqual(screen.locale, "pt_BR.UTF-8") + screen.update(name=screen.name, key="check-internet-connection") # patch assertions mock_get_locale.assert_called_once() + mock_check_internet.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - def test_update_canvas( + @patch("src.app.screens.base_screen.BaseScreen.manager") + @patch("src.app.screens.greetings_screen.Selector") + @patch("src.app.screens.greetings_screen.partial") + @patch("src.app.screens.greetings_screen.Clock.schedule_once") + @patch("src.app.screens.greetings_screen.GreetingsScreen.set_screen") + def test_check_internet_connection( self, + mock_set_screen, + mock_schedule_once, + mock_partial, + mock_selector, + mock_manager, mock_get_locale, + ): + mock_manager.get_screen = MagicMock() + mock_manager.get_screen.update = MagicMock() + mock_selector.return_value = MagicMock(releases=["v0.0.1"]) + screen = GreetingsScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + screen.update(name=screen.name, key="check-internet-connection") + + # patch assertions + mock_get_locale.assert_called_once() + mock_manager.get_screen.assert_called_once() + mock_partial.assert_called_once_with( + mock_manager.get_screen().update, + name="GreetingsScreen", + key="version", + value="v0.0.1", + ) + mock_schedule_once.assert_called() + mock_set_screen.assert_called_once_with(name="MainScreen", direction="left") + + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch( + "src.app.screens.greetings_screen.Selector", side_effect=[Exception("Mocked")] + ) + @patch("src.app.screens.greetings_screen.GreetingsScreen.redirect_exception") + def test_fail_check_internet_connection( + self, mock_redirect_exception, mock_selector, mock_get_locale + ): + screen = GreetingsScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + screen.update(name=screen.name, key="check-internet-connection") + + # patch assertions + mock_get_locale.assert_called_once() + mock_selector.assert_called() + mock_redirect_exception.assert_called() + + @patch("sys.platform", "win32") + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.greetings_screen.partial") + @patch("src.app.screens.greetings_screen.Clock.schedule_once") + def test_pass_check_permissions_not_linux( + self, mock_schedule_once, mock_partial, mock_get_locale + ): + screen = GreetingsScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + screen.update(name=screen.name, key="check-permission") + + # patch assertions + mock_get_locale.assert_called_once() + mock_partial.assert_called_once_with( + screen.update, name="GreetingsScreen", key="check-internet-connection" + ) + mock_schedule_once.assert_called() + + @mark.skipif( + sys.platform in ("win32", "darwin"), + reason="does not run on windows or darwin", + ) + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.app.screens.greetings_screen.os.environ.get", return_value="mockuser") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.greetings_screen.distro.id", return_value="mockos") + @patch("src.app.screens.greetings_screen.GreetingsScreen.redirect_exception") + def test_fail_check_permission_linux( + self, mock_redirect_exception, mock_distro_id, mock_get_locale, mock_environ_get ): screen = GreetingsScreen() self.render(screen) @@ -86,8 +207,10 @@ def test_update_canvas( # get your Window instance safely EventLoop.ensure_window() - # Do the tests - screen.update(name="GreetingsScreen", key="canvas") + screen.update(name=screen.name, key="check-permission") # patch assertions + mock_environ_get.assert_called_once() mock_get_locale.assert_called_once() + mock_distro_id.assert_called_once() + mock_redirect_exception.assert_called_once() diff --git a/src/app/screens/greetings_screen.py b/src/app/screens/greetings_screen.py index f47ade79..88ab9b5e 100644 --- a/src/app/screens/greetings_screen.py +++ b/src/app/screens/greetings_screen.py @@ -77,7 +77,7 @@ def update(self, *args, **kwargs): value = kwargs.get("value") def on_update(): - if key == "check-permission-screen": + if key == "check-permission": self.check_permissions_for_dialout_group() if key == "check-internet-connection": @@ -170,7 +170,7 @@ def check_internet_connection(self): main_screen = self.manager.get_screen("MainScreen") fn = partial( main_screen.update, - name="KruxInstallerApp", + name=self.name, key="version", value=selector.releases[0], ) From 49c3131351f6af3bc7a23fa0e01f8a61f54a470d Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 20 Sep 2024 13:32:49 -0300 Subject: [PATCH 57/61] coveraged 46% of greetings screen II --- e2e/test_001_greetings_screen.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/e2e/test_001_greetings_screen.py b/e2e/test_001_greetings_screen.py index c59a3273..2bef3d65 100644 --- a/e2e/test_001_greetings_screen.py +++ b/e2e/test_001_greetings_screen.py @@ -197,9 +197,15 @@ def test_pass_check_permissions_not_linux( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) @patch("src.app.screens.greetings_screen.distro.id", return_value="mockos") + @patch("src.app.screens.greetings_screen.distro.like", return_value="mockos") @patch("src.app.screens.greetings_screen.GreetingsScreen.redirect_exception") def test_fail_check_permission_linux( - self, mock_redirect_exception, mock_distro_id, mock_get_locale, mock_environ_get + self, + mock_redirect_exception, + mock_distro_like, + mock_distro_id, + mock_get_locale, + mock_environ_get, ): screen = GreetingsScreen() self.render(screen) @@ -210,7 +216,8 @@ def test_fail_check_permission_linux( screen.update(name=screen.name, key="check-permission") # patch assertions - mock_environ_get.assert_called_once() - mock_get_locale.assert_called_once() - mock_distro_id.assert_called_once() + mock_environ_get.assert_called() + mock_get_locale.assert_called() + mock_distro_id.assert_called() + mock_distro_like.assert_called() mock_redirect_exception.assert_called_once() From b8d5bca949c31a244b4ddea467b6856fcf398d37 Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 20 Sep 2024 19:59:03 -0300 Subject: [PATCH 58/61] coveraged 98% of greetings_screen fixed font size on greetings screen --- e2e/test_001_greetings_screen.py | 181 ++++++++++++++++-- .../screens/ask_permission_dialout_screen.py | 2 +- src/app/screens/greetings_screen.py | 20 +- src/app/screens/main_screen.py | 1 + 4 files changed, 180 insertions(+), 24 deletions(-) diff --git a/e2e/test_001_greetings_screen.py b/e2e/test_001_greetings_screen.py index 2bef3d65..bca2c3ff 100644 --- a/e2e/test_001_greetings_screen.py +++ b/e2e/test_001_greetings_screen.py @@ -59,11 +59,9 @@ def test_on_enter(self, mock_schedule_once, mock_partial, mock_get_locale): @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch( - "src.app.screens.greetings_screen.GreetingsScreen.check_permissions_for_dialout_group" - ) + @patch("src.app.screens.greetings_screen.GreetingsScreen.check_dialout_permission") def test_update_check_permission_screen( - self, mock_check_permissions, mock_get_locale + self, mock_check_permission, mock_get_locale ): screen = GreetingsScreen() self.render(screen) @@ -75,7 +73,7 @@ def test_update_check_permission_screen( # patch assertions mock_get_locale.assert_called_once() - mock_check_permissions.assert_called_once() + mock_check_permission.assert_called_once() @patch.object(EventLoopBase, "ensure_window", lambda x: None) @patch( @@ -169,7 +167,7 @@ def test_fail_check_internet_connection( ) @patch("src.app.screens.greetings_screen.partial") @patch("src.app.screens.greetings_screen.Clock.schedule_once") - def test_pass_check_permissions_not_linux( + def test_pass_check_dialout_permission_not_linux( self, mock_schedule_once, mock_partial, mock_get_locale ): screen = GreetingsScreen() @@ -196,28 +194,185 @@ def test_pass_check_permissions_not_linux( @patch( "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" ) - @patch("src.app.screens.greetings_screen.distro.id", return_value="mockos") - @patch("src.app.screens.greetings_screen.distro.like", return_value="mockos") + @patch("src.app.screens.greetings_screen.distro") @patch("src.app.screens.greetings_screen.GreetingsScreen.redirect_exception") def test_fail_check_permission_linux( self, mock_redirect_exception, - mock_distro_like, - mock_distro_id, + mock_distro, mock_get_locale, mock_environ_get, ): + mock_distro.id = MagicMock(return_value="mockos") + mock_distro.like = MagicMock(return_value="mockos") + mock_distro.name = MagicMock(return_value="MockOS") screen = GreetingsScreen() self.render(screen) # get your Window instance safely EventLoop.ensure_window() - screen.update(name=screen.name, key="check-permission") + screen.check_dialout_permission() # patch assertions mock_environ_get.assert_called() mock_get_locale.assert_called() - mock_distro_id.assert_called() - mock_distro_like.assert_called() + mock_distro.id.assert_called() + mock_distro.like.assert_called() + mock_distro.name.assert_called() mock_redirect_exception.assert_called_once() + + @mark.skipif( + sys.platform in ("win32", "darwin"), + reason="does not run on windows or darwin", + ) + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.app.screens.greetings_screen.os.environ.get", return_value="mockuser") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.greetings_screen.distro") + @patch("src.app.screens.greetings_screen.grp") + def test_check_permission_ubuntu_in_dialout( + self, + mock_grp, + mock_distro, + mock_get_locale, + mock_environ_get, + ): + mock_distro.id = MagicMock(return_value="ubuntu") + mock_grp.getgrall = MagicMock() + mock_grp.getgrall.return_value = [ + MagicMock( + gr_name="dialout", gr_passwd="x", gr_gid=1234, gr_mem=["mockuser"] + ) + ] + mock_grp.getgrall.return_value[0].__getitem__ = MagicMock( + return_value=["mock", "mock", "mockuser"] + ) + + screen = GreetingsScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + screen.check_dialout_permission() + + # patch assertions + mock_environ_get.assert_called() + mock_get_locale.assert_called() + mock_distro.id.assert_called() + mock_grp.getgrall.assert_called() + + @mark.skipif( + sys.platform in ("win32", "darwin"), + reason="does not run on windows or darwin", + ) + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.app.screens.greetings_screen.os.environ.get", return_value="mockuser") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.base_screen.BaseScreen.manager") + @patch("src.app.screens.greetings_screen.GreetingsScreen.set_screen") + @patch("src.app.screens.greetings_screen.distro") + @patch("src.app.screens.greetings_screen.grp") + @patch("src.app.screens.greetings_screen.partial") + @patch("src.app.screens.greetings_screen.Clock.schedule_once") + def test_check_permission_ubuntu_not_in_dialout( + self, + mock_schedule_once, + mock_partial, + mock_grp, + mock_distro, + mock_set_screen, + mock_manager, + mock_get_locale, + mock_environ_get, + ): + mock_manager.get_screen = MagicMock() + mock_distro.id = MagicMock(return_value="ubuntu") + mock_distro.name = MagicMock(return_value="Ubuntu") + mock_grp.getgrall = MagicMock() + mock_grp.getgrall.return_value = [ + MagicMock(gr_name="dialout", gr_passwd="x", gr_gid=1234, gr_mem=["mock"]) + ] + mock_grp.getgrall.return_value[0].__getitem__ = MagicMock( + return_value=["mock", "mock", "mock"] + ) + + screen = GreetingsScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + screen.check_dialout_permission() + + # patch assertions + mock_environ_get.assert_called() + mock_get_locale.assert_called() + mock_distro.id.assert_called() + mock_distro.name.assert_called() + mock_grp.getgrall.assert_called() + mock_manager.get_screen.assert_called() + mock_set_screen.assert_called() + mock_partial.assert_called() + mock_schedule_once.assert_called() + + @mark.skipif( + sys.platform in ("win32", "darwin"), + reason="does not run on windows or darwin", + ) + @patch.object(EventLoopBase, "ensure_window", lambda x: None) + @patch("src.app.screens.greetings_screen.os.environ.get", return_value="mockuser") + @patch( + "src.app.screens.base_screen.BaseScreen.get_locale", return_value="en_US.UTF-8" + ) + @patch("src.app.screens.base_screen.BaseScreen.manager") + @patch("src.app.screens.greetings_screen.GreetingsScreen.set_screen") + @patch("src.app.screens.greetings_screen.distro") + @patch("src.app.screens.greetings_screen.grp") + @patch("src.app.screens.greetings_screen.partial") + @patch("src.app.screens.greetings_screen.Clock.schedule_once") + def test_check_permission_arch_not_in_dialout( + self, + mock_schedule_once, + mock_partial, + mock_grp, + mock_distro, + mock_set_screen, + mock_manager, + mock_get_locale, + mock_environ_get, + ): + mock_manager.get_screen = MagicMock() + mock_distro.id = MagicMock(return_value="arch") + mock_distro.name = MagicMock(return_value="ArchLinux") + mock_grp.getgrall = MagicMock() + mock_grp.getgrall.return_value = [ + MagicMock(gr_name="uucp", gr_passwd="x", gr_gid=1234, gr_mem=["mock"]) + ] + mock_grp.getgrall.return_value[0].__getitem__ = MagicMock( + return_value=["mock", "mock", "mock"] + ) + + screen = GreetingsScreen() + self.render(screen) + + # get your Window instance safely + EventLoop.ensure_window() + + screen.check_dialout_permission() + + # patch assertions + mock_environ_get.assert_called() + mock_get_locale.assert_called() + mock_distro.id.assert_called() + mock_distro.name.assert_called() + mock_grp.getgrall.assert_called() + mock_manager.get_screen.assert_called() + mock_set_screen.assert_called() + mock_partial.assert_called() + mock_schedule_once.assert_called() diff --git a/src/app/screens/ask_permission_dialout_screen.py b/src/app/screens/ask_permission_dialout_screen.py index 2b129969..ba1a0158 100644 --- a/src/app/screens/ask_permission_dialout_screen.py +++ b/src/app/screens/ask_permission_dialout_screen.py @@ -97,7 +97,7 @@ def on_ref_press(*args): wid=f"{self.id}_label", text="", root_widget=f"{self.id}_grid", - font_factor=32, + font_factor=38, halign="justify", on_press=None, on_release=None, diff --git a/src/app/screens/greetings_screen.py b/src/app/screens/greetings_screen.py index 88ab9b5e..cfc98985 100644 --- a/src/app/screens/greetings_screen.py +++ b/src/app/screens/greetings_screen.py @@ -60,7 +60,7 @@ def on_enter(self, *args): redirect to MainScreen. """ fn_0 = partial(self.update, name=self.name, key="canvas") - fn_1 = partial(self.update, name=self.name, key="check-permission-screen") + fn_1 = partial(self.update, name=self.name, key="check-permission") Clock.schedule_once(fn_0, 0) Clock.schedule_once(fn_1, 2.1) @@ -78,7 +78,7 @@ def update(self, *args, **kwargs): def on_update(): if key == "check-permission": - self.check_permissions_for_dialout_group() + self.check_dialout_permission() if key == "check-internet-connection": self.check_internet_connection() @@ -92,7 +92,7 @@ def on_update(): on_update=getattr(GreetingsScreen, "on_update"), ) - def check_permissions_for_dialout_group(self): + def check_dialout_permission(self): """ Here's where the check process start first get the current user, then verify @@ -107,10 +107,10 @@ def check_permissions_for_dialout_group(self): _group = None # detect linux distro - if distro.id() in ("ubuntu", "fedora", "linuxmint"): - _group = "dialout" - - elif distro.like() == "debian": + if ( + distro.id() in ("ubuntu", "fedora", "linuxmint") + or distro.like() == "debian" + ): _group = "dialout" elif distro.id() in ("arch", "manjaro", "slackware", "gentoo"): @@ -119,22 +119,22 @@ def check_permissions_for_dialout_group(self): else: exc = RuntimeError(f"{distro.name(pretty=True)} not supported") self.redirect_exception(exception=exc) + return # loop throug all linux groups and check # if the user is registered in the "dialout" group for _grp in grp.getgrall(): if _group == _grp.gr_name: - self.debug(f"Found {_grp.gr_name}") for _grpuser in _grp[3]: - self.debug(_grpuser) if _grpuser == _user: - self.debug(f"'{_user}' already in group '{_group}'") + self.info(f"'{_user}' already in group '{_group}'") _in_dialout = True # if user is not in dialout group, warn user # and then redirect to a screen that will # proceed with the proper operation if not _in_dialout: + print("NOT") ask = self.manager.get_screen("AskPermissionDialoutScreen") _distro = distro.name(pretty=True) diff --git a/src/app/screens/main_screen.py b/src/app/screens/main_screen.py index b95d77c4..5ded5d11 100644 --- a/src/app/screens/main_screen.py +++ b/src/app/screens/main_screen.py @@ -490,6 +490,7 @@ def on_update(): allowed_screens=( "KruxInstallerApp", "ConfigKruxInstaller", + "GreetingsScreen", "MainScreen", "SelectDeviceScreen", "SelectVersionScreen", From 276149b2e651b9a2dc3a8c3469fb18a0d03064df Mon Sep 17 00:00:00 2001 From: qlrd Date: Fri, 20 Sep 2024 20:43:13 -0300 Subject: [PATCH 59/61] Updated CHANGELOG --- CHANGELOG.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce14686f..d846aa33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,15 +3,18 @@ ## 0.0.20-alpha-2 - Changed the version from `0.0.2-alpha` to `0.0.20-alpha-2` as suggested by @odudex; +- Refactored the code a little bit to be more pythonic; - Removed startup messages as suggested by @tadeubas: - On linux the `GreetingsScreen` class will check: - - if user is on `dialout`/`uucp` group; + - if user is on `dialout`/`uucp` group (debian and fedora based / archlinux); - internet connection - On MacOS an Windows the `GreetingsScreen` class will check: - internet connection -- Added a line on `.ci/create-deb` for add user to `input` on debian-based systems where - require permissions for `/dev/input/eventX` (thanks to @theautumnbridge); -- Refactored the code a little bit to be more pythonic one; +- Added the window resize behaviour; +- Removed fullscreen on startup; +- Fedora and Ubuntu: + - fixed desktop icon entry on `.ci/create-deb`; + - fixed desktop icon entry on `.ci/create-rpm`; - Added more tests: - ask_permissions_dialout_screen; - error_screen. From 53db60d6cdf9746b54a40477bdd15c3172606ce5 Mon Sep 17 00:00:00 2001 From: qlrd Date: Sat, 21 Sep 2024 08:30:27 -0300 Subject: [PATCH 60/61] reverted CHANGELOG removed .pylintrc, TODO and .gitignore from CI workflow --- .github/workflows/ci.yml | 5 +---- CHANGELOG.md | 19 ------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 53afb846..49e7facc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,14 +39,11 @@ jobs: let workflowFailMessage = "It looks like you've modified some files that we can't accept as contributions." try { const badFilesArr = [ - '.gitignore', - '.pylintrc', - 'TODO.md', 'CHANGELOG.md', 'LICENSE' ] const badFiles = badFilesArr.join('\n- ') - const reviewMessage = `👋 Hey there kruxer. It looks like you've modified some files that we can't accept as contributions. The complete list of files we can't accept are:\n- ${badFiles}\n\nYou'll need to revert all of the files you changed in that list using [GitHub Desktop](https://docs.github.com/en/free-pro-team@latest/desktop/contributing-and-collaborating-using-github-desktop/managing-commits/reverting-a-commit) or \`git checkout origin/main \`. Once you get those files reverted, we can continue with the review process. :octocat:\n\nMore discussion:\n- https://github.com/electron-vite/electron-vite-vue/issues/192` + const reviewMessage = `👋 Hey there kruxer. It looks like you've modified some files that we can't accept as contributions. The complete list of files we can't accept are:\n- ${badFiles}\n\nYou'll need to revert all of the files you changed in that list using [GitHub Desktop](https://docs.github.com/en/free-pro-team@latest/desktop/contributing-and-collaborating-using-github-desktop/managing-commits/reverting-a-commit) or \`git checkout origin/main \`. Once you get those files reverted, we can continue with the review process. :octocat:` createdComment = await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/CHANGELOG.md b/CHANGELOG.md index d846aa33..0dea23d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,24 +1,5 @@ # CHANGELOG -## 0.0.20-alpha-2 - -- Changed the version from `0.0.2-alpha` to `0.0.20-alpha-2` as suggested by @odudex; -- Refactored the code a little bit to be more pythonic; -- Removed startup messages as suggested by @tadeubas: - - On linux the `GreetingsScreen` class will check: - - if user is on `dialout`/`uucp` group (debian and fedora based / archlinux); - - internet connection - - On MacOS an Windows the `GreetingsScreen` class will check: - - internet connection -- Added the window resize behaviour; -- Removed fullscreen on startup; -- Fedora and Ubuntu: - - fixed desktop icon entry on `.ci/create-deb`; - - fixed desktop icon entry on `.ci/create-rpm`; -- Added more tests: - - ask_permissions_dialout_screen; - - error_screen. - ## 0.0.2-alpha - code refactoration from `nodejs` to `python`; From 7eaf2ac6422cf539c4f5ff91c3027a5de5bc9989 Mon Sep 17 00:00:00 2001 From: qlrd Date: Sat, 21 Sep 2024 08:44:49 -0300 Subject: [PATCH 61/61] Fixed README --- .github/workflows/ci.yml | 3 --- README.md | 52 +++++++++------------------------------- 2 files changed, 11 insertions(+), 44 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49e7facc..eb47215d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,9 +24,6 @@ jobs: list-files: json filters: | change: - - '.gitignore' - - '.pylintrc' - - 'TODO.md' - 'CHANGELOG.md' - 'LICENSE' diff --git a/README.md b/README.md index 356b9f7e..42d6d587 100644 --- a/README.md +++ b/README.md @@ -54,17 +54,13 @@ Follow the instructions at [python.org](https://www.python.org/downloads/windows Before installing `krux-installer` source code, you will need prepare the system: -

-Install `brew` package manager +#### Install `brew` package manager ```bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` -
- -
-Install latest python +#### Install latest python ```bash brew install python @@ -76,10 +72,7 @@ and add this line to your `~/.zshrc`: alias python=python3 ``` -
- -
- Ensure openssl have a correct link +#### Ensure openssl have a correct link Python's `ssl` module relies on OpenSSL for cryptographic operations. Ensure that OpenSSL is installed on your system and is compatible with the @@ -101,10 +94,8 @@ brew link --force openssl This ensures that the OpenSSL libraries are available in the expected locations that Python can find and use. -
-
-Patch your zshrc +#### Patch your zshrc Library paths on MacOS involves verifying that the environment variables and system configurationsare correctyly set to find the necessary libraries, such as OpenSSL, @@ -124,8 +115,6 @@ OPENSSL_FULL_VERSION=`openssl --version | awk ' { print $2}'` export DYLD_LIBRARY_PATH="/opt/homebrew/Cellar/openssl@$OPENSSL_MAJOR_VERSION/$OPENSSL_FULL_VERSION/lib:$DYLD_LIBRARY_PATH" ``` -
- ### Install poetry Make sure you have `poetry` installed: @@ -165,35 +154,25 @@ git submodule update --init Krux-Installer uses `poe` task manager for formatting, linting, tests, coverage and build. -
-See all available tasks +### See all available tasks ```bash poetry run poe ``` -
- -
-Format code +### Format code ```bash poetry run poe format ``` -
- -
-Lint +### Lint ```bash poetry run poe lint ``` -
- -
-Test and coverage +### Test and coverage ```bash poetry run poe test @@ -209,28 +188,20 @@ poetry run poe test --no-xvfb You can see all coverage results opening you browser and type `file:////krux-installer/htmlcov/index.html` (assuming `folder` is where you placed the `krux-installer` project). -
-
-Build for any Linux distribution +### Build for any Linux distribution ```bash poetry run poe build-linux ``` -
- -
-Build for MacOS +### Build for MacOS ```bash poetry run poe build-macos ``` -
- -
-Build for Windows +### Build for Windows ```bash poetry run poe build-win @@ -245,4 +216,3 @@ It will export all project in a To more options see [.ci/create-spec.py](./.ci/create-spec.py) against the PyInstaller [options](https://pyinstaller.org). -