sysetup 1.0.26__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. {sysetup-1.0.26 → sysetup-1.2.0}/LICENSE +1 -1
  2. sysetup-1.2.0/PKG-INFO +54 -0
  3. sysetup-1.2.0/README.md +33 -0
  4. sysetup-1.2.0/pyproject.toml +75 -0
  5. sysetup-1.2.0/src/sysetup/__init__.py +0 -0
  6. sysetup-1.2.0/src/sysetup/cli/__init__.py +1 -0
  7. sysetup-1.2.0/src/sysetup/cli/entry_point.py +6 -0
  8. sysetup-1.2.0/src/sysetup/context/__init__.py +1 -0
  9. sysetup-1.2.0/src/sysetup/context/context.py +31 -0
  10. sysetup-1.2.0/src/sysetup/main/__init__.py +0 -0
  11. sysetup-1.2.0/src/sysetup/main/environment.py +14 -0
  12. sysetup-1.2.0/src/sysetup/main/files/__init__.py +1 -0
  13. sysetup-1.2.0/src/sysetup/main/files/assets.py +40 -0
  14. sysetup-1.2.0/src/sysetup/main/files/permissions.py +33 -0
  15. sysetup-1.2.0/src/sysetup/main/files/settings.py +45 -0
  16. sysetup-1.2.0/src/sysetup/main/files/setup.py +8 -0
  17. sysetup-1.2.0/src/sysetup/main/installations.py +67 -0
  18. sysetup-1.2.0/src/sysetup/main/main.py +30 -0
  19. sysetup-1.2.0/src/sysetup/main/packages.py +60 -0
  20. sysetup-1.2.0/src/sysetup/models/__init__.py +3 -0
  21. sysetup-1.2.0/src/sysetup/models/action.py +9 -0
  22. sysetup-1.2.0/src/sysetup/models/options.py +11 -0
  23. {sysetup-1.0.26/sysetup → sysetup-1.2.0/src/sysetup/models}/path.py +9 -10
  24. sysetup-1.2.0/src/sysetup/py.typed +0 -0
  25. sysetup-1.2.0/src/sysetup/utils/__init__.py +1 -0
  26. sysetup-1.2.0/src/sysetup/utils/download.py +12 -0
  27. sysetup-1.2.0/src/sysetup.egg-info/PKG-INFO +54 -0
  28. sysetup-1.2.0/src/sysetup.egg-info/SOURCES.txt +37 -0
  29. sysetup-1.2.0/src/sysetup.egg-info/entry_points.txt +3 -0
  30. sysetup-1.2.0/src/sysetup.egg-info/requires.txt +11 -0
  31. sysetup-1.2.0/tests/test_background.py +65 -0
  32. sysetup-1.2.0/tests/test_cli_entry_point.py +11 -0
  33. sysetup-1.2.0/tests/test_installer.py +14 -0
  34. sysetup-1.2.0/tests/test_main.py +11 -0
  35. sysetup-1.0.26/PKG-INFO +0 -45
  36. sysetup-1.0.26/README.md +0 -24
  37. sysetup-1.0.26/pyproject.toml +0 -58
  38. sysetup-1.0.26/sysetup/__init__.py +0 -1
  39. sysetup-1.0.26/sysetup/env.py +0 -17
  40. sysetup-1.0.26/sysetup/files.py +0 -98
  41. sysetup-1.0.26/sysetup/installer.py +0 -177
  42. sysetup-1.0.26/sysetup/main.py +0 -36
  43. sysetup-1.0.26/sysetup.egg-info/PKG-INFO +0 -45
  44. sysetup-1.0.26/sysetup.egg-info/SOURCES.txt +0 -19
  45. sysetup-1.0.26/sysetup.egg-info/entry_points.txt +0 -3
  46. sysetup-1.0.26/sysetup.egg-info/requires.txt +0 -13
  47. sysetup-1.0.26/tests/test_background.py +0 -38
  48. sysetup-1.0.26/tests/test_installer.py +0 -17
  49. {sysetup-1.0.26 → sysetup-1.2.0}/bin/pw +0 -0
  50. /sysetup-1.0.26/bin/pw_askpass → /sysetup-1.2.0/bin/pw-askpass +0 -0
  51. {sysetup-1.0.26 → sysetup-1.2.0}/setup.cfg +0 -0
  52. {sysetup-1.0.26 → sysetup-1.2.0/src}/sysetup.egg-info/dependency_links.txt +0 -0
  53. {sysetup-1.0.26 → sysetup-1.2.0/src}/sysetup.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 quintenroets
3
+ Copyright (c) 2023 Quinten Roets
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
sysetup-1.2.0/PKG-INFO ADDED
@@ -0,0 +1,54 @@
1
+ Metadata-Version: 2.1
2
+ Name: sysetup
3
+ Version: 1.2.0
4
+ Summary: Personal system setup
5
+ Author-email: Quinten Roets <qdr2104@columbia.edu>
6
+ License: MIT
7
+ Project-URL: Source Code, https://github.com/quintenroets/sysetup
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: backupmaster<2,>=1.2.6
12
+ Requires-Dist: dbus-next<1,>=0.2.3
13
+ Requires-Dist: package-utils[context]<1,>=0.6.1
14
+ Requires-Dist: powercli<1,>=0.3.1
15
+ Requires-Dist: python-dotenv<2,>=1.0.1
16
+ Requires-Dist: requests<3,>=2.32.3
17
+ Requires-Dist: superpathlib<3,>=2.0.4
18
+ Provides-Extra: dev
19
+ Requires-Dist: package-dev-tools<1,>=0.5.11; extra == "dev"
20
+ Requires-Dist: package-dev-utils<1,>=0.1.6; extra == "dev"
21
+
22
+ # Sysetup
23
+ [![PyPI version](https://badge.fury.io/py/sysetup.svg)](https://badge.fury.io/py/sysetup)
24
+ ![Python version](https://img.shields.io/badge/python-3.10+-brightgreen)
25
+ ![Operating system](https://img.shields.io/badge/os-linux-brightgreen)
26
+ ![Coverage](https://img.shields.io/badge/coverage-66%25-brightgreen)
27
+ ## [Plasma](https://kde.org/plasma-desktop/) 5.22 required
28
+
29
+ [Setup info](docs/setup-plasma.md)
30
+
31
+ ## Setup steps
32
+ 1) Run
33
+ ```shell
34
+ wget -O - https://raw.githubusercontent.com/quintenroets/sysetup/main/bin/setup | bash
35
+ ```
36
+ give rclone password when prompted
37
+ 2) Appearance
38
+ * Set wallpaper
39
+ * Select We10OSX Cursors
40
+ 3) Configure autocpufreq
41
+ 4) Setup Chrome
42
+ * Enable GPU acceleration in chrome://flags
43
+ * PDF viewer: set page zoom to page fit
44
+ * Import certificate from Scripts/assets/sysetup/certificates/certificate.crt
45
+ * Click experimental: enable tab groups save and sync
46
+ 5) Login to
47
+ * Pycharm professional
48
+ * VNC Server
49
+ 6) For new device: set touchpad scroll direction and click on touch
50
+
51
+ ## Installation
52
+ ```shell
53
+ pip install sysetup
54
+ ```
@@ -0,0 +1,33 @@
1
+ # Sysetup
2
+ [![PyPI version](https://badge.fury.io/py/sysetup.svg)](https://badge.fury.io/py/sysetup)
3
+ ![Python version](https://img.shields.io/badge/python-3.10+-brightgreen)
4
+ ![Operating system](https://img.shields.io/badge/os-linux-brightgreen)
5
+ ![Coverage](https://img.shields.io/badge/coverage-66%25-brightgreen)
6
+ ## [Plasma](https://kde.org/plasma-desktop/) 5.22 required
7
+
8
+ [Setup info](docs/setup-plasma.md)
9
+
10
+ ## Setup steps
11
+ 1) Run
12
+ ```shell
13
+ wget -O - https://raw.githubusercontent.com/quintenroets/sysetup/main/bin/setup | bash
14
+ ```
15
+ give rclone password when prompted
16
+ 2) Appearance
17
+ * Set wallpaper
18
+ * Select We10OSX Cursors
19
+ 3) Configure autocpufreq
20
+ 4) Setup Chrome
21
+ * Enable GPU acceleration in chrome://flags
22
+ * PDF viewer: set page zoom to page fit
23
+ * Import certificate from Scripts/assets/sysetup/certificates/certificate.crt
24
+ * Click experimental: enable tab groups save and sync
25
+ 5) Login to
26
+ * Pycharm professional
27
+ * VNC Server
28
+ 6) For new device: set touchpad scroll direction and click on touch
29
+
30
+ ## Installation
31
+ ```shell
32
+ pip install sysetup
33
+ ```
@@ -0,0 +1,75 @@
1
+ [project]
2
+ name = "sysetup"
3
+ version = "1.2.0"
4
+ description = "Personal system setup"
5
+ authors = [{name = "Quinten Roets", email = "qdr2104@columbia.edu"}]
6
+ license = {text = "MIT"}
7
+ readme = "README.md"
8
+ requires-python = ">=3.10"
9
+ dependencies = [
10
+ "backupmaster >=1.2.6, <2",
11
+ "dbus-next >=0.2.3, <1",
12
+ "package-utils[context] >=0.6.1, <1",
13
+ "powercli >=0.3.1, <1",
14
+ "python-dotenv >=1.0.1, <2",
15
+ "requests >=2.32.3, <3",
16
+ "superpathlib >=2.0.4, <3",
17
+ ]
18
+
19
+ [project.optional-dependencies]
20
+ dev = [
21
+ "package-dev-tools >=0.5.11, <1",
22
+ "package-dev-utils >=0.1.6, <1",
23
+ ]
24
+
25
+ [project.urls]
26
+ "Source Code" = "https://github.com/quintenroets/sysetup"
27
+
28
+ [project.scripts]
29
+ sysetup = "sysetup.cli:entry_point"
30
+ exportcrontab = "sysetup.main.files.assets:move_crontab"
31
+
32
+ [build-system]
33
+ requires = ["setuptools"]
34
+ build-backend = "setuptools.build_meta"
35
+
36
+ [tool.coverage.run]
37
+ command_line = "-m pytest tests"
38
+
39
+ [tool.coverage.report]
40
+ precision = 4
41
+ fail_under = 60
42
+
43
+ [tool.mypy]
44
+ strict = true
45
+ no_implicit_reexport = false
46
+
47
+ [tool.pytest.ini_options]
48
+ pythonpath = [
49
+ "src", ".",
50
+ ]
51
+
52
+ [tool.ruff]
53
+ fix = true
54
+
55
+ [tool.ruff.lint]
56
+ select = ["ALL"]
57
+ ignore = [
58
+ "ANN101", # annotate self
59
+ "ANN102", # annotate cls
60
+ "ANN401", # annotated with Any
61
+ "D", # docstrings
62
+ "S101", # assert used
63
+ ]
64
+
65
+ [tool.ruff.lint.isort]
66
+ known-first-party = ["src"]
67
+
68
+ [tool.ruff.lint.per-file-ignores]
69
+ "__init__.py" = ["F401"]
70
+
71
+ [tool.setuptools]
72
+ script-files = ["bin/pw", "bin/pw-askpass"]
73
+
74
+ [tool.setuptools.package-data]
75
+ sysetup = ["assets/scripts/update_wallpaper.js", "py.typed"]
File without changes
@@ -0,0 +1 @@
1
+ from .entry_point import entry_point
@@ -0,0 +1,6 @@
1
+ from package_utils.context.entry_point import create_entry_point
2
+
3
+ from sysetup.context import context
4
+ from sysetup.main.main import main
5
+
6
+ entry_point = create_entry_point(main, context)
@@ -0,0 +1 @@
1
+ from .context import Context, context
@@ -0,0 +1,31 @@
1
+ import os
2
+ from collections.abc import Iterator
3
+ from functools import cached_property
4
+
5
+ import cli
6
+ from package_utils.context import Context as Context_
7
+
8
+ from sysetup.models import Options
9
+
10
+
11
+ class Context(Context_[Options, None, None]):
12
+ @cached_property
13
+ def package_manager(self) -> str:
14
+ def generate_package_manager() -> Iterator[str]:
15
+ package_managers = "apt-get", "pacman"
16
+ for package_manager in package_managers:
17
+ if cli.completes_successfully("which", package_manager):
18
+ yield package_manager
19
+
20
+ return next(generate_package_manager())
21
+
22
+ @cached_property
23
+ def apt_is_installed(self) -> bool:
24
+ return self.package_manager == "apt-get"
25
+
26
+ @cached_property
27
+ def is_running_in_test(self) -> bool:
28
+ return "DISPLAY" not in os.environ
29
+
30
+
31
+ context = Context(Options)
File without changes
@@ -0,0 +1,14 @@
1
+ import os
2
+
3
+ from dotenv import load_dotenv
4
+
5
+ from sysetup.models import Path
6
+ from sysetup.utils import download_file
7
+
8
+
9
+ def setup() -> None:
10
+ download_file(Path("etc") / "environment")
11
+ if "SUDO_ASKPASS" not in os.environ:
12
+ path = Path.HOME / ".bask_profile"
13
+ download_file(Path.HOME / ".bask_profile")
14
+ load_dotenv(dotenv_path=Path.HOME / path)
@@ -0,0 +1 @@
1
+ from .setup import setup
@@ -0,0 +1,40 @@
1
+ import cli
2
+ from backup.backups.cache import cache
3
+
4
+ from sysetup.models import Path
5
+ from sysetup.utils import download_directory
6
+
7
+
8
+ def setup() -> None:
9
+ download_directory(Path.assets)
10
+ move_crontab()
11
+ move_setup_files()
12
+
13
+
14
+ def move_crontab() -> None:
15
+ src = Path.assets / "crontab" / "crontab"
16
+ cli.run("crontab -", input=src.text)
17
+
18
+
19
+ def move_setup_files() -> None:
20
+ setup_files_root = Path.assets / "files"
21
+ setup_files = []
22
+ archived_setup_files = []
23
+ for path in setup_files_root.rglob("*"):
24
+ if path.is_file():
25
+ if path.archive_format is None:
26
+ setup_files.append(path)
27
+ else:
28
+ archived_setup_files.append(path)
29
+
30
+ backup = cache.Backup(paths=setup_files)
31
+ backup.pull()
32
+
33
+ for path in archived_setup_files:
34
+ dest = (backup.source / path.relative_to(setup_files_root)).parent
35
+ if dest.is_root and not dest.exists():
36
+ cli.run("mkdir -p", dest, root=True)
37
+ else:
38
+ dest.create_parent()
39
+ with cli.status(f"Unpacking {path.relative_to(setup_files_root)}"):
40
+ cli.capture_output("unzip -o", path, "-d", dest, root=dest.is_root)
@@ -0,0 +1,33 @@
1
+ import stat
2
+
3
+ import cli
4
+
5
+ from sysetup.models import Path
6
+ from sysetup.utils import download_directory
7
+
8
+
9
+ def setup() -> None:
10
+ set_git_permissions()
11
+ set_ssh_permissions()
12
+
13
+
14
+ def set_git_permissions() -> None:
15
+ git_hooks_folder = Path.HOME / ".config" / "git" / "hooks"
16
+ download_directory(git_hooks_folder)
17
+ for path in git_hooks_folder.iterdir():
18
+ cli.run("chmod +x", path)
19
+
20
+
21
+ def set_ssh_permissions() -> None:
22
+ directory = Path.HOME / ".ssh"
23
+ download_directory(directory)
24
+ for path in directory.glob("id_*"):
25
+ if path.suffix != ".pub":
26
+ check_permissions(path)
27
+
28
+
29
+ def check_permissions(path: Path) -> None:
30
+ permissions = path.stat().st_mode
31
+ other_users_can_read = permissions & (stat.S_IRGRP | stat.S_IROTH)
32
+ if other_users_can_read:
33
+ path.chmod(33152)
@@ -0,0 +1,45 @@
1
+ import cli
2
+
3
+ from sysetup.context import context
4
+ from sysetup.models import Path
5
+ from sysetup.utils import download_directory
6
+
7
+
8
+ def remove_clutter() -> None:
9
+ names = (
10
+ "Desktop",
11
+ "Downloads",
12
+ "Music",
13
+ "Pictures",
14
+ "Public",
15
+ "Templates",
16
+ "Videos",
17
+ )
18
+ for name in names:
19
+ path = Path.HOME / name
20
+ path.rmtree(missing_ok=True)
21
+
22
+ nginx_path = Path("/") / "etc" / "nginx" / "sites-enabled" / "default"
23
+ if nginx_path.exists():
24
+ cli.run("rm", nginx_path, root=True)
25
+
26
+
27
+ def set_background() -> None: # pragma: nocover
28
+ wallpaper_path = (
29
+ Path.HOME / ".local" / "share" / "wallpapers" / "Qwallpapers" / "background.jpg"
30
+ )
31
+ download_directory(wallpaper_path.parent)
32
+ wallpaper_uri = wallpaper_path.as_uri()
33
+ script = Path.update_wallpaper_script.text.replace(
34
+ "__wallpaper_uri__",
35
+ wallpaper_uri,
36
+ )
37
+ run_kde_script(script)
38
+
39
+
40
+ def run_kde_script(script: str) -> None: # pragma: nocover
41
+ command = (
42
+ "qdbus org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript"
43
+ )
44
+ if not context.is_running_in_test:
45
+ cli.run(command, script)
@@ -0,0 +1,8 @@
1
+ from sysetup.main.files import assets, permissions, settings
2
+
3
+
4
+ def setup() -> None:
5
+ permissions.setup()
6
+ assets.setup()
7
+ settings.set_background()
8
+ settings.remove_clutter()
@@ -0,0 +1,67 @@
1
+ import os
2
+
3
+ import cli
4
+
5
+ from sysetup.context import context
6
+ from sysetup.models import Path
7
+
8
+
9
+ def setup() -> None:
10
+ install_chromium()
11
+ install_jumpapp()
12
+ install_language_support()
13
+ install_linter_env()
14
+ install_personal_git_repositories()
15
+
16
+
17
+ def install_personal_git_repositories() -> None:
18
+ base_url = "https://github.com/quintenroets"
19
+ token = os.getenv("GITHUB", None)
20
+ if token is not None:
21
+ base_url = base_url.replace("github.com", f"{token}@github.com")
22
+ if not Path.extensions.exists():
23
+ command = f"git clone {base_url}/extensions.git"
24
+ cli.run(command, Path.extensions)
25
+ cli.run(f"pip install git+{base_url}/system.git")
26
+
27
+
28
+ def install_language_support() -> None:
29
+ try:
30
+ packages = cli.capture_output("check-language-support")
31
+ except FileNotFoundError:
32
+ pass
33
+ else:
34
+ if packages:
35
+ cli.install(packages)
36
+
37
+
38
+ def install_chromium() -> None:
39
+ if not cli.capture_output("which chromium-browser", check=False):
40
+ _install_chromium()
41
+
42
+
43
+ def _install_chromium() -> None:
44
+ release_name = cli.capture_output_lines("lsb_release -sc")[-1]
45
+ repo_url = f"https://freeshell.de/phd/chromium/{release_name}"
46
+ commands = (
47
+ f'echo "deb {repo_url} /" | sudo tee /etc/apt/sources.list.d/phd-chromium.list',
48
+ "apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 869689FE09306074",
49
+ "apt-get update",
50
+ "apt-get install -y chromium",
51
+ )
52
+ check = not context.is_running_in_test
53
+ cli.run_commands(*commands, shell=True, root=True, check=check) # noqa: S604
54
+
55
+
56
+ def install_linter_env() -> None:
57
+ if not Path.linter_env.exists():
58
+ cli.run("python -m venv", Path.linter_env.name, cwd=Path.linter_env.parent)
59
+ python_path = Path.linter_env / "bin" / "python"
60
+ cli.run(f"{python_path} -m pip install autoimport powertrace-hooks")
61
+
62
+
63
+ def install_jumpapp() -> None:
64
+ if not cli.capture_output("which jumpapp", check=False):
65
+ with Path.tempdir() as directory:
66
+ cli.run("git clone https://github.com/mkropat/jumpapp", directory)
67
+ cli.run_commands("make", "sudo make install", cwd=directory)
@@ -0,0 +1,30 @@
1
+ import cli
2
+
3
+ from sysetup.context import context
4
+ from sysetup.models import Action
5
+
6
+ from . import environment, files, installations, packages
7
+
8
+
9
+ def main() -> None:
10
+ """
11
+ Personal system setup.
12
+ """
13
+ action_mapper = {
14
+ Action.all.value: setup,
15
+ Action.env.value: environment.setup,
16
+ Action.files.value: files.setup,
17
+ Action.install.value: installations.setup,
18
+ Action.packages.value: packages.setup,
19
+ }
20
+ action = action_mapper[context.options.action.value]
21
+ action()
22
+
23
+
24
+ def setup() -> None:
25
+ environment.setup()
26
+ packages.setup()
27
+ files.setup()
28
+ installations.setup()
29
+ if not context.is_running_in_test:
30
+ cli.run("reboot now", root=True)
@@ -0,0 +1,60 @@
1
+ import cli
2
+
3
+ from sysetup.context import context
4
+ from sysetup.models import Path
5
+ from sysetup.utils import download_directory
6
+
7
+
8
+ def setup() -> None:
9
+ update_package_manager()
10
+ install_packages()
11
+ cleanup_after_install()
12
+
13
+
14
+ def install_packages() -> None:
15
+ download_directory(Path.packages)
16
+ installations = {"packages": None, "snap": "snap install"}
17
+ for name, command in installations.items():
18
+ path = (Path.packages / name).with_suffix(".yaml")
19
+ packages: list[str] = path.yaml
20
+ cli.install(*packages, install_command=command)
21
+
22
+
23
+ def update_package_manager() -> None:
24
+ if context.apt_is_installed:
25
+ update_apt()
26
+ else:
27
+ cli.run("pacman -Syy", root=True)
28
+
29
+
30
+ def update_apt() -> None:
31
+ agree_eula_command = (
32
+ "echo ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula"
33
+ "select true | sudo debconf-set-selections"
34
+ )
35
+ commands = ["sudo apt-get update", agree_eula_command]
36
+ if not context.is_running_in_test:
37
+ # snap currently doesn't work on arm
38
+ commands.append("sudo systemctl enable --now snapd.socket")
39
+ cli.run_commands_in_shell(*commands)
40
+ if not Path("/snap").exists():
41
+ cli.run("ln -s /var/lib/snapd/snap /snap", root=True)
42
+
43
+
44
+ def cleanup_after_install() -> None:
45
+ after_install_command = (
46
+ "sudo apt-get autoremove -y"
47
+ if context.apt_is_installed
48
+ else (
49
+ "sudo pacman -S --noconfirm python-pip; sudo pacman -S --noconfirm"
50
+ " base-devel; pip install wheel"
51
+ )
52
+ )
53
+ cli.run_commands_in_shell(after_install_command, "sudo tlp start")
54
+ cli.run("systemctl enable ssh", root=True) # start ssh server before log in
55
+ delete = "apt purge -y" if context.apt_is_installed else "pacman -R --noconfirm"
56
+ commands = (
57
+ "auto-cpufreq --install", # Fails on VM
58
+ f"{delete} firefox", # fails if firefox not installed
59
+ )
60
+ cli.run_commands(*commands, check=False, root=True)
@@ -0,0 +1,3 @@
1
+ from .action import Action
2
+ from .options import Options
3
+ from .path import Path
@@ -0,0 +1,9 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Action(str, Enum):
5
+ all = "all"
6
+ files = "files"
7
+ packages = "packages"
8
+ install = "install"
9
+ env = "env"
@@ -0,0 +1,11 @@
1
+ from dataclasses import dataclass
2
+ from typing import Annotated
3
+
4
+ import typer
5
+
6
+ from .action import Action
7
+
8
+
9
+ @dataclass
10
+ class Options:
11
+ action: Annotated[Action, typer.Argument(help="The part to setup")] = Action.all
@@ -1,5 +1,4 @@
1
- import typing
2
- from typing import TypeVar
1
+ from typing import TypeVar, cast
3
2
 
4
3
  import superpathlib
5
4
  from simple_classproperty import classproperty
@@ -11,40 +10,40 @@ class Path(superpathlib.Path):
11
10
  @classmethod
12
11
  @classproperty
13
12
  def source_root(cls: type[T]) -> T:
14
- return cls(__file__).parent
13
+ return cls(__file__).parent.parent
15
14
 
16
15
  @classmethod
17
16
  @classproperty
18
17
  def assets(cls: type[T]) -> T:
19
18
  path = cls.script_assets / cls.source_root.name
20
- return typing.cast(T, path)
19
+ return cast(T, path)
21
20
 
22
21
  @classmethod
23
22
  @classproperty
24
23
  def config(cls: type[T]) -> T:
25
24
  path = cls.assets / "config" / "config.yaml"
26
- return typing.cast(T, path)
25
+ return cast(T, path)
27
26
 
28
27
  @classmethod
29
28
  @classproperty
30
29
  def packages(cls: type[T]) -> T:
31
30
  path = cls.assets / "packages"
32
- return typing.cast(T, path)
31
+ return cast(T, path)
33
32
 
34
33
  @classmethod
35
34
  @classproperty
36
35
  def linter_env(cls: type[T]) -> T:
37
- path = cls.assets / "linterenv"
38
- return typing.cast(T, path)
36
+ path = Path.HOME / ".local" / "share" / "envs" / "linterenv"
37
+ return cast(T, path)
39
38
 
40
39
  @classmethod
41
40
  @classproperty
42
41
  def extensions(cls: type[T]) -> T:
43
42
  path = cls.HOME / ".local" / "share" / "extensions"
44
- return typing.cast(T, path)
43
+ return cast(T, path)
45
44
 
46
45
  @classmethod
47
46
  @classproperty
48
47
  def update_wallpaper_script(cls: type[T]) -> T:
49
48
  path = cls.source_root / "assets" / "scripts" / "update_wallpaper.js"
50
- return typing.cast(T, path)
49
+ return cast(T, path)
File without changes
@@ -0,0 +1 @@
1
+ from .download import download_directory, download_file
@@ -0,0 +1,12 @@
1
+ from backup.backups import Backup
2
+ from backup.models import Path as BackupPath
3
+
4
+ from sysetup.models import Path
5
+
6
+
7
+ def download_directory(path: Path) -> None:
8
+ Backup(sub_check_path=BackupPath(path), confirm=False).pull()
9
+
10
+
11
+ def download_file(path: Path) -> None:
12
+ Backup(path=BackupPath(path), confirm=False).pull()