Exemplo n.º 1
0
    def inforefs(self, request, environ):
        """
        WSGI Response producer for HTTP GET Git Smart
        HTTP /info/refs request.
        """

        git_command = request.GET.get('service')
        if git_command not in self.commands:
            log.debug('command %s not allowed' % git_command)
            return exc.HTTPMethodNotAllowed()

        # note to self:
        # please, resist the urge to add '\n' to git capture and increment
        # line count by 1.
        # The code in Git client not only does NOT need '\n', but actually
        # blows up if you sprinkle "flush" (0000) as "0001\n".
        # It reads binary, per number of bytes specified.
        # if you do add '\n' as part of data, count it.
        server_advert = '# service=%s' % git_command
        packet_len = str(hex(len(server_advert) + 4)[2:].rjust(4, '0')).lower()
        _git_path = kallithea.CONFIG.get('git_path', 'git')
        try:
            out = subprocessio.SubprocessIOChunker(
                r'%s %s --stateless-rpc --advertise-refs "%s"' %
                (_git_path, git_command[4:], self.content_path),
                starting_values=[packet_len + server_advert + '0000'])
        except EnvironmentError, e:
            log.error(traceback.format_exc())
            raise exc.HTTPExpectationFailed()
Exemplo n.º 2
0
    def backend(self, req, environ):
        """
        WSGI Response producer for HTTP POST Git Smart HTTP requests.
        Reads commands and data from HTTP POST's body.
        returns an iterator obj with contents of git command's
        response to stdout
        """
        _git_path = kallithea.CONFIG.get('git_path', 'git')
        git_command = self._get_fixedpath(req.path_info)
        if git_command not in self.commands:
            log.debug('command %s not allowed', git_command)
            return exc.HTTPMethodNotAllowed()

        if 'CONTENT_LENGTH' in environ:
            inputstream = FileWrapper(environ['wsgi.input'],
                                      req.content_length)
        else:
            inputstream = environ['wsgi.input']

        gitenv = dict(os.environ)
        # forget all configs
        gitenv['GIT_CONFIG_NOGLOBAL'] = '1'
        cmd = [
            _git_path, git_command[4:], '--stateless-rpc', self.content_path
        ]
        log.debug('handling cmd %s', cmd)
        try:
            out = subprocessio.SubprocessIOChunker(
                cmd,
                inputstream=inputstream,
                env=gitenv,
                cwd=self.content_path,
            )
        except EnvironmentError as e:
            log.error(traceback.format_exc())
            raise exc.HTTPExpectationFailed()

        if git_command in ['git-receive-pack']:
            # updating refs manually after each push.
            # Needed for pre-1.7.0.4 git clients using regular HTTP mode.
            from kallithea.lib.vcs import get_repo
            from dulwich.server import update_server_info
            repo = get_repo(self.content_path)
            if repo:
                update_server_info(repo._repo)

        resp = Response()
        resp.content_type = 'application/x-%s-result' % git_command.encode(
            'utf-8')
        resp.charset = None
        resp.app_iter = out
        return resp
Exemplo n.º 3
0
    def _run_git_command(cls, cmd, **opts):
        """
        Runs given ``cmd`` as git command and returns tuple
        (stdout, stderr).

        :param cmd: git command to be executed
        :param opts: env options to pass into Subprocess command
        """

        if '_bare' in opts:
            _copts = []
            del opts['_bare']
        else:
            _copts = [
                '-c',
                'core.quotepath=false',
            ]
        safe_call = False
        if '_safe' in opts:
            #no exc on failure
            del opts['_safe']
            safe_call = True

        assert isinstance(cmd, list), cmd

        gitenv = os.environ
        # need to clean fix GIT_DIR !
        if 'GIT_DIR' in gitenv:
            del gitenv['GIT_DIR']
        gitenv['GIT_CONFIG_NOGLOBAL'] = '1'

        _git_path = settings.GIT_EXECUTABLE_PATH
        cmd = [_git_path] + _copts + cmd

        try:
            _opts = dict(
                env=gitenv,
                shell=False,
            )
            _opts.update(opts)
            p = subprocessio.SubprocessIOChunker(cmd, **_opts)
        except (EnvironmentError, OSError) as err:
            tb_err = ("Couldn't run git command (%s).\n"
                      "Original error was:%s\n" % (cmd, err))
            log.error(tb_err)
            if safe_call:
                return '', err
            else:
                raise RepositoryError(tb_err)

        return ''.join(p.output), ''.join(p.error)
Exemplo n.º 4
0
    def inforefs(self, req, environ):
        """
        WSGI Response producer for HTTP GET Git Smart
        HTTP /info/refs request.
        """

        git_command = req.GET.get('service')
        if git_command not in self.commands:
            log.debug('command %s not allowed', git_command)
            return exc.HTTPMethodNotAllowed()

        # From Documentation/technical/http-protocol.txt shipped with Git:
        #
        # Clients MUST verify the first pkt-line is `# service=$servicename`.
        # Servers MUST set $servicename to be the request parameter value.
        # Servers SHOULD include an LF at the end of this line.
        # Clients MUST ignore an LF at the end of the line.
        #
        #  smart_reply     =  PKT-LINE("# service=$servicename" LF)
        #                     ref_list
        #                     "0000"
        server_advert = '# service=%s\n' % git_command
        packet_len = hex(len(server_advert) + 4)[2:].rjust(4, '0').lower()
        _git_path = kallithea.CONFIG.get('git_path', 'git')
        cmd = [
            _git_path, git_command[4:], '--stateless-rpc', '--advertise-refs',
            self.content_path
        ]
        log.debug('handling cmd %s', cmd)
        try:
            out = subprocessio.SubprocessIOChunker(
                cmd,
                starting_values=[
                    ascii_bytes(packet_len + server_advert + '0000')
                ])
        except EnvironmentError as e:
            log.error(traceback.format_exc())
            raise exc.HTTPExpectationFailed()
        resp = Response()
        resp.content_type = 'application/x-%s-advertisement' % str(git_command)
        resp.charset = None
        resp.app_iter = out
        return resp
Exemplo n.º 5
0
    def _run_git_command(cls, cmd, cwd=None):
        """
        Runs given ``cmd`` as git command and returns output bytes in a tuple
        (stdout, stderr) ... or raise RepositoryError.

        :param cmd: git command to be executed
        :param cwd: passed directly to subprocess
        """
        # need to clean fix GIT_DIR !
        gitenv = dict(os.environ)
        gitenv.pop('GIT_DIR', None)
        gitenv['GIT_CONFIG_NOGLOBAL'] = '1'

        assert isinstance(cmd, list), cmd
        cmd = [settings.GIT_EXECUTABLE_PATH, '-c', 'core.quotepath=false'
               ] + cmd
        try:
            p = subprocessio.SubprocessIOChunker(cmd,
                                                 cwd=cwd,
                                                 env=gitenv,
                                                 shell=False)
        except (EnvironmentError, OSError) as err:
            # output from the failing process is in str(EnvironmentError)
            msg = ("Couldn't run git command %s.\n"
                   "Subprocess failed with '%s': %s\n" %
                   (cmd, type(err).__name__, err)).strip()
            log.error(msg)
            raise RepositoryError(msg)

        try:
            stdout = b''.join(p.output)
            stderr = b''.join(p.error)
        finally:
            p.close()
        # TODO: introduce option to make commands fail if they have any stderr output?
        if stderr:
            log.debug('stderr from %s:\n%s', cmd, stderr)
        else:
            log.debug('stderr from %s: None', cmd)
        return stdout, stderr
Exemplo n.º 6
0
    def backend(self, request, environ):
        """
        WSGI Response producer for HTTP POST Git Smart HTTP requests.
        Reads commands and data from HTTP POST's body.
        returns an iterator obj with contents of git command's
        response to stdout
        """
        _git_path = kallithea.CONFIG.get('git_path', 'git')
        git_command = self._get_fixedpath(request.path_info)
        if git_command not in self.commands:
            log.debug('command %s not allowed' % git_command)
            return exc.HTTPMethodNotAllowed()

        if 'CONTENT_LENGTH' in environ:
            inputstream = FileWrapper(environ['wsgi.input'],
                                      request.content_length)
        else:
            inputstream = environ['wsgi.input']

        try:
            gitenv = os.environ
            # forget all configs
            gitenv['GIT_CONFIG_NOGLOBAL'] = '1'
            opts = dict(
                env=gitenv,
                cwd=self.content_path,
            )
            cmd = r'%s %s --stateless-rpc "%s"' % (_git_path, git_command[4:],
                                                   self.content_path),
            log.debug('handling cmd %s' % cmd)
            out = subprocessio.SubprocessIOChunker(cmd,
                                                   inputstream=inputstream,
                                                   **opts)
        except EnvironmentError, e:
            log.error(traceback.format_exc())
            raise exc.HTTPExpectationFailed()