Further progress towards something usable
This commit is contained in:
parent
2440da2644
commit
9983666f77
164
tyop.py
164
tyop.py
|
@ -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!")
|
||||
|
|
Reference in New Issue