dotfiles/home/private_bin/executable_concom

148 lines
3.6 KiB
Python

#!/usr/bin/env python3
import shlex
import subprocess
import sys
from shutil import which
from pathlib import Path
def is_tool(name):
"""Check whether `name` is on PATH and marked as executable."""
if not which(name):
print(f"ERROR: {name} is not found in your PATH")
sys.exit(1)
def is_repo():
if not (Path.cwd() / ".git").is_dir():
print(color("Not a git repo.","9"))
print("exiting...")
sys.exit(1)
def run(cmd, capture=True, returncode=False):
result = subprocess.run(
shlex.split(cmd),
stdout=subprocess.PIPE if capture else None,
text=True,
shell=False,
)
if returncode:
return result.returncode
elif capture:
return result.stdout.strip()
def confirm(q):
return run(
"gum confirm "
"--selected.bold "
"--selected.background 11 "
"--selected.foreground 8 "
f"'{q}'",
returncode=True,
)
# TODO: make gum (and git?) a class an obsufcate the commands
def color(text, color):
return run(f"gum style --foreground {color} '{text}'")
def nl_to_ol(text):
return " ".join([f"'{f}'" for f in text.splitlines()])
def check_status():
files = nl_to_ol(run("git ls-files -dmo"))
if not files:
print(color("nothing to stage", "red"))
sys.exit(1)
else:
return files
def stage_files(files):
to_add = run(f"gum choose --no-limit {files} ")
run(f"git add {to_add}")
def get_staged_info():
staged = run("git diff --cached --stat")
fstaged = []
if not staged:
files = check_status()
print(color("nothing staged..", 9))
if files and confirm("Would you like to stage files?") == 0:
stage_files(files)
return get_staged_info()
else:
print("exiting...")
sys.exit(0)
for text in staged.splitlines()[-1].split(","):
if "changed" in text:
fstaged.append(color(text.strip(), 11))
elif "insertion" in text:
fstaged.append(color(text.strip(), 10))
elif "deletion" in text:
fstaged.append(color(text.strip(), 9))
else:
print(f"Unexpected output from git diff: {text}")
return "\n\t".join(fstaged)
def main():
is_tool("gum")
is_tool("git")
is_repo()
run(
"gum style "
"--foreground 212 --border-foreground 212 --border rounded "
'--align center --width 30 --margin "1 4" '
f"'{color('ConCom',11)}'",
capture=False,
)
print(f" staged: \n\t{get_staged_info()}\n")
commit_type = run(
"gum choose fix feat docs style refactor test chore revert custom"
)
if not commit_type:
print("exiting...")
sys.exit(1)
elif commit_type == "custom":
commit_type = run('gum input --placeholder "type"')
scope = run('gum input --placeholder "scope"')
scope = f"({scope})" if scope else ""
summary = run(
f'gum input --value "{commit_type}{scope}: " --placeholder "Summary of this change"'
)
print(f"{color('message:',11)}\n {summary}")
actions = {
"commit": lambda: run(f"git commit -m '{summary}'", capture=False),
"commit(with message)": lambda: run(
f"git commit -m '{summary}' -m '# note: abort with :cq!' -e", capture=False
),
"quit": lambda: (print("exiting..."), sys.exit()),
}
print("\nHow to proceed?\n")
choices = " ".join([f"'{choice}'" for choice in actions])
choice = str(run(f"gum choose {choices}"))
actions[choice]()
if __name__ == "__main__":
main()