Skip to content

Instantly share code, notes, and snippets.

@iocentos
Last active May 10, 2016 09:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iocentos/4bafb1a1d5f2d1d1e2169d4cf8c89ca3 to your computer and use it in GitHub Desktop.
Save iocentos/4bafb1a1d5f2d1d1e2169d4cf8c89ca3 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'optparse'
require 'couchbase'
require 'rubygems'
require 'highline/import'
require 'json'
require 'fileutils'
# Simple CRUD interaction with the couchbase server.
# Define below which requests are allowed by the script
GET_REQUEST = "GET"
PUT_REQUEST = "PUT"
POST_REQUEST = "POST"
DELETE_REQUEST = "DELETE"
VALID_REQUESTS = [GET_REQUEST, PUT_REQUEST, POST_REQUEST, DELETE_REQUEST]
# Define default values below. These values will not have to
# be provided when invoking the script. You may change these
# values to fit your needs but it is REQUIRED that none of
# these values is nil
# Start of configuration
BUCKET = 'data'
HOST = 'localhost'
PORT = 8091
TMP_DIR = "/tmp/#{File.basename($0, File.extname($0))}/docs"
DEFAULT_REQUEST = GET_REQUEST
LAUNCH_EDITOR = true
# End of configuration
# Define your editor and shell settings. If LAUNCH_EDITOR is set to true,
# the function below will fire a new shell opening the document with your
# editor
SHELL = "/usr/bin/zsh -c"
EDITOR = "/usr/bin/nvim"
# Adjust to fit youw needs
def launchEditor(file)
system "#{SHELL} \"#{EDITOR} #{file}\""
end
Options = Struct.new(:bucket, :host, :port, :file, :doc_id, :temp_dir, :request, :launch_editor)
RequestType = Struct.new(:type)
class Parser
def self.parse(options)
args = Options.new(BUCKET, HOST, PORT, nil, nil, TMP_DIR, DEFAULT_REQUEST, LAUNCH_EDITOR)
opt_parser = OptionParser.new do |opts|
opts.banner = "Usage: #{File.basename($0)} [options]"
# Custom conversion
opts.accept(RequestType) do |type|
not_found = ->{ puts "Valid request type: #{VALID_REQUESTS}"; exit 1}
VALID_REQUESTS.find(not_found) do |r|
type == r
end
end
opts.on("-b", "--bucket=REQUIRED", String, "Couchbase bucket to interact with") do |n| args.bucket = n end
opts.on("-s", "--server=REQUIRED", String, "Couchbase server") do |n| args.host = n end
opts.on("-p", "--port=REQUIRED", Integer, "Couchbase server port") do |n| args.port = n end
opts.on("-f", "--file=REQUIRED", String, "Json file to read. Used for POST and PUT requests File name will be treated as document id. \".json\" suffix will be discared") do |n| args.file = n end
opts.on("-i", "--document-id=REQUIRED", String, "Document id. Used for GET and DELETE requests. \".json\" suffix will be discared. Accepts full paths and filenames as valid document ids") do |n| args.doc_id = n end
opts.on("-t", "--tmp-directory=REQUIRED", String, "Temporary directory to save documents. The directory will be created if does not exist") do |n| args.temp_dir = n end
opts.on("-r", "--request-type=REQUIRED", RequestType, "Request type. Acceptable values are #{VALID_REQUESTS}") do |n| args.request = n end
opts.on("-e", "--launch-editor=REQUIRED", TrueClass, "If true, it will launch the edit on #{GET_REQUEST}. Defaults to True") do |n| args.launch_editor = n end
opts.on("-h", "--help", "Prints help\n
Examples:\n
#{File.basename($0)} -i documentId
#{File.basename($0)} -b #{BUCKET} -s #{HOST} -p #{PORT} -t #{TMP_DIR} -r #{DEFAULT_REQUEST} -e #{LAUNCH_EDITOR} -i documentId
") do
puts opts
exit
end
end
opt_parser.parse!(options)
return args
end
end
# Further validation that cannot be performed by the parser above(or at least
# i don't know how to do it.)
def validateOptions(options)
if((options.request == GET_REQUEST or options.request == DELETE_REQUEST) and options.doc_id == nil)
puts "#{GET_REQUEST} and #{DELETE_REQUEST} requests always require a document id"
exit 1
end
if((options.request == POST_REQUEST or options.request == PUT_REQUEST) and options.file == nil)
puts "#{POST_REQUEST} and #{PUT_REQUEST} requests always require a json file to read"
exit 1
end
if(options.file != nil)
if(!File.exist?(options.file))
puts "Json file '#{options.file}' does not exist"
exit 1
end
end
if(options.doc_id != nil)
options.doc_id = File.basename(options.doc_id, File.extname(options.doc_id))
end
dirname = File.dirname(options.temp_dir + '/test')
unless File.directory?(options.temp_dir)
FileUtils.mkdir_p(dirname)
end
end
# Single connection provided for all types of requests
def getConnection(host, port, bucket, password)
begin
Couchbase.connect(:hostname => host,
:port => port,
:bucket => bucket,
:password => password)
rescue
puts "Failed to connect to #{host}:#{port}"
exit 1
end
end
# Different types of requests and their respective actions
def doGet(connection, doc_id, temp_dir, launch_editor)
connection.run do |couch|
couch.get(doc_id) do |result|
if(result.error == nil)
prettyJson = JSON.pretty_generate(result.value)
file_name = "#{temp_dir}/#{doc_id}.json"
File.open(file_name, 'w') { |file| file.write(prettyJson) }
puts "Saved document at #{file_name}"
if(launch_editor)
launchEditor(file_name)
end
exit 0
else
puts "Failed to #{GET_REQUEST} document #{doc_id}. Document not found."
end
end
end
end
def doDelete(connection, doc_id)
connection.run do |couch|
couch.delete(doc_id) do |result|
if(result.error == nil)
puts "Document #{doc_id} is deleted"
else
puts "Failed to #{DELETE_REQUEST} document #{doc_id}. Document did not exist"
exit 1
end
end
end
end
def doPut(connection, file_id)
doc_id = File.basename(file_id, File.extname(file_id))
jsonFile = File.read(file_id)
data = JSON.parse(jsonFile)
connection.run do |couch|
couch.replace(doc_id, data) do |result|
if(result.error == nil)
puts "Document #{doc_id} is saved"
else
puts "Failed to #{PUT_REQUEST} document #{doc_id}.\n"
puts "Are you sure document '#{doc_id}' already exists?."
exit 1
end
end
end
end
def doPost(connection, file_id)
doc_id = File.basename(file_id, File.extname(file_id))
jsonFile = File.read(file_id)
data = JSON.parse(jsonFile)
connection.run do |couch|
couch.add(doc_id, data) do |result|
if(result.error == nil)
puts "Document #{doc_id} is saved"
else
puts "Failed to #{POST_REQUEST} document #{doc_id}.\n"
puts "Are you sure document '#{doc_id}' does not already exist?."
exit 1
end
end
end
end
# Main program
options = Parser.parse ARGV
validateOptions(options)
password = ask("Password: ") {|q| q.echo =false }
connection = getConnection(options.host, options.port, options.bucket, password)
case options.request
when GET_REQUEST
doGet(connection, options.doc_id, options.temp_dir, options.launch_editor)
when DELETE_REQUEST
doDelete(connection, options.doc_id)
when PUT_REQUEST
doPut(connection, options.file)
when POST_REQUEST
doPost(connection, options.file)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment