Example #1
0
    def handle_levels(self, args):
        if args.opt_all:
            skills_to_show = [skill for skill in all_skills]
            print("All levels and skills:")
        else:
            # Only show levels in one skill
            if args.skill_name:
                try:
                    skills_to_show = [all_skills[args.skill_name]]
                    print('Levels in skill "{}" :'.format(args.skill_name))
                except KeyError:
                    print('There is no skill "{}".'.format(args.skill_name))
                    print(
                        'You may run "git gud levels --all" or "git gud levels --skills" to print all the skills.'
                    )  # noqa: E501
                    return
            elif self.is_initialized():
                current_skill = get_operator().get_level().skill
                skills_to_show = [current_skill]
                print('Levels in the current skill "{}" :'.format(
                    current_skill.name))  # noqa: E501
            else:
                self.subparsers.choices['levels'].print_help()
                return

        print()
        show_skill_tree(skills_to_show,
                        bool(get_operator()),
                        expand_skills=True,
                        show_human_names=not args.opt_short)
        print()
        print("Load a level with `git gud load`")
Example #2
0
    def handle_load(self, args):
        self.assert_initialized()
        args.skill_name = args.skill_name.lower()
        if args.level_name:
            args.level_name = args.level_name.lower()

        level = get_operator().get_level()
        if level:
            if level._test():
                level.mark_complete()
        if args.skill_name in {"next", "prev", "previous"}:
            self.load_level_by_direction(args.skill_name, args.force)
            return

        # No matter what, the dash separates the skill and level
        if '-' in args.skill_name:
            identifier = args.skill_name + (args.level_name or '')
        else:
            identifier = args.skill_name + '-' + (args.level_name or '')
        if identifier.count('-') != 1:
            print("Load formula must not contain more than one dash.")
            return

        args.skill_name, args.level_name = identifier.split('-')

        if not args.skill_name:
            args.skill_name, loaded_level_name = get_operator() \
                    .get_level_identifier()
            print("Inferring skill from currently loaded level: {} {}".format(
                args.skill_name, loaded_level_name))
        if not args.level_name:
            args.level_name = '1'

        # Skill doesn't exist
        if args.skill_name not in all_skills.keys():
            print('Skill "{}" does not exist'.format(args.skill_name))
            print('\nTo view levels/skills, use "git gud levels --all"')
            return

        # Level doesn't exist
        skill = all_skills[args.skill_name]
        if args.level_name not in skill.keys():
            print('Level "{}" does not exist.'.format(args.level_name))
            print('\nTo view levels/skills, use "git gud levels --all"')
            return

        level = skill[args.level_name]
        self.load_level(level)
Example #3
0
def display_commit_content(show_branches=True, show_content=True, content_order=None, sort_commits=True, num_files=2, num_commits=2):  # noqa: E501
    file_operator = operations.get_operator()
    referred_by = target_branch_str()

    commit_format_str = 'Commit {commit_num}: "{message}"'
    if show_branches:
        commit_format_str += "{branches}"

    commits = file_operator.get_all_commits(sort_commits)
    for commit_num, commit in enumerate(commits):
        if commit.hexsha in referred_by and show_branches:
            branches = f" ({referred_by[commit.hexsha]})"
        else:
            branches = ""
        header = commit_format_str.format(
            commit_num=commit_num+1,
            message=commit.message.split('\n')[0].strip(),
            branches=branches
        )
        display_tree_content(
            header,
            file_operator.get_commit_content(commit),
            content_order=content_order,
            show_content=show_content,
            num_files=num_files
        )

    for commit_num in range(len(commits), num_commits):
        print(f"Commit {commit_num+1}: " + existence_str(False))
Example #4
0
    def _test5(self):
        # File 2 was moved in commit 5
        file_operator = operations.get_operator()

        commits = file_operator.get_commits()

        if len(commits) < 5:
            return None

        content4 = file_operator.get_commit_content(commits[3])
        content5 = file_operator.get_commit_content(commits[4])

        if len(content5) != 1:
            return False

        filename2_orig = next(iter(content4.keys()))
        filename2_new = next(iter(content5.keys()))

        if filename2_orig in content5:
            return False

        if content4[filename2_orig] != content5[filename2_new]:
            return False

        return True
Example #5
0
    def _test(self):
        file_operator = operations.get_operator()

        # There are two commits
        if len(file_operator.get_commits()) != 2:
            return False

        # The first commit has one file
        content1 = file_operator.get_commit_content('HEAD~')
        if len(content1.keys()) != 1:
            return False

        # The second commit has two files
        content2 = file_operator.get_commit_content('HEAD')
        if len(content2.keys()) != 2:
            return False

        # The file from the first commit is in the second commit
        file1_name = next(iter(content1.keys()))
        if file1_name not in content2:
            return False

        # The first file is unchanged
        if content1[file1_name] != content2[file1_name]:
            return False

        # Working Directory, Staging Area and Commit 2 are the same
        content_wd = file_operator.get_working_directory_content()
        content_sa = file_operator.get_staging_content()
        if not (content2 == content_wd == content_sa):
            return False

        return True
Example #6
0
    def load_level_by_direction(self, load_direction, force):
        if load_direction == "prev":
            load_direction = "previous"

        try:
            level = get_operator().get_level()
        except InitializationError as e:
            print(e)
            print(f"Cannot load {load_direction} level.")
            return

        if load_direction == "next":
            if level.has_ever_been_completed() or force:
                level_to_load = level.next_level
            else:
                handle_load_confirm()
                return
        else:
            level_to_load = level.prev_level

        if level_to_load is not None:
            self.load_level(level_to_load)
        else:
            if load_direction == "next":
                all_levels_complete()
            else:
                print(
                    'Already on the first level. To reload the level, use "git gud reload".'
                )  # noqa: E501
            print('\nTo view levels/skills, use "git gud levels --all"'
                  )  # noqa: E501
Example #7
0
 def handle_skills(self, args):
     print("All skills:")
     print()
     show_skill_tree([skill for skill in all_skills],
                     bool(get_operator()),
                     expand_skills=False,
                     show_human_names=not args.opt_short)
Example #8
0
    def _test(self):
        file_operator = operations.get_operator()

        # Get commit trees
        test_tree = level_json(*parse_spec(self.file('test.spec')))
        level_tree = file_operator.get_current_tree()

        # Make all user-created branches lowecase
        setup_tree = level_json(*parse_spec(self.file('setup.spec')))
        branches_to_lowercase(level_tree, setup_tree, test_tree)

        # Get commit info
        non_merges = get_non_merges(level_tree)

        # Name known commits
        known_commits = file_operator.get_known_commits()
        name_from_map(level_tree, known_commits)

        # Name rebases and cherrypicks
        known_non_merges = {
            commit_hash: name
            for commit_hash, name in known_commits.items() if name[:1] != 'M'
        }
        diff_map = file_operator.get_copy_mapping(non_merges, known_non_merges)
        name_from_map(level_tree, diff_map)

        # Name merges
        name_merges(level_tree, test_tree)

        # Test for similarity
        return test_ancestry(level_tree, test_tree)
Example #9
0
    def solution(self):
        commit = operations.get_operator().repo.head.commit

        commits = []
        commit_dict = {}
        while commit:
            commits.append((commit.hexsha[:7], commit.message))
            commit_dict[commit.message] = commit.hexsha[:7]
            if commit.parents:
                commit = commit.parents[0]
            else:
                commit = None

        # Chronological order
        commits = list(reversed(commits))

        this_hash = commit_dict['This']
        print('Run: "git rebase -i {}"'.format(this_hash))
        print('"{}" is the hash of the commit with the message "This"'.format(
            this_hash))
        print()
        print("You will see this: ")

        for sha, msg in commits[1:]:
            print(4 * " " + "pick {} {}".format(sha, msg))
        print()

        print("Change it to this:")
        for msg in 'is an easy level'.split():
            sha = commit_dict[msg]
            print(4 * " " + "pick {} {}".format(sha, msg))

        print()
        print('The order of commits will now be "This is an easy level"')
Example #10
0
def repo_already_initialized():
    file_operator = operations.get_operator()
    print('Repo {} already initialized for Git Gud.'
          .format(file_operator.path))
    print('Use "git gud init --force" to delete progress and reinitialize')
    if file_operator.path != Path.cwd():
        print('{} will be left as is.'.format(file_operator.gg_path))  # noqa: E501
Example #11
0
 def handle_solution(self, args):
     self.assert_initialized()
     current_level = get_operator().get_level()
     if not args.confirm and \
             not current_level.has_ever_been_completed():
         rerun_with_confirm_for_solution(current_level)
     else:
         current_level.solution()
Example #12
0
    def handle_reset(self, args):
        self.assert_initialized()

        file_operator = get_operator()

        file_operator.update_level_completion()

        level = file_operator.get_level()
        self.load_level(level)
Example #13
0
    def get_state(self):
        file_operator = operations.get_operator()

        created = bool(file_operator.get_working_directory_content())
        added = bool(file_operator.get_staging_content())
        committed = file_operator.repo.head.is_valid() \
            and bool(file_operator.get_commit_content('HEAD'))

        return created, added, committed
Example #14
0
def test_load(gg):
    load_tests = [('git gud load 1', all_skills["1"]["1"]),
                  ('git gud load rampup', all_skills["rampup"]["1"]),
                  ('git gud load 2 detaching', all_skills["2"]["detaching"]),
                  ('git gud load rampup 4', all_skills["rampup"]["4"]),
                  ('git gud load 5-octopus', all_skills["5"]["octopus"]),
                  ('git gud load rampup-4', all_skills["rampup"]["4"]),
                  ('git gud load -2', all_skills["rampup"]["2"])]

    for command, level in load_tests:
        subprocess.call(command, shell=True)
        op = operations.get_operator()
        assert level == op.get_level()
Example #15
0
    def _test1(self):
        # Test if a single file has been added to the first commit
        file_operator = operations.get_operator()

        commits = file_operator.get_commits()

        if len(commits) < 1:
            return None

        content = file_operator.get_commit_content(commits[0])
        if len(content.keys()) != 1:
            return False

        return True
Example #16
0
    def handle_debug(self, args):
        import readline  # noqa: F401
        import code
        variables = globals()

        file_operator = get_operator()
        variables['file_operator'] = file_operator
        variables['op'] = file_operator

        shell = code.InteractiveConsole(variables)
        shell.interact(banner="\n".join([
            "You are now in the Python interpreter invoked by `git gud debug`.",  # noqa: E501
            "Your current path is " + str(Path.cwd()),
            "To exit, type exit()"
        ]))
Example #17
0
    def _test(self):
        file_operator = operations.get_operator()

        if file_operator.branch_has_merges():
            return False

        if not self._test1():
            return False
        if not self._test2():
            return False
        if not self._test3():
            return False
        if not self._test4():
            return False
        if not self._test5():
            return False

        return True
Example #18
0
def setup_rebase_conflict():
    file_operator = get_operator()

    with open("foo", "w") as f:
        f.write("branch 1")
    file_operator.repo.index.add("foo")
    file_operator.repo.index.commit("Add a file")

    file_operator.repo.git.checkout('-b', 'branch', 'HEAD~')
    with open("foo", "w") as f:
        f.write("branch 2")
    file_operator.repo.index.add("foo")
    file_operator.repo.index.commit("Add a file")

    try:
        file_operator.repo.git.rebase('master')
    except GitCommandError:
        # This will happen every time
        pass
Example #19
0
    def handle_commit(self, args):
        self.assert_initialized()
        file_operator = get_operator()
        last_commit = 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

        commit = file_operator.add_and_commit(commit_name, silent=False)
        file_operator.track_commit(commit_name, commit.hexsha)

        # Next "git gud commit" name
        if int(commit_name) > int(last_commit):
            file_operator.write_last_commit(commit_name)
Example #20
0
    def _test4(self):
        # File 1 was removed in commit 4
        file_operator = operations.get_operator()

        commits = file_operator.get_commits()

        if len(commits) < 4:
            return None

        content1 = file_operator.get_commit_content(commits[0])
        content3 = file_operator.get_commit_content(commits[2])
        content4 = file_operator.get_commit_content(commits[3])

        file1 = next(iter(content1.keys()))

        # Construct content4 from content3
        del content3[file1]

        return content3 == content4
Example #21
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 #22
0
    def _setup(self):
        file_operator = operations.get_operator()
        file_operator.use_repo()
        commits, head = parse_spec(self.file('setup.spec'))

        details_path = self.file('details.yaml')
        if details_path.is_file():
            details = yaml.safe_load(details_path.open())
        else:
            details = None

        file_operator.create_tree(commits, head, details, self.level_dir)

        latest_commit = '0'
        for commit_name, _, _, _ in commits:
            try:
                if int(commit_name) > int(latest_commit):
                    latest_commit = commit_name
            except ValueError:
                pass  # Commit is merge and doesn't have number

        file_operator.write_last_commit(latest_commit)
Example #23
0
    def parse(self):
        if len(sys.argv) >= 2 and sys.argv[1] in self.aliases:
            sys.argv[1] = self.aliases[sys.argv[1]]

        args, _ = self.parser.parse_known_args(sys.argv[1:])

        if args.command is None:
            if get_operator() is None:
                print('Currently in an uninitialized directory.')
                print(
                    'Get started by running "git gud init" (without quotes) in an empty directory!'
                )  # noqa: E501
                if len(list(Path.cwd().iterdir())) != 0:
                    print('Current directory is not empty.')
                else:
                    print('Current directory is empty.')
            else:
                self.parser.print_help()
        else:
            try:
                args = self.parser.parse_args()
                args.func(self, args)
            except InitializationError as error:
                print(error)
Example #24
0
    def _test2(self):
        # Test if a single file has been added to the second commit
        file_operator = operations.get_operator()

        commits = file_operator.get_commits()

        if len(commits) < 2:
            return None

        content1 = file_operator.get_commit_content(commits[0])
        content2 = file_operator.get_commit_content(commits[1])

        # There is only one more file in the second commit
        if len(content1) + 1 != len(content2):
            return False

        filename1 = next(iter(content1.keys()))

        if filename1 not in content2:
            return False
        if content1[filename1] != content2[filename1]:
            return False

        return True
Example #25
0
    def _test3(self):
        # Test that both files were modified in commit three
        file_operator = operations.get_operator()

        commits = file_operator.get_commits()

        if len(commits) < 3:
            return None

        content2 = file_operator.get_commit_content(commits[1])
        content3 = file_operator.get_commit_content(commits[2])

        # Same number of files
        if len(content2) != len(content3):
            return False

        # Both files have new content and same name
        for filename in content2:
            if filename not in content3:
                return False
            if content2[filename] == content3[filename]:
                return False

        return True
Example #26
0
 def get_progress(self):
     file_operator = operations.get_operator()
     return file_operator.get_level_progress(self)
Example #27
0
 def mark_visited(self):
     file_operator = operations.get_operator()
     file_operator.mark_level(self, "visited")
Example #28
0
 def mark_partial(self):
     file_operator = operations.get_operator()
     file_operator.mark_level(self, "partial")
Example #29
0
 def mark_complete(self):
     file_operator = operations.get_operator()
     file_operator.mark_level(self, "complete")
Example #30
0
def display_staging_area_content(**kwargs):
    file_operator = operations.get_operator()
    staging_area = file_operator.get_staging_content()
    display_tree_content("Staging Area:", staging_area, **kwargs)