コード例 #1
0
    def _parent_commit_for_first_lt_child(self):
        """If "change" is going to be the first commit on a new Git branch,
        and if current_branch is a view into a lightweight depot branch
        based on some other branch at some other changelist number, return
        that other branch@change as a sha1/commit that should be a
        commit parent of "change".

        If not, return None.

        Required when the first commit in a lightweight branh is an add,
        not edit, and thus has zero integ actions to connect it to the
        parent branch. We must connect manually. Here.
        """

        # Not copying from a lightweight branch?
        if not self.current_branch.depot_branch:
            return None

        # Lightweight branch lacks a parent?
        if not self.current_branch.depot_branch.parent_depot_branch_id_list:
            return None

        # Find a commit to go with the parent branch @ changelist
        # upon which dest_db is based.
        dest_db = self.current_branch.depot_branch
        for par_cl in dest_db.parent_changelist_list:
            # Mark for a change/commit we're about to copy to this repo?
            ml = self.p2g.mark_list.cl_to_mark_list(par_cl)
            if ml:
                return ml[0]
            # sha1 we've already copied to this repo?
            commit = ObjectType.change_num_to_commit(self.ctx, par_cl)
            if commit:
                return commit.sha1
コード例 #2
0
 def _add_parent_changes(self):
     """If desc_info has parent-changes, add those to parent_commit_list.
     Return True if any parent added to self.parent_commit_list,
     False if nothing added.
     """
     if self.desc_info and self.desc_info.parent_changes:
         # orphan git commits with no parents
         if 'None' in self.desc_info.parent_changes:
             self.parent_commit_list = []
             self.is_git_orphan = True
             return True
         add_list = []
         for sha1 in self.desc_info.parents:
             changes = self.desc_info.parent_changes.get(sha1, None)
             if changes is None:
                 LOG.error(
                     'DescInfo missing parent changes for {}'.format(sha1))
                 return False
             for cl in changes:
                 ml = self.p2g.mark_list.cl_to_mark_list(str(cl))
                 if ml:
                     add_list.append(ml[0])
                     LOG.debug3(
                         '_add_parent_changes() @{} using mark {}'.format(
                             cl, ml[0]))
                     break
                 commit = ObjectType.change_num_to_commit(self.ctx, cl)
                 if commit and p4gf_util.sha1_exists(commit.sha1):
                     add_list.append(commit.sha1)
                     LOG.debug3(
                         '_add_parent_changes() @{} using SHA1 {}'.format(
                             cl, commit.sha1))
                     break
             else:
                 # Fell off the end of the "for cl" list without finding the
                 # parent in our repo.
                 #
                 # DescInfo lists a parent commit sha1/change_num that does
                 # not intersect this repo. This is okay: just means the
                 # changelist came from some other repo that can see some
                 # depot paths that this current repo cannot.
                 LOG.debug3('_add_parent_changes() skipping, could not find'
                            ' parent SHA1 {} cl {}'.format(sha1, changes))
                 self.omitted_di_parents = True
         if add_list:
             self.parent_commit_list.extend(add_list)
             return True
     return False
コード例 #3
0
    def compare_change_num(self, change_num):
        """Compare one Perforce changelist with its corresponding Git
        commit.
        """
        ot = ObjectType.change_num_to_commit(self.ctx, change_num)
        if not ot:
            key_pattern = (p4gf_const.P4GF_P4KEY_INDEX_OT.format(
                repo_name=self.ctx.config.repo_name,
                change_num=change_num,
                branch_id="*"))
            raise RuntimeError("No Git commit for @{change_num}."
                               "\nNo 'p4 keys -e {key_pattern}".format(
                                   change_num=change_num,
                                   key_pattern=key_pattern))

        branch = self.ctx.branch_dict().get(ot.branch_id)
        if not branch:
            raise RuntimeError("No branch view defined for {}".format(
                ot.branch_id))
        self._compare_ot(ot)
コード例 #4
0
    def _calc_merge_parent_list(self):
        """Return a list of marks/sha1s to use as parents for a Git merge commit.

        Returns a 2-tuple of ( [mark/commit parent], [parent branch id] ).
        """
        parent_commit_id = []
        parent_branch_id = []
        for branch_id, cl in self.branch_id_to_changelist_num.items():
            # Changelists from before the start of history cannot be
            # parents. No merging from beyond the event horizon.
            if cl < self.p2g.rev_range.begin_change_num:
                continue

            # Each Perforce commit maps to zero or more Git commits, one per
            # branch that intersects the integ source files from that commit.

            # Do we have any pending commits for this changelist?
            ml = self.p2g.mark_list.cl_to_mark_list(str(cl))
            for mark in ml:
                ### Must only include mark if mark associated with branch.
                ### Must only include one mark here.
                ### But that requires adding more branch/mark tracking than we
                ### want to add until I have a test that proves we need it.
                if mark not in parent_commit_id:
                    parent_commit_id.append(mark)
                    parent_branch_id.append(branch_id)

            # Do we have any existing commits for this changelist?
            commit = ObjectType.change_num_to_commit(self.ctx, cl)

            # Does this Git commit occur in our Git repo at this
            # changelist number?
            if (commit and (commit.sha1 not in parent_commit_id)
                    and p4gf_util.sha1_exists(commit.sha1)):
                parent_commit_id.append(commit.sha1)
                parent_branch_id.append(branch_id)

        return (parent_commit_id, parent_branch_id)
コード例 #5
0
    def _git_object_parent_list(self):
        """Fetch the list of parent commits from our git object mirror of the
        original Git commit that created our current Perforce changelist.

        Return None if no such commit found.

        Return empty list [] if commit found but it lacked parents
        (orphan/first commit in a chain of commits).
        """
        # Find corresponding Git commit object for this changelist. Ignore the
        # sha1 in the changelist DescInfo: it's only there for Git-to-Perforce
        # changelists, not changelists that originated in Perforce.
        commit = ObjectType.change_num_to_commit(self.ctx,
                                                 self.p4change.change)
        if not commit:
            # Cached object is missing, see if the change description has
            # what we need (in the 'parents' field of the Git desc info).
            if self.desc_info and self.desc_info.parents:
                LOG.debug2(
                    '_git_object_parent_list() parents from change: {}'.format(
                        self.desc_info.parents))
                return self.desc_info.parents
            else:
                return None

        depot_path = commit.to_depot_path()
        commit_text = p4gf_util.depot_path_to_git_object(
            self.ctx.p4gf, depot_path)
        # Parse out the parent list.
        parent_list = []
        for line in commit_text.splitlines():
            if line.startswith(b'parent '):
                sha1 = line[len(b'parent '):].decode().strip()
                parent_list.append(sha1)
            elif not len(line.strip()):
                # Done with header. Stop scanning.
                break
        return parent_list
コード例 #6
0
    def _git_branch_to_ot(self, branch):
        """Return the ObjectType of the most recent surviving
        commit for the given branch.

        Return None if branch is not visible to Git.

        Returns the current branch head if the branch is already
        pointing to some old commit/changelist from before the cutoff.

        WARNING: Does not detect or counteract any branch deletion/creation
        that occur after the cutoff. Branches deleted in soon-to-be-obliterated
        history remain deleted after rollback. Branches created in soon-to-be-
        obliterated history remain created, either empty or containing some
        random reused branch content.
        """
                        # Ignore branches with no Git counterpart.
                        # (branch.sha1_for_branch() checks .git_branch_name,
                        #  but not .deleted)
        if branch.deleted or not branch.git_branch_name:
            if branch.git_branch_name:
                LOG.info("Skip Git ref {gbn}."
                         " Branch {branch_id} marked as deleted."
                         .format( branch_id = branch.branch_id
                                , gbn       = branch.git_branch_name))
            return None

                        # Before the rollback, is the Git head already
                        # positioned before/at the cutoff? If so,
                        # change nothing.
        sha1 = branch.sha1_for_branch()
        if not sha1:
                        # No such reference in local Git repo? Expected.
                        # git-branch-name defined from Perforce or other
                        # another Git Fusion server of this same repo, but
                        # either unpopulated, or not yet pulled to this
                        # Git Fusion server's repo.
            LOG.info("Ignore Git ref {gbn}."
                     " Branch {branch_id} has no sha1 in local repo."
                     .format( branch_id = branch.branch_id
                            , gbn       = branch.git_branch_name))
            return None

                        # Lookup this sha1/branch and find its changelist
                        # number. If that's at/before cutoff, retain it.
        otl = ObjectType.commits_for_sha1( ctx       = self.ctx
                                         , sha1      = sha1
                                         , branch_id = branch.branch_id )
        if otl:
            ot = otl[0]
        if ot and int(ot.change_num) <= int(self.change_num):
            LOG.info("Ignore Git ref {gbn}."
                     " Branch {branch_id} has no sha1 in local repo."
                     .format( branch_id = branch.branch_id
                            , gbn       = branch.git_branch_name))
            return None

                        # If it's missing or after the cutoff, find the
                        # change at/before cutoff.
        with self.ctx.switched_to_branch(branch):
            r = self.ctx.p4run(
                  'changes'
                , '-m1'
                , self.ctx.client_view_path(change_num=self.change_num)
                )
            change_num = p4gf_util.first_value_for_key(r, key='change')
                        # No changelists at/before cutoff?
        if not change_num:
            LOG.info("Delete Git ref {gbn}."
                     " Branch {branch_id} has no changelists before"
                     " @{change_num}."
                     .format( branch_id  = branch.branch_id
                            , gbn        = branch.git_branch_name
                            , change_num = self.change_num ))
            return self._create_ot_to_delete_git_ref(branch)

                        # Find corresponding Git commit sha1.
        ot = ObjectType.change_num_to_commit( ctx        = self.ctx
                                            , change_num = change_num
                                            , branch_id  = branch.branch_id )
        if not ot:
            LOG.info("Delete Git ref {gbn}."
                     " Branch {branch_id} has changelist @{survive_cn} before"
                     " @{change_num}, but no corresponding Git commit."
                     .format( branch_id  = branch.branch_id
                            , gbn        = branch.git_branch_name
                            , change_num = self.change_num
                            , survive_cn = change_num ))
            return self._create_ot_to_delete_git_ref(branch)

                        # Surviving changelist exists as a commit in local
                        # Git repo.
        LOG.info("Move Git ref {gbn}."
                 " Branch {branch_id} has changelist @{survive_cn},"
                 " Git commit {sha1} at/before @{change_num}."
                 .format( branch_id  = branch.branch_id
                        , gbn        = branch.git_branch_name
                        , change_num = self.change_num
                        , survive_cn = change_num
                        , sha1       = ot.sha1 ))
        return ot