def reset_git_enviro():
    """Clear GIT_DIR and other GIT_xxx  environment variables,
    then chdir to GIT_WORK_TREE.

    This undoes any strangeness that might come in from T4 calling 'git
    --git-dir=xxx --work-tree=yyy' which might cause us to erroneously
    operate on the "client-side" git repo when invoked from T4.

    or from git-receive-pack chdir-ing into the .git dir.
    """
    git_env_key = [k for k in os.environ if k.startswith("GIT_")]
    for key in git_env_key:
        del os.environ[key]

    # Find our view name, use that to calculate and chdir into our GIT_WORK_TREE.
    rc_path = p4gf_path.cwd_to_rc_file()
    if (rc_path):
        view_name = rc_path_to_view_name(rc_path)
        LOG.debug("reset_git_enviro rc_path_to_view_name({rc_path}) returned {view_name}"
                  .format(rc_path=rc_path, view_name=view_name))
        p4gf_dir    = rc_path_to_p4gf_dir(rc_path)
        LOG.debug("reset_git_enviro rc_path_to_p4gf_dir({rc_path}) returned {p4gf_dir}"
                  .format(rc_path=rc_path, p4gf_dir=p4gf_dir))
        view_dirs  = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)
        os.chdir(view_dirs.GIT_WORK_TREE)
示例#2
0
def reset_git_enviro():
    """Clear GIT_DIR and other GIT_xxx  environment variables,
    then chdir to GIT_WORK_TREE.

    This undoes any strangeness that might come in from T4 calling 'git
    --git-dir=xxx --work-tree=yyy' which might cause us to erroneously
    operate on the "client-side" git repo when invoked from T4.

    or from git-receive-pack chdir-ing into the .git dir.
    """
    git_env_key = [k for k in os.environ if k.startswith("GIT_")]
    for key in git_env_key:
        del os.environ[key]

    # Find our view name, use that to calculate and chdir into our GIT_WORK_TREE.
    rc_path = p4gf_path.cwd_to_rc_file()
    if (rc_path):
        view_name = rc_path_to_view_name(rc_path)
        LOG.debug(
            "reset_git_enviro rc_path_to_view_name({rc_path}) returned {view_name}"
            .format(rc_path=rc_path, view_name=view_name))
        p4gf_dir = rc_path_to_p4gf_dir(rc_path)
        LOG.debug(
            "reset_git_enviro rc_path_to_p4gf_dir({rc_path}) returned {p4gf_dir}"
            .format(rc_path=rc_path, p4gf_dir=p4gf_dir))
        view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)
        os.chdir(view_dirs.GIT_WORK_TREE)
示例#3
0
    def __set_up_paths(self):
        """set up depot and local paths for both content and P4GF

        These paths are derived from the client root and client view.
        """
        self.__set_up_content_paths()
        self.__set_up_p4gf_paths()
        self.view_dirs = p4gf_view_dirs.from_p4gf_dir(self.gitrootdir, self.config.view_name)
示例#4
0
    def __set_up_paths(self):
        """set up depot and local paths for both content and P4GF

        These paths are derived from the client root and client view.
        """
        self.__set_up_content_paths()
        self.__set_up_p4gf_paths()
        self.view_dirs = p4gf_view_dirs.from_p4gf_dir(self.gitrootdir,
                                                      self.config.view_name)
def init_repo(p4,
              view_name,
              view_lock,
              charset=None,
              enable_mismatched_rhs=False,
              view_name_p4client=None,
              handle_imports=True):
    '''
    Create view and repo if necessary. Does NOT copy p4 to the repo
    (that's p4gf_copy_p2g's job). Returns one of the INIT_REPO_* constants.

    This is p4gf_auth_server's entry point into init_repo, called in response
    to a 'git clone'.

    view_name is the internal view_name with special chars already translated

    view_lock           CounterLock mutex that prevents other processes from
                        touching this repo, whether on this Git Fusion server
                        or another.
    '''
    LOG.debug("init_repo : view_name {1} view_name_p4client {1}".format(
        view_name, view_name_p4client))
    client_name = p4gf_util.view_to_client_name(view_name)
    p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4)
    view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)

    result = _create_p4_client(p4, view_name, client_name, view_dirs.p4root,
                               enable_mismatched_rhs, view_name_p4client,
                               handle_imports)
    if result > INIT_REPO_OK:
        return result
    create_perm_groups(p4, view_name)
    with p4gf_context.create_context(view_name, view_lock) as ctx:
        p4gf_config.create_file_repo(ctx, view_name, charset)
        if ctx.client_exclusions_added:
            _print_stderr(
                _("The referenced client view contains implicit exclusions."
                  "\nThe Git Fusion config will contain these as explicit exclusions."
                  ))
        p4gf_copy_p2g.create_git_repo(ctx, view_dirs.GIT_DIR)
    create_p4_client_root(view_dirs.p4root)
    p4gf_rc.update_file(view_dirs.rcfile, client_name, view_name)
    if result == INIT_REPO_OK:
        LOG.debug("repository creation for %s complete", view_name)
    # return the result of creating the client, to indicate if the client
    # had already been set up or not
    return result
def copy_p2g_ctx(ctx, start=None):
    """Using the given context, copy its view from Perforce to Git.

    Common code for p4gf_auth_server.py and p4gf_init_repo.py for setting up
    the eventual call to copy_p2g."""

    view_name = ctx.config.view_name

    # Find directory paths to feed to git.
    p4gf_dir = p4gf_util.p4_to_p4gf_dir(ctx.p4gf)
    ctx.view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)

    # cd into the work directory. Not all git functions react well to --work-tree=xxxx.
    os.chdir(ctx.view_dirs.GIT_WORK_TREE)

    # Fill git with content from Perforce.
    copy_p2g(ctx, start)
示例#7
0
def copy_p2g_ctx(ctx, start=None):
    """Using the given context, copy its view from Perforce to Git.

    Common code for p4gf_auth_server.py and p4gf_init_repo.py for setting up
    the eventual call to copy_p2g."""

    view_name = ctx.config.view_name

    # Find directory paths to feed to git.
    p4gf_dir = p4gf_util.p4_to_p4gf_dir(ctx.p4gf)
    ctx.view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)

    # cd into the work directory. Not all git functions react well to --work-tree=xxxx.
    os.chdir(ctx.view_dirs.GIT_WORK_TREE)

    # Fill git with content from Perforce.
    copy_p2g(ctx, start)
示例#8
0
def _list_for_server():
    '''
    Return list of repos that have been copied to the given Git Fusion
    server.

    "have been copied" here means "has a .git-fusion/views/<view_name>/
    directory on this server."
    '''
    p4 = p4gf_create_p4.create_p4(client=p4gf_util.get_object_client_name())
    result = []
    p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4)

    for view_name in p4gf_util.view_list(p4):
        view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)
        if os.path.exists(view_dirs.GIT_DIR):
            result.append(view_name)
    p4gf_create_p4.destroy(p4)
    return result
示例#9
0
def _list_for_server():
    '''
    Return list of repos that have been copied to the given Git Fusion
    server.

    "have been copied" here means "has a .git-fusion/views/<view_name>/
    directory on this server."
    '''
    p4 = p4gf_create_p4.create_p4(client=p4gf_util.get_object_client_name())
    result = []
    p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4)

    for view_name in p4gf_util.view_list(p4):
        view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)
        if os.path.exists(view_dirs.GIT_DIR):
            result.append(view_name)
    p4gf_create_p4.destroy(p4)
    return result
示例#10
0
def init_repo(p4
             , view_name
             , view_lock
             , charset=None
             , enable_mismatched_rhs=False
             , view_name_p4client=None
             , handle_imports=True):
    '''
    Create view and repo if necessary. Does NOT copy p4 to the repo
    (that's p4gf_copy_p2g's job). Returns one of the INIT_REPO_* constants.

    This is p4gf_auth_server's entry point into init_repo, called in response
    to a 'git clone'.

    view_name is the internal view_name with special chars already translated

    view_lock           CounterLock mutex that prevents other processes from
                        touching this repo, whether on this Git Fusion server
                        or another.
    '''
    LOG.debug("init_repo : view_name {1} view_name_p4client {1}".format(
        view_name, view_name_p4client))
    client_name = p4gf_util.view_to_client_name(view_name)
    p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4)
    view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)

    result = _create_p4_client(p4, view_name, client_name, view_dirs.p4root,
                               enable_mismatched_rhs, view_name_p4client, handle_imports)
    if result > INIT_REPO_OK:
        return result
    create_perm_groups(p4, view_name)
    with p4gf_context.create_context(view_name, view_lock) as ctx:
        p4gf_config.create_file_repo(ctx, view_name, charset)
        if ctx.client_exclusions_added:
            _print_stderr(_("The referenced client view contains implicit exclusions."
                            "\nThe Git Fusion config will contain these as explicit exclusions."))
        p4gf_copy_p2g.create_git_repo(ctx, view_dirs.GIT_DIR)
    create_p4_client_root(view_dirs.p4root)
    p4gf_rc.update_file(view_dirs.rcfile, client_name, view_name)
    if result == INIT_REPO_OK:
        LOG.debug("repository creation for %s complete", view_name)
    # return the result of creating the client, to indicate if the client
    # had already been set up or not
    return result
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_const.P4GF_CLIENT_PREFIX + 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()

    p4gf_dir = p4gf_util.p4_to_p4gf_dir(ctx.p4)
    view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)

    ctx.p4.run('sync', '-fq', command_path + '#none')
    ctx.p4.run('client', '-df', client_name)
    for vdir in [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)
示例#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_const.P4GF_CLIENT_PREFIX + 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()

    p4gf_dir = p4gf_util.p4_to_p4gf_dir(ctx.p4)
    view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)

    ctx.p4.run('sync', '-fq', command_path + '#none')
    ctx.p4.run('client', '-df', client_name)
    for vdir in [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 init_repo(p4, view_name):
    """Create view and repo if necessary. Does NOT copy p4 to the repo
    (that's p4gf_copy_p2g's job). Returns one of the INIT_REPO_* constants.
    """

    client_name = p4gf_context.view_to_client_name(view_name)

    p4gf_dir    = p4gf_util.p4_to_p4gf_dir(p4)
    view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name)
    result = create_p4_client(p4, view_name, client_name, view_dirs.p4root)
    if result > INIT_REPO_OK:
        return result
    create_perm_groups(p4, view_name)
    p4gf_copy_p2g.create_git_repo(view_dirs.GIT_DIR)
    ensure_deny_rewind(view_dirs.GIT_WORK_TREE)
    install_hook(view_dirs.GIT_DIR)
    create_p4_client_root(view_dirs.p4root)
    p4gf_rc.update_file(view_dirs.rcfile, client_name, view_name)
    LOG.debug("repository creation for %s complete", view_name)
    # return the result of creating the client, to indicate if the client
    # had already been set up or not
    return result
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))
示例#15
0
def main():
    """set up repo for a view"""
    with ExceptionAuditLogger():
        args = parse_args(sys.argv[1:])
        if not args:
            return 1

        # Record the p4 user in environment. We use environment to pass to
        # git-invoked hook. We don't have to set ctx.authenticated_p4user because
        # Context.__init__() reads it from environment, which we set here.
        os.environ[p4gf_const.P4GF_AUTH_P4USER_ENVAR] = args.user

        # print "args={}".format(args)
        view_name = args.options[-1]

        p4gf_util.reset_git_enviro()
        p4 = connect_p4()
        if not p4:
            return 2
        LOG.debug("connected to P4: %s", p4)

        _check_lock_perm(p4)

        if not check_protects(p4):
            _raise_p4gf_perm()

        if run_special_command(view_name, p4, args.user):
            return 0

        # Go no further, create NOTHING, if user not authorized.
        view_perm = p4gf_group.ViewPerm.for_user_and_view(
            p4, args.user, view_name)
        _check_authorization(view_perm, args.user, args.command[0], view_name)
        # Create Git Fusion server depot, user, config. NOPs if already created.
        p4gf_init.init(p4)

        with p4gf_lock.view_lock(p4, view_name) as view_lock:

            # Create Git Fusion per-repo client view mapping and config.
            #
            # NOPs if already created.
            # Create the empty directory that will hold the git repo.
            init_repo_status = p4gf_init_repo.init_repo(p4, view_name)
            if init_repo_status == p4gf_init_repo.INIT_REPO_OK:
                repo_created = True
            elif init_repo_status == p4gf_init_repo.INIT_REPO_EXISTS:
                repo_created = False
            else:
                return 1

            # If authorization came from default, not explicit group
            # membership, copy that authorization to a group now. Could
            # not do this until after p4gf_init_repo() has a chance to
            # create not-yet-existing groups.
            view_perm.write_if(p4)

            # Now that we have valid git-fusion-user and
            # git-fusion-<view> client, replace our temporary P4
            # connection with a more permanent Context, shared for the
            # remainder of this process.
            ctx = p4gf_context.create_context(view_name, view_lock)
            del p4
            LOG.debug("reconnected to P4, p4gf=%s", ctx.p4gf)

            # Find directory paths to feed to git.
            ctx.view_dirs = p4gf_view_dirs.from_p4gf_dir(
                ctx.gitrootdir, view_name)
            ctx.log_context()

            # cd into the work directory. Not all git functions react well
            # to --work-tree=xxxx.
            cwd = os.getcwd()
            os.chdir(ctx.view_dirs.GIT_WORK_TREE)

            # Copy any recent changes from Perforce to Git.
            try:
                p4gf_copy_p2g.copy_p2g_ctx(ctx)
            except:
                # Dump failure to log, BEFORE cleanup, just in case
                # cleanup ALSO fails and throws its own error (which
                # happens if we're out of memory).
                LOG.error(traceback.format_exc())

                if repo_created:
                    # Return to the original working directory to allow the
                    # config code to call os.getcwd() without dying, since
                    # we are about to delete the current working directory.
                    os.chdir(cwd)
                    cleanup_client(ctx, view_name)
                raise

            # Detach git repo's workspace from master before calling
            # original git, otherwise we won't be able to push master.
            p4gf_util.checkout_detached_master()

            # Flush stderr before returning control to Git.
            # Otherwise Git's own output might interrupt ours.
            sys.stderr.flush()

            return _call_original_git(ctx, args)
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))
示例#17
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()
示例#18
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()
def main():
    """set up repo for a view"""
    with ExceptionAuditLogger():
        args = parse_args(sys.argv[1:])
        if not args:
            return 1

        # Record the p4 user in environment. We use environment to pass to
        # git-invoked hook. We don't have to set ctx.authenticated_p4user because
        # Context.__init__() reads it from environment, which we set here.
        os.environ[p4gf_const.P4GF_AUTH_P4USER_ENVAR] = args.user

        # print "args={}".format(args)
        view_name = args.options[-1]

        p4gf_util.reset_git_enviro()
        p4 = connect_p4()
        if not p4:
            return 2
        LOG.debug("connected to P4: %s", p4)

        _check_lock_perm(p4)

        if not check_protects(p4):
            _raise_p4gf_perm()

        if run_special_command(view_name, p4, args.user):
            return 0

        # Go no further, create NOTHING, if user not authorized.
        view_perm = p4gf_group.ViewPerm.for_user_and_view(p4, args.user, view_name)
        _check_authorization(view_perm, args.user, args.command[0], view_name)
        # Create Git Fusion server depot, user, config. NOPs if already created.
        p4gf_init.init(p4)

        with p4gf_lock.view_lock(p4, view_name) as view_lock:

            # Create Git Fusion per-repo client view mapping and config.
            #
            # NOPs if already created.
            # Create the empty directory that will hold the git repo.
            init_repo_status = p4gf_init_repo.init_repo(p4, view_name)
            if init_repo_status == p4gf_init_repo.INIT_REPO_OK:
                repo_created = True
            elif init_repo_status == p4gf_init_repo.INIT_REPO_EXISTS:
                repo_created = False
            else:
                return 1

            # If authorization came from default, not explicit group
            # membership, copy that authorization to a group now. Could
            # not do this until after p4gf_init_repo() has a chance to
            # create not-yet-existing groups.
            view_perm.write_if(p4)

            # Now that we have valid git-fusion-user and
            # git-fusion-<view> client, replace our temporary P4
            # connection with a more permanent Context, shared for the
            # remainder of this process.
            ctx = p4gf_context.create_context(view_name, view_lock)
            del p4
            LOG.debug("reconnected to P4, p4gf=%s", ctx.p4gf)

            # Find directory paths to feed to git.
            ctx.view_dirs = p4gf_view_dirs.from_p4gf_dir(ctx.gitrootdir, view_name)
            ctx.log_context()

            # cd into the work directory. Not all git functions react well
            # to --work-tree=xxxx.
            cwd = os.getcwd()
            os.chdir(ctx.view_dirs.GIT_WORK_TREE)

            # Copy any recent changes from Perforce to Git.
            try:
                p4gf_copy_p2g.copy_p2g_ctx(ctx)
            except:
                # Dump failure to log, BEFORE cleanup, just in case
                # cleanup ALSO fails and throws its own error (which
                # happens if we're out of memory).
                LOG.error(traceback.format_exc())

                if repo_created:
                    # Return to the original working directory to allow the
                    # config code to call os.getcwd() without dying, since
                    # we are about to delete the current working directory.
                    os.chdir(cwd)
                    cleanup_client(ctx, view_name)
                raise

            # Detach git repo's workspace from master before calling
            # original git, otherwise we won't be able to push master.
            p4gf_util.checkout_detached_master()

            # Flush stderr before returning control to Git.
            # Otherwise Git's own output might interrupt ours.
            sys.stderr.flush()

            return _call_original_git(ctx, args)