]> git.saurik.com Git - redis.git/commitdiff
client libraries updated
authorantirez <antirez@gmail.com>
Tue, 16 Jun 2009 14:45:04 +0000 (16:45 +0200)
committerantirez <antirez@gmail.com>
Tue, 16 Jun 2009 14:45:04 +0000 (16:45 +0200)
16 files changed:
client-libraries/clojure/benchmarks/clojure.clj
client-libraries/clojure/benchmarks/ruby.clj
client-libraries/clojure/build.xml
client-libraries/clojure/src/redis.clj
client-libraries/clojure/src/redis/internal.clj
client-libraries/clojure/src/redis/tests.clj
client-libraries/clojure/src/redis/tests/internal.clj
client-libraries/cpp/TODO
client-libraries/cpp/redisclient.cpp
client-libraries/cpp/redisclient.h
client-libraries/cpp/test_client.cpp
client-libraries/lua/redis.lua
client-libraries/ruby/.gitignore
client-libraries/ruby/Rakefile
client-libraries/ruby/spec/redis_spec.rb
client-libraries/update-clojure-client.sh [new file with mode: 0755]

index 7f88d8ea85d53cd73d43f1c78b3ce08e7d0c109f..13739f04eb6fac8193b741569e5a659ea25053de 100644 (file)
@@ -30,7 +30,6 @@
   :requests)
 
 
-
 (defmacro defbenchmark [name & body]
   (let [benchmark-name (symbol (str name "-benchmark"))]
     `(def ~(with-meta benchmark-name {:benchmark true})
@@ -64,7 +63,7 @@
   (redis/get (str "key-" (rand-int 1000))))
 
 (defbenchmark set
-  (redis/set (str "key-" (rand-int 1000)) "blahojga!"))
+  (redis/set (str "key-" (rand-int 1000)) "abc"))
 
 (defbenchmark exists-set-and-get
   (let [key (str "key-" (rand-int 100))]
@@ -77,7 +76,7 @@
                          :host "127.0.0.1"
                          :port 6379
                          :db 15
-                         :clients 4
+                         :clients 1
                          :requests 10000))
 
 (defn create-clients [options]
 (defn report-request-times [clients requests]
   (let [requests-dist (map #(let [perc (* 100 (/ (last %) requests))]
                              (conj % perc)) (requests-by-ms clients))]
-    (dorun
-     (map #(println (format "%.2f%% < %d ms" (float (last %)) (inc (first %))))
-          requests-dist))))
+    (loop [items requests-dist
+           seen 0]
+      (if-not (empty? items)
+        (do 
+          (let [item (first items)
+                seen (+ seen (last item))]
+            (println (format "%.2f%% < %d ms" (float seen) (inc (first item))))
+            (recur (rest items) seen)))))))
 
 (defn report-client-rps [client]
   (let [{:keys [id requests-performed request-times]} @client]
       (println (format "====== %s =====\n" name))
       (println (format "   %d requests completed in %f seconds\n" requests time-in-seconds))
       (println (format "   %d parallel clients\n" (:clients options)))
-      ;(report-request-times clients requests)
+      (report-request-times clients requests)
       ;(dorun (map report-client-rps clients))
       (println (format "%f requests per second\n\n" requests-per-second))
       )
index 0ede54d47f73458ff01a81774ad54bcbe54bc44f..c73c1a53e5209c44e98775a4fbc9b50e1eee40e8 100644 (file)
@@ -1,10 +1,9 @@
 (ns benchmarks.ruby
   (:require redis))
 
-
-(dotimes [n 2]
+(dotimes [n 4]
   (redis/with-server 
-   {}
+   {:db 15}
    (redis/set "foo" "The first line we sent to the server is some text")
    (time 
     (dotimes [i 20000]
index b10bdeb00ce90db21ec7090b2db53e99ad89aa83..d25eba38cbeb2fcfea11f539c14f8dcada97c91e 100644 (file)
@@ -38,8 +38,8 @@
   <target name="jar" description="Create jar file" depends="compile">
     <jar jarfile="${redis-clojure.jar}">
       <path location="LICENSE"/>
-      <fileset dir="${source.dir}" includes="**/*.clj"/>
-      <!--<fileset dir="${build.dir}" includes="**/*.class"/>-->
+      <!--<fileset dir="${source.dir}" includes="**/*.clj"/>-->
+      <fileset dir="${build.dir}" includes="**/*.class"/>
       <manifest>
         <attribute name="Built-By" value="${user.name}"/>
       </manifest>
@@ -65,6 +65,7 @@
       <classpath>
         <path location="${basedir}"/>
         <path location="${source.dir}"/>
+        <!--<path location="${redis-clojure.jar}"/>-->
         <path location="${clojure.jar}"/>
         <path location="${clojure-contrib.jar}"/>
       </classpath>
index 0ec33ba63fec7127953efd676834631e97bf00ec..cb5a4faed80822c5ecb06d4bd4a7fe95466aef05 100644 (file)
@@ -1,11 +1,11 @@
 ;(add-classpath "file:///Users/ragge/Projects/clojure/redis-clojure/src/")
 
-(set! *warn-on-reflection* true)
-
 (ns redis
   (:refer-clojure :exclude [get set type keys sort])
   (:use redis.internal))
 
+;(set! *warn-on-reflection* true)
+
 (defmacro with-server
   "Evaluates body in the context of a new connection to a Redis server
   then closes the connection.
   ;; Set commands
   (sadd        [key member] :bulk int-to-bool)
   (srem        [key member] :bulk int-to-bool)
+  (spop        [key] :inline)
   (smove       [srckey destkey member] :bulk int-to-bool)
   (scard       [key] :inline)
   (sismember   [key member] :bulk int-to-bool)
   (bgsave      [] :inline)
   (lastsave    [] :inline int-to-date)
   (shutdown    [] :inline)
+  ;; Remote control
   (info        [] :inline string-to-map)
   ;;(monitor     [] :inline))
 )
index d363a58d0c8da1946ecdb935983e15f6a20c3021..d8399bb82540fdbd3711c481f441a489b121cd11 100644 (file)
@@ -39,7 +39,8 @@
   (let [{:keys [host port timeout]} server
         socket (Socket. #^String host #^Integer port)]
     (doto socket
-      (.setTcpNoDelay true))))
+      (.setTcpNoDelay true)
+      (.setKeepAlive true))))
 
 (defn with-server*
   [server-spec func]
 
 (defn reply-type
   ([#^BufferedReader reader]
-     (let [type (char (.read reader))]
-       type)))
+     (char (.read reader))))
 
 (defmulti parse-reply reply-type :default :unknown)
 
index 8add90af61d2849abb1d39b0975d1f5ef0ea7355..070b45be7957cba5344ba19181733fafdac12112 100644 (file)
   (redis/lset "list" -1 "test3")
   (is (= "test3" (redis/lindex "list" 2))))
 
-
-;; TBD
 (deftest lrem
   (is (thrown? Exception (redis/lrem "foo" 0 "bar")))
-  (is (= 0 (redis/lrem "list" 0 ""))))
+  (is (= 0 (redis/lrem "newlist" 0 "")))
+  (is (= 1 (redis/lrem "list" 1 "two")))
+  (is (= 1 (redis/lrem "list" 42 "three")))
+  (is (= 1 (redis/llen "list"))))
 
 
 (deftest lpop
   (is (thrown? Exception (redis/lpop "foo")))
-  (is (= "one" (redis/lpop "list"))))
+  (is (= nil (redis/lpop "newlist")))
+  (is (= "one" (redis/lpop "list")))
+  (is (= 2 (redis/llen "list"))))
 
 (deftest rpop
   (is (thrown? Exception (redis/rpop "foo")))
-  (is (= "three" (redis/rpop "list"))))
+  (is (= nil (redis/rpop "newlist")))
+  (is (= "three" (redis/rpop "list")))
+  (is (= 2 (redis/llen "list"))))
 
 ;;
 ;; Set commands
 
 (deftest srem
   (is (thrown? Exception (redis/srem "foo" "bar")))
-  (is (thrown? Exception (redis/srem "newset" "member")))
+  (is (= false (redis/srem "newset" "member")))
   (is (= true (redis/srem "set" "two")))
   (is (= false (redis/sismember "set" "two")))
   (is (= false (redis/srem "set" "blahonga"))))
 
+(deftest spop
+  (is (thrown? Exception (redis/spop "foo" "bar")))
+  (is (= nil (redis/spop "newset")))
+  (is (contains? #{"one" "two" "three"} (redis/spop "set"))))
+
 (deftest smove
   (is (thrown? Exception (redis/smove "foo" "set" "one")))
   (is (thrown? Exception (redis/smove "set" "foo" "one")))
index 3daf98dbfef14d3b831c22eb65651316fa262a4a..9f1422e96728a7d3f1b46a98ccf43ef889a48675 100644 (file)
@@ -4,11 +4,6 @@
   (:import [java.io StringReader BufferedReader]))
 
 
-
-
-
-
-
 ;;
 ;; Helpers
 ;;
index 3e84754d86ce7d1ac9800f88d6b9cc1f0906d748..cc541cdb03eb8013c05fd08e2b337d4bec0bfe92 100644 (file)
@@ -1,6 +1,12 @@
+general:
+- check for complete support for 0.100 (compiles; existing tests pass)
+
 command handlers:
 - support DEL as vararg
 - support MLLEN and MSCARD
+- support SDIFF
+- support SDIFFSTORE
+
 
 unit tests:
 - sort with limit
index beaa876a0e517844830d5f474d8b1a495175f70c..5e3468ccc65cedb0bb698697d3de6c364359dbd5 100644 (file)
@@ -40,7 +40,6 @@
 #endif
 
 #include <cstring>
-#include <cstdlib>
 #include <cassert>
 
 #include <sys/errno.h>
@@ -236,32 +235,15 @@ namespace
     return rtrim(line, CRLF);
   }
 
-  unsigned long unsigned_number_from_string(const string & data)
+  template <typename T>
+  T value_from_string(const string & data)
   {
-    errno = 0;
+    T value;
 
-    unsigned long value = strtoul(data.c_str(), NULL, 10);
-
-    if (value == ULONG_MAX && errno == ERANGE)
-      throw redis::value_error("invalid number; out of range of long");
-
-    if (value == 0 && errno == EINVAL)
-      throw redis::value_error("invalid number; unrecognized format");
-
-    return value;
-  }
-
-  redis::client::int_type number_from_string(const string & data)
-  {
-    errno = 0;
-
-    redis::client::int_type value = strtol(data.c_str(), NULL, 10);
-
-    if ((value == LONG_MAX || value == LONG_MIN) && errno == ERANGE)
-      throw redis::value_error("invalid number; out of range of long");
-
-    if (value == 0 && errno == EINVAL)
-      throw redis::value_error("invalid number; unrecognized format");
+    istringstream iss(data);
+    iss >> value;
+    if (iss.fail()) 
+      throw redis::value_error("invalid number");
 
     return value;
   }
@@ -284,6 +266,10 @@ namespace
   const string server_info_key_total_commands_processed = "total_commands_processed";
   const string server_info_key_uptime_in_seconds = "uptime_in_seconds";
   const string server_info_key_uptime_in_days = "uptime_in_days";
+  const string server_info_key_role = "role";
+
+  const string server_info_value_role_master = "master";
+  const string server_info_value_role_slave = "slave";
 }
 
 namespace redis 
@@ -578,11 +564,11 @@ namespace redis
     return recv_multi_bulk_reply_(out);
   }
 
-  void client::sinterstore(const client::string_type & dstkey, 
-                           const client::string_vector & keys)
+  client::int_type client::sinterstore(const client::string_type & dstkey, 
+                                       const client::string_vector & keys)
   {
     send_(makecmd("SINTERSTORE") << dstkey << ' ' << keys);
-    recv_ok_reply_();
+    return recv_int_reply_();
   }
 
   client::int_type client::sunion(const client::string_vector & keys,
@@ -592,11 +578,11 @@ namespace redis
     return recv_multi_bulk_reply_(out);
   }
 
-  void client::sunionstore(const client::string_type & dstkey, 
-                           const client::string_vector & keys)
+  client::int_type client::sunionstore(const client::string_type & dstkey, 
+                                       const client::string_vector & keys)
   {
     send_(makecmd("SUNIONSTORE") << dstkey << ' ' << keys);
-    recv_ok_reply_();
+    return recv_int_reply_();
   }
 
   client::int_type client::smembers(const client::string_type & key, 
@@ -746,25 +732,27 @@ namespace redis
       if (key == server_info_key_version)
         out.version = val;
       else if (key == server_info_key_bgsave_in_progress)
-        out.bgsave_in_progress = unsigned_number_from_string(val) == 1;
+        out.bgsave_in_progress = value_from_string<unsigned long>(val) == 1;
       else if (key == server_info_key_connected_clients)
-        out.connected_clients = unsigned_number_from_string(val);
+        out.connected_clients = value_from_string<unsigned long>(val);
       else if (key == server_info_key_connected_slaves)
-        out.connected_slaves = unsigned_number_from_string(val);
+        out.connected_slaves = value_from_string<unsigned long>(val);
       else if (key == server_info_key_used_memory)
-        out.used_memory = unsigned_number_from_string(val);
+        out.used_memory = value_from_string<unsigned long>(val);
       else if (key == server_info_key_changes_since_last_save)
-        out.changes_since_last_save = unsigned_number_from_string(val);
+        out.changes_since_last_save = value_from_string<unsigned long>(val);
       else if (key == server_info_key_last_save_time)
-        out.last_save_time = unsigned_number_from_string(val);
+        out.last_save_time = value_from_string<unsigned long>(val);
       else if (key == server_info_key_total_connections_received)
-        out.total_connections_received = unsigned_number_from_string(val);
+        out.total_connections_received = value_from_string<unsigned long>(val);
       else if (key == server_info_key_total_commands_processed)
-        out.total_commands_processed = unsigned_number_from_string(val);
+        out.total_commands_processed = value_from_string<unsigned long>(val);
       else if (key == server_info_key_uptime_in_seconds)
-        out.uptime_in_seconds = unsigned_number_from_string(val);
+        out.uptime_in_seconds = value_from_string<unsigned long>(val);
       else if (key == server_info_key_uptime_in_days)
-        out.uptime_in_days = unsigned_number_from_string(val);
+        out.uptime_in_days = value_from_string<unsigned long>(val);
+      else if (key == server_info_key_role)
+        out.role = val == server_info_value_role_master ? role_master : role_slave;
       else
         throw protocol_error(string("unexpected info key '") + key + "'");
     }
@@ -826,7 +814,7 @@ namespace redis
     if (line[0] != prefix)
       throw protocol_error("unexpected prefix for bulk reply");
 
-    return number_from_string(line.substr(1));
+    return value_from_string<client::int_type>(line.substr(1));
   }
 
   string client::recv_bulk_reply_() 
@@ -895,7 +883,7 @@ namespace redis
     if (line[0] != prefix_int_reply)
       throw protocol_error("unexpected prefix for integer reply");
 
-    return number_from_string(line.substr(1));
+    return value_from_string<client::int_type>(line.substr(1));
   }
 
   void client::recv_int_ok_reply_()
index d3fee780a67e268b4c4413866bf49dc69d86c29a..b51da8f9533fc3151ab5ceb23e14170119241260 100644 (file)
 
 namespace redis 
 {
+  enum server_role
+  {
+    role_master,
+    role_slave
+  };
+
   struct server_info 
   {
     std::string version;
@@ -52,6 +58,7 @@ namespace redis
     unsigned long total_commands_processed;
     unsigned long uptime_in_seconds;
     unsigned long uptime_in_days;
+    server_role role;
   };
 
   // Generic error that is thrown when communicating with the redis server.
@@ -355,8 +362,9 @@ namespace redis
 
     // Compute the intersection between the sets stored at key1, key2, ..., 
     // keyN, and store the resulting set at dstkey
+    // Returns the number of items in the intersection
 
-    void sinterstore(const string_type & dstkey, const string_vector & keys);
+    int_type sinterstore(const string_type & dstkey, const string_vector & keys);
 
     // Return the union between the sets stored at key1, key2, ..., keyN
 
@@ -364,8 +372,9 @@ namespace redis
 
     // Compute the union between the sets stored at key1, key2, ..., keyN, 
     // and store the resulting set at dstkey
+    // Returns the number of items in the intersection
 
-    void sunionstore(const string_type & dstkey, const string_vector & keys);
+    int_type sunionstore(const string_type & dstkey, const string_vector & keys);
 
     // Return all the members of the set value at key
 
index c0891cb0af37eaff474f8e51f66348668651fb6e..53ef5117ad423c4783bbdcff11e9871aace721b4 100644 (file)
@@ -478,7 +478,7 @@ int main(int argc, char ** argv)
       keys.push_back("seta");
       keys.push_back("setb");
 
-      c.sinterstore("setc", keys);
+      ASSERT_EQUAL(c.sinterstore("setc", keys), 2L);
 
       redis::client::string_set members;
       ASSERT_EQUAL(c.smembers("setc", members), 2L);
@@ -510,7 +510,7 @@ int main(int argc, char ** argv)
       keys.push_back("setf");
       keys.push_back("setg");
 
-      c.sunionstore("seth", keys);
+      ASSERT_EQUAL(c.sunionstore("seth", keys), 2L);
 
       redis::client::string_set members;
       ASSERT_EQUAL(c.smembers("seth", members), 2L);
index 87351745a366467f18e0e400c7c4ab92778032ae..1e85ffd8790098dc26d2d5cc16fee40f271c170f 100644 (file)
@@ -239,6 +239,7 @@ redis_commands = {
     set_preserve  = bulk('SETNX', toboolean), 
     get           = inline('GET'), 
     get_multiple  = inline('MGET'), 
+    get_set       = bulk('GETSET'), 
     increment     = inline('INCR'), 
     increment_by  = inline('INCRBY'), 
     decrement     = inline('DECR'), 
@@ -262,6 +263,7 @@ redis_commands = {
     rename_preserve  = inline('RENAMENX'), 
     expire           = inline('EXPIRE', toboolean), 
     database_size    = inline('DBSIZE'), 
+    time_to_live     = inline('TTL'), 
 
     -- commands operating on lists
     push_tail    = bulk('RPUSH'), 
@@ -276,12 +278,17 @@ redis_commands = {
     pop_last     = inline('RPOP'), 
 
     -- commands operating on sets
-    set_add                 = inline('SADD'), 
-    set_remove              = inline('SREM'), 
+    set_add                 = bulk('SADD'), 
+    set_remove              = bulk('SREM'), 
+    set_move                = bulk('SMOVE'), 
     set_cardinality         = inline('SCARD'), 
     set_is_member           = inline('SISMEMBER'), 
     set_intersection        = inline('SINTER'), 
     set_intersection_store  = inline('SINTERSTORE'), 
+    set_union               = inline('SUNION'), 
+    set_union_store         = inline('SUNIONSTORE'), 
+    set_diff                = inline('SDIFF'), 
+    set_diff_store          = inline('SDIFFSTORE'), 
     set_members             = inline('SMEMBERS'), 
 
     -- multiple databases handling commands
@@ -321,7 +328,7 @@ redis_commands = {
     ), 
 
     -- remote server control commands
-    info  = inline('INFO', 
+    info = inline('INFO', 
         function(response) 
             local info = {}
             response:gsub('([^\r\n]*)\r\n', function(kv) 
@@ -331,4 +338,10 @@ redis_commands = {
             return info
         end
     ),
+    slave_of        = inline('SLAVEOF'), 
+    slave_of_no_one = custom('SLAVEOF', 
+        function(client, command)
+            return request.inline(client, command, 'NO ONE')
+        end
+    ),
 }
index 2fd676b3cf965a7c1b7935da34d427cbb3204dff..f3b05636d54017c98808811614446e43cf63a7c0 100644 (file)
@@ -2,4 +2,5 @@ nohup.out
 redis/*
 rdsrv
 pkg/*
+coverage/*
 .idea
index 9bed311a3e675a25989e1c997fde695b6217f58d..b6217054a0b85ccfe1dd353b0a1f9247b40a289f 100644 (file)
@@ -8,7 +8,7 @@ require 'tasks/redis.tasks'
 
 GEM = 'redis'
 GEM_NAME = 'redis'
-GEM_VERSION = '0.0.3.4'
+GEM_VERSION = '0.1'
 AUTHORS = ['Ezra Zygmuntowicz', 'Taylor Weibley', 'Matthew Clark']
 EMAIL = "ez@engineyard.com"
 HOMEPAGE = "http://github.com/ezmobius/redis-rb"
@@ -53,4 +53,10 @@ task :make_spec do
   File.open("#{GEM}.gemspec", "w") do |file|
     file.puts spec.to_ruby
   end
-end
\ No newline at end of file
+end
+
+desc "Run all examples with RCov"
+Spec::Rake::SpecTask.new(:rcov) do |t|
+  t.spec_files = FileList['spec/**/*_spec.rb']
+  t.rcov = true
+end
index d4dde96417b8e486c4047dcb649d32194bcabec7..4ffa6b669ff55370f7c3b07290184b08670b2c0d 100644 (file)
@@ -29,7 +29,11 @@ describe "redis" do
     @r.quit
   end  
 
-  it 'should be able to PING' do
+  it "should be able connect without a timeout" do
+    lambda { Redis.new :timeout => 0 }.should_not raise_error
+  end
+
+  it "should be able to PING" do
     @r.ping.should == 'PONG' 
   end
 
@@ -61,13 +65,23 @@ describe "redis" do
     sleep 2
     @r['foo'].should == nil
   end
-  
+
+  it "should be able to return a TTL for a key" do
+    @r.set('foo', 'bar', 1)
+    @r.ttl('foo').should == 1
+  end
+
   it "should be able to SETNX" do
     @r['foo'] = 'nik'
     @r['foo'].should == 'nik'
     @r.setnx 'foo', 'bar'
     @r['foo'].should == 'nik'
   end
+  #
+  it "should be able to GETSET" do
+   @r.getset('foo', 'baz').should == 'bar'
+   @r['foo'].should == 'baz'
+  end
   # 
   it "should be able to INCR a key" do
     @r.del('counter')
@@ -75,7 +89,14 @@ describe "redis" do
     @r.incr('counter').should == 2
     @r.incr('counter').should == 3
   end
-  # 
+  #
+  it "should be able to INCRBY a key" do
+    @r.del('counter')
+    @r.incrby('counter', 1).should == 1
+    @r.incrby('counter', 2).should == 3
+    @r.incrby('counter', 3).should == 6
+  end
+  #
   it "should be able to DECR a key" do
     @r.del('counter')
     @r.incr('counter').should == 1
@@ -137,6 +158,10 @@ describe "redis" do
     @r['foo'] = 'qux'
     @r.keys("f*").sort.should == ['f','fo', 'foo'].sort
   end
+  #
+  it "should be able to return a random key (RANDOMKEY)" do
+    3.times { @r.exists(@r.randomkey).should be_true }
+  end
   #BTM - TODO 
   it "should be able to check the TYPE of a key" do
     @r['foo'] = 'nik'
@@ -356,20 +381,24 @@ describe "redis" do
     @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1], :order => 'desc alpha').should == ['taj', 'terrier']
   end
   # 
-  it "should provide info" do
+  it "should provide info (INFO)" do
     [:last_save_time, :redis_version, :total_connections_received, :connected_clients, :total_commands_processed, :connected_slaves, :uptime_in_seconds, :used_memory, :uptime_in_days, :changes_since_last_save].each do |x|
     @r.info.keys.should include(x)
     end
   end
   # 
-  it "should be able to flush the database" do
+  it "should be able to flush the database (FLUSHDB)" do
     @r['key1'] = 'keyone'
     @r['key2'] = 'keytwo'
     @r.keys('*').sort.should == ['foo', 'key1', 'key2'].sort #foo from before
     @r.flushdb
     @r.keys('*').should == []
   end
-  # 
+  #
+  it "should raise exception when manually try to change the database" do
+    lambda { @r.select(0) }.should raise_error
+  end
+  #
   it "should be able to provide the last save time (LASTSAVE)" do
     savetime = @r.lastsave
     Time.at(savetime).class.should == Time
@@ -387,6 +416,10 @@ describe "redis" do
     @r.bgsave.should == 'OK'
   end
   
+  it "should should be able to ECHO" do
+    @r.echo("message in a bottle\n").should == "message in a bottle\n"
+  end
+
   it "should handle multiple servers" do
     require 'dist_redis'
     @r = DistRedis.new(:hosts=> ['localhost:6379', '127.0.0.1:6379'], :db => 15)
diff --git a/client-libraries/update-clojure-client.sh b/client-libraries/update-clojure-client.sh
new file mode 100755 (executable)
index 0000000..125ad2c
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+rm -rf temp
+mkdir temp
+cd temp
+git clone git://github.com/ragnard/redis-clojure.git
+cd redis-clojure
+rm -rf .git
+cd ..
+cd ..
+rm -rf clojure
+mv temp/redis-clojure clojure
+rm -rf temp