Пример #1
0
def main():
    """create Perforce user and client for Git Fusion"""

    p4gf_version.log_version()
    try:
        log_l10n()
        p4gf_version.version_check()
    # pylint: disable=W0703
    # Catching too general exception
    except Exception as e:
        sys.stderr.write(e.args[0] + '\n')
        sys.exit(1)

    with p4gf_create_p4.Closer():
        p4 = p4gf_create_p4.create_p4()
        if not p4:
            return 2

        Verbosity.report(Verbosity.INFO, "P4PORT : {}".format(p4.port))
        Verbosity.report(Verbosity.INFO, "P4USER : {}".format(p4.user))

        p4gf_util.reset_git_enviro()
        p4gf_proc.init()

        init(p4)

    return 0
def main():
    """Do the thing."""
    try:
        p4gf_version.git_version_check()

        # Connect.
        global P4PORT, P4USER, p4
        p4 = create_p4(port=P4PORT, user=P4USER)
        P4PORT = p4.port
        P4USER = p4.user
        report(INFO, "P4PORT : {}".format(p4.port))
        report(INFO, "P4USER : {}".format(p4.user))
        p4.connect()
        p4gf_version.p4d_version_check(p4)

        # Require that we have super permission.
        # Might as well keep the result in case we need to write a new protect
        # table later. Saves a 'p4 protect -o' trip to the server
        protect_lines = fetch_protect()

        ensure_user()
        ensure_group()
        ensure_depot()
        ensure_protect(protect_lines)
        ensure_protects_configurable()

    # pylint: disable=W0703
    # Catching too general exception
    except Exception as e:
        sys.stderr.write(e.args[0] + '\n')
        exit(1)
Пример #3
0
def main():
    '''
    Parse the command-line arguments and print a configuration.
    '''
    p4gf_util.has_server_id_or_exit()
    p4gf_client = p4gf_util.get_object_client_name()
    p4 = p4gf_create_p4.create_p4(client=p4gf_client)
    if not p4:
        sys.exit(1)
    desc = _("""Display the effective global or repository configuration.
All comment lines are elided and formatting is normalized per the
default behavior of the configparser Python module.
The default configuration options will be produced if either of the
configuration files is missing.
""")
    parser = p4gf_util.create_arg_parser(desc=desc)
    parser.add_argument(
        NTR('repo'),
        metavar=NTR('R'),
        nargs='?',
        default='',
        help=_('name of the repository, or none to display global.'))
    args = parser.parse_args()
    if args.repo:
        cfg = get_repo(p4, args.repo)
    else:
        cfg = get_global(p4)
    if not cfg:
        print(_('Unable to read configuration file!'))
    cfg.write(sys.stdout)
Пример #4
0
def main():
    """create Perforce user and client for Git Fusion"""

    p4gf_version.log_version()
    try:
        log_l10n()
        p4gf_version.version_check()
    # pylint: disable=W0703
    # Catching too general exception
    except Exception as e:
        sys.stderr.write(e.args[0] + '\n')
        sys.exit(1)

    with p4gf_create_p4.Closer():
        p4 = p4gf_create_p4.create_p4()
        if not p4:
            return 2

        Verbosity.report(Verbosity.INFO, "P4PORT : {}".format(p4.port))
        Verbosity.report(Verbosity.INFO, "P4USER : {}".format(p4.user))

        p4gf_util.reset_git_enviro()
        p4gf_proc.init()

        init(p4)

    return 0
Пример #5
0
def main():
    """Do the thing."""
    args = parse_argv()
    p4gf_proc.init()

    # Use current or supplied p4user, NOT git-fusion-user, for our work.
    # Use p4 not os.environ(), so that we can honor .p4config.
    p4_query_enviro = p4gf_create_p4.create_p4(port = args.p4port,
                                               user=args.p4user,
                                               warn_no_client = False)
    LOG.debug("P4PORT   : {}".format(p4_query_enviro.port))
    LOG.debug("P4USER   : {}".format(p4_query_enviro.user))
    p4gf_const.P4GF_USER = p4_query_enviro.user

    gc = GC(p4_query_enviro.port,
            p4_query_enviro.user,
            cont=args.cont,
            keep=args.keep,
            force=args.force,
            stdout=args.stdout,
            doreport=args.doreport,
            quiet=args.quiet)
    gc.gc()

    LOG.info("done")
Пример #6
0
 def __make_p4(self, client=None, user=None, connect=True):
     """create a connection to the perforce server"""
     if not user:
         user = self.config.p4user
     if not client:
         client = self.config.p4client
     return create_p4(port=self.config.p4port, user=user, client=client, connect=connect)
def main():
    """Do the thing."""
    try:
        p4gf_version.git_version_check()

        # Connect.
        global P4PORT, P4USER, p4
        p4 = create_p4(port=P4PORT, user=P4USER)
        P4PORT = p4.port
        P4USER = p4.user
        report(INFO, "P4PORT : {}".format(p4.port))
        report(INFO, "P4USER : {}".format(p4.user))
        p4.connect()
        p4gf_version.p4d_version_check(p4)

        # Require that we have super permission.
        # Might as well keep the result in case we need to write a new protect
        # table later. Saves a 'p4 protect -o' trip to the server
        protect_lines = fetch_protect()

        ensure_user()
        ensure_group()
        ensure_depot()
        ensure_protect(protect_lines)
        ensure_protects_configurable()

    # pylint: disable=W0703
    # Catching too general exception
    except Exception as e:
        sys.stderr.write(e.args[0] + '\n')
        exit(1)
Пример #8
0
def main():
    """
    Parses the command line arguments and performs a search for the given
    email address in the user map.
    """
    p4gf_util.has_server_id_or_exit()
    log_l10n()

    # Set up argument parsing.
    parser = p4gf_util.create_arg_parser(
        _("Searches for an email address in the user map."))
    parser.add_argument(NTR('email'), metavar='E',
                        help=_('email address to find'))
    args = parser.parse_args()

    # make sure the world is sane
    ec = p4gf_init.main()
    if ec:
        print(_("p4gf_usermap initialization failed"))
        sys.exit(ec)

    with p4gf_create_p4.Closer():
        p4 = p4gf_create_p4.create_p4(client=p4gf_util.get_object_client_name())
        if not p4:
            sys.exit(1)

        usermap = UserMap(p4)
        user = usermap.lookup_by_email(args.email)
        if user:
            print(_("Found user '{}' <{}>").format(user[0], user[2]))
            sys.exit(0)
        else:
            sys.stderr.write(_("No such user found: '{}'\n").format(args.email))
            sys.exit(1)
Пример #9
0
def main():
    '''
    Parse the command-line arguments and print a configuration.
    '''
    p4gf_util.has_server_id_or_exit()
    p4gf_client = p4gf_util.get_object_client_name()
    p4 = p4gf_create_p4.create_p4(client=p4gf_client)
    if not p4:
        sys.exit(1)
    desc = _("""Display the effective global or repository configuration.
All comment lines are elided and formatting is normalized per the
default behavior of the configparser Python module.
The default configuration options will be produced if either of the
configuration files is missing.
""")
    parser = p4gf_util.create_arg_parser(desc=desc)
    parser.add_argument(NTR('repo'), metavar=NTR('R'), nargs='?', default='',
        help=_('name of the repository, or none to display global.'))
    args = parser.parse_args()
    if args.repo:
        cfg = get_repo(p4, args.repo)
    else:
        cfg = get_global(p4)
    if not cfg:
        print(_('Unable to read configuration file!'))
    cfg.write(sys.stdout)
Пример #10
0
def pacemaker(view_name, event):
    """
    As long as event flag is clear, update heartbeat of named lock.
    """
    # Running in a separate process, need to establish our own P4 connection
    # and set up a heartbeat-only lock to update the heartbeat of the lock
    # associated with the view.
    p4gf_proc.install_stack_dumper()
    LOG.getChild("pacemaker").debug("starting for lock {}".format(view_name))
    p4 = None
    try:
        p4 = p4gf_create_p4.create_p4(client=p4gf_util.get_object_client_name(), connect=False)
        lock = CounterLock(p4, view_name, heartbeat_only=True)
        while not event.is_set():
            with p4gf_create_p4.Connector(p4):
                lock.update_heartbeat()
            event.wait(HEART_RATE)
    # pylint: disable=W0703
    # Catching too general exception
    except Exception as e:
        LOG.getChild("pacemaker").error("error occurred: {}".format(str(e)))
    finally:
        LOG.getChild("pacemaker").debug("stopping for view {}".format(view_name))
        if p4:
            p4gf_create_p4.destroy(p4)
Пример #11
0
def _get_p4_charset():
    '''
    Retreive the value for P4CHARSET, or return 'utf8' if not set.
    '''
    p4 = p4gf_create_p4.create_p4(connect=False)
    charset = p4.env('P4CHARSET')
    if (not charset) or (charset == ''):
        charset = 'utf8'
    return charset
Пример #12
0
def _get_p4_charset():
    '''
    Retreive the value for P4CHARSET, or return 'utf8' if not set.
    '''
    p4 = p4gf_create_p4.create_p4(connect=False)
    charset = p4.env('P4CHARSET')
    if (not charset) or (charset == ''):
        charset = 'utf8'
    return charset
 def valid_charset(charset):
     '''Return True for a valid charset, False for an invalid charset'''
     p4 = p4gf_create_p4.create_p4(connect=False)
     try:
         # setting invalid charset will raise an exception from p4python
         p4.charset = charset
     except P4.P4Exception:
         return False
     return True
 def valid_charset(charset):
     '''Return True for a valid charset, False for an invalid charset'''
     p4 = p4gf_create_p4.create_p4(connect=False)
     try:
         # setting invalid charset will raise an exception from p4python
         p4.charset = charset
     except P4.P4Exception:
         return False
     return True
Пример #15
0
 def __make_p4(self, client=None, user=None, connect=True):
     """create a connection to the perforce server"""
     if not user:
         user = self.config.p4user
     if not client:
         client = self.config.p4client
     return create_p4(port=self.config.p4port,
                      user=user,
                      client=client,
                      connect=connect)
Пример #16
0
def create_context(view_name, view_lock):
    """Return a Context object that contains the connection details for use
    in communicating with the Perforce server."""
    cfg = Config()
    p4 = create_p4()
    cfg.p4port = p4.env('P4PORT')
    cfg.p4user = p4gf_const.P4GF_USER
    cfg.p4client = view_to_client_name(view_name)
    cfg.p4client_gf = p4gf_util.get_object_client_name()
    cfg.view_name = view_name
    ctx = Context(cfg)
    ctx.view_lock = view_lock  # None OK: can run without a lock.
    return ctx
Пример #17
0
 def __make_p4(self, client=None):
     """create a connection to the perforce server"""
     p4 = create_p4(port=self.config.p4port,
                    user=self.config.p4user)
     if client:
         p4.client = client
     else:
         p4.client = self.config.p4client
     try:
         p4.connect()
     except P4Exception as e:
         raise RuntimeError("Failed P4 connect: {}".format(str(e)))
     p4.exception_level = 1
     return p4
Пример #18
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
Пример #19
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
Пример #20
0
def p4_has_login(user):
    """Return login state for user."""
    login_p4 = p4gf_create_p4.create_p4(port=P4PORT, user=user, client=P4CLIENT)
    if not login_p4:
        raise RuntimeError(_("Failed to connect to P4."))
    try:
        login = login_p4.run('login', '-s')[0]
        if 'TicketExpiration' in login:
            login = LOGIN_HAS_TICKET
        else:
            login = LOGIN_NO_PASSWD
    except P4Exception as e:
        if 'Perforce password (P4PASSWD) invalid or unset.' in str(e) or \
           'Your session was logged out, please login again.' in str(e) or \
           'Your session has expired, please login again.' in str(e):
            login = LOGIN_NEEDS_TICKET
        else:
            emsg = _("Failed to check login status for user={0}\n{1}").format(user, str(e))
            raise RuntimeError(emsg)

    p4gf_create_p4.p4_disconnect(login_p4)
    return login
Пример #21
0
def _wsgi_app(environ, start_response):
    """
    WSGI application to process the incoming Git client request. This is
    nearly equivalent to p4gf_auth_server.main() with the exception of
    input validation and error handling.
    """
    p4gf_log.record_http(environ)
    p4gf_version.log_version()
    _log_environ(environ)
    p4gf_version.version_check()
    LOG.debug("processing HTTP request, pid={}".format(os.getpid()))
    # Keep the content type to exactly 'text/plain' so there is at least
    # the remote chance that Git might show our error messages (does not
    # appear to work in practice, however).
    headers = [('Content-Type', 'text/plain')]

    encoding = sys.getfilesystemencoding()
    if encoding == 'ascii':
        # This encoding is wrong and will eventually lead to problems.
        LOG.error(
            "Using 'ascii' file encoding will ultimately result in errors, "
            "please set LANG/LC_ALL to 'utf-8' in web server configuration.")
        start_response(_('500 Internal Server Error'), headers)
        return [b"Filesystem encoding not set to acceptable value.\n"]

    # Sanity check the request.
    for (name, status, msg) in _REQUIRED_HTTP_PARAMS:
        if name not in environ:
            start_response(status, headers)
            return [msg.encode('UTF-8')]

    input_name = environ['wsgi.input']
    # Extract the view_name_git by removing the expected git request suffixes
    path_info = environ['PATH_INFO']
    git_suffixes = [
        '/info/refs', '/HEAD', '/git-upload-pack', '/git-receive-pack'
    ]
    path_end = len(path_info)
    for suffix in git_suffixes:
        try:
            path_end = path_info.index(suffix)
            break
        except ValueError:
            pass
    # slice away the leading slash and the trailing git request suffixes
    view_name_git = path_info[1:path_end]
    # and remove the view_name_git from the front of PATH_INFO
    environ['PATH_INFO'] = path_info[path_end:]
    LOG.debug("new PATH_INFO {0} view_name_git {1}".format(
        environ['PATH_INFO'], view_name_git))

    if not view_name_git:
        start_response(_('400 Bad Request'), headers)
        msg = _('Missing required repository name in URL\n')
        return [msg.encode('UTF-8')]
    # translate '/' ':' ' ' .. etc .. for internal view_name
    view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git)
    LOG.debug("public view_name: {0}   internal view_name: {1}".format(
        view_name_git, view_name))

    audit_logger = p4gf_server_common.ExceptionAuditLogger()
    p4_closer = p4gf_create_p4.Closer()
    sink = OutputSink()
    temp_deleter = deleting(input_name)
    mirror_closer = unmirror(view_name)
    with audit_logger   \
        , p4_closer     \
        , sink          \
        , temp_deleter  \
        , mirror_closer:
        LOG.debug(p4gf_log.memory_usage())
        start_time = time.time()

        p4gf_util.reset_git_enviro()
        p4 = p4gf_create_p4.create_p4()
        if not p4:
            start_response(_('500 Internal Server Error'), headers)
            return [b"Perforce connection failed\n"]
        LOG.debug("connected to P4: %s", p4)

        p4gf_server_common.check_readiness(p4)
        p4gf_server_common.check_lock_perm(p4)
        if not p4gf_server_common.check_protects(p4):
            p4gf_server_common.raise_p4gf_perm()

        user = environ['REMOTE_USER']
        if p4gf_server_common.run_special_command(view_name, p4, user):
            start_response(_('200 OK'), headers)
            return [sink.readall()]
        command = _get_command(environ)
        if not command:
            start_response(_('400 Bad Request'), headers)
            return [b"Unrecognized service\n"]
        # Other places in the Perforce-to-Git phase will need to know the
        # name of client user, so set that here. As for Git-to-Perforce,
        # that is handled later by setting the REMOTE_USER envar. Notice
        # also that we're setting os.environ and not 'environ'.
        os.environ[p4gf_const.P4GF_AUTH_P4USER] = user
        # Likewise, some code needs a hint that the request is coming over
        # one protocol (HTTP) or the other (SSH).
        os.environ['REMOTE_ADDR'] = environ['REMOTE_ADDR']

        # Initialize the external process launcher early, before allocating lots
        # of memory, and just after all other conditions have been checked.
        p4gf_proc.init()
        # Prepare for possible spawn of GitMirror worker process by forking
        # now before allocating lots of memory.
        p4gf_gitmirror.setup_spawn(view_name)
        # Kick off garbage collection debugging, if enabled.
        p4gf_gc.init_gc()

        # Go no further, create NOTHING, if user not authorized.
        # We use the translated internal view name here for perm authorization
        required_perm = p4gf_server_common.COMMAND_TO_PERM[command]
        view_perm = p4gf_group.ViewPerm.for_user_and_view(
            p4, user, view_name, required_perm)
        try:
            p4gf_server_common.check_authorization(p4, view_perm, user,
                                                   command, view_name)
        except p4gf_server_common.CommandError as ce:
            start_response(_('403 Forbidden'), headers)
            return [str(ce).encode('UTF-8')]

        # Create Git Fusion server depot, user, config. NOPs if already created.
        p4gf_init.init(p4)

        before_lock_time = time.time()
        with p4gf_lock.view_lock(p4, view_name) as view_lock:
            after_lock_time = time.time()

            # Create Git Fusion per-repo client view mapping and config.
            init_repo_status = p4gf_init_repo.init_repo(
                p4, view_name, view_lock)
            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
            elif init_repo_status == p4gf_init_repo.INIT_REPO_NOVIEW:
                start_response(_('404 Not Found'), headers)
                return [sink.readall()]
            else:
                start_response(_('500 Internal Server Error'), headers)
                return [b"Repository initialization failed\n"]

            # 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.
            if view_perm:
                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.
            with p4gf_context.create_context(view_name, view_lock) as ctx:
                LOG.debug("reconnected to P4, p4gf=%s", ctx.p4gf)
                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)

                # Only copy from Perforce to Git if no other process is cloning
                # from this Git repo right now.
                shared_in_progress = p4gf_lock.shared_host_view_lock_exists(
                    ctx.p4, view_name)
                if not shared_in_progress:
                    # Copy any recent changes from Perforce to Git.
                    try:
                        LOG.debug(
                            "bare: No git-upload-pack in progress, force non-bare"
                            " before update Git from Perforce.")
                        p4gf_git.set_bare(False)
                        p4gf_copy_p2g.copy_p2g_ctx(ctx)
                        p4gf_init_repo.process_imports(ctx)

                        # Now is also an appropriate time to clear out any stale Git
                        # Swarm reviews. We're pre-pull, pre-push, time when we've
                        # got exclusive write access to the Git repo,
                        GSReviewCollection.delete_refs_for_closed_reviews(ctx)

                    except p4gf_lock.LockCanceled as lc:
                        LOG.warning(str(lc))
                    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)
                            p4gf_server_common.cleanup_client(ctx, view_name)
                        raise

                try:
                    exclusive = 'upload' not in command
                    is_push = 'upload' not in command
                    git_caller = functools.partial(_call_git, input_name,
                                                   environ, ctx)
                    p4gf_call_git.call_git(git_caller, ctx, view_name,
                                           view_lock, exclusive)
                    if is_push:
                        GSReviewCollection.post_push(ctx)
                except p4gf_atomic_lock.LockConflict as lc:
                    start_response(_('500 Internal Server Error'), headers)
                    return ["{}".format(lc).encode('UTF-8')]

        p4gf_gc.process_garbage('at end of auth_server')
        if LOG.isEnabledFor(logging.DEBUG):
            end_time = time.time()
            frm = NTR(
                'Runtime: preparation {} ms, lock acquisition {} ms, processing {} ms'
            )
            LOG.debug(
                frm.format(before_lock_time - start_time,
                           after_lock_time - before_lock_time,
                           end_time - after_lock_time))
        return []
Пример #22
0
def main(poll_only=False):
    """set up repo for a view
       view_name_git    is the untranslated repo name
       view_name        is the translated repo name
    """
    p4gf_proc.install_stack_dumper()
    _log_environ(os.environ)
    with p4gf_server_common.ExceptionAuditLogger()\
    , p4gf_create_p4.Closer():
        LOG.debug(p4gf_log.memory_usage())
        start_time = time.time()
        args = parse_args(sys.argv[1:])
        if not args:
            return 1

        is_push = 'upload' not in args.command[0]

        # 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] = args.user

        # view_name_git    is the untranslated repo name
        # view_name        is the translated repo name

        # print "args={}".format(args)
        view_name_git = args.options[-1]
        # translate '/' ':' ' '  .. etc .. for internal view_name
        view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git)
        LOG.debug("public view_name: {0}   internal view_name: {1}".
                format(view_name_git, view_name))


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

        p4gf_server_common.check_readiness(p4)

        p4gf_server_common.check_lock_perm(p4)

        if not p4gf_server_common.check_protects(p4):
            p4gf_server_common.raise_p4gf_perm()

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

        # Initialize the external process launcher early, before allocating lots
        # of memory, and just after all other conditions have been checked.
        p4gf_proc.init()
        # Prepare for possible spawn of GitMirror worker process by forking
        # now before allocating lots of memory.
        p4gf_gitmirror.setup_spawn(view_name)
        # Kick off garbage collection debugging, if enabled.
        p4gf_gc.init_gc()

        if poll_only:
            view_perm = None
        else:
            # Go no further, create NOTHING, if user not authorized.
            # We use the translated internal view name here for perm authorization
            required_perm = p4gf_server_common.COMMAND_TO_PERM[args.command[0]]
            view_perm = p4gf_group.ViewPerm.for_user_and_view(p4, args.user,
                        view_name, required_perm)
            p4gf_server_common.check_authorization(p4, view_perm, args.user, args.command[0],
                                                   view_name)

        # Create Git Fusion server depot, user, config. NOPs if already created.
        p4gf_init.init(p4)

        write_motd()

        # view_name is the internal view_name (identical when notExist special chars)
        before_lock_time = time.time()
        with p4gf_lock.view_lock(p4, view_name) as view_lock:
            after_lock_time = time.time()

            # 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, view_lock)
            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.
            if view_perm:
                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.
            with p4gf_context.create_context(view_name, view_lock) as ctx:
                LOG.debug("reconnected to P4, p4gf=%s", ctx.p4gf)

                # Find directory paths to feed to git.
                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)

                # Only copy from Perforce to Git if no other process is cloning
                # from this Git repo right now.
                shared_in_progress = p4gf_lock.shared_host_view_lock_exists(ctx.p4, view_name)
                if not shared_in_progress:
                    # Copy any recent changes from Perforce to Git.
                    try:
                        LOG.debug("bare: No git-upload-pack in progress, force non-bare"
                                  " before update Git from Perforce.")
                        p4gf_git.set_bare(False)
                        p4gf_copy_p2g.copy_p2g_ctx(ctx)
                        p4gf_init_repo.process_imports(ctx)

                        # Now is also an appropriate time to clear out any stale Git
                        # Swarm reviews. We're pre-pull, pre-push, time when we've
                        # got exclusive write access to the Git repo,
                        GSReviewCollection.delete_refs_for_closed_reviews(ctx)

                    except p4gf_lock.LockCanceled as lc:
                        LOG.warning(str(lc))
                    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)
                            p4gf_server_common.cleanup_client(ctx, view_name)
                        raise

                if poll_only:
                    code = os.EX_OK
                else:

                    git_caller = functools.partial(_call_git, args, ctx)
                    try:

                        # Deep in call_git(), we grab an 'p4 reviews' lock on
                        # ctx.clientmap's LHS. Switch that clientmap to our
                        # full union view to prevent simultaneous 'git push'es
                        # from clobbering each other in some shared depot
                        # branch. Must include all lightweight branches, too.
                        ctx.switch_client_view_to_union()

                        exclusive = 'upload' not in args.command[0]
                        code = p4gf_call_git.call_git(
                                git_caller, ctx, view_name, view_lock, exclusive)
                        if is_push:
                            GSReviewCollection.post_push(ctx)
                    except p4gf_atomic_lock.LockConflict as lc:
                        sys.stderr.write("{}\n".format(lc))
                        code = os.EX_SOFTWARE

            p4gf_gc.process_garbage(NTR('at end of auth_server'))
            if LOG.isEnabledFor(logging.DEBUG):
                end_time = time.time()
                frm = NTR("Runtime: preparation {} ms, lock acquisition {} ms,"
                          " processing {} ms")
                LOG.debug(frm.format(before_lock_time - start_time,
                                    after_lock_time - before_lock_time,
                                    end_time - after_lock_time))
        return code
Пример #23
0
def main():
    """set up repo for a view"""
    p4gf_util.has_server_id_or_exit()
    args = _parse_argv()
    p4gf_version.log_version()
    log_l10n()
    # !!! view_name_git    the untranslated repo name
    # !!! view_name        the translated repo name
    view_name_p4client = None
    if args.p4client:
        view_name_p4client = p4gf_util.argv_to_view_name(args.p4client)
    view_name_git = p4gf_util.argv_to_view_name(args.view)
    #strip leading '/' to conform with p4gf_auth_server behavior
    if view_name_git[0] == '/':
        view_name_git = view_name_git[1:]
    view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git)
    p4gf_gitmirror.setup_spawn(view_name)
    p4gf_util.reset_git_enviro()

    p4 = p4gf_create_p4.create_p4()
    if not p4:
        return INIT_REPO_NOVIEW

    LOG.debug("connected to P4 at %s", p4.port)
    p4gf_proc.init()
    try:
        with p4gf_create_p4.Closer():
            p4gf_version.version_check()

            with p4gf_lock.view_lock(p4, view_name) as view_lock:
                # Ensure we have a sane environment.
                p4gf_init.init(p4)

                # Now that we can trust that the git-fusion--p4 client exists,
                # switch to that. Change takes effect immediately, don't need to
                # re-run p4.connect().
                p4.client = p4gf_util.get_object_client_name()

                # If local config file specified, validate it and store in
                # Perforce now. Even if client exists (aka repo was already
                # inited), this is one way for an admin to modify an existing
                # repo's config.
                if args.config:
                    if not os.path.exists(args.config):
                        _print_stderr(
                            _("error: missing config file '{}'").format(
                                args.config))
                        return INIT_REPO_CONFIG_FILE_MISSING
                    with Validator.from_local_file(view_name, p4,
                                                   args.config) as validator:
                        if not validator.is_valid(args.enablemismatchedrhs):
                            return INIT_REPO_CONFIG_FILE_BAD
                    p4gf_config.create_file_repo_with_contents(
                        p4, view_name, args.config)

                elif args.charset and not Validator.valid_charset(
                        args.charset):
                    _print_stderr(
                        _("error: invalid charset: {}").format(args.charset))
                    return INIT_REPO_BAD_CHARSET

                # Initialize the repository if necessary.
                print(_("Initializing '{}'...").format(view_name))
                r = init_repo(p4, view_name, view_lock, args.charset,
                              args.enablemismatchedrhs, view_name_p4client)
                if r > INIT_REPO_OK:
                    return r
                print(_("Initialization complete."))

                # Write --enablemismatchedrhs to config file
                if args.enablemismatchedrhs:
                    config = p4gf_config.read_repo(p4, view_name)
                    config[p4gf_config.SECTION_REPO]\
                          [p4gf_config.KEY_ENABLE_MISMATCHED_RHS] = str(True)
                    p4gf_config.write_repo_if(p4, p4.fetch_client(), view_name,
                                              config)

                # Populate the repo from Perforce unless --noclone.
                if not args.noclone:
                    return populate_repo(view_name, view_lock, args.start)
    except P4.P4Exception as e:
        _print_stderr(_('Error occurred: {}').format(e))

    return INIT_REPO_EXISTS
Пример #24
0
def main():
    """Do the thing."""
    # pylint: disable=too-many-statements, too-many-branches
    try:
        log_l10n()
        parse_argv()
        global P4PORT, P4USER, P4CLIENT
        needs_exit = False
        if not P4PORT and "P4PORT" not in os.environ:
            Verbosity.report(
                Verbosity.INFO,
                _('P4PORT is neither set in the environment nor passed as an option.'))
            needs_exit = True
        if not P4USER and "P4USER" not in os.environ:
            Verbosity.report(
                Verbosity.INFO,
                _('P4USER is neither set in the environment nor passed as an option.'))
            needs_exit = True
        # Check that a pre-existing P4GF_ENV config file P4PORT conflicts with the --port option
        if p4gf_const.P4GF_ENV and not Create_P4GF_CONFIG and P4PORT:
            if P4PORT != os.environ['P4PORT']:
                Verbosity.report(
                    Verbosity.INFO,
                    _("conflicting P4PORT in args: {p4port} and "
                      "P4GF_ENV {env} : P4PORT = {env_p4port}. Stopping.")
                    .format(p4port=P4PORT,
                            env=p4gf_const.P4GF_ENV,
                            env_p4port=os.environ['P4PORT']))
                needs_exit = True
            else:
                Verbosity.report(
                    Verbosity.INFO,
                    _("P4PORT argument is identically configured in {0}. Proceeding.")
                    .format(p4gf_const.P4GF_ENV))
        if needs_exit:
            sys.exit(1)

        p4gf_version_3.version_check()
        # Connect.
        global p4
        if not P4USER:
            P4USER = os.environ['P4USER']
        # if needed, set a bogus client name so that the default to hostname will not be used.
        if "P4CLIENT" not in os.environ:
            P4CLIENT = 'GF-' + str(uuid.uuid4().hex).lower()[-10:]
            os.environ['P4CLIENT'] = P4CLIENT
        else:
            P4CLIENT = os.environ['P4CLIENT']
        p4 = p4gf_create_p4.create_p4(port=P4PORT, user=P4USER, client=P4CLIENT)
        if not p4:
            raise RuntimeError(_("Failed to connect to P4."))
        P4PORT = p4.port
        P4USER = p4.user
        check_and_create_default_p4gf_env_config()
        if SHOW_IDS:
            show_all_server_ids()
            sys.exit(0)
        Verbosity.report(Verbosity.INFO, "P4PORT : {}".format(p4.port))
        Verbosity.report(Verbosity.INFO, "P4USER : {}".format(p4.user))

        # Require that we have super permission.
        # Might as well keep the result in case we need to write a new protect
        # table later. Saves a 'p4 protect -o' trip to the server
        protect_lines = fetch_protect()

        if P4_PASSWD and p4_security_level() > 0 and not strong_passwd(P4_PASSWD):
            Verbosity.report(
                Verbosity.ERROR,
                _("This Perforce server requires a strong password: >= 8 characters and"))
            Verbosity.report(
                Verbosity.ERROR,
                _("with mixed case or contain non alphabetic characters."))
            sys.exit(1)

        ensure_server_id()
        ensure_group()
        ensure_users()
        ensure_depot()
        ensure_protect(protect_lines)
        ensure_protects_configurable()
        set_proxy_protects_key()
        check_triggers()
        initialize_all_gf_reviews()

    except Exception as e:  # pylint: disable=broad-except
        sys.stderr.write(str(e) + '\n')
        p4gf_create_p4.close_all()
        sys.exit(1)
Пример #25
0
def main(poll_only=False):
    """set up repo for a view
       view_name_git    is the untranslated repo name
       view_name        is the translated repo name
    """
    p4gf_proc.install_stack_dumper()
    _log_environ(os.environ)
    with p4gf_server_common.ExceptionAuditLogger()\
    , p4gf_create_p4.Closer():
        LOG.debug(p4gf_log.memory_usage())
        start_time = time.time()
        args = parse_args(sys.argv[1:])
        if not args:
            return 1

        is_push = 'upload' not in args.command[0]

        # 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] = args.user

        # view_name_git    is the untranslated repo name
        # view_name        is the translated repo name

        # print "args={}".format(args)
        view_name_git = args.options[-1]
        # translate '/' ':' ' '  .. etc .. for internal view_name
        view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git)
        LOG.debug("public view_name: {0}   internal view_name: {1}".format(
            view_name_git, view_name))

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

        p4gf_server_common.check_readiness(p4)

        p4gf_server_common.check_lock_perm(p4)

        if not p4gf_server_common.check_protects(p4):
            p4gf_server_common.raise_p4gf_perm()

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

        # Initialize the external process launcher early, before allocating lots
        # of memory, and just after all other conditions have been checked.
        p4gf_proc.init()
        # Prepare for possible spawn of GitMirror worker process by forking
        # now before allocating lots of memory.
        p4gf_gitmirror.setup_spawn(view_name)
        # Kick off garbage collection debugging, if enabled.
        p4gf_gc.init_gc()

        if poll_only:
            view_perm = None
        else:
            # Go no further, create NOTHING, if user not authorized.
            # We use the translated internal view name here for perm authorization
            required_perm = p4gf_server_common.COMMAND_TO_PERM[args.command[0]]
            view_perm = p4gf_group.ViewPerm.for_user_and_view(
                p4, args.user, view_name, required_perm)
            p4gf_server_common.check_authorization(p4, view_perm, args.user,
                                                   args.command[0], view_name)

        # Create Git Fusion server depot, user, config. NOPs if already created.
        p4gf_init.init(p4)

        write_motd()

        # view_name is the internal view_name (identical when notExist special chars)
        before_lock_time = time.time()
        with p4gf_lock.view_lock(p4, view_name) as view_lock:
            after_lock_time = time.time()

            # 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, view_lock)
            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.
            if view_perm:
                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.
            with p4gf_context.create_context(view_name, view_lock) as ctx:
                LOG.debug("reconnected to P4, p4gf=%s", ctx.p4gf)

                # Find directory paths to feed to git.
                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)

                # Only copy from Perforce to Git if no other process is cloning
                # from this Git repo right now.
                shared_in_progress = p4gf_lock.shared_host_view_lock_exists(
                    ctx.p4, view_name)
                if not shared_in_progress:
                    # Copy any recent changes from Perforce to Git.
                    try:
                        LOG.debug(
                            "bare: No git-upload-pack in progress, force non-bare"
                            " before update Git from Perforce.")
                        p4gf_git.set_bare(False)
                        p4gf_copy_p2g.copy_p2g_ctx(ctx)
                        p4gf_init_repo.process_imports(ctx)

                        # Now is also an appropriate time to clear out any stale Git
                        # Swarm reviews. We're pre-pull, pre-push, time when we've
                        # got exclusive write access to the Git repo,
                        GSReviewCollection.delete_refs_for_closed_reviews(ctx)

                    except p4gf_lock.LockCanceled as lc:
                        LOG.warning(str(lc))
                    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)
                            p4gf_server_common.cleanup_client(ctx, view_name)
                        raise

                if poll_only:
                    code = os.EX_OK
                else:

                    git_caller = functools.partial(_call_git, args, ctx)
                    try:

                        # Deep in call_git(), we grab an 'p4 reviews' lock on
                        # ctx.clientmap's LHS. Switch that clientmap to our
                        # full union view to prevent simultaneous 'git push'es
                        # from clobbering each other in some shared depot
                        # branch. Must include all lightweight branches, too.
                        ctx.switch_client_view_to_union()

                        exclusive = 'upload' not in args.command[0]
                        code = p4gf_call_git.call_git(git_caller, ctx,
                                                      view_name, view_lock,
                                                      exclusive)
                        if is_push:
                            GSReviewCollection.post_push(ctx)
                    except p4gf_atomic_lock.LockConflict as lc:
                        sys.stderr.write("{}\n".format(lc))
                        code = os.EX_SOFTWARE

            p4gf_gc.process_garbage(NTR('at end of auth_server'))
            if LOG.isEnabledFor(logging.DEBUG):
                end_time = time.time()
                frm = NTR("Runtime: preparation {} ms, lock acquisition {} ms,"
                          " processing {} ms")
                LOG.debug(
                    frm.format(before_lock_time - start_time,
                               after_lock_time - before_lock_time,
                               end_time - after_lock_time))
        return code
def main():
    """Copy incoming Git commits to Perforce changelists."""
    _log_environ(os.environ)
    log_l10n()
    LOG.debug("main() running, pid={}".format(os.getpid()))
    p4gf_proc.install_stack_dumper()
    for h in ['-?', '-h', '--help']:
        if h in sys.argv:
            print(_('Git Fusion pre-receive hook.'))
            return 2
    with p4gf_create_p4.Closer():
        p4gf_version.print_and_exit_if_argv()
        p4 = p4gf_create_p4.create_p4()
        if not p4:
            return 2
        p4gf_util.reset_git_enviro(p4)

        view_name = p4gf_util.cwd_to_view_name()
        view_lock = p4gf_lock.view_lock_heartbeat_only(p4, view_name)
        with p4gf_context.create_context(view_name, view_lock) as ctx:

            # this script is called by git while a context and temp clients
            # are already in use.  Don't sabotage that context by deleting
            # the temp clients from here.
            ctx.cleanup_client_pool = False

            # Read each input line (usually only one unless pushing multiple branches)
            # and convert to a list of "tuples" from which we can assign branches.
            prl = []
            delete_prl = []
            while True:
                line = sys.stdin.readline()
                if not line:
                    break
                LOG.debug('main() raw pre-receive-tuple: {}'.format(line))
                prt = PreReceiveTuple.from_line(line)
                if int(prt.new_sha1, 16) == 0:
                    delete_prl.append(prt)
                else:
                    prl.append(prt)

            # Initialize the external process launcher early, before allocating lots
            # of memory, and just after all other conditions have been checked.
            p4gf_proc.init()
            # Prepare for possible spawn of GitMirror worker process by forking
            # now before allocating lots of memory.
            p4gf_gitmirror.setup_spawn(view_name)
            # Kick off garbage collection debugging, if enabled.
            p4gf_gc.init_gc()

            # Reject attempt to delete any fully populated branch defined in
            # p4gf_config. Git Fusion never edits p4gf_config, so Git Fusion never
            # deletes fully populated branches. Edit p4gf_config yourself if you
            # want to remove a branch from history.
            for prt in delete_prl:
                git_branch_name = prt.git_branch_name()
                if not git_branch_name:
                    continue
                branch = ctx.git_branch_name_to_branch(git_branch_name)
                if not branch:
                    LOG.debug('attempt to delete branch {} which does not exist'
                              .format(git_branch_name))
                    break
                if not branch.is_lightweight:
                    raise RuntimeError(_('Cannot delete branches defined in'
                                         ' Git Fusion repo config file: {}')
                                       .format(git_branch_name))

            # Swarm review creates new Git merge commits. Must occur before branch
            # assignment so that the review reference can be moved to the new merge
            # commit.
            gsreview_coll = GSReviewCollection.from_prl(ctx, prl)
            if gsreview_coll:
                gsreview_coll.pre_copy_to_p4(prl)

            # Assign branches to each of the received commits for pushed branches  - skip deletes.
            if prl:
                assigner = Assigner(ctx.branch_dict(), prl, ctx)
                assigner.assign()

            # For each of the heads being pushed, copy their commits to Perforce.
            if prl:
                try:
                    err = _copy( ctx
                               , prl           = prl
                               , assigner      = assigner
                               , gsreview_coll = gsreview_coll)   # branch push
                    if err:
                        return _clean_exit(err)
                except RuntimeError as err:
                    # Log the error. The return call below eats the error and stack trace.
                    LOG.exception(NTR("_copy() raised exception."))
                    return _clean_exit(err)
            # For each of the heads being deleted, remove the branch definition from p4gf_config2
            if delete_prl:
                p4gf_call_git.prohibit_interrupt(view_name, os.getpid())
                try:
                    err = _delete(ctx, delete_prl)     # branch delete
                    if err:
                        return _clean_exit(err)
                except RuntimeError as err:
                    # Log the error. The return call below eats the error and stack trace.
                    LOG.exception(NTR("_delete() raised exception."))
                    return _clean_exit(err)
            # Process all of the tags at once.
            err = p4gf_tag.process_tags(ctx, prl + delete_prl)
            if err:
                return _clean_exit(err)

                            # If we have any new Git Swarm review references that
                            # auth/http_server must rename, send a list of such
                            # references across process boundary, via a file.
            if gsreview_coll:
                gsreview_coll.to_file()

            p4gf_gc.process_garbage("at end of pre_receive_hook")
            p4gf_gc.report_objects(NTR("at end of pre_receive_hook"))

        return 0
Пример #27
0
def main():
    """Do the thing."""
    try:
        log_l10n()
        parse_argv()
        global P4PORT, P4USER
        needs_exit = False
        if not P4PORT and "P4PORT" not in os.environ:
            Verbosity.report(
                Verbosity.INFO,
                'P4PORT is neither set in the environment nor passed as an option.'
            )
            needs_exit = True
        if not P4USER and "P4USER" not in os.environ:
            Verbosity.report(
                Verbosity.INFO,
                'P4USER is neither set in the environment nor passed as an option.'
            )
            needs_exit = True
        # Check that a pre-existing P4GF_ENV config file P4PORT conflicts with the --port option
        if p4gf_const.P4GF_ENV and not Create_P4GF_CONFIG and P4PORT:
            if P4PORT != os.environ['P4PORT']:
                Verbosity.report(
                    Verbosity.INFO,
                    "conflicting P4PORT in args: {0} and P4GF_ENV {1} : P4PORT = {2}. Stopping."
                    .format(P4PORT, p4gf_const.P4GF_ENV, os.environ['P4PORT']))
                needs_exit = True
            else:
                Verbosity.report(
                    Verbosity.INFO,
                    "P4PORT argument is identically configured in {0}. Proceeding."
                    .format(p4gf_const.P4GF_ENV))
        if needs_exit:
            sys.exit(1)

        p4gf_version.version_check()
        # Connect.
        global p4
        if not P4USER:
            P4USER = os.environ['P4USER']
        p4 = p4gf_create_p4.create_p4(port=P4PORT, user=P4USER)
        if not p4:
            raise RuntimeError(_("Failed to connect to P4."))
        P4PORT = p4.port
        P4USER = p4.user
        check_and_create_default_p4gf_env_config()
        if SHOW_IDS:
            show_all_server_ids()
            sys.exit(0)
        Verbosity.report(Verbosity.INFO, "P4PORT : {}".format(p4.port))
        Verbosity.report(Verbosity.INFO, "P4USER : {}".format(p4.user))
        _ensure_case_sensitive()

        # Require that we have super permission.
        # Might as well keep the result in case we need to write a new protect
        # table later. Saves a 'p4 protect -o' trip to the server
        protect_lines = fetch_protect()

        ensure_server_id()
        ensure_users()
        ensure_group()
        ensure_depot()
        ensure_protect(protect_lines)
        ensure_protects_configurable()
        check_triggers()
        initialize_all_gf_reviews()

    # pylint: disable=W0703
    # Catching too general exception
    except Exception as e:
        sys.stderr.write(str(e) + '\n')
        p4gf_create_p4.close_all()
        sys.exit(1)
def main():
    """Copy incoming Git commits to Perforce changelists."""
    _log_environ(os.environ)
    log_l10n()
    LOG.debug("main() running, pid={}".format(os.getpid()))
    p4gf_proc.install_stack_dumper()
    for h in ['-?', '-h', '--help']:
        if h in sys.argv:
            print(_('Git Fusion pre-receive hook.'))
            return 2
    with p4gf_create_p4.Closer():
        p4gf_version.print_and_exit_if_argv()
        p4 = p4gf_create_p4.create_p4()
        if not p4:
            return 2
        p4gf_util.reset_git_enviro(p4)

        view_name = p4gf_util.cwd_to_view_name()
        view_lock = p4gf_lock.view_lock_heartbeat_only(p4, view_name)
        with p4gf_context.create_context(view_name, view_lock) as ctx:

            # this script is called by git while a context and temp clients
            # are already in use.  Don't sabotage that context by deleting
            # the temp clients from here.
            ctx.cleanup_client_pool = False

            # Read each input line (usually only one unless pushing multiple branches)
            # and convert to a list of "tuples" from which we can assign branches.
            prl = []
            delete_prl = []
            while True:
                line = sys.stdin.readline()
                if not line:
                    break
                LOG.debug('main() raw pre-receive-tuple: {}'.format(line))
                prt = PreReceiveTuple.from_line(line)
                if int(prt.new_sha1, 16) == 0:
                    delete_prl.append(prt)
                else:
                    prl.append(prt)

            # Initialize the external process launcher early, before allocating lots
            # of memory, and just after all other conditions have been checked.
            p4gf_proc.init()
            # Prepare for possible spawn of GitMirror worker process by forking
            # now before allocating lots of memory.
            p4gf_gitmirror.setup_spawn(view_name)
            # Kick off garbage collection debugging, if enabled.
            p4gf_gc.init_gc()

            # Reject attempt to delete any fully populated branch defined in
            # p4gf_config. Git Fusion never edits p4gf_config, so Git Fusion never
            # deletes fully populated branches. Edit p4gf_config yourself if you
            # want to remove a branch from history.
            for prt in delete_prl:
                git_branch_name = prt.git_branch_name()
                if not git_branch_name:
                    continue
                branch = ctx.git_branch_name_to_branch(git_branch_name)
                if not branch:
                    LOG.debug(
                        'attempt to delete branch {} which does not exist'.
                        format(git_branch_name))
                    break
                if not branch.is_lightweight:
                    raise RuntimeError(
                        _('Cannot delete branches defined in'
                          ' Git Fusion repo config file: {}').format(
                              git_branch_name))

            # Swarm review creates new Git merge commits. Must occur before branch
            # assignment so that the review reference can be moved to the new merge
            # commit.
            gsreview_coll = GSReviewCollection.from_prl(ctx, prl)
            if gsreview_coll:
                gsreview_coll.pre_copy_to_p4(prl)

            # Assign branches to each of the received commits for pushed branches  - skip deletes.
            if prl:
                assigner = Assigner(ctx.branch_dict(), prl, ctx)
                assigner.assign()

            # For each of the heads being pushed, copy their commits to Perforce.
            if prl:
                try:
                    err = _copy(ctx,
                                prl=prl,
                                assigner=assigner,
                                gsreview_coll=gsreview_coll)  # branch push
                    if err:
                        return _clean_exit(err)
                except RuntimeError as err:
                    # Log the error. The return call below eats the error and stack trace.
                    LOG.exception(NTR("_copy() raised exception."))
                    return _clean_exit(err)
            # For each of the heads being deleted, remove the branch definition from p4gf_config2
            if delete_prl:
                p4gf_call_git.prohibit_interrupt(view_name, os.getpid())
                try:
                    err = _delete(ctx, delete_prl)  # branch delete
                    if err:
                        return _clean_exit(err)
                except RuntimeError as err:
                    # Log the error. The return call below eats the error and stack trace.
                    LOG.exception(NTR("_delete() raised exception."))
                    return _clean_exit(err)
            # Process all of the tags at once.
            err = p4gf_tag.process_tags(ctx, prl + delete_prl)
            if err:
                return _clean_exit(err)

                # If we have any new Git Swarm review references that
                # auth/http_server must rename, send a list of such
                # references across process boundary, via a file.
            if gsreview_coll:
                gsreview_coll.to_file()

            p4gf_gc.process_garbage("at end of pre_receive_hook")
            p4gf_gc.report_objects(NTR("at end of pre_receive_hook"))

        return 0
Пример #29
0
def main():
    """
    Process command line arguments and call functions to do the real
    work of cleaning up the Git mirror and Perforce workspaces.
    """
    log_l10n()
    p4gf_util.has_server_id_or_exit()

                        # pylint:disable=C0301
                        # Line too long? Too bad. Keep tabular code tabular.
    # Set up argument parsing.
    parser = p4gf_util.create_arg_parser(
        _('Deletes Git Fusion repositories and workspaces.'))
    parser.add_argument('-a',   '--all',            action='store_true',    help=_('remove all known Git mirrors'))
    parser.add_argument('-y',   '--delete',         action='store_true',    help=_('perform the deletion'))
    parser.add_argument('-v',   '--verbose',        action='store_true',    help=_('print details of deletion process'))
    parser.add_argument('-N',   '--no-obliterate',  action='store_true',    help=_('with the --all option, do not obliterate object cache'))
    parser.add_argument(NTR('views'), metavar=NTR('view'), nargs='*',       help=_('name of view to be deleted'))
    args = parser.parse_args()
                        # pylint:enable=C0301

    # Check that either --all, or 'views' was specified.
    if not args.all and len(args.views) == 0:
        sys.stderr.write(_('Missing view names; try adding --all option.\n'))
        sys.exit(2)

    # Check that --no-obliterate occurs only with --all
    if not args.all and args.no_obliterate:
        sys.stderr.write(_('--no-obliterate permitted only with the --all option.\n'))
        sys.exit(2)

    with p4gf_create_p4.Closer():
        p4 = p4gf_create_p4.create_p4(client=p4gf_util.get_object_client_name())
        if not p4:
            return 2
        # Sanity check the connection (e.g. user logged in?) before proceeding.
        try:
            p4.fetch_client()
        except P4.P4Exception as e:
            sys.stderr.write(_('P4 exception occurred: {}').format(e))
            sys.exit(1)

        metrics = DeletionMetrics()
        if args.all:
            try:
                delete_all(args, p4, metrics)
            except P4.P4Exception as e:
                sys.stderr.write("{}\n".format(e))
                sys.exit(1)
        else:
            # Delete the client(s) for the named view(s).
            for git_view in args.views:
                view_name = p4gf_translate.TranslateReponame.git_to_repo(git_view)
                client_name = p4gf_util.view_to_client_name(view_name)
                try:
                    with p4gf_lock.view_lock(p4, view_name, -1):
                        delete_client(args, p4, client_name, metrics)
                except P4.P4Exception as e:
                    sys.stderr.write("{}\n".format(e))
        if  not args.delete:
            print(_('This was report mode. Use -y to make changes.'))
        else:
            print(_('Deleted {:d} files, {:d} groups, {:d} clients, and {:d} counters.').format(
                metrics.files, metrics.groups, metrics.clients, metrics.counters))
            if args.all:
                print(_('Successfully deleted all repos\n'))
            else:
                print(_('Successfully deleted repos:\n{}').format("\n".join(args.views)))
Пример #30
0
def main():
    """
    Process command line arguments and call functions to do the real
    work of cleaning up the Git mirror and Perforce workspaces.
    """
    log_l10n()
    p4gf_util.has_server_id_or_exit()

    # pylint:disable=C0301
    # Line too long? Too bad. Keep tabular code tabular.
    # Set up argument parsing.
    parser = p4gf_util.create_arg_parser(
        _('Deletes Git Fusion repositories and workspaces.'))
    parser.add_argument('-a',
                        '--all',
                        action='store_true',
                        help=_('remove all known Git mirrors'))
    parser.add_argument('-y',
                        '--delete',
                        action='store_true',
                        help=_('perform the deletion'))
    parser.add_argument('-v',
                        '--verbose',
                        action='store_true',
                        help=_('print details of deletion process'))
    parser.add_argument(
        '-N',
        '--no-obliterate',
        action='store_true',
        help=_('with the --all option, do not obliterate object cache'))
    parser.add_argument(NTR('views'),
                        metavar=NTR('view'),
                        nargs='*',
                        help=_('name of view to be deleted'))
    args = parser.parse_args()
    # pylint:enable=C0301

    # Check that either --all, or 'views' was specified.
    if not args.all and len(args.views) == 0:
        sys.stderr.write(_('Missing view names; try adding --all option.\n'))
        sys.exit(2)

    # Check that --no-obliterate occurs only with --all
    if not args.all and args.no_obliterate:
        sys.stderr.write(
            _('--no-obliterate permitted only with the --all option.\n'))
        sys.exit(2)

    with p4gf_create_p4.Closer():
        p4 = p4gf_create_p4.create_p4(
            client=p4gf_util.get_object_client_name())
        if not p4:
            return 2
        # Sanity check the connection (e.g. user logged in?) before proceeding.
        try:
            p4.fetch_client()
        except P4.P4Exception as e:
            sys.stderr.write(_('P4 exception occurred: {}').format(e))
            sys.exit(1)

        metrics = DeletionMetrics()
        if args.all:
            try:
                delete_all(args, p4, metrics)
            except P4.P4Exception as e:
                sys.stderr.write("{}\n".format(e))
                sys.exit(1)
        else:
            # Delete the client(s) for the named view(s).
            for git_view in args.views:
                view_name = p4gf_translate.TranslateReponame.git_to_repo(
                    git_view)
                client_name = p4gf_util.view_to_client_name(view_name)
                try:
                    with p4gf_lock.view_lock(p4, view_name, -1):
                        delete_client(args, p4, client_name, metrics)
                except P4.P4Exception as e:
                    sys.stderr.write("{}\n".format(e))
        if not args.delete:
            print(_('This was report mode. Use -y to make changes.'))
        else:
            print(
                _('Deleted {:d} files, {:d} groups, {:d} clients, and {:d} counters.'
                  ).format(metrics.files, metrics.groups, metrics.clients,
                           metrics.counters))
            if args.all:
                print(_('Successfully deleted all repos\n'))
            else:
                print(
                    _('Successfully deleted repos:\n{}').format("\n".join(
                        args.views)))
Пример #31
0
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)
Пример #32
0
def main():
    """Process command line arguments and call functions to do the real
    work of cleaning up the Git mirror and Perforce workspaces.
    """
    # Set up argument parsing.
    parser = p4gf_util.create_arg_parser(
        "Convert 2012.2 Git Fusion configured Perforce Server for use with"
        " 2013.1 Git Fusion.\nThis is not reversable.")
    parser.add_argument("-y", "--convert", action="store_true",
                        help="perform the conversion")
    parser.add_argument("-d", "--delete", action="store_true",
                        help="skip obliterate and show delete command")
    parser.add_argument('--id',                              nargs=1,
            help="Set this Git Fusion server's unique id. Default is hostname.")
    args = parser.parse_args()

    # Do not run as root, this is very git account specific
    user = getpass.getuser()
    if user == "root":
        print("This script should be run using the Git dedicated account")
        return 2

    if args.convert:
        try:
            global LOG_FILE
                                # pylint:disable=W1501
                                # "x" is not a valid mode for open.
                                # Yes it is. Pylint 1.0.0 is incorrect here.
            LOG_FILE = open("p4gf_convert_v12_2.log", "x")
                                # pylint:enable=W1501
            print("Logging to p4gf_convert_v12_2.log")
        except IOError:
            print("Please remove or rename p4gf_convert_v12_2.log")
            sys.exit(1)

    client_name = p4gf_const.P4GF_OBJECT_CLIENT_PREFIX + p4gf_util.get_hostname()
    try:
        p4 = p4gf_create_p4.create_p4(client=client_name)
    except RuntimeError as e:
        sys.stderr.write("{}\n".format(e))
        sys.exit(1)
    if not p4:
        return 2

    # Sanity check the connection (e.g. user logged in?) before proceeding.
    try:
        p4.fetch_client()
        view = ['//{depot}/... //{client}/...'.format(
            depot=p4gf_const.P4GF_DEPOT, client=client_name)]
        spec = {'Host': '',
                'Root': os.path.join(os.environ.get("HOME"),
                p4gf_const.P4GF_DIR),
                'View': view}
        p4gf_util.ensure_spec_values(p4, 'client', client_name, spec)
    except P4.P4Exception as e:
        sys.stderr.write("P4 exception occurred: {}".format(e))
        sys.exit(1)

    try:
        convert(args, p4)
    except P4.P4Exception as e:
        sys.stderr.write("{}\n".format(e))
        sys.exit(1)

    if not args.convert:
        print("This was report mode. Use -y to make changes.")
    else:
        print("Commands run were logged to p4gf_convert_v12_2.log.")
        if args.delete:
            print("You must now run: p4 delete //.git-fusion/objects/...")
            print("                  p4 submit")
            print("    Use a client which has this location in its view")
            LOG_FILE.write("Need to run: p4 delete //.git-fusion/objects/...\n")
            LOG_FILE.write("             p4 submit\n")
        LOG_FILE.close()
Пример #33
0
def main():
    """Process command line arguments and call functions to do the real
    work of cleaning up the Git mirror and Perforce workspaces.
    """
    # Set up argument parsing.
    parser = p4gf_util.create_arg_parser(
        "Convert 2012.2 Git Fusion configured Perforce Server for use with"
        " 2013.1 Git Fusion.\nThis is not reversable.")
    parser.add_argument("-y",
                        "--convert",
                        action="store_true",
                        help="perform the conversion")
    parser.add_argument("-d",
                        "--delete",
                        action="store_true",
                        help="skip obliterate and show delete command")
    parser.add_argument(
        '--id',
        nargs=1,
        help="Set this Git Fusion server's unique id. Default is hostname.")
    args = parser.parse_args()

    # Do not run as root, this is very git account specific
    user = getpass.getuser()
    if user == "root":
        print("This script should be run using the Git dedicated account")
        return 2

    if args.convert:
        try:
            global LOG_FILE
            # pylint:disable=W1501
            # "x" is not a valid mode for open.
            # Yes it is. Pylint 1.0.0 is incorrect here.
            LOG_FILE = open("p4gf_convert_v12_2.log", "x")
            # pylint:enable=W1501
            print("Logging to p4gf_convert_v12_2.log")
        except IOError:
            print("Please remove or rename p4gf_convert_v12_2.log")
            sys.exit(1)

    client_name = p4gf_const.P4GF_OBJECT_CLIENT_PREFIX + p4gf_util.get_hostname(
    )
    try:
        p4 = p4gf_create_p4.create_p4(client=client_name)
    except RuntimeError as e:
        sys.stderr.write("{}\n".format(e))
        sys.exit(1)
    if not p4:
        return 2

    # Sanity check the connection (e.g. user logged in?) before proceeding.
    try:
        p4.fetch_client()
        view = [
            '//{depot}/... //{client}/...'.format(depot=p4gf_const.P4GF_DEPOT,
                                                  client=client_name)
        ]
        spec = {
            'Host': '',
            'Root': os.path.join(os.environ.get("HOME"), p4gf_const.P4GF_DIR),
            'View': view
        }
        p4gf_util.ensure_spec_values(p4, 'client', client_name, spec)
    except P4.P4Exception as e:
        sys.stderr.write("P4 exception occurred: {}".format(e))
        sys.exit(1)

    try:
        convert(args, p4)
    except P4.P4Exception as e:
        sys.stderr.write("{}\n".format(e))
        sys.exit(1)

    if not args.convert:
        print("This was report mode. Use -y to make changes.")
    else:
        print("Commands run were logged to p4gf_convert_v12_2.log.")
        if args.delete:
            print("You must now run: p4 delete //.git-fusion/objects/...")
            print("                  p4 submit")
            print("    Use a client which has this location in its view")
            LOG_FILE.write(
                "Need to run: p4 delete //.git-fusion/objects/...\n")
            LOG_FILE.write("             p4 submit\n")
        LOG_FILE.close()
Пример #34
0
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)
Пример #35
0
def main():
    """
    Copy the SSH keys from Perforce to the authorized keys file.
    """
    p4gf_util.has_server_id_or_exit()

    log_l10n()

    # Set up argument parsing.
    parser = p4gf_util.create_arg_parser(
        _("""Copies SSH public keys from
Perforce depot to current user's directory. This script assumes OpenSSH
is the SSH implementation in use, and as such, writes to 'authorized_keys'
in the ~/.ssh directory. If --ssh2 is used, then writes to 'authorization'
in the ~/.ssh2 directory, writing the SSH2 formatted public keys in the
'keys' directory under ~/.ssh2, using the Perforce user names to avoid
name collisions. If public keys read from the depot are the wrong format
(OpenSSH vs. SSH2), they will be converted when written to disk.
"""))
    parser.add_argument('-r',
                        '--rebuild',
                        action=NTR('store_true'),
                        help=_('rebuild keys file'))
    parser.add_argument('-v',
                        '--verbose',
                        action=NTR('store_true'),
                        help=_('print details of update process'))
    parser.add_argument('-2',
                        '--ssh2',
                        action=NTR('store_true'),
                        help=_("produce 'SSH2' output"))
    parser.add_argument('-f', '--file', help=_('path to authorized keys file'))
    args = parser.parse_args()

    # Since this script is called often (by cron), try to reduce the lines
    # that appear in the log by raising the log level for the p4gf_create_p4
    # module.
    logging.getLogger('p4gf_create_p4').setLevel('WARN')
    with p4gf_create_p4.Closer():
        p4 = p4gf_create_p4.create_p4(
            client=p4gf_util.get_object_client_name())
        if not p4:
            return 2
        # Sanity check the connection (e.g. user logged in?) before proceeding.
        try:
            p4.fetch_client()
        except P4Exception as e:
            _print_warn(_('P4 exception occurred: {}').format(e), error=True)
            sys.exit(1)

        # Update global settings based on command line arguments.
        global Verbose
        Verbose = args.verbose
        global Ssh2
        Ssh2 = args.ssh2
        global SshKeysFile
        SshKeysFile = args.file
        if not SshKeysFile:
            SshKeysFile = NTR('~/.ssh2/authorization') if Ssh2 else NTR(
                '~/.ssh/authorized_keys')
        if SshKeysFile[0] == '~':
            SshKeysFile = os.path.expanduser(SshKeysFile)
        global SshDirectory
        SshDirectory = os.path.dirname(SshKeysFile)

        # Update the keys file based either on latest changes or existing files.
        try:
            if args.rebuild:
                rebuild_all_keys(p4)
            else:
                update_by_changes(p4)
        except P4Exception as e:
            _print_warn(_('P4 exception occurred: {}').format(e), error=True)
Пример #36
0
def _wsgi_app(environ, start_response):
    """
    WSGI application to process the incoming Git client request. This is
    nearly equivalent to p4gf_auth_server.main() with the exception of
    input validation and error handling.
    """
    p4gf_log.record_http(environ)
    p4gf_version.log_version()
    _log_environ(environ)
    p4gf_version.version_check()
    LOG.debug("processing HTTP request, pid={}".format(os.getpid()))
    # Keep the content type to exactly 'text/plain' so there is at least
    # the remote chance that Git might show our error messages (does not
    # appear to work in practice, however).
    headers = [('Content-Type', 'text/plain')]

    encoding = sys.getfilesystemencoding()
    if encoding == 'ascii':
        # This encoding is wrong and will eventually lead to problems.
        LOG.error("Using 'ascii' file encoding will ultimately result in errors, "
            "please set LANG/LC_ALL to 'utf-8' in web server configuration.")
        start_response(_('500 Internal Server Error'), headers)
        return [b"Filesystem encoding not set to acceptable value.\n"]

    # Sanity check the request.
    for (name, status, msg) in _REQUIRED_HTTP_PARAMS:
        if name not in environ:
            start_response(status, headers)
            return [msg.encode('UTF-8')]

    input_name = environ['wsgi.input']
    # Extract the view_name_git by removing the expected git request suffixes
    path_info = environ['PATH_INFO']
    git_suffixes = ['/info/refs', '/HEAD', '/git-upload-pack', '/git-receive-pack']
    path_end = len(path_info)
    for suffix in git_suffixes:
        try:
            path_end = path_info.index(suffix)
            break
        except ValueError:
            pass
    # slice away the leading slash and the trailing git request suffixes
    view_name_git  = path_info[1:path_end]
    # and remove the view_name_git from the front of PATH_INFO
    environ['PATH_INFO'] = path_info[path_end:]
    LOG.debug("new PATH_INFO {0} view_name_git {1}".format(environ['PATH_INFO'], view_name_git))

    if not view_name_git:
        start_response(_('400 Bad Request'), headers)
        msg = _('Missing required repository name in URL\n')
        return [msg.encode('UTF-8')]
    # translate '/' ':' ' ' .. etc .. for internal view_name
    view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git)
    LOG.debug("public view_name: {0}   internal view_name: {1}".format(view_name_git, view_name))

    audit_logger = p4gf_server_common.ExceptionAuditLogger()
    p4_closer = p4gf_create_p4.Closer()
    sink = OutputSink()
    temp_deleter = deleting(input_name)
    mirror_closer = unmirror(view_name)
    with audit_logger   \
        , p4_closer     \
        , sink          \
        , temp_deleter  \
        , mirror_closer:
        LOG.debug(p4gf_log.memory_usage())
        start_time = time.time()

        p4gf_util.reset_git_enviro()
        p4 = p4gf_create_p4.create_p4()
        if not p4:
            start_response(_('500 Internal Server Error'), headers)
            return [b"Perforce connection failed\n"]
        LOG.debug("connected to P4: %s", p4)

        p4gf_server_common.check_readiness(p4)
        p4gf_server_common.check_lock_perm(p4)
        if not p4gf_server_common.check_protects(p4):
            p4gf_server_common.raise_p4gf_perm()

        user = environ['REMOTE_USER']
        if p4gf_server_common.run_special_command(view_name, p4, user):
            start_response(_('200 OK'), headers)
            return [sink.readall()]
        command = _get_command(environ)
        if not command:
            start_response(_('400 Bad Request'), headers)
            return [b"Unrecognized service\n"]
        # Other places in the Perforce-to-Git phase will need to know the
        # name of client user, so set that here. As for Git-to-Perforce,
        # that is handled later by setting the REMOTE_USER envar. Notice
        # also that we're setting os.environ and not 'environ'.
        os.environ[p4gf_const.P4GF_AUTH_P4USER] = user
        # Likewise, some code needs a hint that the request is coming over
        # one protocol (HTTP) or the other (SSH).
        os.environ['REMOTE_ADDR'] = environ['REMOTE_ADDR']

        # Initialize the external process launcher early, before allocating lots
        # of memory, and just after all other conditions have been checked.
        p4gf_proc.init()
        # Prepare for possible spawn of GitMirror worker process by forking
        # now before allocating lots of memory.
        p4gf_gitmirror.setup_spawn(view_name)
        # Kick off garbage collection debugging, if enabled.
        p4gf_gc.init_gc()

        # Go no further, create NOTHING, if user not authorized.
        # We use the translated internal view name here for perm authorization
        required_perm = p4gf_server_common.COMMAND_TO_PERM[command]
        view_perm = p4gf_group.ViewPerm.for_user_and_view(p4, user, view_name, required_perm)
        try:
            p4gf_server_common.check_authorization(p4, view_perm, user, command, view_name)
        except p4gf_server_common.CommandError as ce:
            start_response(_('403 Forbidden'), headers)
            return [str(ce).encode('UTF-8')]

        # Create Git Fusion server depot, user, config. NOPs if already created.
        p4gf_init.init(p4)

        before_lock_time = time.time()
        with p4gf_lock.view_lock(p4, view_name) as view_lock:
            after_lock_time = time.time()

            # Create Git Fusion per-repo client view mapping and config.
            init_repo_status = p4gf_init_repo.init_repo(p4, view_name, view_lock)
            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
            elif init_repo_status == p4gf_init_repo.INIT_REPO_NOVIEW:
                start_response(_('404 Not Found'), headers)
                return [sink.readall()]
            else:
                start_response(_('500 Internal Server Error'), headers)
                return [b"Repository initialization failed\n"]

            # 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.
            if view_perm:
                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.
            with p4gf_context.create_context(view_name, view_lock) as ctx:
                LOG.debug("reconnected to P4, p4gf=%s", ctx.p4gf)
                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)

                # Only copy from Perforce to Git if no other process is cloning
                # from this Git repo right now.
                shared_in_progress = p4gf_lock.shared_host_view_lock_exists(ctx.p4, view_name)
                if not shared_in_progress:
                    # Copy any recent changes from Perforce to Git.
                    try:
                        LOG.debug("bare: No git-upload-pack in progress, force non-bare"
                                  " before update Git from Perforce.")
                        p4gf_git.set_bare(False)
                        p4gf_copy_p2g.copy_p2g_ctx(ctx)
                        p4gf_init_repo.process_imports(ctx)

                        # Now is also an appropriate time to clear out any stale Git
                        # Swarm reviews. We're pre-pull, pre-push, time when we've
                        # got exclusive write access to the Git repo,
                        GSReviewCollection.delete_refs_for_closed_reviews(ctx)

                    except p4gf_lock.LockCanceled as lc:
                        LOG.warning(str(lc))
                    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)
                            p4gf_server_common.cleanup_client(ctx, view_name)
                        raise

                try:
                    exclusive = 'upload' not in command
                    is_push   = 'upload' not in command
                    git_caller = functools.partial(_call_git, input_name, environ, ctx)
                    p4gf_call_git.call_git(git_caller, ctx, view_name, view_lock, exclusive)
                    if is_push:
                        GSReviewCollection.post_push(ctx)
                except p4gf_atomic_lock.LockConflict as lc:
                    start_response(_('500 Internal Server Error'), headers)
                    return ["{}".format(lc).encode('UTF-8')]

        p4gf_gc.process_garbage('at end of auth_server')
        if LOG.isEnabledFor(logging.DEBUG):
            end_time = time.time()
            frm = NTR('Runtime: preparation {} ms, lock acquisition {} ms, processing {} ms')
            LOG.debug(frm.format(before_lock_time - start_time,
                                after_lock_time - before_lock_time,
                                end_time - after_lock_time))
        return []
Пример #37
0
def main():
    """set up repo for a view"""
    p4gf_util.has_server_id_or_exit()
    args = _parse_argv()
    p4gf_version.log_version()
    log_l10n()
    # !!! view_name_git    the untranslated repo name
    # !!! view_name        the translated repo name
    view_name_p4client = None
    if args.p4client:
        view_name_p4client = p4gf_util.argv_to_view_name(args.p4client)
    view_name_git = p4gf_util.argv_to_view_name(args.view)
    #strip leading '/' to conform with p4gf_auth_server behavior
    if view_name_git[0] == '/':
        view_name_git = view_name_git[1:]
    view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git)
    p4gf_gitmirror.setup_spawn(view_name)
    p4gf_util.reset_git_enviro()

    p4 = p4gf_create_p4.create_p4()
    if not p4:
        return INIT_REPO_NOVIEW

    LOG.debug("connected to P4 at %s", p4.port)
    p4gf_proc.init()
    try:
        with p4gf_create_p4.Closer():
            p4gf_version.version_check()

            with p4gf_lock.view_lock(p4, view_name) as view_lock:
                # Ensure we have a sane environment.
                p4gf_init.init(p4)

                # Now that we can trust that the git-fusion--p4 client exists,
                # switch to that. Change takes effect immediately, don't need to
                # re-run p4.connect().
                p4.client = p4gf_util.get_object_client_name()

                # If local config file specified, validate it and store in
                # Perforce now. Even if client exists (aka repo was already
                # inited), this is one way for an admin to modify an existing
                # repo's config.
                if args.config:
                    if not os.path.exists(args.config):
                        _print_stderr(_("error: missing config file '{}'").format(args.config))
                        return INIT_REPO_CONFIG_FILE_MISSING
                    with Validator.from_local_file(view_name, p4, args.config) as validator:
                        if not validator.is_valid(args.enablemismatchedrhs):
                            return INIT_REPO_CONFIG_FILE_BAD
                    p4gf_config.create_file_repo_with_contents(p4, view_name, args.config)

                elif args.charset and not Validator.valid_charset(args.charset):
                    _print_stderr(_("error: invalid charset: {}").format(args.charset))
                    return INIT_REPO_BAD_CHARSET

                # Initialize the repository if necessary.
                print(_("Initializing '{}'...").format(view_name))
                r = init_repo(p4, view_name, view_lock, args.charset, args.enablemismatchedrhs,
                        view_name_p4client)
                if r > INIT_REPO_OK:
                    return r
                print(_("Initialization complete."))

                # Write --enablemismatchedrhs to config file
                if args.enablemismatchedrhs:
                    config = p4gf_config.read_repo(p4, view_name)
                    config[p4gf_config.SECTION_REPO]\
                          [p4gf_config.KEY_ENABLE_MISMATCHED_RHS] = str(True)
                    p4gf_config.write_repo_if(p4, p4.fetch_client(), view_name, config)

                # Populate the repo from Perforce unless --noclone.
                if not args.noclone:
                    return populate_repo(view_name, view_lock, args.start)
    except P4.P4Exception as e:
        _print_stderr(_('Error occurred: {}').format(e))

    return INIT_REPO_EXISTS
Пример #38
0
def main():
    """Do the thing."""
    try:
        log_l10n()
        parse_argv()
        global P4PORT, P4USER
        needs_exit = False
        if not P4PORT and "P4PORT" not in os.environ:
            Verbosity.report(Verbosity.INFO,
                'P4PORT is neither set in the environment nor passed as an option.')
            needs_exit = True
        if not P4USER and "P4USER" not in os.environ:
            Verbosity.report(Verbosity.INFO,
                'P4USER is neither set in the environment nor passed as an option.')
            needs_exit = True
        # Check that a pre-existing P4GF_ENV config file P4PORT conflicts with the --port option
        if p4gf_const.P4GF_ENV and not Create_P4GF_CONFIG and P4PORT:
            if P4PORT != os.environ['P4PORT']:
                Verbosity.report(Verbosity.INFO,
                        "conflicting P4PORT in args: {0} and P4GF_ENV {1} : P4PORT = {2}. Stopping."
                        .format(P4PORT, p4gf_const.P4GF_ENV, os.environ['P4PORT']))
                needs_exit = True
            else:
                Verbosity.report(Verbosity.INFO,
                    "P4PORT argument is identically configured in {0}. Proceeding.".format(
                        p4gf_const.P4GF_ENV ))
        if needs_exit:
            sys.exit(1)

        p4gf_version.version_check()
        # Connect.
        global p4
        if not P4USER:
            P4USER = os.environ['P4USER']
        p4 = p4gf_create_p4.create_p4(port=P4PORT, user=P4USER)
        if not p4:
            raise RuntimeError(_("Failed to connect to P4."))
        P4PORT = p4.port
        P4USER = p4.user
        check_and_create_default_p4gf_env_config()
        if SHOW_IDS:
            show_all_server_ids()
            sys.exit(0)
        Verbosity.report(Verbosity.INFO, "P4PORT : {}".format(p4.port))
        Verbosity.report(Verbosity.INFO, "P4USER : {}".format(p4.user))
        _ensure_case_sensitive()

        # Require that we have super permission.
        # Might as well keep the result in case we need to write a new protect
        # table later. Saves a 'p4 protect -o' trip to the server
        protect_lines = fetch_protect()

        ensure_server_id()
        ensure_users()
        ensure_group()
        ensure_depot()
        ensure_protect(protect_lines)
        ensure_protects_configurable()
        check_triggers()
        initialize_all_gf_reviews()

    # pylint: disable=W0703
    # Catching too general exception
    except Exception as e:
        sys.stderr.write(str(e) + '\n')
        p4gf_create_p4.close_all()
        sys.exit(1)