Last active
May 10, 2016 09:42
-
-
Save iocentos/4bafb1a1d5f2d1d1e2169d4cf8c89ca3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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