#!/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()