spacialdb 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/data/cacert.pem +3988 -0
- data/lib/spacialdb/client.rb +40 -4
- data/lib/spacialdb/command.rb +44 -22
- data/lib/spacialdb/command/base.rb +13 -8
- data/lib/spacialdb/command/db.rb +1 -1
- data/lib/spacialdb/command/help.rb +98 -122
- data/lib/spacialdb/deprecated.rb +4 -0
- data/lib/spacialdb/deprecated/help.rb +38 -0
- data/lib/spacialdb/helpers.rb +1 -1
- data/lib/spacialdb/version.rb +1 -1
- data/spec/auth_spec.rb +37 -0
- data/spec/client_spec.rb +1 -1
- data/spec/command/help_spec.rb +34 -0
- data/spec/spec_helper.rb +51 -1
- metadata +10 -5
data/lib/spacialdb/client.rb
CHANGED
@@ -67,11 +67,32 @@ class Spacialdb::Client
|
|
67
67
|
def process(method, uri, extra_headers={}, payload=nil)
|
68
68
|
headers = spacialdb_headers.merge(extra_headers)
|
69
69
|
args = [method, payload, headers].compact
|
70
|
-
response = resource(uri).send(*args)
|
71
70
|
|
71
|
+
resource_options = default_resource_options_for_uri(uri)
|
72
|
+
|
73
|
+
begin
|
74
|
+
response = resource(uri, resource_options).send(*args)
|
75
|
+
rescue RestClient::SSLCertificateNotVerified => ex
|
76
|
+
host = URI.parse(realize_full_uri(uri)).host
|
77
|
+
error "WARNING: Unable to verify SSL certificate for #{host}\nTo disable SSL verification, run with SPACIALDB_SSL_VERIFY=disable"
|
78
|
+
end
|
79
|
+
|
80
|
+
extract_warning(response)
|
72
81
|
response
|
73
82
|
end
|
74
83
|
|
84
|
+
def extract_warning(response)
|
85
|
+
return unless response
|
86
|
+
if response.headers[:x_spacialdb_warning] && @warning_callback
|
87
|
+
warning = response.headers[:x_spacialdb_warning]
|
88
|
+
@displayed_warnings ||= {}
|
89
|
+
unless @displayed_warnings[warning]
|
90
|
+
@warning_callback.call(warning)
|
91
|
+
@displayed_warnings[warning] = true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
75
96
|
def spacialdb_headers # :nodoc:
|
76
97
|
{
|
77
98
|
'X-Spacialdb-API-Version' => '1',
|
@@ -81,7 +102,7 @@ class Spacialdb::Client
|
|
81
102
|
}
|
82
103
|
end
|
83
104
|
|
84
|
-
def resource(uri)
|
105
|
+
def resource(uri, options={})
|
85
106
|
RestClient.proxy = ENV['HTTP_PROXY'] || ENV['http_proxy']
|
86
107
|
resource = RestClient::Resource.new(realize_full_uri(uri),
|
87
108
|
:user => login,
|
@@ -91,12 +112,27 @@ class Spacialdb::Client
|
|
91
112
|
end
|
92
113
|
|
93
114
|
def realize_full_uri(given)
|
94
|
-
full_host = (host =~ /^http/) ? host : "
|
115
|
+
full_host = (host =~ /^http/) ? host : "https://#{host}"
|
95
116
|
host = URI.parse(full_host)
|
96
117
|
uri = URI.parse(given)
|
97
118
|
uri.host ||= host.host
|
98
|
-
uri.scheme ||= host.scheme || "
|
119
|
+
uri.scheme ||= host.scheme || "https"
|
99
120
|
uri.path = (uri.path[0..0] == "/") ? uri.path : "/#{uri.path}"
|
121
|
+
uri.port = host.port if full_host =~ /\:\d+/
|
100
122
|
uri.to_s
|
101
123
|
end
|
124
|
+
|
125
|
+
def default_resource_options_for_uri(uri)
|
126
|
+
if ENV["SPACIALDB_SSL_VERIFY"] == "disable"
|
127
|
+
{}
|
128
|
+
elsif realize_full_uri(uri) =~ %r|^https://beta.spacialdb.com|
|
129
|
+
{ :verify_ssl => OpenSSL::SSL::VERIFY_PEER, :ssl_ca_file => local_ca_file }
|
130
|
+
else
|
131
|
+
{}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def local_ca_file
|
136
|
+
File.expand_path("../../../data/cacert.pem", __FILE__)
|
137
|
+
end
|
102
138
|
end
|
data/lib/spacialdb/command.rb
CHANGED
@@ -48,8 +48,9 @@ module Spacialdb
|
|
48
48
|
|
49
49
|
global_option :db, "--db DB", "-d"
|
50
50
|
global_option :confirm, "--confirm DB"
|
51
|
+
global_option :help, "--help", "-h"
|
51
52
|
|
52
|
-
def self.
|
53
|
+
def self.prepare_run(cmd, args=[])
|
53
54
|
|
54
55
|
command = parse(cmd)
|
55
56
|
|
@@ -85,31 +86,37 @@ module Spacialdb
|
|
85
86
|
retry
|
86
87
|
end
|
87
88
|
|
88
|
-
if opts[:help]
|
89
|
-
run "help", [cmd]
|
90
|
-
return
|
91
|
-
end
|
89
|
+
raise OptionParser::ParseError if opts[:help]
|
92
90
|
|
93
91
|
args.concat(invalid_options)
|
94
92
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
93
|
+
[ command[:klass].new(args.dup, opts.dup), command[:method] ]
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.run(cmd, arguments=[])
|
97
|
+
object, method = prepare_run(cmd, arguments)
|
98
|
+
object.send(method)
|
99
|
+
rescue InvalidCommand
|
100
|
+
error "Unknown command. Run 'spacialdb help' for usage information."
|
101
|
+
rescue RestClient::Unauthorized
|
102
|
+
puts "Authentication failure"
|
103
|
+
run "login"
|
104
|
+
retry
|
105
|
+
rescue RestClient::ResourceNotFound => e
|
106
|
+
error extract_not_found(e.http_body)
|
107
|
+
rescue RestClient::Locked => e
|
108
|
+
db = e.response.headers[:x_confirmation_required]
|
109
|
+
message = extract_error(e.response.body)
|
110
|
+
if confirmation_required(db, message)
|
111
|
+
opts[:confirm] = db
|
103
112
|
retry
|
104
|
-
rescue RestClient::ResourceNotFound => e
|
105
|
-
error extract_not_found(e.http_body)
|
106
|
-
rescue RestClient::RequestFailed => e
|
107
|
-
error extract_error(e.http_body)
|
108
|
-
rescue RestClient::RequestTimeout
|
109
|
-
error "API request timed out. Please try again, or contact support@spacialdb.com if this issue persists."
|
110
|
-
rescue CommandFailed => e
|
111
|
-
error e.message
|
112
113
|
end
|
114
|
+
rescue RestClient::RequestFailed => e
|
115
|
+
error extract_error(e.http_body)
|
116
|
+
rescue RestClient::RequestTimeout
|
117
|
+
error "API request timed out. Please try again, or contact support@spacialdb.com if this issue persists."
|
118
|
+
rescue CommandFailed => e
|
119
|
+
error e.message
|
113
120
|
rescue OptionParser::ParseError => ex
|
114
121
|
commands[cmd] ? run("help", [cmd]) : run("help")
|
115
122
|
rescue Interrupt => e
|
@@ -128,7 +135,7 @@ module Spacialdb
|
|
128
135
|
msg = parse_error_json(body) || parse_error_plain(body) || 'Internal server error'
|
129
136
|
msg.split("\n").map { |line| ' ! ' + line }.join("\n")
|
130
137
|
end
|
131
|
-
|
138
|
+
|
132
139
|
def self.parse_error_json(body)
|
133
140
|
json = json_decode(body.to_s)
|
134
141
|
json ? json['error'] : nil
|
@@ -138,5 +145,20 @@ module Spacialdb
|
|
138
145
|
return unless body.respond_to?(:headers) && body.headers[:content_type].to_s.include?("text/plain")
|
139
146
|
body.to_s
|
140
147
|
end
|
148
|
+
|
149
|
+
def self.confirmation_required(db, message)
|
150
|
+
display
|
151
|
+
display
|
152
|
+
display message
|
153
|
+
display " ! To proceed, type \"#{db}\" or re-run this command with --confirm #{db}"
|
154
|
+
display
|
155
|
+
display "> ", false
|
156
|
+
if ask.downcase != app
|
157
|
+
display " ! Input did not match #{db}. Aborted."
|
158
|
+
false
|
159
|
+
else
|
160
|
+
true
|
161
|
+
end
|
162
|
+
end
|
141
163
|
end
|
142
164
|
end
|
@@ -24,7 +24,7 @@ class Spacialdb::Command::Base
|
|
24
24
|
protected
|
25
25
|
|
26
26
|
def self.inherited(klass)
|
27
|
-
help =
|
27
|
+
help = extract_help_from_caller(caller.first)
|
28
28
|
|
29
29
|
Spacialdb::Command.register_namespace(
|
30
30
|
:name => klass.namespace,
|
@@ -37,13 +37,10 @@ protected
|
|
37
37
|
return if private_method_defined?(method)
|
38
38
|
return if protected_method_defined?(method)
|
39
39
|
|
40
|
-
help =
|
41
|
-
|
40
|
+
help = extract_help_from_caller(caller.first)
|
42
41
|
resolved_method = (method.to_s == "index") ? nil : method.to_s
|
43
|
-
|
44
42
|
default_command = [ self.namespace, resolved_method ].compact.join(":")
|
45
43
|
command = extract_command(help) || default_command
|
46
|
-
|
47
44
|
banner = extract_banner(help) || command
|
48
45
|
permute = !banner.index("*")
|
49
46
|
banner.gsub!("*", "")
|
@@ -67,6 +64,14 @@ protected
|
|
67
64
|
Spacialdb::Command.command_aliases[new] = old
|
68
65
|
end
|
69
66
|
|
67
|
+
def self.extract_help_from_caller(line)
|
68
|
+
# pull out of the caller the information for the file path and line number
|
69
|
+
if line =~ /^(.+?):(\d+)/
|
70
|
+
return extract_help($1, $2)
|
71
|
+
end
|
72
|
+
raise "unable to extract help from caller: #{line}"
|
73
|
+
end
|
74
|
+
|
70
75
|
def self.extract_help(file, line)
|
71
76
|
buffer = []
|
72
77
|
lines = File.read(file).split("\n")
|
@@ -100,7 +105,7 @@ protected
|
|
100
105
|
end
|
101
106
|
|
102
107
|
def self.extract_description(help)
|
103
|
-
lines = help.split("\n").map
|
108
|
+
lines = help.split("\n").map { |l| l.strip }
|
104
109
|
lines.shift
|
105
110
|
lines.reject do |line|
|
106
111
|
line =~ /^-(.+)#(.+)/
|
@@ -108,11 +113,11 @@ protected
|
|
108
113
|
end
|
109
114
|
|
110
115
|
def self.extract_options(help)
|
111
|
-
help.split("\n").map
|
116
|
+
help.split("\n").map { |l| l.strip }.select do |line|
|
112
117
|
line =~ /^-(.+)#(.+)/
|
113
118
|
end.inject({}) do |hash, line|
|
114
119
|
description = line.split("#", 2).last.strip
|
115
|
-
long = line.match(/--([A-Za-z ]+)/)[1].strip
|
120
|
+
long = line.match(/--([A-Za-z\- ]+)/)[1].strip
|
116
121
|
short = line.match(/-([A-Za-z ])/)[1].strip
|
117
122
|
hash.update(long.split(" ").first => { :desc => description, :short => short, :long => long })
|
118
123
|
end
|
data/lib/spacialdb/command/db.rb
CHANGED
@@ -1,155 +1,131 @@
|
|
1
1
|
require "spacialdb/command/base"
|
2
|
+
require "spacialdb/deprecated/help"
|
2
3
|
|
3
|
-
|
4
|
+
# list commands and display help
|
5
|
+
#
|
6
|
+
class Spacialdb::Command::Help < Spacialdb::Command::Base
|
4
7
|
|
5
|
-
|
6
|
-
#
|
7
|
-
class Help < Base
|
8
|
-
|
9
|
-
class HelpGroup < Array
|
10
|
-
attr_reader :title
|
11
|
-
|
12
|
-
def initialize(title)
|
13
|
-
@title = title
|
14
|
-
end
|
8
|
+
PRIMARY_NAMESPACES = %w( auth db )
|
15
9
|
|
16
|
-
|
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
|
10
|
+
include Spacialdb::Deprecated::Help
|
36
11
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
12
|
+
# help [COMMAND]
|
13
|
+
#
|
14
|
+
# list available commands or display help for a specific command
|
15
|
+
#
|
16
|
+
def index
|
17
|
+
if command = args.shift
|
18
|
+
help_for_command(command)
|
19
|
+
else
|
20
|
+
help_for_root
|
43
21
|
end
|
22
|
+
end
|
44
23
|
|
45
|
-
|
24
|
+
private
|
46
25
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
26
|
+
def commands_for_namespace(name)
|
27
|
+
Spacialdb::Command.commands.values.select do |command|
|
28
|
+
command[:namespace] == name && command[:method] != :index
|
51
29
|
end
|
30
|
+
end
|
52
31
|
|
53
|
-
|
54
|
-
|
55
|
-
|
32
|
+
def namespaces
|
33
|
+
namespaces = Spacialdb::Command.namespaces
|
34
|
+
end
|
56
35
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
65
|
-
commands
|
36
|
+
def commands
|
37
|
+
commands = Spacialdb::Command.commands
|
38
|
+
Spacialdb::Command.command_aliases.each do |new, old|
|
39
|
+
commands[new] = commands[old].dup
|
40
|
+
commands[new][:banner] = "#{new} #{commands[new][:banner].split(" ", 2)[1]}"
|
41
|
+
commands[new][:command] = new
|
42
|
+
commands[new][:namespace] = nil
|
66
43
|
end
|
44
|
+
commands
|
45
|
+
end
|
67
46
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
47
|
+
def legacy_help_for_namespace(namespace)
|
48
|
+
instance = Spacialdb::Command::Help.groups.map do |group|
|
49
|
+
[ group.title, group.select { |c| c.first =~ /^#{namespace}/ }.length ]
|
50
|
+
end.sort_by { |l| l.last }.last
|
51
|
+
return nil unless instance
|
52
|
+
return nil if instance.last.zero?
|
53
|
+
instance.first
|
54
|
+
end
|
76
55
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
56
|
+
def legacy_help_for_command(command)
|
57
|
+
Spacialdb::Command::Help.groups.each do |group|
|
58
|
+
group.each do |cmd, description|
|
59
|
+
return description if cmd.split(" ").first == command
|
82
60
|
end
|
83
|
-
nil
|
84
61
|
end
|
62
|
+
nil
|
63
|
+
end
|
85
64
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
PRIMARY_NAMESPACES.map { |name| namespaces[name] }.compact
|
90
|
-
end
|
65
|
+
def primary_namespaces
|
66
|
+
PRIMARY_NAMESPACES.map { |name| namespaces[name] }.compact
|
67
|
+
end
|
91
68
|
|
92
|
-
|
93
|
-
|
94
|
-
|
69
|
+
def additional_namespaces
|
70
|
+
(namespaces.values - primary_namespaces).sort_by { |n| n[:name] }
|
71
|
+
end
|
95
72
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
73
|
+
def summary_for_namespaces(namespaces)
|
74
|
+
size = longest(namespaces.map { |n| n[:name] })
|
75
|
+
namespaces.each do |namespace|
|
76
|
+
name = namespace[:name]
|
77
|
+
namespace[:description] ||= legacy_help_for_namespace(name)
|
78
|
+
puts " %-#{size}s # %s" % [ name, namespace[:description] ]
|
103
79
|
end
|
80
|
+
end
|
104
81
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
82
|
+
def help_for_root
|
83
|
+
puts "Usage: spacialdb COMMAND [command-specific-options]"
|
84
|
+
puts
|
85
|
+
puts "Primary help topics, type \"spacialdb help TOPIC\" for more details:"
|
86
|
+
puts
|
87
|
+
summary_for_namespaces(primary_namespaces)
|
88
|
+
puts
|
89
|
+
puts "Additional topics:"
|
90
|
+
puts
|
91
|
+
summary_for_namespaces(additional_namespaces)
|
92
|
+
puts
|
93
|
+
end
|
117
94
|
|
118
|
-
|
119
|
-
|
95
|
+
def help_for_namespace(name)
|
96
|
+
namespace_commands = commands_for_namespace(name)
|
120
97
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
end
|
98
|
+
unless namespace_commands.empty?
|
99
|
+
size = longest(namespace_commands.map { |c| c[:banner] })
|
100
|
+
namespace_commands.sort_by { |c| c[:method].to_s }.each do |command|
|
101
|
+
next if command[:help] =~ /DEPRECATED/
|
102
|
+
command[:summary] ||= legacy_help_for_command(command[:command])
|
103
|
+
puts " %-#{size}s # %s" % [ command[:banner], command[:summary] ]
|
128
104
|
end
|
129
105
|
end
|
106
|
+
end
|
130
107
|
|
131
|
-
|
132
|
-
|
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
|
108
|
+
def help_for_command(name)
|
109
|
+
command = commands[name]
|
146
110
|
|
147
|
-
|
148
|
-
|
111
|
+
if command
|
112
|
+
if command[:help].strip.length > 0
|
113
|
+
print "Usage: spacialdb #{command[:banner]}"
|
114
|
+
puts command[:help].split("\n")[1..-1].join("\n")
|
149
115
|
puts
|
150
|
-
|
116
|
+
else
|
117
|
+
puts "Usage: spacialdb #{command[:banner]}"
|
118
|
+
puts
|
119
|
+
puts " " + legacy_help_for_command(name).to_s
|
151
120
|
puts
|
152
121
|
end
|
153
122
|
end
|
123
|
+
|
124
|
+
unless commands_for_namespace(name).empty?
|
125
|
+
puts "Additional commands, type \"spacialdb help COMMAND\" for more details:"
|
126
|
+
puts
|
127
|
+
help_for_namespace(name)
|
128
|
+
puts
|
129
|
+
end
|
154
130
|
end
|
155
131
|
end
|