Further progress towards something usable

This commit is contained in:
decentral1se 2021-07-10 14:21:34 +02:00
parent 2440da2644
commit 9983666f77
No known key found for this signature in database
GPG Key ID: 5E2EF5A63E3718CC
1 changed files with 96 additions and 68 deletions

164
tyop.py
View File

@ -18,45 +18,47 @@ class Migration:
def __init__(self):
self.args = self._parse()
self.yaml = self._init_yaml()
self.log = self._init_logging()
self.commit_msg = None
self._validate()
self.yaml = YAML(typ="rt")
self.yaml.preserve_quotes = True
self.yaml.indent(mapping=2, sequence=4, offset=2)
self.yaml.explicit_start = True
self.yaml.allow_duplicate_keys = True
if self.args.validate:
self.log.info("Bailing out as requested...")
exit(0)
self._exit(code=0)
self.matches = glob(expanduser(self.GLOB))
self.paths = list(set([Path(p).parent for p in self.matches]))
self.log.info(f"Discovered '{self.GLOB}' as user defined glob")
self.log.info(f"Matched paths are: {[m for m in self.matches]}")
if not self._confirm():
self.log.info("Bailing out on request...")
exit(1)
self._confirm()
if self.args.reset:
self.log.info("Resetting all changes as requested...")
for match in self.matches:
self._clean(match)
exit(0)
self._clean()
self._exit(code=0)
try:
self._run()
except Exception as exception:
self.log.error(f"Failed to run migration, saw: {exception}")
self.log.info("Resetting all changes...")
for match in self.matches:
self._clean(match)
exit(1)
self._exit(msg=f"Failed to run migration, saw: {exception}")
def _init_yaml(self):
yaml = YAML(typ="rt")
yaml.preserve_quotes = True
yaml.indent(mapping=2, sequence=4, offset=2)
yaml.allow_duplicate_keys = True
return yaml
def _exit(self, msg="Bailing out on request...", code=1):
self.log.info(msg)
exit(code)
def _parse(self):
self.parser = ArgumentParser(description="Tyop: mass typo updates for all")
description = "Tyop: automate your mass typo updates"
parser = ArgumentParser(description=description)
self.parser.add_argument(
parser.add_argument(
"-d",
"--debug",
help="enable verbose debug logs",
@ -65,7 +67,7 @@ class Migration:
const=DEBUG,
default=INFO,
)
self.parser.add_argument(
parser.add_argument(
"-v",
"--validate",
default=False,
@ -73,7 +75,7 @@ class Migration:
dest="validate",
help="Validate end-user defined migrationa and exit",
)
self.parser.add_argument(
parser.add_argument(
"-r",
"--reset",
default=False,
@ -81,7 +83,7 @@ class Migration:
dest="reset",
help="Reset changes without running migrations (git-checkout)",
)
self.parser.add_argument(
parser.add_argument(
"-y",
"--yaml",
default=False,
@ -90,14 +92,11 @@ class Migration:
help="Expect YAML and load for parsing",
)
self.args = self.parser.parse_args()
return self.args
return parser.parse_args()
def _init_logging(self):
basicConfig(level=self.args.log, format="%(levelname)-8s %(message)s")
self.log = getLogger(__name__)
return self.log
return getLogger(__name__)
def _shell(self, cmd, shell=False, check=True, **kwargs):
runner = check_output
@ -115,71 +114,100 @@ class Migration:
if check:
return output.decode("utf-8").strip()
except Exception as exception:
self.log.error(f"Failed to run {cmd}, saw {str(exception)}")
exit(1)
self._exit(msg=f"Failed to run {cmd}, saw {str(exception)}")
def _confirm(self):
def _confirm(self, bail=True):
answer = ""
while answer not in ["y", "Y", "n", "N"]:
answer = input("Does this look good? [y/N]? ").lower()
return any((answer == y for y in ["y", "Y"]))
result = answer == "y" or answer == "Y"
if not result and bail:
self._exit()
return result
def _message(self):
return input("Commit message?")
return input("Commit message? ")
def _commit(self, match):
root_path = Path(match).parent
self._shell("git --no-pager diff", check=False, cwd=root_path)
if self._confirm():
message = self._message()
if self._confirm(bail=False):
if not self.commit_msg:
self.commit_msg = self._message()
self._shell("git add .", check=False, cwd=root_path)
self._shell(f"git commit -vm '{message}'", check=False, cwd=root_path)
self._shell(
f"git commit -vm '{self.commit_msg}'", check=False, cwd=root_path
)
self._shell("git push", check=False, cwd=root_path)
def _validate(self):
if not hasattr(self, "GLOB"):
self.log.error("Missing GLOB attribute!")
exit(1)
self._exit(msg="Missing GLOB attribute!")
self.log.info("Validation succeeded!")
def _diff(self, match, idx):
def _diff(self, match, idx, check=True):
command = "git --no-pager diff"
root_path = Path(match).parent
self.log.debug(f"Running git-diff in {root_path} ({idx+1}/{self.DIFF_LIMIT})")
self._shell("git --no-pager diff", check=False, cwd=root_path)
if not self._confirm():
self._clean(match)
self.log.info("Bailing out on request...")
exit(1)
def _clean(self, match, branch=False):
root_path = Path(match).parent
self.log.info(f"Cleaning {root_path} of local changes...")
if check:
output = self._shell(command, cwd=root_path)
if not output:
self.log.info("No changes detected, moving on...")
return
self._shell("git checkout .", check=False, cwd=root_path)
self.log.info(f"Diffing {root_path} ({idx+1}/{self.DIFF_LIMIT})")
self._shell(command, check=False, cwd=root_path)
if branch:
self.log.info("Checkout out the default branch...")
self._shell(
"git checkout main > /dev/null 2>&1 || git checkout master > /dev/null 2>&1", # noqa
check=False,
shell=True,
cwd=root_path,
)
self._confirm()
def _clean(self, match=None, branch=False):
if match:
_paths = [Path(match).parent]
else:
_paths = self.paths
for _path in _paths:
self.log.info(f"Cleaning {_path} of local changes...")
self._shell("git checkout .", check=False, cwd=_path)
if branch:
self.log.info("Checking out the default branch...")
self._shell(
(
"git checkout main > /dev/null 2>&1 "
"|| git checkout master > /dev/null 2>&1"
),
check=False,
shell=True,
cwd=_path,
)
def _run(self):
idx = 0
for match in self.matches:
self._clean(match, branch=True)
self.log.info(f"Processing {match}...")
for match in self.matches:
self._clean(match=match, branch=True)
with open(match, "r") as handle:
self.log.info(f"Processing {match}...")
contents = handle.read()
if self.args.yaml:
self.log.debug("Attempting to load YAML...")
if "---" in contents:
self.yaml.explicit_start = True
else:
self.yaml.explicit_start = False
contents = self.yaml.load(contents)
original = contents.copy()
migrated = self.migrate(contents)
self.log.debug(f"Migrated {match}...")
@ -190,17 +218,17 @@ class Migration:
else:
handle.write(migrated)
self.log.debug(f"Saved {match} back to the file system...")
if idx < self.DIFF_LIMIT and contents != migrated:
self._diff(match, idx=idx)
if idx < self.DIFF_LIMIT:
self._diff(match, idx=idx, check=True)
idx += 1
self.log.debug(f"Saved {match} back to the file system...")
self.log.info("Finished migrating files...")
self.log.info("Commencing change commit run...")
for match in self.matches:
self._commit(match)
for path in self.paths:
self._commit(path)
self.log.info("Finished committing changes...")
self.log.info("Finished! May your tyops be ever glorious!")