def decided_(self):
     '''
     Guaranteed to return a Decided instance. Creates one if necessary.
     '''
     if not self.decided:
         self.decided = Decided()
     return self.decided
 def decided(self, index):
     """Return a Decided instance, creating Cell and Decided
     if none yet exists.
     """
     c = self.cell(index)
     if not c.decided:
         c.decided = Decided()
     return c.decided
예제 #3
0
    def _decide_jit_if(self):
        """Branch file from fully populated basis if necessary and possible.

        This code runs after any _decide_integ_from_column() and
        _apply_git_delta(). Prefer p4 'branch' file actions from actual Git
        parent branches over JIT branch file actions.

        Store the JIT action we WOULD run if we later decide JIT is required.
        """
        # Not worth attempting to JIT-branch a file that we've already decided
        # to integrate from at least one other branch. We've got files and
        # content coming from other integ source branches, and that's good
        # enough to hold the incoming commit's results.
        if self.has_integ:
            common.debug3('_decide_jit_if() no: has_integ')
            return

        # If we've got no Git action to apply, there's no reason to
        # JIT-branch this file.
        if not (    self.git_delta_cell
                and self.git_delta_cell.decided
                and self.git_delta_cell.decided.has_p4_action() ):
            common.debug3('_decide_jit_if() no: no git delta from prev commit')
            return

        # No need to JIT-branch a file that already exists in destination.
        if common.gdest_cell_exists_in_p4(self.gdest_cell):
            common.debug3('_decide_jit_if() no: already exists in p4 destination')
            return

        # Cannot JIT-branch a file that has no source.
        if not self._p4jitfp_exists():
            common.debug3('_decide_jit_if() no: does not exist in JIT FP basis')
            return

        if self.m.symlink_in_path(self.row.gwt_path):
            common.debug3('_decide_jit_if() no: symlink in path')
            return

        # Look up the correct integ, resolve, and fallback action
        # to take for this file. Sometimes is "do nothing" and that's okay.
        ri = p4gf_g2p_matrix_integ.to_input( row             = self.row
                                           , integ_src_cell  = self.p4jitfp_cell
                                           , integ_dest_cell = self.integ_dest_cell
                                           , git_delta_cell  = self.git_delta_cell
                                           , gdest_cell      = self.gdest_cell )
        r = p4gf_g2p_matrix_integ.find_row(ri)
        if (   not r
            or not ((r.integ_flags is not None) or r.fallback) ):
            common.debug3('_decide_jit_if() no: integ matrix returned'
                          ' no integ or fallback')
            return

        self.p4jitfp_cell.decided = Decided.from_integ_matrix_row(r, ri)
        common.debug3('_decide_jit_if() JIT: {}'.format(self.p4jitfp_cell.decided))
        if r.integ_flags is not None:
            self.has_integ = True
예제 #4
0
    def _ghost_decide_from_git_lfs_initial_track(self, gparn_cell):
        """If this is a top-level .gitattributes row that exists in Git
        but not in Perforce, it's probably one that git-lfs-initial-track
        inserted into Git history but not Perforce. Time to ghost it into
        Perforce history, too.

        Returns a Decided to 'p4 add' it into Perforce history if so, or
        None if not.
        """
        if (    self.m.ctx.is_lfs_enabled
            and self.row.gwt_path == p4gf_const.GITATTRIBUTES
            and gparn_cell
            and "sha1" in gparn_cell.discovered
            and not "depotFile" in gparn_cell.discovered ):
            return Decided( p4_request  = 'add'
                          , integ_input = 'lfs_init'
                          )
        return None
예제 #5
0
    def _decide_populate_from(self, exists_in_git):
        """If discovery marked a column for "populate this branch from this
        column", do so.

        Infrequent. Occurs only on first changelist on a new Perforce branch.
        """
        if not self._want_populate_from(exists_in_git):
            return

        # Yep, we can indeed populate this row's GWT from the
        # populate_from column.
        common.debug3( '_decide_populate_from() col={col} integ -Rbd resolve -at'
               , col=self.m._populate_from_column.index )
        self.populate_from_cell.decided \
                                    = Decided( integ_flags      = '-Rbd'
                                             , resolve_flags    = '-at'
                                             , on_integ_failure = Decided.RAISE
                                             , integ_input      = 'populate_from')
        self.has_integ = True
def apply_git_delta_cell(gdest_cell, git_delta_cell):
    '''
    If git-fast-export or git-diff-tree says to Add/Modify/Delete
    this GWT path, then do so.

    Internally only applies to row if we've no integ action. The big
    integ decision table already factors in Git actions when integrating.
    '''
    git_action = Cell.safe_discovered(git_delta_cell, 'git-action')
    if not git_action:
        return

    exists = (        gdest_cell_exists_in_p4(gdest_cell)
              and not gdest_cell_deleted_at_head(gdest_cell))

    debug3('apply_git_delta_cell() e={e} g={g} '.format(e=exists, g=git_action))
    action = GIT_ACTION_AM[exists][git_action]
    if not action:
        return

    if not git_delta_cell.decided:
        git_delta_cell.decided = Decided()
    git_delta_cell.decided.add_git_action(action)
    def _decide_jit_if(self):
        '''
        Branch file from fully populated basis if necessary and possible.

        This code runs after any _decide_integ_from_column() and
        _apply_git_delta(). Prefer p4 'branch' file actions from actual Git
        parent branches over JIT branch file actions.

        Store the JIT action we WOULD run if we later decide JIT is required.

        ### BUG: integ matrix prohibits JIT-for-delete, but we
                 require JIT-for-delete. Make JIT-for-delete work.
        '''

        # Not worth attempting to JIT-branch a file that we've already decided
        # to integrate from at least one other branch. We've got files and
        # content coming from other integ source branches, and that's good
        # enough to hold the incoming commit's results.
        if self.has_integ:
            common.debug3('_decide_jit_if() no: has_integ')
            return

        # If we've got no Git action to apply, there's no reason to
        # JIT-branch this file.
        if not (    self.git_delta_cell
                and self.git_delta_cell.decided ):
            common.debug3('_decide_jit_if() no: no git delta from prev commit')
            return

        # No need to JIT-branch a file that already exists in destination.
        if common.gdest_cell_exists_in_p4(self.gdest_cell):
            common.debug3('_decide_jit_if() no: no already exists in p4 destination')
            return

        # Cannot JIT-branch a file that has no source.
        if not self._p4jitfp_exists():
            common.debug3('_decide_jit_if() no: does not exist in JIT FP basis')
            return


        if self.m.symlink_in_path(self.row.gwt_path):
            common.debug3('_decide_jit_if() no: symlink in path')
            return

        # Look up the correct integ, resolve, and fallback action
        # to take for this file. Sometimes is "do nothing" and that's okay.
        ri = p4gf_g2p_matrix_integ.to_input( row             = self.row
                                           , integ_src_cell  = self.p4jitfp_cell
                                           , integ_dest_cell = self.integ_dest_cell
                                           , git_delta_cell  = self.git_delta_cell
                                           , gdest_cell      = self.gdest_cell )
        r = p4gf_g2p_matrix_integ.find_row(ri)
        if (   not r
            or not ((r.integ_flags != None) or r.fallback) ):
            common.debug3('_decide_jit_if() no: integ matrix returned'
                    ' no integ or fallback')
            return

        self.p4jitfp_cell.decided = Decided.from_integ_matrix_row(r, ri)
        common.debug3('_decide_jit_if() JIT: {}'.format(self.p4jitfp_cell.decided))
        if r.integ_flags != None:
            self.has_integ = True
예제 #8
0
    def _decide_integ_from_column(self, column):
        '''
        If this column has an integration source that we _discover_branches()
        decide should be used, decide how.

        If column is GPARN with nothing to integrate, but backed by a GPARFPN,
        schedule GPARFP as next work_queue item so that we can check to see
        if it holds something to integrate.

        This code runs before _decide_jit_if(). Prefer p4 'branch' file
        actions from actual Git parent branches over JIT branch file actions.
        '''
        common.debug3('Row._decide_integ_from_column() {col}', col=column.index)
        # Skip any already-integrated population source
        if column is self.m._populate_from_column:
            common.debug3( 'Row._decide_integ_from_column() {col} == pop_fm. Skipping.'
                   , col=column.index )
            return
        # Or from our destination branch.
        if column.branch == self.m.current_branch:
            common.debug3( 'Row._decide_integ_from_column() {col} == curr. Skipping.'
                   , col=column.index )
            return

        # Nothing to integ?
        src_cell = self.row.cells[column.index]
        if not src_cell or not src_cell.discovered:
            # Even if nothing to integ from GPARN, check its GPARFPN
            # basis for something to integ. If so, prepend to work queue
            # to check for something to integ.
            if (    column.col_type == Column.GPARN
                and column.fp_counterpart
                and self.row.cells[column.fp_counterpart.index]):
                self.integ_work_queue.appendleft(column.fp_counterpart)
            common.debug3( 'Row._decide_integ_from_column() {col} no src disc.'
                     ' Skipping.'
                    , col=column.index )
            return

        # Nothing to integ.
        #
        # 'endFromRev'-not-'rev' OK here, indicates _some_ integ action
        # that 'rev' does not.
        if not 'endFromRev' in src_cell.discovered:
            common.debug3( 'Row._decide_integ_from_column() {col} no src endFromRev.'
                     ' Skipping.'
                    , col=column.index )
            return

        # Don't integ duplicate branch or delete actions.
        cur_is = _p4_branch_or_delete(src_cell.discovered)
        if self.is_integ_branch_or_delete and cur_is:
            common.debug3( 'Row._decide_integ_from_column() {col}'
                     ' double-delete/branch. Skipping.'
                   , col=column.index )
            return
        # Or integs that treat a symlink file as a directory.
        if self.m.symlink_in_path(self.row.gwt_path):
            common.debug3( 'Row._decide_integ_from_column() {col} symlink ancestor.'
                     ' Skipping.'
                    , col=column.index)
            return
        # Or source file revisions at or before the destination's
        # fully populated basis
        # common.debug3('### Row._decide_integ_from_column() {col}'
        #         ' checking FP basis...', col=column.index)
        if not self._after_dest_fp(src_cell):
            common.debug3( 'Row._decide_integ_from_column() {col} Not after'
                     ' JIT basis. Skipping.'
                    , col=column.index )
            return

        # Look up the correct integ, resolve, and fallback action
        # to take for this file. Sometimes is "do nothing" and that's okay.
        # common.debug3('### Row._decide_integ_from_column() {col}'
        #         ' checking integ matrix...', col=column.index)
        ri = p4gf_g2p_matrix_integ.to_input( row             = self.row
                                           , integ_src_cell  = src_cell
                                           , integ_dest_cell = self.integ_dest_cell
                                           , git_delta_cell  = self.git_delta_cell
                                           , gdest_cell      = self.gdest_cell )
        r = p4gf_g2p_matrix_integ.find_row(ri)
        if (   not r
            or not ((r.integ_flags != None) or r.fallback) ):
            common.debug3('Row._decide_integ_from_column() {col} {ri} matrix returned'
                    ' no action. Skipping.'
                   , col=column.index
                   , ri = p4gf_g2p_matrix_integ.deb(ri)
                   )
            return

        # I don't _think_ there's a way to gt here on a column we already
        # decided (such as self._poulate_from_column). assert() to be sure.
        assert not src_cell.decided

        src_cell.decided = Decided.from_integ_matrix_row(r, ri)

        common.debug3( 'Row._decide_integ_from_column() col={col} decided={decided}'
               , col     = column.index
               , decided = src_cell.decided )

        if r.integ_flags != None:
            self.has_integ = True
            self.is_integ_branch_or_delete |= cur_is
예제 #9
0
    def ghost_decide(self, row):
        '''
        Main entry point from Matrix.ghost_decide().

        What Perforce file action, if any, should we record in a
        ghost changelist?

        Store decision in ghost_cell.decided
        '''
        self._reset()
        self.row = row

        ghost_cell          = row.cell_if_col(self.m.ghost_column)
        if not ghost_cell:
            return
        self.ghost_cell     = ghost_cell
        self.gdest_cell     = row.cell_if_col(self.m._gdest_column)
        self.git_delta_cell = row.cell_if_col(self.m.git_delta_column)
        self.p4jitfp_cell   = row.cell_if_col(self.m._p4jitfp_column)

        first_parent_col = Column.find_first_parent(self.m.columns)
        gparn_cell = row.cell_if_col(first_parent_col)
        if first_parent_col:
            gparfpn_cell = row.cell_if_col(first_parent_col.fp_counterpart)
        else:
            gparfpn_cell = None

        if not first_parent_col:
            return None

        decision_input = p4gf_g2p_matrix2_ghost.to_input(
                      ghost_cell     = self.ghost_cell
                    , gdest_cell     = self.gdest_cell
                    , gparn_cell     = gparn_cell
                    , gparfpn_cell   = gparfpn_cell
                    , gdest_column   = self.m._gdest_column
                    , gparn_column   = first_parent_col )

        decision_row = p4gf_g2p_matrix2_ghost.find_row(decision_input)
        if LOG.isEnabledFor(logging.DEBUG3):
            LOG.debug3("ghost_decide() {gwt:<10} {input:<47} {output:<6} {comment}"
                      .format( input   = p4gf_g2p_matrix2_ghost.deb(decision_input)
                             , output  = decision_row.output
                             , gwt     = row.gwt_path
                             , comment = decision_row.comment
                             ))

        decided = None
        if not decision_row:
            raise RuntimeError(_('ghost decision input {} matched no known'
                                 ' decision table entry {}')
                                 .format(
                                      p4gf_g2p_matrix2_ghost.deb(decision_input)
                                    , row.gwt_path))
        if    decision_row.output ==   p4gf_g2p_matrix2_ghost.BRANCH:
            decided = Decided( integ_flags      = '-Rbd'
                             , resolve_flags    = '-at'
                             , on_integ_failure = Decided.FALLBACK
                             , integ_fallback   = 'add'
                             , p4_request       = None
                             , integ_input      = decision_input
                             )
                        # To simplify later code, copy integration source
                        # from GPARN/GPARNFP into GHOST column so that
                        # later code can use GHOST as integ source.
            _copy_discovered(ghost_cell, gparn_cell, gparfpn_cell)

        elif  decision_row.output in [ p4gf_g2p_matrix2_ghost.EDIT
                                     , p4gf_g2p_matrix2_ghost.DELETE ]:
            decided = Decided( p4_request  = decision_row.output
                             , integ_input = decision_input )

        elif  decision_row.output ==   p4gf_g2p_matrix2_ghost.NOP:
            decided = None

        elif  decision_row.output ==   p4gf_g2p_matrix2_ghost.ADD_DELETE:
            decided = Decided( p4_request  = 'add'
                             , add_delete  = True
                             , integ_input = decision_input )

        elif  decision_row.output ==   p4gf_g2p_matrix2_ghost.IMPOSSIBLE:
            LOG.error('IMPOSSIBLE. Check your inputs. {}'.format(row.gwt_path))
            p4gf_g2p_matrix2_ghost.LOG.setLevel(logging.DEBUG3)
            p4gf_g2p_matrix2_ghost.to_input(
                      ghost_cell     = self.ghost_cell
                    , gdest_cell     = self.gdest_cell
                    , gparn_cell     = gparn_cell
                    , gparfpn_cell   = gparfpn_cell
                    , gdest_column   = self.m._gdest_column
                    , gparn_column   = first_parent_col )

            raise RuntimeError(_('ghost decision input {} is impossible.'
                                 ' gwt_path={}')
                                 .format(
                                      p4gf_g2p_matrix2_ghost.deb(decision_input)
                                    , row.gwt_path))
        else:
            raise RuntimeError(_('ghost decision input {} produced unknown'
                                 ' output {}. gwt_path={}')
                                 .format(
                                      p4gf_g2p_matrix2_ghost.deb(decision_input)
                                    , decision_row.output
                                    , row.gwt_path))

        self.ghost_cell.decided = decided
        return
예제 #10
0
    def _decide_integ_from_column(self, column):
        """If this column has an integration source that we _discover_branches()
        decide should be used, decide how.

        If column is GPARN with nothing to integrate, but backed by a GPARFPN,
        schedule GPARFP as next work_queue item so that we can check to see
        if it holds something to integrate.

        This code runs before _decide_jit_if(). Prefer p4 'branch' file
        actions from actual Git parent branches over JIT branch file actions.
        """
        common.debug3('Row._decide_integ_from_column() {col}', col=column.index)
        # Skip any already-integrated population source
        if column is self.m._populate_from_column:
            common.debug3( 'Row._decide_integ_from_column() {col} == pop_fm. Skipping.'
                   , col=column.index )
            return
        # Or from our destination branch.
        if column.branch == self.m.current_branch:
            common.debug3( 'Row._decide_integ_from_column() {col} == curr. Skipping.'
                   , col=column.index )
            return

        # Nothing to integ?
        src_cell = self.row.cells[column.index]
        if not src_cell or not src_cell.discovered:
            # Even if nothing to integ from GPARN, check its GPARFPN
            # basis for something to integ. If so, prepend to work queue
            # to check for something to integ.
            if (    column.col_type == Column.GPARN
                and column.fp_counterpart
                and self.row.cells[column.fp_counterpart.index]):
                self.integ_work_queue.appendleft(column.fp_counterpart)
            common.debug3( 'Row._decide_integ_from_column() {col} no src disc.'
                     ' Skipping.'
                    , col=column.index )
            return

        # Skip integ sources that do not exist at all.
        if 'depotFile' not in src_cell.discovered:
            common.debug3('Row._decide_integ_from_column() {col} no src depotFile.'
                          ' Skipping.'
                         , col=column.index )
            return

        # Don't integ duplicate branch or delete actions.
        ### Zig warns: now that we 'p4 fstat' instead of 'p4 integ', a 'branch'
        ### action here means "head action on source depot file is 'branch'"
        ### not "want to branch file from source to dest. This use of
        ### _p4_branch_or_delete() no longer defends against multiple branch
        ### actions in a single dest file, single changelist. This appears to
        ### be okay, because we've never seen multiple branch actions cause a
        ### problem. It's only multiple deletes that fail.
        cur_is = _p4_branch_or_delete(src_cell.discovered)
        if self.is_integ_branch_or_delete and cur_is:
            common.debug3( 'Row._decide_integ_from_column() {col}'
                     ' double-delete/branch. Skipping.'
                   , col=column.index )
            return
        # Or integs that treat a symlink file as a directory.
        if self.m.symlink_in_path(self.row.gwt_path):
            common.debug3( 'Row._decide_integ_from_column() {col} symlink ancestor.'
                     ' Skipping.'
                    , col=column.index)
            return
        # Or source file revisions at or before the destination's
        # fully populated basis
        # common.debug3('### Row._decide_integ_from_column() {col}'
        #         ' checking FP basis...', col=column.index)
        if not self._after_dest_fp(src_cell):
            common.debug3( 'Row._decide_integ_from_column() {col} Not after'
                     ' JIT basis. Skipping.'
                    , col=column.index )
            return

        # Look up the correct integ, resolve, and fallback action
        # to take for this file. Sometimes is "do nothing" and that's okay.
        # common.debug3('### Row._decide_integ_from_column() {col}'
        #         ' checking integ matrix...', col=column.index)
        ri = p4gf_g2p_matrix_integ.to_input( row             = self.row
                                           , integ_src_cell  = src_cell
                                           , integ_dest_cell = self.integ_dest_cell
                                           , git_delta_cell  = self.git_delta_cell
                                           , gdest_cell      = self.gdest_cell )
        r = p4gf_g2p_matrix_integ.find_row(ri)
        if (   not r
            or not ((r.integ_flags is not None) or r.fallback) ):
            common.debug3('Row._decide_integ_from_column() {col} {ri} matrix returned'
                    ' no action. Skipping.'
                   , col=column.index
                   , ri = p4gf_g2p_matrix_integ.deb(ri)
                   )
            return

        # I don't _think_ there's a way to get here on a column we already
        # decided (such as self._poulate_from_column). assert() to be sure.
        assert not (src_cell.decided and src_cell.decided.has_p4_action())

        src_cell.decided = Decided.from_integ_matrix_row(r, ri)

        common.debug3( 'Row._decide_integ_from_column() col={col} decided={decided}'
               , col     = column.index
               , decided = src_cell.decided )

        if r.integ_flags is not None:
            self.has_integ = True
            self.is_integ_branch_or_delete |= cur_is
예제 #11
0
    def _ghost_decide_from_matrix( self, *
                                 , gparn_cell
                                 , gparfpn_cell
                                 , orig_gparn_col
                                 ):
        """Run a row through the ghost decision matrix.

        Returns a Decided value if something to do in a ghost changelist,
        None if nothing to do, or raises exception if surprised.

        Basically a big Python switch statement, without the clever
        Python dict wrapper.
        """
        decision_input = p4gf_g2p_matrix2_ghost.to_input(
                      p4jitfp_cell   = self.p4jitfp_cell
                    , gdest_cell     = self.gdest_cell
                    , gparn_cell     = gparn_cell
                    , gparfpn_cell   = gparfpn_cell
                    , ghost_cell     = self.ghost_cell
                    , gdest_column   = self.m._gdest_column
                    , gparn_column   = orig_gparn_col )

        decision_row = p4gf_g2p_matrix2_ghost.find_row(decision_input)
        if LOG.isEnabledFor(logging.DEBUG3):
            LOG.debug3("ghost_decide() {gwt:<15} {input} {output:<6} {comment}"
                      .format( input   = p4gf_g2p_matrix2_ghost.deb(
                                              decision_input
                                            , p4gf_g2p_matrix2_ghost.LONG)
                             , output  = decision_row.output
                             , gwt     = self.row.gwt_path
                             , comment = decision_row.comment
                             ))

        decided = None
        if not decision_row:
            raise RuntimeError(_('ghost decision input {input} matched no known'
                                 ' decision table entry {gwt_path}')
                               .format(  input    = p4gf_g2p_matrix2_ghost.deb(decision_input)
                                       , gwt_path = self.row.gwt_path))

                        # Branch from GPARN.
        if    decision_row.output ==   p4gf_g2p_matrix2_ghost.BRANCH:
            decided = Decided( integ_flags      = '-Rbd'
                             , resolve_flags    = '-at'
                             , on_integ_failure = Decided.FALLBACK
                             , integ_fallback   = 'add'
                             , p4_request       = None
                             , integ_input      = decision_input
                             )
                        # To simplify later code, copy integration source
                        # from GPARN/GPARNFP into GHOST column so that
                        # later code can use GHOST as integ source.
            self._lazy_create_ghost_cell_discovered()
            _copy_discovered(self.ghost_cell, gparn_cell, gparfpn_cell)

                        # Branch from P4JITFP, submit,
                        # then DELETE in a second GHOST changelist.
        elif  decision_row.output ==   p4gf_g2p_matrix2_ghost.BRANCH_DELETE:
            decided = Decided( integ_flags      = '-Rbd'
                             , resolve_flags    = '-at'
                             , on_integ_failure = Decided.FALLBACK
                             , integ_fallback   = 'add'
                             , p4_request       = None
                             , integ_input      = decision_input
                             , branch_delete    = True
                             )
                        # To simplify later code, copy integration source
                        # from P4JITFP into GHOST column so that
                        # later code can use GHOST as integ source.
            self._lazy_create_ghost_cell_discovered()
            _copy_discovered(self.ghost_cell, self.p4jitfp_cell)

        elif  decision_row.output in [ p4gf_g2p_matrix2_ghost.EDIT
                                     , p4gf_g2p_matrix2_ghost.DELETE ]:
            decided = Decided( p4_request  = decision_row.output
                             , integ_input = decision_input )

        elif  decision_row.output ==   p4gf_g2p_matrix2_ghost.NOP:
            decided = None

        elif  decision_row.output ==   p4gf_g2p_matrix2_ghost.IMPOSSIBLE:
            LOG.error('IMPOSSIBLE ghost. Check your inputs. {}'.format(self.row.gwt_path))
            p4gf_g2p_matrix2_ghost.to_input(
                      p4jitfp_cell   = self.p4jitfp_cell
                    , gdest_cell     = self.gdest_cell
                    , gparn_cell     = gparn_cell
                    , gparfpn_cell   = gparfpn_cell
                    , ghost_cell     = self.ghost_cell
                    , gdest_column   = self.m._gdest_column
                    , gparn_column   = orig_gparn_col )

            raise RuntimeError(
                    _('ghost decision input {input} is impossible. gwt_path={gwt_path}')
                    .format( input    = p4gf_g2p_matrix2_ghost.deb(
                                              decision_input
                                            , fmt=p4gf_g2p_matrix2_ghost.LONG)
                           , gwt_path = self.row.gwt_path))
        else:
            raise RuntimeError(_('ghost decision input {input} produced unknown'
                                 ' output {output}. gwt_path={gwt_path}')
                               .format(
                                      input    = p4gf_g2p_matrix2_ghost.deb(decision_input)
                                    , output   = decision_row.output
                                    , gwt_path = self.row.gwt_path))

        return decided
예제 #12
0
    def ghost_decide(self, row):
        """Main entry point from Matrix.ghost_decide().

        What Perforce file action, if any, should we record in a
        ghost changelist?

        Store decision in ghost_cell.decided
        """
                        # pylint:disable=too-many-branches
        self._reset()

                        # Never include .p4gf_empty_changelist_placeholder in a
                        # GHOST changelist. Doing so will erroneously trigger
                        # "need to delete this file that isn't in Git" actions,
                        # which in turn leads to ghost changelists that do
                        # nothing but delete a placeholder. Pointless waste.
        if row.gwt_path == p4gf_const.P4GF_EMPTY_CHANGELIST_PLACEHOLDER:
            return

        self.row = row

        self.ghost_cell     = row.cell_if_col(self.m.ghost_column)
        self.gdest_cell     = row.cell_if_col(self.m._gdest_column)
        self.git_delta_cell = row.cell_if_col(self.m.git_delta_column)
        self.p4jitfp_cell   = row.cell_if_col(self.m._p4jitfp_column)

        orig_gparn_col = self.m.ghost_orig_gparn_column
        gparn_cell = row.cell_if_col(orig_gparn_col)
        if orig_gparn_col:
            gparfpn_cell = row.cell_if_col(orig_gparn_col.fp_counterpart)
        else:
            gparfpn_cell = None

                        # Special case for git-lfs-initial-track
                        # top-level .gitattributes files that do not (yet)
                        # exist in Perforce but do in Git.
                        #
                        # This is rare.
        decided = self._ghost_decide_from_git_lfs_initial_track(gparn_cell)

                        # Normal decision matrix code.
        if not decided:
            decided = self._ghost_decide_from_matrix(
                      gparn_cell     = gparn_cell
                    , gparfpn_cell   = gparfpn_cell
                    , orig_gparn_col = orig_gparn_col
                    )
                        # If we need to ghost LFS content into existence, do so
                        # from LFS de-dupe storage, NOT the usual ghost source.
        if (    decided
            and decided.p4_request != p4gf_g2p_matrix2_ghost.DELETE
            and self.ghost_cell.discovered
            and common.KEY_LFS in self.ghost_cell.discovered ):
            was_branch_delete = decided.branch_delete
            d2 = Decided( p4_request    = common.P4_REQUEST_LFS_COPY
                        , branch_delete = was_branch_delete
                        , integ_input   = decided.integ_input
                        )
            decided = d2

                        # Lazy-create a cell to hold the decision.
                        # +++ Unless that decision is "None".
                        # +++ Don't need a whole cell just to say "None".
        if decided:
            self._lazy_create_ghost_cell_discovered()
        if self.ghost_cell:
            self.ghost_cell.decided = decided
        return