diff --git a/docs/make_md_docs.py b/docs/make_md_docs.py index 56a2072c..7fbab107 100644 --- a/docs/make_md_docs.py +++ b/docs/make_md_docs.py @@ -6,9 +6,9 @@ from mdutils.mdutils import MdUtils import subprocess as sp -preamble=''' +preamble = """ mepo provides many different commands for working with a multi-repository fixture. -''' +""" # Assume this script is in mepo/doc. Then we need to get to the mepo/mepo.d/command directory doc_dir_path = os.path.dirname(os.path.realpath(__file__)) @@ -21,11 +21,12 @@ mepo_command_path = os.path.join(main_dir_path, "bin", "mepo") + def get_command_list(directory): # Get all commands all_commands_py = glob.glob(os.path.join(directory, "*.py")) all_commands = [os.path.basename(x).replace(".py", "") for x in all_commands_py] - all_commands.remove("command") # manually remove + all_commands.remove("command") # manually remove # Now let's find the commands that have subcommands ## First we get commands with underscore @@ -37,13 +38,16 @@ def get_command_list(directory): return sorted(all_useful_commands) + def create_markdown_from_usage(command, mdFile): cmd = [mepo_command_path, command, "--help"] # Some commands have spaces, so we need to break it up again cmd = " ".join(cmd).split() - result = sp.run(cmd, capture_output=True, universal_newlines=True, env={"COLUMNS": "256"}) + result = sp.run( + cmd, capture_output=True, universal_newlines=True, env={"COLUMNS": "256"} + ) output = result.stdout output_list = output.split("\n") @@ -58,18 +62,25 @@ def create_markdown_from_usage(command, mdFile): mdFile.new_header(level=3, title="Usage") mdFile.insert_code(usage) - positional_arguments = output.partition("positional arguments:\n")[2].partition("\n\n")[0] + positional_arguments = output.partition("positional arguments:\n")[2].partition( + "\n\n" + )[0] if positional_arguments: mdFile.new_header(level=3, title="Positional Arguments") mdFile.insert_code(positional_arguments) - optional_arguments = output.partition("optional arguments:\n")[2].partition("\n\n")[0] + optional_arguments = output.partition("optional arguments:\n")[2].partition("\n\n")[ + 0 + ] # Remove extra blank lines - optional_arguments = os.linesep.join([s for s in optional_arguments.splitlines() if s]) + optional_arguments = os.linesep.join( + [s for s in optional_arguments.splitlines() if s] + ) if optional_arguments: mdFile.new_header(level=3, title="Optional Arguments") mdFile.insert_code(optional_arguments) + if __name__ == "__main__": doc_file = "Mepo-Commands.md" @@ -83,7 +94,7 @@ def create_markdown_from_usage(command, mdFile): for command in command_list: mdFile.new_header(level=2, title=command) print(f"mepo command: {command}") - create_markdown_from_usage(command,mdFile) + create_markdown_from_usage(command, mdFile) mdFile.new_table_of_contents(table_title="Table of Contents", depth=2) mdFile.create_md_file() diff --git a/src/mepo/cmdline/branch_parser.py b/src/mepo/cmdline/branch_parser.py index 386c473f..db0cad5d 100644 --- a/src/mepo/cmdline/branch_parser.py +++ b/src/mepo/cmdline/branch_parser.py @@ -1,11 +1,12 @@ import argparse + class MepoBranchArgParser(object): def __init__(self, branch): self.branch_subparsers = branch.add_subparsers() - self.branch_subparsers.title = 'mepo branch sub-commands' - self.branch_subparsers.dest = 'mepo_branch_cmd' + self.branch_subparsers.title = "mepo branch sub-commands" + self.branch_subparsers.dest = "mepo_branch_cmd" self.branch_subparsers.required = True self.__list() self.__create() @@ -13,50 +14,47 @@ def __init__(self, branch): def __list(self): brlist = self.branch_subparsers.add_parser( - 'list', - description = 'List local branches. If no component is specified, runs over all components') + "list", + description="List local branches. If no component is specified, runs over all components", + ) brlist.add_argument( - '-a', '--all', - action = 'store_true', - help = 'list all (local+remote) branches') + "-a", "--all", action="store_true", help="list all (local+remote) branches" + ) brlist.add_argument( - '--nocolor', - action = 'store_true', - help = 'do not display color') + "--nocolor", action="store_true", help="do not display color" + ) brlist.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '*', - help = 'component to list branches in') + "comp_name", + metavar="comp-name", + nargs="*", + help="component to list branches in", + ) def __create(self): create = self.branch_subparsers.add_parser( - 'create', - description = 'Create branch in component ') - create.add_argument( - 'branch_name', - metavar = 'branch-name', - help = "name of branch") + "create", description="Create branch in component " + ) + create.add_argument("branch_name", metavar="branch-name", help="name of branch") create.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '+', - help = 'component to create branches in') + "comp_name", + metavar="comp-name", + nargs="+", + help="component to create branches in", + ) def __delete(self): delete = self.branch_subparsers.add_parser( - 'delete', - description = 'Delete branch in component ') - delete.add_argument( - 'branch_name', - metavar = 'branch-name', - help = "name of branch") + "delete", description="Delete branch in component " + ) + delete.add_argument("branch_name", metavar="branch-name", help="name of branch") delete.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '+', - help = 'component to delete branches in') + "comp_name", + metavar="comp-name", + nargs="+", + help="component to delete branches in", + ) delete.add_argument( - '--force', - action = 'store_true', - help = 'delete branch even if it has not been fully merged') + "--force", + action="store_true", + help="delete branch even if it has not been fully merged", + ) diff --git a/src/mepo/cmdline/config_parser.py b/src/mepo/cmdline/config_parser.py index 46cd1c89..6516076e 100644 --- a/src/mepo/cmdline/config_parser.py +++ b/src/mepo/cmdline/config_parser.py @@ -1,12 +1,13 @@ import argparse import textwrap + class MepoConfigArgParser(object): def __init__(self, config): self.config = config.add_subparsers() - self.config.title = 'mepo config sub-commands' - self.config.dest = 'mepo_config_cmd' + self.config.title = "mepo config sub-commands" + self.config.dest = "mepo_config_cmd" self.config.required = True self.__get() self.__set() @@ -15,42 +16,39 @@ def __init__(self, config): def __get(self): get = self.config.add_parser( - 'get', - description = ('Get config `entry` in `.mepoconfig`. ' - 'Note this uses gitconfig style where `entry` is of the form `section.option`. ' - 'So to get an `alias` `st` You would run `mepo config get alias.st`')) - get.add_argument( - 'entry', - metavar = 'entry', - help = 'Entry to display.') + "get", + description=( + "Get config `entry` in `.mepoconfig`. " + "Note this uses gitconfig style where `entry` is of the form `section.option`. " + "So to get an `alias` `st` You would run `mepo config get alias.st`" + ), + ) + get.add_argument("entry", metavar="entry", help="Entry to display.") def __set(self): set = self.config.add_parser( - 'set', - description = ('Set config `entry` to `value` in `.mepoconfig`. ' - 'Note this uses gitconfig style where `entry` is of the form `section.option`. ' - 'So to set an `alias` for `status` of `st` You would run `mepo config set alias.st status`')) - set.add_argument( - 'entry', - metavar = 'entry', - help = 'Entry to set.') - set.add_argument( - 'value', - metavar = 'value', - help = 'Value to set entry to.') + "set", + description=( + "Set config `entry` to `value` in `.mepoconfig`. " + "Note this uses gitconfig style where `entry` is of the form `section.option`. " + "So to set an `alias` for `status` of `st` You would run `mepo config set alias.st status`" + ), + ) + set.add_argument("entry", metavar="entry", help="Entry to set.") + set.add_argument("value", metavar="value", help="Value to set entry to.") def __delete(self): delete = self.config.add_parser( - 'delete', - description = ('Delete config `entry` in `.mepoconfig`. ' - 'Note this uses gitconfig style where `entry` is of the form `section.option`. ' - 'So to delete an `alias` `st` You would run `mepo config delete alias.st`')) - delete.add_argument( - 'entry', - metavar = 'entry', - help = 'Entry to delete.') + "delete", + description=( + "Delete config `entry` in `.mepoconfig`. " + "Note this uses gitconfig style where `entry` is of the form `section.option`. " + "So to delete an `alias` `st` You would run `mepo config delete alias.st`" + ), + ) + delete.add_argument("entry", metavar="entry", help="Entry to delete.") def __print(self): print = self.config.add_parser( - 'print', - description = 'Print contents of `.mepoconfig`') + "print", description="Print contents of `.mepoconfig`" + ) diff --git a/src/mepo/cmdline/parser.py b/src/mepo/cmdline/parser.py index 7b487e38..c9c88527 100644 --- a/src/mepo/cmdline/parser.py +++ b/src/mepo/cmdline/parser.py @@ -7,17 +7,19 @@ from ..utilities import mepoconfig + class MepoArgParser(object): - __slots__ = ['parser', 'subparsers'] + __slots__ = ["parser", "subparsers"] def __init__(self): self.parser = argparse.ArgumentParser( - description = 'Tool to manage (m)ultiple r(epo)s') + description="Tool to manage (m)ultiple r(epo)s" + ) self.subparsers = self.parser.add_subparsers() - self.subparsers.title = 'mepo commands' + self.subparsers.title = "mepo commands" self.subparsers.required = True - self.subparsers.dest = 'mepo_cmd' + self.subparsers.dest = "mepo_cmd" def parse(self): self.__init() @@ -50,430 +52,447 @@ def parse(self): def __init(self): init = self.subparsers.add_parser( - 'init', - description = 'Initialize mepo based on `config-file`', - aliases=mepoconfig.get_command_alias('init')) + "init", + description="Initialize mepo based on `config-file`", + aliases=mepoconfig.get_command_alias("init"), + ) init.add_argument( - '--config', - metavar = 'config-file', - nargs = '?', - default = 'components.yaml', - help = 'default: %(default)s') + "--config", + metavar="config-file", + nargs="?", + default="components.yaml", + help="default: %(default)s", + ) init.add_argument( - '--style', - metavar = 'style-type', - nargs = '?', - default = None, - choices = ['naked', 'prefix','postfix'], - help = 'Style of directory file, default: prefix, allowed options: %(choices)s') + "--style", + metavar="style-type", + nargs="?", + default=None, + choices=["naked", "prefix", "postfix"], + help="Style of directory file, default: prefix, allowed options: %(choices)s", + ) def __clone(self): clone = self.subparsers.add_parser( - 'clone', - description = "Clone repositories.", - aliases=mepoconfig.get_command_alias('clone')) + "clone", + description="Clone repositories.", + aliases=mepoconfig.get_command_alias("clone"), + ) clone.add_argument( - 'repo_url', - metavar = 'URL', - nargs = '?', - default = None, - help = 'URL to clone') + "repo_url", metavar="URL", nargs="?", default=None, help="URL to clone" + ) clone.add_argument( - 'directory', - nargs = '?', - default = None, - help = "Directory to clone into (Only allowed with URL!)") + "directory", + nargs="?", + default=None, + help="Directory to clone into (Only allowed with URL!)", + ) clone.add_argument( - '--branch','-b', - metavar = 'name', - nargs = '?', - default = None, - help = 'Branch/tag of URL to initially clone (Only allowed with URL!)') + "--branch", + "-b", + metavar="name", + nargs="?", + default=None, + help="Branch/tag of URL to initially clone (Only allowed with URL!)", + ) clone.add_argument( - '--registry', - metavar = 'registry', - nargs = '?', - default = None, - help = 'Registry (default: components.yaml)') + "--registry", + metavar="registry", + nargs="?", + default=None, + help="Registry (default: components.yaml)", + ) clone.add_argument( - '--style', - metavar = 'style-type', - nargs = '?', - default = None, - choices = ['naked', 'prefix','postfix'], - help = 'Style of directory file, default: prefix, allowed options: %(choices)s (ignored if init already called)') + "--style", + metavar="style-type", + nargs="?", + default=None, + choices=["naked", "prefix", "postfix"], + help="Style of directory file, default: prefix, allowed options: %(choices)s (ignored if init already called)", + ) clone.add_argument( - '--allrepos', - action = 'store_true', - help = 'Must be passed with -b/--branch. When set, it not only checkouts out the branch/tag for the fixture, but for all the subrepositories as well.') + "--allrepos", + action="store_true", + help="Must be passed with -b/--branch. When set, it not only checkouts out the branch/tag for the fixture, but for all the subrepositories as well.", + ) clone.add_argument( - '--partial', - metavar = 'partial-type', - nargs = '?', - default = None, - choices = ['off','blobless','treeless'], - help = 'Style of partial clone, default: None, allowed options: %(choices)s. Off means a "normal" full git clone, blobless means cloning with "--filter=blob:none" and treeless means cloning with "--filter=tree:0". NOTE: We do *not* recommend using "treeless" as it is very aggressive and will cause problems with many git commands.') + "--partial", + metavar="partial-type", + nargs="?", + default=None, + choices=["off", "blobless", "treeless"], + help='Style of partial clone, default: None, allowed options: %(choices)s. Off means a "normal" full git clone, blobless means cloning with "--filter=blob:none" and treeless means cloning with "--filter=tree:0". NOTE: We do *not* recommend using "treeless" as it is very aggressive and will cause problems with many git commands.', + ) def __list(self): listcomps = self.subparsers.add_parser( - 'list', - description = 'List all components that are being tracked', - aliases=mepoconfig.get_command_alias('list')) + "list", + description="List all components that are being tracked", + aliases=mepoconfig.get_command_alias("list"), + ) listcomps.add_argument( - '-1', '--one-per-line', - action = 'store_true', - help = 'one component per line') + "-1", "--one-per-line", action="store_true", help="one component per line" + ) def __status(self): status = self.subparsers.add_parser( - 'status', - description = 'Check current status of all components', - aliases=mepoconfig.get_command_alias('status')) + "status", + description="Check current status of all components", + aliases=mepoconfig.get_command_alias("status"), + ) status.add_argument( - '--ignore-permissions', - action = 'store_true', - help = 'Tells command to ignore changes in file permissions.') + "--ignore-permissions", + action="store_true", + help="Tells command to ignore changes in file permissions.", + ) status.add_argument( - '--nocolor', - action = 'store_true', - help = 'Tells status to not display colors.') + "--nocolor", action="store_true", help="Tells status to not display colors." + ) status.add_argument( - '--hashes', - action = 'store_true', - help = 'Print the exact hash of the HEAD.') + "--hashes", action="store_true", help="Print the exact hash of the HEAD." + ) def __restore_state(self): restore_state = self.subparsers.add_parser( - 'restore-state', - description = 'Restores all components to the last saved state.', - aliases=mepoconfig.get_command_alias('restore-state')) + "restore-state", + description="Restores all components to the last saved state.", + aliases=mepoconfig.get_command_alias("restore-state"), + ) def __diff(self): diff = self.subparsers.add_parser( - 'diff', - description = 'Diff all components', - aliases=mepoconfig.get_command_alias('diff')) + "diff", + description="Diff all components", + aliases=mepoconfig.get_command_alias("diff"), + ) diff.add_argument( - '--name-only', - action = 'store_true', - help = 'Show only names of changed files') + "--name-only", action="store_true", help="Show only names of changed files" + ) diff.add_argument( - '--name-status', - action = 'store_true', - help = 'Show name-status of changed files') + "--name-status", + action="store_true", + help="Show name-status of changed files", + ) diff.add_argument( - '--ignore-permissions', - action = 'store_true', - help = 'Tells command to ignore changes in file permissions.') + "--ignore-permissions", + action="store_true", + help="Tells command to ignore changes in file permissions.", + ) diff.add_argument( - '--staged', - action = 'store_true', - help = 'Show diff of staged changes') + "--staged", action="store_true", help="Show diff of staged changes" + ) diff.add_argument( - '-b','--ignore-space-change', - action = 'store_true', - help = 'Ignore changes in amount of whitespace') + "-b", + "--ignore-space-change", + action="store_true", + help="Ignore changes in amount of whitespace", + ) diff.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '*', - help = 'Component to list branches in') + "comp_name", + metavar="comp-name", + nargs="*", + help="Component to list branches in", + ) def __checkout(self): checkout = self.subparsers.add_parser( - 'checkout', - description = "Switch to branch/tag `branch-name` in component `comp-name`. " + "checkout", + description="Switch to branch/tag `branch-name` in component `comp-name`. " "If no components listed, checkout from all. " "Specifying `-b` causes the branch `branch-name` to be created and checked out.", - aliases=mepoconfig.get_command_alias('checkout')) + aliases=mepoconfig.get_command_alias("checkout"), + ) checkout.add_argument( - 'branch_name', - metavar = 'branch-name', - help = "Name of branch") + "branch_name", metavar="branch-name", help="Name of branch" + ) checkout.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '*', - help = 'Components to checkout branch in') + "comp_name", + metavar="comp-name", + nargs="*", + help="Components to checkout branch in", + ) + checkout.add_argument("-b", action="store_true", help="create the branch") checkout.add_argument( - '-b', - action = 'store_true', - help = 'create the branch') + "-q", "--quiet", action="store_true", help="Suppress prints" + ) checkout.add_argument( - '-q', '--quiet', - action = 'store_true', - help = 'Suppress prints') - checkout.add_argument( - '--detach', - action = 'store_true', - help = 'Detach upon checkout') + "--detach", action="store_true", help="Detach upon checkout" + ) def __checkout_if_exists(self): checkout_if_exists = self.subparsers.add_parser( - 'checkout-if-exists', - description = 'Switch to branch or tag `ref-name` in any component where it is present. ', - aliases=mepoconfig.get_command_alias('checkout-if-exists')) + "checkout-if-exists", + description="Switch to branch or tag `ref-name` in any component where it is present. ", + aliases=mepoconfig.get_command_alias("checkout-if-exists"), + ) checkout_if_exists.add_argument( - 'ref_name', - metavar = 'ref-name', - help = "Name of branch or tag") + "ref_name", metavar="ref-name", help="Name of branch or tag" + ) checkout_if_exists.add_argument( - '-q', '--quiet', - action = 'store_true', - help = 'Suppress prints') + "-q", "--quiet", action="store_true", help="Suppress prints" + ) checkout_if_exists.add_argument( - '--detach', - action = 'store_true', - help = 'Detach on checkout') + "--detach", action="store_true", help="Detach on checkout" + ) checkout_if_exists.add_argument( - '-n','--dry-run', - action = 'store_true', - help = 'Dry-run only (lists repos where branch exists)') + "-n", + "--dry-run", + action="store_true", + help="Dry-run only (lists repos where branch exists)", + ) def __changed_files(self): changed_files = self.subparsers.add_parser( - 'changed-files', - description = 'List files that have changes versus the state. By default runs against all components.', - aliases=mepoconfig.get_command_alias('changed-files')) + "changed-files", + description="List files that have changes versus the state. By default runs against all components.", + aliases=mepoconfig.get_command_alias("changed-files"), + ) changed_files.add_argument( - '--full-path', - action = 'store_true', - help = 'Print with full path') + "--full-path", action="store_true", help="Print with full path" + ) changed_files.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '*', - help = 'Component to list branches in') + "comp_name", + metavar="comp-name", + nargs="*", + help="Component to list branches in", + ) def __fetch(self): fetch = self.subparsers.add_parser( - 'fetch', - description = 'Download objects and refs from in component `comp-name`. ' - 'If no components listed, fetches from all', - aliases=mepoconfig.get_command_alias('fetch')) - fetch.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '*', - help = "Components to fetch in") + "fetch", + description="Download objects and refs from in component `comp-name`. " + "If no components listed, fetches from all", + aliases=mepoconfig.get_command_alias("fetch"), + ) fetch.add_argument( - '--all', - action = 'store_true', - help = 'Fetch all remotes.') + "comp_name", metavar="comp-name", nargs="*", help="Components to fetch in" + ) + fetch.add_argument("--all", action="store_true", help="Fetch all remotes.") fetch.add_argument( - '-p','--prune', - action = 'store_true', - help = 'Prune remote branches.') - fetch.add_argument( - '-t','--tags', - action = 'store_true', - help = 'Fetch tags.') - fetch.add_argument( - '-f','--force', - action = 'store_true', - help = 'Force action.') + "-p", "--prune", action="store_true", help="Prune remote branches." + ) + fetch.add_argument("-t", "--tags", action="store_true", help="Fetch tags.") + fetch.add_argument("-f", "--force", action="store_true", help="Force action.") def __branch(self): branch = self.subparsers.add_parser( - 'branch', - description = "Runs branch commands.", - aliases=mepoconfig.get_command_alias('branch')) + "branch", + description="Runs branch commands.", + aliases=mepoconfig.get_command_alias("branch"), + ) MepoBranchArgParser(branch) def __stash(self): stash = self.subparsers.add_parser( - 'stash', - description = "Runs stash commands.", - aliases=mepoconfig.get_command_alias('stash')) + "stash", + description="Runs stash commands.", + aliases=mepoconfig.get_command_alias("stash"), + ) MepoStashArgParser(stash) def __tag(self): tag = self.subparsers.add_parser( - 'tag', - description = "Runs tag commands.", - aliases=mepoconfig.get_command_alias('tag')) + "tag", + description="Runs tag commands.", + aliases=mepoconfig.get_command_alias("tag"), + ) MepoTagArgParser(tag) def __develop(self): develop = self.subparsers.add_parser( - 'develop', - description = "Checkout current version of 'develop' branches of specified components", - aliases=mepoconfig.get_command_alias('develop')) + "develop", + description="Checkout current version of 'develop' branches of specified components", + aliases=mepoconfig.get_command_alias("develop"), + ) develop.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '+', - default = None, - help = "Component(s) to checkout development branches") + "comp_name", + metavar="comp-name", + nargs="+", + default=None, + help="Component(s) to checkout development branches", + ) develop.add_argument( - '-q','--quiet', - action = 'store_true', - help = 'Suppress prints') + "-q", "--quiet", action="store_true", help="Suppress prints" + ) def __pull(self): pull = self.subparsers.add_parser( - 'pull', - description = "Pull branches of specified components", - aliases=mepoconfig.get_command_alias('pull')) - pull.add_argument('comp_name', - metavar = 'comp-name', - nargs = '+', - default = None, - help = "Components to pull in") + "pull", + description="Pull branches of specified components", + aliases=mepoconfig.get_command_alias("pull"), + ) pull.add_argument( - '-q','--quiet', - action = 'store_true', - help = 'Suppress prints') + "comp_name", + metavar="comp-name", + nargs="+", + default=None, + help="Components to pull in", + ) + pull.add_argument("-q", "--quiet", action="store_true", help="Suppress prints") def __pull_all(self): pull_all = self.subparsers.add_parser( - 'pull-all', - description = "Pull branches of all components (only those in non-detached HEAD state)", - aliases=mepoconfig.get_command_alias('pull-all')) + "pull-all", + description="Pull branches of all components (only those in non-detached HEAD state)", + aliases=mepoconfig.get_command_alias("pull-all"), + ) pull_all.add_argument( - '-q','--quiet', - action = 'store_true', - help = 'Suppress prints') + "-q", "--quiet", action="store_true", help="Suppress prints" + ) def __compare(self): compare = self.subparsers.add_parser( - 'compare', - description = 'Compare current and original states of all components. ' - 'Will only show differing repos unless --all is passed in', - aliases=mepoconfig.get_command_alias('compare')) + "compare", + description="Compare current and original states of all components. " + "Will only show differing repos unless --all is passed in", + aliases=mepoconfig.get_command_alias("compare"), + ) compare.add_argument( - '--all', - action = 'store_true', - help = 'Show all repos, not only differing repos') + "--all", + action="store_true", + help="Show all repos, not only differing repos", + ) compare.add_argument( - '--nocolor', - action = 'store_true', - help = 'Tells command to not display colors.') + "--nocolor", + action="store_true", + help="Tells command to not display colors.", + ) compare.add_argument( - '--wrap', - action = 'store_true', - help = 'Tells command to ignore terminal size and wrap') + "--wrap", + action="store_true", + help="Tells command to ignore terminal size and wrap", + ) def __reset(self): reset = self.subparsers.add_parser( - 'reset', - description = 'Reset the current mepo clone to the original state. ' - 'This will delete all subrepos and does not check for uncommitted changes! ' - 'Must be run in the root of the mepo clone.', - aliases=mepoconfig.get_command_alias('reset')) + "reset", + description="Reset the current mepo clone to the original state. " + "This will delete all subrepos and does not check for uncommitted changes! " + "Must be run in the root of the mepo clone.", + aliases=mepoconfig.get_command_alias("reset"), + ) + reset.add_argument("-f", "--force", action="store_true", help="Force action.") reset.add_argument( - '-f','--force', - action = 'store_true', - help = 'Force action.') - reset.add_argument( - '--reclone', - action = 'store_true', - help = 'Reclone repos after reset.') - reset.add_argument( - '-n','--dry-run', - action = 'store_true', - help = 'Dry-run only') + "--reclone", action="store_true", help="Reclone repos after reset." + ) + reset.add_argument("-n", "--dry-run", action="store_true", help="Dry-run only") def __whereis(self): whereis = self.subparsers.add_parser( - 'whereis', - description = 'Get the location of component `comp-name` ' - 'relative to my current location. If `comp-name` is not present, ' - 'get the relative locations of ALL components.', - aliases=mepoconfig.get_command_alias('whereis')) + "whereis", + description="Get the location of component `comp-name` " + "relative to my current location. If `comp-name` is not present, " + "get the relative locations of ALL components.", + aliases=mepoconfig.get_command_alias("whereis"), + ) whereis.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '?', - default = None, - help = "Component to get location of") + "comp_name", + metavar="comp-name", + nargs="?", + default=None, + help="Component to get location of", + ) whereis.add_argument( - '-i','--ignore-case', - action = 'store_true', - help = 'Ignore case for whereis') + "-i", "--ignore-case", action="store_true", help="Ignore case for whereis" + ) def __stage(self): stage = self.subparsers.add_parser( - 'stage', - description = 'Stage modified & untracked files in the specified component(s)', - aliases=mepoconfig.get_command_alias('stage')) + "stage", + description="Stage modified & untracked files in the specified component(s)", + aliases=mepoconfig.get_command_alias("stage"), + ) stage.add_argument( - '--untracked', - action = 'store_true', - help = 'Stage untracked files as well') + "--untracked", action="store_true", help="Stage untracked files as well" + ) stage.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '+', - help = 'Component to stage file in') + "comp_name", + metavar="comp-name", + nargs="+", + help="Component to stage file in", + ) def __unstage(self): unstage = self.subparsers.add_parser( - 'unstage', - description = 'Un-stage staged files. ' - 'If a component is specified, files are un-staged only for that component.', - aliases=mepoconfig.get_command_alias('unstage')) + "unstage", + description="Un-stage staged files. " + "If a component is specified, files are un-staged only for that component.", + aliases=mepoconfig.get_command_alias("unstage"), + ) unstage.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '*', - help = 'Component to unstage in', - default = None) + "comp_name", + metavar="comp-name", + nargs="*", + help="Component to unstage in", + default=None, + ) def __commit(self): commit = self.subparsers.add_parser( - 'commit', - description = 'Commit staged files in the specified components', - aliases=mepoconfig.get_command_alias('commit')) + "commit", + description="Commit staged files in the specified components", + aliases=mepoconfig.get_command_alias("commit"), + ) commit.add_argument( - '-a', '--all', - action = 'store_true', - help = 'Stage all tracked files and then commit') + "-a", + "--all", + action="store_true", + help="Stage all tracked files and then commit", + ) commit.add_argument( - '-m', '--message', + "-m", + "--message", type=str, - metavar = 'message', + metavar="message", default=None, - help = "Message to commit with") + help="Message to commit with", + ) commit.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '+', - help = 'Component to commit file in') + "comp_name", + metavar="comp-name", + nargs="+", + help="Component to commit file in", + ) def __push(self): push = self.subparsers.add_parser( - 'push', - description = 'Push local commits to remote for specified component. ' - 'Use mepo tag push to push tags', - aliases=mepoconfig.get_command_alias('push')) + "push", + description="Push local commits to remote for specified component. " + "Use mepo tag push to push tags", + aliases=mepoconfig.get_command_alias("push"), + ) push.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '+', - help = 'Component to push to remote') + "comp_name", + metavar="comp-name", + nargs="+", + help="Component to push to remote", + ) def __save(self): save = self.subparsers.add_parser( - 'save', - description = 'Save current state in a yaml registry', - aliases=mepoconfig.get_command_alias('save')) + "save", + description="Save current state in a yaml registry", + aliases=mepoconfig.get_command_alias("save"), + ) save.add_argument( - 'registry', - metavar = 'registry', - nargs = '?', - default = 'components-new.yaml', - help = 'default: %(default)s') + "registry", + metavar="registry", + nargs="?", + default="components-new.yaml", + help="default: %(default)s", + ) def __config(self): config = self.subparsers.add_parser( - 'config', - description = "Runs config commands.", - aliases=mepoconfig.get_command_alias('config')) + "config", + description="Runs config commands.", + aliases=mepoconfig.get_command_alias("config"), + ) MepoConfigArgParser(config) def __update_state(self): update_state = self.subparsers.add_parser( - 'update-state', - description = 'Permanently update mepo1 state to current', - aliases=mepoconfig.get_command_alias('update-state')) + "update-state", + description="Permanently update mepo1 state to current", + aliases=mepoconfig.get_command_alias("update-state"), + ) diff --git a/src/mepo/cmdline/stash_parser.py b/src/mepo/cmdline/stash_parser.py index 0d349204..af0bb4a2 100644 --- a/src/mepo/cmdline/stash_parser.py +++ b/src/mepo/cmdline/stash_parser.py @@ -1,69 +1,75 @@ import argparse + class MepoStashArgParser(object): def __init__(self, stash): self.stash = stash.add_subparsers() - self.stash.title = 'mepo stash sub-commands' - self.stash.dest = 'mepo_stash_cmd' + self.stash.title = "mepo stash sub-commands" + self.stash.dest = "mepo_stash_cmd" self.stash.required = True self.__push() self.__list() self.__pop() self.__apply() self.__show() - + def __push(self): stpush = self.stash.add_parser( - 'push', - description = 'Push (create) stash in component ') + "push", description="Push (create) stash in component " + ) stpush.add_argument( - '-m', '--message', - type=str, - metavar = 'message', + "-m", + "--message", + type=str, + metavar="message", default=None, - help = 'Message for the stash') + help="Message for the stash", + ) stpush.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '+', - help = 'Component to push stash in') + "comp_name", + metavar="comp-name", + nargs="+", + help="Component to push stash in", + ) def __show(self): stshow = self.stash.add_parser( - 'show', - description = 'show stash in component ') + "show", description="show stash in component " + ) stshow.add_argument( - '-p', '--patch', - action = 'store_true', - help = 'Message for the stash') + "-p", "--patch", action="store_true", help="Message for the stash" + ) stshow.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '+', - help = 'Component to show stash in') + "comp_name", + metavar="comp-name", + nargs="+", + help="Component to show stash in", + ) def __list(self): stlist = self.stash.add_parser( - 'list', - description = 'List local stashes of all components') + "list", description="List local stashes of all components" + ) def __pop(self): stpop = self.stash.add_parser( - 'pop', - description = 'Pop stash in component ') + "pop", description="Pop stash in component " + ) stpop.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '+', - help = 'Component to pop stash in') + "comp_name", + metavar="comp-name", + nargs="+", + help="Component to pop stash in", + ) def __apply(self): stapply = self.stash.add_parser( - 'apply', - description = 'apply stash in component ') + "apply", description="apply stash in component " + ) stapply.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '+', - help = 'Component to apply stash in') + "comp_name", + metavar="comp-name", + nargs="+", + help="Component to apply stash in", + ) diff --git a/src/mepo/cmdline/tag_parser.py b/src/mepo/cmdline/tag_parser.py index 0be42e74..dfacfc03 100644 --- a/src/mepo/cmdline/tag_parser.py +++ b/src/mepo/cmdline/tag_parser.py @@ -1,11 +1,12 @@ import argparse + class MepoTagArgParser(object): def __init__(self, tag): self.tag = tag.add_subparsers() - self.tag.title = 'mepo tag sub-commands' - self.tag.dest = 'mepo_tag_cmd' + self.tag.title = "mepo tag sub-commands" + self.tag.dest = "mepo_tag_cmd" self.tag.required = True self.__list() self.__create() @@ -14,71 +15,68 @@ def __init__(self, tag): def __list(self): tglist = self.tag.add_parser( - 'list', - description = 'List tags. If no component is specified, runs over all components') + "list", + description="List tags. If no component is specified, runs over all components", + ) tglist.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '*', - help = 'Component to list tags in') + "comp_name", + metavar="comp-name", + nargs="*", + help="Component to list tags in", + ) def __create(self): create = self.tag.add_parser( - 'create', - description = 'Create tag in component . If no component is specified, runs over all components') - create.add_argument( - 'tag_name', - metavar = 'tag-name', - help = "Name of tag") + "create", + description="Create tag in component . If no component is specified, runs over all components", + ) + create.add_argument("tag_name", metavar="tag-name", help="Name of tag") create.add_argument( - '-a', '--annotate', - action = 'store_true', - help = "Make an annotated tag") + "-a", "--annotate", action="store_true", help="Make an annotated tag" + ) create.add_argument( - '-m', '--message', + "-m", + "--message", type=str, - metavar = 'message', - default = None, - help = "Message for the tag" - ) + metavar="message", + default=None, + help="Message for the tag", + ) create.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '*', - help = 'Component to create tags in') + "comp_name", + metavar="comp-name", + nargs="*", + help="Component to create tags in", + ) def __delete(self): delete = self.tag.add_parser( - 'delete', - description = 'Delete tag in component . If no component is specified, runs over all components') + "delete", + description="Delete tag in component . If no component is specified, runs over all components", + ) + delete.add_argument("tag_name", metavar="tag-name", help="Name of tag") delete.add_argument( - 'tag_name', - metavar = 'tag-name', - help = "Name of tag") - delete.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '*', - help = 'Component to delete tags in') + "comp_name", + metavar="comp-name", + nargs="*", + help="Component to delete tags in", + ) def __push(self): push = self.tag.add_parser( - 'push', - description = 'Push tag in component . If no component is specified, runs over all components') - push.add_argument( - 'tag_name', - metavar = 'tag-name', - help = "Name of tag") + "push", + description="Push tag in component . If no component is specified, runs over all components", + ) + push.add_argument("tag_name", metavar="tag-name", help="Name of tag") push.add_argument( - '-f', '--force', - action = 'store_true', - help = "Force push (be careful!)") + "-f", "--force", action="store_true", help="Force push (be careful!)" + ) push.add_argument( - '-d', '--delete', - action = 'store_true', - help = "Delete (be careful!)") + "-d", "--delete", action="store_true", help="Delete (be careful!)" + ) push.add_argument( - 'comp_name', - metavar = 'comp-name', - nargs = '*', - help = 'Component to push tags in') + "comp_name", + metavar="comp-name", + nargs="*", + help="Component to push tags in", + ) diff --git a/src/mepo/command/branch.py b/src/mepo/command/branch.py index 4abecb1c..b419358a 100644 --- a/src/mepo/command/branch.py +++ b/src/mepo/command/branch.py @@ -2,10 +2,11 @@ from .branch_create import run as branch_create_run from .branch_delete import run as branch_delete_run + def run(args): d = { - 'list': branch_list_run, - 'create': branch_create_run, - 'delete': branch_delete_run, + "list": branch_list_run, + "create": branch_create_run, + "delete": branch_delete_run, } d[args.mepo_branch_cmd](args) diff --git a/src/mepo/command/branch_create.py b/src/mepo/command/branch_create.py index d12afa61..d22ec967 100644 --- a/src/mepo/command/branch_create.py +++ b/src/mepo/command/branch_create.py @@ -2,6 +2,7 @@ from ..utilities import verify from ..git import GitRepository + def run(args): allcomps = MepoState.read_state() verify.valid_components(args.comp_name, allcomps) diff --git a/src/mepo/command/branch_delete.py b/src/mepo/command/branch_delete.py index 1011e859..5c6f718e 100644 --- a/src/mepo/command/branch_delete.py +++ b/src/mepo/command/branch_delete.py @@ -2,6 +2,7 @@ from ..utilities import verify from ..git import GitRepository + def run(args): allcomps = MepoState.read_state() verify.valid_components(args.comp_name, allcomps) @@ -9,4 +10,4 @@ def run(args): for comp in comps2delbr: git = GitRepository(comp.remote, comp.local) git.delete_branch(args.branch_name, args.force) - print('- {}: {}'.format(comp.name, args.branch_name)) + print("- {}: {}".format(comp.name, args.branch_name)) diff --git a/src/mepo/command/branch_list.py b/src/mepo/command/branch_list.py index 7a4600aa..62972e12 100644 --- a/src/mepo/command/branch_list.py +++ b/src/mepo/command/branch_list.py @@ -2,17 +2,19 @@ from ..utilities import verify from ..git import GitRepository + def run(args): allcomps = MepoState.read_state() comps2list = _get_comps_to_list(args.comp_name, allcomps) max_namelen = len(max([x.name for x in comps2list], key=len)) - FMT = '{:<%s.%ss} | {: columns): - print(FMT1.format(name, orig + ' ...')) - print(FMT2.format(name_blank, '...', curr)) + print(FMT1.format(name, orig + " ...")) + print(FMT2.format(name_blank, "...", curr)) else: print(FMT0.format(name, orig, curr)) - diff --git a/src/mepo/command/config.py b/src/mepo/command/config.py index 76f86e8a..0b0c7d0b 100644 --- a/src/mepo/command/config.py +++ b/src/mepo/command/config.py @@ -3,11 +3,12 @@ from .config_delete import run as config_delete_run from .config_print import run as config_print_run + def run(args): d = { - 'get': config_get_run, - 'set': config_set_run, - 'delete': config_delete_run, - 'print': config_print_run, + "get": config_get_run, + "set": config_set_run, + "delete": config_delete_run, + "print": config_print_run, } d[args.mepo_config_cmd](args) diff --git a/src/mepo/command/config_delete.py b/src/mepo/command/config_delete.py index e6c8e7fa..11734c77 100644 --- a/src/mepo/command/config_delete.py +++ b/src/mepo/command/config_delete.py @@ -1,5 +1,6 @@ from ..utilities import mepoconfig + def run(args): section, option = mepoconfig.split_entry(args.entry) mepoconfig.remove_option(section, option) diff --git a/src/mepo/command/config_get.py b/src/mepo/command/config_get.py index 2b96f7f6..c2780890 100644 --- a/src/mepo/command/config_get.py +++ b/src/mepo/command/config_get.py @@ -1,13 +1,18 @@ from ..utilities import mepoconfig + def run(args): section, option = mepoconfig.split_entry(args.entry) if not mepoconfig.has_section(section): - raise Exception(f'Section [{section}] does not exist in .mepoconfig') + raise Exception(f"Section [{section}] does not exist in .mepoconfig") if not mepoconfig.has_option(section, option): - raise Exception(f'Option [{option}] does not exist in section [{section}] in .mepoconfig') + raise Exception( + f"Option [{option}] does not exist in section [{section}] in .mepoconfig" + ) value = mepoconfig.get(section, option) - print(f''' + print( + f""" [{section}] {option} = {value} - ''') + """ + ) diff --git a/src/mepo/command/config_print.py b/src/mepo/command/config_print.py index 5abc27c5..6c785429 100644 --- a/src/mepo/command/config_print.py +++ b/src/mepo/command/config_print.py @@ -1,4 +1,5 @@ from ..utilities import mepoconfig + def run(args): mepoconfig.print() diff --git a/src/mepo/command/config_set.py b/src/mepo/command/config_set.py index fb701bbf..94e4bf30 100644 --- a/src/mepo/command/config_set.py +++ b/src/mepo/command/config_set.py @@ -1,5 +1,6 @@ from ..utilities import mepoconfig + def run(args): section, option = mepoconfig.split_entry(args.entry) value = args.value diff --git a/src/mepo/command/develop.py b/src/mepo/command/develop.py index 7e5def5f..eb611274 100644 --- a/src/mepo/command/develop.py +++ b/src/mepo/command/develop.py @@ -3,6 +3,7 @@ from ..git import GitRepository from ..utilities import colors + def run(args): allcomps = MepoState.read_state() verify.valid_components(args.comp_name, allcomps) @@ -12,8 +13,12 @@ def run(args): if comp.develop is None: raise Exception("'develop' branch not specified for {}".format(comp.name)) if not args.quiet: - print("Checking out development branch %s in %s" % - (colors.YELLOW + comp.develop + colors.RESET, - colors.RESET + comp.name + colors.RESET)) + print( + "Checking out development branch %s in %s" + % ( + colors.YELLOW + comp.develop + colors.RESET, + colors.RESET + comp.name + colors.RESET, + ) + ) git.checkout(comp.develop) output = git.pull() diff --git a/src/mepo/command/diff.py b/src/mepo/command/diff.py index 69e4479e..0dc022cb 100644 --- a/src/mepo/command/diff.py +++ b/src/mepo/command/diff.py @@ -9,6 +9,7 @@ from ..git import GitRepository from ..utilities import verify + def run(args): foundDiff = False @@ -19,12 +20,14 @@ def run(args): result = check_component_diff(comp, args) if result: if not foundDiff: - print('Diffing...'); sys.stdout.flush() + print("Diffing...") + sys.stdout.flush() foundDiff = True print_diff(comp, args, result) if not foundDiff: - print('No diffs found') + print("No diffs found") + def _get_comps_to_diff(specified_comps, allcomps): comps_to_diff = allcomps @@ -33,6 +36,7 @@ def _get_comps_to_diff(specified_comps, allcomps): comps_to_diff = [x for x in allcomps if x.name in specified_comps] return comps_to_diff + def check_component_diff(comp, args): git = GitRepository(comp.remote, comp.local) @@ -44,17 +48,19 @@ def check_component_diff(comp, args): _ignore_submodules = None return git.run_diff(args, _ignore_submodules) + def print_diff(comp, args, output): - columns, lines = get_terminal_size(fallback=(80,20)) - horiz_line = u'\u2500'*columns + columns, lines = get_terminal_size(fallback=(80, 20)) + horiz_line = "\u2500" * columns - print("{} (location: {}):".format(comp.name,_get_relative_path(comp.local))) + print("{} (location: {}):".format(comp.name, _get_relative_path(comp.local))) print() - for line in output.split('\n'): - #print(' |', line.rstrip()) + for line in output.split("\n"): + # print(' |', line.rstrip()) print(line.rstrip()) print(horiz_line) + def _get_relative_path(local_path): """ Get the relative path when given a local path. @@ -63,7 +69,7 @@ def _get_relative_path(local_path): """ # This creates a full path on the disk from the root of mepo and the local_path - full_local_path=os.path.join(MepoState.get_root_dir(),local_path) + full_local_path = os.path.join(MepoState.get_root_dir(), local_path) # We return the path relative to where we currently are return os.path.relpath(full_local_path, os.getcwd()) diff --git a/src/mepo/command/fetch.py b/src/mepo/command/fetch.py index fa794ec8..02c0e3b6 100644 --- a/src/mepo/command/fetch.py +++ b/src/mepo/command/fetch.py @@ -3,15 +3,16 @@ from ..utilities import verify from ..git import GitRepository + def run(args): allcomps = MepoState.read_state() comps2fetch = _get_comps_to_list(args.comp_name, allcomps) for comp in comps2fetch: git = GitRepository(comp.remote, comp.local) - print("Fetching %s" % - colors.YELLOW + comp.name + colors.RESET) + print("Fetching %s" % colors.YELLOW + comp.name + colors.RESET) git.fetch(args) + def _get_comps_to_list(specified_comps, allcomps): comps_to_list = allcomps if specified_comps: diff --git a/src/mepo/command/init.py b/src/mepo/command/init.py index cff65c5a..b28eb7f9 100644 --- a/src/mepo/command/init.py +++ b/src/mepo/command/init.py @@ -1,22 +1,25 @@ from ..state import MepoState from ..utilities import mepoconfig + def run(args): if args.style: style = args.style - elif mepoconfig.has_option('init','style'): - allowed_styles = ['naked','prefix','postfix'] - style = mepoconfig.get('init','style') + elif mepoconfig.has_option("init", "style"): + allowed_styles = ["naked", "prefix", "postfix"] + style = mepoconfig.get("init", "style") if style not in allowed_styles: - raise Exception(f'Detected style [{style}] from .mepoconfig is not an allowed style: {allowed_styles}') + raise Exception( + f"Detected style [{style}] from .mepoconfig is not an allowed style: {allowed_styles}" + ) else: - print(f'Found style [{style}] in .mepoconfig') + print(f"Found style [{style}] in .mepoconfig") else: style = None allcomps = MepoState.initialize(args.registry, style) if not style: - print(f'Initializing mepo using {args.registry}') + print(f"Initializing mepo using {args.registry}") else: - print(f'Initializing mepo using {args.registry} with {style} style') + print(f"Initializing mepo using {args.registry} with {style} style") diff --git a/src/mepo/command/list.py b/src/mepo/command/list.py index e0d9b959..bf6513b7 100644 --- a/src/mepo/command/list.py +++ b/src/mepo/command/list.py @@ -1,7 +1,8 @@ from ..state import MepoState + def run(args): - _end = '\n' if args.one_per_line else ' ' + _end = "\n" if args.one_per_line else " " allcomps = MepoState.read_state() for comp in allcomps[:-1]: print(comp.name, end=_end) diff --git a/src/mepo/command/pull-all.py b/src/mepo/command/pull-all.py index 56511ca1..c54773dd 100644 --- a/src/mepo/command/pull-all.py +++ b/src/mepo/command/pull-all.py @@ -3,20 +3,28 @@ from ..git import GitRepository from ..utilities import colors + def run(args): allcomps = MepoState.read_state() - detached_comps=[] + detached_comps = [] for comp in allcomps: git = GitRepository(comp.remote, comp.local) name, tYpe, detached = MepoVersion(*git.get_version()) if detached: detached_comps.append(comp.name) else: - print("Pulling branch %s in %s " % - (colors.YELLOW + name + colors.RESET, - colors.RESET + comp.name + colors.RESET)) + print( + "Pulling branch %s in %s " + % ( + colors.YELLOW + name + colors.RESET, + colors.RESET + comp.name + colors.RESET, + ) + ) output = git.pull() - if not args.quiet: print(output) + if not args.quiet: + print(output) if len(detached_comps) > 0: - print("The following repos were not pulled (detached HEAD): %s" % (', '.join(map(str, detached_comps)))) - + print( + "The following repos were not pulled (detached HEAD): %s" + % (", ".join(map(str, detached_comps))) + ) diff --git a/src/mepo/command/pull.py b/src/mepo/command/pull.py index 9f7029ed..f3bb97c1 100644 --- a/src/mepo/command/pull.py +++ b/src/mepo/command/pull.py @@ -4,6 +4,7 @@ from ..utilities import colors from ..git import GitRepository + def run(args): allcomps = MepoState.read_state() verify.valid_components(args.comp_name, allcomps) @@ -12,10 +13,15 @@ def run(args): git = GitRepository(comp.remote, comp.local) name, tYpe, is_detached = MepoVersion(*git.get_version()) if is_detached: - raise Exception('{} has detached head! Cannot pull.'.format(comp.name)) + raise Exception("{} has detached head! Cannot pull.".format(comp.name)) else: - print("Pulling branch %s in %s " % - (colors.YELLOW + name + colors.RESET, - colors.RESET + comp.name + colors.RESET)) + print( + "Pulling branch %s in %s " + % ( + colors.YELLOW + name + colors.RESET, + colors.RESET + comp.name + colors.RESET, + ) + ) output = git.pull() - if not args.quiet: print(output) + if not args.quiet: + print(output) diff --git a/src/mepo/command/push.py b/src/mepo/command/push.py index 09f9d838..78869d61 100644 --- a/src/mepo/command/push.py +++ b/src/mepo/command/push.py @@ -2,6 +2,7 @@ from ..state import MepoState from ..git import GitRepository + def run(args): allcomps = MepoState.read_state() verify.valid_components(args.comp_name, allcomps) @@ -9,5 +10,5 @@ def run(args): for comp in comps2push: git = GitRepository(comp.remote, comp.local) output = git.push() - print('----------\nPushed: {}\n----------'.format(comp.name)) + print("----------\nPushed: {}\n----------".format(comp.name)) print(output) diff --git a/src/mepo/command/reset.py b/src/mepo/command/reset.py index 108c59c0..1f360250 100644 --- a/src/mepo/command/reset.py +++ b/src/mepo/command/reset.py @@ -11,6 +11,7 @@ # subrepos. This is useful if you want to start over with a fresh clone # of the project. + def run(args): allcomps = MepoState.read_state() @@ -21,14 +22,19 @@ def run(args): curdir = os.getcwd() ## Then check that they are the same, if they are not, then throw a NotInRootDirError if rootdir != curdir: - raise NotInRootDirError('Error! As a safety precaution, you must be in the root directory of the project to reset') + raise NotInRootDirError( + "Error! As a safety precaution, you must be in the root directory of the project to reset" + ) # If we get this far, then we are in the root directory of the project # If a user has called this command without the force flag, we # will ask them to confirm that they want to reset the project if not args.force and not args.dry_run: - print(f"Are you sure you want to reset the project? If so, type 'yes' and press enter.", end=' ') + print( + f"Are you sure you want to reset the project? If so, type 'yes' and press enter.", + end=" ", + ) answer = input() if answer != "yes": print("Reset cancelled.") @@ -43,21 +49,21 @@ def run(args): else: # Get the relative path to the component relpath = _get_relative_path(comp.local) - print(f'Removing {relpath}', end='...') + print(f"Removing {relpath}", end="...") # Remove the component if not dry run if not args.dry_run: shutil.rmtree(relpath) - print('done.') + print("done.") else: - print(f'dry-run only. Not removing {relpath}') + print(f"dry-run only. Not removing {relpath}") # Next, we need to remove the .mepo directory - print(f'Removing mepo state', end='...') + print(f"Removing mepo state", end="...") if not args.dry_run: shutil.rmtree(MepoState.get_dir()) - print('done.') + print("done.") else: - print(f'dry-run only. Not removing mepo state') + print(f"dry-run only. Not removing mepo state") # If they pass in the --reclone flag, then we will re-clone all the subrepos if args.reclone: @@ -65,19 +71,25 @@ def run(args): # mepo_clone requires args which is an Argparse Namespace object # We will create a new Namespace object with the correct arguments # for mepo_clone - clone_args = type('Namespace', (object,), { - 'repo_url': None, - 'directory': None, - 'branch': None, - 'registry': None, - 'allrepos': False, - 'style': None}) + clone_args = type( + "Namespace", + (object,), + { + "repo_url": None, + "directory": None, + "branch": None, + "registry": None, + "allrepos": False, + "style": None, + }, + ) if not args.dry_run: - print('Re-cloning all subrepos') + print("Re-cloning all subrepos") mepo_clone_run(clone_args) - print('Recloning done.') + print("Recloning done.") else: - print(f'Dry-run only. Not re-cloning all subrepos') + print(f"Dry-run only. Not re-cloning all subrepos") + def _get_relative_path(local_path): """ @@ -87,7 +99,7 @@ def _get_relative_path(local_path): """ # This creates a full path on the disk from the root of mepo and the local_path - full_local_path=os.path.join(MepoState.get_root_dir(),local_path) + full_local_path = os.path.join(MepoState.get_root_dir(), local_path) # We return the path relative to where we currently are return os.path.relpath(full_local_path, os.getcwd()) diff --git a/src/mepo/command/restore-state.py b/src/mepo/command/restore-state.py index 15725a55..8f3c54e0 100644 --- a/src/mepo/command/restore-state.py +++ b/src/mepo/command/restore-state.py @@ -7,29 +7,36 @@ from ..utilities.version import version_to_string from ..utilities import colors + def run(args): - print('Checking status...'); sys.stdout.flush() + print("Checking status...") + sys.stdout.flush() allcomps = MepoState.read_state() with mp.Pool() as pool: result = pool.map(check_component_status, allcomps) restore_state(allcomps, result) + def check_component_status(comp): git = GitRepository(comp.remote, comp.local) - curr_ver = version_to_string(git.get_version(),git) + curr_ver = version_to_string(git.get_version(), git) return (curr_ver, git.check_status()) + def restore_state(allcomps, result): for index, comp in enumerate(allcomps): git = GitRepository(comp.remote, comp.local) - current_version = result[index][0].split(' ')[1] + current_version = result[index][0].split(" ")[1] orig_version = comp.version.name if current_version != orig_version: - print(colors.YELLOW - + "Restoring " - + colors.RESET - + "{} to {} from {}.".format( - comp.name, - colors.GREEN + orig_version + colors.RESET, - colors.RED + current_version + colors.RESET)) + print( + colors.YELLOW + + "Restoring " + + colors.RESET + + "{} to {} from {}.".format( + comp.name, + colors.GREEN + orig_version + colors.RESET, + colors.RED + current_version + colors.RESET, + ) + ) git.checkout(comp.version.name) diff --git a/src/mepo/command/save.py b/src/mepo/command/save.py index 386f5cb1..0e678b5c 100644 --- a/src/mepo/command/save.py +++ b/src/mepo/command/save.py @@ -6,6 +6,7 @@ from ..registry import Registry from ..utilities.version import sanitize_version_string + def run(args): allcomps = MepoState.read_state() for comp in allcomps: @@ -17,49 +18,62 @@ def run(args): relpath_start = MepoState.get_root_dir() for comp in allcomps: complist.update(comp.to_registry_format()) - registry_root_dir=os.path.join(relpath_start,args.registry) + registry_root_dir = os.path.join(relpath_start, args.registry) Registry(registry_root_dir).write_yaml(complist) print(f"Components written to '{registry_root_dir}'") + def _update_comp(comp): git = GitRepository(comp.remote, comp.local) orig_ver = comp.version curr_ver = MepoVersion(*git.get_version()) - orig_ver_is_tag_or_hash = (orig_ver.type == 't' or orig_ver.type == 'h') - curr_ver_is_tag_or_hash = (curr_ver.type == 't' or curr_ver.type == 'h') + orig_ver_is_tag_or_hash = orig_ver.type == "t" or orig_ver.type == "h" + curr_ver_is_tag_or_hash = curr_ver.type == "t" or curr_ver.type == "h" if orig_ver_is_tag_or_hash and curr_ver_is_tag_or_hash: # This command is to try and work with git tag oddities - curr_ver_to_use = sanitize_version_string(orig_ver.name,curr_ver.name,git) + curr_ver_to_use = sanitize_version_string(orig_ver.name, curr_ver.name, git) if curr_ver_to_use == orig_ver.name: comp.version = orig_ver else: - _verify_local_and_remote_commit_ids_match(git, curr_ver_to_use, comp.name, curr_ver.type) + _verify_local_and_remote_commit_ids_match( + git, curr_ver_to_use, comp.name, curr_ver.type + ) comp.version = curr_ver else: if _version_has_changed(curr_ver, orig_ver, comp.name): - _verify_local_and_remote_commit_ids_match(git, curr_ver.name, comp.name, curr_ver.type) + _verify_local_and_remote_commit_ids_match( + git, curr_ver.name, comp.name, curr_ver.type + ) comp.version = curr_ver + def _version_has_changed(curr_ver, orig_ver, name): result = False if curr_ver != orig_ver: - if curr_ver.type == 'b': - assert curr_ver.detached is False, f'You cannot save a detached branch, have you committed your code in {name}?\n {curr_ver}' + if curr_ver.type == "b": + assert ( + curr_ver.detached is False + ), f"You cannot save a detached branch, have you committed your code in {name}?\n {curr_ver}" result = True - elif curr_ver.type == 't': + elif curr_ver.type == "t": result = True - elif curr_ver.type == 'h': + elif curr_ver.type == "h": result = True else: raise Exception("This should not happen") return result -def _verify_local_and_remote_commit_ids_match(git, curr_ver_name, comp_name, curr_ver_type): + +def _verify_local_and_remote_commit_ids_match( + git, curr_ver_name, comp_name, curr_ver_type +): remote_id = git.get_remote_latest_commit_id(curr_ver_name, curr_ver_type) local_id = git.get_local_latest_commit_id() - failmsg = "{} (remote commit) != {} (local commit) for {}:{}. Did you try 'mepo push'?" + failmsg = ( + "{} (remote commit) != {} (local commit) for {}:{}. Did you try 'mepo push'?" + ) if remote_id != local_id: msg = failmsg.format(remote_id, local_id, comp_name, curr_ver_name) raise Exception(msg) diff --git a/src/mepo/command/stage.py b/src/mepo/command/stage.py index ccaeac61..7a3b9966 100644 --- a/src/mepo/command/stage.py +++ b/src/mepo/command/stage.py @@ -3,6 +3,7 @@ from ..git import GitRepository from ..component import MepoVersion + def run(args): allcomps = MepoState.read_state() verify.valid_components(args.comp_name, allcomps) @@ -11,9 +12,10 @@ def run(args): git = GitRepository(comp.remote, comp.local) stage_files(git, comp, args.untracked) + def stage_files(git, comp, untracked=False, commit=False): curr_ver = MepoVersion(*git.get_version()) - if curr_ver.detached: # detached head + if curr_ver.detached: # detached head raise Exception(f"{comp.name} has detached head! Cannot stage.") for myfile in git.get_changed_files(untracked=untracked): git.stage_file(myfile) @@ -22,4 +24,3 @@ def stage_files(git, comp, untracked=False, commit=False): print(f"Staged: {print_output}") else: print(f"+ {print_output}") - diff --git a/src/mepo/command/stash.py b/src/mepo/command/stash.py index 44a0cf28..4da79326 100644 --- a/src/mepo/command/stash.py +++ b/src/mepo/command/stash.py @@ -4,12 +4,13 @@ from .stash_push import run as stash_push_run from .stash_show import run as stash_show_run + def run(args): d = { - 'list': stash_list_run, - 'pop': stash_pop_run, - 'apply': stash_apply_run, - 'push': stash_push_run, - 'show': stash_show_run, + "list": stash_list_run, + "pop": stash_pop_run, + "apply": stash_apply_run, + "push": stash_push_run, + "show": stash_show_run, } d[args.mepo_stash_cmd](args) diff --git a/src/mepo/command/stash_apply.py b/src/mepo/command/stash_apply.py index 6447049b..54617ce3 100644 --- a/src/mepo/command/stash_apply.py +++ b/src/mepo/command/stash_apply.py @@ -2,6 +2,7 @@ from ..utilities import verify from ..git import GitRepository + def run(args): allcomps = MepoState.read_state() verify.valid_components(args.comp_name, allcomps) @@ -9,4 +10,4 @@ def run(args): for comp in comps2appst: git = GitRepository(comp.remote, comp.local) git.apply_stash() - #print('+ {}'.format(comp.name)) + # print('+ {}'.format(comp.name)) diff --git a/src/mepo/command/stash_list.py b/src/mepo/command/stash_list.py index aa8059ae..a93537ce 100644 --- a/src/mepo/command/stash_list.py +++ b/src/mepo/command/stash_list.py @@ -1,13 +1,14 @@ from ..state import MepoState from ..git import GitRepository + def run(args): allcomps = MepoState.read_state() max_namelen = len(max([x.name for x in allcomps], key=len)) - FMT = '{:<%s.%ss} | {:{file_name_length}}: {verbose_status}".format( + file_name=file_name, + file_name_length=max_file_name_length, + verbose_status=verbose_status, + ) + ) verbose_output_list.append(verbose_status_string) output = "\n".join(verbose_output_list) @@ -307,19 +453,19 @@ def check_status(self, ignore_permissions=False, ignore_submodules=False): def __get_modified_files(self, orig_ver, comp_type): if not orig_ver: - cmd = self.__git + ' diff --name-only' + cmd = self.__git + " diff --name-only" else: if comp_type == "b": - cmd = self.__git + ' diff --name-only origin/{}'.format(orig_ver) + cmd = self.__git + " diff --name-only origin/{}".format(orig_ver) else: - cmd = self.__git + ' diff --name-only {}'.format(orig_ver) + cmd = self.__git + " diff --name-only {}".format(orig_ver) output = shellcmd.run(shlex.split(cmd), output=True).strip() - return output.split('\n') if output else [] + return output.split("\n") if output else [] def __get_untracked_files(self): - cmd = self.__git + ' ls-files --others --exclude-standard' + cmd = self.__git + " ls-files --others --exclude-standard" output = shellcmd.run(shlex.split(cmd), output=True).strip() - return output.split('\n') if output else [] + return output.split("\n") if output else [] def get_changed_files(self, untracked=False, orig_ver=None, comp_type=None): changed_files = self.__get_modified_files(orig_ver, comp_type) @@ -328,103 +474,106 @@ def get_changed_files(self, untracked=False, orig_ver=None, comp_type=None): return changed_files def stage_file(self, myfile): - cmd = self.__git + ' add {}'.format(myfile) + cmd = self.__git + " add {}".format(myfile) shellcmd.run(shlex.split(cmd)) def get_staged_files(self): - cmd = self.__git + ' diff --name-only --staged' + cmd = self.__git + " diff --name-only --staged" output = shellcmd.run(shlex.split(cmd), output=True).strip() - return output.split('\n') if output else [] + return output.split("\n") if output else [] def unstage_file(self, myfile): - cmd = self.__git + ' reset -- {}'.format(myfile) + cmd = self.__git + " reset -- {}".format(myfile) shellcmd.run(shlex.split(cmd)) def commit_files(self, message, tf_file=None): if tf_file: - cmd = ['git', '-C', self.__full_local_path, 'commit', '-F', tf_file] + cmd = ["git", "-C", self.__full_local_path, "commit", "-F", tf_file] elif message: - cmd = ['git', '-C', self.__full_local_path, 'commit', '-m', message] + cmd = ["git", "-C", self.__full_local_path, "commit", "-m", message] else: raise Exception("This should not happen") shellcmd.run(cmd) def push(self): - cmd = self.__git + ' push -u {}'.format(self.__remote) + cmd = self.__git + " push -u {}".format(self.__remote) return shellcmd.run(shlex.split(cmd), output=True).strip() def get_remote_latest_commit_id(self, branch, commit_type): - if commit_type == 'h': - cmd = self.__git + ' cat-file -e {}'.format(branch) + if commit_type == "h": + cmd = self.__git + " cat-file -e {}".format(branch) status = shellcmd.run(shlex.split(cmd), status=True) if status != 0: - msg = 'Hash {} does not exist on {}'.format(branch, self.__remote) + msg = "Hash {} does not exist on {}".format(branch, self.__remote) msg += " Have you run 'mepo push'?" raise RuntimeError(msg) return branch else: # If we are a branch... - if commit_type == 'b': + if commit_type == "b": msgtype = "Branch" - reftype = 'heads' - elif commit_type == 't': - msgtype = 'Tag' - reftype = 'tags' + reftype = "heads" + elif commit_type == "t": + msgtype = "Tag" + reftype = "tags" else: raise RuntimeError("Should not get here") - cmd = self.__git + ' ls-remote {} refs/{}/{}'.format(self.__remote, reftype, branch) + cmd = self.__git + " ls-remote {} refs/{}/{}".format( + self.__remote, reftype, branch + ) output = shellcmd.run(shlex.split(cmd), stdout=True).strip() if not output: - #msg = '{} {} does not exist on {}'.format(msgtype, branch, self.__remote) - #msg += " Have you run 'mepo push'?" - #raise RuntimeError(msg) - cmd = self.__git + ' rev-parse HEAD' + # msg = '{} {} does not exist on {}'.format(msgtype, branch, self.__remote) + # msg += " Have you run 'mepo push'?" + # raise RuntimeError(msg) + cmd = self.__git + " rev-parse HEAD" output = shellcmd.run(shlex.split(cmd), output=True).strip() return output.split()[0] def get_local_latest_commit_id(self): - cmd = self.__git + ' rev-parse HEAD' + cmd = self.__git + " rev-parse HEAD" return shellcmd.run(shlex.split(cmd), output=True).strip() def pull(self): - cmd = self.__git + ' pull' + cmd = self.__git + " pull" return shellcmd.run(shlex.split(cmd), output=True).strip() def get_version(self): - cmd = self.__git + ' show -s --pretty=%D HEAD' + cmd = self.__git + " show -s --pretty=%D HEAD" output = shellcmd.run(shlex.split(cmd), output=True) - if output.startswith('HEAD ->'): # an actual branch + if output.startswith("HEAD ->"): # an actual branch detached = False - name = output.split(',')[0].split('->')[1].strip() - tYpe = 'b' - elif output.startswith('HEAD,'): # detached head + name = output.split(",")[0].split("->")[1].strip() + tYpe = "b" + elif output.startswith("HEAD,"): # detached head detached = True - tmp = output.split(',')[1].strip() - if tmp.startswith('tag:'): # tag + tmp = output.split(",")[1].strip() + if tmp.startswith("tag:"): # tag name = tmp[5:] - tYpe = 't' + tYpe = "t" else: # This was needed for when we weren't explicitly detaching on clone - #cmd_for_branch = self.__git + ' reflog HEAD -n 1' - #reflog_output = shellcmd.run(shlex.split(cmd_for_branch), output=True) - #name = reflog_output.split()[-1].strip() + # cmd_for_branch = self.__git + ' reflog HEAD -n 1' + # reflog_output = shellcmd.run(shlex.split(cmd_for_branch), output=True) + # name = reflog_output.split()[-1].strip() name = output.split()[-1].strip() - tYpe = 'b' - elif output.startswith('HEAD'): # Assume hash - cmd = self.__git + ' rev-parse HEAD' + tYpe = "b" + elif output.startswith("HEAD"): # Assume hash + cmd = self.__git + " rev-parse HEAD" hash_out = shellcmd.run(shlex.split(cmd), output=True) detached = True name = hash_out.rstrip() - tYpe = 'h' - elif output.startswith('grafted'): - cmd = self.__git + ' describe --always' + tYpe = "h" + elif output.startswith("grafted"): + cmd = self.__git + " describe --always" hash_out = shellcmd.run(shlex.split(cmd), output=True) detached = True name = hash_out.rstrip() - tYpe = 'h' + tYpe = "h" return (name, tYpe, detached) + def get_current_remote_url(): - cmd = 'git remote get-url origin' + cmd = "git remote get-url origin" output = shellcmd.run(shlex.split(cmd), output=True).strip() return output diff --git a/src/mepo/registry.py b/src/mepo/registry.py index 61bb7162..a5e148bb 100644 --- a/src/mepo/registry.py +++ b/src/mepo/registry.py @@ -3,6 +3,7 @@ from .utilities.exceptions import SuffixNotRecognizedError + # From https://github.com/yaml/pyyaml/issues/127#issuecomment-525800484 class AddBlankLinesDumper(yaml.SafeDumper): # HACK: insert blank lines between top-level objects @@ -13,43 +14,49 @@ def write_line_break(self, data=None): if len(self.indents) == 1: super().write_line_break() + class Registry(object): - __slots__ = ['__filename', '__filetype'] + __slots__ = ["__filename", "__filetype"] def __init__(self, filename): self.__filename = filename - SUFFIX_LIST = ['.yaml', '.json', '.cfg'] + SUFFIX_LIST = [".yaml", ".json", ".cfg"] file_suffix = pathlib.Path(filename).suffix if file_suffix in SUFFIX_LIST: self.__filetype = file_suffix[1:] else: - raise SuffixNotRecognizedError('suffix {} not supported'.format(file_suffix)) + raise SuffixNotRecognizedError( + "suffix {} not supported".format(file_suffix) + ) def read_file(self): - '''Call read_yaml, read_json etc. using dispatch pattern''' - return getattr(self, 'read_'+self.__filetype)() + """Call read_yaml, read_json etc. using dispatch pattern""" + return getattr(self, "read_" + self.__filetype)() def read_yaml(self): - '''Read yaml registry and return a dict containing contents''' + """Read yaml registry and return a dict containing contents""" import yaml - with open(self.__filename, 'r') as fin: + + with open(self.__filename, "r") as fin: d = yaml.safe_load(fin) return d def read_json(self): - '''Read json registry and return a dict containing contents''' + """Read json registry and return a dict containing contents""" import json - with open(self.__filename, 'r') as fin: + + with open(self.__filename, "r") as fin: d = json.load(fin) return d def read_cfg(self): - '''Read python registry and return a dict containing contents''' - raise NotImplementedError('Reading of cfg file has not yet been implemented') + """Read python registry and return a dict containing contents""" + raise NotImplementedError("Reading of cfg file has not yet been implemented") def write_yaml(self, d): - '''Dump dict d into a yaml file''' + """Dump dict d into a yaml file""" import yaml - with open(self.__filename, 'w') as fout: - yaml.dump(d, fout, sort_keys = False, Dumper=AddBlankLinesDumper) + + with open(self.__filename, "w") as fout: + yaml.dump(d, fout, sort_keys=False, Dumper=AddBlankLinesDumper) diff --git a/src/mepo/state.py b/src/mepo/state.py index 031fc56c..8137decd 100644 --- a/src/mepo/state.py +++ b/src/mepo/state.py @@ -14,16 +14,17 @@ from .utilities.exceptions import StateAlreadyInitializedError from .utilities.chdir import chdir as mepo_chdir + class MepoState(object): - __state_dir_name = '.mepo' - __state_fileptr_name = 'state.pkl' + __state_dir_name = ".mepo" + __state_fileptr_name = "state.pkl" @staticmethod def get_parent_dirs(): mypath = os.getcwd() parentdirs = [mypath] - while mypath != '/': + while mypath != "/": mypath = os.path.dirname(mypath) parentdirs.append(mypath) return parentdirs @@ -34,11 +35,11 @@ def get_dir(cls): state_dir = os.path.join(mydir, cls.__state_dir_name) if os.path.exists(state_dir): return state_dir - raise OSError('mepo state dir [.mepo] does not exist') + raise OSError("mepo state dir [.mepo] does not exist") @classmethod def get_root_dir(cls): - '''Return directory that contains .mepo''' + """Return directory that contains .mepo""" return os.path.dirname(cls.get_dir()) @classmethod @@ -46,7 +47,7 @@ def get_file(cls): state_file = os.path.join(cls.get_dir(), cls.__state_fileptr_name) if os.path.exists(state_file): return state_file - raise OSError('mepo state file [%s] does not exist' % state_file) + raise OSError("mepo state file [%s] does not exist" % state_file) @classmethod def exists(cls): @@ -59,15 +60,15 @@ def exists(cls): @classmethod def initialize(cls, project_registry, directory_style): if cls.exists(): - raise StateAlreadyInitializedError('Error! mepo state already exists') + raise StateAlreadyInitializedError("Error! mepo state already exists") input_components = Registry(project_registry).read_file() num_fixture = 0 complist = list() for name, comp in input_components.items(): # We only allow one fixture - if 'fixture' in comp: - num_fixture += comp['fixture'] + if "fixture" in comp: + num_fixture += comp["fixture"] if num_fixture > 1: raise Exception("Only one fixture allowed") @@ -84,13 +85,15 @@ def __mepo1_patch(): """ print( colors.YELLOW - + 'Converting mepo1 state to mepo2 state\n' + + "Converting mepo1 state to mepo2 state\n" + "Run to permanently convert to mepo2 state" - + colors.RESET) + + colors.RESET + ) import mepo - sys.modules['state'] = mepo.state - sys.modules['state.component'] = mepo.component - sys.modules['utilities'] = mepo.utilities + + sys.modules["state"] = mepo.state + sys.modules["state.component"] = mepo.component + sys.modules["utilities"] = mepo.utilities @staticmethod def mepo1_patch_undo(): @@ -98,15 +101,16 @@ def mepo1_patch_undo(): Undo changes made my __mepo1_patch(). Called during """ import mepo - entries_to_remove = ['state', 'state.component', 'utilities'] + + entries_to_remove = ["state", "state.component", "utilities"] for key in entries_to_remove: sys.modules.pop(key, None) @classmethod def read_state(cls): if not cls.exists(): - raise StateDoesNotExistError('Error! mepo state does not exist') - with open(cls.get_file(), 'rb') as fin: + raise StateDoesNotExistError("Error! mepo state does not exist") + with open(cls.get_file(), "rb") as fin: try: allcomps = pickle.load(fin) except ModuleNotFoundError: @@ -119,21 +123,21 @@ def read_state(cls): def write_state(cls, state_details): if cls.exists(): state_dir = cls.get_dir() - pattern = os.path.join(cls.get_dir(), 'state.*.pkl') + pattern = os.path.join(cls.get_dir(), "state.*.pkl") states = [os.path.basename(x) for x in glob.glob(os.path.join(pattern))] - new_state_id = max([int(x.split('.')[1]) for x in states]) + 1 - state_file_name = 'state.' + str(new_state_id) + '.pkl' + new_state_id = max([int(x.split(".")[1]) for x in states]) + 1 + state_file_name = "state." + str(new_state_id) + ".pkl" else: state_dir = os.path.join(os.getcwd(), cls.__state_dir_name) os.mkdir(state_dir) - state_file_name = 'state.0.pkl' + state_file_name = "state.0.pkl" new_state_file = os.path.join(state_dir, state_file_name) - with open(new_state_file, 'wb') as fout: + with open(new_state_file, "wb") as fout: pickle.dump(state_details, fout, -1) state_fileptr = cls.__state_fileptr_name state_fileptr_fullpath = os.path.join(state_dir, state_fileptr) if os.path.isfile(state_fileptr_fullpath): os.remove(state_fileptr_fullpath) - #os.symlink(new_state_file, state_fileptr_fullpath) + # os.symlink(new_state_file, state_fileptr_fullpath) with mepo_chdir(state_dir): os.symlink(state_file_name, state_fileptr) diff --git a/src/mepo/utilities/chdir.py b/src/mepo/utilities/chdir.py index 6a35a70e..05b4b85c 100644 --- a/src/mepo/utilities/chdir.py +++ b/src/mepo/utilities/chdir.py @@ -1,6 +1,7 @@ import os from contextlib import contextmanager + @contextmanager def chdir(path): cwd = os.getcwd() diff --git a/src/mepo/utilities/colors.py b/src/mepo/utilities/colors.py index 78ca5e67..e2581686 100644 --- a/src/mepo/utilities/colors.py +++ b/src/mepo/utilities/colors.py @@ -2,16 +2,16 @@ import colorama from colorama import Fore, Back, Style - RED = Fore.RED - BLUE = Fore.BLUE - CYAN = Fore.CYAN - GREEN = Fore.GREEN + RED = Fore.RED + BLUE = Fore.BLUE + CYAN = Fore.CYAN + GREEN = Fore.GREEN YELLOW = Fore.YELLOW - RESET = Style.RESET_ALL + RESET = Style.RESET_ALL except ImportError: - RED = "\x1b[1;31m" - BLUE = "\x1b[1;34m" - CYAN = "\x1b[1;36m" - GREEN = "\x1b[1;32m" + RED = "\x1b[1;31m" + BLUE = "\x1b[1;34m" + CYAN = "\x1b[1;36m" + GREEN = "\x1b[1;32m" YELLOW = "\x1b[1;33m" - RESET = "\x1b[0;0m" + RESET = "\x1b[0;0m" diff --git a/src/mepo/utilities/exceptions.py b/src/mepo/utilities/exceptions.py index 888e01fe..084a1b61 100644 --- a/src/mepo/utilities/exceptions.py +++ b/src/mepo/utilities/exceptions.py @@ -1,23 +1,34 @@ class StateDoesNotExistError(SystemExit): """Raised when the mepo state does not exist""" + pass + class StateAlreadyInitializedError(SystemExit): """Raised when the mepo state has already been initialized""" + pass + class RepoAlreadyClonedError(SystemExit): """Raised when the repository has already been cloned""" + pass + class RegistryNotFoundError(FileNotFoundError): """Raised when the registry is not found""" + pass + class SuffixNotRecognizedError(RuntimeError): """Raised when the registry suffix is not recognized""" + pass + class NotInRootDirError(SystemExit): """Raised when a command is run not in the root directory""" + pass diff --git a/src/mepo/utilities/mepoconfig.py b/src/mepo/utilities/mepoconfig.py index 0fc8c5db..6451e2de 100644 --- a/src/mepo/utilities/mepoconfig.py +++ b/src/mepo/utilities/mepoconfig.py @@ -2,62 +2,76 @@ import os import sys -config_file = os.path.expanduser('~/.mepoconfig') +config_file = os.path.expanduser("~/.mepoconfig") config = configparser.ConfigParser() config.read(config_file) + def split_entry(entry): - entry_list = entry.split('.') + entry_list = entry.split(".") if len(entry_list) != 2: - raise Exception(f'Invalid entry [{entry}]. Must be of form section.option, e.g., "alias.st"') + raise Exception( + f'Invalid entry [{entry}]. Must be of form section.option, e.g., "alias.st"' + ) section = entry_list[0] option = entry_list[1] return section, option + def write(): - with open(config_file,'w') as fp: + with open(config_file, "w") as fp: config.write(fp) + def print_sections(): print(config.sections()) + def print_options(section): print(config.options(section)) + def print(): config.write(sys.stdout) + def has_section(section): return config.has_section(section) + def has_option(section, option): return config.has_option(section, option) + def get(section, option): return config[section][option] + def remove_option(section, option): config.remove_option(section, option) if not config[section]: config.remove_section(section) + def set(section, option, value): if not has_section(section): config[section] = {} config[section][option] = value + def get_command_alias(command): output = [] - if has_section('alias'): - for key,value in config.items('alias'): + if has_section("alias"): + for key, value in config.items("alias"): if value == command: output.append(key) return output + def get_alias_command(alias): command = alias - if has_section('alias'): - for key,value in config.items('alias'): + if has_section("alias"): + for key, value in config.items("alias"): if key == alias: command = value return command diff --git a/src/mepo/utilities/shellcmd.py b/src/mepo/utilities/shellcmd.py index f7359320..f69da200 100644 --- a/src/mepo/utilities/shellcmd.py +++ b/src/mepo/utilities/shellcmd.py @@ -1,11 +1,12 @@ import subprocess as sp + def run(cmd, output=None, stdout=None, status=None): result = sp.run( cmd, - stdout = sp.PIPE, - stderr = sp.PIPE, - universal_newlines = True # result byte sequence -> string + stdout=sp.PIPE, + stderr=sp.PIPE, + universal_newlines=True, # result byte sequence -> string ) if status: diff --git a/src/mepo/utilities/verify.py b/src/mepo/utilities/verify.py index d5fadf04..8e7dfa33 100644 --- a/src/mepo/utilities/verify.py +++ b/src/mepo/utilities/verify.py @@ -11,7 +11,9 @@ def valid_components(specified_comp_names, allcomps, ignore_case=False): """ # Make a list of all the component names depending on ignore_case - all_component_names = [x.name.casefold() if ignore_case else x.name for x in allcomps] + all_component_names = [ + x.name.casefold() if ignore_case else x.name for x in allcomps + ] # Loop over all the components we want to verify... for component_name in specified_comp_names: @@ -22,6 +24,7 @@ def valid_components(specified_comp_names, allcomps, ignore_case=False): # Validate the component _validate_component(component_to_find, all_component_names) + def _validate_component(component, all_components): """ Function to raise exception on invalid component name @@ -32,4 +35,4 @@ def _validate_component(component, all_components): """ if component not in all_components: - raise Exception('Unknown component name [{}]'.format(component)) + raise Exception("Unknown component name [{}]".format(component)) diff --git a/src/mepo/utilities/version.py b/src/mepo/utilities/version.py index 62d74ff1..aa4c70f2 100644 --- a/src/mepo/utilities/version.py +++ b/src/mepo/utilities/version.py @@ -1,27 +1,29 @@ from collections import namedtuple -MepoVersion = namedtuple('MepoVersion', ['name', 'type', 'detached']) +MepoVersion = namedtuple("MepoVersion", ["name", "type", "detached"]) -def version_to_string(version,git=None): - version_name = version[0] - version_type = version[1] + +def version_to_string(version, git=None): + version_name = version[0] + version_type = version[1] version_detached = version[2] - if version_detached: # detached head + if version_detached: # detached head # We remove the "origin/" from the internal detached branch name # for clarity in mepo status output - version_name = version_name.replace('origin/','') - if version_type == 'b' and git: + version_name = version_name.replace("origin/", "") + if version_type == "b" and git: cur_hash = git.rev_parse(short=True).strip() - s = f'({version_type}) {version_name} (DH, {cur_hash})' + s = f"({version_type}) {version_name} (DH, {cur_hash})" else: - s = f'({version_type}) {version_name} (DH)' + s = f"({version_type}) {version_name} (DH)" else: - s = f'({version_type}) {version_name}' + s = f"({version_type}) {version_name}" return s -def sanitize_version_string(orig,curr,git): - ''' + +def sanitize_version_string(orig, curr, git): + """ This routine tries to figure out if two tags are the same. The issue is that git sometimes returns the "wrong" tag in @@ -29,19 +31,19 @@ def sanitize_version_string(orig,curr,git): if that commit is also tagged with foo, then sometimes mepo will say that things have changed because it thinks it's on foo. - ''' + """ # The trick below only works on tags and hashes (I think), so # if not a tag or hash, just do nothing for now - is_tag = '(t)' - is_hash = '(h)' + is_tag = "(t)" + is_hash = "(h)" # For status, we pass in space-delimited strings that are: # 'type version dh' # So let's split into lists and pull the type # But for save, we are passing in one single string orig_list = orig.split() - if (len(orig_list) > 1): + if len(orig_list) > 1: # Pull out the type orig_type = orig_list[0] # Pull out the version string... @@ -53,7 +55,7 @@ def sanitize_version_string(orig,curr,git): orig_ver = orig_list[0] curr_list = curr.split() - if (len(curr_list) > 1): + if len(curr_list) > 1: # Pull out the type curr_type = curr_list[0] # Pull out the version string... @@ -64,8 +66,8 @@ def sanitize_version_string(orig,curr,git): # version is the only element curr_ver = curr_list[0] - orig_type_is_tag_or_hash = (orig_type == is_tag or orig_type == is_hash) - curr_type_is_tag_or_hash = (curr_type == is_tag or curr_type == is_hash) + orig_type_is_tag_or_hash = orig_type == is_tag or orig_type == is_hash + curr_type_is_tag_or_hash = curr_type == is_tag or curr_type == is_hash # Now if a type or hash... if orig_type_is_tag_or_hash and curr_type_is_tag_or_hash: @@ -84,7 +86,7 @@ def sanitize_version_string(orig,curr,git): curr_list[curr_list.index(curr_type)] = orig_type # And then remake the curr string - curr = ' '.join(curr_list) + curr = " ".join(curr_list) # And return curr return curr diff --git a/tests/test_mepo_commands.py b/tests/test_mepo_commands.py index 69c0125e..5aab6212 100644 --- a/tests/test_mepo_commands.py +++ b/tests/test_mepo_commands.py @@ -1,5 +1,6 @@ import os import sys + THIS_DIR = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0, os.path.join(THIS_DIR, "..", "src")) import shutil @@ -33,6 +34,7 @@ mepo_checkout_if_exists = importlib.import_module("mepo.command.checkout-if-exists") mepo_pull_all = importlib.import_module("mepo.command.pull-all") + class TestMepoCommands(unittest.TestCase): @classmethod @@ -66,9 +68,11 @@ def __mepo_clone(cls): allrepos=None, branch=None, directory=None, - partial="blobless",) + partial="blobless", + ) mepo_clone(args) - print(); sys.stdout.flush() + print() + sys.stdout.flush() @classmethod def setUpClass(cls): @@ -89,16 +93,17 @@ def setUp(self): pass def __mepo_status(self, saved_output): - '''saved_output is either a string or a filename''' + """saved_output is either a string or a filename""" os.chdir(self.__class__.fixture_dir) args = SimpleNamespace( ignore_permissions=False, nocolor=True, - hashes=False,) + hashes=False, + ) sys.stdout = output = StringIO() mepo_status(args) sys.stdout = sys.__stdout__ - try: # assume saved_output is a file + try: # assume saved_output is a file saved_output_s = self.__class__.__get_saved_output(saved_output) except FileNotFoundError: saved_output_s = saved_output @@ -106,7 +111,7 @@ def __mepo_status(self, saved_output): def __mepo_restore_state(self): os.chdir(self.__class__.fixture_dir) - sys.stdout = output = StringIO() # suppress output + sys.stdout = output = StringIO() # suppress output mepo_restore_state.run(SimpleNamespace()) sys.stdout = sys.__stdout__ self.__mepo_status(self.__class__.output_clone_status) @@ -124,8 +129,9 @@ def test_develop(self): os.chdir(self.__class__.fixture_dir) args = SimpleNamespace( comp_name=["env", "cmake", "fvdycore"], - quiet=False,) - sys.stdout = output = StringIO() # suppressing output to stdout + quiet=False, + ) + sys.stdout = output = StringIO() # suppressing output to stdout mepo_develop(args) sys.stdout = sys.__stdout__ self.__mepo_status("output_develop_status.txt") @@ -140,15 +146,17 @@ def test_checkout_compare(self): comp_name=["MAPL"], b=False, quiet=False, - detach=False,) - sys.stdout = output = StringIO() # suppress output + detach=False, + ) + sys.stdout = output = StringIO() # suppress output mepo_checkout(args) sys.stdout = sys.__stdout__ # Compare (default) args_cmp = SimpleNamespace( all=False, nocolor=True, - wrap=True,) + wrap=True, + ) sys.stdout = output = StringIO() mepo_compare(args_cmp) sys.stdout = sys.__stdout__ @@ -171,7 +179,8 @@ def test_checkout_if_exists(self): ref_name="not-expected-to-exist", quiet=True, detach=False, - dry_run=False,) + dry_run=False, + ) mepo_checkout_if_exists.run(args) # Since we do not expect this ref to exist, status should be that of clone self.__mepo_status(self.__class__.output_clone_status) @@ -182,7 +191,8 @@ def test_branch_list(self): args = SimpleNamespace( comp_name=["ecbuild"], all=True, - nocolor=True,) + nocolor=True, + ) sys.stdout = output = StringIO() mepo_branch_list(args) sys.stdout = sys.__stdout__ @@ -193,7 +203,8 @@ def test_branch_create_delete(self): os.chdir(self.__class__.fixture_dir) args = SimpleNamespace( comp_name=["ecbuild"], - branch_name="the-best-branch-ever",) + branch_name="the-best-branch-ever", + ) # Create branch sys.stdout = output = StringIO() mepo_branch_create(args) @@ -222,7 +233,8 @@ def test_tag_create_delete(self): comp_name=["FMS", "MAPL"], tag_name="new-awesome-tag", annotate=False, - message=None,) + message=None, + ) # Create tag sys.stdout = output = StringIO() mepo_tag_create(args) @@ -243,7 +255,8 @@ def test_fetch(self): all=True, prune=True, tags=True, - force=False,) + force=False, + ) sys.stdout = output = StringIO() mepo_fetch(args) sys.stdout = sys.__stdout__ @@ -254,7 +267,8 @@ def test_pull(self): os.chdir(self.__class__.fixture_dir) args = SimpleNamespace( comp_name=["FVdycoreCubed_GridComp"], - quiet=False,) + quiet=False, + ) err_msg = "FVdycoreCubed_GridComp has detached head! Cannot pull." with self.assertRaisesRegex(Exception, err_msg): mepo_pull(args) @@ -263,7 +277,8 @@ def test_pull_all(self): os.chdir(self.__class__.fixture_dir) args = SimpleNamespace( comp_name=["FVdycoreCubed_GridComp"], - quiet=False,) + quiet=False, + ) sys.stdout = output = StringIO() mepo_pull_all.run(args) sys.stdout = sys.__stdout__ @@ -274,7 +289,8 @@ def test_push(self): os.chdir(self.__class__.fixture_dir) args = SimpleNamespace( comp_name=["FVdycoreCubed_GridComp"], - quiet=False,) + quiet=False, + ) sys.stdout = output = StringIO() with self.assertRaises(sp.CalledProcessError): mepo_push(args) @@ -295,7 +311,8 @@ def test_diff(self): name_status=False, ignore_permissions=False, staged=False, - ignore_space_change=False,) + ignore_space_change=False, + ) sys.stdout = output = StringIO() mepo_diff(args) sys.stdout = sys.__stdout__ @@ -311,7 +328,8 @@ def test_whereis(self): os.chdir(self.__class__.fixture_dir) args = SimpleNamespace( comp_name=None, - ignore_case=False,) + ignore_case=False, + ) sys.stdout = output = StringIO() mepo_whereis(args) sys.stdout = sys.__stdout__ @@ -323,7 +341,8 @@ def test_reset(self): args = SimpleNamespace( force=True, reclone=False, - dry_run=False,) + dry_run=False, + ) sys.stdout = output = StringIO() mepo_reset(args) sys.stdout = sys.__stdout__ @@ -342,5 +361,6 @@ def tearDownClass(cls): os.chdir(THIS_DIR) shutil.rmtree(cls.tmpdir) + if __name__ == "__main__": unittest.main()