nixvenv/nvenv.py
thecookingsenpai b262b2e0dc Initial commit
2023-12-25 13:28:06 +01:00

159 lines
6.6 KiB
Python

import os
import subprocess
import json
from pprint import pprint
import sys
import shutil
environment = os.environ.copy()
config = {}
nvenv_name = ""
local_bin_folder = ""
load_file = ""
hostname = ""
username = ""
# INFO Entry point
def main(config_file="./config.json", new=False, delete=False):
print("[ Welcome to NixVenv, the *nix compatible virtual shell environment manager ]")
global environment, config, cmds, local_bin_folder, load_file, nvenv_name, shell, hostname, username
p = subprocess.run("whoami", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
username = p.stdout.decode('utf-8').strip()
p = subprocess.run("hostname", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
hostname = p.stdout.decode('utf-8').strip()
p = subprocess.run("echo $SHELL", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
shell = p.stdout.decode('utf-8').strip()
print(shell)
cmds = 'echo "[ Setting environment variables ]"\n'
config = open(config_file, "r")
config = json.loads(config.read())
print("[*] Config file loaded: " + config_file)
nvenv_name = config["nvenv_name"]
# Halt if we have to delete the environment
if delete:
if not os.path.exists(nvenv_name):
print("[*] Environment does not exist: " + nvenv_name)
else:
shutil.rmtree(nvenv_name, ignore_errors=True)
print("[*] Deleted environment: " + nvenv_name)
os._exit(0)
# Else we use the environment
print("[*] Reading from environment: " + nvenv_name)
local_bin_folder = os.getcwd() + "/" + nvenv_name + "/" + config["local_bin"]
print("[*] Local bin folder: " + local_bin_folder)
load_file = os.getcwd() + "/" + nvenv_name + "/" + config["load_file"]
new_environment(new)
load_config()
load_environment()
# INFO Load a configuration file
def load_config():
global cmds, local_bin_folder, load_file, hostname
# Overwrites replace environment variables fully or create a new one
overwrites = config['overwrites']
for key in overwrites:
cmds += "export " + key + "=" + overwrites[key] + "\n"
print("[*] Overwriting enviromental variable: " + key)
# Additions add the value to the environment variable preserving the original value
additions = config["additions"]
for key in additions:
cmds += "export " + key + "=${" + key + "}:" + additions[key] + "\n"
print("[*] Adding to enviromental variable: " + key)
# Setting our environment variables
print("[*] Setting our environment variables")
cmds += "export PATH=" + local_bin_folder + ":" + os.environ["PATH"]
# Loading the static environment variables defined in the config file
print("[*] Setting the environment name as " + config["nvenv_name"])
cmds += "export NVENV_NAME=" + config["nvenv_name"] + "\n"
print("[*] Changing to: " + config["working_dir"])
cmds += "cd " + config["working_dir"] + "\n"
cmds += 'echo "nvenv environment loaded: $NVENV_NAME"\n'
# Setting up customizations
cmds += 'export PS1="' + username + ' [' + config["nvenv_name"] + '@' + hostname+ '] :> "\n'
# Finally, writing to the load file
print("[*] Writing to the load file: " + load_file)
with open(load_file, "w") as f:
f.write(cmds)
# INFO Loading the local environment fully
def load_environment():
print("[*] Loading the environment")
global environment, load_file, shell
# Multiple shells are supported
if "zsh" in shell:
cmd = "source " + load_file + " && " + shell + " -f -d"
else:
cmd = shell + " --rcfile " + load_file
# Finally, loading the environment by sourcing the load file
print("[+] Executing: " + cmd)
print("\nNOTE: Digit 'exit' and press ENTER to return to the previous environment\n")
os.system(cmd)
# INFO Environemnt creation
def new_environment(new_flag=False):
global cmds, local_bin_folder
if os.path.exists(os.getcwd() + "/" + nvenv_name):
if not new_flag:
raise Exception("[x] Environment already exists: " + nvenv_name)
print("[+] Environment already exists: " + nvenv_name)
return
# Creating the local_bin_folder if it doesn't exist
if not os.path.exists(local_bin_folder):
os.makedirs(local_bin_folder)
# Reading the init commands
init_cmds_list = config["init_cmds"]
for cmd in init_cmds_list:
# Replacing folders if needed
if (cmd == "here"):
running_dir = os.getcwd()
elif (cmd == "nvenv_folder"):
running_dir = os.getcwd() + "/" + nvenv_name
elif (cmd == "local_bin_folder"):
running_dir = local_bin_folder
else:
# Support for custom directories
# REVIEW Security note: limit it to the current working directory
if not os.path.exists(running_dir):
raise Exception("Running directory does not exist: " + running_dir)
# Compiling the command to be executed before the environment is activated
single_cmd = init_cmds_list[cmd]
actual_cmd = "cd '" + running_dir + "' && " + single_cmd
print("[*] Executing: " + actual_cmd)
os.system(actual_cmd)
# Support files
files = config["files"]
for file in files:
origin = file[0]
destination = file[1]
if not os.path.exists(origin):
raise Exception("[x] Origin file does not exist: " + origin)
if os.path.exists(destination):
raise Exception("[x] Destination file already exists: " + destination)
print("[*] Copying file: " + origin + " to: " + destination)
shutil.copy(origin, destination)
if __name__ == '__main__':
# Argument parsing
args_len = len(sys.argv)
print(sys.argv)
filename = sys.argv[0]
params = {
"operation": "run",
"config_file": "config.json",
}
# Getting parameters
for param in sys.argv[1:]:
if "operation=" in param:
params["operation"] = param.split("=")[1]
if "config_file=" in param:
params["config_file"] = param.split("=")[1]
# Sanity checks
if not os.path.exists(params["config_file"]):
raise Exception("[x] Config file does not exist: " + params["config_file"])
# Runs based on operation
if params["operation"] == "activate" or params["operation"] == "run":
main(config_file=params["config_file"])
elif params["operation"] == "new":
main(config_file=params["config_file"], new=True)
elif params["operation"] == "remove":
main(config_file=params["config_file"], delete=True)