redis-load 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGES ADDED
@@ -0,0 +1,4 @@
1
+ == Release 0.1
2
+ First release to github
3
+ Added initial support for loading JSON into Redis. Path support not yet fully tested
4
+ Added basic command line tools for loading/saving
data/README ADDED
@@ -0,0 +1,64 @@
1
+ Utility for managing data structures in Redis, allowing lists, sets, etc to be populated by loading
2
+ data from flat files and JSON. Data structures can also be saved out to local files.
3
+
4
+ The rationale here was to provide some easy ways to persistent out the results of data manipulations from
5
+ Redis in easy to process formats. Similarly I also wanted to load data structures from files for use in Redis,
6
+ but where the original data has been created separately, e.g. by a map-reduce job.
7
+
8
+ == Author
9
+
10
+ Leigh Dodds (leigh.dodds@talis.com)
11
+
12
+ == Download
13
+
14
+ http://github.com/ldodds/redis-load
15
+
16
+ == Installation
17
+
18
+ redis-load is available as a gem:
19
+
20
+ sudo gem install redis-load
21
+
22
+ It has dependencies on the ruby redis library, json/pure and siren
23
+
24
+ If you grab a copy from github then there's an install target in the Rakefile that will build and install the gem
25
+
26
+ == Usage
27
+
28
+ The command-line app is called redis-load. You need to provide it with a file name and generally
29
+ a key to be populated:
30
+
31
+ Load the contents of a json file as entries into a server
32
+
33
+ redis-load load-json --file myfile.json
34
+
35
+ Load the contents of a file as key-value pairs. Must be: key,value
36
+
37
+ redis-load load-keys --file mykeys.txt
38
+
39
+ Load the contents of a file into a list. Each line is a list entry
40
+
41
+ redis-load load-list --key mylist --file mylist.txt
42
+
43
+ Load the contents of a file into a set. Each line is a set entry
44
+
45
+ redis-load load-set --key myset --file myset.txt
46
+
47
+ Load the contents of a file into a sort set. Each line is a key-value pair of entry,score
48
+
49
+ redis-load load-zset --key myzset --file myzset.txt
50
+
51
+ Save a list into a file
52
+
53
+ redis-load save-list --key mylist --file mylist.txt
54
+
55
+ Save a set into a file
56
+
57
+ redis-load save-set --key myset --file myset.txt
58
+
59
+ Save a sorted set into a file
60
+
61
+ redis-load save-zset --key myzset --file myzset.txt
62
+
63
+ Note that when saving a file any existing file will automatically be over-written.
64
+
data/Rakefile ADDED
@@ -0,0 +1,66 @@
1
+ require 'rake'
2
+ require 'rake/gempackagetask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/testtask'
5
+ require 'rake/clean'
6
+
7
+ NAME = "redis-load"
8
+ VER = "0.1"
9
+
10
+ RDOC_OPTS = ['--quiet', '--title', 'redis-load Reference', '--main', 'README']
11
+
12
+ PKG_FILES = %w( README Rakefile CHANGES ) +
13
+ Dir.glob("{bin,doc,tests,examples,lib}/**/*")
14
+
15
+ CLEAN.include ['*.gem', 'pkg']
16
+ SPEC =
17
+ Gem::Specification.new do |s|
18
+ s.name = NAME
19
+ s.version = VER
20
+ s.platform = Gem::Platform::RUBY
21
+ s.required_ruby_version = ">= 1.8.5"
22
+ s.has_rdoc = true
23
+ s.extra_rdoc_files = ["README", "CHANGES"]
24
+ s.rdoc_options = RDOC_OPTS
25
+ s.summary = "Utility of loading/saving data structures from Redis"
26
+ s.description = s.summary
27
+ s.author = "Leigh Dodds"
28
+ s.email = 'leigh.dodds@talis.com'
29
+ s.homepage = 'http://github.org/ldodds/redis-load'
30
+ #s.rubyforge_project = ''
31
+ s.files = PKG_FILES
32
+ s.require_path = "lib"
33
+ s.bindir = "bin"
34
+ s.executables = ["redis-load"]
35
+ s.test_file = "tests/ts_redis-load.rb"
36
+ s.add_dependency("redis")
37
+ s.add_dependency("json_pure")
38
+ s.add_dependency("siren")
39
+ end
40
+
41
+ Rake::GemPackageTask.new(SPEC) do |pkg|
42
+ pkg.need_tar = true
43
+ end
44
+
45
+ Rake::RDocTask.new do |rdoc|
46
+ rdoc.rdoc_dir = 'doc/rdoc'
47
+ rdoc.options += RDOC_OPTS
48
+ rdoc.rdoc_files.include("README", "CHANGES", "lib/**/*.rb")
49
+ rdoc.main = "README"
50
+
51
+ end
52
+
53
+ Rake::TestTask.new do |test|
54
+ test.test_files = FileList['tests/tc_*.rb']
55
+ end
56
+
57
+ desc "Install from a locally built copy of the gem"
58
+ task :install do
59
+ sh %{rake package}
60
+ sh %{sudo gem install pkg/#{NAME}-#{VER}}
61
+ end
62
+
63
+ desc "Uninstall the gem"
64
+ task :uninstall => [:clean] do
65
+ sh %{sudo gem uninstall #{NAME}}
66
+ end
data/bin/redis-load ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'redis-load'
4
+
5
+ require 'rubygems'
6
+ require 'redis'
7
+ require 'getoptlong'
8
+
9
+ PROGRAM = File::basename $0
10
+
11
+ USAGE = <<-EOL
12
+ SYNOPSIS
13
+
14
+ #{ PROGRAM } mode [args]*
15
+
16
+ DESCRIPTION
17
+
18
+ MODE
19
+
20
+ load-json
21
+ Load the contents of a json file as entries into a server
22
+
23
+ load-keys
24
+ Load the contents of a file as key-value pairs. Must be: key,value
25
+
26
+ load-list
27
+ Load the contents of a file into a list. Each line is a list entry
28
+
29
+ load-set
30
+ Load the contents of a file into a set. Each line is a set entry
31
+
32
+ load-zset
33
+ Load the contents of a file into a sort set. Each line is a key-value pair of entry,score
34
+
35
+ save-list
36
+ Save a list into a file
37
+
38
+ save-set
39
+ Save a set into a file
40
+
41
+ save-zset
42
+ Save a sorted set into a file
43
+
44
+
45
+ OPTIONS
46
+
47
+ --database , -d
48
+ specify database
49
+ --help , -?
50
+ show this message
51
+ --host , -h
52
+ specify host on which server is running
53
+ --file , -f
54
+ path to file containing the data to load
55
+ --password , -x
56
+ specify password to access server
57
+ --port , -p
58
+ specify port on which server is running
59
+ --key , -k
60
+ specify a key into which data is loaded
61
+
62
+ EOL
63
+
64
+ mode = ARGV.shift
65
+
66
+ opts = GetoptLong::new(
67
+ [ "--help" , "-?" , GetoptLong::NO_ARGUMENT ],
68
+ [ "--host" , "-h" , GetoptLong::REQUIRED_ARGUMENT ],
69
+ [ "--port" , "-p" , GetoptLong::REQUIRED_ARGUMENT ],
70
+ [ "--password" , "-x" , GetoptLong::REQUIRED_ARGUMENT ],
71
+ [ "--database" , "-d" , GetoptLong::REQUIRED_ARGUMENT ],
72
+ [ "--key" , "-k" , GetoptLong::REQUIRED_ARGUMENT ],
73
+ [ "--file" , "-f" , GetoptLong::REQUIRED_ARGUMENT ],
74
+ [ "--jsonpath" , "-j" , GetoptLong::REQUIRED_ARGUMENT ]
75
+ ).enum_for.inject({}) { |h, (k, v)| h.update k.delete('-') => v }
76
+
77
+ mode = "help" if opts["--help"]
78
+
79
+ if mode == "help"
80
+ USAGE.display
81
+ else
82
+
83
+ if opts["file"] == nil
84
+ abort USAGE
85
+ end
86
+
87
+ if (mode != "load-json" && mode != "load-keys") && opts["key"] == nil
88
+ abort USAGE
89
+ end
90
+
91
+ cmdline = RedisLoad::CommandLine.new(opts, ENV)
92
+
93
+ case mode
94
+ when "load-json"
95
+ cmdline.load_json()
96
+ when "load-keys"
97
+ cmdline.load_keys()
98
+ when "load-list"
99
+ cmdline.load_list()
100
+ when "load-set"
101
+ cmdline.load_set()
102
+ when "load-zset"
103
+ cmdline.load_zset()
104
+ when "save-list"
105
+ cmdline.save_list()
106
+ when "save-set"
107
+ cmdline.save_set()
108
+ when "save-zset"
109
+ cmdline.save_zset()
110
+ else
111
+ puts "Unknown command"
112
+ end
113
+ end
114
+
data/lib/redis-load.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'redis'
3
+ require 'json/pure'
4
+ require 'siren'
5
+
6
+ require 'redis-load/command_line.rb'
7
+ require 'redis-load/loader.rb'
@@ -0,0 +1,71 @@
1
+ module RedisLoad
2
+
3
+ #This class acts as an adapter, taking parameters and environment variables and
4
+ #using those to drive an instance of RedisLoad::Loader
5
+ class CommandLine
6
+
7
+ def initialize(opts, env)
8
+ @opts = opts
9
+ @env = env
10
+
11
+ opts = Hash.new
12
+ opts[:host] = @opts["host"] if @opts["host"]
13
+ opts[:port] = @opts["port"] if @opts["port"]
14
+ opts[:db] = @opts["database"] if @opts["database"]
15
+ opts[:password] = @opts["password"] if @opts["password"]
16
+
17
+ @redis = Redis.new(opts)
18
+ @loader = RedisLoad::Loader.new(@redis)
19
+
20
+ end
21
+
22
+ def load_json()
23
+ puts "Loading data from JSON file #{@opts["file"]} into server"
24
+ counter = @loader.load_json( @opts["file"], @opts["jsonpath"] )
25
+ puts "#{counter} keys loaded."
26
+ end
27
+
28
+ def load_list()
29
+ puts "Loading #{@opts["file"]} into list #{@opts["key"]} into server"
30
+ counter = @loader.load_list( @opts["key"] , @opts["file"] )
31
+ puts "#{counter} lines loaded."
32
+ end
33
+
34
+ def save_list()
35
+ puts "Saving list #{@opts["key"]} into #{@opts["file"]}"
36
+ size = @loader.save_list( @opts["key"], @opts["file"] )
37
+ puts "#{size} lines saved."
38
+ end
39
+
40
+ def load_keys()
41
+ puts "Loading keys from #{@opts["file"]} into server"
42
+ counter = @loader.load_keys( @opts["file"] )
43
+ puts "#{counter} lines loaded."
44
+ end
45
+
46
+ def load_set()
47
+ puts "Loading #{@opts["file"]} into set #{@opts["key"]} on server"
48
+ counter @loader.load_set( @opts["key"], @opts["file"] )
49
+ puts "#{counter} lines loaded."
50
+ end
51
+
52
+ def save_set()
53
+ puts "Saving set #{@opts["key"]} into #{@opts["file"]}"
54
+ size = @loader.save_set( @opts["key"], @opts["file"] )
55
+ puts "#{size} items saved."
56
+ end
57
+
58
+ def load_zset()
59
+ puts "Loading #{@opts["file"]} into sorted set #{@opts["key"]} on server"
60
+ counter = @loader.load_zset( @opts["key"], @opts["file"] )
61
+ puts "#{counter} items loaded."
62
+ end
63
+
64
+ def save_zset()
65
+ puts "Saving set #{@opts["key"]} into #{@opts["file"]}"
66
+ size = @loader.save_zset( @opts["key"], @opts["file"] )
67
+ puts "#{size} items saved."
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,136 @@
1
+ module RedisLoad
2
+
3
+ #Exposes support for loading and saving different types of redis data
4
+ #structures to and from files
5
+ class Loader
6
+
7
+ attr_reader :redis
8
+
9
+ def initialize(redis)
10
+ @redis = redis
11
+ end
12
+
13
+ def load_keys(file)
14
+ f = File.new( file )
15
+ counter = process_lines(f) do |redis,line|
16
+ line = line.chomp
17
+ parts = line.split(",")
18
+ redis.set( parts[0], parts[1] )
19
+ end
20
+ return counter
21
+ end
22
+
23
+ #Load the contents of a JSON file into Redis
24
+ #
25
+ #Each key in the JSON file becomes a redis key. If the value is a literal then this is added
26
+ #as a redis key-value pair. If an array, then a List. If a hash, then a Hash.
27
+ #
28
+ #Nested objects will be flattened.
29
+ #
30
+ # file:: json file
31
+ # path:: optional, path in the json file indicating the subsection to load
32
+ def load_json(file, path=nil)
33
+ f = File.new( file )
34
+ json = JSON.parse( f.read )
35
+ if path != nil
36
+ json = Siren.query(query, json)
37
+ end
38
+ counter = 0
39
+ #TODO could support proper results, not just path?
40
+ if json != nil
41
+ json.each_pair do |key,value|
42
+ if value.class() == Array
43
+ value.each do |v|
44
+ @redis.lpush( key, v )
45
+ end
46
+ elsif value.class == Hash
47
+ value.each_pair do |field, v|
48
+ #TODO better handling of nesting?
49
+ #E.g. convert hash or array back into JSON?
50
+ @redis.hset(key, field, v)
51
+ end
52
+ else
53
+ @redis.set(key, value)
54
+ end
55
+ counter = counter + 1
56
+ end
57
+ end
58
+ return counter
59
+ end
60
+
61
+ #Load the contents of a file into a Redis list
62
+ #
63
+ # key:: name of the list
64
+ # file:: name of file (string)
65
+ def load_list(key, file)
66
+ f = File.new( file )
67
+ counter = process_lines(f) do |redis,line|
68
+ redis.lpush( key , line.chomp)
69
+ end
70
+ return counter
71
+ end
72
+
73
+ def load_set(key, file)
74
+ f = File.new( file )
75
+ counter = process_lines(f) do |redis,line|
76
+ redis.sadd( key , line.chomp)
77
+ end
78
+ return counter
79
+ end
80
+
81
+ def load_zset(key, file)
82
+ f = File.new( file )
83
+ counter = process_lines(f) do |redis,line|
84
+ line = line.chomp
85
+ parts = line.split(",")
86
+ redis.set( key , parts[1], parts[0] )
87
+ end
88
+ return counter
89
+ end
90
+
91
+ def save_list(key, file)
92
+ size = @redis.llen( key )
93
+ count = 0
94
+ File.open( file , "w") do |file|
95
+ while (count < size)
96
+ file.puts( @redis.lindex(key , count) )
97
+ count = count + 1
98
+ end
99
+ end
100
+ return size
101
+ end
102
+
103
+ def save_set(key, file)
104
+ members = @redis.smembers( key )
105
+ File.open( file , "w") do |file|
106
+ members.each do |m|
107
+ file.puts(m)
108
+ end
109
+ end
110
+ return members.length
111
+ end
112
+
113
+ def save_zset(key, file)
114
+ members = @redis.zrange( key , 0, -1, :with_scores => true)
115
+ File.open( file , "w") do |file|
116
+ members.each_slice(2) do |member,value|
117
+ file.puts("#{member},#{value}")
118
+ end
119
+ end
120
+ return members.length/2
121
+ end
122
+
123
+ #Process lines
124
+ #
125
+ # io:: IO Object
126
+ def process_lines(io)
127
+ counter = 0
128
+ io.each_line do |line|
129
+ yield @redis, line
130
+ counter = counter + 1
131
+ end
132
+ return counter
133
+ end
134
+
135
+ end
136
+ end
@@ -0,0 +1,2 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require 'test/unit'
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redis-load
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ version: "0.1"
10
+ platform: ruby
11
+ authors:
12
+ - Leigh Dodds
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-22 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: redis
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: json_pure
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: siren
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :runtime
61
+ version_requirements: *id003
62
+ description: Utility of loading/saving data structures from Redis
63
+ email: leigh.dodds@talis.com
64
+ executables:
65
+ - redis-load
66
+ extensions: []
67
+
68
+ extra_rdoc_files:
69
+ - README
70
+ - CHANGES
71
+ files:
72
+ - README
73
+ - Rakefile
74
+ - CHANGES
75
+ - bin/redis-load
76
+ - tests/ts_redis-load.rb
77
+ - lib/redis-load.rb
78
+ - lib/redis-load/command_line.rb
79
+ - lib/redis-load/loader.rb
80
+ has_rdoc: true
81
+ homepage: http://github.org/ldodds/redis-load
82
+ licenses: []
83
+
84
+ post_install_message:
85
+ rdoc_options:
86
+ - --quiet
87
+ - --title
88
+ - redis-load Reference
89
+ - --main
90
+ - README
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 61
99
+ segments:
100
+ - 1
101
+ - 8
102
+ - 5
103
+ version: 1.8.5
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: 3
110
+ segments:
111
+ - 0
112
+ version: "0"
113
+ requirements: []
114
+
115
+ rubyforge_project:
116
+ rubygems_version: 1.3.7
117
+ signing_key:
118
+ specification_version: 3
119
+ summary: Utility of loading/saving data structures from Redis
120
+ test_files:
121
+ - tests/ts_redis-load.rb