mirror of
https://github.com/foo-dogsquared/dotfiles.git
synced 2025-01-31 04:57:57 +00:00
e5222304a1
I've migrated to Neovim because of one thing... Luke Smith-senpai... Ever since I've seen him typed 'nvim' in his recent videos, I was devastated. All of those hours that my little heart and soul poured into creating a 130-line vimrc to configure Vim to its absolute in the way I wanted to use was gone. All of those 7 days and a few minutes every now and then, are crushed. It is truly a betrayal to see it use a modernized version of a relic of the past. I first thought, "How dare he?". I was not able to sleep well the following days. It was heart-wrenching. Out of spite, I've tried to. I've nothing left and you know there is a saying 'a weeb with nothing got nothing to lose'. All it took was to rename certain files, reinstall the plugin manager and its plugins, a grand total of 5 minutes. My heart skipped a beat. It was like being a birb with broken wings trying to fly and eventually didn't left off until its talon is in the ground. And the ground is Neovim. Now I love Neovim more than ever... Thank you Luke Smith Unaboomer-kun-senpai. It was truly a wonderful experience.
198 lines
6.9 KiB
Python
198 lines
6.9 KiB
Python
#!/usr/bin/env python
|
|
|
|
# A simple setup script for the packages.
|
|
# There should be a file named `locations.json` in this setup where it contains a top-level hash map with the packages and their target path.
|
|
# Feel free to modify it accordingly.
|
|
|
|
# This script is tailored to my specific needs.
|
|
# It also strives to only rely on the standard library so further no installation needed.
|
|
# Feel free to modify this script as well.
|
|
|
|
# For future references, the Python version when creating for this script is v3.8.2.
|
|
# If there's any reason why stuff is not working, it might be because it is different on the older versions or just my bad code lol.
|
|
|
|
# Anyway, I feel like this script should be only up to half the size.
|
|
# Hell, I think this should be simpler but no... I pushed for a more complex setup or something.
|
|
# What am I doing?
|
|
# Is this what ricing is all about?
|
|
# Why are you reading this?
|
|
|
|
import argparse
|
|
import json
|
|
import logging
|
|
import os
|
|
import os.path
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
|
|
PACKAGE_DATA_FILE="locations.json"
|
|
|
|
|
|
class PackageDir:
|
|
""" A package directory should have a file named `locations.json` where it contains a top-level object of the stow packages with their usual target path. """
|
|
|
|
def __init__(self, package_path = None):
|
|
"""
|
|
Creates an instance of PackageDir
|
|
|
|
:param: package_path - The directory where it should contain a file named `locations.json`.
|
|
"""
|
|
if package_path is None:
|
|
package_path = os.getcwd()
|
|
|
|
package_path = Path(package_path)
|
|
self.path = package_path
|
|
|
|
# Loads the packages
|
|
self.packages = {}
|
|
try:
|
|
self.load_packages()
|
|
except:
|
|
pass
|
|
|
|
|
|
def add_package(self, package, target):
|
|
"""
|
|
Add the package to the list.
|
|
|
|
:param: package - the name of the package
|
|
:param: target - the target path of the package
|
|
"""
|
|
package_path = self.path / package
|
|
assert package_path.is_dir(), f"The given package '{package}' does not exist in the package directory."
|
|
self.packages[package] = target
|
|
|
|
|
|
def remove_package(self, package):
|
|
"""
|
|
Remove the package in the list.
|
|
Although this function is quite simple, this is only meant as an official API.
|
|
|
|
:param: package - the package to be removed
|
|
"""
|
|
return self.packages.pop(package, None)
|
|
|
|
|
|
def load_packages(self):
|
|
"""
|
|
Loads the packages from the data file.
|
|
"""
|
|
assert self.json_location.is_file(), "There is no 'package.json` in the given directory."
|
|
|
|
with open(self.json_location) as f:
|
|
package_map = json.load(f)
|
|
for package, target in package_map.items():
|
|
try:
|
|
self.add_package(package, target)
|
|
except Exception as e:
|
|
logging.error(e)
|
|
|
|
|
|
def execute_packages(self, commands):
|
|
"""
|
|
Execute a set of commands with the packages.
|
|
|
|
:param: commands - A list of strings that'll be used as a template.
|
|
The template string uses the `string.format` syntax.
|
|
(https://docs.python.org/3/library/string.html?highlight=template#format-string-syntax)
|
|
It should contain a binding to the keywords `package` and `location` (e.g., `stow --restow {package} --target {location}`).
|
|
"""
|
|
for package, location in self.packages.items():
|
|
# Making sure the location is expanded.
|
|
location = os.path.expanduser(location)
|
|
target_cwd = os.path.realpath(self.path)
|
|
|
|
for command in commands:
|
|
command = command.format(package=package, location=location)
|
|
|
|
process_status = subprocess.run(command, cwd=target_cwd, capture_output=True, shell=True, encoding='utf-8')
|
|
if process_status.returncode == 0:
|
|
logging.info(f"{command}: successfully ran")
|
|
else:
|
|
logging.error(process_status.stderr.strip())
|
|
|
|
|
|
@property
|
|
def json_location(self):
|
|
""" Simply appends the path with the required JSON file. """
|
|
return self.path / PACKAGE_DATA_FILE
|
|
|
|
|
|
def setup_logging():
|
|
"""
|
|
Setup the logger instance.
|
|
"""
|
|
logging.basicConfig(format="[%(levelname)s] %(module)s: %(message)s", level=logging.INFO, stream=sys.stdout)
|
|
|
|
|
|
def setup_args():
|
|
"""
|
|
Setup the argument parser.
|
|
|
|
:returns: An ArgumentParser object.
|
|
"""
|
|
description = """A quick installation script for this setup. Take note this is tailored to my specific needs."""
|
|
argparser = argparse.ArgumentParser(description=description)
|
|
|
|
argparser.add_argument("-c", "--commands", metavar = "command", help = "Executing the specified commands. All of the commands are treated as they were entered in the shell.", nargs = "*", default = ["echo {package}"])
|
|
argparser.add_argument("-d", "--directory", metavar = "path", help = "Set the directory of the package data file.", type = Path, nargs = "?", default = Path(os.getcwd()))
|
|
argparser.add_argument("--exclude", metavar = "package", help = "Exclude the given packages.", type = str, nargs = "+", default = [])
|
|
argparser.add_argument("--include", metavar = ("package", "location"), help = "Include with the following packages.", type = str, nargs = 2, action = "append", default = [])
|
|
argparser.add_argument("--only", metavar = "package", help = "Only execute with the given packages.", type = str, nargs = "+", default = [])
|
|
|
|
return argparser
|
|
|
|
|
|
def parse_args(parser, argv):
|
|
"""
|
|
Parse the arguments.
|
|
|
|
This is also the main function to pay attention to.
|
|
|
|
:param: parser - An instance of the argument parser.
|
|
:param: argv - A list of arguments to be parsed.
|
|
"""
|
|
args = parser.parse_args(argv)
|
|
|
|
try:
|
|
package_dir = PackageDir(args.directory)
|
|
|
|
# Include the following packages.
|
|
for package, target in args.include:
|
|
try:
|
|
package_dir.add_package(package, target)
|
|
except Exception as e:
|
|
logging.error(e)
|
|
|
|
# Exclude the following packages.
|
|
# We don't need the value here so we'll let it pass.
|
|
for package in args.exclude:
|
|
package_dir.remove_package(package)
|
|
|
|
if len(args.only) >= 1:
|
|
items = {}
|
|
for package in args.only:
|
|
value = package_dir.remove_package(package)
|
|
if value is None:
|
|
continue
|
|
items[package] = value
|
|
|
|
package_dir.packages.clear()
|
|
package_dir.packages = items
|
|
|
|
|
|
# Execute the commands with the packages.
|
|
package_dir.execute_packages(args.commands)
|
|
except Exception as e:
|
|
logging.error(e)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
setup_logging()
|
|
argparser = setup_args()
|
|
|
|
parse_args(argparser, sys.argv[1:])
|
|
|
|
|