Compare commits
6 Commits
Author | SHA1 | Date |
---|---|---|
Riley Housden | 44555fc84e | |
Riley Housden | 067ab48de0 | |
Riley Housden | eedecb34d5 | |
Riley Housden | cc6bbe937f | |
Riley Housden | 67fd1b3cf4 | |
Riley Housden | 0f5bbd78ad |
|
@ -1,5 +1,3 @@
|
||||||
import:
|
|
||||||
- /home/riley/.config/alacritty/dracula.yml
|
|
||||||
# Configuration for Alacritty, the GPU enhanced terminal emulator.
|
# Configuration for Alacritty, the GPU enhanced terminal emulator.
|
||||||
|
|
||||||
# Import additional configuration files
|
# Import additional configuration files
|
||||||
|
@ -16,16 +14,11 @@ import:
|
||||||
# Any items in the `env` entry below will be added as
|
# Any items in the `env` entry below will be added as
|
||||||
# environment variables. Some entries may override variables
|
# environment variables. Some entries may override variables
|
||||||
# set by alacritty itself.
|
# set by alacritty itself.
|
||||||
#env:
|
env:
|
||||||
# TERM variable
|
WINIT_X11_SCALE_FACTOR: '1.0'
|
||||||
#
|
|
||||||
# This value is used to set the `$TERM` environment variable for
|
|
||||||
# each instance of Alacritty. If it is not present, alacritty will
|
|
||||||
# check the local terminfo database and use `alacritty` if it is
|
|
||||||
# available, otherwise `xterm-256color` is used.
|
|
||||||
#TERM: alacritty
|
|
||||||
|
|
||||||
window:
|
window:
|
||||||
|
opacity: 0.95
|
||||||
# Window dimensions (changes require restart)
|
# Window dimensions (changes require restart)
|
||||||
#
|
#
|
||||||
# Number of lines/columns (not pixels) in the terminal. The number of columns
|
# Number of lines/columns (not pixels) in the terminal. The number of columns
|
||||||
|
@ -178,142 +171,120 @@ window:
|
||||||
#draw_bold_text_with_bright_colors: false
|
#draw_bold_text_with_bright_colors: false
|
||||||
|
|
||||||
# Colors (Tomorrow Night)
|
# Colors (Tomorrow Night)
|
||||||
#colors:
|
schemes:
|
||||||
# Default colors
|
dracula: &dracula
|
||||||
#primary:
|
colors:
|
||||||
# background: '#1d1f21'
|
primary:
|
||||||
# foreground: '#c5c8c6'
|
background: '0x282a36'
|
||||||
|
foreground: '0xf8f8f2'
|
||||||
|
cursor:
|
||||||
|
text: CellBackground
|
||||||
|
cursor: CellForeground
|
||||||
|
vi_mode_cursor:
|
||||||
|
text: CellBackground
|
||||||
|
cursor: CellForeground
|
||||||
|
search:
|
||||||
|
matches:
|
||||||
|
foreground: '0x44475a'
|
||||||
|
background: '0x50fa7b'
|
||||||
|
focused_match:
|
||||||
|
foreground: '0x44475a'
|
||||||
|
background: '0xffb86c'
|
||||||
|
bar:
|
||||||
|
background: '0x282a36'
|
||||||
|
foreground: '0xf8f8f2'
|
||||||
|
line_indicator:
|
||||||
|
foreground: None
|
||||||
|
background: None
|
||||||
|
selection:
|
||||||
|
text: CellForeground
|
||||||
|
background: '0x44475a'
|
||||||
|
normal:
|
||||||
|
black: '0x000000'
|
||||||
|
red: '0xff5555'
|
||||||
|
green: '0x50fa7b'
|
||||||
|
yellow: '0xf1fa8c'
|
||||||
|
blue: '0xbd93f9'
|
||||||
|
magenta: '0xff79c6'
|
||||||
|
cyan: '0x8be9fd'
|
||||||
|
white: '0xbfbfbf'
|
||||||
|
bright:
|
||||||
|
black: '0x4d4d4d'
|
||||||
|
red: '0xff6e67'
|
||||||
|
green: '0x5af78e'
|
||||||
|
yellow: '0xf4f99d'
|
||||||
|
blue: '0xcaa9fa'
|
||||||
|
magenta: '0xff92d0'
|
||||||
|
cyan: '0x9aedfe'
|
||||||
|
white: '0xe6e6e6'
|
||||||
|
dim:
|
||||||
|
black: '0x14151b'
|
||||||
|
red: '0xff2222'
|
||||||
|
green: '0x1ef956'
|
||||||
|
yellow: '0xebf85b'
|
||||||
|
blue: '0x4d5b86'
|
||||||
|
magenta: '0xff46b0'
|
||||||
|
cyan: '0x59dffc'
|
||||||
|
white: '0xe6e6d1'
|
||||||
|
# Tokyo Night theme, based on both:
|
||||||
|
# https://github.com/ghifarit53/tokyonight-vim
|
||||||
|
# https://github.com/enkia/tokyo-night-vscode-theme
|
||||||
|
tokyo-night: &tokyo-night
|
||||||
|
# Default colors
|
||||||
|
primary:
|
||||||
|
background: '0x1a1b26'
|
||||||
|
foreground: '0xa9b1d6'
|
||||||
|
|
||||||
# Bright and dim foreground colors
|
# Normal colors
|
||||||
#
|
normal:
|
||||||
# The dimmed foreground color is calculated automatically if it is not
|
black: '0x32344a'
|
||||||
# present. If the bright foreground color is not set, or
|
red: '0xf7768e'
|
||||||
# `draw_bold_text_with_bright_colors` is `false`, the normal foreground
|
green: '0x9ece6a'
|
||||||
# color will be used.
|
yellow: '0xe0af68'
|
||||||
#dim_foreground: '#828482'
|
blue: '0x7aa2f7'
|
||||||
#bright_foreground: '#eaeaea'
|
magenta: '0xad8ee6'
|
||||||
|
cyan: '0x449dab'
|
||||||
|
white: '0x787c99'
|
||||||
|
|
||||||
# Cursor colors
|
# Bright colors
|
||||||
#
|
bright:
|
||||||
# Colors which should be used to draw the terminal cursor.
|
black: '0x444b6a'
|
||||||
#
|
red: '0xff7a93'
|
||||||
# Allowed values are CellForeground/CellBackground, which reference the
|
green: '0xb9f27c'
|
||||||
# affected cell, or hexadecimal colors like #ff00ff.
|
yellow: '0xff9e64'
|
||||||
#cursor:
|
blue: '0x7da6ff'
|
||||||
# text: CellBackground
|
magenta: '0xbb9af7'
|
||||||
# cursor: CellForeground
|
cyan: '0x0db9d7'
|
||||||
|
white: '0xacb0d0'
|
||||||
|
|
||||||
# Vi mode cursor colors
|
tokyo-night-storm: &tokyo-night-storm
|
||||||
#
|
# Default colors
|
||||||
# Colors for the cursor when the vi mode is active.
|
primary:
|
||||||
#
|
background: '0x24283b'
|
||||||
# Allowed values are CellForeground/CellBackground, which reference the
|
foreground: '0xa9b1d6'
|
||||||
# affected cell, or hexadecimal colors like #ff00ff.
|
|
||||||
#vi_mode_cursor:
|
|
||||||
# text: CellBackground
|
|
||||||
# cursor: CellForeground
|
|
||||||
|
|
||||||
# Search colors
|
# Normal colors
|
||||||
#
|
normal:
|
||||||
# Colors used for the search bar and match highlighting.
|
black: '0x32344a'
|
||||||
#search:
|
red: '0xf7768e'
|
||||||
# Allowed values are CellForeground/CellBackground, which reference the
|
green: '0x9ece6a'
|
||||||
# affected cell, or hexadecimal colors like #ff00ff.
|
yellow: '0xe0af68'
|
||||||
#matches:
|
blue: '0x7aa2f7'
|
||||||
# foreground: '#000000'
|
magenta: '0xad8ee6'
|
||||||
# background: '#ffffff'
|
cyan: '0x449dab'
|
||||||
#focused_match:
|
white: '0x9699a8'
|
||||||
# foreground: '#ffffff'
|
|
||||||
# background: '#000000'
|
|
||||||
|
|
||||||
#bar:
|
|
||||||
# background: '#c5c8c6'
|
|
||||||
# foreground: '#1d1f21'
|
|
||||||
|
|
||||||
# Keyboard regex hints
|
|
||||||
#hints:
|
|
||||||
# First character in the hint label
|
|
||||||
#
|
|
||||||
# Allowed values are CellForeground/CellBackground, which reference the
|
|
||||||
# affected cell, or hexadecimal colors like #ff00ff.
|
|
||||||
#start:
|
|
||||||
# foreground: '#1d1f21'
|
|
||||||
# background: '#e9ff5e'
|
|
||||||
|
|
||||||
# All characters after the first one in the hint label
|
|
||||||
#
|
|
||||||
# Allowed values are CellForeground/CellBackground, which reference the
|
|
||||||
# affected cell, or hexadecimal colors like #ff00ff.
|
|
||||||
#end:
|
|
||||||
# foreground: '#e9ff5e'
|
|
||||||
# background: '#1d1f21'
|
|
||||||
|
|
||||||
# Line indicator
|
|
||||||
#
|
|
||||||
# Color used for the indicator displaying the position in history during
|
|
||||||
# search and vi mode.
|
|
||||||
#
|
|
||||||
# By default, these will use the opposing primary color.
|
|
||||||
#line_indicator:
|
|
||||||
# foreground: None
|
|
||||||
# background: None
|
|
||||||
|
|
||||||
# Selection colors
|
|
||||||
#
|
|
||||||
# Colors which should be used to draw the selection area.
|
|
||||||
#
|
|
||||||
# Allowed values are CellForeground/CellBackground, which reference the
|
|
||||||
# affected cell, or hexadecimal colors like #ff00ff.
|
|
||||||
#selection:
|
|
||||||
# text: CellBackground
|
|
||||||
# background: CellForeground
|
|
||||||
|
|
||||||
# Normal colors
|
|
||||||
#normal:
|
|
||||||
# black: '#1d1f21'
|
|
||||||
# red: '#cc6666'
|
|
||||||
# green: '#b5bd68'
|
|
||||||
# yellow: '#f0c674'
|
|
||||||
# blue: '#81a2be'
|
|
||||||
# magenta: '#b294bb'
|
|
||||||
# cyan: '#8abeb7'
|
|
||||||
# white: '#c5c8c6'
|
|
||||||
|
|
||||||
# Bright colors
|
|
||||||
#bright:
|
|
||||||
# black: '#666666'
|
|
||||||
# red: '#d54e53'
|
|
||||||
# green: '#b9ca4a'
|
|
||||||
# yellow: '#e7c547'
|
|
||||||
# blue: '#7aa6da'
|
|
||||||
# magenta: '#c397d8'
|
|
||||||
# cyan: '#70c0b1'
|
|
||||||
# white: '#eaeaea'
|
|
||||||
|
|
||||||
# Dim colors
|
|
||||||
#
|
|
||||||
# If the dim colors are not set, they will be calculated automatically based
|
|
||||||
# on the `normal` colors.
|
|
||||||
#dim:
|
|
||||||
# black: '#131415'
|
|
||||||
# red: '#864343'
|
|
||||||
# green: '#777c44'
|
|
||||||
# yellow: '#9e824c'
|
|
||||||
# blue: '#556a7d'
|
|
||||||
# magenta: '#75617b'
|
|
||||||
# cyan: '#5b7d78'
|
|
||||||
# white: '#828482'
|
|
||||||
|
|
||||||
# Indexed Colors
|
|
||||||
#
|
|
||||||
# The indexed colors include all colors from 16 to 256.
|
|
||||||
# When these are not set, they're filled with sensible defaults.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# `- { index: 16, color: '#ff00ff' }`
|
|
||||||
#
|
|
||||||
#indexed_colors: []
|
|
||||||
|
|
||||||
|
# Bright colors
|
||||||
|
bright:
|
||||||
|
black: '0x444b6a'
|
||||||
|
red: '0xff7a93'
|
||||||
|
green: '0xb9f27c'
|
||||||
|
yellow: '0xff9e64'
|
||||||
|
blue: '0x7da6ff'
|
||||||
|
magenta: '0xbb9af7'
|
||||||
|
cyan: '0x0db9d7'
|
||||||
|
white: '0xacb0d0'
|
||||||
|
colors: *tokyo-night-storm
|
||||||
# Bell
|
# Bell
|
||||||
#
|
#
|
||||||
# The bell is rung every time the BEL control character is received.
|
# The bell is rung every time the BEL control character is received.
|
||||||
|
|
3
.vimrc
3
.vimrc
|
@ -12,7 +12,6 @@ if $TERM == 'tmux-256color'
|
||||||
let &t_8b = "\033[48;2;%lu;%lu;%lum"
|
let &t_8b = "\033[48;2;%lu;%lu;%lum"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
set termguicolors
|
|
||||||
set background=dark
|
set background=dark
|
||||||
syntax enable
|
syntax enable
|
||||||
|
|
||||||
|
@ -66,5 +65,7 @@ Plug 'preservim/nerdtree'
|
||||||
Plug 'chiel92/vim-autoformat'
|
Plug 'chiel92/vim-autoformat'
|
||||||
Plug 'natebosch/vim-lsc'
|
Plug 'natebosch/vim-lsc'
|
||||||
Plug 'https://tildegit.org/sloum/gemini-vim-syntax'
|
Plug 'https://tildegit.org/sloum/gemini-vim-syntax'
|
||||||
|
Plug 'meatballs/vim-xonsh'
|
||||||
|
Plug 'davidhalter/jedi-vim'
|
||||||
|
|
||||||
call plug#end()
|
call plug#end()
|
||||||
|
|
5
.xonshrc
5
.xonshrc
|
@ -6,15 +6,12 @@ elif $HOSTNAME == "riley-server":
|
||||||
elif $HOSTNAME == "riley-desktop":
|
elif $HOSTNAME == "riley-desktop":
|
||||||
$PROMPT = '{RED} >< {RESET}| {BOLD_GREEN}{cwd_base}{RESET} ) '
|
$PROMPT = '{RED} >< {RESET}| {BOLD_GREEN}{cwd_base}{RESET} ) '
|
||||||
$XONSH_COLOR_STYLE = 'default'
|
$XONSH_COLOR_STYLE = 'default'
|
||||||
xontrib load argcomplete autovox jedi z bashisms
|
xontrib load argcomplete autovox jedi z bashisms jds
|
||||||
|
|
||||||
source "~/xsh/functions.xsh"
|
source "~/xsh/functions.xsh"
|
||||||
source "~/xsh/exceptions.xsh"
|
source "~/xsh/exceptions.xsh"
|
||||||
source "~/xsh/aliases.xsh"
|
source "~/xsh/aliases.xsh"
|
||||||
|
|
||||||
# TODO: Fix with Arch-based distros
|
|
||||||
# import addins # my extra stuffs :p
|
|
||||||
|
|
||||||
# Windows Subsystem for Linux stuff
|
# Windows Subsystem for Linux stuff
|
||||||
if in_wsl():
|
if in_wsl():
|
||||||
$GPG_TTY=$(tty) # allows gpg to work inside WSL
|
$GPG_TTY=$(tty) # allows gpg to work inside WSL
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
"""
|
||||||
|
Backup Module:
|
||||||
|
|
||||||
|
Classes:
|
||||||
|
- BackupManager
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
from zipfile import ZipFile
|
||||||
|
|
||||||
|
from . import Storage
|
||||||
|
|
||||||
|
__all__ = ["BackupManager"]
|
||||||
|
|
||||||
|
class BackupManager:
|
||||||
|
"""
|
||||||
|
Facilitates backup creation. Stores all backups in ~/.storage/backups
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
- create_backup()
|
||||||
|
- get_backups()
|
||||||
|
- get_delete_candidates()
|
||||||
|
- delete_excess_backups()
|
||||||
|
"""
|
||||||
|
def __init__(self, target_path: Path, backup_storage: Storage = Storage("backups"),
|
||||||
|
date_format: str = "%d_%m_%y__%H%M%S", separator: str = "-") -> None:
|
||||||
|
"""
|
||||||
|
Test
|
||||||
|
"""
|
||||||
|
self.target_path = target_path
|
||||||
|
self.backup_storage = backup_storage
|
||||||
|
self.date_format = date_format
|
||||||
|
self.separator = separator
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target_path(self) -> Path:
|
||||||
|
"""
|
||||||
|
Target to create backups of. This could be a file or folder.
|
||||||
|
"""
|
||||||
|
return self._target_path
|
||||||
|
|
||||||
|
@target_path.setter
|
||||||
|
def target_path(self, new_path: Path):
|
||||||
|
if isinstance(new_path, Path):
|
||||||
|
if new_path.exists() and (new_path.is_dir() or new_path.is_file()):
|
||||||
|
self._target_path = new_path
|
||||||
|
else:
|
||||||
|
raise ValueError(new_path)
|
||||||
|
else:
|
||||||
|
raise TypeError(new_path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def backup_storage(self) -> Storage:
|
||||||
|
"""
|
||||||
|
Storage object to store created backups in.
|
||||||
|
"""
|
||||||
|
return self._backup_storage
|
||||||
|
|
||||||
|
@backup_storage.setter
|
||||||
|
def backup_storage(self, new_storage: Storage):
|
||||||
|
if isinstance(new_storage, Storage):
|
||||||
|
self._backup_storage = new_storage
|
||||||
|
else:
|
||||||
|
raise TypeError(new_storage)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def date_format(self) -> str:
|
||||||
|
"""The datetime format string used to date the backups."""
|
||||||
|
return self._date_format
|
||||||
|
|
||||||
|
@date_format.setter
|
||||||
|
def date_format(self, new_format):
|
||||||
|
if isinstance(new_format, str):
|
||||||
|
self._date_format = new_format
|
||||||
|
else:
|
||||||
|
raise TypeError(new_format)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def separator(self) -> str:
|
||||||
|
"""The separator that separates the archive name from the date"""
|
||||||
|
return self._separator
|
||||||
|
|
||||||
|
@separator.setter
|
||||||
|
def separator(self, new_separator):
|
||||||
|
if isinstance(new_separator, str):
|
||||||
|
if new_separator not in self.target_path.name and new_separator not in self.date_format:
|
||||||
|
self._separator = new_separator
|
||||||
|
else:
|
||||||
|
raise ValueError(new_separator)
|
||||||
|
else:
|
||||||
|
raise TypeError(new_separator)
|
||||||
|
|
||||||
|
def create_backup(self):
|
||||||
|
"""
|
||||||
|
Create a backup of the target path, stored in the backup storage folder.
|
||||||
|
"""
|
||||||
|
date_string = datetime.now().strftime(self.date_format)
|
||||||
|
backup_name = f"{self.target_path.name}{self.separator}{date_string}.zip"
|
||||||
|
backup_path = self.backup_storage.get_file(backup_name)
|
||||||
|
with ZipFile(backup_path, mode="w") as zip_file:
|
||||||
|
for item in self.target_path.glob("**/*"):
|
||||||
|
zip_file.write(item, item.relative_to(self.target_path))
|
||||||
|
|
||||||
|
def get_backups(self):
|
||||||
|
"""
|
||||||
|
Get all backups found in the given folder.
|
||||||
|
"""
|
||||||
|
return self.backup_storage.list_files(f"{self.target_path.stem}{self.separator}*.zip")
|
||||||
|
|
||||||
|
def get_delete_candidates(self, max_backup_count) -> list[Path]:
|
||||||
|
"""
|
||||||
|
Get all candidates for deletion with the given max_backup_count.
|
||||||
|
If none are available for deletion, returns None.
|
||||||
|
"""
|
||||||
|
def get_date(file: Path) -> datetime:
|
||||||
|
"""
|
||||||
|
Turns the datetime string in the file name into a datetime object.
|
||||||
|
"""
|
||||||
|
date_string = file.name.split(self.separator)[1].replace(file.suffix, "")
|
||||||
|
return datetime.strptime(date_string, self.date_format)
|
||||||
|
|
||||||
|
backups = self.get_backups()
|
||||||
|
backups.sort(key=get_date)
|
||||||
|
return backups[:(len(backups)-max_backup_count)] # returns the oldest excess backups
|
||||||
|
|
||||||
|
def delete_excess_backups(self, max_backup_count: int):
|
||||||
|
"""Delete all excess backups"""
|
||||||
|
for file in self.get_delete_candidates(max_backup_count):
|
||||||
|
file.unlink()
|
|
@ -0,0 +1,137 @@
|
||||||
|
"""
|
||||||
|
Storage Module:
|
||||||
|
|
||||||
|
Classes:
|
||||||
|
- Storage
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
__all__ = ['Storage']
|
||||||
|
|
||||||
|
class Storage:
|
||||||
|
"""
|
||||||
|
Unifies all filesystem access methods under a single class.
|
||||||
|
Minimizes room for mistakes and improves reusability.
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
- get_file()
|
||||||
|
- get_folder()
|
||||||
|
- write_file()
|
||||||
|
- read_file()
|
||||||
|
- delete_file()
|
||||||
|
- rename_file()
|
||||||
|
- add_file()
|
||||||
|
- list_files()
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, folder: str, root_folder: str = ".storage") -> None:
|
||||||
|
"""
|
||||||
|
Create a new storage instance, it automatically creates and manages a folder in the user's home directory, all you have to do is supply a subfolder to store files in.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
folder (str): the name of the folder to use.
|
||||||
|
"""
|
||||||
|
self.root = Path.home().joinpath(root_folder)
|
||||||
|
self.folder = self.root.joinpath(folder)
|
||||||
|
self.folder.mkdir(exist_ok=True, parents=True)
|
||||||
|
|
||||||
|
def get_file(self, path: str) -> Path:
|
||||||
|
"""Get the fully qualified path of a file in the folder.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): the name of the file to grab.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path: the path of the file.
|
||||||
|
"""
|
||||||
|
return self.folder.joinpath(path)
|
||||||
|
|
||||||
|
def get_folder(self, name: str) -> Storage:
|
||||||
|
"""
|
||||||
|
Get a folder inside the Storage directory.
|
||||||
|
Returns a Storage object representing that folder.
|
||||||
|
"""
|
||||||
|
return Storage(name, root_folder=self.folder.name)
|
||||||
|
|
||||||
|
def write_file(self, name: str, data: dict):
|
||||||
|
"""Write data to the given file in JSON format.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): the name of the file.
|
||||||
|
data (dict): the data to write.
|
||||||
|
"""
|
||||||
|
file = self.get_file(name)
|
||||||
|
file.touch(exist_ok=True)
|
||||||
|
with file.open("w+", encoding="utf-8") as f:
|
||||||
|
json.dump(data, f, indent=4)
|
||||||
|
|
||||||
|
def read_file(self, name: str) -> dict:
|
||||||
|
"""Read data from the given file in JSON format.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): the name of the file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: the data from the file.
|
||||||
|
"""
|
||||||
|
file = self.get_file(name)
|
||||||
|
if not file.exists():
|
||||||
|
return {}
|
||||||
|
with file.open("r+", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def delete_file(self, name: str):
|
||||||
|
"""Delete the given file from the folder.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): the name of the file.
|
||||||
|
"""
|
||||||
|
file = self.get_file(name)
|
||||||
|
file.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
def rename_file(self, old_name: str, new_name: str):
|
||||||
|
"""Rename a file in the folder.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
old_name (str): the current name of the file.
|
||||||
|
new_name (str): the new name of the file.
|
||||||
|
"""
|
||||||
|
file = self.get_file(old_name)
|
||||||
|
new_file = self.folder.joinpath(new_name)
|
||||||
|
file.rename(new_file)
|
||||||
|
|
||||||
|
def add_file(self, name: str, path: Path | None = None, binary: bytes | None = None):
|
||||||
|
"""Add a copy of a file to the folder.
|
||||||
|
If a binary stream is given, it is saved directly to the named location.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): The name to save it under.
|
||||||
|
path (Path): The path of the file to copy from.
|
||||||
|
binary (BinaryIO): The binary stream to copy from.
|
||||||
|
"""
|
||||||
|
if path is not None and binary is not None:
|
||||||
|
raise ValueError(binary, "Cannot supply both a path and a binary stream.")
|
||||||
|
elif path is not None:
|
||||||
|
shutil.copy(path, self.folder.joinpath(name))
|
||||||
|
elif binary is not None:
|
||||||
|
with self.folder.joinpath(name).open("wb+") as f:
|
||||||
|
f.write(binary)
|
||||||
|
|
||||||
|
def list_files(self, pattern: str | None = None) -> list[Path]:
|
||||||
|
"""
|
||||||
|
Return a list of all files in the directory.
|
||||||
|
"""
|
||||||
|
files: list[Path] = []
|
||||||
|
if pattern is None:
|
||||||
|
for file in self.folder.iterdir():
|
||||||
|
files.append(file)
|
||||||
|
else:
|
||||||
|
for file in self.folder.glob(pattern):
|
||||||
|
files.append(file)
|
||||||
|
return files
|
|
@ -0,0 +1,52 @@
|
||||||
|
"""Integrates Johnny Decimal Notation into Xonsh"""
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from xonsh.built_ins import XSH
|
||||||
|
|
||||||
|
HOME = Path("/run/media/riley/drive")
|
||||||
|
|
||||||
|
def find_category(number: int, path, regex: str):
|
||||||
|
"""Find matching JDN folder when given notation"""
|
||||||
|
import re
|
||||||
|
folders = path.iterdir()
|
||||||
|
for folder in folders:
|
||||||
|
if not folder.is_dir():
|
||||||
|
continue
|
||||||
|
folder_category = re.match(regex, folder.name)
|
||||||
|
if folder_category is None:
|
||||||
|
continue
|
||||||
|
if len(folder_category.groups()) == 2:
|
||||||
|
if number >= int(folder_category.group(1)) and number <= int(folder_category.group(2)):
|
||||||
|
return folder
|
||||||
|
elif len(folder_category.groups()) == 1:
|
||||||
|
if number == int(folder_category.group((1))):
|
||||||
|
return folder
|
||||||
|
return path
|
||||||
|
|
||||||
|
@XSH.builtins.events.on_transform_command
|
||||||
|
def jds_preproc(cmd: str, **kw):
|
||||||
|
"""processes command strings starting with "`" to cd to matching folder."""
|
||||||
|
if cmd.startswith("`") and "." in cmd and not cmd.strip().endswith("`"):
|
||||||
|
try:
|
||||||
|
johnny_decimal_notation = cmd.replace("`", "")
|
||||||
|
bucket = find_category(int(johnny_decimal_notation.split(".")[0]), HOME, r"(^\d0)-(\d9)")
|
||||||
|
category = find_category(int(johnny_decimal_notation.split(".")[0]), bucket, r"^(\d\d)")
|
||||||
|
folder = find_category(int(johnny_decimal_notation.split(".")[1]), category, r"^(\d\d)")
|
||||||
|
cmd = f"cd '{folder.resolve()}'"
|
||||||
|
except FileNotFoundError:
|
||||||
|
cmd = f'print("\'{HOME}\' not found.")'
|
||||||
|
except ValueError:
|
||||||
|
cmd = f'print("\'{cmd.strip().replace("`", "")}\' is not a valid JDN.")'
|
||||||
|
elif cmd.startswith("`") and not (len(cmd.strip()) >= 2 and cmd.strip().endswith("`")):
|
||||||
|
try:
|
||||||
|
johnny_decimal_notation = cmd.replace("`", "")
|
||||||
|
if johnny_decimal_notation == "\n":
|
||||||
|
return f"cd '{HOME.resolve()}'"
|
||||||
|
bucket = find_category(int(johnny_decimal_notation.split(".")[0]), HOME, r"(^\d0)-(\d9)")
|
||||||
|
category = find_category(int(johnny_decimal_notation.split(".")[0]), bucket, r"^(\d\d)")
|
||||||
|
cmd = f"cd '{category.resolve()}'"
|
||||||
|
except FileNotFoundError:
|
||||||
|
cmd = f'print("\'{HOME}\' not found.")'
|
||||||
|
except ValueError:
|
||||||
|
cmd = f'print("\'{cmd.strip().replace("`", "")}\' is not a valid JDN.")'
|
||||||
|
return cmd
|
|
@ -1,4 +1,5 @@
|
||||||
source xsh/functions.xsh
|
import lib
|
||||||
|
source ~/xsh/functions.xsh
|
||||||
|
|
||||||
def _debug():
|
def _debug():
|
||||||
if $XONSH_SHOW_TRACEBACK:
|
if $XONSH_SHOW_TRACEBACK:
|
||||||
|
@ -41,19 +42,60 @@ def _bwc(args: list):
|
||||||
else:
|
else:
|
||||||
print(f"copied {i}")
|
print(f"copied {i}")
|
||||||
|
|
||||||
def _mcrcon(args: list):
|
def _backup(args: list):
|
||||||
if p"~/.mcrcon".exists():
|
from pathlib import Path
|
||||||
source "~/.mcrcon"
|
target_path = Path(args[0])
|
||||||
else:
|
max_backup_count: int = 3
|
||||||
raise FileNotFoundError("~/.mcrcon")
|
if len(args) == 2 and isinstance(args[1], int):
|
||||||
$(mcrcon @(" ".join(args)))
|
max_backup_count = int(args[1])
|
||||||
|
bm = lib.BackupManager(target_path)
|
||||||
|
bm.create_backup()
|
||||||
|
bm.delete_excess_backups(max_backup_count)
|
||||||
|
|
||||||
def _mcterm():
|
def _mcrcon(args: list):
|
||||||
if p"~/.mcrcon".exists():
|
import json
|
||||||
source "~/.mcrcon"
|
try:
|
||||||
else:
|
with p"~/.mcrcon.json".open("r") as fp:
|
||||||
raise FileNotFoundError("~/.mcrcon")
|
servers_data = json.load(fp)
|
||||||
mcrcon -t
|
server_data = servers_data[args[0]]
|
||||||
|
$MCRCON_HOST = server_data["address"]
|
||||||
|
$MCRCON_PORT = server_data["port"]
|
||||||
|
$MCRCON_PASS = server_data["password"]
|
||||||
|
$(mcrcon @(" ".join(args[1:])))
|
||||||
|
except IndexError:
|
||||||
|
print("Please indicate which server to connect to.")
|
||||||
|
except KeyError:
|
||||||
|
print("Server configuration not found.")
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("Server configuration file '.mcrcon.json' is not found.")
|
||||||
|
|
||||||
|
def _mcterm(args: list):
|
||||||
|
import json
|
||||||
|
try:
|
||||||
|
with p"~/.mcrcon.json".open("r") as fp:
|
||||||
|
servers_data = json.load(fp)
|
||||||
|
server_data = servers_data[args[0]]
|
||||||
|
$MCRCON_HOST = server_data["address"]
|
||||||
|
$MCRCON_PORT = server_data["port"]
|
||||||
|
$MCRCON_PASS = server_data["password"]
|
||||||
|
mcrcon -t
|
||||||
|
except IndexError:
|
||||||
|
print("Please indicate which server to connect to.")
|
||||||
|
except KeyError:
|
||||||
|
print("Server configuration not found.")
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("Server configuration file '.mcrcon.json' is not found.")
|
||||||
|
|
||||||
|
def _mclist():
|
||||||
|
import json
|
||||||
|
try:
|
||||||
|
with p"~/.mcrcon.json".open("r") as fp:
|
||||||
|
servers_data = json.load(fp)
|
||||||
|
print("Servers:")
|
||||||
|
for key in servers_data:
|
||||||
|
print("\t-", key)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("Server configuration file '.mcrcon.json' is not found.")
|
||||||
|
|
||||||
def _alias():
|
def _alias():
|
||||||
for alias in aliases:
|
for alias in aliases:
|
||||||
|
@ -91,12 +133,15 @@ def _ls():
|
||||||
|
|
||||||
def load_aliases():
|
def load_aliases():
|
||||||
aliases.update({
|
aliases.update({
|
||||||
|
'bu': _backup,
|
||||||
|
'backup': _backup,
|
||||||
'bwg': _bwc,
|
'bwg': _bwc,
|
||||||
'colortest': _colortest,
|
'colortest': _colortest,
|
||||||
'debug': _debug,
|
'debug': _debug,
|
||||||
'ls': 'ls -alhs --color=auto',
|
'ls': 'ls -alhs --color=auto',
|
||||||
'mc': _mcrcon,
|
'mc': _mcrcon,
|
||||||
'mct': _mcterm,
|
'mct': _mcterm,
|
||||||
|
'mcl': _mclist,
|
||||||
':q': 'exit',
|
':q': 'exit',
|
||||||
'ensure-tmux': _ensure_tmux,
|
'ensure-tmux': _ensure_tmux,
|
||||||
'aliases': _alias,
|
'aliases': _alias,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
source xsh/exceptions.xsh
|
source ~/xsh/exceptions.xsh
|
||||||
|
|
||||||
def in_wsl() -> bool:
|
def in_wsl() -> bool:
|
||||||
"""Determines if the system is running inside a WSL environment."""
|
"""Determines if the system is running inside a WSL environment."""
|
||||||
|
|
Loading…
Reference in New Issue