184 lines
5.1 KiB
Python
184 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
|
|
from git import Repo
|
|
from git import Actor
|
|
import shutil
|
|
import os
|
|
|
|
WORKING_DIR = "/tmp/push-dotfiles"
|
|
GIT_REPO_URL = "git@git.seanomik.net:SeanOMik/nixos-dotfiles.git"
|
|
|
|
## Get a yes or no answer from the user and handle invalid input
|
|
def get_yes_no_answer(question: str, error_msg: str = "ERROR: Malformed input!"):
|
|
ans = ""
|
|
|
|
while ans != "y" or ans != "n":
|
|
print(f"{question} (y,n): ", end="")
|
|
ans = input()
|
|
|
|
if ans != "y" or ans != "n":
|
|
print(error_msg)
|
|
|
|
if ans == "y":
|
|
return True
|
|
elif ans == "n":
|
|
return False
|
|
|
|
## Clears the working directory
|
|
def remove_working_dir():
|
|
if os.path.exists(WORKING_DIR):
|
|
shutil.rmtree(WORKING_DIR)
|
|
print(f"Removed working directory ({WORKING_DIR}).")
|
|
else:
|
|
print(f"Skipping deletion of working directory since it doesn't exist.")
|
|
|
|
## Copy the dotfiles (/etc/nixos) to the working directory
|
|
def copy_dotfiles():
|
|
src_directory = "/etc/nixos"
|
|
for filename in os.listdir(src_directory):
|
|
if filename == ".git":
|
|
continue
|
|
else:
|
|
full_path = os.path.join(src_directory, filename)
|
|
if os.path.isdir(full_path):
|
|
shutil.copytree(full_path, os.path.join(WORKING_DIR, filename))
|
|
else:
|
|
shutil.copy(full_path, WORKING_DIR)
|
|
|
|
print("Copied \"/etc/nixos\" dotfiles to working directory.")
|
|
|
|
## Clone the git repository to the working dir
|
|
def clone_git_repo():
|
|
print("Cloning git repository...")
|
|
Repo.clone_from(GIT_REPO_URL, WORKING_DIR)
|
|
print("Cloned git repository!")
|
|
|
|
## Clear the working directory
|
|
def clear_working_dir():
|
|
for filename in os.listdir(WORKING_DIR):
|
|
if filename == ".git" or filename.endswith(".py") or filename == "shell.nix":
|
|
continue
|
|
else:
|
|
full_path = os.path.join(WORKING_DIR, filename)
|
|
if os.path.isdir(full_path):
|
|
shutil.rmtree(full_path)
|
|
else:
|
|
os.remove(full_path)
|
|
print("Cleared git repo...")
|
|
|
|
## Get the git repository in the working dir
|
|
def get_git_repo():
|
|
return Repo(WORKING_DIR)
|
|
|
|
## Stage changes
|
|
def stage_git_changes(repo: Repo):
|
|
file_diff_list = []
|
|
|
|
# TODO: Check for the staged changes also
|
|
diff = repo.index.diff(None)
|
|
|
|
if len(diff) == 0:
|
|
diff = repo.index.diff("HEAD")
|
|
|
|
if len(diff) == 0:
|
|
print("ERROR: No changes have been made!")
|
|
exit()
|
|
else:
|
|
print("All changes are already staged...")
|
|
return
|
|
|
|
print("Git diff:")
|
|
for item in diff:
|
|
if item.deleted_file:
|
|
print(f" D - {item.a_path}")
|
|
|
|
file_diff_list.append(os.path.join(repo.working_tree_dir, item.a_path))
|
|
elif item.new_file:
|
|
print(f" N - {item.b_path}")
|
|
|
|
file_diff_list.append(os.path.join(repo.working_tree_dir, item.b_path))
|
|
elif item.renamed_file:
|
|
print(f" R - {item.a_path} to {item.b_path}")
|
|
|
|
file_diff_list.append(os.path.join(repo.working_tree_dir, item.b_path))
|
|
else:
|
|
print(f" C - {item.a_path}")
|
|
|
|
file_diff_list.append(os.path.join(repo.working_tree_dir, item.a_path))
|
|
|
|
ans = get_yes_no_answer("Stage entire diff?")
|
|
|
|
if ans:
|
|
for diff in file_diff_list:
|
|
repo.git.add(diff)
|
|
|
|
print("Staged all changes")
|
|
else:
|
|
print("TODO: Create numbered list to only stage certain files") # TODO
|
|
|
|
## Get the author from the user
|
|
def get_git_author(repo: Repo):
|
|
ans = get_yes_no_answer("Use git config user?")
|
|
if ans:
|
|
username = repo.config_reader().get_value("user", "name")
|
|
email = repo.config_reader().get_value("user", "email")
|
|
|
|
print(f"Got git author:\n Username: {username}\n Email: {email}")
|
|
|
|
ans = get_yes_no_answer("Is this author correct?")
|
|
|
|
if ans:
|
|
return Actor(username, email)
|
|
else:
|
|
return get_git_author(repo)
|
|
else:
|
|
print("Enter username: ", end="")
|
|
username = input()
|
|
|
|
print("Enter email: ", end="")
|
|
email = input()
|
|
|
|
return Actor(username, email)
|
|
|
|
## Commit changes
|
|
def commit_changes(repo: Repo, message: str, author: Actor):
|
|
res = repo.git.commit('-S', '-m', f'"{message}"', author=f'"{author.name} <{author.email}>"')
|
|
print(res)
|
|
print("Committed changes!")
|
|
|
|
## Push git changes to the repo!
|
|
def push_git_changes():
|
|
repo = get_git_repo()
|
|
stage_git_changes(repo)
|
|
|
|
ans = ""
|
|
|
|
while len(ans) == 0:
|
|
print("Commit message: ", end="")
|
|
ans = input()
|
|
|
|
if len(ans) == 0:
|
|
print("ERROR: Cannot use an empty commit message!")
|
|
|
|
commit_changes(repo, ans, get_git_author(repo))
|
|
|
|
# Actually push now
|
|
print("Pushing changes...")
|
|
origin = repo.remote(name='origin')
|
|
origin.push()
|
|
print("Pushed changes!")
|
|
|
|
def main():
|
|
remove_working_dir();
|
|
|
|
clone_git_repo();
|
|
clear_working_dir();
|
|
|
|
copy_dotfiles();
|
|
push_git_changes();
|
|
|
|
print("Done!")
|
|
|
|
if __name__ == '__main__':
|
|
main()
|