Commit d8f3b9bc authored by Stan Hu's avatar Stan Hu

Add redis-rb as a vendored library

`make update-redis` will clone the library and adjust the paths properly
parent b99bc5d4
...@@ -8,3 +8,4 @@ coverage/ ...@@ -8,3 +8,4 @@ coverage/
.bundle .bundle
tags tags
.bundle/ .bundle/
*.orig
source "http://rubygems.org" source "http://rubygems.org"
gem 'redis', '~> 3.3'
group :development, :test do group :development, :test do
gem 'coveralls', require: false gem 'coveralls', require: false
gem 'rspec', '~> 2.14.0' gem 'rspec', '~> 2.14.0'
......
...@@ -37,7 +37,6 @@ GEM ...@@ -37,7 +37,6 @@ GEM
method_source (~> 0.8) method_source (~> 0.8)
slop (~> 3.3.1) slop (~> 3.3.1)
rainbow (2.0.0) rainbow (2.0.0)
redis (3.3.0)
rest-client (1.7.2) rest-client (1.7.2)
mime-types (>= 1.16, < 3.0) mime-types (>= 1.16, < 3.0)
netrc (~> 0.7) netrc (~> 0.7)
...@@ -78,7 +77,6 @@ DEPENDENCIES ...@@ -78,7 +77,6 @@ DEPENDENCIES
coveralls coveralls
guard guard
guard-rspec guard-rspec
redis (~> 3.3)
rspec (~> 2.14.0) rspec (~> 2.14.0)
rubocop (= 0.28.0) rubocop (= 0.28.0)
vcr vcr
......
REDIS_RB_VERSION=v3.3.0
REDIS_RB_TMP_DIR := $(shell mktemp -d)
REDIS_RB_VENDOR_DIR=lib/vendor
PWD=`pwd`
all:
update-redis:
cd lib
git clone https://github.com/redis/redis-rb.git $(REDIS_RB_TMP_DIR)
cd $(REDIS_RB_TMP_DIR); git checkout $(REDIS_RB_VERSION)
cd $(PWD)
mkdir -p $(REDIS_RB_VENDOR_DIR)
cp -r $(REDIS_RB_TMP_DIR)/lib/* $(REDIS_RB_VENDOR_DIR)
# Adjust all 'require redis/' paths to relative paths
sed -i.orig -e 's/require "redis/require_relative "redis/g' $(REDIS_RB_VENDOR_DIR)/redis.rb
find $(REDIS_RB_VENDOR_DIR)/redis -name \*.rb -maxdepth 1 -exec sed -i.orig -e "s/require \"redis\//require_relative \"/g" {} \;
find $(REDIS_RB_VENDOR_DIR)/redis/connection -name \*.rb -maxdepth 1 -exec sed -i.orig -e 's/require "redis\/connection\//require_relative "/g' *.rb {} \;
find $(REDIS_RB_VENDOR_DIR)/redis/connection -name \*.rb -maxdepth 1 -exec sed -i.orig -e 's/require "redis\//require_relative "..\//g' *.rb {} \;
.PHONY=update-redis
require 'net/http' require 'net/http'
require 'openssl' require 'openssl'
require 'json' require 'json'
require 'redis'
require_relative 'gitlab_config' require_relative 'gitlab_config'
require_relative 'gitlab_logger' require_relative 'gitlab_logger'
require_relative 'gitlab_access' require_relative 'gitlab_access'
require_relative 'httpunix' require_relative 'httpunix'
require_relative 'vendor/redis'
class GitlabNet class GitlabNet
class ApiUnreachableError < StandardError; end class ApiUnreachableError < StandardError; end
......
...@@ -2,7 +2,6 @@ require_relative 'gitlab_init' ...@@ -2,7 +2,6 @@ require_relative 'gitlab_init'
require_relative 'gitlab_net' require_relative 'gitlab_net'
require 'json' require 'json'
require 'base64' require 'base64'
require 'redis'
require 'securerandom' require 'securerandom'
class GitlabPostReceive class GitlabPostReceive
......
This diff is collapsed.
This diff is collapsed.
require_relative "connection/registry"
# If a connection driver was required before this file, the array
# Redis::Connection.drivers will contain one or more classes. The last driver
# in this array will be used as default driver. If this array is empty, we load
# the plain Ruby driver as our default. Another driver can be required at a
# later point in time, causing it to be the last element of the #drivers array
# and therefore be chosen by default.
require_relative "connection/ruby" if Redis::Connection.drivers.empty?
class Redis
module Connection
module CommandHelper
COMMAND_DELIMITER = "\r\n"
def build_command(args)
command = [nil]
args.each do |i|
if i.is_a? Array
i.each do |j|
j = j.to_s
command << "$#{j.bytesize}"
command << j
end
else
i = i.to_s
command << "$#{i.bytesize}"
command << i
end
end
command[0] = "*#{(command.length - 1) / 2}"
# Trailing delimiter
command << ""
command.join(COMMAND_DELIMITER)
end
protected
if defined?(Encoding::default_external)
def encode(string)
string.force_encoding(Encoding::default_external)
end
else
def encode(string)
string
end
end
end
end
end
require_relative "registry"
require_relative "../errors"
require "hiredis/connection"
require "timeout"
class Redis
module Connection
class Hiredis
def self.connect(config)
connection = ::Hiredis::Connection.new
connect_timeout = (config.fetch(:connect_timeout, 0) * 1_000_000).to_i
if config[:scheme] == "unix"
connection.connect_unix(config[:path], connect_timeout)
elsif config[:scheme] == "rediss" || config[:ssl]
raise NotImplementedError, "SSL not supported by hiredis driver"
else
connection.connect(config[:host], config[:port], connect_timeout)
end
instance = new(connection)
instance.timeout = config[:read_timeout]
instance
rescue Errno::ETIMEDOUT
raise TimeoutError
end
def initialize(connection)
@connection = connection
end
def connected?
@connection && @connection.connected?
end
def timeout=(timeout)
# Hiredis works with microsecond timeouts
@connection.timeout = Integer(timeout * 1_000_000)
end
def disconnect
@connection.disconnect
@connection = nil
end
def write(command)
@connection.write(command.flatten(1))
rescue Errno::EAGAIN
raise TimeoutError
end
def read
reply = @connection.read
reply = CommandError.new(reply.message) if reply.is_a?(RuntimeError)
reply
rescue Errno::EAGAIN
raise TimeoutError
rescue RuntimeError => err
raise ProtocolError.new(err.message)
end
end
end
end
Redis::Connection.drivers << Redis::Connection::Hiredis
class Redis
module Connection
# Store a list of loaded connection drivers in the Connection module.
# Redis::Client uses the last required driver by default, and will be aware
# of the loaded connection drivers if the user chooses to override the
# default connection driver.
def self.drivers
@drivers ||= []
end
end
end
This diff is collapsed.
require_relative "command_helper"
require_relative "registry"
require_relative "../errors"
require "em-synchrony"
require "hiredis/reader"
class Redis
module Connection
class RedisClient < EventMachine::Connection
include EventMachine::Deferrable
attr_accessor :timeout
def post_init
@req = nil
@connected = false
@reader = ::Hiredis::Reader.new
end
def connection_completed
@connected = true
succeed
end
def connected?
@connected
end
def receive_data(data)
@reader.feed(data)
loop do
begin
reply = @reader.gets
rescue RuntimeError => err
@req.fail [:error, ProtocolError.new(err.message)]
break
end
break if reply == false
reply = CommandError.new(reply.message) if reply.is_a?(RuntimeError)
@req.succeed [:reply, reply]
end
end
def read
@req = EventMachine::DefaultDeferrable.new
if @timeout > 0
@req.timeout(@timeout, :timeout)
end
EventMachine::Synchrony.sync @req
end
def send(data)
callback { send_data data }
end
def unbind
@connected = false
if @req
@req.fail [:error, Errno::ECONNRESET]
@req = nil
else
fail
end
end
end
class Synchrony
include Redis::Connection::CommandHelper
def self.connect(config)
if config[:scheme] == "unix"
conn = EventMachine.connect_unix_domain(config[:path], RedisClient)
elsif config[:scheme] == "rediss" || config[:ssl]
raise NotImplementedError, "SSL not supported by synchrony driver"
else
conn = EventMachine.connect(config[:host], config[:port], RedisClient) do |c|
c.pending_connect_timeout = [config[:connect_timeout], 0.1].max
end
end
fiber = Fiber.current
conn.callback { fiber.resume }
conn.errback { fiber.resume :refused }
raise Errno::ECONNREFUSED if Fiber.yield == :refused
instance = new(conn)
instance.timeout = config[:read_timeout]
instance
end
def initialize(connection)
@connection = connection
end
def connected?
@connection && @connection.connected?
end
def timeout=(timeout)
@connection.timeout = timeout
end
def disconnect
@connection.close_connection
@connection = nil
end
def write(command)
@connection.send(build_command(command))
end
def read
type, payload = @connection.read
if type == :reply
payload
elsif type == :error
raise payload
elsif type == :timeout
raise TimeoutError
else
raise "Unknown type #{type.inspect}"
end
end
end
end
end
Redis::Connection.drivers << Redis::Connection::Synchrony
This diff is collapsed.
class Redis
# Base error for all redis-rb errors.
class BaseError < RuntimeError
end
# Raised by the connection when a protocol error occurs.
class ProtocolError < BaseError
def initialize(reply_type)
super(<<-EOS.gsub(/(?:^|\n)\s*/, " "))
Got '#{reply_type}' as initial reply byte.
If you're in a forking environment, such as Unicorn, you need to
connect to Redis after forking.
EOS
end
end
# Raised by the client when command execution returns an error reply.
class CommandError < BaseError
end
# Base error for connection related errors.
class BaseConnectionError < BaseError
end
# Raised when connection to a Redis server cannot be made.
class CannotConnectError < BaseConnectionError
end
# Raised when connection to a Redis server is lost.
class ConnectionError < BaseConnectionError
end
# Raised when performing I/O times out.
class TimeoutError < BaseConnectionError
end
# Raised when the connection was inherited by a child process.
class InheritedError < BaseConnectionError
end
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
class Redis
VERSION = "3.3.0"
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment