From 6f7e469e66ac4fe94ec44d31ea890aeb27d237d5 Mon Sep 17 00:00:00 2001 From: Angel <157843979+Angel-Karasu@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:37:04 +0200 Subject: [PATCH] Code refactoring, more readable and easier to modify (#736) * Add global variables * Add global variables * Code refactoring * Refactoring --- auto_cpufreq/__init__.py | 0 auto_cpufreq/battery_scripts/battery.py | 26 +- auto_cpufreq/battery_scripts/ideapad_acpi.py | 11 +- .../battery_scripts/ideapad_laptop.py | 13 +- auto_cpufreq/battery_scripts/thinkpad.py | 9 +- auto_cpufreq/bin/__init__.py | 0 auto_cpufreq/bin/auto_cpufreq.py | 218 ++--- auto_cpufreq/bin/auto_cpufreq_gtk.py | 7 +- auto_cpufreq/{utils => config}/config.py | 15 +- auto_cpufreq/config/config_event_handler.py | 23 + auto_cpufreq/core.py | 915 ++++-------------- auto_cpufreq/globals.py | 12 + auto_cpufreq/gui/__init__.py | 0 auto_cpufreq/gui/app.py | 25 +- auto_cpufreq/gui/objects.py | 32 +- auto_cpufreq/gui/tray.py | 2 - auto_cpufreq/power_helper.py | 48 +- auto_cpufreq/utils/__init__.py | 0 auto_cpufreq/utils/config_event_handler.py | 29 - nix/patches/prevent-install-and-copy.patch | 73 +- 20 files changed, 456 insertions(+), 1002 deletions(-) delete mode 100644 auto_cpufreq/__init__.py delete mode 100644 auto_cpufreq/bin/__init__.py rename auto_cpufreq/{utils => config}/config.py (89%) create mode 100644 auto_cpufreq/config/config_event_handler.py create mode 100644 auto_cpufreq/globals.py delete mode 100644 auto_cpufreq/gui/__init__.py delete mode 100644 auto_cpufreq/utils/__init__.py delete mode 100644 auto_cpufreq/utils/config_event_handler.py diff --git a/auto_cpufreq/__init__.py b/auto_cpufreq/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/auto_cpufreq/battery_scripts/battery.py b/auto_cpufreq/battery_scripts/battery.py index 14c02970..2e85c6a4 100644 --- a/auto_cpufreq/battery_scripts/battery.py +++ b/auto_cpufreq/battery_scripts/battery.py @@ -1,20 +1,20 @@ #!/usr/bin/env python3 -import subprocess +from subprocess import PIPE, run -from auto_cpufreq.battery_scripts.thinkpad import thinkpad_setup, thinkpad_print_thresholds -from auto_cpufreq.battery_scripts.ideapad_acpi import ideapad_acpi_setup, ideapad_acpi_print_thresholds -from auto_cpufreq.battery_scripts.ideapad_laptop import ideapad_laptop_setup, ideapad_laptop_print_thresholds +from auto_cpufreq.battery_scripts.ideapad_acpi import ideapad_acpi_print_thresholds, ideapad_acpi_setup +from auto_cpufreq.battery_scripts.ideapad_laptop import ideapad_laptop_print_thresholds, ideapad_laptop_setup +from auto_cpufreq.battery_scripts.thinkpad import thinkpad_print_thresholds, thinkpad_setup -def lsmod(module): return module in subprocess.run(['lsmod'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True).stdout - -def battery_setup(): - if lsmod("thinkpad_acpi"): thinkpad_setup() - elif lsmod("ideapad_acpi"): ideapad_acpi_setup() - elif lsmod("ideapad_laptop"): ideapad_laptop_setup() - else: return +def lsmod(module): return module in run(['lsmod'], stdout=PIPE, stderr=PIPE, text=True).stdout def battery_get_thresholds(): - if lsmod("thinkpad_acpi"): thinkpad_print_thresholds() - elif lsmod("ideapad_acpi"): ideapad_acpi_print_thresholds() + if lsmod("ideapad_acpi"): ideapad_acpi_print_thresholds() elif lsmod("ideapad_laptop"): ideapad_laptop_print_thresholds() + elif lsmod("thinkpad_acpi"): thinkpad_print_thresholds() + else: return + +def battery_setup(): + if lsmod("ideapad_acpi"): ideapad_acpi_setup() + elif lsmod("ideapad_laptop"): ideapad_laptop_setup() + elif lsmod("thinkpad_acpi"): thinkpad_setup() else: return diff --git a/auto_cpufreq/battery_scripts/ideapad_acpi.py b/auto_cpufreq/battery_scripts/ideapad_acpi.py index ae783581..966132ce 100644 --- a/auto_cpufreq/battery_scripts/ideapad_acpi.py +++ b/auto_cpufreq/battery_scripts/ideapad_acpi.py @@ -1,9 +1,8 @@ #!/usr/bin/env python3 -import os -import subprocess -from auto_cpufreq.utils.config import config +import os, subprocess -POWER_SUPPLY_DIR = "/sys/class/power_supply/" +from auto_cpufreq.config.config import config +from auto_cpufreq.globals import POWER_SUPPLY_DIR def set_battery(value, mode, bat): path = f"{POWER_SUPPLY_DIR}{bat}/charge_{mode}_threshold" @@ -25,7 +24,7 @@ def ideapad_acpi_setup(): for bat in batteries: set_battery(get_threshold_value("start"), "start", bat) set_battery(get_threshold_value("stop"), "stop", bat) - else: print(f"WARNING: could NOT access {POWER_SUPPLY_DIR}") + else: print("WARNING: could NOT access", POWER_SUPPLY_DIR) def ideapad_acpi_print_thresholds(): batteries = [name for name in os.listdir(POWER_SUPPLY_DIR) if name.startswith('BAT')] @@ -35,4 +34,4 @@ def ideapad_acpi_print_thresholds(): try: print(f'{bat} start threshold = {subprocess.getoutput(f"cat {POWER_SUPPLY_DIR}{bat}/charge_start_threshold")}') print(f'{bat} start threshold = {subprocess.getoutput(f"cat {POWER_SUPPLY_DIR}{bat}/charge_stop_threshold")}') - except Exception as e: print(f"ERROR: failed to read battery {bat} thresholds: ", repr(e)) + except Exception as e: print(f"ERROR: failed to read battery {bat} thresholds:", repr(e)) diff --git a/auto_cpufreq/battery_scripts/ideapad_laptop.py b/auto_cpufreq/battery_scripts/ideapad_laptop.py index 9d724d24..03001626 100644 --- a/auto_cpufreq/battery_scripts/ideapad_laptop.py +++ b/auto_cpufreq/battery_scripts/ideapad_laptop.py @@ -1,9 +1,8 @@ #!/usr/bin/env python3 -import os -import subprocess -from auto_cpufreq.utils.config import config +import os, subprocess -POWER_SUPPLY_DIR = "/sys/class/power_supply/" +from auto_cpufreq.config.config import config +from auto_cpufreq.globals import CONSERVATION_MODE_FILE, POWER_SUPPLY_DIR def set_battery(value, mode, bat): path = f"{POWER_SUPPLY_DIR}{bat}/charge_{mode}_threshold" @@ -17,14 +16,14 @@ def get_threshold_value(mode): def conservation_mode(value): try: - subprocess.check_output(f"echo {value} | tee /sys/bus/platform/drivers/ideapad_acpi/VPC2004:00/conservation_mode", shell=True, text=True) + subprocess.check_output(f"echo {value} | tee {CONSERVATION_MODE_FILE}", shell=True, text=True) print(f"conservation_mode is {value}") except: print("unable to set conservation mode") return def check_conservation_mode(): try: - value = subprocess.check_output("cat /sys/bus/platform/drivers/ideapad_acpi/VPC2004:00/conservation_mode", shell=True, text=True) + value = subprocess.check_output(["cat", CONSERVATION_MODE_FILE], text=True) if value == "1": return True elif value == "0": return False else: @@ -66,4 +65,4 @@ def ideapad_laptop_print_thresholds(): try: print(f'{bat} start threshold = {subprocess.getoutput(f"cat {POWER_SUPPLY_DIR}{bat}/charge_start_threshold")}') print(f'{bat} start threshold = {subprocess.getoutput(f"cat {POWER_SUPPLY_DIR}{bat}/charge_stop_threshold")}') - except Exception as e: print(f"ERROR: failed to read battery {bat} thresholds: ", repr(e)) + except Exception as e: print(f"ERROR: failed to read battery {bat} thresholds:", repr(e)) diff --git a/auto_cpufreq/battery_scripts/thinkpad.py b/auto_cpufreq/battery_scripts/thinkpad.py index a37500bc..04a10df1 100644 --- a/auto_cpufreq/battery_scripts/thinkpad.py +++ b/auto_cpufreq/battery_scripts/thinkpad.py @@ -1,9 +1,8 @@ #!/usr/bin/env python3 -import os -import subprocess -from auto_cpufreq.utils.config import config +import os, subprocess -POWER_SUPPLY_DIR = "/sys/class/power_supply/" +from auto_cpufreq.config.config import config +from auto_cpufreq.globals import POWER_SUPPLY_DIR def set_battery(value, mode, bat): path = f"{POWER_SUPPLY_DIR}{bat}/charge_{mode}_threshold" @@ -36,4 +35,4 @@ def thinkpad_print_thresholds(): try: print(f'{bat} start threshold = {subprocess.getoutput(f"cat {POWER_SUPPLY_DIR}{bat}/charge_start_threshold")}') print(f'{bat} start threshold = {subprocess.getoutput(f"cat {POWER_SUPPLY_DIR}{bat}/charge_stop_threshold")}') - except Exception as e: print(f"ERROR: failed to read battery {bat} thresholds: ", repr(e)) + except Exception as e: print(f"ERROR: failed to read battery {bat} thresholds:", repr(e)) diff --git a/auto_cpufreq/bin/__init__.py b/auto_cpufreq/bin/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/auto_cpufreq/bin/auto_cpufreq.py b/auto_cpufreq/bin/auto_cpufreq.py index 55331379..15849ca8 100755 --- a/auto_cpufreq/bin/auto_cpufreq.py +++ b/auto_cpufreq/bin/auto_cpufreq.py @@ -5,36 +5,32 @@ # Blog post: https://foolcontrol.org/?p=3124 # core import -import sys -import time -from click import UsageError -from subprocess import call, run +import sys, time +from subprocess import run from shutil import rmtree -# sys.path.append("../") +from auto_cpufreq.battery_scripts.battery import * +from auto_cpufreq.config.config import config as conf, find_config_file from auto_cpufreq.core import * +from auto_cpufreq.globals import GITHUB, IS_INSTALLED_WITH_AUR, IS_INSTALLED_WITH_SNAP from auto_cpufreq.power_helper import * -from auto_cpufreq.battery_scripts.battery import * -from auto_cpufreq.utils.config import config as conf, find_config_file -# cli + @click.command() @click.option("--monitor", is_flag=True, help="Monitor and see suggestions for CPU optimizations") @click.option("--live", is_flag=True, help="Monitor and make (temp.) suggested CPU optimizations") +@click.option("--daemon", is_flag=True, hidden=True) @click.option("--install", is_flag=True, help="Install daemon for (permanent) automatic CPU optimizations") @click.option("--update", is_flag=False, help="Update daemon and package for (permanent) automatic CPU optimizations", flag_value="--update") @click.option("--remove", is_flag=True, help="Remove daemon for (permanent) automatic CPU optimizations") - -@click.option("--stats", is_flag=True, help="View live stats of CPU optimizations made by daemon") @click.option("--force", is_flag=False, help="Force use of either \"powersave\" or \"performance\" governors. Setting to \"reset\" will go back to normal mode") -@click.option("--get-state", is_flag=True, hidden=True) @click.option("--config", is_flag=False, required=False, help="Use config file at defined path",) +@click.option("--stats", is_flag=True, help="View live stats of CPU optimizations made by daemon") +@click.option("--get-state", is_flag=True, hidden=True) +@click.option("--completions", is_flag=False, help="Enables shell completions for bash, zsh and fish.\n Possible values bash|zsh|fish") @click.option("--debug", is_flag=True, help="Show debug info (include when submitting bugs)") @click.option("--version", is_flag=True, help="Show currently installed version") @click.option("--donate", is_flag=True, help="Support the project") -@click.option("--completions", is_flag=False, help="Enables shell completions for bash, zsh and fish.\n Possible values bash|zsh|fish") -@click.option("--log", is_flag=True, hidden=True) -@click.option("--daemon", is_flag=True, hidden=True) -def main(config, daemon, debug, update, install, remove, live, log, monitor, stats, version, donate, force, get_state, completions): +def main(monitor, live, daemon, install, update, remove, force, config, stats, get_state, completions, debug, version, donate): # display info if config file is used config_path = find_config_file(config) conf.set_path(config_path) @@ -42,12 +38,6 @@ def config_info_dialog(): if conf.has_config(): print("\nUsing settings defined in " + config_path + " file") - # set governor override unless None or invalid - if force is not None: - not_running_daemon_check() - root_check() # Calling root_check before set_override as it will require sudo access - set_override(force) # Calling set override, only if force has some values - if len(sys.argv) == 1: print("\n" + "-" * 32 + " auto-cpufreq " + "-" * 33 + "\n") print("Automatic CPU speed & power optimizer for Linux") @@ -58,37 +48,20 @@ def config_info_dialog(): run(["auto-cpufreq", "--help"]) footer() else: - if daemon: - config_info_dialog() - root_check() - file_stats() - if os.getenv("PKG_MARKER") == "SNAP" and dcheck == "enabled": - gnome_power_detect_snap() - tlp_service_detect_snap() - elif os.getenv("PKG_MARKER") != "SNAP": - gnome_power_detect() - tlp_service_detect() - battery_setup() - conf.notifier.start() - while True: - try: - footer() - gov_check() - cpufreqctl() - distro_info() - sysinfo() - set_autofreq() - countdown(2) - except KeyboardInterrupt: break - conf.notifier.stop() - elif monitor: + # set governor override unless None or invalid + if force is not None: + not_running_daemon_check() + root_check() # Calling root_check before set_override as it will require sudo access + set_override(force) # Calling set override, only if force has some values + + if monitor: config_info_dialog() root_check() print('\nNote: You can quit monitor mode by pressing "ctrl+c"') battery_setup() battery_get_thresholds() conf.notifier.start() - if os.getenv("PKG_MARKER") == "SNAP": + if IS_INSTALLED_WITH_SNAP: gnome_power_detect_snap() tlp_service_detect_snap() else: @@ -115,7 +88,7 @@ def config_info_dialog(): battery_setup() battery_get_thresholds() conf.notifier.start() - if os.getenv("PKG_MARKER") == "SNAP": + if IS_INSTALLED_WITH_SNAP: gnome_power_detect_snap() tlp_service_detect_snap() else: @@ -137,59 +110,32 @@ def config_info_dialog(): print() break conf.notifier.stop() - elif stats: - not_running_daemon_check() + elif daemon: config_info_dialog() - print('\nNote: You can quit stats mode by pressing "ctrl+c"') - if os.getenv("PKG_MARKER") == "SNAP": + root_check() + file_stats() + if IS_INSTALLED_WITH_SNAP and dcheck == "enabled": gnome_power_detect_snap() tlp_service_detect_snap() - else: + elif not IS_INSTALLED_WITH_SNAP: gnome_power_detect() tlp_service_detect() - battery_get_thresholds() - read_stats() - elif log: deprecated_log_msg() - elif get_state: - not_running_daemon_check() - override = get_override() - print(override) - elif debug: - # ToDo: add status of GNOME Power Profile service status - config_info_dialog() - root_check() - battery_get_thresholds() - cpufreqctl() - footer() - distro_info() - sysinfo() - print() - app_version() - print() - python_info() - print() - device_info() - print(f"Battery is: {'' if charging() else 'dis'}charging") - print() - app_res_use() - display_load() - get_current_gov() - get_turbo() - footer() - elif version: - footer() - distro_info() - app_version() - footer() - elif donate: - footer() - print("If auto-cpufreq helped you out and you find it useful ...\n") - print("Show your appreciation by donating!") - print("https://github.com/AdnanHodzic/auto-cpufreq/#donate") - footer() + battery_setup() + conf.notifier.start() + while True: + try: + footer() + gov_check() + cpufreqctl() + distro_info() + sysinfo() + set_autofreq() + countdown(2) + except KeyboardInterrupt: break + conf.notifier.stop() elif install: root_check() - if os.getenv("PKG_MARKER") == "SNAP": + if IS_INSTALLED_WITH_SNAP: running_daemon_check() gnome_power_detect_snap() tlp_service_detect_snap() @@ -202,22 +148,6 @@ def config_info_dialog(): gov_check() deploy_daemon() deploy_complete_msg() - elif remove: - root_check() - if os.getenv("PKG_MARKER") == "SNAP": - run("snapctl set daemon=disabled", shell=True) - run("snapctl stop --disable auto-cpufreq", shell=True) - if auto_cpufreq_stats_path.exists(): - if auto_cpufreq_stats_file is not None: - auto_cpufreq_stats_file.close() - - auto_cpufreq_stats_path.unlink() - # ToDo: - # {the following snippet also used in --update, update it there too(if required)} - # * undo bluetooth boot disable - gnome_power_rm_reminder_snap() - else: remove_daemon() - remove_complete_msg() elif update: root_check() custom_dir = "/opt/auto-cpufreq/source" @@ -231,15 +161,14 @@ def config_info_dialog(): sys.argv.remove("--update") if len(sys.argv) == 2: custom_dir = sys.argv[1] - if os.getenv("PKG_MARKER") == "SNAP": + if IS_INSTALLED_WITH_SNAP: print("Detected auto-cpufreq was installed using snap") # refresh snap directly using this command # path wont work in this case print("Please update using snap package manager, i.e: `sudo snap refresh auto-cpufreq`.") #check for AUR - elif subprocess.run(["bash", "-c", "command -v pacman >/dev/null 2>&1"]).returncode == 0 and subprocess.run(["bash", "-c", "pacman -Q auto-cpufreq >/dev/null 2>&1"]).returncode == 0: - print("Arch-based distribution with AUR support detected. Please refresh auto-cpufreq using your AUR helper.") + elif IS_INSTALLED_WITH_AUR: print("Arch-based distribution with AUR support detected. Please refresh auto-cpufreq using your AUR helper.") else: is_new_update = check_for_update() if not is_new_update: return @@ -255,6 +184,38 @@ def config_info_dialog(): print("auto-cpufreq is installed with the latest version") run(["auto-cpufreq", "--version"]) else: print("Aborted") + elif remove: + root_check() + if IS_INSTALLED_WITH_SNAP: + run("snapctl set daemon=disabled", shell=True) + run("snapctl stop --disable auto-cpufreq", shell=True) + if auto_cpufreq_stats_path.exists(): + if auto_cpufreq_stats_file is not None: + auto_cpufreq_stats_file.close() + + auto_cpufreq_stats_path.unlink() + # ToDo: + # {the following snippet also used in --update, update it there too(if required)} + # * undo bluetooth boot disable + gnome_power_rm_reminder_snap() + else: remove_daemon() + remove_complete_msg() + elif stats: + not_running_daemon_check() + config_info_dialog() + print('\nNote: You can quit stats mode by pressing "ctrl+c"') + if IS_INSTALLED_WITH_SNAP: + gnome_power_detect_snap() + tlp_service_detect_snap() + else: + gnome_power_detect() + tlp_service_detect() + battery_get_thresholds() + read_stats() + elif get_state: + not_running_daemon_check() + override = get_override() + print(override) elif completions: if completions == "bash": print("Run the below command in your current shell!\n") @@ -268,5 +229,38 @@ def config_info_dialog(): print("Run the below command in your current shell!\n") print("echo '_AUTO_CPUFREQ_COMPLETE=fish_source auto-cpufreq | source' > ~/.config/fish/completions/auto-cpufreq.fish") else: print("Invalid Option, try bash|zsh|fish as argument to --completions") + elif debug: + # ToDo: add status of GNOME Power Profile service status + config_info_dialog() + root_check() + battery_get_thresholds() + cpufreqctl() + footer() + distro_info() + sysinfo() + print() + app_version() + print() + python_info() + print() + device_info() + print(f"Battery is: {'' if charging() else 'dis'}charging") + print() + app_res_use() + get_load() + get_current_gov() + get_turbo() + footer() + elif version: + footer() + distro_info() + app_version() + footer() + elif donate: + footer() + print("If auto-cpufreq helped you out and you find it useful ...\n") + print("Show your appreciation by donating!") + print(GITHUB+"#donate") + footer() if __name__ == "__main__": main() diff --git a/auto_cpufreq/bin/auto_cpufreq_gtk.py b/auto_cpufreq/bin/auto_cpufreq_gtk.py index 7c63663c..c4b26ca6 100644 --- a/auto_cpufreq/bin/auto_cpufreq_gtk.py +++ b/auto_cpufreq/bin/auto_cpufreq_gtk.py @@ -1,13 +1,8 @@ #!/usr/bin/env python3 - -import sys - -sys.path.append("../") - import gi gi.require_version("Gtk", "3.0") - from gi.repository import Gtk, GLib + from auto_cpufreq.gui.app import ToolWindow def main(): diff --git a/auto_cpufreq/utils/config.py b/auto_cpufreq/config/config.py similarity index 89% rename from auto_cpufreq/utils/config.py rename to auto_cpufreq/config/config.py index 5f0e196f..3966df61 100644 --- a/auto_cpufreq/utils/config.py +++ b/auto_cpufreq/config/config.py @@ -1,9 +1,8 @@ +import os, pyinotify, sys from configparser import ConfigParser, ParsingError -from auto_cpufreq.utils.config_event_handler import ConfigEventHandler -import pyinotify from subprocess import run, PIPE -import os -import sys + +from auto_cpufreq.config.config_event_handler import ConfigEventHandler def find_config_file(args_config_file) -> str: """ @@ -56,16 +55,14 @@ def set_path(self, path: str) -> None: self.watch_manager.add_watch(os.path.dirname(path), mask=mask) if os.path.isfile(path): self.update_config() - def has_config(self) -> bool: - return os.path.isfile(self.path) + def has_config(self) -> bool: return os.path.isfile(self.path) - def get_config(self) -> ConfigParser: - return self._config + def get_config(self) -> ConfigParser: return self._config def update_config(self) -> None: # create new ConfigParser to prevent old data from remaining self._config = ConfigParser() try: self._config.read(self.path) - except ParsingError as e: print(f"The following error occured while parsing the config file: \n{e}") + except ParsingError as e: print(f"The following error occured while parsing the config file: \n{repr(e)}") config = _Config() \ No newline at end of file diff --git a/auto_cpufreq/config/config_event_handler.py b/auto_cpufreq/config/config_event_handler.py new file mode 100644 index 00000000..9ced244f --- /dev/null +++ b/auto_cpufreq/config/config_event_handler.py @@ -0,0 +1,23 @@ +from pyinotify import Event, ProcessEvent + +class ConfigEventHandler(ProcessEvent): + def __init__(self, config) -> None: + self.config = config + + def _process_update(self, event: Event): + if event.pathname.rstrip("~") == self.config.path: self.config.update_config() + + # activates when auto-cpufreq config file is modified + def process_IN_MODIFY(self, event: Event) -> None: self._process_update(event) + + # activates when auto-cpufreq config file is deleted + def process_IN_DELETE(self, event: Event) -> None: self._process_update(event) + + # activates when auto-cpufreq config file is created + def process_IN_CREATE(self, event: Event) -> None: self._process_update(event) + + # activates when auto-cpufreq config file is moved from watched directory + def process_IN_MOVED_FROM(self, event: Event) -> None: self._process_update(event) + + # activates when auto-cpufreq config file is moved into the watched directory + def process_IN_MOVED_TO(self, event: Event) -> None: self._process_update(event) \ No newline at end of file diff --git a/auto_cpufreq/core.py b/auto_cpufreq/core.py index 106ad9d0..e79daaaf 100755 --- a/auto_cpufreq/core.py +++ b/auto_cpufreq/core.py @@ -1,34 +1,25 @@ #!/usr/bin/env python3 # # auto-cpufreq - core functionality - -import os -import platform as pl -import shutil -import sys -import psutil -import distro -import time -import click -import pickle -import warnings -# import pkg_resources -import importlib.metadata +import click, distro, os, platform, psutil, sys +from importlib.metadata import metadata, PackageNotFoundError from math import isclose from pathlib import Path -from shutil import which -from subprocess import getoutput, call, run, check_output, DEVNULL -import requests -import re - -# execution timestamp used in countdown func -from datetime import datetime - -sys.path.append("../") +from pickle import dump, load +from re import search +from requests import get, exceptions +from shutil import copy +from subprocess import call, check_output, DEVNULL, getoutput, run +from time import sleep +from warnings import filterwarnings + +from auto_cpufreq.config.config import config +from auto_cpufreq.globals import ( + ALL_GOVERNORS, AVAILABLE_GOVERNORS, AVAILABLE_GOVERNORS_SORTED, GITHUB, IS_INSTALLED_WITH_AUR, IS_INSTALLED_WITH_SNAP, POWER_SUPPLY_DIR +) from auto_cpufreq.power_helper import * -from auto_cpufreq.utils.config import config -warnings.filterwarnings("ignore") +filterwarnings("ignore") # add path to auto-cpufreq executables for GUI os.environ["PATH"] += ":/usr/local/bin" @@ -37,16 +28,6 @@ # - replace get system/CPU load from: psutil.getloadavg() | available in 5.6.2) SCRIPTS_DIR = Path("/usr/local/share/auto-cpufreq/scripts/") - -# from the highest performance to the lowest -ALL_GOVERNORS = ( - "performance", - "ondemand", - "conservative", - "schedutil", - "userspace", - "powersave", -) CPUS = os.cpu_count() # ignore these devices under /sys/class/power_supply/ @@ -57,105 +38,72 @@ # decraled where their execution takes place # powersave/performance system load thresholds -powersave_load_threshold = (75 * CPUS) / 100 performance_load_threshold = (50 * CPUS) / 100 +powersave_load_threshold = (75 * CPUS) / 100 # auto-cpufreq stats file path -auto_cpufreq_stats_path = None auto_cpufreq_stats_file = None +auto_cpufreq_stats_path = None # track governor override -if os.getenv("PKG_MARKER") == "SNAP": - governor_override_state = Path("/var/snap/auto-cpufreq/current/override.pickle") -else: - governor_override_state = Path("/opt/auto-cpufreq/override.pickle") - -if os.getenv("PKG_MARKER") == "SNAP": +if IS_INSTALLED_WITH_SNAP: auto_cpufreq_stats_path = Path("/var/snap/auto-cpufreq/current/auto-cpufreq.stats") + governor_override_state = Path("/var/snap/auto-cpufreq/current/override.pickle") else: auto_cpufreq_stats_path = Path("/var/run/auto-cpufreq.stats") + governor_override_state = Path("/opt/auto-cpufreq/override.pickle") # daemon check dcheck = getoutput("snapctl get daemon") - def file_stats(): global auto_cpufreq_stats_file auto_cpufreq_stats_file = open(auto_cpufreq_stats_path, "w") sys.stdout = auto_cpufreq_stats_file - def get_override(): if os.path.isfile(governor_override_state): - with open(governor_override_state, "rb") as store: - return pickle.load(store) - else: - return "default" + with open(governor_override_state, "rb") as store: return load(store) + else: return "default" def set_override(override): if override in ["powersave", "performance"]: with open(governor_override_state, "wb") as store: - pickle.dump(override, store) + dump(override, store) print(f"Set governor override to {override}") elif override == "reset": if os.path.isfile(governor_override_state): os.remove(governor_override_state) print("Governor override removed") - elif override is not None: - print("Invalid option.\nUse force=performance, force=powersave, or force=reset") - - + elif override is not None: print("Invalid option.\nUse force=performance, force=powersave, or force=reset") # get distro name -try: - dist_name = distro.id() +try: dist_name = distro.id() except PermissionError: # Current work-around for Pop!_OS where symlink causes permission issues print("[!] Warning: Cannot get distro name") - if os.path.exists("/etc/pop-os/os-release"): - # Check if using a Snap - if os.getenv("PKG_MARKER") == "SNAP": - print("[!] Snap install on PopOS detected, you must manually run the following" - " commands in another terminal:\n") - print("[!] Backup the /etc/os-release file:") - print("sudo mv /etc/os-release /etc/os-release-backup\n") - print("[!] Create hardlink to /etc/os-release:") - print("sudo ln /etc/pop-os/os-release /etc/os-release\n") - print("[!] Aborting. Restart auto-cpufreq when you created the hardlink") - sys.exit(1) - else: - # This should not be the case. But better be sure. - print("[!] Check /etc/os-release permissions and make sure it is not a symbolic link") - print("[!] Aborting...") - sys.exit(1) - + if IS_INSTALLED_WITH_SNAP and os.path.exists("/etc/pop-os/os-release"): + print("[!] Snap install on PopOS detected, you must manually run the following" + " commands in another terminal:\n") + print("[!] Backup the /etc/os-release file:") + print("sudo mv /etc/os-release /etc/os-release-backup\n") + print("[!] Create hardlink to /etc/os-release:") + print("sudo ln /etc/pop-os/os-release /etc/os-release\n") + print("[!] Aborting. Restart auto-cpufreq when you created the hardlink") else: print("[!] Check /etc/os-release permissions and make sure it is not a symbolic link") print("[!] Aborting...") - sys.exit(1) + sys.exit(1) # display running version of auto-cpufreq def app_version(): - print("auto-cpufreq version: ", end="") - # snap package - if os.getenv("PKG_MARKER") == "SNAP": - print(getoutput(r"echo \(Snap\) $SNAP_VERSION")) - # aur package - elif os.path.exists("/etc/arch-release"): - aur_pkg_check = call("pacman -Qs auto-cpufreq > /dev/null", shell=True) - if aur_pkg_check == 1: - print(get_formatted_version()) - else: - print(getoutput("pacman -Qi auto-cpufreq | grep Version")) + if IS_INSTALLED_WITH_SNAP: print(getoutput(r"echo \(Snap\) $SNAP_VERSION")) + elif IS_INSTALLED_WITH_AUR: print(getoutput("pacman -Qi auto-cpufreq | grep Version")) else: - # source code (auto-cpufreq-installer) - try: - print(get_formatted_version()) - except Exception as e: - print(repr(e)) - pass + try: print(get_formatted_version()) + except Exception as e: print(repr(e)) def check_for_update(): # returns True if a new release is available from the GitHub repo @@ -163,21 +111,19 @@ def check_for_update(): # Specify the repository and package name # IT IS IMPORTANT TO THAT IF THE REPOSITORY STRUCTURE IS CHANGED, THE FOLLOWING FUNCTION NEEDS TO BE UPDATED ACCORDINGLY # Fetch the latest release information from GitHub API - latest_release_url = f"https://api.github.com/repos/AdnanHodzic/auto-cpufreq/releases/latest" + latest_release_url = GITHUB.replace("github.com", "api.github.com/repos") + "/releases/latest" try: - response = requests.get(latest_release_url) - if response.status_code == 200: - latest_release = response.json() + response = get(latest_release_url) + if response.status_code == 200: latest_release = response.json() else: message = response.json().get("message") print("Error fetching recent release!") if message is not None and message.startswith("API rate limit exceeded"): print("GitHub Rate limit exceeded. Please try again later within 1 hour or use different network/VPN.") - else: - print("Unexpected status code:", response.status_code) + else: print("Unexpected status code:", response.status_code) return False - except (requests.exceptions.ConnectionError, requests.exceptions.Timeout, - requests.exceptions.RequestException, requests.exceptions.HTTPError) as err: + except (exceptions.ConnectionError, exceptions.Timeout, + exceptions.RequestException, exceptions.HTTPError): print("Error Connecting to server!") return False @@ -187,8 +133,7 @@ def check_for_update(): # Get the current version of auto-cpufreq # Extract version number from the output string output = check_output(['auto-cpufreq', '--version']).decode('utf-8') - try: - version_line = next((re.search(r'\d+\.\d+\.\d+', line).group() for line in output.split('\n') if line.startswith('auto-cpufreq version')), None) + try: version_line = next((search(r'\d+\.\d+\.\d+', line).group() for line in output.split('\n') if line.startswith('auto-cpufreq version')), None) except AttributeError: print("Error Retrieving Current Version!") exit(1) @@ -202,47 +147,31 @@ def check_for_update(): print(f"Updates are available,\nCurrent version: {installed_version}\nLatest version: {latest_version}") print("Note that your previous custom settings might be erased with the following update") return True - else: - # Handle the case where "tag_name" key doesn't exist - print("Malformed Released data!\nReinstall manually or Open an issue on GitHub for help!") - - + # Handle the case where "tag_name" key doesn't exist + else: print("Malformed Released data!\nReinstall manually or Open an issue on GitHub for help!") def new_update(custom_dir): os.chdir(custom_dir) print(f"Cloning the latest release to {custom_dir}") - run(["git", "clone", "https://github.com/AdnanHodzic/auto-cpufreq.git"]) + run(["git", "clone", GITHUB+".git"]) os.chdir("auto-cpufreq") print(f"package cloned to directory {custom_dir}") run(['./auto-cpufreq-installer'], input='i\n', encoding='utf-8') def get_literal_version(package_name): try: - package_metadata = importlib.metadata.metadata(package_name) - + package_metadata = metadata(package_name) package_name = package_metadata['Name'] - metadata_version = package_metadata['Version'] + numbered_version, _, git_version = package_metadata['Version'].partition("+") - numbered_version, _, git_version = metadata_version.partition("+") + return f"{numbered_version}+{git_version}" # Construct the literal version string - # Construct the literal version string - literal_version = f"{numbered_version}+{git_version}" - - return literal_version - - except importlib.metadata.PackageNotFoundError: - return f"Package '{package_name}' not found" + except PackageNotFoundError: return f"Package '{package_name}' not found" # return formatted version for a better readability def get_formatted_version(): - literal_version = get_literal_version("auto-cpufreq") - splitted_version = literal_version.split("+") - formatted_version = splitted_version[0] - - if len(splitted_version) > 1: - formatted_version += " (git: " + splitted_version[1] + ")" - - return formatted_version + splitted_version = get_literal_version("auto-cpufreq").split("+") + return splitted_version[0] + ("" if len(splitted_version) > 1 else " (git: " + splitted_version[1] + ")") def app_res_use(): p = psutil.Process() @@ -250,7 +179,6 @@ def app_res_use(): print("cpu usage:", p.cpu_percent(), "%") print("memory use:", round(p.memory_percent(), 2), "%") - # set/change state of turbo def turbo(value: bool = None): """ @@ -277,104 +205,52 @@ def turbo(value: bool = None): return False if value is not None: - if inverse: - value = not value - - try: - f.write_text(str(int(value)) + "\n") + try: f.write_text(f"{int(value ^ inverse)}\n") except PermissionError: print("Warning: Changing CPU turbo is not supported. Skipping.") return False - value = bool(int(f.read_text().strip())) - if inverse: - value = not value - - return value - - -# display current state of turbo -def get_turbo(): - - if turbo(): - print("Currently turbo boost is: on") - else: - print("Currently turbo boost is: off") + return bool(int(f.read_text().strip())) ^ inverse +def get_turbo(): print("Currently turbo boost is:", "on" if turbo() else "off") +def set_turbo(value:bool): + print("Setting turbo boost:", "on" if value else "off") + turbo(value) def charging(): """ get charge state: is battery charging or discharging """ - power_supply_path = "/sys/class/power_supply/" - power_supplies = os.listdir(Path(power_supply_path)) # sort it so AC is 'always' first - power_supplies = sorted(power_supplies) + power_supplies = sorted(os.listdir(Path(POWER_SUPPLY_DIR))) - # check if we found power supplies. on a desktop these are not found - # and we assume we are on a powercable. - if len(power_supplies) == 0: - # nothing found found, so nothing to check - return True + # check if we found power supplies. on a desktop these are not found and we assume we are on a powercable. + if len(power_supplies) == 0: return True # nothing found, so nothing to check # we found some power supplies, lets check their state for supply in power_supplies: - # Check if supply is in ignore list - ignore_supply = any(item in supply for item in POWER_SUPPLY_IGNORELIST) - # If found in ignore list, skip it. - if ignore_supply: - continue - - power_supply_type_path = Path(power_supply_path + supply + "/type") - if not power_supply_type_path.exists(): - continue - with open(power_supply_type_path) as f: - supply_type = f.read()[:-1] + # Check if supply is in ignore list, if found in ignore list, skip it. + if any(item in supply for item in POWER_SUPPLY_IGNORELIST): continue + + power_supply_type_path = Path(POWER_SUPPLY_DIR + supply + "/type") + if not power_supply_type_path.exists(): continue + with open(power_supply_type_path) as f: supply_type = f.read()[:-1] if supply_type == "Mains": # we found an AC - power_supply_online_path = Path(power_supply_path + supply + "/online") - if not power_supply_online_path.exists(): - continue + power_supply_online_path = Path(POWER_SUPPLY_DIR + supply + "/online") + if not power_supply_online_path.exists(): continue with open(power_supply_online_path) as f: - val = int(f.read()[:-1]) - if val == 1: - # we are definitely charging - return True + if int(f.read()[:-1]) == 1: return True # we are definitely charging elif supply_type == "Battery": # we found a battery, check if its being discharged - power_supply_status_path = Path(power_supply_path + supply + "/status") - if not power_supply_status_path.exists(): - continue + power_supply_status_path = Path(POWER_SUPPLY_DIR + supply + "/status") + if not power_supply_status_path.exists(): continue with open(power_supply_status_path) as f: - val = str(f.read()[:-1]) - if val == "Discharging": - # we found a discharging battery - return False - - # we cannot determine discharging state, assume we are on powercable - return True - -def get_avail_gov(): - f = Path("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors") - return f.read_text().strip().split(" ") - - -def get_avail_powersave(): - """ - Iterate over ALL_GOVERNORS in reverse order: from powersave to performance - :return: - """ - for g in ALL_GOVERNORS[::-1]: - if g in get_avail_gov(): - return g - - -def get_avail_performance(): - for g in ALL_GOVERNORS: - if g in get_avail_gov(): - return g + # we found a discharging battery + if str(f.read()[:-1]) == "Discharging": return False + return True # we cannot determine discharging state, assume we are on powercable def get_current_gov(): return print( @@ -383,36 +259,21 @@ def get_current_gov(): "governor", ) - def cpufreqctl(): """ - deploy cpufreqctl script + deploy cpufreqctl.auto-cpufreq script """ - - # detect if running on a SNAP - if os.getenv("PKG_MARKER") == "SNAP": - pass - else: - # deploy cpufreqctl.auto-cpufreq script - if not os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq"): - shutil.copy(SCRIPTS_DIR / "cpufreqctl.sh", "/usr/local/bin/cpufreqctl.auto-cpufreq") - + if not (IS_INSTALLED_WITH_SNAP or os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq")): + copy(SCRIPTS_DIR / "cpufreqctl.sh", "/usr/local/bin/cpufreqctl.auto-cpufreq") def cpufreqctl_restore(): """ remove cpufreqctl.auto-cpufreq script """ - # detect if running on a SNAP - if os.getenv("PKG_MARKER") == "SNAP": - pass - else: - if os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq"): - os.remove("/usr/local/bin/cpufreqctl.auto-cpufreq") - - -def footer(l=79): - print("\n" + "-" * l + "\n") + if not IS_INSTALLED_WITH_SNAP and os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq"): + os.remove("/usr/local/bin/cpufreqctl.auto-cpufreq") +def footer(l=79): print("\n" + "-" * l + "\n") def deploy_complete_msg(): print("\n" + "-" * 17 + " auto-cpufreq daemon installed and running " + "-" * 17 + "\n") @@ -420,85 +281,65 @@ def deploy_complete_msg(): print("\nTo disable and remove auto-cpufreq daemon, run:\nsudo auto-cpufreq --remove") footer() - -def deprecated_log_msg(): - print("\n" + "-" * 24 + " auto-cpufreq log file renamed " + "-" * 24 + "\n") - print("The --log flag has been renamed to --stats\n") - print("To view live stats, run:\nauto-cpufreq --stats") - footer() - - def remove_complete_msg(): print("\n" + "-" * 25 + " auto-cpufreq daemon removed " + "-" * 25 + "\n") print("auto-cpufreq successfully removed.") footer() - def deploy_daemon(): print("\n" + "-" * 21 + " Deploying auto-cpufreq as a daemon " + "-" * 22 + "\n") - # deploy cpufreqctl script func call - cpufreqctl() + cpufreqctl() # deploy cpufreqctl script func call - # turn off bluetooth on boot - bluetooth_disable() + bluetooth_disable() # turn off bluetooth on boot auto_cpufreq_stats_path.touch(exist_ok=True) print("\n* Deploy auto-cpufreq install script") - shutil.copy(SCRIPTS_DIR / "auto-cpufreq-install.sh", "/usr/local/bin/auto-cpufreq-install") + copy(SCRIPTS_DIR / "auto-cpufreq-install.sh", "/usr/local/bin/auto-cpufreq-install") print("\n* Deploy auto-cpufreq remove script") - shutil.copy(SCRIPTS_DIR / "auto-cpufreq-remove.sh", "/usr/local/bin/auto-cpufreq-remove") + copy(SCRIPTS_DIR / "auto-cpufreq-remove.sh", "/usr/local/bin/auto-cpufreq-remove") # output warning if gnome power profile is running gnome_power_detect_install() gnome_power_svc_disable() - # output warning if TLP service is detected - tlp_service_detect() + tlp_service_detect() # output warning if TLP service is detected call("/usr/local/bin/auto-cpufreq-install", shell=True) - def deploy_daemon_performance(): print("\n" + "-" * 21 + " Deploying auto-cpufreq as a daemon (performance) " + "-" * 22 + "\n") # check that performance is in scaling_available_governors - with open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors") as available_governors: - if "performance" not in available_governors.read(): - print("\"performance\" governor is unavailable on this system, run:\n" - "sudo sudo auto-cpufreq --install\n\n" - "to install auto-cpufreq using default \"balanced\" governor.\n") + if "performance" not in AVAILABLE_GOVERNORS_SORTED: + print("\"performance\" governor is unavailable on this system, run:\n" + "sudo sudo auto-cpufreq --install\n\n" + "to install auto-cpufreq using default \"balanced\" governor.\n") - # deploy cpufreqctl script func call - cpufreqctl() + cpufreqctl() # deploy cpufreqctl script func call - # turn off bluetooth on boot - bluetooth_disable() + bluetooth_disable() # turn off bluetooth on boot auto_cpufreq_stats_path.touch(exist_ok=True) print("\n* Deploy auto-cpufreq install script") - shutil.copy(SCRIPTS_DIR / "auto-cpufreq-install.sh", "/usr/local/bin/auto-cpufreq-install") + copy(SCRIPTS_DIR / "auto-cpufreq-install.sh", "/usr/local/bin/auto-cpufreq-install") print("\n* Deploy auto-cpufreq remove script") - shutil.copy(SCRIPTS_DIR / "auto-cpufreq-remove.sh", "/usr/local/bin/auto-cpufreq-remove") + copy(SCRIPTS_DIR / "auto-cpufreq-remove.sh", "/usr/local/bin/auto-cpufreq-remove") # output warning if gnome power profile is running gnome_power_detect_install() #"gnome_power_svc_disable_performance" is not defined #gnome_power_svc_disable_performance() - - # output warning if TLP service is detected - tlp_service_detect() + + tlp_service_detect() # output warning if TLP service is detected call("/usr/local/bin/auto-cpufreq-install", shell=True) - -# remove auto-cpufreq daemon def remove_daemon(): - # check if auto-cpufreq is installed if not os.path.exists("/usr/local/bin/auto-cpufreq-remove"): print("\nauto-cpufreq daemon is not installed.\n") @@ -506,8 +347,7 @@ def remove_daemon(): print("\n" + "-" * 21 + " Removing auto-cpufreq daemon " + "-" * 22 + "\n") - # turn on bluetooth on boot - bluetooth_enable() + bluetooth_enable() # turn on bluetooth on boot # output warning if gnome power profile is stopped gnome_power_rm_reminder() @@ -520,28 +360,21 @@ def remove_daemon(): os.remove("/usr/local/bin/auto-cpufreq-remove") # delete override pickle if it exists - if os.path.exists(governor_override_state): - os.remove(governor_override_state) + if os.path.exists(governor_override_state): os.remove(governor_override_state) # delete stats file if auto_cpufreq_stats_path.exists(): - if auto_cpufreq_stats_file is not None: - auto_cpufreq_stats_file.close() - + if auto_cpufreq_stats_file is not None: auto_cpufreq_stats_file.close() auto_cpufreq_stats_path.unlink() - # restore original cpufrectl script - cpufreqctl_restore() - + cpufreqctl_restore() # restore original cpufrectl script def gov_check(): - for gov in get_avail_gov(): + for gov in AVAILABLE_GOVERNORS: if gov not in ALL_GOVERNORS: print("\n" + "-" * 18 + " Checking for necessary scaling governors " + "-" * 19 + "\n") sys.exit("ERROR:\n\nCouldn't find any of the necessary scaling governors.\n") - -# root check func def root_check(): if not os.geteuid() == 0: print("\n" + "-" * 33 + " Root check " + "-" * 34 + "\n") @@ -549,8 +382,6 @@ def root_check(): footer() exit(1) - -# refresh countdown def countdown(s): # Fix for wrong stats output and "TERM environment variable not set" os.environ["TERM"] = "xterm" @@ -566,35 +397,23 @@ def countdown(s): # auto-refresh counter for remaining in range(s, -1, -1): + if remaining <= 3 and remaining >= 0: print(".", end="", flush=True) + sleep(s/3) - if remaining <= 3 and remaining >= 0: - print(".", end="", flush=True) - time.sleep(0.75) - - now = datetime.now() - current_time = now.strftime("%B %d (%A) - %H:%M:%S") - print("\n\t\tExecuted on:", current_time) - + print("\n\t\tExecuted on:", getoutput('date')) # get cpu usage + system load for (last minute) -def display_load(): - - # get CPU utilization as a percentage - cpuload = psutil.cpu_percent(interval=1) - - # get system/CPU load - load1m, _, _ = os.getloadavg() +def get_load(): + cpuload = psutil.cpu_percent(interval=1) # get CPU utilization as a percentage + load1m, _, _ = os.getloadavg() # get system/CPU load print("\nTotal CPU usage:", cpuload, "%") print("Total system load: {:.2f}".format(load1m)) print("Average temp. of all cores: {:.2f} °C \n".format(avg_all_core_temp)) -# get system load average 1m, 5m, 15m (equivalent to uptime) -def display_system_load_avg(): + return cpuload, load1m - load1m, load5m, load15m = os.getloadavg() - - print(f" (load average: {load1m:.2f}, {load5m:.2f}, {load15m:.2f})") +def display_system_load_avg(): print(" (load average: {:.2f}, {:.2f}, {:.2f})".format(*os.getloadavg())) # set minimum and maximum CPU frequencies def set_frequencies(): @@ -610,10 +429,8 @@ def set_frequencies(): if ( hasattr(set_frequencies, "prev_power_supply") and power_supply == set_frequencies.prev_power_supply - ): - return - else: - set_frequencies.prev_power_supply = power_supply + ): return + else: set_frequencies.prev_power_supply = power_supply frequency = { "scaling_max_freq": { @@ -642,46 +459,30 @@ def set_frequencies(): else: curr_freq = int(getoutput(f"cpufreqctl.auto-cpufreq --frequency-min")) value = set_frequencies.min_limit - if curr_freq == value: - continue + if curr_freq == value: continue - try: - frequency[freq_type]["value"] = ( - value if value else int(conf[power_supply][freq_type].strip()) - ) + try: frequency[freq_type]["value"] = value if value else int(conf[power_supply][freq_type].strip()) except ValueError: print(f"Invalid value for '{freq_type}': {frequency[freq_type]['value']}") exit(1) - if not ( - set_frequencies.min_limit <= frequency[freq_type]["value"] <= set_frequencies.max_limit - ): + if not set_frequencies.min_limit <= frequency[freq_type]["value"] <= set_frequencies.max_limit: print( f"Given value for '{freq_type}' is not within the allowed frequencies {set_frequencies.min_limit}-{set_frequencies.max_limit} kHz" ) exit(1) - args = f"{frequency[freq_type]['cmdargs']} --set={frequency[freq_type]['value']}" - message = f'Setting {frequency[freq_type]["minmax"]} CPU frequency to {round(frequency[freq_type]["value"]/1000)} Mhz' - + print(f'Setting {frequency[freq_type]["minmax"]} CPU frequency to {round(frequency[freq_type]["value"]/1000)} Mhz') # set the frequency - print(message) - run(f"cpufreqctl.auto-cpufreq {args}", shell=True) + run(f"cpufreqctl.auto-cpufreq {frequency[freq_type]['cmdargs']} --set={frequency[freq_type]['value']}", shell=True) - -# set powersave and enable turbo def set_powersave(): conf = config.get_config() - if conf.has_option("battery", "governor"): - gov = conf["battery"]["governor"] - else: - gov = get_avail_powersave() + gov = conf["battery"]["governor"] if conf.has_option("battery", "governor") else AVAILABLE_GOVERNORS_SORTED[-1] print(f'Setting to use: "{gov}" governor') - if get_override() != "default": - print("Warning: governor overwritten using `--force` flag.") + if get_override() != "default": print("Warning: governor overwritten using `--force` flag.") run(f"cpufreqctl.auto-cpufreq --governor --set={gov}", shell=True) - if Path("/sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference").exists() is False: print('Not setting EPP (not supported by system)') else: @@ -692,8 +493,7 @@ def set_powersave(): os.popen("cat /sys/devices/system/cpu/intel_pstate/hwp_dynamic_boost").read() )) - if dynboost_enabled: - print('Not setting EPP (dynamic boosting is enabled)') + if dynboost_enabled: print('Not setting EPP (dynamic boosting is enabled)') else: if conf.has_option("battery", "energy_performance_preference"): epp = conf["battery"]["energy_performance_preference"] @@ -703,213 +503,60 @@ def set_powersave(): run("cpufreqctl.auto-cpufreq --epp --set=balance_power", shell=True) print('Setting to use: "balance_power" EPP') - # set frequencies set_frequencies() - # get CPU utilization as a percentage - cpuload = psutil.cpu_percent(interval=1) - - # get system/CPU load - load1m, _, _ = os.getloadavg() + cpuload, load1m= get_load() - print("\nTotal CPU usage:", cpuload, "%") - print("Total system load: {:.2f}".format(load1m)) - print("Average temp. of all cores: {:.2f} °C \n".format(avg_all_core_temp)) - - # conditions for setting turbo in powersave - if conf.has_option("battery", "turbo"): - auto = conf["battery"]["turbo"] - else: - auto = "auto" + auto = conf["battery"]["turbo"] if conf.has_option("battery", "turbo") else "auto" if auto == "always": print("Configuration file enforces turbo boost") - print("setting turbo boost: on") - turbo(True) + set_turbo(True) elif auto == "never": print("Configuration file disables turbo boost") - print("setting turbo boost: off") - turbo(False) + set_turbo(False) else: if psutil.cpu_percent(percpu=False, interval=0.01) >= 30.0 or isclose( max(psutil.cpu_percent(percpu=True, interval=0.01)), 100 - ): - print("High CPU load", end=""), display_system_load_avg() + ): print("High CPU load", end="") + elif load1m > powersave_load_threshold: print("High system load", end="") + else: print("Load optimal", end="") + display_system_load_avg() - # high cpu usage trigger - if cpuload >= 20: - print("setting turbo boost: on") - turbo(True) - - # set turbo state based on average of all core temperatures - elif cpuload <= 20 and avg_all_core_temp >= 70: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) - print("setting turbo boost: off") - turbo(False) - else: - print("setting turbo boost: off") - turbo(False) - - elif load1m > powersave_load_threshold: - print("High system load", end=""), display_system_load_avg() - - # high cpu usage trigger - if cpuload >= 20: - print("setting turbo boost: on") - turbo(True) - - # set turbo state based on average of all core temperatures - elif cpuload <= 20 and avg_all_core_temp >= 65: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) - print("setting turbo boost: off") - turbo(False) - else: - print("setting turbo boost: off") - turbo(False) - - else: - print("Load optimal", end=""), display_system_load_avg() - - # high cpu usage trigger - if cpuload >= 20: - print("setting turbo boost: on") - turbo(True) - - # set turbo state based on average of all core temperatures - elif cpuload <= 20 and avg_all_core_temp >= 60: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) - print("setting turbo boost: off") - turbo(False) - else: - print("setting turbo boost: off") - turbo(False) + if cpuload >= 20: set_turbo(True) # high cpu usage trigger + else: # set turbo state based on average of all core temperatures + print(f"Optimal total CPU usage: {cpuload}%, high average core temp: {avg_all_core_temp}°C") + set_turbo(False) footer() - -# make turbo suggestions in powersave def mon_powersave(): - - # get CPU utilization as a percentage - cpuload = psutil.cpu_percent(interval=1) - - # get system/CPU load - load1m, _, _ = os.getloadavg() - - print("\nTotal CPU usage:", cpuload, "%") - print("Total system load: {:.2f}".format(load1m)) - print("Average temp. of all cores: {:.2f} °C \n".format(avg_all_core_temp)) + cpuload, load1m = get_load() if psutil.cpu_percent(percpu=False, interval=0.01) >= 30.0 or isclose( max(psutil.cpu_percent(percpu=True, interval=0.01)), 100 - ): - print("High CPU load", end=""), display_system_load_avg() + ): print("High CPU load", end="") + elif load1m > powersave_load_threshold: print("High system load", end="") + else: print("Load optimal", end="") + display_system_load_avg() - # high cpu usage trigger - if cpuload >= 20: - print("suggesting to set turbo boost: on") - get_turbo() - - # set turbo state based on average of all core temperatures - elif cpuload <= 20 and avg_all_core_temp >= 70: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) - print("suggesting to set turbo boost: off") - get_turbo() - else: - print("suggesting to set turbo boost: off") - get_turbo() - - elif load1m > powersave_load_threshold: - print("High system load", end=""), display_system_load_avg() - - # high cpu usage trigger - if cpuload >= 20: - print("suggesting to set turbo boost: on") - get_turbo() - - # set turbo state based on average of all core temperatures - elif cpuload <= 20 and avg_all_core_temp >= 65: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) - print("suggesting to set turbo boost: off") - get_turbo() - else: - print("suggesting to set turbo boost: off") - get_turbo() - - else: - print("Load optimal", end=""), display_system_load_avg() - - # high cpu usage trigger - if cpuload >= 20: - print("suggesting to set turbo boost: on") - get_turbo() - - # set turbo state based on average of all core temperatures - elif cpuload <= 20 and avg_all_core_temp >= 60: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) - print("suggesting to set turbo boost: off") - get_turbo() - else: - print("suggesting to set turbo boost: off") - get_turbo() + if cpuload >= 20: print("suggesting to set turbo boost: on") # high cpu usage trigger + else: # set turbo state based on average of all core temperatures + print(f"Optimal total CPU usage: {cpuload}%, high average core temp: {avg_all_core_temp}°C") + print("suggesting to set turbo boost: off") + get_turbo() footer() - -# set performance and enable turbo def set_performance(): conf = config.get_config() - if conf.has_option("charger", "governor"): - gov = conf["charger"]["governor"] - else: - gov = get_avail_performance() + gov = conf["charger"]["governor"] if conf.has_option("charger", "governor") else AVAILABLE_GOVERNORS_SORTED[0] print(f'Setting to use: "{gov}" governor') - if get_override() != "default": - print("Warning: governor overwritten using `--force` flag.") - run( - f"cpufreqctl.auto-cpufreq --governor --set={gov}", - shell=True, - ) - + if get_override() != "default": print("Warning: governor overwritten using `--force` flag.") + run("cpufreqctl.auto-cpufreq --governor --set="+gov, shell=True) - if Path("/sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference").exists() is False: + if not Path("/sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference").exists(): print('Not setting EPP (not supported by system)') else: if Path("/sys/devices/system/cpu/intel_pstate").exists(): @@ -920,8 +567,7 @@ def set_performance(): os.popen("cat /sys/devices/system/cpu/intel_pstate/hwp_dynamic_boost").read() )) - if dynboost_enabled: - print('Not setting EPP (dynamic boosting is enabled)') + if dynboost_enabled: print('Not setting EPP (dynamic boosting is enabled)') else: intel_pstate_status_path = "/sys/devices/system/cpu/intel_pstate/status" @@ -962,200 +608,88 @@ def set_performance(): else: run("cpufreqctl.auto-cpufreq --epp --set=balance_performance", shell=True) print('Setting to use: "balance_performance" EPP') - - # set frequencies set_frequencies() - # get CPU utilization as a percentage - cpuload = psutil.cpu_percent(interval=1) - - # get system/CPU load - load1m, _, _ = os.getloadavg() - - print("\nTotal CPU usage:", cpuload, "%") - print("Total system load: {:.2f}".format(load1m)) - print("Average temp. of all cores: {:.2f} °C \n".format(avg_all_core_temp)) - - if conf.has_option("charger", "turbo"): - auto = conf["charger"]["turbo"] - else: - auto = "auto" + cpuload, load1m = get_load() + auto = conf["charger"]["turbo"] if conf.has_option("charger", "turbo") else "auto" if auto == "always": print("Configuration file enforces turbo boost") - print("setting turbo boost: on") - turbo(True) + set_turbo(True) elif auto == "never": print("Configuration file disables turbo boost") - print("setting turbo boost: off") - turbo(False) + set_turbo(False) else: if ( psutil.cpu_percent(percpu=False, interval=0.01) >= 20.0 or max(psutil.cpu_percent(percpu=True, interval=0.01)) >= 75 ): print("High CPU load", end=""), display_system_load_avg() - - # high cpu usage trigger - if cpuload >= 20: - print("setting turbo boost: on") - turbo(True) - - # set turbo state based on average of all core temperatures - elif avg_all_core_temp >= 70: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) - print("setting turbo boost: off") - turbo(False) - else: - print("setting turbo boost: on") - turbo(True) - + if cpuload >= 20: set_turbo(True) # high cpu usage trigger + elif avg_all_core_temp >= 70: # set turbo state based on average of all core temperatures + print(f"Optimal total CPU usage: {cpuload}%, high average core temp: {avg_all_core_temp}°C") + set_turbo(False) + else: set_turbo(True) elif load1m >= performance_load_threshold: print("High system load", end=""), display_system_load_avg() - - # high cpu usage trigger - if cpuload >= 20: - print("setting turbo boost: on") - turbo(True) - - # set turbo state based on average of all core temperatures - elif avg_all_core_temp >= 65: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) - print("setting turbo boost: off") - turbo(False) - else: - print("setting turbo boost: on") - turbo(True) - + if cpuload >= 20: set_turbo(True) # high cpu usage trigger + elif avg_all_core_temp >= 65: # set turbo state based on average of all core temperatures + print(f"Optimal total CPU usage: {cpuload}%, high average core temp: {avg_all_core_temp}°C") + set_turbo(False) + else: set_turbo(True) else: print("Load optimal", end=""), display_system_load_avg() - - # high cpu usage trigger - if cpuload >= 20: - print("setting turbo boost: on") - turbo(True) - - # set turbo state based on average of all core temperatures - elif avg_all_core_temp >= 60: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) - print("setting turbo boost: off") - turbo(False) - else: - print("setting turbo boost: off") - turbo(False) - + if cpuload >= 20: set_turbo(True) # high cpu usage trigger + else: # set turbo state based on average of all core temperatures + print(f"Optimal total CPU usage: {cpuload}%, high average core temp: {avg_all_core_temp}°C") + set_turbo(False) footer() - -# make turbo suggestions in performance def mon_performance(): - - # get CPU utilization as a percentage - cpuload = psutil.cpu_percent(interval=1) - - # get system/CPU load - load1m, _, _ = os.getloadavg() - - print("\nTotal CPU usage:", cpuload, "%") - print("Total system load: {:.2f}".format(load1m)) - print("Average temp. of all cores: {:.2f} °C \n".format(avg_all_core_temp)) - - # get system/CPU load - load1m, _, _ = os.getloadavg() + cpuload, load1m = get_load() if ( psutil.cpu_percent(percpu=False, interval=0.01) >= 20.0 or max(psutil.cpu_percent(percpu=True, interval=0.01)) >= 75 ): print("High CPU load", end=""), display_system_load_avg() - - # high cpu usage trigger - if cpuload >= 20: + if cpuload >= 20: # high cpu usage trigger print("suggesting to set turbo boost: on") get_turbo() - # set turbo state based on average of all core temperatures elif cpuload <= 25 and avg_all_core_temp >= 70: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) + print(f"Optimal total CPU usage: {cpuload}%, high average core temp: {avg_all_core_temp}°C") print("suggesting to set turbo boost: off") get_turbo() else: print("suggesting to set turbo boost: on") get_turbo() - elif load1m > performance_load_threshold: print("High system load", end=""), display_system_load_avg() - - # high cpu usage trigger - if cpuload >= 20: + if cpuload >= 20: # high cpu usage trigger print("suggesting to set turbo boost: on") get_turbo() - - # set turbo state based on average of all core temperatures - elif cpuload <= 25 and avg_all_core_temp >= 65: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) + elif cpuload <= 25 and avg_all_core_temp >= 65: # set turbo state based on average of all core temperatures + print(f"Optimal total CPU usage: {cpuload}%, high average core temp: {avg_all_core_temp}°C") print("suggesting to set turbo boost: off") get_turbo() else: print("suggesting to set turbo boost: on") get_turbo() - else: print("Load optimal", end=""), display_system_load_avg() - - # high cpu usage trigger - if cpuload >= 20: + if cpuload >= 20: # high cpu usage trigger print("suggesting to set turbo boost: on") get_turbo() - - # set turbo state based on average of all core temperatures - elif cpuload <= 25 and avg_all_core_temp >= 60: - print( - "Optimal total CPU usage:", - cpuload, - "%, high average core temp:", - avg_all_core_temp, - "°C", - ) + elif cpuload <= 25 and avg_all_core_temp >= 60: # set turbo state based on average of all core temperatures + print(f"Optimal total CPU usage: {cpuload}%, high average core temp: {avg_all_core_temp}°C") print("suggesting to set turbo boost: off") get_turbo() else: print("suggesting to set turbo boost: on") get_turbo() - footer() - def set_autofreq(): """ set cpufreq governor based if device is charging @@ -1164,10 +698,8 @@ def set_autofreq(): # determine which governor should be used override = get_override() - if override == "powersave": - set_powersave() - elif override == "performance": - set_performance() + if override == "powersave": set_powersave() + elif override == "performance": set_performance() elif charging(): print("Battery is: charging\n") set_performance() @@ -1175,7 +707,6 @@ def set_autofreq(): print("Battery is: discharging\n") set_powersave() - def mon_autofreq(): """ make cpufreq suggestions @@ -1187,33 +718,27 @@ def mon_autofreq(): if charging(): print("Battery is: charging\n") get_current_gov() - print(f'Suggesting use of "{get_avail_performance()}" governor') + print(f'Suggesting use of "{AVAILABLE_GOVERNORS_SORTED[0]}" governor') mon_performance() else: print("Battery is: discharging\n") get_current_gov() - print(f'Suggesting use of "{get_avail_powersave()}" governor') + print(f'Suggesting use of "{AVAILABLE_GOVERNORS_SORTED[-1]}" governor') mon_powersave() - def python_info(): - print("Python:", pl.python_version()) + print("Python:", platform.python_version()) print("psutil package:", psutil.__version__) - print("platform package:", pl.__version__) + print("platform package:", platform.__version__) print("click package:", click.__version__) print("distro package:", distro.__version__) - -def device_info(): - print("Computer type:", getoutput("dmidecode --string chassis-type")) - +def device_info(): print("Computer type:", getoutput("dmidecode --string chassis-type")) def distro_info(): dist = "UNKNOWN distro" version = "UNKNOWN version" - - # get distro information in snap env. - if os.getenv("PKG_MARKER") == "SNAP": + if IS_INSTALLED_WITH_SNAP: try: with open("/var/lib/snapd/hostfs/etc/os-release", "r") as searchfile: for line in searchfile: @@ -1223,25 +748,19 @@ def distro_info(): elif line.startswith("VERSION="): version = line[8 : line.find("$")].strip('"') continue - except PermissionError as e: - print(repr(e)) - pass - + except PermissionError as e: print(repr(e)) dist = f"{dist} {version}" - else: - # get distro information + else: # get distro information fdist = distro.linux_distribution() dist = " ".join(x for x in fdist) print("Linux distro: " + dist) - print("Linux kernel: " + pl.release()) - + print("Linux kernel: " + platform.release()) def sysinfo(): """ get system information """ - # processor_info model_name = getoutput("grep -E 'model name' /proc/cpuinfo -m 1").split(":")[-1] print(f"Processor:{model_name}") @@ -1251,7 +770,7 @@ def sysinfo(): print("Cores:", total_cpu_count) # get architecture - cpu_arch = pl.machine() + cpu_arch = platform.machine() print("Architecture:", cpu_arch) # get driver @@ -1276,19 +795,14 @@ def sysinfo(): freq_per_cpu = [] for i in range(0, len(coreid_info), 3): # ensure that indices are within the valid range, before accessing the corresponding elements - if i + 1 < len(coreid_info): - freq_per_cpu.append(float(coreid_info[i + 1].split(":")[-1])) - else: - # handle the case where the index is out of range - continue + if i + 1 < len(coreid_info): freq_per_cpu.append(float(coreid_info[i + 1].split(":")[-1])) + else: continue # handle the case where the index is out of range # ensure that indices are within the valid range, before accessing the corresponding elements cpu = int(coreid_info[i].split(":")[-1]) if i + 2 < len(coreid_info): core = int(coreid_info[i + 2].split(":")[-1]) cpu_core[cpu] = core - else: - # handle the case where the index is out of range - continue + else: continue # handle the case where the index is out of range online_cpu_count = len(cpu_core) offline_cpus = [str(cpu) for cpu in range(total_cpu_count) if cpu not in cpu_core] @@ -1311,29 +825,23 @@ def sysinfo(): for sensor in temp_sensors: # iterate over all temperatures in the current sensor for temp in temp_sensors[sensor]: - if 'CPU' in temp.label: - if temp.current != 0: - temp_per_cpu = [temp.current] * online_cpu_count - break - else: - continue + if 'CPU' in temp.label and temp.current != 0: + temp_per_cpu = [temp.current] * online_cpu_count + break + else: continue break else: for sensor in ["acpitz", "k10temp", "zenpower"]: - if sensor in temp_sensors: - if temp_sensors[sensor][0].current != 0: - temp_per_cpu = [temp_sensors[sensor][0].current] * online_cpu_count - break - except Exception as e: - print(repr(e)) - pass + if sensor in temp_sensors and temp_sensors[sensor][0].current != 0: + temp_per_cpu = [temp_sensors[sensor][0].current] * online_cpu_count + break + except Exception as e: print(repr(e)) print("Core\tUsage\tTemperature\tFrequency") for (cpu, usage, freq, temp) in zip(cpu_core, usage_per_cpu, freq_per_cpu, temp_per_cpu): print(f"CPU{cpu} {usage:>5.1f}% {temp:>3.0f} °C {freq:>5.0f} MHz") - if offline_cpus: - print(f"\nDisabled CPUs: {','.join(offline_cpus)}") + if offline_cpus: print(f"\nDisabled CPUs: {','.join(offline_cpus)}") # get average temperature of all cores avg_cores_temp = sum(temp_per_cpu) @@ -1342,32 +850,21 @@ def sysinfo(): # print current fan speed current_fans = list(psutil.sensors_fans()) - for current_fan in current_fans: - print("\nCPU fan speed:", psutil.sensors_fans()[current_fan][0].current, "RPM") - - + for current_fan in current_fans: print("\nCPU fan speed:", psutil.sensors_fans()[current_fan][0].current, "RPM") -# read stats func def read_stats(): - # read stats - if os.path.isfile(auto_cpufreq_stats_path): - call(["tail", "-n 50", "-f", str(auto_cpufreq_stats_path)], stderr=DEVNULL) + if os.path.isfile(auto_cpufreq_stats_path): call(["tail", "-n 50", "-f", str(auto_cpufreq_stats_path)], stderr=DEVNULL) footer() - # check if program (argument) is running def is_running(program, argument): # iterate over all processes found by psutil # and find the one with name and args passed to the function for p in psutil.process_iter(): - try: - cmd = p.cmdline() - except: - continue + try: cmd = p.cmdline() + except: continue for s in filter(lambda x: program in x, cmd): - if argument in cmd: - return True - + if argument in cmd: return True def daemon_running_msg(): print("\n" + "-" * 24 + " auto-cpufreq running " + "-" * 30 + "\n") @@ -1388,7 +885,7 @@ def running_daemon_check(): if is_running("auto-cpufreq", "--daemon"): daemon_running_msg() exit(1) - elif os.getenv("PKG_MARKER") == "SNAP" and dcheck == "enabled": + elif IS_INSTALLED_WITH_SNAP and dcheck == "enabled": daemon_running_msg() exit(1) @@ -1397,6 +894,6 @@ def not_running_daemon_check(): if not is_running("auto-cpufreq", "--daemon"): daemon_not_running_msg() exit(1) - elif os.getenv("PKG_MARKER") == "SNAP" and dcheck == "disabled": + elif IS_INSTALLED_WITH_SNAP and dcheck == "disabled": daemon_not_running_msg() exit(1) \ No newline at end of file diff --git a/auto_cpufreq/globals.py b/auto_cpufreq/globals.py new file mode 100644 index 00000000..b2799586 --- /dev/null +++ b/auto_cpufreq/globals.py @@ -0,0 +1,12 @@ +from os import getenv, path +from subprocess import getoutput + +ALL_GOVERNORS = ('performance', 'ondemand', 'conservative', 'schedutil', 'userspace', 'powersave') # from the highest performance to the lowest +AVAILABLE_GOVERNORS = getoutput('cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors').split(' ') +AVAILABLE_GOVERNORS_SORTED = tuple(filter(lambda gov: gov in AVAILABLE_GOVERNORS, ALL_GOVERNORS)) + +CONSERVATION_MODE_FILE = "/sys/bus/platform/drivers/ideapad_acpi/VPC2004:00/conservation_mode" +GITHUB = "https://github.com/AdnanHodzic/auto-cpufreq" +IS_INSTALLED_WITH_AUR = path.isfile("/etc/arch-release") and bool(getoutput("pacman -Qs auto-cpufreq")) +IS_INSTALLED_WITH_SNAP = getenv("PKG_MARKER") == "SNAP" +POWER_SUPPLY_DIR = "/sys/class/power_supply/" \ No newline at end of file diff --git a/auto_cpufreq/gui/__init__.py b/auto_cpufreq/gui/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/auto_cpufreq/gui/app.py b/auto_cpufreq/gui/app.py index e4c0ab04..73cf69ef 100644 --- a/auto_cpufreq/gui/app.py +++ b/auto_cpufreq/gui/app.py @@ -1,27 +1,22 @@ import gi - gi.require_version("Gtk", "3.0") +from gi.repository import Gdk, GdkPixbuf, Gio, GLib, Gtk -from gi.repository import Gtk, GLib, Gdk, Gio, GdkPixbuf - -import os -import sys from contextlib import redirect_stdout from io import StringIO -from subprocess import run, PIPE -import shutil +from subprocess import PIPE, run from threading import Thread -sys.path.append("../") -from auto_cpufreq.core import is_running, check_for_update, remove_daemon, new_update -from auto_cpufreq.gui.objects import RadioButtonView, SystemStatsLabel, CPUFreqStatsLabel, CurrentGovernorBox, DropDownMenu, DaemonNotRunningView, UpdateDialog +from auto_cpufreq.core import check_for_update, is_running +from auto_cpufreq.globals import GITHUB, IS_INSTALLED_WITH_SNAP +from auto_cpufreq.gui.objects import CPUFreqStatsLabel, CurrentGovernorBox, DaemonNotRunningView, DropDownMenu, RadioButtonView, SystemStatsLabel, UpdateDialog -if os.getenv("PKG_MARKER") == "SNAP": - ICON_FILE = "/snap/auto-cpufreq/current/icon.png" +if IS_INSTALLED_WITH_SNAP: CSS_FILE = "/snap/auto-cpufreq/current/style.css" + ICON_FILE = "/snap/auto-cpufreq/current/icon.png" else: - ICON_FILE = "/usr/local/share/auto-cpufreq/images/icon.png" CSS_FILE = "/usr/local/share/auto-cpufreq/scripts/style.css" + ICON_FILE = "/usr/local/share/auto-cpufreq/images/icon.png" HBOX_PADDING = 20 PKEXEC_ERROR = "Error executing command as another user: Not authorized\n\nThis incident has been reported.\n" @@ -67,7 +62,7 @@ def snap(self): label = Gtk.Label(label="GUI not available due to Snap package confinement limitations.\nPlease install auto-cpufreq using auto-cpufreq-installer\nVisit the GitHub repo for more info") label.set_justify(Gtk.Justification.CENTER) button = Gtk.LinkButton.new_with_label( - uri="https://github.com/AdnanHodzic/auto-cpufreq", + uri=GITHUB, label="GitHub Repo" ) @@ -102,7 +97,7 @@ def daemon_not_running(self): self.add(self.box) def build(self): - if os.getenv("PKG_MARKER") == "SNAP": self.snap() + if IS_INSTALLED_WITH_SNAP: self.snap() elif is_running("auto-cpufreq", "--daemon"): self.main() else: self.daemon_not_running() diff --git a/auto_cpufreq/gui/objects.py b/auto_cpufreq/gui/objects.py index eb60f27b..d2a34359 100644 --- a/auto_cpufreq/gui/objects.py +++ b/auto_cpufreq/gui/objects.py @@ -1,37 +1,31 @@ import gi - gi.require_version("Gtk", "3.0") - -from gi.repository import Gtk, GdkPixbuf +from gi.repository import GdkPixbuf, Gtk import sys -import os -import platform as pl from concurrent.futures import ThreadPoolExecutor - -sys.path.append("../../") -from subprocess import getoutput, run, PIPE -from auto_cpufreq.core import sysinfo, distro_info, set_override, get_override, get_formatted_version, dist_name, deploy_daemon, remove_daemon - from io import StringIO +from os.path import isfile +from platform import python_version +from subprocess import getoutput, PIPE, run + +from auto_cpufreq.core import distro_info, get_formatted_version, get_override, sysinfo +from auto_cpufreq.globals import GITHUB, IS_INSTALLED_WITH_AUR, IS_INSTALLED_WITH_SNAP PKEXEC_ERROR = "Error executing command as another user: Not authorized\n\nThis incident has been reported.\n" -auto_cpufreq_stats_path = ("/var/snap/auto-cpufreq/current" if os.getenv("PKG_MARKER") == "SNAP" else "/var/run") + "/auto-cpufreq.stats" +auto_cpufreq_stats_path = ("/var/snap/auto-cpufreq/current" if IS_INSTALLED_WITH_SNAP else "/var/run") + "/auto-cpufreq.stats" def get_stats(): - if os.path.isfile(auto_cpufreq_stats_path): + if isfile(auto_cpufreq_stats_path): with open(auto_cpufreq_stats_path, "r") as file: stats = [line for line in (file.readlines() [-50:])] return "".join(stats) def get_version(): # snap package - if os.getenv("PKG_MARKER") == "SNAP": return getoutput(r"echo \(Snap\) $SNAP_VERSION") + if IS_INSTALLED_WITH_SNAP: return getoutput(r"echo \(Snap\) $SNAP_VERSION") # aur package - elif dist_name in ["arch", "manjaro", "garuda"]: - aur_pkg_check = run("pacman -Qs auto-cpufreq > /dev/null", shell=True) - if aur_pkg_check == 1: return get_formatted_version() - else: return getoutput("pacman -Qi auto-cpufreq | grep Version") + elif IS_INSTALLED_WITH_AUR: return getoutput("pacman -Qi auto-cpufreq | grep Version") else: # source code (auto-cpufreq-installer) try: return get_formatted_version() @@ -207,8 +201,8 @@ def __init__(self, parent): self.image = Gtk.Image.new_from_pixbuf(img_buffer) self.title = Gtk.Label(label="auto-cpufreq", name="bold") self.version = Gtk.Label(label=app_version) - self.python = Gtk.Label(label=f"Python {pl.python_version()}") - self.github = Gtk.Label(label="https://github.com/AdnanHodzic/auto-cpufreq") + self.python = Gtk.Label(label=f"Python {python_version()}") + self.github = Gtk.Label(label=GITHUB) self.license = Gtk.Label(label="Licensed under LGPL3", name="small") self.love = Gtk.Label(label="Made with <3", name="small") diff --git a/auto_cpufreq/gui/tray.py b/auto_cpufreq/gui/tray.py index efd7d0d3..e62948c2 100644 --- a/auto_cpufreq/gui/tray.py +++ b/auto_cpufreq/gui/tray.py @@ -1,7 +1,5 @@ import gi - gi.require_version("Gtk", "3.0") - from gi.repository import Gtk, AppIndicator3 as appindicator from subprocess import run diff --git a/auto_cpufreq/power_helper.py b/auto_cpufreq/power_helper.py index 97c71aa2..3c22024f 100644 --- a/auto_cpufreq/power_helper.py +++ b/auto_cpufreq/power_helper.py @@ -1,17 +1,17 @@ # * add status as one of the available options # * alert user on snap if detected and how to remove first time live/stats message starts # * if daemon is disabled and auto-cpufreq is removed (snap) remind user to enable it back -from logging import root -import os, sys, click, subprocess +import click from shutil import which -from subprocess import getoutput, call, run, check_output, DEVNULL +from subprocess import call, DEVNULL, getoutput, STDOUT +from sys import argv -sys.path.append("../") from auto_cpufreq.core import * +from auto_cpufreq.globals import GITHUB, IS_INSTALLED_WITH_SNAP from auto_cpufreq.tlp_stat_parser import TLPStatusParser # app_name var -app_name = "python3 power_helper.py" if sys.argv[0] == "power_helper.py" else "auto-cpufreq" +app_name = "python3 power_helper.py" if argv[0] == "power_helper.py" else "auto-cpufreq" def header(): print("\n------------------------- auto-cpufreq: Power helper -------------------------\n") def warning(): print("\n----------------------------------- Warning -----------------------------------\n") @@ -21,19 +21,19 @@ def helper_opts(): print("\nFor full list of options run: python3 power_helper.p # used to check if binary exists on the system def does_command_exists(cmd): return which(cmd) is not None -systemctl_exists = does_command_exists("systemctl") bluetoothctl_exists = does_command_exists("bluetoothctl") -tlp_stat_exists = does_command_exists("tlp-stat") powerprofilesctl_exists = does_command_exists("powerprofilesctl") +systemctl_exists = does_command_exists("systemctl") +tlp_stat_exists = does_command_exists("tlp-stat") # detect if gnome power profile service is running -if os.getenv("PKG_MARKER") != "SNAP": +if not IS_INSTALLED_WITH_SNAP: if systemctl_exists: try: gnome_power_status = call(["systemctl", "is-active", "--quiet", "power-profiles-daemon"]) except: print("\nUnable to determine init system") print("If this causes any problems, please submit an issue:") - print("https://github.com/AdnanHodzic/auto-cpufreq/issues") + print(GITHUB+"/issues") # alert in case TLP service is running def tlp_service_detect(): @@ -60,10 +60,10 @@ def gnome_power_detect(): print("Detected running GNOME Power Profiles daemon service!") print("This daemon might interfere with auto-cpufreq and should be disabled.") print("\nSteps to perform this action using auto-cpufreq: power_helper script:") - print("git clone https://github.com/AdnanHodzic/auto-cpufreq.git") + print(f"git clone {GITHUB}.git") print("cd auto-cpufreq/auto_cpufreq") print("python3 power_helper.py --gnome_power_disable") - print("\nReference: https://github.com/AdnanHodzic/auto-cpufreq#configuring-auto-cpufreq") + print(f"\nReference: {GITHUB}#configuring-auto-cpufreq") # automatically disable gnome power profile service in case it's running during install def gnome_power_detect_install(): @@ -79,15 +79,15 @@ def gnome_power_detect_install(): def gnome_power_detect_snap(): warning() print("Due to Snap package confinement limitations please consider installing auto-cpufreq using") - print("auto-cpufreq-installer: https://github.com/AdnanHodzic/auto-cpufreq/#auto-cpufreq-installer") + print(f"auto-cpufreq-installer: {GITHUB}#auto-cpufreq-installer") print() print("Unable to detect state of GNOME Power Profiles daemon service!") print("This daemon might interfere with auto-cpufreq and should be disabled.") print("\nSteps to perform this action using auto-cpufreq: power_helper script:") - print("git clone https://github.com/AdnanHodzic/auto-cpufreq.git") + print(f"git clone {GITHUB}.git") print("cd auto-cpufreq/auto_cpufreq") print("python3 power_helper.py --gnome_power_disable") - print("\nReference: https://github.com/AdnanHodzic/auto-cpufreq#configuring-auto-cpufreq") + print(f"\nReference: {GITHUB}#configuring-auto-cpufreq") # stops gnome >= 40 power profiles (live) def gnome_power_stop_live(): @@ -111,7 +111,7 @@ def gnome_power_svc_enable(): except: print("\nUnable to enable GNOME power profiles") print("If this causes any problems, please submit an issue:") - print("https://github.com/AdnanHodzic/auto-cpufreq/issues") + print(GITHUB+"/issues") # gnome power profiles current status def gnome_power_svc_status(): @@ -122,11 +122,11 @@ def gnome_power_svc_status(): except: print("\nUnable to see GNOME power profiles status") print("If this causes any problems, please submit an issue:") - print("https://github.com/AdnanHodzic/auto-cpufreq/issues") + print(GITHUB+"/issues") # disable bluetooth on boot def bluetooth_disable(): - if os.getenv("PKG_MARKER") == "SNAP": bluetooth_notif_snap() + if IS_INSTALLED_WITH_SNAP: bluetooth_notif_snap() elif bluetoothctl_exists: print("* Turn off bluetooth on boot") btconf = Path("/etc/bluetooth/main.conf") @@ -143,7 +143,7 @@ def bluetooth_disable(): # enable bluetooth on boot def bluetooth_enable(): - if os.getenv("PKG_MARKER") == "SNAP": bluetooth_on_notif_snap() + if IS_INSTALLED_WITH_SNAP: bluetooth_on_notif_snap() if bluetoothctl_exists: print("* Turn on bluetooth on boot") btconf = "/etc/bluetooth/main.conf" @@ -183,10 +183,10 @@ def gnome_power_rm_reminder_snap(): print("Unable to detect state of GNOME Power Profiles daemon service!") print("Now it's recommended to enable this service.") print("\nSteps to perform this action using auto-cpufreq: power_helper script:") - print("git clone https://github.com/AdnanHodzic/auto-cpufreq.git") + print(f"git clone {GITHUB}.git") print("cd auto-cpufreq/auto_cpufreq") print("python3 power_helper.py --gnome_power_enable") - print("\nReference: https://github.com/AdnanHodzic/auto-cpufreq#configuring-auto-cpufreq") + print(f"\nReference: {GITHUB}#configuring-auto-cpufreq") def valid_options(): print("--gnome_power_enable\t\tEnable GNOME Power Profiles daemon") @@ -203,7 +203,7 @@ def disable_power_profiles_daemon(): except: print("\nUnable to disable GNOME power profiles") print("If this causes any problems, please submit an issue:") - print("https://github.com/AdnanHodzic/auto-cpufreq/issues") + print(GITHUB+"/issues") # default gnome_power_svc_disable func (balanced) def gnome_power_svc_disable(): @@ -213,8 +213,8 @@ def gnome_power_svc_disable(): try: # check if snap package installed snap_pkg_check = call(['snap', 'list', '|', 'grep', 'auto-cpufreq'], - stdout=subprocess.DEVNULL, - stderr=subprocess.STDOUT) + stdout=DEVNULL, + stderr=STDOUT) # check if snapd is present and if snap package is installed | 0 is success if not bool(snap_pkg_check): print("GNOME Power Profiles Daemon is already disabled, it can be re-enabled by running:\n" @@ -262,7 +262,7 @@ def main( root_check() header() - if len(sys.argv) == 1: print('Unrecognized option!\n\nRun: "' + app_name + ' --help" for list of available options.') + if len(argv) == 1: print('Unrecognized option!\n\nRun: "' + app_name + ' --help" for list of available options.') else: if gnome_power_enable: gnome_power_svc_enable() elif gnome_power_disable: gnome_power_svc_disable() diff --git a/auto_cpufreq/utils/__init__.py b/auto_cpufreq/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/auto_cpufreq/utils/config_event_handler.py b/auto_cpufreq/utils/config_event_handler.py deleted file mode 100644 index 7dc79bc0..00000000 --- a/auto_cpufreq/utils/config_event_handler.py +++ /dev/null @@ -1,29 +0,0 @@ -import pyinotify - -class ConfigEventHandler(pyinotify.ProcessEvent): - def __init__(self, config) -> None: - self.config = config - - def _process_update(self, event: pyinotify.Event): - if event.pathname.rstrip("~") == self.config.path: - self.config.update_config() - - # activates when auto-cpufreq config file is modified - def process_IN_MODIFY(self, event: pyinotify.Event) -> None: - self._process_update(event) - - # activates when auto-cpufreq config file is deleted - def process_IN_DELETE(self, event: pyinotify.Event) -> None: - self._process_update(event) - - # activates when auto-cpufreq config file is created - def process_IN_CREATE(self, event: pyinotify.Event) -> None: - self._process_update(event) - - # activates when auto-cpufreq config file is moved from watched directory - def process_IN_MOVED_FROM(self, event: pyinotify.Event) -> None: - self._process_update(event) - - # activates when auto-cpufreq config file is moved into the watched directory - def process_IN_MOVED_TO(self, event: pyinotify.Event) -> None: - self._process_update(event) \ No newline at end of file diff --git a/nix/patches/prevent-install-and-copy.patch b/nix/patches/prevent-install-and-copy.patch index 7e1eced0..a1c3e14e 100644 --- a/nix/patches/prevent-install-and-copy.patch +++ b/nix/patches/prevent-install-and-copy.patch @@ -1,23 +1,16 @@ diff --git a/auto_cpufreq/core.py b/auto_cpufreq/core.py -index 99397a9..16869ab 100755 +index 6ee9986..5015982 100755 --- a/auto_cpufreq/core.py +++ b/auto_cpufreq/core.py -@@ -350,29 +350,12 @@ def get_current_gov(): - +@@ -260,18 +260,12 @@ def get_current_gov(): + ) def cpufreqctl(): - """ -- deploy cpufreqctl script +- deploy cpufreqctl.auto-cpufreq script - """ -- -- # detect if running on a SNAP -- if os.getenv("PKG_MARKER") == "SNAP": -- pass -- else: -- # deploy cpufreqctl.auto-cpufreq script -- if not os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq"): -- shutil.copy(SCRIPTS_DIR / "cpufreqctl.sh", "/usr/local/bin/cpufreqctl.auto-cpufreq") -- +- if not (IS_INSTALLED_WITH_SNAP or os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq")): +- copy(SCRIPTS_DIR / "cpufreqctl.sh", "/usr/local/bin/cpufreqctl.auto-cpufreq") + # scripts are already in the correct place + pass @@ -25,55 +18,48 @@ index 99397a9..16869ab 100755 - """ - remove cpufreqctl.auto-cpufreq script - """ -- # detect if running on a SNAP -- if os.getenv("PKG_MARKER") == "SNAP": -- pass -- else: -- if os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq"): -- os.remove("/usr/local/bin/cpufreqctl.auto-cpufreq") +- if not IS_INSTALLED_WITH_SNAP and os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq"): +- os.remove("/usr/local/bin/cpufreqctl.auto-cpufreq") + #no need to restore + pass + def footer(l=79): print("\n" + "-" * l + "\n") - def footer(l=79): -@@ -400,30 +383,8 @@ def remove_complete_msg(): - +@@ -287,27 +281,8 @@ def remove_complete_msg(): + footer() def deploy_daemon(): - print("\n" + "-" * 21 + " Deploying auto-cpufreq as a daemon " + "-" * 22 + "\n") - -- # deploy cpufreqctl script func call -- cpufreqctl() +- cpufreqctl() # deploy cpufreqctl script func call - -- # turn off bluetooth on boot -- bluetooth_disable() +- bluetooth_disable() # turn off bluetooth on boot - - auto_cpufreq_stats_path.touch(exist_ok=True) - - print("\n* Deploy auto-cpufreq install script") -- shutil.copy(SCRIPTS_DIR / "auto-cpufreq-install.sh", "/usr/local/bin/auto-cpufreq-install") +- copy(SCRIPTS_DIR / "auto-cpufreq-install.sh", "/usr/local/bin/auto-cpufreq-install") - - print("\n* Deploy auto-cpufreq remove script") -- shutil.copy(SCRIPTS_DIR / "auto-cpufreq-remove.sh", "/usr/local/bin/auto-cpufreq-remove") +- copy(SCRIPTS_DIR / "auto-cpufreq-remove.sh", "/usr/local/bin/auto-cpufreq-remove") - - # output warning if gnome power profile is running - gnome_power_detect_install() - gnome_power_svc_disable() - -- # output warning if TLP service is detected -- tlp_service_detect() +- tlp_service_detect() # output warning if TLP service is detected - - call("/usr/local/bin/auto-cpufreq-install", shell=True) + # prevent needless copying and system changes + pass - def deploy_daemon_performance(): -@@ -463,40 +424,7 @@ def deploy_daemon_performance(): + print("\n" + "-" * 21 + " Deploying auto-cpufreq as a daemon (performance) " + "-" * 22 + "\n") +@@ -339,35 +314,7 @@ def deploy_daemon_performance(): - # remove auto-cpufreq daemon - def remove_daemon(): -- + call("/usr/local/bin/auto-cpufreq-install", shell=True) + +-def remove_daemon(): - # check if auto-cpufreq is installed - if not os.path.exists("/usr/local/bin/auto-cpufreq-remove"): - print("\nauto-cpufreq daemon is not installed.\n") @@ -81,8 +67,7 @@ index 99397a9..16869ab 100755 - - print("\n" + "-" * 21 + " Removing auto-cpufreq daemon " + "-" * 22 + "\n") - -- # turn on bluetooth on boot -- bluetooth_enable() +- bluetooth_enable() # turn on bluetooth on boot - - # output warning if gnome power profile is stopped - gnome_power_rm_reminder() @@ -95,19 +80,15 @@ index 99397a9..16869ab 100755 - os.remove("/usr/local/bin/auto-cpufreq-remove") - - # delete override pickle if it exists -- if os.path.exists(governor_override_state): -- os.remove(governor_override_state) +- if os.path.exists(governor_override_state): os.remove(governor_override_state) - - # delete stats file - if auto_cpufreq_stats_path.exists(): -- if auto_cpufreq_stats_file is not None: -- auto_cpufreq_stats_file.close() -- +- if auto_cpufreq_stats_file is not None: auto_cpufreq_stats_file.close() - auto_cpufreq_stats_path.unlink() - -- # restore original cpufrectl script -- cpufreqctl_restore() -+ pass - +- cpufreqctl_restore() # restore original cpufrectl script ++def remove_daemon(): pass def gov_check(): + for gov in AVAILABLE_GOVERNORS: