spacialdb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,23 @@
1
+ SpacialDB API - provision geospatial databases on SpacialDB from the command line
2
+ =================================================================================
3
+
4
+ This library wraps the SpacialDB's REST API for provisioning and managing geospatial databases in SpacialDB's cloud service.
5
+
6
+ Sample Workflow
7
+ ---------------
8
+
9
+ Signup and create a new database:
10
+
11
+ spacialdb signup
12
+ spacialdb create
13
+ spacialdb list
14
+
15
+ Delete a database:
16
+
17
+ spacialdb destroy --db <db name>
18
+
19
+ Setup
20
+ -----
21
+
22
+ gem install spacialdb
23
+
data/bin/spacialdb ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'spacialdb'
7
+ require 'spacialdb/command'
8
+
9
+ args = ARGV.dup
10
+ ARGV.clear
11
+ command = args.shift.strip rescue 'help'
12
+
13
+ Spacialdb::Command.load
14
+ Spacialdb::Command.run(command, args)
@@ -0,0 +1,189 @@
1
+ require "spacialdb/client"
2
+ require "spacialdb/helpers"
3
+
4
+ class Spacialdb::Auth
5
+ class PasswordMismatch < RuntimeError; end
6
+
7
+ class << self
8
+ attr_accessor :credentials
9
+
10
+ def default_host
11
+ "beta.spacialdb.com"
12
+ end
13
+
14
+ def host
15
+ ENV['SPACIALDB_HOST'] || default_host
16
+ end
17
+
18
+ def client
19
+ @client ||= begin
20
+ client = Spacialdb::Client.new(email, private_api_key, host)
21
+ client
22
+ end
23
+ end
24
+
25
+ def signup
26
+ delete_credentials
27
+ signup_and_save_credentials
28
+ display "Signed up successfully."
29
+ end
30
+
31
+ def login
32
+ delete_credentials
33
+ get_credentials
34
+ display "Logged in successfully."
35
+ end
36
+
37
+ def logout
38
+ delete_credentials
39
+ display "Logged out successfully."
40
+ end
41
+
42
+ def clear
43
+ @credentials = nil
44
+ @client = nil
45
+ end
46
+
47
+ def email
48
+ get_credentials
49
+ @credentials[0]
50
+ end
51
+
52
+ def private_api_key
53
+ get_credentials
54
+ @credentials[1]
55
+ end
56
+
57
+ def get_credentials
58
+ return if @credentials
59
+ unless @credentials = read_credentials
60
+ ask_for_and_save_credentials
61
+ end
62
+ @credentials
63
+ end
64
+
65
+ def read_credentials
66
+ File.exists?(credentials_file) and File.read(credentials_file).split("\n")
67
+ end
68
+
69
+ include Spacialdb::Helpers
70
+
71
+ def credentials_file
72
+ if host == default_host
73
+ "#{home_directory}/.spacialdb/credentials"
74
+ else
75
+ "#{home_directory}/.spacialdb/credentials.#{host}"
76
+ end
77
+ end
78
+
79
+ def signup_for_credientials
80
+ puts "Sign up to Spacialdb."
81
+
82
+ print "Email: "
83
+ email = ask
84
+
85
+ print "Username: "
86
+ username = ask
87
+
88
+ print "Password: "
89
+ password = ask_for_password
90
+
91
+ print "Password confirmation: "
92
+ password_confirmation = ask_for_password
93
+
94
+ raise PasswordMismatch, "Password doesn't match confirmation." if password != password_confirmation
95
+
96
+ signup = Spacialdb::Client.signup(username, email, password, password_confirmation, host)
97
+ private_api_key = signup['private_api_key']
98
+ email = signup['email']
99
+
100
+ [email, private_api_key]
101
+ end
102
+
103
+ def ask_for_credentials
104
+ puts "Enter your Spacialdb credentials."
105
+
106
+ print "Email or Username: "
107
+ login = ask
108
+
109
+ print "Password: "
110
+ password = ask_for_password
111
+
112
+ auth = Spacialdb::Client.auth(login, password, host)
113
+ private_api_key = auth['private_api_key']
114
+ email = auth['email']
115
+
116
+ [email, private_api_key]
117
+ end
118
+
119
+ def ask_for_password
120
+ echo_off
121
+ password = ask
122
+ puts
123
+ echo_on
124
+ return password
125
+ end
126
+
127
+ def signup_and_save_credentials
128
+ begin
129
+ @credentials = signup_for_credientials
130
+ write_credentials
131
+ rescue ::RestClient::Unauthorized, ::RestClient::Forbidden => e
132
+ clear
133
+ display "Sign up failed:"
134
+ display e.response
135
+ exit 1
136
+ rescue PasswordMismatch => e
137
+ clear
138
+ display "Sign up failed:"
139
+ display e.message
140
+ exit 1
141
+ rescue Exception => e
142
+ delete_credentials
143
+ clear
144
+ display "Sign up failed:"
145
+ display e.message
146
+ raise e
147
+ end
148
+ end
149
+
150
+ def ask_for_and_save_credentials
151
+ begin
152
+ @credentials = ask_for_credentials
153
+ write_credentials
154
+ rescue ::RestClient::Unauthorized, ::RestClient::ResourceNotFound => e
155
+ delete_credentials
156
+ clear
157
+ display "Authentication failed."
158
+ exit 1
159
+ rescue Exception => e
160
+ delete_credentials
161
+ raise e
162
+ end
163
+ end
164
+
165
+ def write_credentials
166
+ FileUtils.mkdir_p(File.dirname(credentials_file))
167
+ f = File.open(credentials_file, 'w')
168
+ f.puts self.credentials
169
+ f.close
170
+ set_credentials_permissions
171
+ end
172
+
173
+ def set_credentials_permissions
174
+ FileUtils.chmod 0700, File.dirname(credentials_file)
175
+ FileUtils.chmod 0600, credentials_file
176
+ end
177
+
178
+ def delete_credentials
179
+ FileUtils.rm_f(credentials_file)
180
+ clear
181
+ end
182
+
183
+ def clear
184
+ @credentials = nil
185
+ @client = nil
186
+ end
187
+
188
+ end
189
+ end
@@ -0,0 +1,102 @@
1
+ require 'spacialdb/version'
2
+ require 'spacialdb/auth'
3
+ require 'spacialdb/helpers'
4
+ require 'rest_client'
5
+
6
+ class Spacialdb::Client
7
+
8
+ include Spacialdb::Helpers
9
+ extend Spacialdb::Helpers
10
+
11
+ def self.version
12
+ Spacialdb::VERSION
13
+ end
14
+
15
+ def self.gem_version_string
16
+ "spacialdb-gem/#{version}"
17
+ end
18
+
19
+ attr_accessor :host, :login, :password
20
+
21
+ def initialize(login, password, host=Spacialdb::Auth.default_host)
22
+ @login = login
23
+ @password = password
24
+ @host = host
25
+ end
26
+
27
+ def self.signup(username, email, password, password_confirmation, host=Spacialdb::Auth.default_host)
28
+ client = new(email, password, host)
29
+ json_decode client.post('/api/users',
30
+ { :email => email,
31
+ :username => username,
32
+ :password => password,
33
+ :password_confirmation => password_confirmation },
34
+ :accept => 'json').to_s
35
+ end
36
+
37
+ def self.auth(login, password, host=Spacialdb::Auth.default_host)
38
+ client = new(login, password, host)
39
+ json_decode client.get('/api/users/credentials', :accept => 'json').to_s
40
+ end
41
+
42
+ def list
43
+ json_decode get('/api/databases', :accept => 'json').to_s
44
+ end
45
+
46
+ def create
47
+ post('/api/databases', '', :accept => 'json')
48
+ end
49
+
50
+ # Destroy the database permanently.
51
+ def destroy(name)
52
+ delete("/api/databases/#{name}", :accept => 'json').to_s
53
+ end
54
+
55
+ def get(uri, extra_headers={}) # :nodoc:
56
+ process(:get, uri, extra_headers)
57
+ end
58
+
59
+ def post(uri, payload="", extra_headers={}) # :nodoc:
60
+ process(:post, uri, extra_headers, payload)
61
+ end
62
+
63
+ def delete(uri, extra_headers={}) # :nodoc:
64
+ process(:delete, uri, extra_headers)
65
+ end
66
+
67
+ def process(method, uri, extra_headers={}, payload=nil)
68
+ headers = spacialdb_headers.merge(extra_headers)
69
+ args = [method, payload, headers].compact
70
+ response = resource(uri).send(*args)
71
+
72
+ response
73
+ end
74
+
75
+ def spacialdb_headers # :nodoc:
76
+ {
77
+ 'X-Spacialdb-API-Version' => '1',
78
+ 'User-Agent' => self.class.gem_version_string,
79
+ 'X-Ruby-Version' => RUBY_VERSION,
80
+ 'X-Ruby-Platform' => RUBY_PLATFORM
81
+ }
82
+ end
83
+
84
+ def resource(uri)
85
+ RestClient.proxy = ENV['HTTP_PROXY'] || ENV['http_proxy']
86
+ resource = RestClient::Resource.new(realize_full_uri(uri),
87
+ :user => login,
88
+ :password => password
89
+ )
90
+ resource
91
+ end
92
+
93
+ def realize_full_uri(given)
94
+ full_host = (host =~ /^http/) ? host : "http://#{host}"
95
+ host = URI.parse(full_host)
96
+ uri = URI.parse(given)
97
+ uri.host ||= host.host
98
+ uri.scheme ||= host.scheme || "http"
99
+ uri.path = (uri.path[0..0] == "/") ? uri.path : "/#{uri.path}"
100
+ uri.to_s
101
+ end
102
+ end
@@ -0,0 +1,36 @@
1
+ require "spacialdb/command/base"
2
+
3
+ # authentication (signup, login, logout)
4
+ #
5
+ class Spacialdb::Command::Auth < Spacialdb::Command::Base
6
+
7
+ # auth:signup
8
+ #
9
+ # sign up for a free plan with Spacialdb
10
+ #
11
+ def signup
12
+ Spacialdb::Auth.signup
13
+ end
14
+
15
+ alias_command "signup", "auth:signup"
16
+
17
+ # auth:login
18
+ #
19
+ # log in with your Spacialdb credentials
20
+ #
21
+ def login
22
+ Spacialdb::Auth.login
23
+ end
24
+
25
+ alias_command "login", "auth:login"
26
+
27
+ # auth:logout
28
+ #
29
+ # clear local authentication credentials
30
+ #
31
+ def logout
32
+ Spacialdb::Auth.logout
33
+ end
34
+
35
+ alias_command "logout", "auth:logout"
36
+ end
@@ -0,0 +1,135 @@
1
+ require "fileutils"
2
+ require "spacialdb/client"
3
+ require "spacialdb/command"
4
+
5
+ class Spacialdb::Command::Base
6
+ include Spacialdb::Helpers
7
+
8
+ def self.namespace
9
+ self.to_s.split("::").last.downcase
10
+ end
11
+
12
+ attr_reader :args
13
+ attr_reader :options
14
+
15
+ def initialize(args=[], options={})
16
+ @args = args
17
+ @options = options
18
+ end
19
+
20
+ def spacialdb
21
+ Spacialdb::Auth.client
22
+ end
23
+
24
+ protected
25
+
26
+ def self.inherited(klass)
27
+ help = extract_help(*(caller.first.split(":")[0..1])).strip
28
+
29
+ Spacialdb::Command.register_namespace(
30
+ :name => klass.namespace,
31
+ :description => help.split("\n").first
32
+ )
33
+ end
34
+
35
+ def self.method_added(method)
36
+ return if self == Spacialdb::Command::Base
37
+ return if private_method_defined?(method)
38
+ return if protected_method_defined?(method)
39
+
40
+ help = extract_help(*(caller.first.split(":")[0..1]))
41
+
42
+ resolved_method = (method.to_s == "index") ? nil : method.to_s
43
+
44
+ default_command = [ self.namespace, resolved_method ].compact.join(":")
45
+ command = extract_command(help) || default_command
46
+
47
+ banner = extract_banner(help) || command
48
+ permute = !banner.index("*")
49
+ banner.gsub!("*", "")
50
+
51
+ Spacialdb::Command.register_command(
52
+ :klass => self,
53
+ :method => method,
54
+ :namespace => self.namespace,
55
+ :command => command,
56
+ :banner => banner,
57
+ :help => help,
58
+ :summary => extract_summary(help),
59
+ :description => extract_description(help),
60
+ :options => extract_options(help),
61
+ :permute => permute
62
+ )
63
+ end
64
+
65
+ def self.alias_command(new, old)
66
+ raise "no such command: #{old}" unless Spacialdb::Command.commands[old]
67
+ Spacialdb::Command.command_aliases[new] = old
68
+ end
69
+
70
+ def self.extract_help(file, line)
71
+ buffer = []
72
+ lines = File.read(file).split("\n")
73
+
74
+ catch(:done) do
75
+ (line.to_i-2).downto(1) do |i|
76
+ case lines[i].strip[0..0]
77
+ when "", "#" then buffer << lines[i]
78
+ else throw(:done)
79
+ end
80
+ end
81
+ end
82
+
83
+ buffer.map! do |line|
84
+ line.strip.gsub(/^#/, "")
85
+ end
86
+
87
+ buffer.reverse.join("\n").strip
88
+ end
89
+
90
+ def self.extract_command(help)
91
+ extract_banner(help).to_s.split(" ").first
92
+ end
93
+
94
+ def self.extract_banner(help)
95
+ help.split("\n").first
96
+ end
97
+
98
+ def self.extract_summary(help)
99
+ extract_description(help).split("\n").first
100
+ end
101
+
102
+ def self.extract_description(help)
103
+ lines = help.split("\n").map(&:strip)
104
+ lines.shift
105
+ lines.reject do |line|
106
+ line =~ /^-(.+)#(.+)/
107
+ end.join("\n").strip
108
+ end
109
+
110
+ def self.extract_options(help)
111
+ help.split("\n").map(&:strip).select do |line|
112
+ line =~ /^-(.+)#(.+)/
113
+ end.inject({}) do |hash, line|
114
+ description = line.split("#", 2).last.strip
115
+ long = line.match(/--([A-Za-z ]+)/)[1].strip
116
+ short = line.match(/-([A-Za-z ])/)[1].strip
117
+ hash.update(long.split(" ").first => { :desc => description, :short => short, :long => long })
118
+ end
119
+ end
120
+
121
+ def extract_option(name, default=true)
122
+ key = name.gsub("--", "").to_sym
123
+ return unless options[key]
124
+ value = options[key] || default
125
+ block_given? ? yield(value) : value
126
+ end
127
+
128
+ def extract_db
129
+ if options[:db].is_a?(String)
130
+ options[:db]
131
+ else
132
+ raise Spacialdb::Command::CommandFailed, "No db specified.\nSpecify which db to use with --db <db name>"
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,41 @@
1
+ require "spacialdb/command/base"
2
+
3
+ # manage databases (create, destroy)
4
+ #
5
+ class Spacialdb::Command::Db < Spacialdb::Command::Base
6
+
7
+ # db
8
+ #
9
+ # list your databases
10
+ #
11
+ def index
12
+ display spacialdb.list.join("\n")
13
+ end
14
+
15
+ alias_command "list", "db"
16
+
17
+ # db:create
18
+ #
19
+ # create your databases
20
+ #
21
+ def create
22
+ display spacialdb.create
23
+ end
24
+
25
+ alias_command "create", "db:create"
26
+
27
+ # db:destroy
28
+ #
29
+ # permanently destroy a database
30
+ #
31
+ def destroy
32
+ db = extract_db
33
+ if confirm_command(db)
34
+ redisplay "Destroying #{db} ... "
35
+ spacialdb.destroy(db)
36
+ display "done"
37
+ end
38
+ end
39
+
40
+ alias_command "destroy", "db:destroy"
41
+ end
@@ -0,0 +1,155 @@
1
+ require "spacialdb/command/base"
2
+
3
+ module Spacialdb::Command
4
+
5
+ # show this help
6
+ #
7
+ class Help < Base
8
+
9
+ class HelpGroup < Array
10
+ attr_reader :title
11
+
12
+ def initialize(title)
13
+ @title = title
14
+ end
15
+
16
+ def command(name, description)
17
+ self << [name, description]
18
+ end
19
+
20
+ def space
21
+ self << ['', '']
22
+ end
23
+ end
24
+
25
+ def self.groups
26
+ @groups ||= []
27
+ end
28
+
29
+ def self.group(title, &block)
30
+ groups << begin
31
+ group = HelpGroup.new(title)
32
+ yield group
33
+ group
34
+ end
35
+ end
36
+
37
+ def index
38
+ if command = args.shift
39
+ help_for_command(command)
40
+ else
41
+ help_for_root
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def commands_for_namespace(name)
48
+ Spacialdb::Command.commands.values.select do |command|
49
+ command[:namespace] == name && command[:method] != :index
50
+ end
51
+ end
52
+
53
+ def namespaces
54
+ namespaces = Spacialdb::Command.namespaces
55
+ end
56
+
57
+ def commands
58
+ commands = Spacialdb::Command.commands
59
+ Spacialdb::Command.command_aliases.each do |new, old|
60
+ commands[new] = commands[old].dup
61
+ commands[new][:banner] = "#{new} #{commands[new][:banner].split(" ", 2)[1]}"
62
+ commands[new][:command] = new
63
+ commands[new][:namespace] = nil
64
+ end
65
+ commands
66
+ end
67
+
68
+ def legacy_help_for_namespace(namespace)
69
+ instance = Spacialdb::Command::Help.groups.map do |group|
70
+ [ group.title, group.select { |c| c.first =~ /^#{namespace}/ }.length ]
71
+ end.sort_by(&:last).last
72
+ return nil unless instance
73
+ return nil if instance.last.zero?
74
+ instance.first
75
+ end
76
+
77
+ def legacy_help_for_command(command)
78
+ Spacialdb::Command::Help.groups.each do |group|
79
+ group.each do |cmd, description|
80
+ return description if cmd.split(" ").first == command
81
+ end
82
+ end
83
+ nil
84
+ end
85
+
86
+ PRIMARY_NAMESPACES = %w( auth db )
87
+
88
+ def primary_namespaces
89
+ PRIMARY_NAMESPACES.map { |name| namespaces[name] }.compact
90
+ end
91
+
92
+ def additional_namespaces
93
+ (namespaces.values - primary_namespaces).sort_by { |n| n[:name] }
94
+ end
95
+
96
+ def summary_for_namespaces(namespaces)
97
+ size = longest(namespaces.map { |n| n[:name] })
98
+ namespaces.each do |namespace|
99
+ name = namespace[:name]
100
+ namespace[:description] ||= legacy_help_for_namespace(name)
101
+ puts " %-#{size}s # %s" % [ name, namespace[:description] ]
102
+ end
103
+ end
104
+
105
+ def help_for_root
106
+ puts "Usage: spacialdb COMMAND [command-specific-options]"
107
+ puts
108
+ puts "Primary help topics, type \"spacialdb help TOPIC\" for more details:"
109
+ puts
110
+ summary_for_namespaces(primary_namespaces)
111
+ puts
112
+ puts "Additional topics:"
113
+ puts
114
+ summary_for_namespaces(additional_namespaces)
115
+ puts
116
+ end
117
+
118
+ def help_for_namespace(name)
119
+ namespace_commands = commands_for_namespace(name)
120
+
121
+ unless namespace_commands.empty?
122
+ size = longest(namespace_commands.map { |c| c[:banner] })
123
+ namespace_commands.sort_by { |c| c[:method].to_s }.each do |command|
124
+ next if command[:help] =~ /DEPRECATED/
125
+ command[:summary] ||= legacy_help_for_command(command[:command])
126
+ puts " %-#{size}s # %s" % [ command[:banner], command[:summary] ]
127
+ end
128
+ end
129
+ end
130
+
131
+ def help_for_command(name)
132
+ command = commands[name]
133
+
134
+ if command
135
+ if command[:help].strip.length > 0
136
+ print "Usage: spacialdb #{command[:banner]}"
137
+ puts command[:help].split("\n")[1..-1].join("\n")
138
+ puts
139
+ else
140
+ puts "Usage: spacialdb #{command[:banner]}"
141
+ puts
142
+ puts " " + legacy_help_for_command(name).to_s
143
+ puts
144
+ end
145
+ end
146
+
147
+ unless commands_for_namespace(name).empty?
148
+ puts "Additional commands, type \"spacialdb help COMMAND\" for more details:"
149
+ puts
150
+ help_for_namespace(name)
151
+ puts
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,16 @@
1
+ require "spacialdb/command/base"
2
+
3
+ # display version
4
+ #
5
+ module Spacialdb::Command
6
+
7
+ # version
8
+ #
9
+ # show the spacialdb gem version
10
+ #
11
+ class Version < Base
12
+ def index
13
+ display Spacialdb::Client.gem_version_string
14
+ end
15
+ end
16
+ end