Beispiel #1
0
def _create_client(p4, client_name, p4gf_dir):
    """Create the host-specific Perforce client to enable working with
    the object cache in the P4GF_DEPOT depot.
    """
    # to prevent the mirrored git commit/tree objects from being retained in the
    # git-fusion workspace, set client option 'rmdir' and sync #none in p4gf_gitmirror
    # Assume the usual P4 client default options are being used so that
    # these options below differ ONLY with normdir -> rmdir
    # if this assumption proves troublesome, then read/write cycle will be needed.
    options = NTR('allwrite clobber nocompress unlocked nomodtime rmdir')

    view = ['//{depot}/... //{client}/...'.format(depot=p4gf_const.P4GF_DEPOT,
                                                  client=client_name)]
    spec_created = False
    if not p4gf_util.spec_exists(p4, 'client', client_name):
        # See if the old object clients exist, in which case we will remove them.
        for old_client_name in [OLD_OBJECT_CLIENT, OLDER_OBJECT_CLIENT]:
            if p4gf_util.spec_exists(p4, 'client', old_client_name):
                p4.run('client', '-df', old_client_name)
                _info(_("Old client '{}' deleted.").format(old_client_name))
        spec_created = p4gf_util.ensure_spec(
                            p4, 'client', spec_id=client_name,
                            values={'Host': None, 'Root': p4gf_dir,
                                    'Description': _('Created by Perforce Git Fusion'),
                                    'Options': options,
                                    'View': view})
    if spec_created:
        _info(_("Client '{}' created.").format(client_name))
    if not spec_created:
        modified = p4gf_util.ensure_spec_values(p4, 'client', client_name,
                {'Root': p4gf_dir, 'View': view, 'Options': options})
        if modified:
            _info(_("Client '{}' updated.").format(client_name))
        else:
            _info(_("Client '{}' already exists.").format(client_name))
def create_p4_client(p4, view_name, client_name, client_root):
    """Create the p4 client to contain Git meta-data mirror.

    Keyword arguments:
    p4          -- Perforce client API
    view_name   -- client view of repository to clone
    client_name -- client that will be created
    client_root -- path for client workspace

    Returns one of the INIT_REPO_* constants.
    """
    # Ensure the client root directory has been created.
    if not os.path.exists(client_root):
        os.makedirs(client_root)

    # If a client for this view already exists, we're probably done.
    #
    # Make sure the client root is correct.
    if p4gf_util.spec_exists(p4, 'client', client_name):
        LOG.debug("%s client already exists for %s", client_name, view_name)
        p4gf_util.ensure_spec_values(p4, 'client', client_name, {'Root':client_root})
        return INIT_REPO_EXISTS

    # Client does not yet exist. We'll have to configure it manually, using
    # the view's name as a template.
    if not p4gf_util.spec_exists(p4, 'client', view_name):
        LOG.warn("requested client %s does not exist, required for creating a mirror", view_name)
        sys.stderr.write("View {} does not exist\n".format(view_name))
        return INIT_REPO_NOVIEW

    # Seed a new client using the view's view as a template.
    LOG.info("client %s does not exist, creating from view %s", client_name, view_name)

    view = p4gf_util.first_value_for_key(
            p4.run('client', '-o', '-t', view_name, client_name),
            'View')

    if not view_depots_ok(p4, view_name, view):
        # nature of problem already reported
        return INIT_REPO_BADVIEW

    desc = ("Created by Perforce Git Fusion for work in {view}."
            .format(view=view_name))
    p4gf_util.set_spec(p4, 'client', spec_id=client_name,
                     values={'Owner'         : p4gf_const.P4GF_USER,
                             'LineEnd'       : 'unix',
                             'View'          : view,
                             'Root'          : client_root,
                             'Host'          : None,
                             'Description'   : desc})
    LOG.debug("successfully created client %s", client_name)
    return INIT_REPO_OK
def repo_from_template_client( p4, view_name, view_name_p4client, client_name
                             , client_root, enable_mismatched_rhs):
    '''
    Create a new Perforce client spec <client_name> using existing Perforce
    client spec <view_name> as a template (just use its View).
    '''
    # view_name_p4client is the p4client
    # view_name        is the gfinternal repo name
    # view_name differs from view_name_p4client if latter contains special chars
    #           or was configured with --p4client argument


    if not p4gf_util.spec_exists(p4, 'client', view_name_p4client):
        return INIT_REPO_NOVIEW

    client = p4.run('client', '-o', view_name_p4client)[0]
    if 'Stream' in client:
        return _repo_from_stream(p4, view_name, client.get('Stream'),
                                 client_name, client_root, enable_mismatched_rhs)

    with Validator.from_template_client(view_name, p4, view_name_p4client) as validator:
        if not validator.is_valid(enable_mismatched_rhs):
            return INIT_REPO_CONFIG_FILE_BAD

    # Seed a new client using the view's view as a template.
    LOG.info("Git Fusion client %s does not exist,"
             " creating from existing Perforce client %s"
            , client_name, view_name_p4client)

    view = p4gf_util.first_value_for_key(
            p4.run('client', '-o', '-t', view_name_p4client, client_name),
            'View')

    create_repo_client(p4, view_name, client_name, client_root, view, None)
    return INIT_REPO_OK
Beispiel #4
0
def convert_client(args, p4, client_name):
    """Convert the named Perforce client and its workspace. Raises
    P4Exception if the client is not present, or the client configuration is
    not set up as expected.

    Keyword arguments:
    args        -- parsed command line arguments
    p4          -- Git user's Perforce client
    client_name -- name of client to be deleted

    """
    group_list = [
        p4gf_const.P4GF_GROUP_VIEW_PULL, p4gf_const.P4GF_GROUP_VIEW_PUSH
    ]
    p4.user = p4gf_const.P4GF_USER
    old_client = p4.client
    p4.client = client_name

    print("  Processing client {}...".format(client_name))
    if not p4gf_util.spec_exists(p4, 'client', client_name):
        raise P4.P4Exception('No such client "{}" defined'.format(client_name))

    view_name = client_name[len(p4gf_const.P4GF_CLIENT_PREFIX):]
    client = p4.fetch_client()
    command_path = client["Root"]

    if not args.convert:
        print("    Removing client files for {}...".format(client_name))
        print("      p4 sync -fqk {}/...#none".format(command_path))
        print("    Create config for client {}...".format(client_name))
        p4.client = old_client
        for group_template in group_list:
            group = group_template.format(view=view_name)
            print("    Leaving existing group {}".format(group))
        print("    Remove client lock counter")
        print("      p4 counter -u -d {}".format(
            p4gf_lock.view_lock_name(view_name)))

    else:
        LOG_FILE.write("Processing client {}\n".format(client_name))
        print("    Removing client files for {}...".format(client_name))
        print("      p4 sync -fqk {}/...#none".format(command_path))
        LOG_FILE.write("p4 sync -fqk {}/...#none\n".format(command_path))
        p4.run('sync', '-fqk', command_path + '/...#none')
        print("    Creating config for client {}...".format(client_name))
        LOG_FILE.write(
            "Creating config for client {}...\n".format(client_name))
        p4.client = old_client
        create_from_12x_gf_client_name(p4, client_name)
        for group_template in group_list:
            group = group_template.format(view=view_name)
            print("    Leaving existing group {}".format(group))
        print("    Remove client lock counter")
        print("      p4 counter -u -d {}".format(
            p4gf_lock.view_lock_name(view_name)))
        LOG_FILE.write("p4 counter -u -d {}\n".format(
            p4gf_lock.view_lock_name(view_name)))
        _delete_counter(p4, p4gf_lock.view_lock_name(view_name))
Beispiel #5
0
def _create_client(p4, client_name, p4gf_dir):
    """Create the host-specific Perforce client to enable working with
    the object cache in the P4GF_DEPOT depot.
    """
    # to prevent the mirrored git commit/tree objects from being retained in the
    # git-fusion workspace, set client option 'rmdir' and sync #none in p4gf_gitmirror
    # Assume the usual P4 client default options are being used so that
    # these options below differ ONLY with normdir -> rmdir
    # if this assumption proves troublesome, then read/write cycle will be needed.
    options = NTR('allwrite clobber nocompress unlocked nomodtime rmdir')

    view = [
        '//{depot}/... //{client}/...'.format(depot=p4gf_const.P4GF_DEPOT,
                                              client=client_name)
    ]
    spec_created = False
    if not p4gf_util.spec_exists(p4, 'client', client_name):
        # See if the old object clients exist, in which case we will remove them.
        for old_client_name in [OLD_OBJECT_CLIENT, OLDER_OBJECT_CLIENT]:
            if p4gf_util.spec_exists(p4, 'client', old_client_name):
                p4.run('client', '-df', old_client_name)
                _info(_("Old client '{}' deleted.").format(old_client_name))
        spec_created = p4gf_util.ensure_spec(
            p4,
            'client',
            spec_id=client_name,
            values={
                'Host': None,
                'Root': p4gf_dir,
                'Description': _('Created by Perforce Git Fusion'),
                'Options': options,
                'View': view
            })
    if spec_created:
        _info(_("Client '{}' created.").format(client_name))
    if not spec_created:
        modified = p4gf_util.ensure_spec_values(p4, 'client', client_name, {
            'Root': p4gf_dir,
            'View': view,
            'Options': options
        })
        if modified:
            _info(_("Client '{}' updated.").format(client_name))
        else:
            _info(_("Client '{}' already exists.").format(client_name))
def _repo_from_stream(p4, view_name, stream_name, client_name,
                      client_root, enable_mismatched_rhs, handle_imports=True):
    """Create a new client from the named stream.

    Create a new Perforce client spec <client_name> using existing Perforce
    stream spec <stream_name> as a template (just use its View).

    Returns one of the INIT_REPO_* constants.

    """
    # stream_name      is the name of a stream, e.g. '//depot/stream'
    # view_name        is the gfinternal repo name

    if not p4gf_util.spec_exists(p4, 'stream', stream_name):
        return INIT_REPO_NOVIEW

    with Validator.from_stream(view_name, p4, stream_name) as validator:
        if not validator.is_valid(enable_mismatched_rhs):
            return INIT_REPO_CONFIG_FILE_BAD

    # Seed a new client using the stream's view as a template.
    LOG.info("Git Fusion client %s does not exist, creating from existing Perforce stream %s",
             client_name, stream_name)

    # Create virtual stream with excluded paths, use that for client.
    stream = p4.fetch_stream(stream_name)
    if handle_imports:
        config = p4gf_config.get_repo(p4, view_name)
        imports_enabled = p4gf_config.is_feature_enabled(config, p4gf_config.FEATURE_IMPORTS)
    else:
        imports_enabled = False
    if imports_enabled:
        stream_paths = p4gf_streams.stream_import_exclude(stream['Paths'])
    else:
        stream_paths = stream['Paths']
    desc = (_("Created by Perforce Git Fusion for work in '{view}'.")
            .format(view=p4gf_translate.TranslateReponame.repo_to_git(view_name)))
    spec_values = {
        'Owner': p4gf_const.P4GF_USER,
        'Parent': stream_name,
        'Type': 'virtual',
        'Description': desc,
        'Options': 'notoparent nofromparent',
        'Paths': stream_paths,
        'Remapped': ['.gitmodules-{} .gitmodules'.format(view_name)]
    }
    if imports_enabled:
        stream_name += '_p4gfv'
        p4gf_util.set_spec(p4, 'stream', spec_id=stream_name, values=spec_values)
        LOG.debug('virtual stream {} created for {}'.format(stream_name, client_name))
    create_repo_client(p4, view_name, client_name, client_root, None, stream_name)

    return INIT_REPO_OK
def _create_client(p4, client_name, p4gf_dir):
    """Create the host-specific Perforce client to enable working with
    the object cache in the .git-fusion depot.
    """
    view = ['//{depot}/... //{client}/...'.format(depot=p4gf_const.P4GF_DEPOT,
                                                  client=client_name)]
    spec_created = False
    if not p4gf_util.spec_exists(p4, "client", client_name):
        # See if the old object clients exist, in which case we will remove them.
        if p4gf_util.spec_exists(p4, "client", OLD_OBJECT_CLIENT):
            p4.run('client', '-df', OLD_OBJECT_CLIENT)
        if p4gf_util.spec_exists(p4, "client", OLDER_OBJECT_CLIENT):
            p4.run('client', '-df', OLDER_OBJECT_CLIENT)
        spec_created = p4gf_util.ensure_spec(
                            p4, "client", spec_id=client_name,
                            values={'Host': None, 'Root': p4gf_dir,
                                    'Description': 'Created by Perforce Git Fusion',
                                    'View': view})
    if not spec_created:
        p4gf_util.ensure_spec_values(p4, "client", client_name,
                                   {'Root': p4gf_dir, 'View': view})
def convert_client(args, p4, client_name):
    """Convert the named Perforce client and its workspace. Raises
    P4Exception if the client is not present, or the client configuration is
    not set up as expected.

    Keyword arguments:
    args        -- parsed command line arguments
    p4          -- Git user's Perforce client
    client_name -- name of client to be deleted

    """
    group_list = [p4gf_const.P4GF_GROUP_VIEW_PULL, p4gf_const.P4GF_GROUP_VIEW_PUSH]
    p4.user = p4gf_const.P4GF_USER
    old_client = p4.client
    p4.client = client_name

    print("  Processing client {}...".format(client_name))
    if not p4gf_util.spec_exists(p4, 'client', client_name):
        raise P4.P4Exception('No such client "{}" defined'
                             .format(client_name))

    view_name = client_name[len(p4gf_const.P4GF_CLIENT_PREFIX):]
    client = p4.fetch_client()
    command_path = client["Root"]

    if not args.convert:
        print("    Removing client files for {}...".format(client_name))
        print("      p4 sync -fqk {}/...#none".format(command_path))
        print("    Create config for client {}...".format(client_name))
        p4.client = old_client
        for group_template in group_list:
            group = group_template.format(view=view_name)
            print("    Leaving existing group {}".format(group))
        print("    Remove client lock counter")
        print("      p4 counter -u -d {}".format(p4gf_lock.view_lock_name(view_name)))

    else:
        LOG_FILE.write("Processing client {}\n".format(client_name))
        print("    Removing client files for {}...".format(client_name))
        print("      p4 sync -fqk {}/...#none".format(command_path))
        LOG_FILE.write("p4 sync -fqk {}/...#none\n".format(command_path))
        p4.run('sync', '-fqk', command_path + '/...#none')
        print("    Creating config for client {}...".format(client_name))
        LOG_FILE.write("Creating config for client {}...\n".format(client_name))
        p4.client = old_client
        create_from_12x_gf_client_name(p4, client_name)
        for group_template in group_list:
            group = group_template.format(view=view_name)
            print("    Leaving existing group {}".format(group))
        print("    Remove client lock counter")
        print("      p4 counter -u -d {}".format(p4gf_lock.view_lock_name(view_name)))
        LOG_FILE.write("p4 counter -u -d {}\n".format(p4gf_lock.view_lock_name(view_name)))
        _delete_counter(p4, p4gf_lock.view_lock_name(view_name))
    def get_branch_dict(self):
        """Get a branch dictionary for this repo.

        If the p4gf_config exists, use that.
        Else if the p4 client exists
        create a branch dict containing a branch from the client views.
        Else return None
        """
        LOG.debug("get_branch_dict for {0}".format(self.view_name))
        # Repo config file already checked into Perforce?
        # Use that.
        config_path = p4gf_config.depot_path_repo(self.view_name)
        config_exists = p4gf_util.depot_file_exists(self.p4, config_path)
        if config_exists:
            self.config = p4gf_config.get_repo(self.p4, self.view_name)
            if self.config:
                return p4gf_branch.dict_from_config(self.config, self.p4)
            else:
                return None
        else:
            LOG.debug("checking if client {0} exists.".format(self.view_name))
            if not p4gf_util.spec_exists(self.p4, 'client', self.view_name):
                LOG.debug("         client {0} NOT exists.".format(
                    self.view_name))
                return None
            view_lines = p4gf_util.first_value_for_key(
                self.p4.run('client', '-o', '-t', self.view_name,
                            self.p4client), 'View')
            if not view_lines:
                return None
            else:
                # create a Branch object to manage this client view
                if isinstance(view_lines, str):
                    view_lines = view_lines.splitlines()
                LOG.debug(
                    "create branch from client views: {0}".format(view_lines))
                branch = p4gf_branch.Branch()
                branch.branch_id = 'master'
                branch.git_branch_name = 'master'
                branch.view_p4map = P4.Map(view_lines)
                branch.view_lines = view_lines
                LOG.debug(
                    "create branch from client branch view_p4map: {0}".format(
                        branch.view_p4map))
                LOG.debug(
                    "create branch from client branch view_lines: {0}".format(
                        branch.view_lines))
                branch_dict = {}
                branch_dict[branch.branch_id] = branch
                return branch_dict
    def get_branch_dict(self):
        """Get a branch dictionary for this repo.

        If the p4gf_config exists, use that.
        Else if the p4 client exists
        create a branch dict containing a branch from the client views.
        Else return None
        """
        LOG.debug("get_branch_dict for {0}".format(self.view_name))
        # Repo config file already checked into Perforce?
        # Use that.
        config_path   = p4gf_config.depot_path_repo(self.view_name)
        config_exists = p4gf_util.depot_file_exists(self.p4, config_path)
        if config_exists:
            self.config = p4gf_config.get_repo(self.p4, self.view_name)
            if self.config:
                return p4gf_branch.dict_from_config(self.config, self.p4)
            else:
                return None
        else:
            LOG.debug("checking if client {0} exists.".format(self.view_name))
            if not p4gf_util.spec_exists(self.p4, 'client', self.view_name):
                LOG.debug("         client {0} NOT exists.".format(self.view_name))
                return None
            view_lines = p4gf_util.first_value_for_key(
                    self.p4.run('client', '-o', '-t', self.view_name, self.p4client),
                    'View')
            if not view_lines:
                return None
            else:
                # create a Branch object to manage this client view
                if isinstance(view_lines, str):
                    view_lines = view_lines.splitlines()
                LOG.debug("create branch from client views: {0}".format(view_lines))
                branch = p4gf_branch.Branch()
                branch.branch_id = 'master'
                branch.git_branch_name = 'master'
                branch.view_p4map = P4.Map(view_lines)
                branch.view_lines = view_lines
                LOG.debug("create branch from client branch view_p4map: {0}".
                        format(branch.view_p4map))
                LOG.debug("create branch from client branch view_lines: {0}".
                        format(branch.view_lines))
                branch_dict = {}
                branch_dict[branch.branch_id] = branch
                return branch_dict
def cleanup_client(ctx, view_name):
    """Clean up the failed client and workspace after an error occurs while
    creating the initial clone. If the client does not exist, nothing is done.
    """
    client_name = p4gf_util.view_to_client_name(view_name)
    if not p4gf_util.spec_exists(ctx.p4, 'client', client_name):
        return

    LOG.debug('cleaning up failed view {}'.format(view_name))
    command_path = ctx.client_view_path()

    ctx.p4.run('sync', '-fq', command_path + '#none')
    ctx.p4.run('client', '-df', client_name)
    for vdir in [ctx.view_dirs.view_container]:
        LOG.debug('removing view directory {}'.format(vdir))
        if os.path.isdir(vdir):
            shutil.rmtree(vdir)
        elif os.path.isfile(vdir):
            os.remove(vdir)
Beispiel #12
0
def cleanup_client(ctx, view_name):
    """Clean up the failed client and workspace after an error occurs while
    creating the initial clone. If the client does not exist, nothing is done.
    """
    client_name = p4gf_util.view_to_client_name(view_name)
    if not p4gf_util.spec_exists(ctx.p4, 'client', client_name):
        return

    LOG.debug('cleaning up failed view {}'.format(view_name))
    command_path = ctx.client_view_path()

    ctx.p4.run('sync', '-fq', command_path + '#none')
    ctx.p4.run('client', '-df', client_name)
    for vdir in [ctx.view_dirs.view_container]:
        LOG.debug('removing view directory {}'.format(vdir))
        if os.path.isdir(vdir):
            shutil.rmtree(vdir)
        elif os.path.isfile(vdir):
            os.remove(vdir)
def repo_from_template_client(p4, view_name, view_name_p4client, client_name,
                              client_root, enable_mismatched_rhs):
    '''
    Create a new Perforce client spec <client_name> using existing Perforce
    client spec <view_name> as a template (just use its View).
    '''
    # view_name_p4client is the p4client
    # view_name        is the gfinternal repo name
    # view_name differs from view_name_p4client if latter contains special chars
    #           or was configured with --p4client argument

    if not p4gf_util.spec_exists(p4, 'client', view_name_p4client):
        return INIT_REPO_NOVIEW

    client = p4.run('client', '-o', view_name_p4client)[0]
    if 'Stream' in client:
        return _repo_from_stream(p4, view_name, client.get('Stream'),
                                 client_name, client_root,
                                 enable_mismatched_rhs)

    with Validator.from_template_client(view_name, p4,
                                        view_name_p4client) as validator:
        if not validator.is_valid(enable_mismatched_rhs):
            return INIT_REPO_CONFIG_FILE_BAD

    # Seed a new client using the view's view as a template.
    LOG.info(
        "Git Fusion client %s does not exist,"
        " creating from existing Perforce client %s", client_name,
        view_name_p4client)

    view = p4gf_util.first_value_for_key(
        p4.run('client', '-o', '-t', view_name_p4client, client_name), 'View')

    create_repo_client(p4, view_name, client_name, client_root, view, None)
    return INIT_REPO_OK
def delete_client(args, p4, client_name, metrics, prune_objs=True):
    """Delete the named Perforce client and its workspace. Raises
    P4Exception if the client is not present, or the client configuration is
    not set up as expected.

    Keyword arguments:
    args        -- parsed command line arguments
    p4          -- Git user's Perforce client
    client_name -- name of client to be deleted
    metrics     -- DeletionMetrics for collecting resulting metrics
    prune_objs  -- if True, delete associated objects from cache

    """
    # pylint: disable=R0912,R0915
    group_list = [p4gf_const.P4GF_GROUP_VIEW_PULL, p4gf_const.P4GF_GROUP_VIEW_PUSH]
    p4.user = p4gf_const.P4GF_USER

    print_verbose(args, _("Checking for client '{}'...").format(client_name))
    if not p4gf_util.spec_exists(p4, 'client', client_name):
        raise P4.P4Exception(_("No such client '{}' defined")
                             .format(client_name))
    view_name = p4gf_util.client_to_view_name(client_name)
    p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4)
    view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)
    p4gf_util.ensure_spec_values(p4, 'client', client_name, {'Root': view_dirs.p4root})

    view_lock = None  # We're clobbering and deleting. Overrule locks.
    with p4gf_context.create_context(view_name, view_lock) as ctx:
        command_path = ctx.client_view_path()

        homedir = os.path.expanduser('~')
        raise_if_homedir(homedir, view_name, view_dirs.view_container)

        # Scan for objects associated only with this view so we can remove them.
        objects_to_delete = []
        if prune_objs:
            objects_to_delete = _find_client_commit_objects(args, p4, view_name)

        # Do we have a repo config file to delete?
        config_file = p4gf_config.depot_path_repo(view_name) + '*'
        config_file_exists = p4gf_util.depot_file_exists(p4, config_file)

        # What counters shall we delete?
        counter_list = []
        counter_list.append(p4gf_context.calc_last_copied_change_counter_name(
                            view_name, p4gf_util.get_server_id()))
        for spec in p4.run('counters', '-u', '-e', "git-fusion-index-last-{},*"
                                                   .format(view_name)):
            counter_list.append(spec['counter'])
        for spec in p4.run('counters', '-u', '-e', "git-fusion-index-branch-{},*"
                                                   .format(view_name)):
            counter_list.append(spec['counter'])

        if not args.delete:
            print(NTR('p4 sync -f {}#none').format(command_path))
            print(NTR('p4 client -f -d {}').format(client_name))
            print(NTR('rm -rf {}').format(view_dirs.view_container))
            print(NTR('Deleting {} objects from //{}/objects/...').format(
                len(objects_to_delete), p4gf_const.P4GF_DEPOT))
            for group_template in group_list:
                group = group_template.format(view=view_name)
                print(NTR('p4 group -a -d {}').format(group))
            for c in counter_list:
                print(NTR('p4 counter -u -d {}').format(c))

            if config_file_exists:
                print(NTR('p4 sync -f {}').format(config_file))
                print(NTR('p4 delete  {}').format(config_file))
                print(NTR('p4 submit -d "Delete repo config for {view_name}" {config_file}')
                      .format(view_name=view_name, config_file=config_file))
        else:
            print_verbose(args, NTR('Removing client files for {}...').format(client_name))
            ctx.p4.run('sync', '-fq', command_path + '#none')
            print_verbose(args, NTR('Deleting client {}...').format(client_name))
            p4.run('client', '-df', client_name)
            metrics.clients += 1
            print_verbose(args, NTR("Deleting repo {0}'s directory {1}...").format(view_name,
                view_dirs.view_container))
            _remove_tree(view_dirs.view_container, contents_only=False)
            metrics.files += _delete_files(p4, objects_to_delete, view_name)
            for group_template in group_list:
                _delete_group(args, p4, group_template.format(view=view_name), metrics)
            for c in counter_list:
                _delete_counter(p4, c, metrics)

            if config_file_exists:
                p4gf_util.p4run_logged(p4, ['sync', '-fq', config_file])
                with p4gf_util.NumberedChangelist(
                        p4=p4, description=_("Delete repo config for '{}'")
                                           .format(view_name)) as nc:
                    nc.p4run(["delete", config_file])
                    nc.submit()
def _repo_from_stream(p4,
                      view_name,
                      stream_name,
                      client_name,
                      client_root,
                      enable_mismatched_rhs,
                      handle_imports=True):
    """Create a new client from the named stream.

    Create a new Perforce client spec <client_name> using existing Perforce
    stream spec <stream_name> as a template (just use its View).

    Returns one of the INIT_REPO_* constants.

    """
    # stream_name      is the name of a stream, e.g. '//depot/stream'
    # view_name        is the gfinternal repo name

    if not p4gf_util.spec_exists(p4, 'stream', stream_name):
        return INIT_REPO_NOVIEW

    with Validator.from_stream(view_name, p4, stream_name) as validator:
        if not validator.is_valid(enable_mismatched_rhs):
            return INIT_REPO_CONFIG_FILE_BAD

    # Seed a new client using the stream's view as a template.
    LOG.info(
        "Git Fusion client %s does not exist, creating from existing Perforce stream %s",
        client_name, stream_name)

    # Create virtual stream with excluded paths, use that for client.
    stream = p4.fetch_stream(stream_name)
    if handle_imports:
        config = p4gf_config.get_repo(p4, view_name)
        imports_enabled = p4gf_config.is_feature_enabled(
            config, p4gf_config.FEATURE_IMPORTS)
    else:
        imports_enabled = False
    if imports_enabled:
        stream_paths = p4gf_streams.stream_import_exclude(stream['Paths'])
    else:
        stream_paths = stream['Paths']
    desc = (_("Created by Perforce Git Fusion for work in '{view}'.").format(
        view=p4gf_translate.TranslateReponame.repo_to_git(view_name)))
    spec_values = {
        'Owner': p4gf_const.P4GF_USER,
        'Parent': stream_name,
        'Type': 'virtual',
        'Description': desc,
        'Options': 'notoparent nofromparent',
        'Paths': stream_paths,
        'Remapped': ['.gitmodules-{} .gitmodules'.format(view_name)]
    }
    if imports_enabled:
        stream_name += '_p4gfv'
        p4gf_util.set_spec(p4,
                           'stream',
                           spec_id=stream_name,
                           values=spec_values)
        LOG.debug('virtual stream {} created for {}'.format(
            stream_name, client_name))
    create_repo_client(p4, view_name, client_name, client_root, None,
                       stream_name)

    return INIT_REPO_OK
def delete_client(args, p4, client_name):
    """Delete the named Perforce client and its workspace. Raises
    P4Exception if the client is not present, or the client configuration is
    not set up as expected.

    Keyword arguments:
    args        -- parsed command line arguments
    p4          -- Git user's Perforce client
    client_name -- name of client to be deleted

    """
    group_list = [p4gf_const.P4GF_GROUP_VIEW_PULL, p4gf_const.P4GF_GROUP_VIEW_PUSH]
    p4.user = p4gf_const.P4GF_USER

    print_verbose(args, "Checking for client {}...".format(client_name))
    if not p4gf_util.spec_exists(p4, 'client', client_name):
        raise P4.P4Exception('No such client "{}" defined'
                             .format(client_name))

    view_name = client_name[len(p4gf_const.P4GF_CLIENT_PREFIX):]
    view_lock = None  # We're clobbering and deleting. Overrule locks.
    try:
        ctx = p4gf_context.create_context(view_name, view_lock)
    except RuntimeError:
        # not a conforming Git Fusion client, ignore it
        return
    command_path = ctx.client_view_path()

    p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4)
    view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)
    rm_list = [view_dirs.view_container]
    homedir = os.path.expanduser('~')
    raise_if_homedir(homedir, view_name, rm_list)

    # Scan for objects associated only with this view so we can either remove
    # them completely or update their 'views' attribute appropriately.
    p4.handler = FilterViewFstatHandler(view_name)
    p4.run("fstat", "-Oa", "-T", "depotFile, attr-views", "//.git-fusion/objects/...")
    objects_to_delete = p4.handler.files_to_delete
    objects_to_modify = p4.handler.files_to_modify
    p4.handler = None

    if not args.delete:
        print("p4 sync -f {}#none".format(command_path))
        print("p4 client -f -d {}".format(client_name))
        for d in rm_list:
            print("rm -rf {}".format(d))
        for to_delete in objects_to_delete:
            print("p4 obliterate -y {}".format(to_delete))
        if objects_to_modify:
            for (fname, views) in objects_to_modify:
                print("attribute -p -n views -v {} {}".format(views, fname))
        for group_template in group_list:
            group = group_template.format(view=view_name)
            print("p4 group -a -d {}".format(group))
        print('p4 counter -u -d {}'.format(p4gf_lock.view_lock_name(view_name)))

    else:
        print_verbose(args, "Removing client files for {}...".format(client_name))
        ctx.p4.run('sync', '-fq', command_path + '#none')
        print_verbose(args, "Deleting client {}...".format(client_name))
        p4.run('client', '-df', client_name)
        for d in rm_list:
            remove_file_or_dir(args, view_name, d)
        bite_size = 1000
        while len(objects_to_delete):
            to_delete = objects_to_delete[:bite_size]
            objects_to_delete = objects_to_delete[bite_size:]
            p4.run("obliterate", "-y", to_delete)
        if objects_to_modify:
            for (fname, views) in objects_to_modify:
                p4.run("edit", fname)
                p4.run("attribute", "-p", "-n", "views", "-v", views, fname)
            p4.run("submit", "-d", "'Removing {} from views attribute'".format(view_name))
        for group_template in group_list:
            delete_group(args, p4, group_template.format(view=view_name))
        _delete_counter(p4, p4gf_lock.view_lock_name(view_name))
def _create_p4_client(p4, view_name, client_name, client_root,
        enable_mismatched_rhs, view_name_p4client, handle_imports=True):
    """Create the p4 client to contain Git meta-data mirror.

    Keyword arguments:
    p4                    -- Perforce client API
    view_name             -- client view of repository to clone - internal (translated) viewname
    client_name           -- client that will be created
    client_root           -- path for client workspace
    enable_mismatched_rhs -- allow branches to have differing RHS?
    view_name_p4client    -- name of actual p4 client on which to base this new repo
                             if None - will be determined from view_name if needed

    Returns one of the INIT_REPO_* constants.
    """
    # Ensure the client root directory has been created.
    if not os.path.exists(client_root):
        os.makedirs(client_root)

    view_name_git = p4gf_translate.TranslateReponame.repo_to_git(view_name)
    LOG.debug("_create_p4_client(): view_name_git {0}   view_name {1}   view_name_p4client {2}".
            format(view_name_git, view_name ,view_name_p4client))

    # If a Git Fusion client for this view already exists, use that,
    # no need to init the repo.
    # Do make sure that the client root is correct.
    if p4gf_util.spec_exists(p4, 'client', client_name):
        LOG.debug("%s client already exists for %s", client_name, view_name)
        p4gf_util.ensure_spec_values(p4, 'client', client_name
            , { 'Root'    : client_root
              , 'Options' : CLIENT_OPTIONS })
        return INIT_REPO_EXISTS

    # Repo config file already checked into Perforce?
    # Use that.
    config_path   = p4gf_config.depot_path_repo(view_name)
    config_exists = p4gf_util.depot_file_exists(p4, config_path)
    if config_exists:
        return repo_from_config( p4, view_name, client_name, client_root
                               , enable_mismatched_rhs)

    # Client exist with the same name as this Git Fusion repo?
    # Build a new config, check it into Perforce, and use that.
    if not view_name_p4client:
        view_name_p4client = p4gf_translate.TranslateReponame.git_to_p4client(view_name_git)
    nop4client = ''
    if p4gf_util.spec_exists(p4, 'client', view_name_p4client):
        return repo_from_template_client( p4, view_name, view_name_p4client, client_name
                                        , client_root
                                        , enable_mismatched_rhs)
    else:
        nop4client = _("p4 client '{0}' does not exist\n").format(view_name_p4client)

    # creating repo from stream?
    # note that we can't pass '//depot/stream' because git would be confused
    # but it's ok to pass 'depot/stream' and add the leading '//' here
    stream_name = '//'+view_name_git
    if p4gf_util.spec_exists(p4, 'stream', stream_name):
        return _repo_from_stream(p4, view_name, stream_name, client_name, client_root,
                                 enable_mismatched_rhs, handle_imports)

    # We don't have, and cannot create, a config for this repo.
    # Say so and give up.
    msg = p4gf_const.NO_REPO_MSG_TEMPLATE.format(view_name=view_name
            ,view_name_p4client=view_name_p4client
            ,nop4client=nop4client)
    LOG.warn(msg)
    _print_stderr(msg)
    return INIT_REPO_NOVIEW
def import_submodules(ctx, view, change_view, import_paths):
    """For stream clients, create a submodule for each import.

    Arguments:
        ctx -- parent repo context.
        view -- the parent stream's 'View'.
        change_view -- the parent stream's 'ChangeView'.
        import_paths -- result from p4gf_streams.match_import_paths() on the
                        virtual stream's paths and the parent stream's paths.

    """
    usermap = p4gf_usermap.UserMap(ctx.p4gf)
    user_3tuple = usermap.lookup_by_p4user(p4gf_const.P4GF_USER)
    if not user_3tuple:
        LOG.error('Missing Perforce user {}'.format(p4gf_const.P4GF_USER))
        return
    client_name = ctx.config.p4client
    LOG.debug('processing imports for {}'.format(client_name))
    LOG.debug3('import_submodules() view={}, change_view={}, import_paths={}'.format(
        view, change_view, import_paths))
    change_views = p4gf_streams.stream_imports_with_changes(view, change_view, import_paths)
    LOG.debug2('import_submodules() change_views={}'.format(change_views))
    if not change_views and LOG.isEnabledFor(logging.DEBUG2):
        LOG.debug2('import_submodules() view={} change_view={} import_paths={}'.format(
            view, change_view, import_paths))
    # initialize and populate the submodules
    old_sha1 = ctx.view_repo.lookup_reference('HEAD').resolve().hex
    for depot_path, change_num, local_path in change_views:
        # avoid double-nesting by excluding the local path from the client path
        client_path = "//{}/...".format(client_name)
        LOG.debug('import_submodules() for {} => {}'.format(depot_path, client_path))
        stream_name = depot_path[:-4]
        if p4gf_util.spec_exists(ctx.p4, 'stream', stream_name):
            # convert stream name to repo name by pruning leading slashes
            repo_name = p4gf_streams.repo_name_from_depot_path(stream_name)
            config = None
            LOG.debug('initializing stream import for {}'.format(depot_path))
        else:
            # create a repo configuration file for this 1-line view
            repo_name = p4gf_streams.repo_name_from_depot_path(depot_path)
            client_less_path = CLIENT_LESS_REGEX.match(client_path).group(1)
            if client_path and client_path[0] == '"':
                client_less_path = '"' + client_less_path
            repo_view = depot_path + " " + client_less_path
            LOG.debug('creating config for {}'.format(repo_name))
            config = p4gf_config.default_config_repo_for_view_plain(ctx.p4, repo_name, repo_view)
        # prepare to initialize the repository
        p4 = p4gf_create_p4.create_p4()
        if not p4:
            LOG.error('unable to create P4 instance for {}'.format(repo_name))
            return
        with p4gf_lock.view_lock(p4, repo_name) as view_lock:
            if config:
                p4gf_config.create_file_repo_from_config(ctx, repo_name, config)
            LOG.debug('initializing repo for {}'.format(repo_name))
            result = init_repo(p4, repo_name, view_lock, handle_imports=False)
            if result > INIT_REPO_OK:
                return result
            with p4gf_context.create_context(repo_name, view_lock) as subtxt:
                # set up gitmirror for child repos
                p4gf_gitmirror.setup_spawn(repo_name)
                # populate the submodule
                shared_in_progress = p4gf_lock.shared_host_view_lock_exists(subtxt.p4, repo_name)
                if not shared_in_progress:
                    copy_submodule(ctx, repo_name, subtxt, local_path, change_num, user_3tuple)
        p4gf_create_p4.p4_disconnect(p4)
    # Remove any submodules controlled by Git Fusion that no longer match
    # any of the current import paths.
    deport_submodules(ctx, import_paths, user_3tuple)
    #
    # Ensure the Git commits we just created are copied back to Perforce by
    # faking a 'push' from the client. Roll the HEAD reference ('master')
    # back to the old SHA1, assign the commits to Perforce branches, then
    # move the reference back to the latest commit and copy everything to
    # the depot as usual.
    #
    new_head = ctx.view_repo.lookup_reference('HEAD').resolve()
    ctx.view_repo.git_reference_create(new_head.name, old_sha1, True)
    prt = p4gf_branch_id.PreReceiveTuple(old_sha1, new_head.hex, new_head.name)
    LOG.debug('Copying modules to depot: {}'.format(prt))
    assigner = p4gf_branch_id.Assigner(ctx.branch_dict(), [prt], ctx)
    assigner.assign()
    ctx.view_repo.git_reference_create(new_head.name, new_head.hex, True)
    err = p4gf_copy_to_p4.copy_git_changes_to_p4(ctx, prt, assigner, None)
    if err:
        LOG.error(err)
def import_submodules(ctx, view, change_view, import_paths):
    """For stream clients, create a submodule for each import.

    Arguments:
        ctx -- parent repo context.
        view -- the parent stream's 'View'.
        change_view -- the parent stream's 'ChangeView'.
        import_paths -- result from p4gf_streams.match_import_paths() on the
                        virtual stream's paths and the parent stream's paths.

    """
    usermap = p4gf_usermap.UserMap(ctx.p4gf)
    user_3tuple = usermap.lookup_by_p4user(p4gf_const.P4GF_USER)
    if not user_3tuple:
        LOG.error('Missing Perforce user {}'.format(p4gf_const.P4GF_USER))
        return
    client_name = ctx.config.p4client
    LOG.debug('processing imports for {}'.format(client_name))
    LOG.debug3(
        'import_submodules() view={}, change_view={}, import_paths={}'.format(
            view, change_view, import_paths))
    change_views = p4gf_streams.stream_imports_with_changes(
        view, change_view, import_paths)
    LOG.debug2('import_submodules() change_views={}'.format(change_views))
    if not change_views and LOG.isEnabledFor(logging.DEBUG2):
        LOG.debug2(
            'import_submodules() view={} change_view={} import_paths={}'.
            format(view, change_view, import_paths))
    # initialize and populate the submodules
    old_sha1 = ctx.view_repo.lookup_reference('HEAD').resolve().hex
    for depot_path, change_num, local_path in change_views:
        # avoid double-nesting by excluding the local path from the client path
        client_path = "//{}/...".format(client_name)
        LOG.debug('import_submodules() for {} => {}'.format(
            depot_path, client_path))
        stream_name = depot_path[:-4]
        if p4gf_util.spec_exists(ctx.p4, 'stream', stream_name):
            # convert stream name to repo name by pruning leading slashes
            repo_name = p4gf_streams.repo_name_from_depot_path(stream_name)
            config = None
            LOG.debug('initializing stream import for {}'.format(depot_path))
        else:
            # create a repo configuration file for this 1-line view
            repo_name = p4gf_streams.repo_name_from_depot_path(depot_path)
            client_less_path = CLIENT_LESS_REGEX.match(client_path).group(1)
            if client_path and client_path[0] == '"':
                client_less_path = '"' + client_less_path
            repo_view = depot_path + " " + client_less_path
            LOG.debug('creating config for {}'.format(repo_name))
            config = p4gf_config.default_config_repo_for_view_plain(
                ctx.p4, repo_name, repo_view)
        # prepare to initialize the repository
        p4 = p4gf_create_p4.create_p4()
        if not p4:
            LOG.error('unable to create P4 instance for {}'.format(repo_name))
            return
        with p4gf_lock.view_lock(p4, repo_name) as view_lock:
            if config:
                p4gf_config.create_file_repo_from_config(
                    ctx, repo_name, config)
            LOG.debug('initializing repo for {}'.format(repo_name))
            result = init_repo(p4, repo_name, view_lock, handle_imports=False)
            if result > INIT_REPO_OK:
                return result
            with p4gf_context.create_context(repo_name, view_lock) as subtxt:
                # set up gitmirror for child repos
                p4gf_gitmirror.setup_spawn(repo_name)
                # populate the submodule
                shared_in_progress = p4gf_lock.shared_host_view_lock_exists(
                    subtxt.p4, repo_name)
                if not shared_in_progress:
                    copy_submodule(ctx, repo_name, subtxt, local_path,
                                   change_num, user_3tuple)
        p4gf_create_p4.p4_disconnect(p4)
    # Remove any submodules controlled by Git Fusion that no longer match
    # any of the current import paths.
    deport_submodules(ctx, import_paths, user_3tuple)
    #
    # Ensure the Git commits we just created are copied back to Perforce by
    # faking a 'push' from the client. Roll the HEAD reference ('master')
    # back to the old SHA1, assign the commits to Perforce branches, then
    # move the reference back to the latest commit and copy everything to
    # the depot as usual.
    #
    new_head = ctx.view_repo.lookup_reference('HEAD').resolve()
    ctx.view_repo.git_reference_create(new_head.name, old_sha1, True)
    prt = p4gf_branch_id.PreReceiveTuple(old_sha1, new_head.hex, new_head.name)
    LOG.debug('Copying modules to depot: {}'.format(prt))
    assigner = p4gf_branch_id.Assigner(ctx.branch_dict(), [prt], ctx)
    assigner.assign()
    ctx.view_repo.git_reference_create(new_head.name, new_head.hex, True)
    err = p4gf_copy_to_p4.copy_git_changes_to_p4(ctx, prt, assigner, None)
    if err:
        LOG.error(err)
Beispiel #20
0
def _global_init(p4):
    """Check that p4gf_super_init has been run and created the following
    * user git-fusion-user
    * depot //P4GF_DEPOT
    * 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).
    #

    p4gf_util.has_server_id_or_exit()

    spec_list = {
        'user1':  p4gf_const.P4GF_USER,
        'user2':  p4gf_util.gf_reviews_user_name(),
        'user3':  p4gf_const.P4GF_REVIEWS__NON_GF,
        'group':  p4gf_const.P4GF_GROUP,
        'depot':  p4gf_const.P4GF_DEPOT
    }
    for spec_type, spec_id in spec_list.items():
        spec_type = re.sub(NTR(r'\d$'), '', spec_type)
        if not p4gf_util.spec_exists(p4, spec_type, spec_id):
        # pylint:disable=C0301
            raise RuntimeError(_("error: {spec_type} '{spec_id}' does not exist."
                                 " Please contact your administrator.")
                               .format(spec_type=spec_type, spec_id=spec_id))
        # pylint:enable=C0301

    for group in [p4gf_group.PERM_PULL, p4gf_group.PERM_PUSH]:
        c = p4gf_group.create_global_perm(p4, group)
        if c:
            _info(_("Global permission group '{}' created.").format(group))
        else:
            _info(_("Global permission group '{}' already exists.").format(group))

    c = p4gf_group.create_default_perm(p4)
    if c:
        _info(_("Default permission counter '{}' set to '{}'.")
              .format( p4gf_const.P4GF_COUNTER_PERMISSION_GROUP_DEFAULT
                     , p4gf_group.DEFAULT_PERM ))
    else:
        _info(_("Default permission counter '{}' already exists.")
              .format(p4gf_const.P4GF_COUNTER_PERMISSION_GROUP_DEFAULT))

    # Require that single git-fusion-user have admin privileges
    # over the //P4GF_DEPOT/ 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_all_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_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)]})
        _info(_('Protects table set.'))
def _create_p4_client(p4,
                      view_name,
                      client_name,
                      client_root,
                      enable_mismatched_rhs,
                      view_name_p4client,
                      handle_imports=True):
    """Create the p4 client to contain Git meta-data mirror.

    Keyword arguments:
    p4                    -- Perforce client API
    view_name             -- client view of repository to clone - internal (translated) viewname
    client_name           -- client that will be created
    client_root           -- path for client workspace
    enable_mismatched_rhs -- allow branches to have differing RHS?
    view_name_p4client    -- name of actual p4 client on which to base this new repo
                             if None - will be determined from view_name if needed

    Returns one of the INIT_REPO_* constants.
    """
    # Ensure the client root directory has been created.
    if not os.path.exists(client_root):
        os.makedirs(client_root)

    view_name_git = p4gf_translate.TranslateReponame.repo_to_git(view_name)
    LOG.debug(
        "_create_p4_client(): view_name_git {0}   view_name {1}   view_name_p4client {2}"
        .format(view_name_git, view_name, view_name_p4client))

    # If a Git Fusion client for this view already exists, use that,
    # no need to init the repo.
    # Do make sure that the client root is correct.
    if p4gf_util.spec_exists(p4, 'client', client_name):
        LOG.debug("%s client already exists for %s", client_name, view_name)
        p4gf_util.ensure_spec_values(p4, 'client', client_name, {
            'Root': client_root,
            'Options': CLIENT_OPTIONS
        })
        return INIT_REPO_EXISTS

    # Repo config file already checked into Perforce?
    # Use that.
    config_path = p4gf_config.depot_path_repo(view_name)
    config_exists = p4gf_util.depot_file_exists(p4, config_path)
    if config_exists:
        return repo_from_config(p4, view_name, client_name, client_root,
                                enable_mismatched_rhs)

    # Client exist with the same name as this Git Fusion repo?
    # Build a new config, check it into Perforce, and use that.
    if not view_name_p4client:
        view_name_p4client = p4gf_translate.TranslateReponame.git_to_p4client(
            view_name_git)
    nop4client = ''
    if p4gf_util.spec_exists(p4, 'client', view_name_p4client):
        return repo_from_template_client(p4, view_name, view_name_p4client,
                                         client_name, client_root,
                                         enable_mismatched_rhs)
    else:
        nop4client = _("p4 client '{0}' does not exist\n").format(
            view_name_p4client)

    # creating repo from stream?
    # note that we can't pass '//depot/stream' because git would be confused
    # but it's ok to pass 'depot/stream' and add the leading '//' here
    stream_name = '//' + view_name_git
    if p4gf_util.spec_exists(p4, 'stream', stream_name):
        return _repo_from_stream(p4, view_name, stream_name, client_name,
                                 client_root, enable_mismatched_rhs,
                                 handle_imports)

    # We don't have, and cannot create, a config for this repo.
    # Say so and give up.
    msg = p4gf_const.NO_REPO_MSG_TEMPLATE.format(
        view_name=view_name,
        view_name_p4client=view_name_p4client,
        nop4client=nop4client)
    LOG.warn(msg)
    _print_stderr(msg)
    return INIT_REPO_NOVIEW
Beispiel #22
0
def _global_init(p4):
    """Check that p4gf_super_init has been run and created the following
    * user git-fusion-user
    * depot //P4GF_DEPOT
    * 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).
    #

    p4gf_util.has_server_id_or_exit()

    spec_list = {
        'user1': p4gf_const.P4GF_USER,
        'user2': p4gf_util.gf_reviews_user_name(),
        'user3': p4gf_const.P4GF_REVIEWS__NON_GF,
        'group': p4gf_const.P4GF_GROUP,
        'depot': p4gf_const.P4GF_DEPOT
    }
    for spec_type, spec_id in spec_list.items():
        spec_type = re.sub(NTR(r'\d$'), '', spec_type)
        if not p4gf_util.spec_exists(p4, spec_type, spec_id):
            # pylint:disable=C0301
            raise RuntimeError(
                _("error: {spec_type} '{spec_id}' does not exist."
                  " Please contact your administrator.").format(
                      spec_type=spec_type, spec_id=spec_id))
        # pylint:enable=C0301

    for group in [p4gf_group.PERM_PULL, p4gf_group.PERM_PUSH]:
        c = p4gf_group.create_global_perm(p4, group)
        if c:
            _info(_("Global permission group '{}' created.").format(group))
        else:
            _info(
                _("Global permission group '{}' already exists.").format(
                    group))

    c = p4gf_group.create_default_perm(p4)
    if c:
        _info(
            _("Default permission counter '{}' set to '{}'.").format(
                p4gf_const.P4GF_COUNTER_PERMISSION_GROUP_DEFAULT,
                p4gf_group.DEFAULT_PERM))
    else:
        _info(
            _("Default permission counter '{}' already exists.").format(
                p4gf_const.P4GF_COUNTER_PERMISSION_GROUP_DEFAULT))

    # Require that single git-fusion-user have admin privileges
    # over the //P4GF_DEPOT/ 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_all_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_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)
                               ]
                           })
        _info(_('Protects table set.'))
def delete_client(args, p4, client_name):
    """Delete the named Perforce client and its workspace. Raises
    P4Exception if the client is not present, or the client configuration is
    not set up as expected.

    Keyword arguments:
    args        -- parsed command line arguments
    p4          -- Git user's Perforce client
    client_name -- name of client to be deleted

    """
    group_list = [
        p4gf_const.P4GF_GROUP_VIEW_PULL, p4gf_const.P4GF_GROUP_VIEW_PUSH
    ]
    p4.user = p4gf_const.P4GF_USER

    print_verbose(args, "Checking for client {}...".format(client_name))
    if not p4gf_util.spec_exists(p4, 'client', client_name):
        raise P4.P4Exception('No such client "{}" defined'.format(client_name))

    view_name = client_name[len(p4gf_const.P4GF_CLIENT_PREFIX):]
    view_lock = None  # We're clobbering and deleting. Overrule locks.
    try:
        ctx = p4gf_context.create_context(view_name, view_lock)
    except RuntimeError:
        # not a conforming Git Fusion client, ignore it
        return
    command_path = ctx.client_view_path()

    p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4)
    view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)
    rm_list = [view_dirs.view_container]
    homedir = os.path.expanduser('~')
    raise_if_homedir(homedir, view_name, rm_list)

    # Scan for objects associated only with this view so we can either remove
    # them completely or update their 'views' attribute appropriately.
    p4.handler = FilterViewFstatHandler(view_name)
    p4.run("fstat", "-Oa", "-T", "depotFile, attr-views",
           "//.git-fusion/objects/...")
    objects_to_delete = p4.handler.files_to_delete
    objects_to_modify = p4.handler.files_to_modify
    p4.handler = None

    if not args.delete:
        print("p4 sync -f {}#none".format(command_path))
        print("p4 client -f -d {}".format(client_name))
        for d in rm_list:
            print("rm -rf {}".format(d))
        for to_delete in objects_to_delete:
            print("p4 obliterate -y {}".format(to_delete))
        if objects_to_modify:
            for (fname, views) in objects_to_modify:
                print("attribute -p -n views -v {} {}".format(views, fname))
        for group_template in group_list:
            group = group_template.format(view=view_name)
            print("p4 group -a -d {}".format(group))
        print('p4 counter -u -d {}'.format(
            p4gf_lock.view_lock_name(view_name)))

    else:
        print_verbose(args,
                      "Removing client files for {}...".format(client_name))
        ctx.p4.run('sync', '-fq', command_path + '#none')
        print_verbose(args, "Deleting client {}...".format(client_name))
        p4.run('client', '-df', client_name)
        for d in rm_list:
            remove_file_or_dir(args, view_name, d)
        bite_size = 1000
        while len(objects_to_delete):
            to_delete = objects_to_delete[:bite_size]
            objects_to_delete = objects_to_delete[bite_size:]
            p4.run("obliterate", "-y", to_delete)
        if objects_to_modify:
            for (fname, views) in objects_to_modify:
                p4.run("edit", fname)
                p4.run("attribute", "-p", "-n", "views", "-v", views, fname)
            p4.run("submit", "-d",
                   "'Removing {} from views attribute'".format(view_name))
        for group_template in group_list:
            delete_group(args, p4, group_template.format(view=view_name))
        _delete_counter(p4, p4gf_lock.view_lock_name(view_name))
Beispiel #24
0
def delete_client(args, p4, client_name, metrics, prune_objs=True):
    """Delete the named Perforce client and its workspace. Raises
    P4Exception if the client is not present, or the client configuration is
    not set up as expected.

    Keyword arguments:
    args        -- parsed command line arguments
    p4          -- Git user's Perforce client
    client_name -- name of client to be deleted
    metrics     -- DeletionMetrics for collecting resulting metrics
    prune_objs  -- if True, delete associated objects from cache

    """
    # pylint: disable=R0912,R0915
    group_list = [
        p4gf_const.P4GF_GROUP_VIEW_PULL, p4gf_const.P4GF_GROUP_VIEW_PUSH
    ]
    p4.user = p4gf_const.P4GF_USER

    print_verbose(args, _("Checking for client '{}'...").format(client_name))
    if not p4gf_util.spec_exists(p4, 'client', client_name):
        raise P4.P4Exception(
            _("No such client '{}' defined").format(client_name))
    view_name = p4gf_util.client_to_view_name(client_name)
    p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4)
    view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)
    p4gf_util.ensure_spec_values(p4, 'client', client_name,
                                 {'Root': view_dirs.p4root})

    view_lock = None  # We're clobbering and deleting. Overrule locks.
    with p4gf_context.create_context(view_name, view_lock) as ctx:
        command_path = ctx.client_view_path()

        homedir = os.path.expanduser('~')
        raise_if_homedir(homedir, view_name, view_dirs.view_container)

        # Scan for objects associated only with this view so we can remove them.
        objects_to_delete = []
        if prune_objs:
            objects_to_delete = _find_client_commit_objects(
                args, p4, view_name)

        # Do we have a repo config file to delete?
        config_file = p4gf_config.depot_path_repo(view_name) + '*'
        config_file_exists = p4gf_util.depot_file_exists(p4, config_file)

        # What counters shall we delete?
        counter_list = []
        counter_list.append(
            p4gf_context.calc_last_copied_change_counter_name(
                view_name, p4gf_util.get_server_id()))
        for spec in p4.run('counters', '-u', '-e',
                           "git-fusion-index-last-{},*".format(view_name)):
            counter_list.append(spec['counter'])
        for spec in p4.run('counters', '-u', '-e',
                           "git-fusion-index-branch-{},*".format(view_name)):
            counter_list.append(spec['counter'])

        if not args.delete:
            print(NTR('p4 sync -f {}#none').format(command_path))
            print(NTR('p4 client -f -d {}').format(client_name))
            print(NTR('rm -rf {}').format(view_dirs.view_container))
            print(
                NTR('Deleting {} objects from //{}/objects/...').format(
                    len(objects_to_delete), p4gf_const.P4GF_DEPOT))
            for group_template in group_list:
                group = group_template.format(view=view_name)
                print(NTR('p4 group -a -d {}').format(group))
            for c in counter_list:
                print(NTR('p4 counter -u -d {}').format(c))

            if config_file_exists:
                print(NTR('p4 sync -f {}').format(config_file))
                print(NTR('p4 delete  {}').format(config_file))
                print(
                    NTR('p4 submit -d "Delete repo config for {view_name}" {config_file}'
                        ).format(view_name=view_name, config_file=config_file))
        else:
            print_verbose(
                args,
                NTR('Removing client files for {}...').format(client_name))
            ctx.p4.run('sync', '-fq', command_path + '#none')
            print_verbose(args,
                          NTR('Deleting client {}...').format(client_name))
            p4.run('client', '-df', client_name)
            metrics.clients += 1
            print_verbose(
                args,
                NTR("Deleting repo {0}'s directory {1}...").format(
                    view_name, view_dirs.view_container))
            _remove_tree(view_dirs.view_container, contents_only=False)
            metrics.files += _delete_files(p4, objects_to_delete, view_name)
            for group_template in group_list:
                _delete_group(args, p4, group_template.format(view=view_name),
                              metrics)
            for c in counter_list:
                _delete_counter(p4, c, metrics)

            if config_file_exists:
                p4gf_util.p4run_logged(p4, ['sync', '-fq', config_file])
                with p4gf_util.NumberedChangelist(
                        p4=p4,
                        description=_("Delete repo config for '{}'").format(
                            view_name)) as nc:
                    nc.p4run(["delete", config_file])
                    nc.submit()