Example #1
0
    def handle_init(self, args):
        # Make sure it's safe to initialize
        if not args.force:
            # We aren't forcing
            if self.file_operator:
                print('Repo {} already initialized for git gud.'.format(self.file_operator.path))
                print('Use --force to initialize {}.'.format(os.getcwd()))
                return

            self.file_operator = Operator(os.getcwd(), initialize_repo=False)

            if os.path.exists(self.file_operator.git_path):
                # Current directory is a git repo
                print('Currently in a git repo. Use --force to force initialize here.')
                return
            if os.path.exists(self.file_operator.gg_path):
                # Current directory is a git repo
                print('Git gud has already initialized. Use --force to force initialize again.')
                return
            if len(os.listdir(self.file_operator.path)) != 0:
                print('Current directory is nonempty. Use --force to force initialize here.')
                return
        else:
            print('Force initializing git gud.')
            if not self.file_operator:
                self.file_operator = Operator(os.getcwd(), initialize_repo=False)

        # After here, we initialize everything
        try:
            self.file_operator.repo = Repo(self.file_operator.path)
        except InvalidGitRepositoryError:
            self.file_operator.repo = Repo.init(self.file_operator.path)

        if not os.path.exists(self.file_operator.gg_path):
            os.mkdir(self.file_operator.gg_path)

        python_exec = sys.executable.replace('\\', '/')  # Git uses unix-like path separators

        for git_hook_name, module_hook_name in all_hooks:
            path = os.path.join(self.file_operator.hooks_path, git_hook_name)
            with open(path, 'w+') as hook_file:
                hook_file.write('#!/bin/sh' + os.linesep)
                hook_file.write('' + python_exec + ' -m gitgud.hooks.' + module_hook_name + " $@" + os.linesep)
                hook_file.write(
                    "if [[ $? -ne 0 ]]" + os.linesep + "" \
                    "then" + os.linesep + "" \
                    "\t exit 1" + os.linesep+ "" \
                    "fi" + os.linesep)

            # Make the files executable

            mode = os.stat(path).st_mode
            mode |= (mode & 0o444) >> 2
            os.chmod(path, mode)

        print('Git Gud successfully setup in {}'.format(os.getcwd()))
        print('Welcome to Git Gud!')
        print()

        self.load_level(all_skills["1"]["1"])
Example #2
0
    def handle_init(self, args):
        # Make sure it's safe to initialize

        file_operator = get_operator()
        if file_operator:
            if not args.force:
                print('Repo {} already initialized for Git Gud.'.format(
                    file_operator.path))
                print('Use --force to initialize {}.'.format(Path.cwd()))
                if file_operator.path != Path.cwd():
                    print('{} will be left as is.'.format(
                        file_operator.gg_path))  # noqa: E501
                return
            else:
                print('Force initializing Git Gud.')
        elif len(list(Path.cwd().iterdir())) != 0:
            if not (args.force and args.prettyplease):
                print(
                    'Current directory is nonempty. Initializing will delete all files.'
                )  # noqa: E501
                print('Use --force --prettyplease to force initialize here.')
                return
            else:
                print('Deleting all files.')
                print('Initializing Git Gud.')

        file_operator = Operator(Path.cwd())
        file_operator.init_gg()

        print()

        self.load_level(all_skills["0"]["1"])
Example #3
0
    def handle_start(self, args):
        # Make sure it's safe to initialize
        if not args.force:
            # We aren't forcing
            if self.file_operator:
                print('Repo {} already initialized for git gud.'.format(self.file_operator.path))
                print('Use --force to initialize {}.'.format(os.getcwd()))
                return

            self.file_operator = Operator(os.getcwd(), initialize_repo=False)

            if os.path.exists(self.file_operator.git_path):
                # Current directory is a git repo
                print('Currently in a git repo. Use --force to force initialize here.')
                return
            if os.path.exists(self.file_operator.gg_path):
                # Current directory is a git repo
                print('Git gud has already initialized. Use --force to force initialize again.')
                return
            if len(os.listdir(self.file_operator.path)) != 0:
                print('Current directory is nonempty. Use --force to force initialize here.')
                return
        else:
            print('Force initializing git gud.')

        # After here, we initialize everything
        try:
            self.file_operator.repo = Repo(self.file_operator.path)
        except InvalidGitRepositoryError:
            self.file_operator.repo = Repo.init(self.file_operator.path)

        if not os.path.exists(self.file_operator.gg_path):
            os.mkdir(self.file_operator.gg_path)
        with open(self.file_operator.last_commit_path, 'w+') as commit_file:
            commit_file.write('0')  # First commit will be 1
        with open(self.file_operator.level_path, 'w+') as level_file:
            level1 = next(iter(all_levels.values()))
            challenge1 = next(iter(level1.challenges.values()))
            level_file.write(challenge1.full_name())

        python_exec = sys.executable.replace('\\', '/')  # Git uses unix-like path separators

        for git_hook_name, module_hook_name in all_hooks:
            with open(os.path.join(self.file_operator.hooks_path, git_hook_name), 'w+') as hook_file:
                hook_file.write('#!/bin/sh' + os.linesep)
                hook_file.write('cat - | ' + python_exec + ' -m gitgud.hooks.' + module_hook_name + ' $1' +os.linesep)
                hook_file.write('exit 0' + os.linesep)

        print('Git Gud successfully setup in {}'.format(os.getcwd()))

        self.file_operator.get_challenge().setup(self.file_operator)
Example #4
0
    def handle_start(self, args):
        if not args.force:
            # We aren't forcing
            if self.file_operator:
                print('Repo {} already initialized for git gud.'.format(
                    self.file_operator.path))
                print('Use --force to initialize {}.'.format(os.getcwd()))
                return

            self.file_operator = Operator(os.getcwd())

            if os.path.exists(self.file_operator.git_path):
                # Current directory is a git repo
                print(
                    'Currently in a git repo. Use --force to force initialize here.'
                )
                return
            if os.path.exists(self.file_operator.gg_path):
                # Current directory is a git repo
                print(
                    'Git gud has already initialized. Use --force to force initialize again.'
                )
                return
            if len(os.listdir(self.file_operator.path)) != 0:
                print(
                    'Current directory is nonempty. Use --force to force initialize here.'
                )
                return
        else:
            print('Force initializing git gud.')

        # After here, we initialize everything
        self.file_operator.initialize()

        if not os.path.exists(self.file_operator.gg_path):
            os.mkdir(self.file_operator.gg_path)
        with open(self.file_operator.last_commit_path, 'w+') as commit_file:
            commit_file.write('0')  # First commit will be 1
        with open(self.file_operator.level_path, 'w+') as level_file:
            level_file.write('intro commits')

        print('Git Gud successfully setup in {}'.format(os.getcwd()))

        self.file_operator.get_challenge().setup(self.file_operator)
Example #5
0
    def handle_init(self, args):
        # Make sure it's safe to initialize

        file_operator = get_operator()
        if file_operator:
            if not args.force:
                repo_already_initialized()
                return
            else:
                force_initializing()
        elif len(list(Path.cwd().iterdir())) != 0:
            if not (args.force and args.prettyplease):
                cant_init_repo_not_empty()
                return
            else:
                deleting_and_initializing()

        file_operator = Operator(Path.cwd())
        file_operator.init_gg()

        self.load_level(all_skills["0"]["1"])
Example #6
0
class GitGud:
    def __init__(self):
        self.file_operator = get_operator(
        )  # Only gets operator if in a valid gitgud repo

        self.parser = argparse.ArgumentParser(prog='git gud')

        subparsers = self.parser.add_subparsers(title='Subcommands',
                                                metavar='<command>',
                                                dest='command')

        # TODO Add git gud help <command>, which would return the same output as git gud <command> -- help

        # TODO Display help message for subcommand when it fails.
        # ie `git gud load level1 challenge1 random-input` should have output similar to `git gud load --help`

        start_parser = subparsers.add_parser('start', help='Git started!')
        status_parser = subparsers.add_parser(
            'status', help='Print out the current level')
        instructions_parser = subparsers.add_parser(
            'instructions', help='Show the instructions for the current level')
        reset_parser = subparsers.add_parser('reset',
                                             help='Reset the current level')
        test_parser = subparsers.add_parser(
            'test',
            help=
            'Test to see if you\'ve successfully completed the current level')
        progress_parser = subparsers.add_parser(
            'progress', help='Continue to the next level')
        levels_parser = subparsers.add_parser('levels', help='List levels')
        challenges_parser = subparsers.add_parser(
            'challenges',
            help=
            'List challenges in current level or in other level if specified')
        load_parser = subparsers.add_parser(
            'load', help='Load a specific level or challenge')
        commit_parser = subparsers.add_parser(
            'commit', help='Quickly create and commit a file')
        goal_parser = subparsers.add_parser(
            'goal', help='Show a description of the current goal')
        show_tree_parser = subparsers.add_parser(
            'show-tree', help='Show the current state of the branching tree')

        start_parser.add_argument('--force', action='store_true')

        challenges_parser.add_argument('level_name',
                                       metavar='level',
                                       nargs='?')

        load_parser.add_argument('level_name',
                                 metavar='level',
                                 help='Level to load')
        load_parser.add_argument('challenge_name',
                                 metavar='challenge',
                                 nargs='?',
                                 help='Challenge to load')

        commit_parser.add_argument('file', nargs='?')

        self.command_dict = {
            'start': self.handle_start,
            'status': self.handle_status,
            'instructions': self.handle_instructions,
            'reset': self.handle_reset,
            'test': self.handle_test,
            'progress': self.handle_progress,
            'levels': self.handle_levels,
            'challenges': self.handle_challenges,
            'load': self.handle_load,
            'commit': self.handle_commit,
            'goal': self.handle_goal,
            'show_tree': self.handle_show_tree,
        }

    def is_initialized(self):
        return self.file_operator is not None

    def assert_initialized(self):
        if not self.is_initialized():
            raise InitializationError(
                "Git gud not initialized. Use \"git gud start\" to initialize")

    def handle_start(self, args):
        if not args.force:
            # We aren't forcing
            if self.file_operator:
                print('Repo {} already initialized for git gud.'.format(
                    self.file_operator.path))
                print('Use --force to initialize {}.'.format(os.getcwd()))
                return

            self.file_operator = Operator(os.getcwd())

            if os.path.exists(self.file_operator.git_path):
                # Current directory is a git repo
                print(
                    'Currently in a git repo. Use --force to force initialize here.'
                )
                return
            if os.path.exists(self.file_operator.gg_path):
                # Current directory is a git repo
                print(
                    'Git gud has already initialized. Use --force to force initialize again.'
                )
                return
            if len(os.listdir(self.file_operator.path)) != 0:
                print(
                    'Current directory is nonempty. Use --force to force initialize here.'
                )
                return
        else:
            print('Force initializing git gud.')

        # After here, we initialize everything
        self.file_operator.initialize()

        if not os.path.exists(self.file_operator.gg_path):
            os.mkdir(self.file_operator.gg_path)
        with open(self.file_operator.last_commit_path, 'w+') as commit_file:
            commit_file.write('0')  # First commit will be 1
        with open(self.file_operator.level_path, 'w+') as level_file:
            level_file.write('intro commits')

        print('Git Gud successfully setup in {}'.format(os.getcwd()))

        self.file_operator.get_challenge().setup(self.file_operator)

    def handle_status(self, args):
        if self.is_initialized():
            challenge_name = self.file_operator.get_challenge().full_name()
            print("Currently on challenge: \"{}\"".format(challenge_name))
        else:
            print("Git gud not initialized.")
            print("Initialize using \"git gud start\"")

    def handle_instructions(self, args):
        self.assert_initialized()
        self.file_operator.get_challenge().instructions()

    def handle_reset(self, args):
        self.assert_initialized()

        challenge = self.file_operator.get_challenge()
        print("Resetting...")
        challenge.setup(self.file_operator)

    def handle_test(self, args):
        self.assert_initialized()
        challenge = self.file_operator.get_challenge()

        if challenge.test(self.file_operator):
            print(
                "Level complete! `git gud progress` to advance to the next level"
            )
        else:
            print(
                "Level not complete, keep trying. `git gud reset` to start from scratch."
            )

    def handle_progress(self, args):
        self.assert_initialized()

        print("Progressing to next level...")

        challenge = self.file_operator.get_challenge()

        next_challenge = challenge.next_challenge
        if next_challenge is not None:
            next_challenge.setup(self.file_operator)
            self.file_operator.write_challenge(next_challenge)
        else:
            print("Wow! You've complete every challenge, congratulations!")
            print(
                "If you want to keep learning git, why not try contributing to git-gud by forking us at https://github.com/bthayer2365/git-gud/"
            )
            print(
                "We're always looking for contributions and are more than happy to accept both pull requests and suggestions!"
            )

    def handle_levels(self, args):
        cur_level = self.file_operator.get_challenge().level

        print("Currently on level: \"{}\"\n".format(cur_level.name))

        for level in all_levels.values():
            # TODO Make pretty
            # TODO Add description
            print(level.name, ": {} challenges".format(len(level.challenges)))

    def handle_challenges(self, args):
        if args.level_name is None:
            level = self.file_operator.get_challenge().level
        else:
            level = all_levels[args.level_name]

        print("Printing challenges for level: \"{level.name}\"\n".format(
            level.name))

        for challenge in level.challenges.values():
            print(challenge.name)

    def handle_load(self, args):
        self.assert_initialized()

        level = all_levels[args.level_name]

        if args.challenge_name is not None:
            level.challenges[args.challenge_name].setup(self.file_operator)
        else:
            first_level = next(iter(level.challenges.values()))
            first_level.setup(self.file_operator)

    def handle_commit(self, args):
        self.assert_initialized()

        last_commit = self.file_operator.get_last_commit()
        commit_name = str(int(last_commit) + 1)

        if args.file is not None:
            try:
                int(args.file)
                commit_name = args.file
            except ValueError:
                pass

        print("Simulating: Create file \"{}\"".format(commit_name))
        print("Simulating: git add {}".format(commit_name))
        print("Simulating: git commit -m \"{}\"".format(commit_name))

        self.file_operator.add_and_commit(commit_name)

        # Check if the newest commit is greater than the last_commit, if yes, then write

        if int(commit_name) > int(last_commit):
            self.file_operator.write_last_commit(commit_name)

    def handle_goal(self, args):
        self.assert_initialized()
        raise NotImplementedError

    def handle_show_tree(self, args):
        raise NotImplementedError

    def parse(self):
        args = self.parser.parse_args()
        if args.command is None:
            self.parser.print_help()
        else:
            try:
                self.command_dict[args.command](args)
            except InitializationError:
                print(
                    "Git gud has not been initialized. Initialize using \"git gud start\""
                )
                pass
Example #7
0
class GitGud:
    def __init__(self):
        self.file_operator = get_operator(
        )  # Only gets operator if in a valid gitgud repo

        self.parser = argparse.ArgumentParser(prog='git gud')

        self.subparsers = self.parser.add_subparsers(title='Subcommands',
                                                     metavar='<command>',
                                                     dest='command')

        # TODO Add git gud help <command>, which would return the same output as git gud <command> -- help

        # TODO Display help message for subcommand when it fails.
        # ie `git gud load level1 challenge1 random-input` should have output similar to `git gud load --help`

        # Use "git gud help" to print helps of all subcommands.
        # "git gud help <command>" prints the description of the <command> but not help.
        # TODO Add longer descriptions

        help_parser = self.subparsers.add_parser(
            'help',
            help='Show help for commands',
            description='Show help for commands')
        start_parser = self.subparsers.add_parser('start',
                                                  help='Git started!',
                                                  description='Git started!')
        status_parser = self.subparsers.add_parser(
            'status',
            help='Print out the name of the current challenge',
            description='Print out the name of the current challenge')
        instructions_parser = self.subparsers.add_parser(
            'instructions',
            help='Show the instructions for the current challenge',
            description='Show the instructions for the current challenge')
        goal_parser = self.subparsers.add_parser(
            'goal',
            help=
            'Concisely show what needs to be done to complete the challenge.',
            description=
            'Concisely show what needs to be done to complete the challenge.')
        reset_parser = self.subparsers.add_parser(
            'reset',
            help='Reset the current challenge',
            description='Reset the current challenge')
        reload_parser = self.subparsers.add_parser(
            'reload',
            help=
            'Reset the current challenge. Reload command is an alias for reset command.',
            description=
            'Reset the current challenge. Reload command is an alias for reset command.'
        )
        test_parser = self.subparsers.add_parser(
            'test',
            help=
            'Test to see if you\'ve successfully completed the current challenge',
            description=
            'Test to see if you\'ve successfully completed the current challenge'
        )
        progress_parser = self.subparsers.add_parser(
            'progress',
            help='Continue to the next challenge',
            description='Continue to the next challenge')
        levels_parser = self.subparsers.add_parser('levels',
                                                   help='List levels',
                                                   description='List levels')
        challenges_parser = self.subparsers.add_parser(
            'challenges',
            help='List challenges',
            description=
            'List challenges in current level or in other level if specified')
        load_parser = self.subparsers.add_parser(
            'load',
            help='Load a specific level or challenge',
            description='Load a specific level or challenge')
        commit_parser = self.subparsers.add_parser(
            'commit',
            help='Quickly create and commit a file',
            description='Quickly create and commit a file')
        goal_parser = self.subparsers.add_parser(
            'goal',
            help='Show a description of the current goal',
            description='Show a description of the current goal')
        show_tree_parser = self.subparsers.add_parser(
            'show-tree',
            help='Show the current state of the branching tree',
            description='Show the current state of the branching tree')
        contrib_parser = self.subparsers.add_parser(
            'contributors',
            help='Show all the contributors of the project',
            description='Show all the contributors of the project')

        help_parser.add_argument('command_name',
                                 metavar='<command>',
                                 nargs='?')

        start_parser.add_argument('--force', action='store_true')

        challenges_parser.add_argument('level_name',
                                       metavar='level',
                                       nargs='?')

        load_parser.add_argument('level_name',
                                 metavar='level',
                                 help='Level to load')
        load_parser.add_argument('challenge_name',
                                 metavar='challenge',
                                 nargs='?',
                                 help='Challenge to load')

        commit_parser.add_argument('file', nargs='?')

        self.command_dict = {
            'help': self.handle_help,
            'start': self.handle_start,
            'status': self.handle_status,
            'instructions': self.handle_instructions,
            'goal': self.handle_goal,
            'reset': self.handle_reset,
            'reload': self.handle_reset,
            'test': self.handle_test,
            'progress': self.handle_progress,
            'levels': self.handle_levels,
            'challenges': self.handle_challenges,
            'load': self.handle_load,
            'commit': self.handle_commit,
            'show-tree': self.handle_show_tree,
            'contributors': self.handle_contrib,
        }

    def is_initialized(self):
        return self.file_operator is not None

    def assert_initialized(self):
        if not self.is_initialized():
            raise InitializationError(
                "Git gud not initialized. Use \"git gud start\" to initialize")

    def load_challenge(self, challenge):
        challenge.setup(self.file_operator)
        self.file_operator.write_challenge(challenge)
        show_tree()

    def handle_help(self, args):
        if args.command_name is None:
            self.parser.print_help()
        else:
            try:
                self.subparsers.choices[args.command_name].print_help()
            except KeyError:
                print('No such command exists: \"{}\"\n'.format(
                    args.command_name))
                self.parser.print_help()

    def handle_start(self, args):
        # Make sure it's safe to initialize
        if not args.force:
            # We aren't forcing
            if self.file_operator:
                print('Repo {} already initialized for git gud.'.format(
                    self.file_operator.path))
                print('Use --force to initialize {}.'.format(os.getcwd()))
                return

            self.file_operator = Operator(os.getcwd(), initialize_repo=False)

            if os.path.exists(self.file_operator.git_path):
                # Current directory is a git repo
                print(
                    'Currently in a git repo. Use --force to force initialize here.'
                )
                return
            if os.path.exists(self.file_operator.gg_path):
                # Current directory is a git repo
                print(
                    'Git gud has already initialized. Use --force to force initialize again.'
                )
                return
            if len(os.listdir(self.file_operator.path)) != 0:
                print(
                    'Current directory is nonempty. Use --force to force initialize here.'
                )
                return
        else:
            print('Force initializing git gud.')
            if not self.file_operator:
                self.file_operator = Operator(os.getcwd(),
                                              initialize_repo=False)

        # After here, we initialize everything
        try:
            self.file_operator.repo = Repo(self.file_operator.path)
        except InvalidGitRepositoryError:
            self.file_operator.repo = Repo.init(self.file_operator.path)

        if not os.path.exists(self.file_operator.gg_path):
            os.mkdir(self.file_operator.gg_path)
        with open(self.file_operator.last_commit_path, 'w+') as commit_file:
            commit_file.write('0')  # First commit will be 1
        with open(self.file_operator.level_path, 'w+') as level_file:
            level_file.write(all_levels[0][0].full_name())

        python_exec = sys.executable.replace(
            '\\', '/')  # Git uses unix-like path separators

        for git_hook_name, module_hook_name in all_hooks:
            with open(
                    os.path.join(self.file_operator.hooks_path, git_hook_name),
                    'w+') as hook_file:
                hook_file.write('#!/bin/sh' + os.linesep)
                hook_file.write('cat - | ' + python_exec +
                                ' -m gitgud.hooks.' + module_hook_name +
                                ' "$@"' + os.linesep)
                hook_file.write('exit 0' + os.linesep)

        print('Git Gud successfully setup in {}'.format(os.getcwd()))

        self.file_operator.get_challenge().setup(self.file_operator)
        show_tree()

    def handle_status(self, args):
        if self.is_initialized():
            challenge_name = self.file_operator.get_challenge().full_name()
            print("Currently on challenge: \"{}\"".format(challenge_name))
        else:
            print("Git gud not initialized.")
            print("Initialize using \"git gud start\"")

    def handle_instructions(self, args):
        self.assert_initialized()
        self.file_operator.get_challenge().instructions()

    def handle_goal(self, args):
        self.assert_initialized()
        self.file_operator.get_challenge().goal()

    def handle_reset(self, args):
        self.assert_initialized()

        challenge = self.file_operator.get_challenge()
        print("Resetting...")
        challenge.setup(self.file_operator)
        show_tree()

    def handle_test(self, args):
        self.assert_initialized()
        challenge = self.file_operator.get_challenge()

        if challenge.test(self.file_operator):
            try:
                if challenge.next_challenge.level != challenge.level:
                    print(
                        "Challenge complete, you've completed this level! `git gud progress` to advance to the next level"
                    )
                    print("Next level is: {}".format(
                        challenge.next_challenge.level.name))
                else:
                    print(
                        "Challenge complete! `git gud progress` to advance to the next challenge"
                    )
                    print("Next challenge is: {}".format(
                        challenge.next_challenge.full_name()))
            except AttributeError:
                print("All challenges completed!")
        else:
            print(
                "Challenge not complete, keep trying. `git gud reset` to start from scratch."
            )

    def handle_progress(self, args):
        self.assert_initialized()

        print("Progressing to next level...")

        challenge = self.file_operator.get_challenge()

        next_challenge = challenge.next_challenge
        if next_challenge is not None:
            self.load_challenge(next_challenge)
        else:
            print("Wow! You've complete every challenge, congratulations!")
            print(
                "If you want to keep learning git, why not try contributing to git-gud by forking us at https://github.com/bthayer2365/git-gud/"
            )
            print(
                "We're always looking for contributions and are more than happy to accept both pull requests and suggestions!"
            )

    def handle_levels(self, args):
        cur_level = self.file_operator.get_challenge().level

        print("Currently on level: \"{}\"\n".format(cur_level.name))

        for level in all_levels:
            # TODO Add description
            # 10 characters for the short IDs.
            print("Level {:<10} :{:>2} challenge{}".format(
                "\"" + level.name + "\"", len(level),
                ("", "s")[len(level) > 1]))
            for index, challenge in enumerate(level):
                # " " * (characters allocated for ID - 6)
                print("{}Challenge {:>2} : {:<10}".format(
                    " " * 4, index + 1, challenge.name))

    def handle_challenges(self, args):
        key_error_flag = False
        if args.level_name is None:
            level = self.file_operator.get_challenge().level
        else:
            try:
                level = all_levels[args.level_name]
            except KeyError:
                print("There is no level \"{}\".".format(args.level_name))
                print(
                    "You may run \"git gud levels\" to print all the levels. \n"
                )
                level = self.file_operator.get_challenge().level
                key_error_flag = True

        if key_error_flag == True or args.level_name is None:
            print("Challenges in the current level \"{}\" : \n".format(
                level.name))
        else:
            print("Challenges for level \"{}\" : \n".format(level.name))

        for index, challenge in enumerate(level):
            print(str(index + 1) + ": " + challenge.name)

    def handle_load(self, args):
        self.assert_initialized()
        if args.level_name in all_levels:
            level = all_levels[args.level_name]

            if args.challenge_name is not None:
                if args.challenge_name in all_levels[args.level_name]:
                    challenge = level[args.challenge_name]
                    self.load_challenge(challenge)
                else:
                    print("Challenge \"{}\" does not exist".format(
                        args.challenge_name))
                    print(
                        "To view challenges/levels, use git gud challenges or git gud levels"
                    )
            else:
                self.load_challenge(level[0])
        else:
            print("Level \"{}\" does not exist".format(args.level_name))
            print(
                "To view challenges/levels, use git gud challenges or git gud levels"
            )

    def handle_commit(self, args):
        self.assert_initialized()

        last_commit = self.file_operator.get_last_commit()
        commit_name = str(int(last_commit) + 1)

        if args.file is not None:
            try:
                int(args.file)
                commit_name = args.file
            except ValueError:
                pass

        print("Simulating: Create file \"{}\"".format(commit_name))
        print("Simulating: git add {}".format(commit_name))
        print("Simulating: git commit -m \"{}\"".format(commit_name))

        commit = self.file_operator.add_and_commit(commit_name)
        print("New Commit: {}".format(commit.hexsha[:7]))

        # Check if the newest commit is greater than the last_commit, if yes, then write

        if int(commit_name) > int(last_commit):
            self.file_operator.write_last_commit(commit_name)

    def handle_show_tree(self, args):
        show_tree()

    def handle_contrib(self, args):
        contrib_website = "https://github.com/bthayer2365/git-gud/graphs/contributors"
        webbrowser.open_new(contrib_website)

    def parse(self):
        args, _ = self.parser.parse_known_args()
        if args.command is None:
            self.parser.print_help()
        else:
            try:
                self.command_dict[args.command](args)
            except InitializationError:
                print(
                    "Git gud has not been initialized. Initialize using \"git gud start\""
                )
                pass
Example #8
0
class GitGud:
    def __init__(self):
        self.file_operator = get_operator()  # Only gets operator if Git Gud has been initialized

        self.parser = argparse.ArgumentParser(prog='git gud')

        load_description = '\n'.join([
            "Load a specific skill or level. This command can be used in several ways.",
            "\n",
            "============Basic Usage============",
            "\n",
            "These commands are the simplest commands to load a level on a certain skill, and are identical in functionality:",
            "\n",
            "   git gud load <skill> <level>",
            "   git gud load <skill>-<level>",
            "\n",
            "<skill> and <level> could either be the name of the skill/level or the number of the skill/level.",
            "Running `git gud skills` will help you find the number and name associated with each skill/level.",
            "\n",
            "Here are example uses which load the same level:",
            "\n",
            "   git gud load basics-2",
            "   git gud load 1 branching",
            "\n",
            "============Additional Commands============",
            "\n",
            "`git gud load` supports additional shortcut commands to ease level navigation.",
            "\n",
            "======Loading the first level on a skill======",
            "\n",
            "This command loads the first level on the specified skill:",
            "\n",
            "   git gud load <skill>",
            "\n",
            "======Loading a level on the current skill======",
            "\n",
            "This command loads the specified level of the current skill.",
            "NOTE: <level> MUST be a number in order for this command to work.",
            "\n",
            "   git gud load -<level>",
            "\n",
        ])
        self.subparsers = self.parser.add_subparsers(title='Subcommands', metavar='<command>', dest='command')

        help_parser = self.subparsers.add_parser('help', help='Show help for commands', description='Show help for commands')
        init_parser = self.subparsers.add_parser('init', help='Init Git Gud and load first level', description='Initialize the direcotry with a git repository and load the first level of Git Gud.')
        status_parser = self.subparsers.add_parser('status', help='Print out the name of the current level', description='Print out the name of the current level')
        instructions_parser = self.subparsers.add_parser('instructions', help='Show the instructions for the current level', description='Show the instructions for the current level')
        goal_parser = self.subparsers.add_parser('goal', help='Concisely show what needs to be done to complete the level.', description='Concisely show what needs to be done to complete the level.')
        reset_parser = self.subparsers.add_parser('reset', help='Reset the current level', description='Reset the current level')
        reload_parser = self.subparsers.add_parser('reload', help='Alias for reset', description='Reset the current level. Reload command is an alias for reset command.')
        test_parser = self.subparsers.add_parser('test', help="Test to see if you've successfully completed the current level", description="Test to see if you've successfully completed the current level")
        skills_parser = self.subparsers.add_parser('skills', help='List skills', description='List skills')
        levels_parser = self.subparsers.add_parser('levels', help='List levels in a skill', description='List the levels in the specified skill or in the current skill if Git Gud has been initialized and no skill is provided.')
        load_parser = self.subparsers.add_parser('load', help='Load a specific skill or level', description=load_description, formatter_class=argparse.RawDescriptionHelpFormatter)
        commit_parser = self.subparsers.add_parser('commit', help='Quickly create and commit a file', description='Quickly create and commit a file')
        goal_parser = self.subparsers.add_parser('goal', help='Show a description of the current goal', description='Show a description of the current goal')
        show_tree_parser = self.subparsers.add_parser('show-tree', help='Show the current state of the branching tree', description='Show the current state of the branching tree')
        contrib_parser = self.subparsers.add_parser('contributors', help='Show project contributors webpage', description='Show all the contributors of the project')
        issues_parser = self.subparsers.add_parser('issues', help='Show project issues webpage', description="Show all the issues for the project")
        
        help_parser.add_argument('command_name', metavar='<command>', nargs='?')

        init_parser.add_argument('--force', action='store_true')

        levels_parser.add_argument('skill_name', metavar='skill', nargs='?')

        load_parser.add_argument('skill_name', metavar='skill', help='Skill to load')
        load_parser.add_argument('level_name', metavar='level', nargs='?', help='Level to load')

        commit_parser.add_argument('file', nargs='?')

        self.command_dict = {
            'help': self.handle_help,
            'init': self.handle_init,
            'status': self.handle_status,
            'instructions': self.handle_instructions,
            'goal': self.handle_goal,
            'reset': self.handle_reset,
            'reload': self.handle_reset,
            'test': self.handle_test,
            'skills': self.handle_skills,
            'levels': self.handle_levels,
            'load': self.handle_load,
            'commit': self.handle_commit,
            'show-tree': self.handle_show_tree,
            'contributors': self.handle_contrib,
            'issues': self.handle_issues    
        }

    def is_initialized(self):
        return self.file_operator is not None

    def assert_initialized(self, skip_level_check=False):
        if not self.is_initialized():
            raise InitializationError('Git gud has not been initialized. Use "git gud init" to initialize')

        if not skip_level_check:
            try:
                self.file_operator.get_level()
            except KeyError:
                level_name = self.file_operator.read_level_file()
                raise InitializationError('Currently loaded level does not exist: "{}"'.format(level_name))

    def load_level(self, level):
        level.setup(self.file_operator)
        self.file_operator.write_level(level)
        show_tree()

    def handle_help(self, args):
        if args.command_name is None:
            self.parser.print_help()
        else:
            try:
                self.subparsers.choices[args.command_name].print_help()
            except KeyError:
                print('No such command exists: "{}"\n'.format(args.command_name))
                self.parser.print_help()

    def handle_init(self, args):
        # Make sure it's safe to initialize
        if not args.force:
            # We aren't forcing
            if self.file_operator:
                print('Repo {} already initialized for git gud.'.format(self.file_operator.path))
                print('Use --force to initialize {}.'.format(os.getcwd()))
                return

            self.file_operator = Operator(os.getcwd(), initialize_repo=False)

            if os.path.exists(self.file_operator.git_path):
                # Current directory is a git repo
                print('Currently in a git repo. Use --force to force initialize here.')
                return
            if os.path.exists(self.file_operator.gg_path):
                # Current directory is a git repo
                print('Git gud has already initialized. Use --force to force initialize again.')
                return
            if len(os.listdir(self.file_operator.path)) != 0:
                print('Current directory is nonempty. Use --force to force initialize here.')
                return
        else:
            print('Force initializing git gud.')
            if not self.file_operator:
                self.file_operator = Operator(os.getcwd(), initialize_repo=False)

        # After here, we initialize everything
        try:
            self.file_operator.repo = Repo(self.file_operator.path)
        except InvalidGitRepositoryError:
            self.file_operator.repo = Repo.init(self.file_operator.path)

        if not os.path.exists(self.file_operator.gg_path):
            os.mkdir(self.file_operator.gg_path)

        python_exec = sys.executable.replace('\\', '/')  # Git uses unix-like path separators

        for git_hook_name, module_hook_name in all_hooks:
            path = os.path.join(self.file_operator.hooks_path, git_hook_name)
            with open(path, 'w+') as hook_file:
                hook_file.write('#!/bin/sh' + os.linesep)
                hook_file.write('' + python_exec + ' -m gitgud.hooks.' + module_hook_name + " $@" + os.linesep)
                hook_file.write(
                    "if [[ $? -ne 0 ]]" + os.linesep + "" \
                    "then" + os.linesep + "" \
                    "\t exit 1" + os.linesep+ "" \
                    "fi" + os.linesep)

            # Make the files executable

            mode = os.stat(path).st_mode
            mode |= (mode & 0o444) >> 2
            os.chmod(path, mode)

        print('Git Gud successfully setup in {}'.format(os.getcwd()))
        print('Welcome to Git Gud!')
        print()

        self.load_level(all_skills["1"]["1"])

    def handle_status(self, args):
        if self.is_initialized():
            try:
                level = self.file_operator.get_level()
                print('Currently on level: "{}"'.format(level.full_name()))
            except KeyError:
                level_name = self.file_operator.read_level_file()
                print('Currently on unregistered level: "{}"'.format(level_name))
        else:
            print("Git gud not initialized.")
            print('Initialize using "git gud init"')

    def handle_instructions(self, args):
        self.assert_initialized()
        self.file_operator.get_level().instructions()

    def handle_goal(self, args):
        self.assert_initialized()
        self.file_operator.get_level().goal()

    def handle_reset(self, args):
        self.assert_initialized()

        level = self.file_operator.get_level()
        print("Resetting...")
        level.setup(self.file_operator)
        show_tree()

    def handle_test(self, args):
        self.assert_initialized()
        level = self.file_operator.get_level()
        level.test(self.file_operator)

    def handle_skills(self, args):
        if self.is_initialized():
            try:
                cur_skill = self.file_operator.get_level().skill
                print('Currently on skill: "{}"'.format(cur_skill.name))
                print()
            except KeyError:
                pass
        
        skill_chars = max(len(skill.name) for skill in all_skills)
        skill_format_template = 'Skill {{}} - "{{:<{}}}" :{{:>2}} level{{}}'.format(skill_chars)
        level_format_template = "    Level {:>2} : {:<3}"
        
        for i, skill in enumerate(all_skills):
            # TODO Add description
            print(skill_format_template.format(i + 1, skill.name, len(skill), ("", "s")[len(skill) > 1]))

            for index, level in enumerate(skill):
                print(level_format_template.format(index + 1, level.name))
        
        print("\nLoad a level with `git gud load`")
        
    def handle_levels(self, args):
        key_error_flag = False
        if args.skill_name is None:
            if self.file_operator is None:
                self.subparsers.choices['levels'].print_help()
                return

            try:
                skill = self.file_operator.get_level().skill
            except KeyError:
                skill_name = self.file_operator.read_level_file().split()[0]
                print('Cannot find any levels in skill: "{}"'.format(skill_name))
                return
        else:
            try:
                skill = all_skills[args.skill_name]
            except KeyError:
                print('There is no skill "{}".'.format(args.skill_name))
                print('You may run "git gud skills" to print all the skills. \n')
                skill = self.file_operator.get_level().skill
                key_error_flag = True
        
        if key_error_flag or args.skill_name is None:
            print('Levels in the current skill "{}" : \n'.format(skill.name))
        else:
            print('Levels for skill "{}" : \n'.format(skill.name))

        for index, level in enumerate(skill):
            print(str(index + 1) + ": " + level.name)

        print('\nTo see levels in all skills, run "git gud skills".')

    def handle_load(self, args):
        self.assert_initialized(skip_level_check=True)

        argskillset = args.skill_name.split("-", 1)
        
        # Set up args.level_name and args.skill_name
        if args.level_name:
            if args.skill_name is "-":
                # Replace the dash with the current skill's name.
                args.skill_name = self.file_operator.get_level().skill.name
        else:
            if len(argskillset) == 2:   
                args.skill_name, args.level_name = tuple(argskillset)
            else:
                args.skill_name, args.level_name = argskillset[0], None

        skill_to_load = self.file_operator.get_level().skill.name
        if args.skill_name:
            if args.skill_name.lower() in {"next", "prev", "previous"}:
                query = args.skill_name.lower()
                level = self.file_operator.get_level()
                                
                if query == "next":
                    level_to_load = level.next_level
                else:
                    query = "previous"
                    level_to_load = level.prev_level
                
                print("Loading the {} level...\n".format(query))

                if level_to_load is not None:
                    self.load_level(level_to_load)
                else:
                    print('To view levels/skills, use "git gud levels" or "git gud skills"\n')
                    if query == "next":
                        print_all_complete()
                    else:
                        print('Already on the first level. To reload the level, use "git gud reload".')
                return
            else:
                skill_to_load = args.skill_name
        
        level_to_load = '1'
        if args.level_name:
            level_to_load = args.level_name

        if skill_to_load in all_skills.keys():
            skill = all_skills[skill_to_load]
            if level_to_load in skill.keys():
                    level = skill[level_to_load]
                    self.load_level(level)
            else:
                print('Level "{}" does not exist'.format(args.level_name))
                print('To view levels/skills, use "git gud levels" or "git gud skills"\n')
        else:
            print('Skill "{}" does not exist'.format(args.skill_name))
            print('To view levels/skills, use "git gud levels" or "git gud skills"\n')


    def handle_commit(self, args):
        self.assert_initialized()

        last_commit = self.file_operator.get_last_commit()
        commit_name = str(int(last_commit) + 1)

        if args.file is not None:
            try:
                int(args.file)
                commit_name = args.file
            except ValueError:
                pass

        print('Simulating: Create file "{}"'.format(commit_name))
        print('Simulating: git add {}'.format(commit_name))
        print('Simulating: git commit -m "{}"'.format(commit_name))

        commit = self.file_operator.add_and_commit(commit_name)
        print("New Commit: {}".format(commit.hexsha[:7]))

        # Check if the newest commit is greater than the last_commit, if yes, then write

        if int(commit_name) > int(last_commit):
            self.file_operator.write_last_commit(commit_name)

    def handle_show_tree(self, args):
        show_tree()

    def handle_contrib(self, args):
        contrib_website = "https://github.com/benthayer/git-gud/graphs/contributors"
        webbrowser.open_new(contrib_website)

    def handle_issues(self, args):
        issues_website = "https://github.com/benthayer/git-gud/issues"
        webbrowser.open_new(issues_website)
    
    def parse(self):
        args, _ = self.parser.parse_known_args()
        if args.command is None:
            self.parser.print_help()
        else:
            try:
                self.command_dict[args.command](args)
            except InitializationError as error:
                print(error)
Example #9
0
class GitGud:
    def __init__(self):
        self.file_operator = get_operator(
        )  # Only gets operator if Git Gud has been initialized

        self.parser = argparse.ArgumentParser(prog='git gud')

        self.subparsers = self.parser.add_subparsers(title='Subcommands',
                                                     metavar='<command>',
                                                     dest='command')

        help_parser = self.subparsers.add_parser(
            'help',
            help='Show help for commands',
            description='Show help for commands')
        init_parser = self.subparsers.add_parser(
            'init',
            help='Init Git Gud and load first level',
            description=
            'Initialize the direcotry with a git repository and load the first level of Git Gud.'
        )
        status_parser = self.subparsers.add_parser(
            'status',
            help='Print out the name of the current level',
            description='Print out the name of the current level')
        instructions_parser = self.subparsers.add_parser(
            'instructions',
            help='Show the instructions for the current level',
            description='Show the instructions for the current level')
        goal_parser = self.subparsers.add_parser(
            'goal',
            help='Concisely show what needs to be done to complete the level.',
            description=
            'Concisely show what needs to be done to complete the level.')
        reset_parser = self.subparsers.add_parser(
            'reset',
            help='Reset the current level',
            description='Reset the current level')
        reload_parser = self.subparsers.add_parser(
            'reload',
            help='Alias for reset',
            description=
            'Reset the current level. Reload command is an alias for reset command.'
        )
        test_parser = self.subparsers.add_parser(
            'test',
            help=
            "Test to see if you've successfully completed the current level",
            description=
            "Test to see if you've successfully completed the current level")
        progress_parser = self.subparsers.add_parser(
            'progress',
            help='Continue to the next level',
            description='Continue to the next level')
        skills_parser = self.subparsers.add_parser('skills',
                                                   help='List skills',
                                                   description='List skills')
        levels_parser = self.subparsers.add_parser(
            'levels',
            help='List levels in a skill',
            description=
            'List the levels in the specified skill or in the current skill if Git Gud has been initialized and no skill is provided.'
        )
        load_parser = self.subparsers.add_parser(
            'load',
            help='Load a specific skill or level',
            description='Load a specific skill or level')
        commit_parser = self.subparsers.add_parser(
            'commit',
            help='Quickly create and commit a file',
            description='Quickly create and commit a file')
        goal_parser = self.subparsers.add_parser(
            'goal',
            help='Show a description of the current goal',
            description='Show a description of the current goal')
        show_tree_parser = self.subparsers.add_parser(
            'show-tree',
            help='Show the current state of the branching tree',
            description='Show the current state of the branching tree')
        contrib_parser = self.subparsers.add_parser(
            'contributors',
            help='Show project contributors webpage',
            description='Show all the contributors of the project')

        help_parser.add_argument('command_name',
                                 metavar='<command>',
                                 nargs='?')

        init_parser.add_argument('--force', action='store_true')

        levels_parser.add_argument('skill_name', metavar='skill', nargs='?')

        load_parser.add_argument('skill_name',
                                 metavar='skill',
                                 help='Skill to load')
        load_parser.add_argument('level_name',
                                 metavar='level',
                                 nargs='?',
                                 help='Level to load')

        commit_parser.add_argument('file', nargs='?')

        self.command_dict = {
            'help': self.handle_help,
            'init': self.handle_init,
            'status': self.handle_status,
            'instructions': self.handle_instructions,
            'goal': self.handle_goal,
            'reset': self.handle_reset,
            'reload': self.handle_reset,
            'test': self.handle_test,
            'progress': self.handle_progress,
            'skills': self.handle_skills,
            'levels': self.handle_levels,
            'load': self.handle_load,
            'commit': self.handle_commit,
            'show-tree': self.handle_show_tree,
            'contributors': self.handle_contrib,
        }

    def is_initialized(self):
        return self.file_operator is not None

    def assert_initialized(self, skip_level_check=False):
        if not self.is_initialized():
            raise InitializationError(
                'Git gud has not been initialized. Use "git gud init" to initialize'
            )

        if not skip_level_check:
            try:
                self.file_operator.get_level()
            except KeyError:
                level_name = self.file_operator.read_level_file()
                raise InitializationError(
                    'Currently loaded level does not exist: "{}"'.format(
                        level_name))

    def load_level(self, level):
        level.setup(self.file_operator)
        self.file_operator.write_level(level)
        show_tree()

    def handle_help(self, args):
        if args.command_name is None:
            self.parser.print_help()
        else:
            try:
                self.subparsers.choices[args.command_name].print_help()
            except KeyError:
                print('No such command exists: "{}"\n'.format(
                    args.command_name))
                self.parser.print_help()

    def handle_init(self, args):
        # Make sure it's safe to initialize
        if not args.force:
            # We aren't forcing
            if self.file_operator:
                print('Repo {} already initialized for git gud.'.format(
                    self.file_operator.path))
                print('Use --force to initialize {}.'.format(os.getcwd()))
                return

            self.file_operator = Operator(os.getcwd(), initialize_repo=False)

            if os.path.exists(self.file_operator.git_path):
                # Current directory is a git repo
                print(
                    'Currently in a git repo. Use --force to force initialize here.'
                )
                return
            if os.path.exists(self.file_operator.gg_path):
                # Current directory is a git repo
                print(
                    'Git gud has already initialized. Use --force to force initialize again.'
                )
                return
            if len(os.listdir(self.file_operator.path)) != 0:
                print(
                    'Current directory is nonempty. Use --force to force initialize here.'
                )
                return
        else:
            print('Force initializing git gud.')
            if not self.file_operator:
                self.file_operator = Operator(os.getcwd(),
                                              initialize_repo=False)

        # After here, we initialize everything
        try:
            self.file_operator.repo = Repo(self.file_operator.path)
        except InvalidGitRepositoryError:
            self.file_operator.repo = Repo.init(self.file_operator.path)

        if not os.path.exists(self.file_operator.gg_path):
            os.mkdir(self.file_operator.gg_path)
        with open(self.file_operator.last_commit_path, 'w+') as commit_file:
            commit_file.write('0')  # First commit will be 1
        with open(self.file_operator.level_path, 'w+') as level_file:
            level_file.write(all_skills[0][0].full_name())

        python_exec = sys.executable.replace(
            '\\', '/')  # Git uses unix-like path separators

        for git_hook_name, module_hook_name in all_hooks:
            with open(
                    os.path.join(self.file_operator.hooks_path, git_hook_name),
                    'w+') as hook_file:
                hook_file.write('#!/bin/sh' + os.linesep)
                hook_file.write('cat - | ' + python_exec +
                                ' -m gitgud.hooks.' + module_hook_name +
                                ' "$@"' + os.linesep)
                hook_file.write('exit 0' + os.linesep)

        print('Git Gud successfully setup in {}'.format(os.getcwd()))
        print('Welcome to Git Gud!')
        print()

        self.file_operator.get_level().setup(self.file_operator)
        show_tree()

    def handle_status(self, args):
        if self.is_initialized():
            try:
                level = self.file_operator.get_level()
                print('Currently on level: "{}"'.format(level.full_name()))
            except KeyError:
                level_name = self.file_operator.read_level_file()
                print(
                    'Currently on unregistered level: "{}"'.format(level_name))
        else:
            print("Git gud not initialized.")
            print('Initialize using "git gud init"')

    def handle_instructions(self, args):
        self.assert_initialized()
        self.file_operator.get_level().instructions()

    def handle_goal(self, args):
        self.assert_initialized()
        self.file_operator.get_level().goal()

    def handle_reset(self, args):
        self.assert_initialized()

        level = self.file_operator.get_level()
        print("Resetting...")
        level.setup(self.file_operator)
        show_tree()

    def handle_test(self, args):
        self.assert_initialized()
        level = self.file_operator.get_level()
        level.test(self.file_operator)

    def handle_progress(self, args):
        self.assert_initialized()

        print("Progressing to next skill...")
        print()

        level = self.file_operator.get_level()

        next_level = level.next_level
        if next_level is not None:
            self.load_level(next_level)
        else:
            print_all_complete()

    def handle_skills(self, args):
        if self.is_initialized():
            try:
                cur_skill = self.file_operator.get_level().skill
                print('Currently on skill: "{}"'.format(cur_skill.name))
                print()
            except KeyError:
                pass

        for skill in all_skills:
            # TODO Add description
            # 10 characters for the short IDs.
            print("Skill {:<10} :{:>2} level{}".format(
                "\"" + skill.name + "\"", len(skill),
                ("", "s")[len(skill) > 1]))
            for index, level in enumerate(skill):
                # " " * (characters allocated for ID - 6)
                print("{}Level {:>2} : {:<10}".format(" " * 4, index + 1,
                                                      level.name))

    def handle_levels(self, args):
        key_error_flag = False
        if args.skill_name is None:
            if self.file_operator is None:
                self.subparsers.choices['levels'].print_help()
                return

            try:
                skill = self.file_operator.get_level().skill
            except KeyError:
                skill_name = self.file_operator.read_level_file().split()[0]
                print(
                    'Cannot find any levels in skill: "{}"'.format(skill_name))
                return
        else:
            try:
                skill = all_skills[args.skill_name]
            except KeyError:
                print('There is no skill "{}".'.format(args.skill_name))
                print(
                    'You may run "git gud skills" to print all the skills. \n')
                skill = self.file_operator.get_level().skill
                key_error_flag = True

        if key_error_flag or args.skill_name is None:
            print('Levels in the current skill "{}" : \n'.format(skill.name))
        else:
            print('Levels for skill "{}" : \n'.format(skill.name))

        for index, level in enumerate(skill):
            print(str(index + 1) + ": " + level.name)

    def handle_load(self, args):
        self.assert_initialized(skip_level_check=True)
        if args.skill_name in all_skills:
            skill = all_skills[args.skill_name]

            if args.level_name is not None:
                if args.level_name in all_skills[args.skill_name]:
                    level = skill[args.level_name]
                    self.load_level(level)
                else:
                    print('Level "{}" does not exist'.format(args.level_name))
                    print(
                        "To view levels/skills, use git gud levels or git gud skills"
                    )
            else:
                self.load_level(skill[0])
        else:
            print('Skill "{}" does not exist'.format(args.skill_name))
            print(
                "To view levels/skills, use git gud levels or git gud skills")

    def handle_commit(self, args):
        self.assert_initialized()

        last_commit = self.file_operator.get_last_commit()
        commit_name = str(int(last_commit) + 1)

        if args.file is not None:
            try:
                int(args.file)
                commit_name = args.file
            except ValueError:
                pass

        print('Simulating: Create file "{}"'.format(commit_name))
        print('Simulating: git add {}'.format(commit_name))
        print('Simulating: git commit -m "{}"'.format(commit_name))

        commit = self.file_operator.add_and_commit(commit_name)
        print("New Commit: {}".format(commit.hexsha[:7]))

        # Check if the newest commit is greater than the last_commit, if yes, then write

        if int(commit_name) > int(last_commit):
            self.file_operator.write_last_commit(commit_name)

    def handle_show_tree(self, args):
        show_tree()

    def handle_contrib(self, args):
        contrib_website = "https://github.com/benthayer/git-gud/graphs/contributors"
        webbrowser.open_new(contrib_website)

    def parse(self):
        args, _ = self.parser.parse_known_args()
        if args.command is None:
            self.parser.print_help()
        else:
            try:
                self.command_dict[args.command](args)
            except InitializationError as error:
                print(error)