mirror of
https://github.com/nwg-piotr/nwg-shell.git
synced 2024-09-11 22:27:23 +03:00
318 lines
12 KiB
Python
318 lines
12 KiB
Python
#!/usr/bin/python3
|
|
|
|
"""
|
|
Installer script to copy all the components' configs and style sheets to their locations, or to restore original files.
|
|
Pass the `--all` argument to install/overwrite all, or use w/ no argument to restore selected files interactively.
|
|
This script is primarily intended to work (and tested!) on fresh installed Arch Linux.
|
|
See: https://github.com/nwg-piotr/nwg-shell/wiki
|
|
|
|
The package dependencies should pull all the packages needed for the nwg-shell to run.
|
|
|
|
Project: https://github.com/nwg-piotr/nwg-shell
|
|
Author's email: nwg.piotr@gmail.com
|
|
Copyright (c) 2022 Piotr Miller
|
|
License: MIT
|
|
"""
|
|
|
|
import argparse
|
|
import datetime
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
from shutil import copy, copy2
|
|
|
|
from nwg_shell.__about__ import __version__
|
|
|
|
from nwg_shell.tools import load_json, save_json, is_command
|
|
|
|
dir_name = os.path.dirname(__file__)
|
|
|
|
config_home = os.getenv('XDG_CONFIG_HOME') if os.getenv('XDG_CONFIG_HOME') else os.path.join(os.getenv("HOME"),
|
|
".config")
|
|
|
|
data_home = os.getenv('XDG_DATA_HOME') if os.getenv('XDG_DATA_HOME') else os.path.join(os.getenv("HOME"),
|
|
".local/share")
|
|
|
|
shell_data = None
|
|
shell_data_file = os.path.join(data_home, "nwg-shell/data")
|
|
|
|
browsers = {
|
|
"brave": "brave --enable-features=UseOzonePlatform --ozone-platform=wayland",
|
|
"chromium": "chromium --enable-features=UseOzonePlatform --ozone-platform=wayland",
|
|
"google-chrome-stable": "google-chrome-stable --enable-features=UseOzonePlatform --ozone-platform=wayland",
|
|
"epiphany": "epiphany",
|
|
"falkon": "falkon",
|
|
"firefox": "MOZ_ENABLE_WAYLAND=1 firefox",
|
|
"konqueror": "konqueror",
|
|
"midori": "midori",
|
|
"microsoft-edge-stable": "microsoft-edge-stable --enable-features=UseOzonePlatform --ozone-platform=wayland",
|
|
"opera": "opera",
|
|
"qutebrowser": "qutebrowser",
|
|
"seamonkey": "seamonkey",
|
|
"surf": "surf",
|
|
"vivaldi-stable": "vivaldi-stable --enable-features=UseOzonePlatform --ozone-platform=wayland",
|
|
}
|
|
|
|
|
|
def copy_folder(src, dst, hyprland=False):
|
|
if not os.path.isdir(dst):
|
|
os.mkdir(dst)
|
|
|
|
for item in os.listdir(src):
|
|
if hyprland or "hyprland" not in item:
|
|
print(" {}".format(item))
|
|
copy2(os.path.join(src, item), os.path.join(dst, item))
|
|
|
|
|
|
def copy_from_skel(name, folder="config", skip_confirmation=False, hyprland=False):
|
|
src = os.path.join(dir_name, "skel/{}/".format(folder), name)
|
|
if folder == "data":
|
|
dst = os.path.join(data_home, name)
|
|
else:
|
|
dst = os.path.join(config_home, name)
|
|
|
|
a = input("Install/overwrite files in the '{}' directory? y/N ".format(dst)) if not skip_confirmation else "Y"
|
|
if a.strip().upper() != "Y":
|
|
print("'{}' directory skipped".format(dst))
|
|
return
|
|
|
|
else:
|
|
print("Copying files to '{}'".format(dst))
|
|
try:
|
|
# copytree(src, dst, dirs_exist_ok=True)
|
|
copy_folder(src, dst, hyprland=hyprland)
|
|
except Exception as e:
|
|
print("Failure: {}".format(e), file=sys.stderr)
|
|
|
|
|
|
def restore(name, folder="config"):
|
|
src = os.path.join(dir_name, "skel/{}/".format(folder), name)
|
|
if folder == "data":
|
|
dst = os.path.join(data_home, name)
|
|
if not os.path.isdir(dst):
|
|
os.mkdir(dst)
|
|
else:
|
|
dst = os.path.join(config_home, name)
|
|
if not os.path.isdir(dst):
|
|
os.mkdir(dst)
|
|
|
|
response = []
|
|
|
|
for f in os.listdir(src):
|
|
src_path = os.path.join(src, f)
|
|
dst_path = os.path.join(dst, f)
|
|
try:
|
|
if not os.path.isfile(dst_path):
|
|
copy(src_path, dst_path, follow_symlinks=False)
|
|
response.append("Copied '{}'".format(dst_path))
|
|
|
|
except Exception as e:
|
|
response.append("Couldn't copy '{}' to '{}': {}".format(src_path, dst_path, e))
|
|
|
|
return "\n".join(response) if len(response) > 0 else None
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("-a",
|
|
"--all",
|
|
action="store_true",
|
|
help="install/overwrite All configs and styles w/o confirmation")
|
|
parser.add_argument("-hypr",
|
|
action="store_true",
|
|
help="install Hyprland presets; use together w/ -a or -w")
|
|
parser.add_argument("-r",
|
|
"--restore",
|
|
action="store_true",
|
|
help="Restore missing configs, styles & data files")
|
|
parser.add_argument("-w",
|
|
"--web",
|
|
action="store_true",
|
|
help="Web installer - skip confirmations")
|
|
parser.add_argument("-k",
|
|
"--keyboard_layout",
|
|
type=str,
|
|
default="",
|
|
help="Preselect keyboard layout")
|
|
parser.add_argument("-s",
|
|
"--skip_reboot",
|
|
action="store_true",
|
|
help="Skip final messages and reboot")
|
|
parser.add_argument("-v",
|
|
"--version",
|
|
action="version",
|
|
version="%(prog)s version {}".format(__version__),
|
|
help="display Version information")
|
|
args = parser.parse_args()
|
|
|
|
if args.restore:
|
|
summary = []
|
|
items = ["sway", "nwg-panel", "nwg-drawer", "nwg-dock", "nwg-bar", "nwg-look", "swaync", "swaync", "foot",
|
|
"gtklock"]
|
|
if args.hypr:
|
|
items.append("hypr")
|
|
items.append("nwg-dock-hyprland")
|
|
for item in items:
|
|
r = restore(item, folder="config")
|
|
if r:
|
|
summary.append(r)
|
|
for item in ["nwg-look"]:
|
|
r = restore(item, folder="data")
|
|
if r:
|
|
summary.append(r)
|
|
if len(summary) > 0:
|
|
print("\n".join(summary))
|
|
|
|
sys.exit(0)
|
|
|
|
global shell_data
|
|
|
|
if not args.web:
|
|
print("\n*******************************************************************")
|
|
print(" This script installs/overwrites configs and style sheets ")
|
|
print(" for sway, Hyprland and nwg-shell components. ")
|
|
print(" The only backup that will be made is the main sway config file. ")
|
|
print(" This script should be used on a fresh Arch Linux installation. ")
|
|
print(" If you're running it on your existing setup, ")
|
|
print(" you're doing it at your own risk. ")
|
|
print("*******************************************************************")
|
|
|
|
a = input("\nProceed? y/N ")
|
|
else:
|
|
a = "Y"
|
|
|
|
if a.strip().upper() != "Y":
|
|
print("Installation cancelled")
|
|
sys.exit(0)
|
|
else:
|
|
if not os.path.isfile(shell_data_file):
|
|
# It must be a new installation. We need to init and save the shell data file.
|
|
if not os.path.isdir(os.path.join(data_home, "nwg-shell")):
|
|
os.makedirs(os.path.join(data_home, "nwg-shell"))
|
|
shell_data = {
|
|
"installed-version": __version__,
|
|
"updates": [__version__],
|
|
"interface-locale": ""
|
|
}
|
|
save_json(shell_data, shell_data_file)
|
|
|
|
else:
|
|
# Installing over existing install
|
|
shell_data = load_json(shell_data_file)
|
|
# We no longer need the pre-v0.3.0 "last-upgrade" key: delete it if found
|
|
if "last-upgrade" in shell_data:
|
|
del shell_data["last-upgrade"]
|
|
save_json(shell_data, shell_data_file)
|
|
|
|
# Backup sway config file (we may have none on fresh installation)
|
|
now = datetime.datetime.now()
|
|
new_name = now.strftime("config-backup-%Y%m%d-%H%M%S")
|
|
src = os.path.join(config_home, "sway/config")
|
|
dst = os.path.join(config_home, "sway/{}".format(new_name))
|
|
proceed = True
|
|
try:
|
|
if os.path.isfile(src):
|
|
copy(src, dst)
|
|
print("* Original sway config file copied to '{}'".format(new_name))
|
|
except Exception as e:
|
|
print("Error: {}".format(e))
|
|
a = input("Proceed with installation? y/N ")
|
|
proceed = a.strip().upper() == "Y"
|
|
|
|
if proceed:
|
|
skip = args.all or args.web
|
|
items = ["sway", "nwg-panel", "nwg-drawer", "nwg-dock", "nwg-bar", "nwg-look", "swaync", "foot", "gtklock",
|
|
"gtk-3.0"]
|
|
if args.hypr:
|
|
items.append("hypr")
|
|
items.append("nwg-dock-hyprland")
|
|
for item in items:
|
|
copy_from_skel(item, folder="config", skip_confirmation=skip, hyprland=args.hypr)
|
|
for item in ["nwg-look", "nwg-shell-config"]:
|
|
copy_from_skel(item, folder="data", skip_confirmation=skip, hyprland=args.hypr)
|
|
|
|
# Detect default apps and keyboard layout
|
|
shell_config_settings_file = os.path.join(data_home, "nwg-shell-config", "settings")
|
|
shell_config_settings = load_json(shell_config_settings_file)
|
|
|
|
shell_config_settings_hyprland_file = os.path.join(data_home, "nwg-shell-config", "settings-hyprland")
|
|
shell_config_settings_hyprland = load_json(shell_config_settings_hyprland_file)
|
|
|
|
settings = [shell_config_settings]
|
|
if args.hypr:
|
|
settings.append(shell_config_settings_hyprland)
|
|
|
|
# Set default apps, if found
|
|
for s in settings:
|
|
if "terminal" not in s or not s["terminal"]:
|
|
s["terminal"] = "foot"
|
|
|
|
if "file-manager" not in s or not s["file-manager"]:
|
|
for cmd in ["thunar", "caja", "dolphin", "nautilus", "nemo", "pcmanfm"]:
|
|
if is_command(cmd):
|
|
s["file-manager"] = cmd
|
|
break
|
|
|
|
if "editor" not in s or not s["editor"]:
|
|
for cmd in ["mousepad", "atom", "emacs", "gedit", "geany", "kate", "vim"]:
|
|
if is_command(cmd):
|
|
s["editor"] = cmd
|
|
break
|
|
|
|
if "browser" not in s or not s["browser"]:
|
|
for cmd in ["brave", "chromium", "google-chrome-stable", "epiphany", "falkon", "firefox", "konqueror",
|
|
"midori", "microsoft-edge-stable", "opera", "qutebrowser", "seamonkey", "surf",
|
|
"vivaldi-stable"]:
|
|
if is_command(cmd):
|
|
s["browser"] = browsers[cmd]
|
|
break
|
|
|
|
keymap = args.keyboard_layout
|
|
# Detect keyboard layout (requires systemd)
|
|
if not keymap and is_command("localectl"):
|
|
try:
|
|
lines = subprocess.check_output("localectl status", shell=True).decode("utf-8").strip().splitlines()
|
|
for line in lines:
|
|
if "VC Keymap" in line:
|
|
if "unset" not in line:
|
|
keymap = line.split()[-1]
|
|
break
|
|
except subprocess.CalledProcessError:
|
|
pass
|
|
|
|
if keymap:
|
|
shell_config_settings["keyboard-xkb-layout"] = keymap
|
|
if shell_config_settings_hyprland:
|
|
shell_config_settings_hyprland["input-kb_layout"] = keymap
|
|
|
|
save_json(shell_config_settings, shell_config_settings_file)
|
|
if args.hypr:
|
|
save_json(shell_config_settings_hyprland, shell_config_settings_hyprland_file)
|
|
|
|
# Copy default background
|
|
bcg = os.path.join(os.getenv("HOME"), "azotebg")
|
|
if not os.path.isfile(bcg):
|
|
print("Copying default background")
|
|
copy(os.path.join(dir_name, "skel", "stuff", "azotebg"), bcg)
|
|
os.rename(bcg, os.path.join(os.getenv("HOME"), ".azotebg"))
|
|
copy(os.path.join(os.getenv("HOME"), ".azotebg"), os.path.join(os.getenv("HOME"), ".azotebg-hyprland"))
|
|
|
|
if not args.skip_reboot:
|
|
if not args.web:
|
|
if is_command("Hyprland"):
|
|
print("\nThat's all. You may run sway or Hyprland now.\n")
|
|
else:
|
|
print("\nThat's all. You may run sway now.\n")
|
|
else:
|
|
print("Your computer will now restart...")
|
|
time.sleep(3)
|
|
if is_command("systemctl"):
|
|
subprocess.call("sudo systemctl reboot -f", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
|
else:
|
|
subprocess.call("sudo reboot", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|