diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0c020d7..b0a2fd9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ env: jobs: push-ghcr: name: Build and push image - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 permissions: contents: read packages: write @@ -21,12 +21,12 @@ jobs: strategy: fail-fast: false matrix: - major_version: [38, 39] + major_version: [39, 40] include: - - major_version: 38 - is_latest_version: true - is_stable_version: true - major_version: 39 + is_latest_version: false + is_stable_version: true + - major_version: 40 is_latest_version: true is_stable_version: false steps: @@ -139,21 +139,3 @@ jobs: if: github.event_name != 'pull_request' run: | echo "${{ toJSON(steps.push.outputs) }}" - - copr-build: - permissions: - contents: read - packages: read - runs-on: ubuntu-latest - container: - image: ghcr.io/akdev1l/copr-build:latest - if: github.event_name != 'pull_request' - steps: - - name: trigger copr build - uses: akdev1l/copr-build@main - id: copr-build - env: - COPR_API_TOKEN_CONFIG: ${{ secrets.UBLUE_COPR_API_TOKEN }} - with: - owner: ublue-os - project-name: staging diff --git a/Containerfile.builder b/Containerfile.builder index df05bcc..f820f85 100644 --- a/Containerfile.builder +++ b/Containerfile.builder @@ -6,6 +6,8 @@ WORKDIR /app ADD . /app +RUN dnf install python3-pip && pip install topgrade + RUN dnf install \ --disablerepo='*' \ --enablerepo='fedora,updates' \ diff --git a/README.md b/README.md index 13b6ee5..647bcae 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Small update program written in python intended for use in Universal Blue that u Includes systemd timers and services for auto update -dependencies (fedora): ```sudo dnf install python3-psutil libnotify``` +dependencies (fedora): ```sudo dnf install python3-psutil libnotify && pip install topgrade``` # Usage @@ -16,14 +16,14 @@ You can add this to your image by simply pulling down and installing the rpm: ``` COPY --from=ghcr.io/ublue-os/ublue-update:latest /rpms/ublue-update.noarch.rpm /tmp/rpms/ -RUN rpm-ostree install /tmp/rpms/ublue-update.noarch.rpm +RUN pip install topgrade && rpm-ostree install /tmp/rpms/ublue-update.noarch.rpm ``` If you are on an image derived from uBlue main: ``` COPY --from=ghcr.io/ublue-os/ublue-update:latest /rpms/ublue-update.noarch.rpm /tmp/rpms/ -RUN rpm-ostree override remove ublue-os-update-services && rpm-ostree install /tmp/rpms/ublue-update.noarch.rpm +RUN pip install topgrade && rpm-ostree override remove ublue-os-update-services && rpm-ostree install /tmp/rpms/ublue-update.noarch.rpm ``` > **Note** diff --git a/src/ublue_update/cli.py b/src/ublue_update/cli.py index e46987f..5650ec3 100644 --- a/src/ublue_update/cli.py +++ b/src/ublue_update/cli.py @@ -127,9 +127,7 @@ def run_updates(system, system_update_available): log.debug(out.stdout.decode("utf-8")) if out.returncode != 0: - print( - f"topgrade returned code {out.returncode}, program output:" - ) + print(f"topgrade returned code {out.returncode}, program output:") print(out.stdout.decode("utf-8")) os._exit(out.returncode) @@ -140,9 +138,7 @@ def run_updates(system, system_update_available): except KeyError as e: log.error(f"failed to get xdg_runtime_dir for user: {user['Name']}", e) break - log.info( - f"""Running update for user: '{user['Name']}'""" - ) + log.info(f"""Running update for user: '{user['Name']}'""") out = subprocess.run( [ @@ -211,10 +207,7 @@ def main(): action="store_true", help="wait for transactions to complete and exit", ) - parser.add_argument( - "--config", - help="use the specified config file" - ) + parser.add_argument("--config", help="use the specified config file") parser.add_argument( "--system", action="store_true", diff --git a/src/ublue_update/update_inhibitors/custom.py b/src/ublue_update/update_inhibitors/custom.py index cb83398..6b85468 100644 --- a/src/ublue_update/update_inhibitors/custom.py +++ b/src/ublue_update/update_inhibitors/custom.py @@ -1,4 +1,3 @@ -import psutil import subprocess from typing import List, Optional from logging import getLogger @@ -9,22 +8,28 @@ def run_custom_check_script(script) -> dict: - if 'run' in script and 'shell' not in script: - raise Exception('checks.scripts.*: \'shell\' must be specified when \'run\' is used') + if "run" in script and "shell" not in script: + raise Exception( + "checks.scripts.*: 'shell' must be specified when 'run' is used" + ) - if 'run' in script and 'file' in script: - raise Exception('checks.scripts.*: Only one of \'run\' and \'file\' must be set for a given script') + if "run" in script and "file" in script: + raise Exception( + "checks.scripts.*: Only one of 'run' and 'file' must be set for a given script" + ) log.debug(f"Running script {script}") # Run the specified custom script - if 'run' in script: - run_args = [script['shell'], '-c', script['run']] - elif 'shell' in script: - run_args = [script['shell'], script['file']] + if "run" in script: + run_args = [script["shell"], "-c", script["run"]] + elif "shell" in script: + run_args = [script["shell"], script["file"]] else: - run_args = [script['file']] - script_result = subprocess.run(run_args, capture_output=True, text=True, check=False) + run_args = [script["file"]] + script_result = subprocess.run( + run_args, capture_output=True, text=True, check=False + ) # An exit code of 0 means "OK", a non-zero exit code # means "Do not download or perform updates right now" @@ -40,10 +45,12 @@ def run_custom_check_script(script) -> dict: # to catch any interpreter errors etc. script_stderr = script_result.stderr.strip() if not script_pass and len(script_stderr) > 0: - log.warning(f"A custom check script failed and wrote the following to STDERR:\n====\n{script_stderr}\n====") + log.warning( + f"A custom check script failed and wrote the following to STDERR:\n====\n{script_stderr}\n====" + ) fallback_message = "A custom check script returned a non-0 exit code" - script_message = script.get('message') or script_output or fallback_message + script_message = script.get("message") or script_output or fallback_message return { "passed": script_pass, @@ -53,13 +60,12 @@ def run_custom_check_script(script) -> dict: def run_custom_check_scripts() -> List[dict]: results = [] - for script in (cfg.custom_check_scripts or []): + for script in cfg.custom_check_scripts or []: results.append(run_custom_check_script(script)) return results def check_custom_inhibitors() -> bool: - custom_inhibitors = run_custom_check_scripts() failures = [] diff --git a/src/ublue_update/update_inhibitors/hardware.py b/src/ublue_update/update_inhibitors/hardware.py index c3f77e1..81b42c3 100644 --- a/src/ublue_update/update_inhibitors/hardware.py +++ b/src/ublue_update/update_inhibitors/hardware.py @@ -1,6 +1,5 @@ import psutil import subprocess -from typing import Optional from logging import getLogger from ublue_update.config import cfg @@ -29,7 +28,8 @@ def check_network_not_metered() -> dict: # Use busctl CLI to query the NetworkManager via D-Bus for # the current metering status of the connection. # The output on stdout will be " ". - metered_status = subprocess.run([ + metered_status = subprocess.run( + [ "busctl", "get-property", "org.freedesktop.NetworkManager", @@ -50,7 +50,7 @@ def check_network_not_metered() -> dict: # NM_METERED_GUESS_YES = 3 # Metered, the value was guessed # NM_METERED_GUESS_NO = 4 # Not metered, the value was guessed # - is_network_metered = metered_status.strip() in ['u 1', 'u 3'] + is_network_metered = metered_status.strip() in ["u 1", "u 3"] return { "passed": not is_network_metered, "message": "Network is metered", @@ -65,7 +65,8 @@ def check_battery_status() -> dict: battery_pass: bool = True if battery_status is not None: battery_pass = ( - battery_status.percent >= cfg.min_battery_percent or battery_status.power_plugged + battery_status.percent >= cfg.min_battery_percent + or battery_status.power_plugged ) return { "passed": battery_pass, @@ -109,7 +110,6 @@ def check_mem_percentage() -> dict: def check_hardware_inhibitors() -> bool: - hardware_inhibitors = [ check_network_status(), check_network_not_metered(),