refactor(root): remove legacy lapctl.py and update roadmap status

The removed file contained outdated GPU power‑management integration now handled elsewhere; updating the README marks the associated tasks as completed.

Enhancements:
- Marked CLI structure, GPU mode switching, and hardware status command as completed.
This commit is contained in:
sankalp committed 2026-03-11 23:36:57 +05:45
1 parent fb69cdc63c
commit c0481b1149
3 files changed
+4 -818

No files matched your search

+1
View File
@@ -25,3 +25,4 @@ target
/target
./lapctl.py
lapctl.py
+3 -3
View File
@@ -93,10 +93,10 @@ lapctl
## Roadmap
- [ ] CLI structure
- [ ] GPU mode switching
- [x] CLI structure
- [x] GPU mode switching
- [ ] Battery charge limit management
- [ ] Hardware status command
- [x] Hardware status command
- [ ] Configuration support
---
-815
View File
@@ -1,815 +0,0 @@
#!/usr/bin/env python3
import argparse
import logging
import os
import re
import shutil
import subprocess
import sys
from contextlib import contextmanager
# begin constants definition
VERSION = "3.5.2"
# Note: Do NOT remove this in cleanup!
CACHE_FILE_PATH = "/var/cache/lapctl/cache.json"
BLACKLIST_PATH = "/etc/modprobe.d/blacklist-nvidia.conf"
BLACKLIST_CONTENT = """# Automatically generated by lapctl
blacklist nouveau
blacklist nova_core
blacklist nova_drm
blacklist nvidia
blacklist nvidia_drm
blacklist nvidia_uvm
blacklist nvidia_modeset
blacklist nvidia_current
blacklist nvidia_current_drm
blacklist nvidia_current_uvm
blacklist nvidia_current_modeset
blacklist i2c_nvidia_gpu
alias nouveau off
alias nova_core off
alias nova_drm off
alias nvidia off
alias nvidia_drm off
alias nvidia_uvm off
alias nvidia_modeset off
alias nvidia_current off
alias nvidia_current_drm off
alias nvidia_current_uvm off
alias nvidia_current_modeset off
alias i2c_nvidia_gpu off
"""
UDEV_INTEGRATED_PATH = "/etc/udev/rules.d/50-remove-nvidia.rules"
UDEV_INTEGRATED = """# Automatically generated by lapctl
# Remove NVIDIA USB xHCI Host Controller devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{power/control}="auto", ATTR{remove}="1"
# Remove NVIDIA USB Type-C UCSI devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{power/control}="auto", ATTR{remove}="1"
# Remove NVIDIA Audio devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{power/control}="auto", ATTR{remove}="1"
# Remove NVIDIA VGA/3D controller devices
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x03[0-9]*", ATTR{power/control}="auto", ATTR{remove}="1"
"""
UDEV_PM_PATH = "/etc/udev/rules.d/80-nvidia-pm.rules"
UDEV_PM_CONTENT = """# Automatically generated by lapctl
# Remove NVIDIA USB xHCI Host Controller devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{remove}="1"
# Remove NVIDIA USB Type-C UCSI devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{remove}="1"
# Remove NVIDIA Audio devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{remove}="1"
# Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto"
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto"
# Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on"
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on"
"""
XORG_PATH = "/etc/X11/xorg.conf"
XORG_INTEL = """# Automatically generated by lapctl
Section "ServerLayout"
Identifier "layout"
Screen 0 "nvidia"
Inactive "intel"
EndSection
Section "Device"
Identifier "nvidia"
Driver "nvidia"
BusID "{}"
EndSection
Section "Screen"
Identifier "nvidia"
Device "nvidia"
Option "AllowEmptyInitialConfiguration"
EndSection
Section "Device"
Identifier "intel"
Driver "modesetting"
EndSection
Section "Screen"
Identifier "intel"
Device "intel"
EndSection
"""
XORG_AMD = """# Automatically generated by lapctl
Section "ServerLayout"
Identifier "layout"
Screen 0 "nvidia"
Inactive "amdgpu"
EndSection
Section "Device"
Identifier "nvidia"
Driver "nvidia"
BusID "{}"
EndSection
Section "Screen"
Identifier "nvidia"
Device "nvidia"
Option "AllowEmptyInitialConfiguration"
EndSection
Section "Device"
Identifier "amdgpu"
Driver "amdgpu"
EndSection
Section "Screen"
Identifier "amd"
Device "amdgpu"
EndSection
"""
EXTRA_XORG_PATH = "/etc/X11/xorg.conf.d/10-nvidia.conf"
EXTRA_XORG_CONTENT = """# Automatically generated by lapctl
Section "OutputClass"
Identifier "nvidia"
MatchDriver "nvidia-drm"
Driver "nvidia"
"""
FORCE_COMP = ' Option "ForceCompositionPipeline" "true"\n'
COOLBITS = ' Option "Coolbits" "{}"\n'
MODESET_PATH = "/etc/modprobe.d/nvidia.conf"
MODESET_CONTENT = """# Automatically generated by lapctl
options nvidia-drm modeset=1
options nvidia NVreg_UsePageAttributeTable=1 NVreg_InitializeSystemMemoryAllocations=0
"""
MODESET_CURRENT_CONTENT = """# Automatically generated by lapctl
options nvidia-current-drm modeset=1
options nvidia-current NVreg_UsePageAttributeTable=1 NVreg_InitializeSystemMemoryAllocations=0
"""
MODESET_RTD3 = """# Automatically generated by lapctl
options nvidia-drm modeset=1
options nvidia "NVreg_DynamicPowerManagement=0x0{}"
options nvidia NVreg_UsePageAttributeTable=1 NVreg_InitializeSystemMemoryAllocations=0
"""
MODESET_CURRENT_RTD3 = """# Automatically generated by lapctl
options nvidia-current-drm modeset=1
options nvidia-current "NVreg_DynamicPowerManagement=0x0{}"
options nvidia-current NVreg_UsePageAttributeTable=1 NVreg_InitializeSystemMemoryAllocations=0
"""
SDDM_XSETUP_PATH = "/usr/share/sddm/scripts/Xsetup"
SDDM_XSETUP_CONTENT = """#!/bin/sh
# Xsetup - run as root before the login dialog appears
"""
LIGHTDM_SCRIPT_PATH = "/etc/lightdm/nvidia.sh"
LIGHTDM_CONFIG_PATH = "/etc/lightdm/lightdm.conf.d/20-nvidia.conf"
LIGHTDM_CONFIG_CONTENT = """# Automatically generated by lapctl
[Seat:*]
display-setup-script=/etc/lightdm/nvidia.sh
"""
NVIDIA_XRANDR_SCRIPT = """#!/bin/sh
# Automatically generated by lapctl
current=""
xrandr --setprovideroutputsource "{}" NVIDIA-0
xrandr --auto
for next in $(xrandr --listmonitors | grep -E " *[0-9]+:.*" | cut -d" " -f6); do
[ -z "$current" ] && current=$next && continue
xrandr --output "$current" --auto --output "$next" --auto --right-of "$current"
current=$next
done
"""
SUPPORTED_MODES = ["integrated", "hybrid", "nvidia"]
SUPPORTED_DISPLAY_MANAGERS = ["gdm", "gdm3", "sddm", "lightdm"]
RTD3_MODES = [0, 1, 2, 3]
# end constants definition
def graphics_mode_switcher(
graphics_mode,
user_display_manager,
enable_force_comp,
coolbits_value,
rtd3_value,
use_nvidia_current,
):
print(f"Switching to {graphics_mode} mode")
if graphics_mode == "integrated":
if logging.getLogger().level == logging.DEBUG:
service = subprocess.run(
["systemctl", "disable", "nvidia-persistenced.service"]
)
else:
service = subprocess.run(
["systemctl", "disable", "nvidia-persistenced.service"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
if service.returncode == 0:
print("Successfully disabled nvidia-persistenced.service")
else:
logging.error("An error ocurred while disabling service")
cleanup()
# blacklist all nouveau, nova and Nvidia modules
create_file(BLACKLIST_PATH, BLACKLIST_CONTENT)
# power off the Nvidia GPU with udev rules
create_file(UDEV_INTEGRATED_PATH, UDEV_INTEGRATED)
rebuild_initramfs()
elif graphics_mode == "hybrid":
print(
f"Enable PCI-Express Runtime D3 (RTD3) Power Management: {rtd3_value or False}"
)
cleanup()
if logging.getLogger().level == logging.DEBUG:
service = subprocess.run(
["systemctl", "enable", "nvidia-persistenced.service"]
)
else:
service = subprocess.run(
["systemctl", "enable", "nvidia-persistenced.service"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
if service.returncode == 0:
print("Successfully enabled nvidia-persistenced.service")
else:
logging.error("An error ocurred while enabling service")
if rtd3_value == None:
if use_nvidia_current:
create_file(MODESET_PATH, MODESET_CURRENT_CONTENT)
else:
create_file(MODESET_PATH, MODESET_CONTENT)
else:
# setup rtd3
if use_nvidia_current:
create_file(MODESET_PATH, MODESET_CURRENT_RTD3.format(rtd3_value))
else:
create_file(MODESET_PATH, MODESET_RTD3.format(rtd3_value))
create_file(UDEV_PM_PATH, UDEV_PM_CONTENT)
rebuild_initramfs()
elif graphics_mode == "nvidia":
print(f"Enable ForceCompositionPipeline: {enable_force_comp}")
print(f"Enable Coolbits: {coolbits_value or False}")
if logging.getLogger().level == logging.DEBUG:
service = subprocess.run(
["systemctl", "enable", "nvidia-persistenced.service"]
)
else:
service = subprocess.run(
["systemctl", "enable", "nvidia-persistenced.service"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
if service.returncode == 0:
print("Successfully enabled nvidia-persistenced.service")
else:
logging.error("An error ocurred while enabling service")
cleanup()
# get the Nvidia dGPU PCI bus
nvidia_gpu_pci_bus = get_nvidia_gpu_pci_bus()
# get iGPU vendor
igpu_vendor = get_igpu_vendor()
# create the X.org config
if igpu_vendor == "intel":
create_file(XORG_PATH, XORG_INTEL.format(nvidia_gpu_pci_bus))
elif igpu_vendor == "amd":
create_file(XORG_PATH, XORG_AMD.format(nvidia_gpu_pci_bus))
# enable modeset for Nvidia driver
if use_nvidia_current:
create_file(MODESET_PATH, MODESET_CURRENT_CONTENT)
else:
create_file(MODESET_PATH, MODESET_CONTENT)
# extra Xorg config
if enable_force_comp and coolbits_value != None:
create_file(
EXTRA_XORG_PATH,
EXTRA_XORG_CONTENT
+ FORCE_COMP
+ COOLBITS.format(coolbits_value)
+ "EndSection\n",
)
elif enable_force_comp:
create_file(
EXTRA_XORG_PATH, EXTRA_XORG_CONTENT + FORCE_COMP + "EndSection\n"
)
elif coolbits_value != None:
create_file(
EXTRA_XORG_PATH,
EXTRA_XORG_CONTENT + COOLBITS.format(coolbits_value) + "EndSection\n",
)
# try to detect the display manager if not provided
if user_display_manager == None:
display_manager = get_display_manager()
else:
display_manager = user_display_manager
# only sddm and lightdm require further config
if display_manager == "sddm":
# backup Xsetup
if os.path.exists(SDDM_XSETUP_PATH):
logging.info("Creating Xsetup backup")
with open(SDDM_XSETUP_PATH, mode="r", encoding="utf-8") as f:
create_file(SDDM_XSETUP_PATH + ".bak", f.read())
create_file(SDDM_XSETUP_PATH, generate_xrandr_script(igpu_vendor), True)
elif display_manager == "lightdm":
create_file(LIGHTDM_SCRIPT_PATH, generate_xrandr_script(igpu_vendor), True)
create_file(LIGHTDM_CONFIG_PATH, LIGHTDM_CONFIG_CONTENT)
rebuild_initramfs()
print("Operation completed successfully")
print("Please reboot your computer for changes to take effect!")
def cleanup():
# define list of files to remove
to_remove = [
BLACKLIST_PATH,
UDEV_INTEGRATED_PATH,
UDEV_PM_PATH,
XORG_PATH,
EXTRA_XORG_PATH,
MODESET_PATH,
LIGHTDM_SCRIPT_PATH,
LIGHTDM_CONFIG_PATH,
# legacy files
"/etc/X11/xorg.conf.d/90-nvidia.conf",
"/lib/udev/rules.d/50-remove-nvidia.rules",
"/lib/udev/rules.d/80-nvidia-pm.rules",
]
# remove each file in the list
for file_path in to_remove:
try:
if os.path.exists(file_path):
os.remove(file_path)
logging.info(f"Removed file {file_path}")
except OSError as e:
# only warn if file exists (code 2)
if e.errno != 2:
logging.error(f"Failed to remove file '{file_path}': {e}")
# restore Xsetup backup if found
backup_path = SDDM_XSETUP_PATH + ".bak"
if os.path.exists(backup_path):
logging.info("Restoring Xsetup backup")
with open(backup_path, mode="r", encoding="utf-8") as f:
create_file(SDDM_XSETUP_PATH, f.read())
# remove backup
os.remove(backup_path)
logging.info(f"Removed file {backup_path}")
def get_nvidia_gpu_pci_bus():
lspci_output = subprocess.check_output(["lspci"]).decode("utf-8")
for line in lspci_output.splitlines():
if "NVIDIA" in line and (
"VGA compatible controller" in line or "3D controller" in line
):
# remove leading zeros
pci_bus_id = line.split()[0].replace("0000:", "")
logging.info(f"Found Nvidia GPU at {pci_bus_id}")
break
else:
logging.error("Could not find Nvidia GPU")
print("Try switching to hybrid mode first!")
sys.exit(1)
# need to return the BusID in 'PCI:bus:device:function' format
# also perform hexadecimal to decimal conversion
bus, device_function = pci_bus_id.split(":")
device, function = device_function.split(".")
return f"PCI:{int(bus, 16)}:{int(device, 16)}:{int(function, 16)}"
def get_igpu_vendor():
lspci_output = subprocess.check_output(["lspci"]).decode("utf-8")
for line in lspci_output.splitlines():
if "VGA compatible controller" in line or "Display controller" in line:
if "Intel" in line:
logging.info("Found Intel iGPU")
return "intel"
elif "ATI" in line or "AMD" in line or "AMD/ATI" in line:
logging.info("Found AMD iGPU")
return "amd"
logging.warning("Could not find Intel or AMD iGPU")
return None
def get_display_manager():
try:
with open(
"/etc/systemd/system/display-manager.service", "r", encoding="utf-8"
) as f:
content = f.read()
match = re.search(r"ExecStart=(.+)\n", content)
if match:
# only return the final component of the path
display_manager = os.path.basename(match.group(1))
logging.info(f"Found {display_manager} Display Manager")
return display_manager
except FileNotFoundError:
logging.warning("Display Manager detection is not available")
def generate_xrandr_script(igpu_vendor):
if igpu_vendor == "intel":
return NVIDIA_XRANDR_SCRIPT.format("modesetting")
elif igpu_vendor == "amd":
amd_igpu_name = get_amd_igpu_name()
if amd_igpu_name != None:
return NVIDIA_XRANDR_SCRIPT.format(amd_igpu_name)
else:
return NVIDIA_XRANDR_SCRIPT.format("modesetting")
else:
return NVIDIA_XRANDR_SCRIPT.format("modesetting")
def get_amd_igpu_name():
if not os.path.exists("/usr/bin/xrandr"):
logging.warning(
"The 'xrandr' command is not available. Make sure the package is installed!"
)
return None
try:
xrandr_output = subprocess.check_output(["xrandr", "--listproviders"]).decode(
"utf-8"
)
except subprocess.CalledProcessError:
logging.warning("Failed to run the 'xrandr' command.")
pattern = re.compile(r"(name:).*(ATI*|AMD*|AMD\/ATI)*")
if pattern.findall(xrandr_output):
return re.search(pattern, xrandr_output).group(0)[5:]
else:
logging.warning("Could not find AMD iGPU in 'xrandr' output.")
return None
def rebuild_initramfs():
# OSTree systems first
if any(os.path.exists(dir) for dir in ["/ostree", "/sysroot/ostree"]):
print("Rebuilding the initramfs with rpm-ostree...")
command = ["rpm-ostree", "initramfs", "--enable", "--arg=--force"]
# Debian and Ubuntu derivatives
elif os.path.exists("/etc/debian_version"):
command = ["update-initramfs", "-u", "-k", "all"]
# RHEL and SUSE derivatives
elif os.path.exists("/etc/redhat-release") or os.path.exists("/usr/bin/zypper"):
command = ["dracut", "--force", "--regenerate-all"]
# EndeavourOS with dracut
elif os.path.exists("/usr/lib/endeavouros-release") and os.path.exists(
"/usr/bin/dracut"
):
command = ["dracut-rebuild"]
# ALT Linux
elif os.path.exists("/etc/altlinux-release"):
command = ["make-initrd"]
# Arch Linux
elif os.path.exists("/etc/arch-release"):
command = ["mkinitcpio", "-P"]
else:
command = []
if shutil.which("systemd-inhibit"):
command = [
"systemd-inhibit",
"--who=lapctl",
"--why",
"Rebuilding initramfs",
"--",
*command,
]
if len(command) != 0:
print("Rebuilding the initramfs...")
if logging.getLogger().level == logging.DEBUG:
p = subprocess.run(command)
else:
p = subprocess.run(
command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
if p.returncode == 0:
print("Successfully rebuilt the initramfs!")
else:
logging.error("An error ocurred while rebuilding the initramfs")
def create_file(path, content, executable=False):
try:
# create the parent folders if needed
if not os.path.exists(os.path.dirname(path)):
os.makedirs(os.path.dirname(path))
with open(path, mode="w", encoding="utf-8") as f:
f.write(content)
logging.info(f"Created file {path}")
if logging.getLogger().level == logging.DEBUG:
print(content)
# add execution privilege
if executable:
subprocess.run(["chmod", "+x", path], stdout=subprocess.DEVNULL)
logging.info(f"Added execution privilege to file {path}")
except OSError as e:
logging.error(f"Failed to create file '{path}': {e}")
def assert_root():
if os.geteuid() != 0:
logging.error("This operation requires root privileges")
sys.exit(1)
def main():
# define CLI arguments
parser = argparse.ArgumentParser()
parser.add_argument(
"-v",
"--version",
action="version",
version=VERSION,
help="Output the current version",
)
parser.add_argument(
"-q", "--query", action="store_true", help="Query the current graphics mode"
)
parser.add_argument(
"-s",
"--switch",
type=str,
metavar="MODE",
action="store",
choices=SUPPORTED_MODES,
help="Switch the graphics mode. Available choices: %(choices)s",
)
parser.add_argument(
"--dm",
type=str,
metavar="DISPLAY_MANAGER",
action="store",
choices=SUPPORTED_DISPLAY_MANAGERS,
help="Manually specify your Display Manager for Nvidia mode. Available choices: %(choices)s",
)
parser.add_argument(
"--force-comp",
action="store_true",
help="Enable ForceCompositionPipeline on Nvidia mode",
)
parser.add_argument(
"--coolbits",
type=int,
nargs="?",
metavar="VALUE",
action="store",
const=28,
help="Enable Coolbits on Nvidia mode. Default if specified: %(const)s",
)
parser.add_argument(
"--rtd3",
type=int,
nargs="?",
metavar="VALUE",
action="store",
choices=RTD3_MODES,
const=2,
help="Setup PCI-Express Runtime D3 (RTD3) Power Management on Hybrid mode. Available choices: %(choices)s. Default if specified: %(const)s",
)
parser.add_argument(
"--use-nvidia-current",
action="store_true",
help="Use nvidia-current instead of nvidia for kernel modules",
)
parser.add_argument(
"--reset-sddm", action="store_true", help="Restore default Xsetup file"
)
parser.add_argument(
"--reset", action="store_true", help="Revert changes made by lapctl"
)
parser.add_argument(
"--cache-create",
action="store_true",
help="Create cache used by lapctl; only works in hybrid mode",
)
parser.add_argument(
"--cache-delete",
action="store_true",
help="Delete cache created by lapctl",
)
parser.add_argument(
"--cache-query", action="store_true", help="Show cache created by lapctl"
)
parser.add_argument(
"--verbose", default=False, action="store_true", help="Enable verbose mode"
)
# print help if no arg is provided
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
# log formatting
logging.basicConfig(format="%(levelname)s: %(message)s")
# set debug level for verbose mode
if args.verbose:
logging.getLogger().setLevel(logging.DEBUG)
if args.query:
mode = get_current_mode()
print(mode)
return
elif args.cache_create:
assert_root()
CachedConfig(args).create_cache_file()
return
elif args.cache_delete:
assert_root()
CachedConfig.delete_cache_file()
return
elif args.cache_query:
CachedConfig.show_cache_file()
return
if args.switch or args.reset_sddm or args.reset:
with CachedConfig(args).adapter():
if args.switch:
assert_root()
graphics_mode_switcher(
args.switch,
args.dm,
args.force_comp,
args.coolbits,
args.rtd3,
args.use_nvidia_current,
)
elif args.reset_sddm:
assert_root()
create_file(SDDM_XSETUP_PATH, SDDM_XSETUP_CONTENT, True)
print("Operation completed successfully")
elif args.reset:
assert_root()
cleanup()
CachedConfig.delete_cache_file()
rebuild_initramfs()
print("Operation completed successfully")
class CachedConfig:
"""Adapter for config from CACHE_FILE_PATH"""
def __init__(self, app_args) -> None:
self.app_args = app_args
self.current_mode = get_current_mode()
@contextmanager
def adapter(self):
global get_nvidia_gpu_pci_bus
use_cache = os.path.exists(CACHE_FILE_PATH)
if self.is_hybrid(): # recreate cache file when in hybrid mode
self.create_cache_file()
if use_cache:
self.read_cache_file() # might not be in hybrid mode
# rebind function to use cached value instead of detection
get_nvidia_gpu_pci_bus = self.get_nvidia_gpu_pci_bus
yield # back to main ...
def create_cache_file(self):
if not self.is_hybrid():
raise ValueError(
"--cache-create requires that the system be in the hybrid Optimus mode"
)
self.nvidia_gpu_pci_bus = get_nvidia_gpu_pci_bus()
self.obj = self.create_cache_obj(self.nvidia_gpu_pci_bus)
self.write_cache_file()
def create_cache_obj(self, nvidia_gpu_pci_bus):
return {"nvidia_gpu_pci_bus": nvidia_gpu_pci_bus}
def is_hybrid(self):
return "hybrid" == self.current_mode
def get_nvidia_gpu_pci_bus(self):
return self.nvidia_gpu_pci_bus
@staticmethod
def delete_cache_file():
os.remove(CACHE_FILE_PATH)
os.removedirs(os.path.dirname(CACHE_FILE_PATH))
logging.debug(f"Removed file {CACHE_FILE_PATH}")
def read_cache_file(self):
from json import loads
if os.path.exists(CACHE_FILE_PATH):
with open(CACHE_FILE_PATH, "r", encoding="utf-8") as f:
content = f.read()
self.obj = loads(content)
self.nvidia_gpu_pci_bus = self.obj["nvidia_gpu_pci_bus"]
elif self.is_hybrid():
self.nvidia_gpu_pci_bus = get_nvidia_gpu_pci_bus()
else:
raise ValueError(
"No cache present. Operation requires that the system be in the hybrid Optimus mode"
)
@staticmethod
def show_cache_file():
content = f"ERROR: Could not read {CACHE_FILE_PATH}"
if os.path.exists(CACHE_FILE_PATH):
with open(CACHE_FILE_PATH, "r", encoding="utf-8") as f:
content = f.read()
print(content)
def write_cache_file(self):
from json import dump
os.makedirs(os.path.dirname(CACHE_FILE_PATH), exist_ok=True)
with open(CACHE_FILE_PATH, "w", encoding="utf-8") as f:
dump(self.obj, fp=f, indent=4, sort_keys=False)
logging.debug(f"Created file {CACHE_FILE_PATH}")
def get_current_mode():
mode = "hybrid"
if os.path.exists(BLACKLIST_PATH) and (
os.path.exists(UDEV_INTEGRATED_PATH)
or os.path.exists("/lib/udev/rules.d/50-remove-nvidia.rules")
):
mode = "integrated"
elif os.path.exists(XORG_PATH) and os.path.exists(MODESET_PATH):
mode = "nvidia"
return mode
if __name__ == "__main__":
main()