jchris-couchrest 0.9.2 → 0.9.3
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/bin/couchview +40 -101
- data/lib/couch_rest.rb +1 -1
- data/lib/couch_rest/commands.rb +5 -0
- data/lib/couch_rest/commands/generate.rb +71 -0
- data/lib/couch_rest/commands/push.rb +99 -0
- data/lib/couchrest.rb +18 -0
- data/lib/file_manager.rb +35 -208
- metadata +5 -2
data/bin/couchview
CHANGED
@@ -1,111 +1,50 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
require 'optparse'
|
4
|
+
require File.dirname(__FILE__) + "/../lib/couch_rest/commands"
|
5
|
+
|
6
|
+
# Set defaults
|
7
|
+
options = {
|
8
|
+
:loud => true,
|
9
|
+
}
|
10
|
+
|
11
|
+
opts = OptionParser.new do |opts|
|
12
|
+
opts.banner = "Usage: #$0 [options] (push|generate) directory database"
|
13
|
+
opts.on('-q', '--quiet', "Omit extra debug info") do
|
14
|
+
options[:loud] = false
|
15
|
+
end
|
16
|
+
opts.on_tail('-h', '--help [push|generate]', "Display detailed help and exit") do |help_command|
|
17
|
+
puts opts
|
18
|
+
case help_command
|
19
|
+
when "push"
|
20
|
+
puts CouchRest::Commands::Push.help
|
21
|
+
when "generate"
|
22
|
+
puts CouchRest::Commands::Generate.help
|
23
|
+
end
|
24
|
+
exit
|
25
|
+
end
|
12
26
|
end
|
27
|
+
opts.parse!(ARGV)
|
13
28
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
puts <<-GEN
|
18
|
-
Usage: couchview generate directory design1 design2 design3 ...
|
19
|
-
|
20
|
-
Couchview will create directories and example views for the design documents you specify.
|
21
|
-
|
22
|
-
GEN
|
23
|
-
when "push"
|
24
|
-
puts <<-PUSH
|
25
|
-
== Pushing views with Couchview ==
|
26
|
-
|
27
|
-
Usage: couchview push directory dbname
|
28
|
-
|
29
|
-
Couchview expects a specific filesystem layout for your CouchDB views (see
|
30
|
-
example below). It also supports advanced features like inlining of library
|
31
|
-
code (so you can keep DRY) as well as avoiding unnecessary document
|
32
|
-
modification.
|
33
|
-
|
34
|
-
Couchview also solves a problem with CouchDB's view API, which only provides
|
35
|
-
access to the final reduce side of any views which have both a map and a
|
36
|
-
reduce function defined. The intermediate map results are often useful for
|
37
|
-
development and production. CouchDB is smart enough to reuse map indexes for
|
38
|
-
functions duplicated across views within the same design document.
|
39
|
-
|
40
|
-
For views with a reduce function defined, Couchview creates both a reduce view
|
41
|
-
and a map-only view, so that you can browse and query the map side as well as
|
42
|
-
the reduction, with no performance penalty.
|
43
|
-
|
44
|
-
== Example ==
|
45
|
-
|
46
|
-
couchview push foo-project/bar-views baz-database
|
29
|
+
options[:command] = ARGV.shift
|
30
|
+
options[:directory] = ARGV.shift
|
31
|
+
options[:trailing_args] = ARGV
|
47
32
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
foo-project/bar-views/my-design/viewname-map.js
|
53
|
-
foo-project/bar-views/my-design/viewname-reduce.js
|
54
|
-
foo-project/bar-views/my-design/noreduce-map.js
|
55
|
-
|
56
|
-
Pushed to => http://localhost:5984/baz-database/_design/my-design
|
57
|
-
|
58
|
-
And the design document:
|
59
|
-
{
|
60
|
-
"views" : {
|
61
|
-
"viewname-map" : {
|
62
|
-
"map" : "### contents of view-name-map.js ###"
|
63
|
-
},
|
64
|
-
"viewname-reduce" : {
|
65
|
-
"map" : "### contents of view-name-map.js ###",
|
66
|
-
"reduce" : "### contents of view-name-reduce.js ###"
|
67
|
-
},
|
68
|
-
"noreduce-map" : {
|
69
|
-
"map" : "### contents of noreduce-map.js ###"
|
70
|
-
}
|
71
|
-
}
|
72
|
-
}
|
73
|
-
|
74
|
-
Couchview will create a design document for each subdirectory of the views
|
75
|
-
directory specified on the command line.
|
76
|
-
|
77
|
-
== Library Inlining ==
|
78
|
-
|
79
|
-
Couchview can optionally inline library code into your views so you only have
|
80
|
-
to maintain it in one place. It looks for any files named lib.* in your
|
81
|
-
design-doc directory (for doc specific libs) and in the parent views directory
|
82
|
-
(for project global libs). These libraries are only inserted into views which
|
83
|
-
include the text
|
84
|
-
|
85
|
-
//include-lib
|
86
|
-
|
87
|
-
or
|
88
|
-
|
89
|
-
#include-lib
|
90
|
-
|
91
|
-
Couchview is a result of scratching my own itch. I'd be happy to make it more
|
92
|
-
general, so please contact me at jchris@grabb.it if you'd like to see anything
|
93
|
-
added or changed.
|
94
|
-
PUSH
|
95
|
-
end
|
33
|
+
# There must be a better way to check for extra required args
|
34
|
+
unless (["push", "generate"].include?(options[:command]) && options[:directory] && options[:trailing_args])
|
35
|
+
puts(opts)
|
96
36
|
exit
|
97
37
|
end
|
98
38
|
|
99
|
-
|
100
|
-
|
39
|
+
# The options hash now contains the resolved defaults
|
40
|
+
# and the overrides from the command line.
|
41
|
+
|
42
|
+
# Call your class and send it the options here
|
43
|
+
# cr = CouchRest::FileManager.new(options[:database_name])
|
101
44
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
puts "Pushing views from directory #{dirname} to database #{fm.db}"
|
108
|
-
fm.push_views(dirname)
|
109
|
-
elsif command == 'generate'
|
110
|
-
puts "Under construction ;)"
|
45
|
+
case options[:command]
|
46
|
+
when "push"
|
47
|
+
CouchRest::Commands::Push.run(options)
|
48
|
+
when "generate"
|
49
|
+
CouchRest::Commands::Generate.run(options)
|
111
50
|
end
|
data/lib/couch_rest.rb
CHANGED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
class CouchRest
|
4
|
+
module Commands
|
5
|
+
module Generate
|
6
|
+
|
7
|
+
def self.run(options)
|
8
|
+
directory = options[:directory]
|
9
|
+
design_names = options[:trailing_args]
|
10
|
+
|
11
|
+
FileUtils.mkdir_p(directory)
|
12
|
+
filename = File.join(directory, "lib.js")
|
13
|
+
self.write(filename, <<-FUNC)
|
14
|
+
// Put global functions here.
|
15
|
+
// Include in your views with
|
16
|
+
//
|
17
|
+
// //include-lib
|
18
|
+
FUNC
|
19
|
+
|
20
|
+
design_names.each do |design_name|
|
21
|
+
subdirectory = File.join(directory, design_name)
|
22
|
+
FileUtils.mkdir_p(subdirectory)
|
23
|
+
filename = File.join(subdirectory, "sample-map.js")
|
24
|
+
self.write(filename, <<-FUNC)
|
25
|
+
function(doc) {
|
26
|
+
// Keys is first letter of _id
|
27
|
+
emit(doc._id[0], doc);
|
28
|
+
}
|
29
|
+
FUNC
|
30
|
+
|
31
|
+
filename = File.join(subdirectory, "sample-reduce.js")
|
32
|
+
self.write(filename, <<-FUNC)
|
33
|
+
function(keys, values) {
|
34
|
+
// Count the number of keys starting with this letter
|
35
|
+
return values.length;
|
36
|
+
}
|
37
|
+
FUNC
|
38
|
+
|
39
|
+
filename = File.join(subdirectory, "lib.js")
|
40
|
+
self.write(filename, <<-FUNC)
|
41
|
+
// Put functions specific to '#{design_name}' here.
|
42
|
+
// Include in your views with
|
43
|
+
//
|
44
|
+
// //include-lib
|
45
|
+
FUNC
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.help
|
50
|
+
helpstring = <<-GEN
|
51
|
+
|
52
|
+
Usage: couchview generate directory design1 design2 design3 ...
|
53
|
+
|
54
|
+
Couchview will create directories and example views for the design documents you specify.
|
55
|
+
|
56
|
+
GEN
|
57
|
+
helpstring.gsub(/^ /, '')
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.write(filename, contents)
|
61
|
+
puts "Writing #{filename}"
|
62
|
+
File.open(filename, "w") do |f|
|
63
|
+
# Remove leading spaces
|
64
|
+
contents.gsub!(/^ ( )?/, '')
|
65
|
+
f.write contents
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
class CouchRest
|
2
|
+
|
3
|
+
module Commands
|
4
|
+
|
5
|
+
module Push
|
6
|
+
|
7
|
+
def self.run(options)
|
8
|
+
directory = options[:directory]
|
9
|
+
database = options[:trailing_args].first
|
10
|
+
|
11
|
+
fm = CouchRest::FileManager.new(database)
|
12
|
+
fm.loud = options[:loud]
|
13
|
+
puts "Pushing views from directory #{directory} to database #{fm.db}"
|
14
|
+
fm.push_views(directory)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.help
|
18
|
+
helpstring = <<-GEN
|
19
|
+
|
20
|
+
== Pushing views with Couchview ==
|
21
|
+
|
22
|
+
Usage: couchview push directory dbname
|
23
|
+
|
24
|
+
Couchview expects a specific filesystem layout for your CouchDB views (see
|
25
|
+
example below). It also supports advanced features like inlining of library
|
26
|
+
code (so you can keep DRY) as well as avoiding unnecessary document
|
27
|
+
modification.
|
28
|
+
|
29
|
+
Couchview also solves a problem with CouchDB's view API, which only provides
|
30
|
+
access to the final reduce side of any views which have both a map and a
|
31
|
+
reduce function defined. The intermediate map results are often useful for
|
32
|
+
development and production. CouchDB is smart enough to reuse map indexes for
|
33
|
+
functions duplicated across views within the same design document.
|
34
|
+
|
35
|
+
For views with a reduce function defined, Couchview creates both a reduce view
|
36
|
+
and a map-only view, so that you can browse and query the map side as well as
|
37
|
+
the reduction, with no performance penalty.
|
38
|
+
|
39
|
+
== Example ==
|
40
|
+
|
41
|
+
couchview push foo-project/bar-views baz-database
|
42
|
+
|
43
|
+
This will push the views defined in foo-project/bar-views into a database
|
44
|
+
called baz-database. Couchview expects the views to be defined in files with
|
45
|
+
names like:
|
46
|
+
|
47
|
+
foo-project/bar-views/my-design/viewname-map.js
|
48
|
+
foo-project/bar-views/my-design/viewname-reduce.js
|
49
|
+
foo-project/bar-views/my-design/noreduce-map.js
|
50
|
+
|
51
|
+
Pushed to => http://localhost:5984/baz-database/_design/my-design
|
52
|
+
|
53
|
+
And the design document:
|
54
|
+
{
|
55
|
+
"views" : {
|
56
|
+
"viewname-map" : {
|
57
|
+
"map" : "### contents of view-name-map.js ###"
|
58
|
+
},
|
59
|
+
"viewname-reduce" : {
|
60
|
+
"map" : "### contents of view-name-map.js ###",
|
61
|
+
"reduce" : "### contents of view-name-reduce.js ###"
|
62
|
+
},
|
63
|
+
"noreduce-map" : {
|
64
|
+
"map" : "### contents of noreduce-map.js ###"
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
Couchview will create a design document for each subdirectory of the views
|
70
|
+
directory specified on the command line.
|
71
|
+
|
72
|
+
== Library Inlining ==
|
73
|
+
|
74
|
+
Couchview can optionally inline library code into your views so you only have
|
75
|
+
to maintain it in one place. It looks for any files named lib.* in your
|
76
|
+
design-doc directory (for doc specific libs) and in the parent views directory
|
77
|
+
(for project global libs). These libraries are only inserted into views which
|
78
|
+
include the text
|
79
|
+
|
80
|
+
//include-lib
|
81
|
+
|
82
|
+
or
|
83
|
+
|
84
|
+
#include-lib
|
85
|
+
|
86
|
+
Couchview is a result of scratching my own itch. I'd be happy to make it more
|
87
|
+
general, so please contact me at jchris@grabb.it if you'd like to see anything
|
88
|
+
added or changed.
|
89
|
+
|
90
|
+
GEN
|
91
|
+
helpstring.gsub(/^ /, '')
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
data/lib/couchrest.rb
CHANGED
@@ -8,4 +8,22 @@ require File.dirname(__FILE__) + '/pager'
|
|
8
8
|
require File.dirname(__FILE__) + '/file_manager'
|
9
9
|
require File.dirname(__FILE__) + '/streamer'
|
10
10
|
|
11
|
+
# this has to come after the JSON gem
|
11
12
|
|
13
|
+
# this date format sorts lexicographically
|
14
|
+
# and is compatible with Javascript's new Date(time_string) constructor
|
15
|
+
# note that sorting will break if you store times from multiple timezones
|
16
|
+
# I like to add a ENV['TZ'] = 'UTC' to my apps
|
17
|
+
class Time
|
18
|
+
def to_json(options = nil)
|
19
|
+
%("#{strftime("%Y/%m/%d %H:%M:%S %z")}")
|
20
|
+
end
|
21
|
+
# this works to decode the outputted time format
|
22
|
+
# from ActiveSupport
|
23
|
+
# def self.parse string, fallback=nil
|
24
|
+
# d = DateTime.parse(string).new_offset
|
25
|
+
# self.utc(d.year, d.month, d.day, d.hour, d.min, d.sec)
|
26
|
+
# rescue
|
27
|
+
# fallback
|
28
|
+
# end
|
29
|
+
end
|
data/lib/file_manager.rb
CHANGED
@@ -84,7 +84,7 @@ class CouchRest
|
|
84
84
|
|
85
85
|
doc["_attachments"][path] = {
|
86
86
|
"data" => content,
|
87
|
-
"content_type" =>
|
87
|
+
"content_type" => MIMES[path.split('.').last]
|
88
88
|
}
|
89
89
|
end
|
90
90
|
|
@@ -151,6 +151,40 @@ class CouchRest
|
|
151
151
|
designs
|
152
152
|
end
|
153
153
|
|
154
|
+
def pull_views(view_dir)
|
155
|
+
prefix = "_design"
|
156
|
+
ds = db.documents(:startkey => '#{prefix}/', :endkey => '#{prefix}/ZZZZZZZZZ')
|
157
|
+
ds['rows'].collect{|r|r['id']}.each do |id|
|
158
|
+
puts directory = id.split('/').last
|
159
|
+
FileUtils.mkdir_p(File.join(view_dir,directory))
|
160
|
+
views = db.get(id)['views']
|
161
|
+
|
162
|
+
vgroups = views.keys.group_by{|k|k.sub(/\-(map|reduce)$/,'')}
|
163
|
+
vgroups.each do|g,vs|
|
164
|
+
mapname = vs.find {|v|views[v]["map"]}
|
165
|
+
if mapname
|
166
|
+
# save map
|
167
|
+
mapfunc = views[mapname]["map"]
|
168
|
+
mapfile = File.join(view_dir, directory, "#{g}-map.js") # todo support non-js views
|
169
|
+
File.open(mapfile,'w') do |f|
|
170
|
+
f.write mapfunc
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
reducename = vs.find {|v|views[v]["reduce"]}
|
175
|
+
if reducename
|
176
|
+
# save reduce
|
177
|
+
reducefunc = views[reducename]["reduce"]
|
178
|
+
reducefile = File.join(view_dir, directory, "#{g}-reduce.js") # todo support non-js views
|
179
|
+
File.open(reducefile,'w') do |f|
|
180
|
+
f.write reducefunc
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
154
188
|
|
155
189
|
private
|
156
190
|
|
@@ -187,210 +221,3 @@ class CouchRest
|
|
187
221
|
end
|
188
222
|
end
|
189
223
|
end
|
190
|
-
|
191
|
-
__END__
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
# parse the file structure to load the public files, controllers, and views into a hash with the right shape for coucdb
|
197
|
-
couch = {}
|
198
|
-
|
199
|
-
couch["public"] = Dir["#{File.expand_path(File.dirname("."))}/public/**/*.*"].collect do |f|
|
200
|
-
{f.split("public/").last => open(f).read}
|
201
|
-
end
|
202
|
-
|
203
|
-
couch["controllers"] = {}
|
204
|
-
Dir["#{File.expand_path(File.dirname("."))}/app/controllers/**/*.*"].collect do |c|
|
205
|
-
path_parts = c.split("/")
|
206
|
-
|
207
|
-
controller_name = path_parts[path_parts.length - 2]
|
208
|
-
action_name = path_parts[path_parts.length - 1].split(".").first
|
209
|
-
|
210
|
-
couch["controllers"][controller_name] ||= {"actions" => {}}
|
211
|
-
couch["controllers"][controller_name]["actions"][action_name] = open(c).read
|
212
|
-
|
213
|
-
end
|
214
|
-
|
215
|
-
couch["designs"] = {}
|
216
|
-
Dir["#{File.expand_path(File.dirname("."))}/app/views/**/*.*"].collect do |design_doc|
|
217
|
-
design_doc_parts = design_doc.split('/')
|
218
|
-
pre_normalized_view_name = design_doc_parts.last.split("-")
|
219
|
-
view_name = pre_normalized_view_name[0..pre_normalized_view_name.length-2].join("-")
|
220
|
-
|
221
|
-
folder = design_doc.split("app/views").last.split("/")[1]
|
222
|
-
|
223
|
-
couch["designs"][folder] ||= {}
|
224
|
-
couch["designs"][folder]["views"] ||= {}
|
225
|
-
couch["designs"][folder]["language"] ||= LANGS[design_doc_parts.last.split(".").last]
|
226
|
-
|
227
|
-
if design_doc_parts.last =~ /-map/
|
228
|
-
couch["designs"][folder]["views"]["#{view_name}-map"] ||= {}
|
229
|
-
|
230
|
-
couch["designs"][folder]["views"]["#{view_name}-map"]["map"] = open(design_doc).read
|
231
|
-
|
232
|
-
couch["designs"][folder]["views"]["#{view_name}-reduce"] ||= {}
|
233
|
-
couch["designs"][folder]["views"]["#{view_name}-reduce"]["map"] = open(design_doc).read
|
234
|
-
end
|
235
|
-
|
236
|
-
if design_doc_parts.last =~ /-reduce/
|
237
|
-
couch["designs"][folder]["views"]["#{view_name}-reduce"] ||= {}
|
238
|
-
|
239
|
-
couch["designs"][folder]["views"]["#{view_name}-reduce"]["reduce"] = open(design_doc).read
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
# cleanup empty maps and reduces
|
244
|
-
couch["designs"].each do |name, props|
|
245
|
-
props["views"].delete("#{name}-reduce") unless props["views"]["#{name}-reduce"].keys.include?("reduce")
|
246
|
-
end
|
247
|
-
|
248
|
-
# parsing done, begin posting
|
249
|
-
|
250
|
-
# connect to couchdb
|
251
|
-
cr = CouchRest.new("http://localhost:5984")
|
252
|
-
@db = cr.database(DBNAME)
|
253
|
-
|
254
|
-
def create_or_update(id, fields)
|
255
|
-
existing = get(id)
|
256
|
-
|
257
|
-
if existing
|
258
|
-
updated = fields.merge({"_id" => id, "_rev" => existing["_rev"]})
|
259
|
-
else
|
260
|
-
puts "saving #{id}"
|
261
|
-
save(fields.merge({"_id" => id}))
|
262
|
-
end
|
263
|
-
|
264
|
-
if existing == updated
|
265
|
-
puts "no change to #{id}. skipping..."
|
266
|
-
else
|
267
|
-
puts "replacing #{id}"
|
268
|
-
save(updated)
|
269
|
-
end
|
270
|
-
|
271
|
-
end
|
272
|
-
|
273
|
-
def get(id)
|
274
|
-
doc = handle_errors do
|
275
|
-
@db.get(id)
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
def save(doc)
|
280
|
-
handle_errors do
|
281
|
-
@db.save(doc)
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
def handle_errors(&block)
|
286
|
-
begin
|
287
|
-
yield
|
288
|
-
rescue Exception => e
|
289
|
-
# puts e.message
|
290
|
-
nil
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
|
295
|
-
if todo.include? "views"
|
296
|
-
puts "posting views into CouchDB"
|
297
|
-
couch["designs"].each do |k,v|
|
298
|
-
create_or_update("_design/#{k}", v)
|
299
|
-
end
|
300
|
-
puts
|
301
|
-
end
|
302
|
-
|
303
|
-
if todo.include? "controllers"
|
304
|
-
puts "posting controllers into CouchDB"
|
305
|
-
couch["controllers"].each do |k,v|
|
306
|
-
create_or_update("controller/#{k}", v)
|
307
|
-
end
|
308
|
-
puts
|
309
|
-
end
|
310
|
-
|
311
|
-
|
312
|
-
if todo.include? "public"
|
313
|
-
puts "posting public docs into CouchDB"
|
314
|
-
|
315
|
-
if couch["public"].empty?
|
316
|
-
puts "no docs in public"; exit
|
317
|
-
end
|
318
|
-
|
319
|
-
@content_types = {
|
320
|
-
"html" => "text/html",
|
321
|
-
"htm" => "text/html",
|
322
|
-
"png" => "image/png",
|
323
|
-
"css" => "text/css",
|
324
|
-
"js" => "test/javascript"
|
325
|
-
}
|
326
|
-
|
327
|
-
def md5 string
|
328
|
-
Digest::MD5.hexdigest(string)
|
329
|
-
end
|
330
|
-
|
331
|
-
@attachments = {}
|
332
|
-
@signatures = {}
|
333
|
-
couch["public"].each do |doc|
|
334
|
-
@signatures[doc.keys.first] = md5(doc.values.first)
|
335
|
-
|
336
|
-
@attachments[doc.keys.first] = {
|
337
|
-
"data" => doc.values.first,
|
338
|
-
"content_type" => @content_types[doc.keys.first.split('.').last]
|
339
|
-
}
|
340
|
-
end
|
341
|
-
|
342
|
-
doc = get("public")
|
343
|
-
|
344
|
-
unless doc
|
345
|
-
puts "creating public"
|
346
|
-
@db.save({"_id" => "public", "_attachments" => @attachments, "signatures" => @signatures})
|
347
|
-
exit
|
348
|
-
end
|
349
|
-
|
350
|
-
# remove deleted docs
|
351
|
-
to_be_removed = doc["signatures"].keys.select{|d| !couch["public"].collect{|p| p.keys.first}.include?(d) }
|
352
|
-
|
353
|
-
to_be_removed.each do |p|
|
354
|
-
puts "deleting #{p}"
|
355
|
-
doc["signatures"].delete(p)
|
356
|
-
doc["_attachments"].delete(p)
|
357
|
-
end
|
358
|
-
|
359
|
-
# update existing docs:
|
360
|
-
doc["signatures"].each do |path, sig|
|
361
|
-
if (@signatures[path] == sig)
|
362
|
-
puts "no change to #{path}. skipping..."
|
363
|
-
else
|
364
|
-
puts "replacing #{path}"
|
365
|
-
doc["signatures"][path] = md5(@attachments[path]["data"])
|
366
|
-
doc["_attachments"][path].delete("stub")
|
367
|
-
doc["_attachments"][path].delete("length")
|
368
|
-
doc["_attachments"][path]["data"] = @attachments[path]["data"]
|
369
|
-
doc["_attachments"][path].merge!({"data" => @attachments[path]["data"]} )
|
370
|
-
|
371
|
-
end
|
372
|
-
end
|
373
|
-
|
374
|
-
# add in new files
|
375
|
-
new_files = couch["public"].select{|d| !doc["signatures"].keys.include?( d.keys.first) }
|
376
|
-
|
377
|
-
new_files.each do |f|
|
378
|
-
puts "creating #{f}"
|
379
|
-
path = f.keys.first
|
380
|
-
content = f.values.first
|
381
|
-
doc["signatures"][path] = md5(content)
|
382
|
-
|
383
|
-
doc["_attachments"][path] = {
|
384
|
-
"data" => content,
|
385
|
-
"content_type" => @content_types[path.split('.').last]
|
386
|
-
}
|
387
|
-
end
|
388
|
-
|
389
|
-
begin
|
390
|
-
@db.save(doc)
|
391
|
-
rescue Exception => e
|
392
|
-
puts e.message
|
393
|
-
end
|
394
|
-
|
395
|
-
puts
|
396
|
-
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jchris-couchrest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- J. Chris Anderson
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2008-
|
13
|
+
date: 2008-09-10 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -47,6 +47,9 @@ files:
|
|
47
47
|
- lib/pager.rb
|
48
48
|
- lib/file_manager.rb
|
49
49
|
- lib/streamer.rb
|
50
|
+
- lib/couch_rest/commands.rb
|
51
|
+
- lib/couch_rest/commands/generate.rb
|
52
|
+
- lib/couch_rest/commands/push.rb
|
50
53
|
- Rakefile
|
51
54
|
- README.markdown
|
52
55
|
- bin/couchdir
|