mirror of
				https://github.com/ItsDrike/dotfiles.git
				synced 2025-11-04 09:16:36 +00:00 
			
		
		
		
	remove deploy source
This commit is contained in:
		
							parent
							
								
									33cccffc7d
								
							
						
					
					
						commit
						20c1734cbc
					
				
					 11 changed files with 0 additions and 612 deletions
				
			
		| 
						 | 
				
			
			@ -1,9 +0,0 @@
 | 
			
		|||
if ! type "python3" &> /dev/null; then
 | 
			
		||||
	sudo pacman -S python
 | 
			
		||||
fi
 | 
			
		||||
if ! type "pip3" &> /dev/null; then
 | 
			
		||||
	sudo pacman -S python-pip
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
pip install -r requirements.txt
 | 
			
		||||
python3 -m src
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +0,0 @@
 | 
			
		|||
pyyaml
 | 
			
		||||
psutil
 | 
			
		||||
colorama
 | 
			
		||||
pyinquirer
 | 
			
		||||
inquirer
 | 
			
		||||
| 
						 | 
				
			
			@ -1,26 +0,0 @@
 | 
			
		|||
import sys
 | 
			
		||||
 | 
			
		||||
import colorama
 | 
			
		||||
import inquirer.shortcuts
 | 
			
		||||
 | 
			
		||||
from src.arch_install import install_arch
 | 
			
		||||
from src.dotfiles_install import install_dotfiles
 | 
			
		||||
from src.package_install import install_packages
 | 
			
		||||
from src.util.command import run_cmd
 | 
			
		||||
 | 
			
		||||
colorama.init(autoreset=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if inquirer.shortcuts.confirm("Do you wish to perform Arch install? (Directly from live ISO)"):
 | 
			
		||||
    run_cmd("clear")
 | 
			
		||||
    print(f"{colorama.Fore.BLUE}Running Arch Installation")
 | 
			
		||||
    root_mountpoint = install_arch()
 | 
			
		||||
    print(f"{colorama.Fore.GREEN}Arch installation complete")
 | 
			
		||||
    print(f"{colorama.Fore.CYAN}To install packages and dotfiles, move this whole directory to the new installation and run it from there.")
 | 
			
		||||
    sys.exit()
 | 
			
		||||
 | 
			
		||||
if inquirer.shortcuts.confirm("Do you wish to perform package installation (from packages.yaml)"):
 | 
			
		||||
    install_packages()
 | 
			
		||||
 | 
			
		||||
if inquirer.shortcuts.confirm("Do you wish to install dotfiles? (from home and root folders)"):
 | 
			
		||||
    install_dotfiles()
 | 
			
		||||
| 
						 | 
				
			
			@ -1,130 +0,0 @@
 | 
			
		|||
from pathlib import Path
 | 
			
		||||
from typing import Optional
 | 
			
		||||
 | 
			
		||||
import colorama
 | 
			
		||||
import inquirer.shortcuts
 | 
			
		||||
 | 
			
		||||
from src.util.command import run_cmd, run_root_cmd
 | 
			
		||||
from src.util.internet import connect_internet
 | 
			
		||||
 | 
			
		||||
colorama.init(autoreset=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def mount_partition(partition_path: Path, mount_path: Optional[Path] = None, default_path: str = "/mnt") -> Path:
 | 
			
		||||
    """
 | 
			
		||||
    Mount given `partition_path` to `mount_path`.;
 | 
			
		||||
    If `mount_path` wasn't provided, ask user for it.
 | 
			
		||||
 | 
			
		||||
    After mounting, mount_path will be returned
 | 
			
		||||
    """
 | 
			
		||||
    if not mount_path:
 | 
			
		||||
        mount_path = Path(inquirer.shortcuts.path(f"Specify mountpoint for {partition_path}", default=default_path))
 | 
			
		||||
 | 
			
		||||
    if not mount_path.exists():
 | 
			
		||||
        run_root_cmd(f"mkdir -p {mount_path}")
 | 
			
		||||
 | 
			
		||||
    run_root_cmd(f"mount {partition_path} {mount_path}")
 | 
			
		||||
    return mount_path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def partition_disk() -> Path:
 | 
			
		||||
    """Create all necessary partitions and return root mountpoint"""
 | 
			
		||||
    uefi = Path("/sys/firmware/efi/efivars").is_dir()
 | 
			
		||||
 | 
			
		||||
    # Let user make partitions in shell environment
 | 
			
		||||
    partitions_made = inquirer.shortcuts.confirm("Do you already have partitions pre-made?")
 | 
			
		||||
    if not partitions_made:
 | 
			
		||||
        print(
 | 
			
		||||
            f"{colorama.Fore.CYAN}Dropping to shell environment, create your partitions here."
 | 
			
		||||
            " When you are done, use `exit` to return\n"
 | 
			
		||||
            f"{colorama.Style.DIM}This is {'UEFI' if uefi else 'LEGACY (BIOS)'} system\n"
 | 
			
		||||
        )
 | 
			
		||||
        run_cmd("exec $SHELL")
 | 
			
		||||
 | 
			
		||||
    # Obtain partitions from user and mount them
 | 
			
		||||
    root_part = Path(inquirer.shortcuts.path("Specify the root partition (/dev/sdXY)", exists=True))
 | 
			
		||||
    if inquirer.shortcuts.confirm(f"Do you wish to make EXT4 filesystem on {root_part}?", default=True):
 | 
			
		||||
        run_root_cmd(f"mkfs.ext4 {root_part}")
 | 
			
		||||
    root_mountpoint = mount_partition(root_part)
 | 
			
		||||
 | 
			
		||||
    if inquirer.shortcuts.confirm("Do you have an EFI partition?", default=uefi):
 | 
			
		||||
        if not uefi:
 | 
			
		||||
            print(
 | 
			
		||||
                f"{colorama.Fore.RED}Warning: Adding EFI partition from non-uefi system isn't adviced.\n"
 | 
			
		||||
                "While this process won't directly fail, you won't be able to install a bootloader from "
 | 
			
		||||
                "this computer. You can proceed, but you will have to use another computer to install the bootloader."
 | 
			
		||||
            )
 | 
			
		||||
        efi_part = Path(inquirer.shortcuts.path("Specify EFI partition (/dev/sdXY)", exists=True))
 | 
			
		||||
        if inquirer.shortcuts.confirm(f"Do you wish to make FAT32 filesystem on {efi_part}?", default=True):
 | 
			
		||||
            run_root_cmd(f"mkfs.fat -F32 {efi_part}")
 | 
			
		||||
        mount_partition(efi_part, default_path=str(Path(root_mountpoint, "boot")))
 | 
			
		||||
    elif uefi:
 | 
			
		||||
        print(
 | 
			
		||||
            f"{colorama.Fore.RED}Proceeding without EFI partition on UEFI system is not adviced, "
 | 
			
		||||
            "unless you want to run this OS with other UEFI capable system"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    if inquirer.shortcuts.confirm("Do you have a swap partition?"):
 | 
			
		||||
        swap_part = Path(inquirer.shortcuts.path("Specify the swap partition (/dev/sdXY)", exists=True))
 | 
			
		||||
        if inquirer.shortcuts.confirm(f"Do you wish to make swap system on {root_part}?", default=True):
 | 
			
		||||
            run_root_cmd(f"mkswap {swap_part}")
 | 
			
		||||
        if inquirer.shortcuts.confirm("Do you wish to turn on swap?", default=True):
 | 
			
		||||
            run_root_cmd(f"swapon {swap_part}")
 | 
			
		||||
 | 
			
		||||
    while inquirer.shortcuts.confirm("Do you have any other partition?"):
 | 
			
		||||
        part_path = Path(inquirer.shortcuts.path("Specify partition path (/dev/sdXY)", exists=True))
 | 
			
		||||
        if inquirer.shortcuts.confirm("Do you wish to format this partition?"):
 | 
			
		||||
            print(f"{colorama.Fore.CYAN}Dropping to shell, format the partition here and type `exit` to return")
 | 
			
		||||
            run_cmd("exec $SHELL")
 | 
			
		||||
        mount_partition(part_path)
 | 
			
		||||
 | 
			
		||||
    print(f"{colorama.Fore.LIGHTCYAN_EX}Printing disk report (with lsblk)")
 | 
			
		||||
    run_root_cmd("lsblk")
 | 
			
		||||
    if inquirer.shortcuts.confirm("Do you want to drop to shell and make some further adjustments?"):
 | 
			
		||||
        print(f"{colorama.Fore.CYAN}After you are done, return by typing `exit`")
 | 
			
		||||
        run_cmd("exec $SHELL")
 | 
			
		||||
 | 
			
		||||
    print(f"{colorama.Fore.GREEN}Partitioning complete")
 | 
			
		||||
    return root_mountpoint
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def run_pacstrap(root_mountpoint: Path):
 | 
			
		||||
    mirror_setup = inquirer.shortcuts.confirm("Do you wish to setup your mirrors (This is necessary for fast downloads)?", default=True)
 | 
			
		||||
    if mirror_setup:
 | 
			
		||||
        print(
 | 
			
		||||
            f"{colorama.Fore.CYAN}Dropping to shell environment, setup your mirrors from here."
 | 
			
		||||
            " When you are done, use `exit` to return\n"
 | 
			
		||||
            f"{colorama.Style.DIM}Mirrors are located in `/etc/pacman.d/mirrorlist`\n"
 | 
			
		||||
        )
 | 
			
		||||
        run_cmd("exec $SHELL")
 | 
			
		||||
 | 
			
		||||
    extra_pkgs = inquirer.shortcuts.checkbox(
 | 
			
		||||
        "You can choose to install additional packages with pacstrap here (select with space)",
 | 
			
		||||
        choices=["networkmanager", "base-devel", "vim", "nano"]
 | 
			
		||||
    )
 | 
			
		||||
    run_root_cmd(f"pacstrap {root_mountpoint} base linux linux-firmware {' '.join(extra_pkgs)}")
 | 
			
		||||
 | 
			
		||||
    if inquirer.shortcuts.confirm("Do you wish to make some further adjustments and drop to shell?"):
 | 
			
		||||
        print(f"{colorama.Fore.CYAN}When you are done, use `exit` to return")
 | 
			
		||||
        run_cmd("exec $SHELL")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def install_arch():
 | 
			
		||||
    """Perform full Arch installation and return mountpoint and default user"""
 | 
			
		||||
    connect_internet()
 | 
			
		||||
 | 
			
		||||
    run_root_cmd("timedatectl set-ntp true")
 | 
			
		||||
    root_mountpoint = partition_disk()
 | 
			
		||||
    run_pacstrap(root_mountpoint)
 | 
			
		||||
    print(f"{colorama.Fore.CYAN}Generating fstab")
 | 
			
		||||
    run_root_cmd(f"genfstab -U {root_mountpoint} >> {root_mountpoint}/etc/fstab")
 | 
			
		||||
    print(
 | 
			
		||||
        f"\n{colorama.Fore.GREEN}Core installation complete.\n"
 | 
			
		||||
        f"{colorama.Fore.YELLOW}Instalation within chroot environment is not possible from this script, "
 | 
			
		||||
        "run chroot_install.py within chroot environment.\n"
 | 
			
		||||
        f"{colorama.Fore.LIGHTBLUE_EX}Execute: {colorama.Style.BRIGHT}`arch-chroot /mnt`"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    install_arch()
 | 
			
		||||
| 
						 | 
				
			
			@ -1,12 +0,0 @@
 | 
			
		|||
import colorama
 | 
			
		||||
 | 
			
		||||
colorama.init(autoreset=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def install_chroot():
 | 
			
		||||
    print(f"{colorama.Fore.RED}Sorry, chroot installation file is still WIP, for now, proceed manually.")
 | 
			
		||||
    print(f"{colorama.Fore.LIGHTCYAN_EX}You can use `arch-install-checklist.md` file which containes detailed installation steps.")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    install_chroot()
 | 
			
		||||
| 
						 | 
				
			
			@ -1,111 +0,0 @@
 | 
			
		|||
from datetime import datetime
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
 | 
			
		||||
import colorama
 | 
			
		||||
import inquirer.shortcuts
 | 
			
		||||
 | 
			
		||||
from src.util.command import run_root_cmd
 | 
			
		||||
 | 
			
		||||
colorama.init(autoreset=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _find_all_files(path: Path):
 | 
			
		||||
    for subpath in path.iterdir():
 | 
			
		||||
        if subpath.is_dir():
 | 
			
		||||
            yield from _find_all_files(subpath)
 | 
			
		||||
        else:
 | 
			
		||||
            yield subpath
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _walk_dotfiles():
 | 
			
		||||
    """
 | 
			
		||||
    Walk through every stored file in repositorie's dotfiles,
 | 
			
		||||
    start by going through `home` specific files, and continue
 | 
			
		||||
    with `root` dotfiles.
 | 
			
		||||
    """
 | 
			
		||||
    yield from _find_all_files(Path.cwd().joinpath("home"))
 | 
			
		||||
    yield from _find_all_files(Path.cwd().joinpath("root"))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _dotfile_to_system(dotfile_path: Path) -> Path:
 | 
			
		||||
    """Convert dotfile path to corresponding path on real system"""
 | 
			
		||||
    base_dir = str(Path.cwd())
 | 
			
		||||
 | 
			
		||||
    if base_dir + "/home/" in str(dotfile_path):
 | 
			
		||||
        rel_path = str(dotfile_path).replace(base_dir + "/home/", "")
 | 
			
		||||
        return Path.home().joinpath(rel_path)
 | 
			
		||||
    elif base_dir + "/root/" in str(dotfile_path):
 | 
			
		||||
        rel_path = str(dotfile_path).replace(base_dir + "/root/", "")
 | 
			
		||||
        return Path("/", rel_path)
 | 
			
		||||
    else:
 | 
			
		||||
        raise ValueError(f"Given path is not a valid dotfile path ({dotfile_path})")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def make_backup() -> None:
 | 
			
		||||
    """
 | 
			
		||||
    Find all files which will be replaced and back them up.
 | 
			
		||||
    Files which doesn't exist in the real system destination
 | 
			
		||||
    will be ignored.
 | 
			
		||||
    """
 | 
			
		||||
    print(f"{colorama.Fore.LIGHTYELLOW_EX}Creating current dotfiles backup")
 | 
			
		||||
    time = str(datetime.now()).replace(" ", "--")
 | 
			
		||||
    backup_dir = Path.joinpath(Path.cwd(), "backup", time)
 | 
			
		||||
    backup_dir.mkdir(parents=True, exist_ok=True)
 | 
			
		||||
 | 
			
		||||
    for dotfile_path in _walk_dotfiles():
 | 
			
		||||
        real_path = _dotfile_to_system(dotfile_path)
 | 
			
		||||
        if not real_path.exists():
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        rel_path = str(dotfile_path).replace(str(Path.cwd()) + "/", "")
 | 
			
		||||
        backup_path = backup_dir.joinpath(rel_path)
 | 
			
		||||
 | 
			
		||||
        # Ensure backup directory existence
 | 
			
		||||
        if real_path.is_dir():
 | 
			
		||||
            backup_path.mkdir(parents=True, exist_ok=True)
 | 
			
		||||
        else:
 | 
			
		||||
            backup_path.parent.mkdir(parents=True, exist_ok=True)
 | 
			
		||||
 | 
			
		||||
        print(f"{colorama.Style.DIM}Backing up{real_path}")
 | 
			
		||||
        run_root_cmd(f"cp '{real_path}' '{backup_path}'", enable_debug=False)
 | 
			
		||||
 | 
			
		||||
    print(f"{colorama.Fore.LIGHTYELLOW_EX}Backup complete")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def overwrite_dotfiles() -> None:
 | 
			
		||||
    for dotfile_path in _walk_dotfiles():
 | 
			
		||||
        real_path = _dotfile_to_system(dotfile_path)
 | 
			
		||||
        # Ensure existence of system directory
 | 
			
		||||
        if dotfile_path.is_dir():
 | 
			
		||||
            real_path.mkdir(parents=True, exist_ok=True)
 | 
			
		||||
        else:
 | 
			
		||||
            dotfile_path.parent.mkdir(parents=True, exist_ok=True)
 | 
			
		||||
 | 
			
		||||
        # If we encounter placeholder file, making folder is suffictient
 | 
			
		||||
        # don't proceed with copying it to avoid clutterring the original system
 | 
			
		||||
        # with empty placeholder files, these files are here only for git to
 | 
			
		||||
        # recognize that directory
 | 
			
		||||
        if str(dotfile_path).endswith("placeholder"):
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        print(f"{colorama.Style.DIM}Overwriting {real_path}")
 | 
			
		||||
        run_root_cmd(f"cp '{dotfile_path}' '{real_path}'")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def install_dotfiles() -> None:
 | 
			
		||||
    if inquirer.shortcuts.confirm("Do you want to backup current dotfiles? (Recommended)", default=True):
 | 
			
		||||
        make_backup()
 | 
			
		||||
 | 
			
		||||
    print(f"{colorama.Fore.CYAN}Proceeding with dotfiles installation (this will overwrite your original files)")
 | 
			
		||||
    if inquirer.shortcuts.confirm(
 | 
			
		||||
        "Have you adjusted all dotfiles to your liking? "
 | 
			
		||||
        f"{colorama.Fore.RED}(proceeding without checking the dotfiles first isn't adviced){colorama.Fore.RESET}"
 | 
			
		||||
    ):
 | 
			
		||||
        overwrite_dotfiles()
 | 
			
		||||
        print(f"{colorama.Fore.LIGHTYELLOW_EX}Dotfile installation complete, make sure to adjust the dotfiles to your liking.")
 | 
			
		||||
    else:
 | 
			
		||||
        print(f"{colorama.Fore.RED}Aborted...")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    install_dotfiles()
 | 
			
		||||
| 
						 | 
				
			
			@ -1,45 +0,0 @@
 | 
			
		|||
import typing as t
 | 
			
		||||
 | 
			
		||||
import colorama
 | 
			
		||||
import inquirer.shortcuts
 | 
			
		||||
import yaml
 | 
			
		||||
 | 
			
		||||
from src.util.command import run_root_cmd
 | 
			
		||||
from src.util.package import InvalidPackage, Package, PackageAlreadyInstalled
 | 
			
		||||
 | 
			
		||||
colorama.init(autoreset=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def obtain_packages() -> t.List[Package]:
 | 
			
		||||
    with open("packages.yaml") as f:
 | 
			
		||||
        yaml_file = yaml.safe_load(f)
 | 
			
		||||
 | 
			
		||||
    pacman_packages = yaml_file["pacman"]
 | 
			
		||||
    aur_packages = yaml_file["aur"]
 | 
			
		||||
    git_packages = yaml_file["git"]
 | 
			
		||||
 | 
			
		||||
    packages = []
 | 
			
		||||
    packages += Package.safe_load(pacman_packages)
 | 
			
		||||
    packages += Package.safe_load(git_packages, git=True)
 | 
			
		||||
    packages += Package.safe_load(aur_packages, aur=True)
 | 
			
		||||
 | 
			
		||||
    return packages
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def install_packages() -> None:
 | 
			
		||||
    packages = obtain_packages()
 | 
			
		||||
    if inquirer.shortcuts.confirm("Do you wish to perform system upgrade first? (Recommended)", default=True):
 | 
			
		||||
        run_root_cmd("pacman -Syu")
 | 
			
		||||
 | 
			
		||||
    for package in packages:
 | 
			
		||||
        try:
 | 
			
		||||
            print(f"{colorama.Fore.CYAN}Installing {package}")
 | 
			
		||||
            package.install()
 | 
			
		||||
        except PackageAlreadyInstalled:
 | 
			
		||||
            print(f"{colorama.Style.DIM}Package {package} is already installed, skipping")
 | 
			
		||||
        except InvalidPackage as e:
 | 
			
		||||
            print(f"{colorama.Fore.RED}{str(e)}")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    install_packages()
 | 
			
		||||
| 
						 | 
				
			
			@ -1,47 +0,0 @@
 | 
			
		|||
import os
 | 
			
		||||
import subprocess
 | 
			
		||||
 | 
			
		||||
import colorama
 | 
			
		||||
import inquirer.shortcuts
 | 
			
		||||
 | 
			
		||||
DEBUG = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def debug_confirm_run(cmd):
 | 
			
		||||
    if DEBUG:
 | 
			
		||||
        cnfrm = inquirer.shortcuts.confirm(
 | 
			
		||||
            f"{colorama.Fore.BLUE}[DEBUG] Running command: "
 | 
			
		||||
            f"{colorama.Fore.YELLOW}{cmd}{colorama.Fore.RESET}"
 | 
			
		||||
        )
 | 
			
		||||
        return cnfrm
 | 
			
		||||
    else:
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def run_root_cmd(cmd: str, enable_debug: bool = True) -> subprocess.CompletedProcess:
 | 
			
		||||
    """Run command as root"""
 | 
			
		||||
    if os.geteuid() != 0:
 | 
			
		||||
        return run_cmd(f"sudo {cmd}", enable_debug=enable_debug)
 | 
			
		||||
    else:
 | 
			
		||||
        return run_cmd(cmd, enable_debug=enable_debug)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def run_cmd(cmd: str, capture_out: bool = False, enable_debug: bool = True) -> subprocess.CompletedProcess:
 | 
			
		||||
    """Run given command"""
 | 
			
		||||
    args = {}
 | 
			
		||||
    if capture_out:
 | 
			
		||||
        args.update({"stdout": subprocess.PIPE, "stderr": subprocess.STDOUT})
 | 
			
		||||
 | 
			
		||||
    if not enable_debug or debug_confirm_run(cmd):
 | 
			
		||||
        return subprocess.run(cmd, shell=True, **args)
 | 
			
		||||
    else:
 | 
			
		||||
        # If debug confirm wasn't confirmed, return code 1 (error)
 | 
			
		||||
        return subprocess.CompletedProcess(cmd, returncode=1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def command_exists(cmd) -> bool:
 | 
			
		||||
    """Check if given command can be executed"""
 | 
			
		||||
    parts = cmd.split()
 | 
			
		||||
    executable = parts[0] if parts[0] != "sudo" else parts[1]
 | 
			
		||||
    proc = run_cmd(f"which {executable}", capture_out=True)
 | 
			
		||||
    return proc.returncode != 1
 | 
			
		||||
| 
						 | 
				
			
			@ -1,95 +0,0 @@
 | 
			
		|||
import sys
 | 
			
		||||
import time
 | 
			
		||||
import urllib.request
 | 
			
		||||
from urllib.error import URLError
 | 
			
		||||
 | 
			
		||||
import colorama
 | 
			
		||||
import inquirer.shortcuts
 | 
			
		||||
 | 
			
		||||
from src.util.command import command_exists, run_cmd, run_root_cmd
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _connect_wifi() -> bool:
 | 
			
		||||
    """
 | 
			
		||||
    Attempt to connect to internet using WiFI.
 | 
			
		||||
 | 
			
		||||
    This uses `nmtui` with fallback to `iwctl`, if none
 | 
			
		||||
    of these tools are aviable, either quit or return False,
 | 
			
		||||
    if the tool was executed properly, return True
 | 
			
		||||
 | 
			
		||||
    Note: True doesn't mean we connected, just that the tool was ran,
 | 
			
		||||
    it is up to user to use that tool properly and make the connection.
 | 
			
		||||
    """
 | 
			
		||||
    if command_exists("nmtui"):
 | 
			
		||||
        run_root_cmd("nmtui")
 | 
			
		||||
    elif command_exists("iwctl"):
 | 
			
		||||
        run_root_cmd("iwctl")
 | 
			
		||||
    else:
 | 
			
		||||
        print(
 | 
			
		||||
            f"{colorama.Fore.RED}{colorama.Style.BRIGHT}ERROR: "
 | 
			
		||||
            "WiFi connection tool not found: `nmtui`/`iwctl`, please use Ethernet instead.\n"
 | 
			
		||||
            "Alternatively, connect manually outside of this script and re-run it."
 | 
			
		||||
        )
 | 
			
		||||
        opt = inquirer.shortcuts.list_input(
 | 
			
		||||
            "How do you wish to proceed?",
 | 
			
		||||
            choices=["Quit and connect manually", "Proceed with Ethernet"]
 | 
			
		||||
        )
 | 
			
		||||
        if opt == "Quit and connect manually":
 | 
			
		||||
            sys.exit()
 | 
			
		||||
        else:
 | 
			
		||||
            return False
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _connect_ethernet(max_wait_time: int = 20, iteration_time: int = 1) -> bool:
 | 
			
		||||
    """
 | 
			
		||||
    Attempt to connect to internet using Ethernet.
 | 
			
		||||
 | 
			
		||||
    This will simply wait for the user to plug in the ethernet cable,
 | 
			
		||||
    once that happens loop is interrupted and True is returned. In case
 | 
			
		||||
    it takes over the `max_wait_time`, loop ends and False is returned.
 | 
			
		||||
 | 
			
		||||
    `iteration_time` is the time of each loop iteration, after whcih we
 | 
			
		||||
    check if connection is valid, if not, we continue iterating.
 | 
			
		||||
    """
 | 
			
		||||
    print(f"{colorama.Style.DIM}Please plug in the Ethernet cable, waiting 20s")
 | 
			
		||||
    time_elapsed = 0
 | 
			
		||||
    while not check_connection() and time_elapsed < max_wait_time:
 | 
			
		||||
        time.sleep(iteration_time)
 | 
			
		||||
        time_elapsed += iteration_time
 | 
			
		||||
 | 
			
		||||
    if time_elapsed >= max_wait_time:
 | 
			
		||||
        # We stopped because max wait time was crossed
 | 
			
		||||
        return False
 | 
			
		||||
    else:
 | 
			
		||||
        # We stopped because connection to internet was successful
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def connect_internet():
 | 
			
		||||
    wifi_possible = True
 | 
			
		||||
 | 
			
		||||
    while not check_connection():
 | 
			
		||||
        run_cmd("clear")
 | 
			
		||||
        print(f"{colorama.Fore.RED}Internet connection unaviable")
 | 
			
		||||
        if wifi_possible:
 | 
			
		||||
            connect_opt = inquirer.shortcuts.list_input("How do you wish to connect to internet?", choices=["Wi-Fi", "Ethernet"])
 | 
			
		||||
        else:
 | 
			
		||||
            connect_opt = "Ethernet"
 | 
			
		||||
 | 
			
		||||
        if connect_opt == "Wi-Fi":
 | 
			
		||||
            wifi_possible = _connect_wifi()
 | 
			
		||||
        else:
 | 
			
		||||
            if _connect_ethernet():
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
    print(f"{colorama.Fore.GREEN}Internet connection successful")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def check_connection(host="https://google.com") -> bool:
 | 
			
		||||
    """Check if system is connected to the internet"""
 | 
			
		||||
    try:
 | 
			
		||||
        urllib.request.urlopen(host)
 | 
			
		||||
        return True
 | 
			
		||||
    except URLError:
 | 
			
		||||
        return False
 | 
			
		||||
| 
						 | 
				
			
			@ -1,113 +0,0 @@
 | 
			
		|||
import os
 | 
			
		||||
import typing as t
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
 | 
			
		||||
import colorama
 | 
			
		||||
import inquirer.shortcuts
 | 
			
		||||
 | 
			
		||||
from src.util.command import run_cmd, run_root_cmd
 | 
			
		||||
 | 
			
		||||
colorama.init(autoreset=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class InvalidPackage(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PackageAlreadyInstalled(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def is_installed(pkg: str) -> bool:
 | 
			
		||||
    """Check if the package is already installed in the system"""
 | 
			
		||||
    return run_cmd(f"pacman -Qi {pkg}", capture_out=True).returncode != 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def pacman_install(package: str) -> None:
 | 
			
		||||
    """Install given `package`"""
 | 
			
		||||
    run_root_cmd(f"pacman -S {package}")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def yay_install(package: str) -> None:
 | 
			
		||||
    """Install give package via `yay` (from AUR)"""
 | 
			
		||||
    run_cmd(f"yay -S {package}")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def git_install(url: str) -> None:
 | 
			
		||||
    """Clone a git repository with given `url`"""
 | 
			
		||||
    dir_name = Path(url.split("/")[-1].replace(".git", ""))
 | 
			
		||||
    if dir_name.exists():
 | 
			
		||||
        print(f"{colorama.Style.DIM}Git repository {dir_name} already exists")
 | 
			
		||||
 | 
			
		||||
    ret_code = run_cmd(f"git clone {url}").returncode
 | 
			
		||||
    if ret_code == 128:
 | 
			
		||||
        print(f"{colorama.Fore.RED}Unable to install git repository {url}")
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    if not Path(dir_name, "PKGBUILD").exists:
 | 
			
		||||
        print(f"{colorama.Fore.YELLOW}Git repository {dir_name} doesn't contain PKGBUILD, only downloaded.")
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    if inquirer.shortcuts.confirm("Do you wish to run makepkg on the downloaded git repository?"):
 | 
			
		||||
        cwd = os.getcwd()
 | 
			
		||||
        os.chdir(dir_name)
 | 
			
		||||
        run_cmd("makepkg -si")
 | 
			
		||||
        os.chdir(cwd)
 | 
			
		||||
        run_cmd(f"rm -rf {dir_name}")
 | 
			
		||||
    else:
 | 
			
		||||
        os.makedirs("download")
 | 
			
		||||
        run_cmd(f"mv {dir_name} download/")
 | 
			
		||||
        print(f"{colorama.Style.DIM}Your git repository was cloned into `download/{dir_name}`")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Package:
 | 
			
		||||
    def __init__(self, name: str, aur: bool = False, git: bool = False):
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.aur = aur
 | 
			
		||||
        self.git = git
 | 
			
		||||
 | 
			
		||||
        if self.git:
 | 
			
		||||
            self._resolve_git_package()
 | 
			
		||||
 | 
			
		||||
    def _resolve_git_package(self) -> None:
 | 
			
		||||
        """Figure out `git_url` variable from `name`."""
 | 
			
		||||
        if "/" not in self.name:
 | 
			
		||||
            raise InvalidPackage("You need to specify both author and repository name for git packages (f.e. `ItsDrike/dotfiles`)")
 | 
			
		||||
 | 
			
		||||
        if "http://" in self.name or "https://" in self.name:
 | 
			
		||||
            self.git_url = self.name
 | 
			
		||||
        else:
 | 
			
		||||
            self.git_url = f"https://github.com/{self.name}"
 | 
			
		||||
 | 
			
		||||
    def install(self) -> None:
 | 
			
		||||
        if not self.git and is_installed(self.name):
 | 
			
		||||
            raise PackageAlreadyInstalled(f"Package {self} is already installed")
 | 
			
		||||
 | 
			
		||||
        if self.aur:
 | 
			
		||||
            if not is_installed("yay"):
 | 
			
		||||
                raise InvalidPackage(f"Package {self} can't be installed (missing `yay` - AUR installation software), alternatively, you can use git")
 | 
			
		||||
            yay_install(self.name)
 | 
			
		||||
        elif self.git:
 | 
			
		||||
            git_install(self.git_url)
 | 
			
		||||
        else:
 | 
			
		||||
            pacman_install(self.name)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self) -> str:
 | 
			
		||||
        if self.git:
 | 
			
		||||
            if self.name == self.git_url:
 | 
			
		||||
                return f"<Git package: {self.name}>"
 | 
			
		||||
            return f"<Git package: {self.name} ({self.git_url})>"
 | 
			
		||||
        elif self.aur:
 | 
			
		||||
            return f"<Aur package: {self.name}>"
 | 
			
		||||
        return f"<Package: {self.name}>"
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def safe_load(cls, packages: t.List[str], aur: bool = False, git: bool = False) -> t.List["Package"]:
 | 
			
		||||
        loaded_packages = []
 | 
			
		||||
        for package in packages:
 | 
			
		||||
            try:
 | 
			
		||||
                loaded_packages.append(cls(package, aur=aur, git=git))
 | 
			
		||||
            except InvalidPackage as e:
 | 
			
		||||
                print(f"{colorama.Fore.RED}{str(e)}")
 | 
			
		||||
 | 
			
		||||
        return loaded_packages
 | 
			
		||||
							
								
								
									
										19
									
								
								tox.ini
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								tox.ini
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,19 +0,0 @@
 | 
			
		|||
[flake8]
 | 
			
		||||
max_line_length=150
 | 
			
		||||
import-order-style=pycharm
 | 
			
		||||
application_import_names=src
 | 
			
		||||
exclude=
 | 
			
		||||
    .venv/**,
 | 
			
		||||
    .git/**
 | 
			
		||||
ignore=
 | 
			
		||||
    # Ignore missing return type annotations for special methods
 | 
			
		||||
    ANN204
 | 
			
		||||
    # Ignore missing type annotations
 | 
			
		||||
    ANN101 # Init
 | 
			
		||||
    ANN102 # cls
 | 
			
		||||
    ANN002, # *Args
 | 
			
		||||
    ANN003, # **Kwargs
 | 
			
		||||
    # Allow lambdas
 | 
			
		||||
    E731
 | 
			
		||||
    # Allow markdown inline HTML
 | 
			
		||||
    MD033
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue