Example #1
0
def update_tags(ctx):
    """Based on the recent changes to the tags, update our repository
    (remove deleted tags, add new pushed tags).
    """
    last_copied_change = _read_last_copied_tag(ctx)
    tags_prefix = '{root}/repos/{repo}/tags/'.format(
        root=p4gf_const.objects_root(), repo=ctx.config.repo_name)
    tags_path = '{prefix}...'.format(prefix=tags_prefix)
    num = 1 + int(last_copied_change)
    r = ctx.p4gfrun('changes', '-s', 'submitted', '-e', num, tags_path)
    changes = sorted(r, key=lambda k: int(k['change']))
    for change in changes:
        LOG.debug2('update_tags() processing {}'.format(change['change']))
        d = ctx.p4gfrun('describe', change['change'])
        d = p4gf_util.first_dict(d)
        for d_file, rev, action in zip(d['depotFile'], d['rev'], d['action']):
            LOG.debug2('update_tags() processing {} - {}'.format(
                d_file, action))
            if not d_file.startswith(tags_prefix):
                LOG.info('non-tag file {} in tag-related Git Fusion change {}'.
                         format(d_file, change['change']))
                continue
            if action == 'add':
                r = ctx.p4gfrun('sync', '-f', "{}#{}".format(d_file, rev))
                r = p4gf_util.first_dict(r)
                _install_tag(ctx.repo, r['clientFile'])
            elif action == 'delete':
                r = ctx.p4gfrun('sync', '-f',
                                "{}#{}".format(d_file,
                                               int(rev) - 1))
                r = p4gf_util.first_dict(r)
                _uninstall_tag(ctx.repo, r['clientFile'])
            elif action == 'edit':
                # get the tags named in the file prior to this change
                tags_before = _read_tags(ctx, d_file, int(rev) - 1)
                # get the tags named in the file after this change
                tags_after = _read_tags(ctx, d_file)
                # remove old (lightweight) tags and add new ones
                sha1 = d_file[-42:].replace('/', '')
                for old_tag in tags_before - tags_after:
                    _remove_tag_ref(old_tag, sha1)
                for new_tag in tags_after - tags_before:
                    _create_tag_ref(ctx.repo, new_tag, sha1)
            else:
                LOG.error(
                    "update_tags() received an unexpected change action: " +
                    "@{}, '{}' on {}".format(change['change'], action, d_file))
    _write_last_copied_tag(ctx, changes[-1]['change'])
Example #2
0
def generate_tags(ctx):
    """
    Regenerate the original tags into the (rebuilt) Git repository.
    This should only be called when the repository was just rebuilt
    from Perforce, otherwise it will do a bunch of work for nothing.
    """
    # Fetch everything under //.git-fusion/objects/repos/<repo>/tags/...
    tags_path = NTR('objects/repos/{repo}/tags').format(
        repo=ctx.config.view_name)
    with ctx.p4gf.at_exception_level(P4.P4.RAISE_NONE):
        client_path = "//{}/{}/...".format(ctx.config.p4client_gf, tags_path)
        ctx.p4gfrun(['sync', '-f', '-q', client_path])

    # Walk the tree looking for tags, reconstituting those we encounter.
    tags_root = os.path.join(ctx.gitlocalroot, tags_path)
    for walk_root, _, files in os.walk(tags_root):
        for name in files:
            fname = os.path.join(walk_root, name)
            _install_tag(ctx.view_repo, fname)

    # Update the tag change counter to avoid repeating our efforts.
    last_copied_change = _read_last_copied_tag(ctx)
    tags_path = '{root}/repos/{repo}/tags/...@{num},#head'.format(
        root=p4gf_const.objects_root(),
        repo=ctx.config.view_name,
        num=1 + int(last_copied_change))
    r = ctx.p4gfrun(['changes', '-m1', '-s', 'submitted', tags_path])
    changes = p4gf_util.first_dict(r)
    if changes:
        _write_last_copied_tag(ctx, changes['change'])
Example #3
0
def spec_values_match(p4, spec_type, spec_id, values):
    """Verify that the spec holds desired values, returning True if okay."""
    spec = p4gf_util.first_dict(p4.run(spec_type, '-o', spec_id))
    for key in values:
        if spec.get(key) != values[key]:
            return False
    return True
Example #4
0
    def log_context(self):
        """Dump connection info, client info, directories, all to log category
        'context' as INFO."""

        log = logging.getLogger('context')
        if not log.isEnabledFor(logging.INFO):
            return

        # Dump client spec as raw untagged text.
        self.p4.tagged = 0
        client_lines_raw = self.p4.run('client', '-o')[0].splitlines()
        self.p4.tagged = 1
        # Strip comment header
        client_lines = [l for l in client_lines_raw if not l.startswith('#')]

        # Dump p4 info, tagged, since that includes more pairs than untagged.
        p4info = p4gf_util.first_dict(self.p4.run('info'))
        key_len_max = max(len(k) for k in p4info.keys())
        info_template = NTR('%-{}s : %s').format(key_len_max)

        log.info(info_template, 'P4PORT',     self.p4.port)
        log.info(info_template, 'P4USER',     self.p4.user)
        log.info(info_template, 'P4CLIENT',   self.p4.client)
        log.info(info_template, 'p4gfclient', self.p4gf.client)

        for k in sorted(p4info.keys(), key=str.lower):
            log.info(info_template, k, p4info[k])

        for line in client_lines:
            log.info(line)
Example #5
0
def generate_tags(ctx):
    """
    Regenerate the original tags into the (rebuilt) Git repository.
    This should only be called when the repository was just rebuilt
    from Perforce, otherwise it will do a bunch of work for nothing.
    """
    # Fetch everything under //.git-fusion/objects/repos/<repo>/tags/...
    tags_path = NTR('objects/repos/{repo}/tags').format(repo=ctx.config.view_name)
    with ctx.p4gf.at_exception_level(P4.P4.RAISE_NONE):
        client_path = "//{}/{}/...".format(ctx.config.p4client_gf, tags_path)
        ctx.p4gfrun(['sync', '-f', '-q', client_path])

    # Walk the tree looking for tags, reconstituting those we encounter.
    tags_root = os.path.join(ctx.gitlocalroot, tags_path)
    for walk_root, _, files in os.walk(tags_root):
        for name in files:
            fname = os.path.join(walk_root, name)
            _install_tag(ctx.view_repo, fname)

    # Update the tag change counter to avoid repeating our efforts.
    last_copied_change = _read_last_copied_tag(ctx)
    tags_path = '{root}/repos/{repo}/tags/...@{num},#head'.format(
        root=p4gf_const.objects_root(),
        repo=ctx.config.view_name,
        num=1 + int(last_copied_change))
    r = ctx.p4gfrun(['changes', '-m1', '-s', 'submitted', tags_path])
    changes = p4gf_util.first_dict(r)
    if changes:
        _write_last_copied_tag(ctx, changes['change'])
def ensure_group():
    """Create Perforce group git-fusion-group if not already exists."""
    users = []
    # Keep the order of the users in the same order that P4 insists on
    # (if the order doesn't match then the group is updated repeatedly).
    users.append(p4gf_const.P4GF_REVIEWS__ALL_GF)
    users.append(p4gf_const.P4GF_REVIEWS__NON_GF)
    users.append(p4gf_util.gf_reviews_user_name())
    users.append(p4gf_const.P4GF_USER)
    args = [p4, NTR("group")]
    spec = {'Timeout': NTR('unlimited'), 'Users': users}
    kwargs = {'spec_id': p4gf_const.P4GF_GROUP, 'values': spec}
    if not p4gf_util.ensure_spec(*args, **kwargs):
        # We change the list of users in the group from time to time,
        # so ensure the membership is up to date.
        users = p4gf_util.first_dict(p4.run('group', '-o', p4gf_const.P4GF_GROUP))['Users']
        # Add the gf_reviews_user_name if not already in the group.
        # This avoids removing already existing reviews users from multiple GF instances.
        if not p4gf_util.gf_reviews_user_name() in users:
            users.append(p4gf_util.gf_reviews_user_name())
            spec = {'Timeout': NTR('unlimited'), 'Users': users}
            kwargs = {'spec_id': p4gf_const.P4GF_GROUP, 'values': spec}
            if p4gf_util.ensure_spec_values(*args, **kwargs):
                Verbosity.report(Verbosity.INFO
                                , _("Group '{}' updated.").format(p4gf_const.P4GF_GROUP))
            else:
                Verbosity.report(Verbosity.INFO, _("Group '{}' already up to date.")
                                 .format(p4gf_const.P4GF_GROUP))
        else:
            Verbosity.report(Verbosity.INFO, _("Group '{}' already up to date.")
                             .format(p4gf_const.P4GF_GROUP))
        return False
    else:
        Verbosity.report(Verbosity.INFO, _("Group '{}' created.").format(p4gf_const.P4GF_GROUP))
    return True
Example #7
0
def update_tags(ctx):
    """
    Based on the recent changes to the tags, update our repository
    (remove deleted tags, add new pushed tags).
    """
    if not ctx.view_repo:
        # In some cases the Git repository object is not yet created.
        ctx.view_repo = pygit2.Repository(ctx.view_dirs.GIT_DIR)

    last_copied_change = _read_last_copied_tag(ctx)
    tags_path = '{root}/repos/{repo}/tags/...@{num},#head'.format(
        root=p4gf_const.objects_root(),
        repo=ctx.config.view_name,
        num=1 + int(last_copied_change))
    r = ctx.p4gfrun(['changes', '-s', 'submitted', tags_path])
    changes = sorted(r, key=lambda k: int(k['change']))
    for change in changes:
        d = ctx.p4gfrun(['describe', change['change']])
        d = p4gf_util.first_dict(d)
        for d_file, action in zip(d['depotFile'], d['action']):
            if action == 'add':
                r = ctx.p4gfrun(['sync', '-f', d_file])
                r = p4gf_util.first_dict(r)
                _install_tag(ctx.view_repo, r['clientFile'])
            elif action == 'delete':
                change_num = int(change['change']) - 1
                r = ctx.p4gfrun(
                    ['sync', '-f', "{}@{}".format(d_file, change_num)])
                r = p4gf_util.first_dict(r)
                _uninstall_tag(ctx.view_repo, r['clientFile'])
            elif action == 'edit':
                # get the tags named in the file prior to this change
                tags_before = _read_tags(ctx, d_file,
                                         int(change['change']) - 1)
                # get the tags named in the file after this change
                tags_after = _read_tags(ctx, d_file)
                # remove old (lightweight) tags and add new ones
                sha1 = d_file[-42:].replace('/', '')
                for old_tag in tags_before - tags_after:
                    _remove_tag_ref(old_tag, sha1)
                for new_tag in tags_after - tags_before:
                    _create_tag_ref(ctx.view_repo, new_tag, sha1)
            else:
                LOG.error(
                    "update_tags() received an unexpected change action: " +
                    "@{}, '{}' on {}".format(change['change'], action, d_file))
    _write_last_copied_tag(ctx, changes[-1]['change'])
Example #8
0
 def _is_case_sensitive(self):
     """
     Returns True if the server indicates case-handling is 'sensitive',
     and False otherwise.
     """
     if self._case_sensitive is None:
         info = p4gf_util.first_dict(self.p4.run('info'))
         self._case_sensitive = info.get('caseHandling') == 'sensitive'
     return self._case_sensitive
Example #9
0
def update_tags(ctx):
    """
    Based on the recent changes to the tags, update our repository
    (remove deleted tags, add new pushed tags).
    """
    if not ctx.view_repo:
        # In some cases the Git repository object is not yet created.
        ctx.view_repo = pygit2.Repository(ctx.view_dirs.GIT_DIR)

    last_copied_change = _read_last_copied_tag(ctx)
    tags_path = '{root}/repos/{repo}/tags/...@{num},#head'.format(
        root=p4gf_const.objects_root(),
        repo=ctx.config.view_name,
        num=1 + int(last_copied_change))
    r = ctx.p4gfrun(['changes', '-s', 'submitted', tags_path])
    changes = sorted(r, key=lambda k: int(k['change']))
    for change in changes:
        d = ctx.p4gfrun(['describe', change['change']])
        d = p4gf_util.first_dict(d)
        for d_file, action in zip(d['depotFile'], d['action']):
            if action == 'add':
                r = ctx.p4gfrun(['sync', '-f', d_file])
                r = p4gf_util.first_dict(r)
                _install_tag(ctx.view_repo, r['clientFile'])
            elif action == 'delete':
                change_num = int(change['change']) - 1
                r = ctx.p4gfrun(['sync', '-f', "{}@{}".format(d_file, change_num)])
                r = p4gf_util.first_dict(r)
                _uninstall_tag(ctx.view_repo, r['clientFile'])
            elif action == 'edit':
                # get the tags named in the file prior to this change
                tags_before = _read_tags(ctx, d_file, int(change['change']) - 1)
                # get the tags named in the file after this change
                tags_after = _read_tags(ctx, d_file)
                # remove old (lightweight) tags and add new ones
                sha1 = d_file[-42:].replace('/', '')
                for old_tag in tags_before - tags_after:
                    _remove_tag_ref(old_tag, sha1)
                for new_tag in tags_after - tags_before:
                    _create_tag_ref(ctx.view_repo, new_tag, sha1)
            else:
                LOG.error("update_tags() received an unexpected change action: " +
                          "@{}, '{}' on {}".format(change['change'], action, d_file))
    _write_last_copied_tag(ctx, changes[-1]['change'])
Example #10
0
def _review_id_status(ctx, review_id):
    """Run 'p4 change -o' on the review's changelist and return its status.

    Return None if not found.
    """
    with ctx.p4.at_exception_level(ctx.p4.RAISE_NONE):
        rr = p4gf_util.first_dict(ctx.p4run('change', '-o', review_id))
        if rr and hasattr(rr, '__getitem__') and rr.get('Status'):
            return rr.get('Status')
        else:
            return None
def process_imports(ctx):
    """Ensure stream imports are processed appropriately.

    The parent repository has already been initialized and populated.
    This function only applies to clients with a stream that contains
    import(ed) paths. For all other clients this will be a NOP.

    """
    if not ctx.is_feature_enabled(p4gf_config.FEATURE_IMPORTS):
        return
    # check if this client has a virtual stream
    # (need to force the stream-ish definition of the client, if one exists)
    branch = p4gf_branch.most_equal(ctx.branch_dict())
    LOG.debug2('process_imports() branch {}'.format(branch))
    if branch and branch.stream_name:
        LOG.debug2('process_imports() switching to {}'.format(branch))
        ctx.switch_client_to_stream(branch)
    client = ctx.p4.fetch_client()
    LOG.debug2('process_imports() checking {} for a stream'.format(
        client['Client']))
    if 'Stream' not in client:
        LOG.debug2('process_imports() {} is not a stream client'.format(
            client['Client']))
        return
    virt_stream = client['Stream']
    virtual = ctx.p4.fetch_stream(virt_stream)
    if 'Parent' not in virtual or virtual['Parent'] == 'none':
        LOG.debug2('process_imports() {} has no parent'.format(virt_stream))
        return
    if virtual['Type'] != 'virtual':
        LOG.debug2(
            'process_imports() {} created prior to submodules support'.format(
                virt_stream))
        return
    parent = p4gf_util.first_dict(
        ctx.p4.run('stream', '-ov', virtual['Parent']))
    LOG.debug3('process_imports() parent stream={}'.format(parent))
    v_paths = virtual['Paths']
    p_paths = parent['Paths']
    import_paths = p4gf_streams.match_import_paths(v_paths, p_paths)
    if not import_paths:
        LOG.debug2(
            'process_imports() {} has no exclude paths'.format(virt_stream))
        return
    if ctx.view_repo is None:
        # ensure the pygit2 repository is ready to go
        ctx.get_view_repo()
    #pylint:disable=W0703
    try:
        import_submodules(ctx, parent['View'], parent.get('ChangeView'),
                          import_paths)
    except Exception:
        LOG.error("submodule imports failed...\n{}".format(
            traceback.format_exc()))
Example #12
0
def _read_tags(ctx, depot_path, change_num=None):
    """
    Return the set of (lightweight) tag names read from the given file.
    """
    if change_num:
        cmd = ['sync', '-f', "{}@{}".format(depot_path, change_num)]
    else:
        cmd = ['sync', '-f', depot_path]
    r = ctx.p4gfrun(cmd)
    r = p4gf_util.first_dict(r)
    with open(r['clientFile'], 'rb') as f:
        contents = f.read()
    tag_names = contents.decode('UTF-8').splitlines()
    return set(tag_names)
Example #13
0
def _read_tags(ctx, depot_path, change_num=None):
    """
    Return the set of (lightweight) tag names read from the given file.
    """
    if change_num:
        cmd = ['sync', '-f', "{}@{}".format(depot_path, change_num)]
    else:
        cmd = ['sync', '-f', depot_path]
    r = ctx.p4gfrun(cmd)
    r = p4gf_util.first_dict(r)
    with open(r['clientFile'], 'rb') as f:
        contents = f.read()
    tag_names = contents.decode('UTF-8').splitlines()
    return set(tag_names)
 def write_map(self, p4, p4map):
     """Write our spec to Perforce."""
     spec = p4gf_util.first_dict(p4.run('branch', '-o', self.name))
     spec['Options'] = NTR(
         'unlocked')  # 'locked' complicates cleanup/delete.
     spec['View'] = p4map.as_array()
     spec['Description'] = _("Temporary mapping created during 'git push'.")
     if LOG.isEnabledFor(logging.DEBUG3):
         LOG.debug3('write_map() name={} view={}'.format(
             self.name, spec['View']))
     else:
         LOG.debug2('write_map() name={}'.format(self.name))
     p4.save_branch(spec)
     self.written = True
Example #15
0
def fetch_client(p4, client_name=None, routeless=False):
    """Retrieve the specification for the named client.

    :param p4: P4API instance.
    :param str client_name: name of P4 client to temporarily switch to (default None).
    :param bool routeless: if True, switch connection to not have a 'route' flag (default False).

    """
    with ExitStack() as stack:
        if routeless:
            p4 = stack.enter_context(p4gf_create_p4.routeless(p4))
        if client_name:
            stack.enter_context(p4gf_util.restore_client(p4, client_name))
        spec = p4gf_util.first_dict(p4.run('client', '-o'))
    return spec
Example #16
0
def fetch_client_template(p4, client_name, template_client, routeless=False):
    """Create a specification for the named client using the given template.

    :param p4: P4API instance.
    :param str client_name: name of P4 client to temporarily switch to (default None).
    :param str template_client: name of P4 client to use as a template.
    :param bool routeless: if True, switch connection to not have a 'route' flag (default False).

    """
    with ExitStack() as stack:
        if routeless:
            p4 = stack.enter_context(p4gf_create_p4.routeless(p4))
        stack.enter_context(p4gf_util.restore_client(p4, client_name))
        spec = p4gf_util.first_dict(p4.run('client', '-o', '-t', template_client))
    return spec
def _find_gitmodules(p4, stream_name):
    """Retrieve the depot path of the .gitmodules file for this stream.

    :param p4: instance of P4
    :param stream_name: name of the virtual stream

    Returns None if the .gitmodules file was not in the stream view.

    """
    parent = p4gf_util.first_dict(p4.run('stream', '-ov', stream_name))
    for line in parent['View']:
        if '.gitmodules' in line:
            # return everything up to the ' .gitmodules' at the end of the line
            return line[:-12]
    return None
Example #18
0
def process_imports(ctx):
    """Ensure stream imports are processed appropriately.

    The parent repository has already been initialized and populated.
    This function only applies to clients with a stream that contains
    import(ed) paths. For all other clients this will be a NOP.

    """
    if not ctx.is_feature_enabled(p4gf_config.FEATURE_IMPORTS):
        return
    # check if this client has a virtual stream
    # (need to force the stream-ish definition of the client, if one exists)
    branch = p4gf_branch.most_equal(ctx.branch_dict())
    LOG.debug2('process_imports() branch {}'.format(branch))
    if branch and branch.stream_name:
        LOG.debug2('process_imports() switching to {}'.format(branch))
        ctx.switch_client_to_stream(branch)
    client = ctx.p4.fetch_client()
    LOG.debug2('process_imports() checking {} for a stream'.format(client['Client']))
    if 'Stream' not in client:
        LOG.debug2('process_imports() {} is not a stream client'.format(client['Client']))
        return
    virt_stream = client['Stream']
    virtual = ctx.p4.fetch_stream(virt_stream)
    if 'Parent' not in virtual or virtual['Parent'] == 'none':
        LOG.debug2('process_imports() {} has no parent'.format(virt_stream))
        return
    if virtual['Type'] != 'virtual':
        LOG.debug2('process_imports() {} created prior to submodules support'.format(virt_stream))
        return
    parent = p4gf_util.first_dict(ctx.p4.run('stream', '-ov', virtual['Parent']))
    LOG.debug3('process_imports() parent stream={}'.format(parent))
    v_paths = virtual['Paths']
    p_paths = parent['Paths']
    import_paths = p4gf_streams.match_import_paths(v_paths, p_paths)
    if not import_paths:
        LOG.debug2('process_imports() {} has no exclude paths'.format(virt_stream))
        return
    if ctx.view_repo is None:
        # ensure the pygit2 repository is ready to go
        ctx.get_view_repo()
    #pylint:disable=W0703
    try:
        import_submodules(ctx, parent['View'], parent.get('ChangeView'), import_paths)
    except Exception:
        LOG.error("submodule imports failed...\n{}".format(traceback.format_exc()))
def ensure_group():
    """Create Perforce group git-fusion-group if not already exists."""
    users = []
    # Keep the order of the users in the same order that P4 insists on
    # (if the order doesn't match then the group is updated repeatedly).
    users.append(p4gf_const.P4GF_REVIEWS__ALL_GF)
    users.append(p4gf_const.P4GF_REVIEWS__NON_GF)
    users.append(p4gf_util.gf_reviews_user_name())
    users.append(p4gf_const.P4GF_USER)
    args = [p4, NTR("group")]
    spec = {'Timeout': NTR('unlimited'), 'Users': users}
    kwargs = {'spec_id': p4gf_const.P4GF_GROUP, 'values': spec}
    if not p4gf_util.ensure_spec(*args, **kwargs):
        # We change the list of users in the group from time to time,
        # so ensure the membership is up to date.
        users = p4gf_util.first_dict(
            p4.run('group', '-o', p4gf_const.P4GF_GROUP))['Users']
        # Add the gf_reviews_user_name if not already in the group.
        # This avoids removing already existing reviews users from multiple GF instances.
        if not p4gf_util.gf_reviews_user_name() in users:
            users.append(p4gf_util.gf_reviews_user_name())
            spec = {'Timeout': NTR('unlimited'), 'Users': users}
            kwargs = {'spec_id': p4gf_const.P4GF_GROUP, 'values': spec}
            if p4gf_util.ensure_spec_values(*args, **kwargs):
                Verbosity.report(
                    Verbosity.INFO,
                    _("Group '{}' updated.").format(p4gf_const.P4GF_GROUP))
            else:
                Verbosity.report(
                    Verbosity.INFO,
                    _("Group '{}' already up to date.").format(
                        p4gf_const.P4GF_GROUP))
        else:
            Verbosity.report(
                Verbosity.INFO,
                _("Group '{}' already up to date.").format(
                    p4gf_const.P4GF_GROUP))
        return False
    else:
        Verbosity.report(
            Verbosity.INFO,
            _("Group '{}' created.").format(p4gf_const.P4GF_GROUP))
    return True
Example #20
0
def ensure_spec_values(p4, spec_type, spec_id, values):
    """
    Spec exists but holds unwanted values? Replace those values.

    Does NOT create spec if missing. The idea here is to ensure VALUES,
    not complete spec. If you want to create an entire spec, you
    probably want to specify more values that aren't REQUIRED to match,
    such as Description.
    """
    if spec_type == 'client':
        spec = fetch_client(p4, spec_id)
    else:
        spec = p4gf_util.first_dict(p4.run(spec_type, '-o', spec_id))
    mismatches = {key: values[key] for key in values if spec.get(key) != values[key]}
    LOG.debug2("ensure_spec_values(): want={want} got={spec} mismatch={mismatch}".format(
        spec=spec, want=values, mismatch=mismatches))

    if mismatches:
        set_spec(p4, spec_type, spec_id=spec_id, values=mismatches)
        LOG.debug("successfully updated %s %s", spec_type, spec_id)
    return mismatches
def print_reviews_status(p4, server_id, pfunc=print):
    """Report on the status of the reviews locks.

    :param p4: P4API to query Perforce.
    :param server_id: identifier for this Git Fusion instance.
    :param pfunc: print function -  either 'print' or some logger : 'LOG.debug'

    """
    reviews_users = [
        p4gf_const.P4GF_REVIEWS_GF + server_id, p4gf_const.P4GF_REVIEWS__NON_GF
    ]

    trigger_lock_msg = \
        "Git Fusion Triggers have locks on these repo Views for the indicated GF-<changelist>:"
    for user in reviews_users:
        args_ = ['-o', user]
        r = p4.run('user', args_)
        vardict = p4gf_util.first_dict(r)
        reviews_locks_exist = False
        if "Reviews" in vardict:
            reviews_locks_exist = True
            current_reviews = vardict["Reviews"]
            if current_reviews:
                if user == p4gf_const.P4GF_REVIEWS__NON_GF:
                    pfunc(trigger_lock_msg)
                    current_reviews[0] = '  ' + current_reviews[0]
                    pfunc("{0}".format('\n  '.join(current_reviews)))
                else:
                    current_reviews[0] = '  ' + current_reviews[0]
                    pfunc("Git Fusion has locks on these repo Views:")
                    pfunc("{0}".format('\n  '.join(current_reviews)))

    if reviews_locks_exist:
        pfunc("Reviews locks are expected to exist during normal activity.")
        pfunc(
            "Specific locks will not persist after a completed Git Fusion push or p4 submit."
        )
        pfunc(
            "Check again to see that these Review locks do not continue to exist."
        )
def _ensure_case_sensitive():
    """
    Ensure that the Perforce server is case sensitive, but only if we have
    not been instructed to ignore the issue completely, in which case it is
    assumed the administrator knows what they are doing.
    """
    if not IGNORE_CASE_HANDLING:
        info = p4gf_util.first_dict(p4.run('info'))
        if not info.get('caseHandling') == 'sensitive':
            # Yes, the formatting is weird, but otherwise dedent and fill
            # will not yield the desired results (see job job070463).
            msg = _("""\
            The Perforce service's case-handling policy is not set to 'sensitive',
            which means any files introduced via Git whose names differ only by case may
            result in data loss or errors during push. It is strongly advised to set the
            case-handling policy to 'sensitive'. To bypass this check, pass --ignore-case
            when invoking this script.
            """)
            dims = shutil.get_terminal_size()
            msg = textwrap.fill(textwrap.dedent(msg), dims[0])
            Verbosity.report(Verbosity.ERROR, msg)
            sys.exit(1)
def _ensure_case_sensitive():
    """
    Ensure that the Perforce server is case sensitive, but only if we have
    not been instructed to ignore the issue completely, in which case it is
    assumed the administrator knows what they are doing.
    """
    if not IGNORE_CASE_HANDLING:
        info = p4gf_util.first_dict(p4.run('info'))
        if not info.get('caseHandling') == 'sensitive':
            # Yes, the formatting is weird, but otherwise dedent and fill
            # will not yield the desired results (see job job070463).
            msg = _("""\
            The Perforce service's case-handling policy is not set to 'sensitive',
            which means any files introduced via Git whose names differ only by case may
            result in data loss or errors during push. It is strongly advised to set the
            case-handling policy to 'sensitive'. To bypass this check, pass --ignore-case
            when invoking this script.
            """)
            dims = shutil.get_terminal_size()
            msg = textwrap.fill(textwrap.dedent(msg), dims[0])
            Verbosity.report(Verbosity.ERROR, msg)
            sys.exit(1)
def update_repo_reviews(p4_reviews, user, clientmap, action=None, change=None):
    """Add or remove view left maps to the review user Reviews.
    Using Map.join, check for a conflict with self - this gf_reviews user.
    This check handles the case of overlapping views pushed to the same GF server.
    If conflict, return INTERSECT and do not update the user reviews
    """

    if clientmap:
        repo_views = clientmap.lhs()
    LOG.debug3("clientmap  = {}".format(clientmap))

    args_ = ['-o', user]
    r = p4_reviews.run('user', args_)
    vardict = p4gf_util.first_dict(r)
    current_reviews = []
    if "Reviews" in vardict:
        current_reviews = vardict["Reviews"]
        if action == ADD:
            if has_intersecting_views(current_reviews, clientmap):
                return INTERSECT

    if action == ADD:
        reviews = current_reviews + repo_views
    elif action == REMOVE:
        if user == p4gf_const.P4GF_REVIEWS__NON_GF:
            reviews = remove_non_gf_changelist_files(change, current_reviews)
        else:  # for Git Fusion reviews
            reviews = list(current_reviews)  # make a copy
            for path in repo_views:
                try:
                    reviews.remove(path)
                except ValueError:
                    pass
    else:
        raise RuntimeError(_("Git Fusion: update_repo_reviews incorrect action '{}'")
                           .format(action))
    LOG.debug3("for user {} setting reviews {}".format(user, reviews))
    p4gf_util.set_spec(p4_reviews, 'user', user, values={"Reviews": reviews})
    return NO_INTERSECT
Example #25
0
def _read_tags(ctx, depot_path, rev=None):
    """Return the set of (lightweight) tag names read from the given file.

    :type ctx: :class:`p4gf_context.Context`
    :param ctx: Git Fusion context

    :type depot_path: str
    :param depot_path: file path within depot

    :type rev: int
    :param rev: if not None, specifies file revision to retrieve

    """
    if rev:
        cmd = ['sync', '-f', "{}#{}".format(depot_path, rev)]
    else:
        cmd = ['sync', '-f', depot_path]
    r = ctx.p4gfrun(cmd)
    r = p4gf_util.first_dict(r)
    with open(r['clientFile'], 'rb') as f:
        contents = f.read()
    tag_names = contents.decode('UTF-8').splitlines()
    return set(tag_names)
Example #26
0
def set_spec(p4, spec_type, spec_id=None, values=None, args=None, cached_vardict=None):
    """Create a new spec with the given ID and values.

    :type p4: :class:`P4API`
    :param p4: P4 instance for setting spec

    :param str spec_type: type of specification (e.g. 'client')

    :param str spec_id: name of fetch+set

    :type values: dict
    :param values: spec values to set

    :type args: str or list
    :param args: additional flags to pass for set

    :param dict cached_vardict:
            A dict returned by a prior call to set_spec(). Saves us a call to
            '<spec> -o' to fetch the contents of the spec before modifying it.
            CHANGED IN PLACE. If you don't want the dict modified,
            pass us a copy.

    :return: the vardict used as input to <spec> -i
    :rtype: dict

    :raises KeyError: if spec_type not known to SpecInfo.

    """
    # pylint: disable=too-many-arguments
    si = SpecInfo[spec_type]
    _args = ['-o']
    if spec_id:
        _args.append(spec_id)

    if cached_vardict:
        vardict = cached_vardict
    else:
        if spec_type == 'client':
            vardict = fetch_client(p4, spec_id)
        else:
            r = p4.run(si['cmd_one'], _args)
            vardict = p4gf_util.first_dict(r)

    if values:
        for key in values:
            if values[key] is None:
                if key in vardict:
                    del vardict[key]
            else:
                vardict[key] = values[key]

    _args = ['-i']
    if args:
        _args += _to_list(args)
    p4.input = vardict
    try:
        p4.run(si['cmd_one'],  _args)
        return vardict
    except:
        LOG.debug("failed cmd: set_spec {type} {id} {dict}"
                  .format(type=spec_type, id=spec_id, dict=vardict))
        raise
 def _fetch_spec(self, spec_type, spec_id):
     """Read one spec and return it."""
     return p4gf_util.first_dict(self._p4.run(spec_type, "-o", spec_id))