Ejemplo n.º 1
0
    def _p4_add_in_bites(ctx, path_list):
        '''
        'p4 add' all the files in path_list, running multiple 'p4 add'
        commands if necessary to avoid adding more than _BITE_SIZE
        files in a single command.

        Return list of depotFile successfully opened.
        '''
        # Why copy.copy()? Because even though our caller doesn't really care
        # that we drain our list *today*, it might *tomorrow*. The C++
        # programmer in me really misses const and copy semantics. So I'll
        # write C++ in Python here to avoid that nasty surprise in the future.
        remainder_list = copy.copy(path_list)
        success_list = []
        while remainder_list:
            bite_list      = remainder_list[:_BITE_SIZE]
            remainder_list = remainder_list[_BITE_SIZE:]
            cmd = ['add', bite_list]
            ctx.p4gfrun(cmd)

            l = p4gf_p4msg.find_msgid(ctx.p4gf, p4gf_p4msgid.MsgDm_OpenSuccess)
            success_list.extend([x['depotFile'] for x in l])

        LOG.debug('_p4_add_in_bites() want={} success={}'
                  .format(len(path_list), len(success_list)))
        return success_list
Ejemplo n.º 2
0
    def _p4_add_in_bites(ctx, path_list):
        '''
        'p4 add' all the files in path_list, running multiple 'p4 add'
        commands if necessary to avoid adding more than _BITE_SIZE
        files in a single command.

        Return list of depotFile successfully opened.
        '''
        # Why copy.copy()? Because even though our caller doesn't really care
        # that we drain our list *today*, it might *tomorrow*. The C++
        # programmer in me really misses const and copy semantics. So I'll
        # write C++ in Python here to avoid that nasty surprise in the future.
        remainder_list = copy.copy(path_list)
        success_list = []
        while remainder_list:
            bite_list = remainder_list[:_BITE_SIZE]
            remainder_list = remainder_list[_BITE_SIZE:]
            cmd = ['add', bite_list]
            ctx.p4gfrun(cmd)

            l = p4gf_p4msg.find_msgid(ctx.p4gf, p4gf_p4msgid.MsgDm_OpenSuccess)
            success_list.extend([x['depotFile'] for x in l])

        LOG.debug('_p4_add_in_bites() want={} success={}'.format(
            len(path_list), len(success_list)))
        return success_list
def ensure_protect(protect_lines):
    """Require that 'p4 protect' table includes grant of admin to git-fusion-user.

    """
    with p4.at_exception_level(p4.RAISE_NONE):
        r = p4.run('protects', '-m', '-u', p4gf_const.P4GF_USER)

    if p4gf_p4msg.find_msgid(p4, p4gf_p4msgid.MsgDm_ProtectsEmpty):
        report(INFO, "Protect table empty. Setting....")

    report(DEBUG, 'p4 protects -mu git-fusion-user\n{}'.format(r))
    perm = p4gf_util.first_value_for_key(r, KEY_PERM_MAX)
    if perm and perm in ['admin', 'super']:
        report(INFO,
               ("Protect table already grants 'admin'" +
                " to user {}. Not changing").format(p4gf_const.P4GF_USER))
        return False

    l = protect_lines
    if p4gf_version.p4d_version_supports_admin_user(p4):
        perm = 'admin'
    else:
        perm = 'super'
    l.append('{perm} user {user} * //...'.format(perm=perm,
                                                 user=p4gf_const.P4GF_USER))

    p4gf_util.set_spec(p4, 'protect', values={KEY_PROTECTIONS: l})
    report(
        INFO, "Protect table modified. {} granted admin permission.".format(
            p4gf_const.P4GF_USER))
    return True
Ejemplo n.º 4
0
def _ensure_admin_privileges(p4):
    """Ensure that single git-fusion-user has admin privileges over GF depot."""
    is_protects_empty = False
    try:
        p4.run('protects', '-u', p4gf_const.P4GF_USER, '-m',
               '//{depot}/...'.format(depot=p4gf_const.P4GF_DEPOT))
    except P4.P4Exception:
        # Why MsgDm_ReferClient here? Because p4d 11.1 returns
        # "must refer to client" instead of "Protections table is empty" when
        # given a depot path to 'p4 protects -m -u'. Surprise!
        if p4gf_p4msg.find_msgid(p4, [p4gf_p4msgid.MsgDm_ProtectsEmpty,
                                      p4gf_p4msgid.MsgDm_ReferClient]):
            is_protects_empty = True
        # All other errors are fatal, propagated.

    if is_protects_empty:
        # - order the lines in increasing permission
        # - end with at least one user (even a not-yet-created user) with super
        #     write user * * //...
        #     admin user git-fusion-user * //...
        #     super user super * //...
        p4gf_p4spec.set_spec(p4, 'protect', values={
            'Protections': ["super user * * //...",
                            "super user {user} * //...".format(user=p4gf_const.P4GF_USER),
                            "admin user {user} * //{depot}/..."
                            .format(user=p4gf_const.P4GF_USER, depot=p4gf_const.P4GF_DEPOT)]})
        _info(_('Protects table set.'))
def ensure_protect(protect_lines):
    """Require that 'p4 protect' table includes grant of admin to git-fusion-user.

    """
    with p4.at_exception_level(p4.RAISE_NONE):
        r = p4.run('protects', '-m', '-u', p4gf_const.P4GF_USER)

    if p4gf_p4msg.find_msgid(p4, p4gf_p4msgid.MsgDm_ProtectsEmpty):
        report(INFO, "Protect table empty. Setting....")

    report(DEBUG, 'p4 protects -mu git-fusion-user\n{}'.format(r))
    perm = p4gf_util.first_value_for_key(r, KEY_PERM_MAX)
    if perm and perm in ['admin', 'super']:
        report(INFO, ( "Protect table already grants 'admin'"
                     + " to user {}. Not changing").format(p4gf_const.P4GF_USER))
        return False

    l = protect_lines
    if p4gf_version.p4d_version_supports_admin_user(p4):
        perm = 'admin'
    else:
        perm = 'super'
    l.append('{perm} user {user} * //...'.format(perm=perm, user=p4gf_const.P4GF_USER))

    p4gf_util.set_spec(p4, 'protect', values={KEY_PROTECTIONS : l})
    report(INFO, "Protect table modified. {} granted admin permission."
                 .format(p4gf_const.P4GF_USER))
    return True
Ejemplo n.º 6
0
def ensure_protect(protect_lines):
    """Require that 'p4 protect' table includes grant of admin to git-fusion-user.

    And review to git-fusion-reviews-*
    """
    with p4.at_exception_level(p4.RAISE_NONE):
        r = p4.run('protects', '-m', '-u', p4gf_const.P4GF_USER)

    if p4gf_p4msg.find_msgid(p4, p4gf_p4msgid.MsgDm_ProtectsEmpty):
        Verbosity.report(Verbosity.INFO, _("Protect table empty. Setting...."))

    l = None
    gfuser_perms_set = False
    reviews_users_perms_set = False
    Verbosity.report(Verbosity.DEBUG, NTR('p4 protects -mu git-fusion-user\n{}').format(r))
    perm = p4gf_util.first_value_for_key(r, KEY_PERM_MAX)
    if perm and perm in ['admin', 'super']:
        Verbosity.report(Verbosity.INFO,
                         _("Protect table already grants 'admin' to user '{user}'. Not changing")
                         .format(user=p4gf_const.P4GF_USER))
    else:
        l = protect_lines
        l.append('admin user {user} * //...'.format(user=p4gf_const.P4GF_USER))
        gfuser_perms_set = True

    review_perm = 'review user git-fusion-reviews-* * //...'
    review_perm_user_mask = 'review user git-fusion-reviews-*'
    review_perm_exists = False
    for perm in protect_lines:
        if perm.startswith(review_perm_user_mask):
                        # Do not insert a newline into this line even
                        # though it is long. Makes it too hard to test
                        # in p4gf_super_init.t
            Verbosity.report(
                Verbosity.INFO,
                _("Protect table already grants 'review' to users 'git-fusion-reviews-*'."
                  " Not changing"))
            review_perm_exists = True
            break

    if not review_perm_exists:
        if not l:
            l = protect_lines
        l.append(review_perm)
        reviews_users_perms_set = True

    if l:
        p4gf_p4spec.set_spec(p4, 'protect', values={KEY_PROTECTIONS: l})
        if gfuser_perms_set:
            Verbosity.report(
                Verbosity.INFO,
                _("Protect table modified. User '{user}' granted admin permission.")
                .format(user=p4gf_const.P4GF_USER))
        if reviews_users_perms_set:
            Verbosity.report(
                Verbosity.INFO,
                _("Protect table modified. git-fusion-reviews-* granted reviews permission."))
Ejemplo n.º 7
0
def _global_init(p4):
    """Create global Git Fusion Perforce data:
    * user git-fusion-user
    * depot //.git-fusion
    * group git-fusion-pull
    * group git-fusion-push
    * protects entries
    """

    #
    # The global initialization process below must be idempotent in the sense
    # that it is safe to perform more than once. As such, there are checks to
    # determine if work is needed or not, and if that work results in an
    # error, log and carry on with the rest of the steps, with the assumption
    # that a previous attempt had failed in the middle (or possibly that
    # another instance of Git Fusion has started at nearly the same time as
    # this one).
    #

    with p4gf_group.PermErrorOK(p4):
        p4gf_util.ensure_user_gf(p4)

    with p4gf_group.PermErrorOK(p4):
        p4gf_util.ensure_depot_gf(p4)

    p4gf_group.create_global_perm(p4, p4gf_group.PERM_PULL)
    p4gf_group.create_global_perm(p4, p4gf_group.PERM_PUSH)
    p4gf_group.create_default_perm(p4)

    ### ONCE ADMIN works, downgrade our auto-generated Protections
    ### table to git-fusion-user=admin, not super, and user * = write.

    # Require that single git-fusion-user have admin privileges
    # over the //.git-fusion/ depot
    is_protects_empty = False
    try:
        ### ONCE ADMIN works, remove the use of -u option
        p4.run('protects', '-u', p4gf_const.P4GF_USER, '-m',
               '//{depot}/...'.format(depot=p4gf_const.P4GF_DEPOT))
    except P4.P4Exception:
        if p4gf_p4msg.find_msgid(p4, p4gf_p4msgid.MsgDm_ProtectsEmpty):
            is_protects_empty = True
        # All other errors are fatal, propagated.

    if is_protects_empty:
        ### ONCE ADMIN works, modify the protects table as follows
        # - order the lines in increasing permission
        # - end with at least one user (even a not-yet-created user) with super
        #     write user * * //...
        #     admin user git-fusion-user * //...
        #     super user super * //...
        p4gf_util.set_spec(p4, 'protect', values={
            'Protections': ["super user * * //...",
                            "super user {user} * //...".format(user=p4gf_const.P4GF_USER),
                            "admin user {user} * //{depot}/..."
                            .format(user=p4gf_const.P4GF_USER, depot=p4gf_const.P4GF_DEPOT)]})
Ejemplo n.º 8
0
    def _create_client_for_view_lines(self, view_lines):
        """Create a new client spec with the requested view_lines.

        Return its name.
        """
        if not len(view_lines):
            raise RuntimeError(_("Can't create client with empty view."))

        client_name, client_root, desc = self._create_client_name_root_desc()

        # Replace RHS lines with new client name.
        new_view_map = p4gf_branch.replace_client_name(
            view_lines, self.ctx.config.p4client, client_name)

        if LOG.isEnabledFor(logging.DEBUG3):
            LOG.debug3(
                '_create_client_for_view_lines() name={} view={}'.format(
                    client_name, new_view_map.as_array()))
        else:
            LOG.debug2(
                '_create_client_for_view_lines() name={}'.format(client_name))
        try:
            _create_temporary_client(self.ctx.p4gf,
                                     client_name,
                                     client_root,
                                     desc,
                                     view_map=new_view_map)
        except Exception as e:  # pylint: disable=broad-except

            # If git-fusion-user does not have write permission to the repo view paths
            # then 'p4 client -i' command fails with:
            #   Error in client specification. Mapping '%depotFile%' is not under '%prefix%'."
            # This is caused by the protects table not granting write permissions to those views.
            # Return a message indicating the permissions failure and the Exception's message.
            if p4gf_p4msg.find_msgid(self.ctx.p4gf,
                                     p4gf_p4msgid.MsgDm_MapNotUnder):
                LOG.error(
                    _("git-fusion-user not granted sufficient privileges.\n"
                      "          Check the P4 protects entry for git-fusion-user.\n"
                      "          The IP field must match the IP set in P4PORT={p4port}"
                      ).format(p4port=os.environ['P4PORT']))
                raise RuntimeError(
                    _("Perforce: git-fusion-user not granted sufficient privileges."
                      " Please contact your admin.\n")) from e
            else:
                raise

        return (client_name, new_view_map, client_root)
Ejemplo n.º 9
0
    def _p4_sync_k_edit(ctx, path_list):
        '''
        'p4 sync -k' then 'p4 edit' the paths.

        Return list of depotFile successfully opened.
        '''
        if not path_list:
            return []

        cmd = ['sync', '-k', path_list]
        ctx.p4gfrun(cmd)
        cmd = ['edit', '-k', path_list]
        ctx.p4gfrun(cmd)

        l = p4gf_p4msg.find_msgid(ctx.p4gf, p4gf_p4msgid.MsgDm_OpenSuccess)
        success_list = [x['depotFile'] for x in l]
        return success_list
Ejemplo n.º 10
0
    def _p4_sync_k_edit(ctx, path_list):
        '''
        'p4 sync -k' then 'p4 edit' the paths.

        Return list of depotFile successfully opened.
        '''
        if not path_list:
            return []

        cmd = ['sync', '-k', path_list]
        ctx.p4gfrun(cmd)
        cmd = ['edit', '-k', path_list]
        ctx.p4gfrun(cmd)

        l = p4gf_p4msg.find_msgid(ctx.p4gf, p4gf_p4msgid.MsgDm_OpenSuccess)
        success_list = [x['depotFile'] for x in l]
        return success_list
Ejemplo n.º 11
0
def acquire(p4_or_ctx, key_name):
    """Acquire a lock via 'p4 key -i' atomic increment.

    Return True if caller now exclusively owns this key and all it
    controls. Caller must call delete() when done.

    Return False if some other process owns this key and all it controls.

    """
    try:
        value = increment(p4_or_ctx, key_name)
        return "1" == value
    except P4Exception:
        # incrementing a non-integer value raises without modifying the p4key
        # that's expected and not a real error, just a failure to acquire
        if p4gf_p4msg.find_msgid(p4_or_ctx, p4gf_p4msgid.MsgServer_KeyNotNumeric):
            return False
        raise
Ejemplo n.º 12
0
def p4d_supports_protects(p4):
    """Check that p4d is ALREADY configured to give git-fusion-user
    permission to run 'p4 protects -u'. Return False if not.

    *** This function does not really belong here! ***
    This is NOT a version check, but I'm sticking it in this
    file anyway because the OVA web UI needs this function, and the OVA
    web UI already has access to p4gf_version_26.py.
    """
    okay = False
    try:
        p4.run('protects', '-u', p4gf_const.P4GF_USER, '-m')
        # if we can use -u, we're good to go
        okay = True
    except P4Exception:
        e = sys.exc_info()[1]
        LOG.warning("'protects -u' failed: {0}".format(e))
        if p4gf_p4msg.find_msgid(p4, p4gf_p4msgid.MsgDm_ProtectsEmpty):
            okay = True
        # All other errors are fatal
    return okay
Ejemplo n.º 13
0
def p4d_supports_protects(p4):
    '''
    Check that p4d is ALREADY configured to give git-fusion-user
    permission to run 'p4 protects -u'. Return False if not.

    *** This function does not really belong here! ***
    This is NOT a version check, but I'm sticking it in this
    file anyway because the OVA web UI needs this function, and the OVA
    web UI already has access to p4gf_version_26.py.
    '''
    okay = False
    try:
        p4.run('protects', '-u', p4gf_const.P4GF_USER, '-m')
        # if we can use -u, we're good to go
        okay = True
    except P4Exception:
        e = sys.exc_info()[1]
        LOG.warn("'protects -u' failed: {0}".format(e))
        if p4gf_p4msg.find_msgid(p4, p4gf_p4msgid.MsgDm_ProtectsEmpty):
            okay = True
        # All other errors are fatal
    return okay
Ejemplo n.º 14
0
def ensure_protect(protect_lines):
    """Require that 'p4 protect' table includes grant of admin to git-fusion-user.
    And review to git-fusion-reviews-*
    """
    with p4.at_exception_level(p4.RAISE_NONE):
        r = p4.run('protects', '-m', '-u', p4gf_const.P4GF_USER)

    if p4gf_p4msg.find_msgid(p4, p4gf_p4msgid.MsgDm_ProtectsEmpty):
        Verbosity.report(Verbosity.INFO, _("Protect table empty. Setting...."))

    l = None
    Verbosity.report(Verbosity.DEBUG, NTR('p4 protects -mu git-fusion-user\n{}').format(r))
    perm = p4gf_util.first_value_for_key(r, KEY_PERM_MAX)
    if perm and perm in ['admin', 'super']:
        Verbosity.report(Verbosity.INFO,
                         _("Protect table already grants 'admin' to user '{}'. Not changing")
                         .format(p4gf_const.P4GF_USER))
    else:
        l = protect_lines
        l.append('admin user {user} * //...'.format(user=p4gf_const.P4GF_USER))

    review_perm = 'review user git-fusion-reviews-* * //...'
    if review_perm in protect_lines:
                        # Do not insert a newline into this line even
                        # though it is long. Makes it too hard to test
                        # in p4gf_super_init.t
        Verbosity.report(Verbosity.INFO,
            _("Protect table already grants 'review' to users 'git-fusion-reviews-*'."
              "Not changing"))
    else:
        if not l:
            l = protect_lines
        l.append(review_perm)

    if l:
        p4gf_util.set_spec(p4, 'protect', values={KEY_PROTECTIONS : l})
        Verbosity.report(Verbosity.INFO,
                _("Protect table modified. User '{}' granted admin permission.")
                .format(p4gf_const.P4GF_USER))