160 lines
4.2 KiB
Ruby
Executable file
160 lines
4.2 KiB
Ruby
Executable file
#!/usr/bin/env ruby
|
|
|
|
commands = %w{push generate}
|
|
|
|
command = ARGV[0]
|
|
|
|
if !commands.include?(command)
|
|
puts <<-USAGE
|
|
Couchview has two modes: push and generate. Run couchview push or couchview generate for usage documentation.
|
|
USAGE
|
|
exit
|
|
end
|
|
|
|
if ARGV.length == 1
|
|
case command
|
|
when "generate"
|
|
puts <<-GEN
|
|
|
|
|
|
GEN
|
|
when "push"
|
|
puts <<-PUSH
|
|
== Pushing views with Couchview ==
|
|
|
|
Usage: couchview push directory dbname
|
|
|
|
Couchview expects a specific filesystem layout for your CouchDB views (see
|
|
example below). It also supports advanced features like inlining of library
|
|
code (so you can keep DRY) as well as avoiding unnecessary document
|
|
modification.
|
|
|
|
Couchview also solves a problem with CouchDB's view API, which only provides
|
|
access to the final reduce side of any views which have both a map and a
|
|
reduce function defined. The intermediate map results are often useful for
|
|
development and production. CouchDB is smart enough to reuse map indexes for
|
|
functions duplicated across views within the same design document.
|
|
|
|
For views with a reduce function defined, Couchview creates both a reduce view
|
|
and a map-only view, so that you can browse and query the map side as well as
|
|
the reduction, with no performance penalty.
|
|
|
|
== Example ==
|
|
|
|
couchview push foo-project/bar-views baz-database
|
|
|
|
This will push the views defined in foo-project/bar-views into a database
|
|
called baz-database. Couchview expects the views to be defined in files with
|
|
names like:
|
|
|
|
foo-project/bar-views/my-design/viewname-map.js
|
|
foo-project/bar-views/my-design/viewname-reduce.js
|
|
foo-project/bar-views/my-design/noreduce-map.js
|
|
|
|
Pushed to => http://localhost:5984/baz-database/_design/my-design
|
|
|
|
And the design document:
|
|
{
|
|
"views" : {
|
|
"viewname-map" : {
|
|
"map" : "### contents of view-name-map.js ###"
|
|
},
|
|
"viewname-reduce" : {
|
|
"map" : "### contents of view-name-map.js ###",
|
|
"reduce" : "### contents of view-name-reduce.js ###"
|
|
},
|
|
"noreduce-map" : {
|
|
"map" : "### contents of noreduce-map.js ###"
|
|
}
|
|
}
|
|
}
|
|
|
|
Couchview will create a design document for each subdirectory of the views
|
|
directory specified on the command line.
|
|
|
|
== Library Inlining ==
|
|
|
|
Couchview can optionally inline library code into your views so you only have
|
|
to maintain it in one place. It looks for any files named lib.* in your
|
|
design-doc directory (for doc specific libs) and in the parent views directory
|
|
(for project global libs). These libraries are only inserted into views which
|
|
include the text
|
|
|
|
//include-lib
|
|
|
|
or
|
|
|
|
#include-lib
|
|
|
|
Couchview is a result of scratching my own itch. I'd be happy to make it more
|
|
general, so please contact me at jchris@grabb.it if you'd like to see anything
|
|
added or changed.
|
|
PUSH
|
|
end
|
|
exit
|
|
end
|
|
|
|
require 'rubygems'
|
|
require 'couchrest'
|
|
|
|
if command == 'push'
|
|
dirname = ARGV[1]
|
|
dbname = ARGV[2]
|
|
puts "Pushing views from directory #{dirname} to database #{dbname}"
|
|
fm = CouchRest::FileManager.new(dbname)
|
|
# fm.loud = true
|
|
fm.push_views(dirname)
|
|
elsif command == 'pull'
|
|
end
|
|
|
|
|
|
__END__
|
|
|
|
|
|
|
|
|
|
|
|
dbname = ARGV[1]
|
|
dirname = ARGV[2] || "views"
|
|
|
|
puts "Running #{command} on #{dbname} from directory #{dirname}."
|
|
|
|
require 'rubygems'
|
|
require 'couchrest'
|
|
|
|
case command
|
|
when "push" # files to views
|
|
|
|
|
|
|
|
when "pull" # views to files
|
|
ds = db.documents(:startkey => '_design/', :endkey => '_design/ZZZZZZZZZ')
|
|
ds['rows'].collect{|r|r['id']}.each do |id|
|
|
puts directory = id.split('/').last
|
|
FileUtils.mkdir_p(File.join("views",directory))
|
|
views = db.get(id)['views']
|
|
|
|
vgroups = views.keys.group_by{|k|k.sub(/\-(map|reduce)$/,'')}
|
|
vgroups.each do|g,vs|
|
|
mapname = vs.find {|v|views[v]["map"]}
|
|
if mapname
|
|
# save map
|
|
mapfunc = views[mapname]["map"]
|
|
mapfile = File.join(dirname,directory,"#{g}-map.js") # todo support non-js views
|
|
File.open(mapfile,'w') do |f|
|
|
f.write mapfunc
|
|
end
|
|
end
|
|
|
|
reducename = vs.find {|v|views[v]["reduce"]}
|
|
if reducename
|
|
# save reduce
|
|
reducefunc = views[reducename]["reduce"]
|
|
reducefile = File.join(dirname,directory,"#{g}-reduce.js") # todo support non-js views
|
|
File.open(reducefile,'w') do |f|
|
|
f.write reducefunc
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|