diff --git a/script/couchcontrol b/bin/couchcontrol similarity index 100% rename from script/couchcontrol rename to bin/couchcontrol diff --git a/bin/couchdir b/bin/couchdir new file mode 100755 index 0000000..c65d671 --- /dev/null +++ b/bin/couchdir @@ -0,0 +1,20 @@ +#!/usr/bin/env ruby + +unless ARGV.length >= 2 + puts "usage: couchdir path/to/directory db-name [docid]" + exit +end + +require 'rubygems' +require 'couchrest' + +dirname = ARGV[0] +dbname = ARGV[1] +docid = ARGV[2] + +puts "Create attachments for the files in #{dirname} in database #{dbname}." + +fm = CouchRest::FileManager.new(dbname) +fm.loud = true +puts "Pushing views from directory #{dirname} to database #{fm.db}" +fm.push_directory(dirname, docid) diff --git a/script/couchview b/bin/couchview similarity index 68% rename from script/couchview rename to bin/couchview index 91546a2..d319d05 100755 --- a/script/couchview +++ b/bin/couchview @@ -15,8 +15,10 @@ if ARGV.length == 1 case command when "generate" puts <<-GEN +Usage: couchview generate directory design1 design2 design3 ... - +Couchview will create directories and example views for the design documents you specify. + GEN when "push" puts <<-PUSH @@ -100,61 +102,10 @@ 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.loud = true + puts "Pushing views from directory #{dirname} to database #{fm.db}" 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 +elsif command == 'generate' + puts "Under construction ;)" end diff --git a/couchrest.gemspec b/couchrest.gemspec index e18ab78..989033c 100644 --- a/couchrest.gemspec +++ b/couchrest.gemspec @@ -1,7 +1,7 @@ Gem::Specification.new do |s| s.name = "couchrest" - s.version = "0.8.4" - s.date = "2008-06-20" + s.version = "0.8.9" + s.date = "2008-08-03" s.summary = "Lean and RESTful interface to CouchDB." s.email = "jchris@grabb.it" s.homepage = "http://github.com/jchris/couchrest" @@ -9,13 +9,17 @@ Gem::Specification.new do |s| s.has_rdoc = false s.authors = ["J. Chris Anderson"] s.files = %w{ - lib/couchrest.rb lib/database.rb lib/pager.rb lib/file_manager.rb + lib/couchrest.rb + lib/couch_rest.rb lib/database.rb lib/pager.rb lib/file_manager.rb Rakefile README - script/couchdir script/couchview + bin/couchdir bin/couchview spec/couchrest_spec.rb spec/database_spec.rb spec/pager_spec.rb spec/file_manager_spec.rb spec/spec_helper.rb } s.require_path = "lib" + s.bindir = 'bin' + s.executables << 'couchview' + s.executables << 'couchdir' s.add_dependency("json", [">= 1.1.2"]) s.add_dependency("rest-client", [">= 0.5"]) end diff --git a/couchrest.rb b/couchrest.rb deleted file mode 100644 index 5aabba6..0000000 --- a/couchrest.rb +++ /dev/null @@ -1,9 +0,0 @@ -require "rubygems" -require 'json' -require 'rest_client' - -require File.dirname(__FILE__) + '/lib/couchrest' -require File.dirname(__FILE__) + '/lib/database' -require File.dirname(__FILE__) + '/lib/pager' -require File.dirname(__FILE__) + '/lib/file_manager' - diff --git a/lib/couch_rest.rb b/lib/couch_rest.rb new file mode 100644 index 0000000..f07114d --- /dev/null +++ b/lib/couch_rest.rb @@ -0,0 +1,62 @@ +class CouchRest + attr_accessor :uri + def initialize server = 'http://localhost:5984' + @uri = server + end + + # list all databases on the server + def databases + CouchRest.get "#{@uri}/_all_dbs" + end + + def database name + CouchRest::Database.new(@uri, name) + end + + # get the welcome message + def info + CouchRest.get "#{@uri}/" + end + + # restart the couchdb instance + def restart! + CouchRest.post "#{@uri}/_restart" + end + + # create a database + def create_db name + CouchRest.put "#{@uri}/#{name}" + database name + end + + class << self + def put uri, doc = nil + payload = doc.to_json if doc + JSON.parse(RestClient.put(uri, payload)) + end + + def get uri + JSON.parse(RestClient.get(uri), :max_nesting => false) + end + + def post uri, doc = nil + payload = doc.to_json if doc + JSON.parse(RestClient.post(uri, payload)) + end + + def delete uri + JSON.parse(RestClient.delete(uri)) + end + + def paramify_url url, params = nil + if params + query = params.collect do |k,v| + v = v.to_json if %w{key startkey endkey}.include?(k.to_s) + "#{k}=#{CGI.escape(v.to_s)}" + end.join("&") + url = "#{url}?#{query}" + end + url + end + end +end diff --git a/lib/couchrest.rb b/lib/couchrest.rb index f07114d..899e117 100644 --- a/lib/couchrest.rb +++ b/lib/couchrest.rb @@ -1,62 +1,10 @@ -class CouchRest - attr_accessor :uri - def initialize server = 'http://localhost:5984' - @uri = server - end - - # list all databases on the server - def databases - CouchRest.get "#{@uri}/_all_dbs" - end - - def database name - CouchRest::Database.new(@uri, name) - end - - # get the welcome message - def info - CouchRest.get "#{@uri}/" - end +require "rubygems" +require 'json' +require 'rest_client' + +require File.dirname(__FILE__) + '/couch_rest' +require File.dirname(__FILE__) + '/database' +require File.dirname(__FILE__) + '/pager' +require File.dirname(__FILE__) + '/file_manager' - # restart the couchdb instance - def restart! - CouchRest.post "#{@uri}/_restart" - end - - # create a database - def create_db name - CouchRest.put "#{@uri}/#{name}" - database name - end - class << self - def put uri, doc = nil - payload = doc.to_json if doc - JSON.parse(RestClient.put(uri, payload)) - end - - def get uri - JSON.parse(RestClient.get(uri), :max_nesting => false) - end - - def post uri, doc = nil - payload = doc.to_json if doc - JSON.parse(RestClient.post(uri, payload)) - end - - def delete uri - JSON.parse(RestClient.delete(uri)) - end - - def paramify_url url, params = nil - if params - query = params.collect do |k,v| - v = v.to_json if %w{key startkey endkey}.include?(k.to_s) - "#{k}=#{CGI.escape(v.to_s)}" - end.join("&") - url = "#{url}?#{query}" - end - url - end - end -end diff --git a/lib/database.rb b/lib/database.rb index 6fada0c..7d0bfec 100644 --- a/lib/database.rb +++ b/lib/database.rb @@ -10,6 +10,10 @@ class CouchRest @root = "#{host}/#{name}" end + def to_s + @root + end + def documents params = nil url = CouchRest.paramify_url "#{@root}/_all_docs", params CouchRest.get url diff --git a/lib/file_manager.rb b/lib/file_manager.rb index eda1f0c..4c97fe2 100644 --- a/lib/file_manager.rb +++ b/lib/file_manager.rb @@ -3,6 +3,7 @@ require 'digest/md5' class CouchRest class FileManager attr_reader :db + attr_accessor :loud LANGS = {"rb" => "ruby", "js" => "javascript"} MIMES = { @@ -41,16 +42,18 @@ class CouchRest doc = @db.get(docid) rescue nil unless doc - # puts "creating public" + say "creating #{docid}" @db.save({"_id" => docid, "_attachments" => @attachments, "signatures" => @signatures}) return end # remove deleted docs - to_be_removed = doc["signatures"].keys.select{|d| !couch["public"].collect{|p| p.keys.first}.include?(d) } + to_be_removed = doc["signatures"].keys.select do |d| + !pushfiles.collect{|p| p.keys.first}.include?(d) + end to_be_removed.each do |p| - # puts "deleting #{p}" + say "deleting #{p}" doc["signatures"].delete(p) doc["_attachments"].delete(p) end @@ -58,9 +61,9 @@ class CouchRest # update existing docs: doc["signatures"].each do |path, sig| if (@signatures[path] == sig) - # puts "no change to #{path}. skipping..." + say "no change to #{path}. skipping..." else - # puts "replacing #{path}" + say "replacing #{path}" doc["signatures"][path] = md5(@attachments[path]["data"]) doc["_attachments"][path].delete("stub") doc["_attachments"][path].delete("length") @@ -71,10 +74,10 @@ class CouchRest end # add in new files - new_files = couch["public"].select{|d| !doc["signatures"].keys.include?( d.keys.first) } + new_files = pushfiles.select{|d| !doc["signatures"].keys.include?( d.keys.first) } new_files.each do |f| - # puts "creating #{f}" + say "creating #{f}" path = f.keys.first content = f.values.first doc["signatures"][path] = md5(content) @@ -88,15 +91,16 @@ class CouchRest begin @db.save(doc) rescue Exception => e - # puts e.message + say e.message end end def push_views(view_dir) designs = {} - Dir["#{view_dir}/**/*.*"].collect do |design_doc| + Dir["#{view_dir}/**/*.*"].each do |design_doc| design_doc_parts = design_doc.split('/') + next if /^lib\..*$/.match design_doc_parts.last pre_normalized_view_name = design_doc_parts.last.split("-") view_name = pre_normalized_view_name[0..pre_normalized_view_name.length-2].join("-") @@ -150,6 +154,10 @@ class CouchRest private + def say words + puts words if @loud + end + def md5 string Digest::MD5.hexdigest(string) end @@ -165,16 +173,17 @@ class CouchRest if existing updated = fields.merge({"_id" => id, "_rev" => existing["_rev"]}) + if existing != updated + say "replacing #{id}" + db.save(updated) + else + say "skipping #{id}" + end else - # puts "saving #{id}" + say "creating #{id}" db.save(fields.merge({"_id" => id})) end - if existing != updated - # puts "replacing #{id}" - db.save(updated) - end - end end end diff --git a/script/couchdir b/script/couchdir deleted file mode 100755 index a90ef0e..0000000 --- a/script/couchdir +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env ruby - -unless ARGV.length >= 2 - puts "usage: couchdir path/to/directory db-name" - exit -end - -dirname = ARGV[0].sub(/\/$/,'') -dbname = ARGV[1] - - - -puts "Shoving #{dirname} into #{dbname}." - -require File.expand_path(File.dirname(__FILE__)) + '/../couchrest' -require 'fileutils' - -cr = CouchRest.new("http://localhost:5984") -@db = cr.database(dbname) - -@content_types = { - "html" => "text/html", - "htm" => "text/html", - "png" => "image/png", - "css" => "text/css" -} - -files = Dir.glob(File.join(dirname,"**","*")) -attachments = {} -files.each do |filename| - content = open(filename).read - aname = filename.split('/') - aname.shift - aname = aname.join('/') - attachments[aname] = { - "data" => content, - "content_type" => @content_types[aname.split('.').last] - } -end - -puts attachments.keys.inspect - -begin - doc = @db.get(dirname) -rescue RestClient::Request::RequestFailed - doc = nil -end - -# puts "get: #{doc.inspect}" - -if doc - doc["_attachments"] = attachments -else - doc = { - "_id" => dirname, - "_attachments" => attachments - } -end - -# puts "saving: #{doc.inspect}" -@db.save(doc) -puts "saved" \ No newline at end of file diff --git a/spec/file_manager_spec.rb b/spec/file_manager_spec.rb index ad4b01e..16a4b08 100644 --- a/spec/file_manager_spec.rb +++ b/spec/file_manager_spec.rb @@ -51,6 +51,10 @@ describe CouchRest::FileManager, "pushing views" do @design["views"]["only-map"]["map"].should include("globalLib") @design["views"]["only-map"]["map"].should include("justThisView") end + it "should not create extra design docs" do + docs = @db.documents(:startkey => '_design', :endkey => '_design/ZZZZZZ') + docs['total_rows'].should == 1 + end end describe CouchRest::FileManager, "pushing a directory with id" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6369bb2..22063b9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../couchrest' +require File.dirname(__FILE__) + '/../lib/couchrest' COUCHHOST = "http://localhost:5984" TESTDB = 'couchrest-test' \ No newline at end of file