ibm_sbdtc_rest 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 David Ruan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,18 @@
1
+ = ibm_sbdtc_rest
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but
13
+ bump version in a commit by itself I can ignore when I pull)
14
+ * Send me a pull request. Bonus points for topic branches.
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2009 David Ruan. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,66 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ibm_sbdtc_rest"
8
+ gem.summary = %Q{isbdtc rest api client}
9
+ gem.description = %Q{isbdtc rest api client}
10
+ gem.email = "ruanwz@gmail.com"
11
+ gem.homepage = "http://github.com/ruanwz/ibm_sbdtc_rest"
12
+ gem.authors = ["David Ruan"]
13
+ gem.add_development_dependency "rspec", ">=1.2.9"
14
+ gem.add_development_dependency "cucumber", ">= 0"
15
+ gem.add_development_dependency "jeweler", ">= 1.4.0"
16
+ gem.add_dependency "thor", ">=0.11.8"
17
+ gem.add_dependency "json", ">=1.1.9"
18
+ gem.add_dependency "rest-client", ">=1.0.4"
19
+ gem.files = FileList['lib/**/*.rb', 'bin/*', '[A-Z]*', 'test/**/*'].to_a
20
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
21
+ end
22
+ Jeweler::GemcutterTasks.new
23
+ rescue LoadError
24
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
25
+ end
26
+
27
+ require 'spec/rake/spectask'
28
+ Spec::Rake::SpecTask.new(:spec) do |spec|
29
+ spec.libs << 'lib' << 'spec'
30
+ spec.spec_files = FileList['spec/**/*_spec.rb']
31
+ end
32
+
33
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
34
+ spec.libs << 'lib' << 'spec'
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :spec => :check_dependencies
40
+
41
+ begin
42
+ require 'cucumber/rake/task'
43
+ Cucumber::Rake::Task.new(:features)
44
+
45
+ task :features => :check_dependencies
46
+ rescue LoadError
47
+ task :features do
48
+ abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
49
+ end
50
+ end
51
+
52
+ task :default => :spec
53
+
54
+ require 'rake/rdoctask'
55
+ Rake::RDocTask.new do |rdoc|
56
+ if File.exist?('VERSION')
57
+ version = File.read('VERSION')
58
+ else
59
+ version = ""
60
+ end
61
+
62
+ rdoc.rdoc_dir = 'rdoc'
63
+ rdoc.title = "ibm_sbdtc_rest #{version}"
64
+ rdoc.rdoc_files.include('README*')
65
+ rdoc.rdoc_files.include('lib/**/*.rb')
66
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'thor'
5
+ begin
6
+ if RUBY_VERSION <= '1.8.6'
7
+ require 'ruby-debug'
8
+ end
9
+ rescue LoadError
10
+ end
11
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
12
+ require 'ibm_sbdtc_rest'
13
+ require 'pp'
14
+
15
+ class IbmCloudAdmin < Thor
16
+ map "-h" => :help
17
+ map "-li" => :list_instances
18
+ map "-v" => :version
19
+ map "--list_instances" => :list_instances
20
+
21
+ desc 'list_instances', "list the current instances of IbmCloudAdmin"
22
+ def list_instances
23
+ server = IbmCloudRest.new
24
+ puts JSON.pretty_generate(server.instances)
25
+ end
26
+
27
+ desc 'version', "the current version of IbmCloudAdmin"
28
+ def version
29
+ version_file = File.dirname(__FILE__) + '/../VERSION'
30
+ if File.exists?(version_file) and version = File.read(version_file)
31
+ puts "IbmCloudAdmin version: #{version}"
32
+ end
33
+ end
34
+
35
+ desc 'help', 'help output'
36
+ def help
37
+ puts %{
38
+ Usage: #{$0} /path/to/your/app [options]
39
+
40
+ Options:
41
+ -g, --generate Run the generate command to build a project
42
+ -li, --list_instances List all instances
43
+ -j, --just_recipe Run the just_recipe command to only run specified recipes, templates, etc.
44
+ -d, --display Instead of running, show the template or recipe body
45
+ -r, --recipes Recipes to use
46
+ -s, --save Save current set of options
47
+ -u, --use Use a saved set of options
48
+ --gems Gems to include
49
+
50
+ IbmCloudAdmin Info:
51
+ -v, --version Show the IbmCloudAdmin version number and quit.
52
+ -l, --list Show the various recipes known to IbmCloudAdmin and quit.
53
+ -h, --help Show this help message and quit.
54
+
55
+ General Options:
56
+
57
+ Description:
58
+ IbmCloudAdmin is used for Ibm Cloud Service.
59
+
60
+ Example:
61
+ }
62
+ end
63
+ end
64
+ def method_missing(*args)
65
+ unless @activesupport_required
66
+ require 'activesupport'
67
+ @activesupport_required = true
68
+ m = args.shift
69
+ send(m, *args)
70
+ else
71
+ super
72
+ end
73
+ end
74
+
75
+ IbmCloudAdmin.start
76
+
@@ -0,0 +1,45 @@
1
+ module RestClientAdapter
2
+
3
+ module API
4
+ def read_config
5
+ if File.exists? File.expand_path('~/.isbdtcrc')
6
+ return YAML.load(File.new(File.expand_path('~/.isbdtcrc')))
7
+ else
8
+ raise "Error while read config file"
9
+ end
10
+ end
11
+ def proxy=(url)
12
+ RestClient.proxy = url
13
+ end
14
+
15
+ def proxy
16
+ RestClient.proxy
17
+ end
18
+
19
+ def get(uri, headers={:accept => 'application/json'})
20
+ #RestClient.get(uri, headers)
21
+ config = read_config
22
+ rest_get=RestClient::Request.new(:method => :get, :url => uri, :headers => headers,:user => config['user'], :password => config['password'])
23
+ rest_get.execute
24
+ end
25
+
26
+ def post(uri, payload, headers={:accept => 'application/json'})
27
+ RestClient.post(uri, payload, headers)
28
+ end
29
+
30
+ def put(uri, payload, headers={:accept => 'application/json'})
31
+ RestClient.put(uri, payload, headers)
32
+ end
33
+
34
+ def delete(uri, headers={:accept => 'application/json'})
35
+ RestClient.delete(uri, headers)
36
+ end
37
+
38
+ def copy(uri, headers)
39
+ RestClient::Request.execute( :method => :copy,
40
+ :url => uri,
41
+ :headers => headers)
42
+ end
43
+ end
44
+
45
+ end
File without changes
@@ -0,0 +1,328 @@
1
+ require 'cgi'
2
+ require "base64"
3
+
4
+ module IbmCloudRest
5
+ class Database
6
+ attr_reader :server, :host, :name, :root, :uri
7
+ attr_accessor :bulk_save_cache_limit
8
+
9
+ # Create a IbmCloudRest::Database adapter for the supplied IbmCloudRest::Server
10
+ # and database name.
11
+ #
12
+ # ==== Parameters
13
+ # server<IbmCloudRest::Server>:: database host
14
+ # name<String>:: database name
15
+ #
16
+ def initialize(server, name)
17
+ @name = name
18
+ @server = server
19
+ @host = server.uri
20
+ @uri = "/#{name.gsub('/','%2F')}"
21
+ @root = host + uri
22
+ @streamer = Streamer.new(self)
23
+ @bulk_save_cache = []
24
+ @bulk_save_cache_limit = 500 # must be smaller than the uuid count
25
+ end
26
+
27
+ # returns the database's uri
28
+ def to_s
29
+ @root
30
+ end
31
+
32
+ # GET the database info from CouchDB
33
+ def info
34
+ IbmCloudRest.get @root
35
+ end
36
+
37
+ # Query the <tt>_all_docs</tt> view. Accepts all the same arguments as view.
38
+ def documents(params = {})
39
+ keys = params.delete(:keys)
40
+ url = IbmCloudRest.paramify_url "#{@root}/_all_docs", params
41
+ if keys
42
+ IbmCloudRest.post(url, {:keys => keys})
43
+ else
44
+ IbmCloudRest.get url
45
+ end
46
+ end
47
+
48
+ # load a set of documents by passing an array of ids
49
+ def get_bulk(ids)
50
+ documents(:keys => ids, :include_docs => true)
51
+ end
52
+ alias :bulk_load :get_bulk
53
+
54
+ # POST a temporary view function to CouchDB for querying. This is not
55
+ # recommended, as you don't get any performance benefit from CouchDB's
56
+ # materialized views. Can be quite slow on large databases.
57
+ def slow_view(funcs, params = {})
58
+ keys = params.delete(:keys)
59
+ funcs = funcs.merge({:keys => keys}) if keys
60
+ url = IbmCloudRest.paramify_url "#{@root}/_temp_view", params
61
+ JSON.parse(HttpAbstraction.post(url, funcs.to_json, {"Content-Type" => 'application/json'}))
62
+ end
63
+
64
+ # backwards compatibility is a plus
65
+ alias :temp_view :slow_view
66
+
67
+ # Query a CouchDB view as defined by a <tt>_design</tt> document. Accepts
68
+ # paramaters as described in http://wiki.apache.org/couchdb/HttpViewApi
69
+ def view(name, params = {}, &block)
70
+ keys = params.delete(:keys)
71
+ name = name.split('/') # I think this will always be length == 2, but maybe not...
72
+ dname = name.shift
73
+ vname = name.join('/')
74
+ url = IbmCloudRest.paramify_url "#{@root}/_design/#{dname}/_view/#{vname}", params
75
+ if keys
76
+ IbmCloudRest.post(url, {:keys => keys})
77
+ else
78
+ if block_given?
79
+ @streamer.view("_design/#{dname}/_view/#{vname}", params, &block)
80
+ else
81
+ IbmCloudRest.get url
82
+ end
83
+ end
84
+ end
85
+
86
+ # GET a document from CouchDB, by id. Returns a Ruby Hash.
87
+ def get(id, params = {})
88
+ slug = escape_docid(id)
89
+ url = IbmCloudRest.paramify_url("#{@root}/#{slug}", params)
90
+ result = IbmCloudRest.get(url)
91
+ return result unless result.is_a?(Hash)
92
+ doc = if /^_design/ =~ result["_id"]
93
+ Design.new(result)
94
+ else
95
+ Document.new(result)
96
+ end
97
+ doc.database = self
98
+ doc
99
+ end
100
+
101
+ # GET an attachment directly from CouchDB
102
+ def fetch_attachment(doc, name)
103
+ uri = url_for_attachment(doc, name)
104
+ HttpAbstraction.get uri
105
+ end
106
+
107
+ # PUT an attachment directly to CouchDB
108
+ def put_attachment(doc, name, file, options = {})
109
+ docid = escape_docid(doc['_id'])
110
+ name = CGI.escape(name)
111
+ uri = url_for_attachment(doc, name)
112
+ JSON.parse(HttpAbstraction.put(uri, file, options))
113
+ end
114
+
115
+ # DELETE an attachment directly from CouchDB
116
+ def delete_attachment(doc, name, force=false)
117
+ uri = url_for_attachment(doc, name)
118
+ # this needs a rev
119
+ begin
120
+ JSON.parse(HttpAbstraction.delete(uri))
121
+ rescue Exception => error
122
+ if force
123
+ # get over a 409
124
+ doc = get(doc['_id'])
125
+ uri = url_for_attachment(doc, name)
126
+ JSON.parse(HttpAbstraction.delete(uri))
127
+ else
128
+ error
129
+ end
130
+ end
131
+ end
132
+
133
+ # Save a document to CouchDB. This will use the <tt>_id</tt> field from
134
+ # the document as the id for PUT, or request a new UUID from CouchDB, if
135
+ # no <tt>_id</tt> is present on the document. IDs are attached to
136
+ # documents on the client side because POST has the curious property of
137
+ # being automatically retried by proxies in the event of network
138
+ # segmentation and lost responses.
139
+ #
140
+ # If <tt>bulk</tt> is true (false by default) the document is cached for bulk-saving later.
141
+ # Bulk saving happens automatically when #bulk_save_cache limit is exceded, or on the next non bulk save.
142
+ def save_doc(doc, bulk = false)
143
+ if doc['_attachments']
144
+ doc['_attachments'] = encode_attachments(doc['_attachments'])
145
+ end
146
+ if bulk
147
+ @bulk_save_cache << doc
148
+ return bulk_save if @bulk_save_cache.length >= @bulk_save_cache_limit
149
+ return {"ok" => true} # Compatibility with Document#save
150
+ elsif !bulk && @bulk_save_cache.length > 0
151
+ bulk_save
152
+ end
153
+ result = if doc['_id']
154
+ slug = escape_docid(doc['_id'])
155
+ begin
156
+ IbmCloudRest.put "#{@root}/#{slug}", doc
157
+ rescue HttpAbstraction::ResourceNotFound
158
+ p "resource not found when saving even tho an id was passed"
159
+ slug = doc['_id'] = @server.next_uuid
160
+ IbmCloudRest.put "#{@root}/#{slug}", doc
161
+ end
162
+ else
163
+ begin
164
+ slug = doc['_id'] = @server.next_uuid
165
+ IbmCloudRest.put "#{@root}/#{slug}", doc
166
+ rescue #old version of couchdb
167
+ IbmCloudRest.post @root, doc
168
+ end
169
+ end
170
+ if result['ok']
171
+ doc['_id'] = result['id']
172
+ doc['_rev'] = result['rev']
173
+ doc.database = self if doc.respond_to?(:database=)
174
+ end
175
+ result
176
+ end
177
+
178
+ ### DEPRECATION NOTICE
179
+ def save(doc, bulk=false)
180
+ puts "IbmCloudRest::Database's save method is being deprecated, please use save_doc instead"
181
+ save_doc(doc, bulk)
182
+ end
183
+
184
+
185
+ # POST an array of documents to CouchDB. If any of the documents are
186
+ # missing ids, supply one from the uuid cache.
187
+ #
188
+ # If called with no arguments, bulk saves the cache of documents to be bulk saved.
189
+ def bulk_save(docs = nil, use_uuids = true)
190
+ if docs.nil?
191
+ docs = @bulk_save_cache
192
+ @bulk_save_cache = []
193
+ end
194
+ if (use_uuids)
195
+ ids, noids = docs.partition{|d|d['_id']}
196
+ uuid_count = [noids.length, @server.uuid_batch_count].max
197
+ noids.each do |doc|
198
+ nextid = @server.next_uuid(uuid_count) rescue nil
199
+ doc['_id'] = nextid if nextid
200
+ end
201
+ end
202
+ IbmCloudRest.post "#{@root}/_bulk_docs", {:docs => docs}
203
+ end
204
+ alias :bulk_delete :bulk_save
205
+
206
+ # DELETE the document from CouchDB that has the given <tt>_id</tt> and
207
+ # <tt>_rev</tt>.
208
+ #
209
+ # If <tt>bulk</tt> is true (false by default) the deletion is recorded for bulk-saving (bulk-deletion :) later.
210
+ # Bulk saving happens automatically when #bulk_save_cache limit is exceded, or on the next non bulk save.
211
+ def delete_doc(doc, bulk = false)
212
+ raise ArgumentError, "_id and _rev required for deleting" unless doc['_id'] && doc['_rev']
213
+ if bulk
214
+ @bulk_save_cache << { '_id' => doc['_id'], '_rev' => doc['_rev'], '_deleted' => true }
215
+ return bulk_save if @bulk_save_cache.length >= @bulk_save_cache_limit
216
+ return { "ok" => true } # Mimic the non-deferred version
217
+ end
218
+ slug = escape_docid(doc['_id'])
219
+ IbmCloudRest.delete "#{@root}/#{slug}?rev=#{doc['_rev']}"
220
+ end
221
+
222
+ ### DEPRECATION NOTICE
223
+ def delete(doc, bulk=false)
224
+ puts "IbmCloudRest::Database's delete method is being deprecated, please use delete_doc instead"
225
+ delete_doc(doc, bulk)
226
+ end
227
+
228
+ # COPY an existing document to a new id. If the destination id currently exists, a rev must be provided.
229
+ # <tt>dest</tt> can take one of two forms if overwriting: "id_to_overwrite?rev=revision" or the actual doc
230
+ # hash with a '_rev' key
231
+ def copy_doc(doc, dest)
232
+ raise ArgumentError, "_id is required for copying" unless doc['_id']
233
+ slug = escape_docid(doc['_id'])
234
+ destination = if dest.respond_to?(:has_key?) && dest['_id'] && dest['_rev']
235
+ "#{dest['_id']}?rev=#{dest['_rev']}"
236
+ else
237
+ dest
238
+ end
239
+ IbmCloudRest.copy "#{@root}/#{slug}", destination
240
+ end
241
+
242
+ ### DEPRECATION NOTICE
243
+ def copy(doc, dest)
244
+ puts "IbmCloudRest::Database's copy method is being deprecated, please use copy_doc instead"
245
+ copy_doc(doc, dest)
246
+ end
247
+
248
+ # Compact the database, removing old document revisions and optimizing space use.
249
+ def compact!
250
+ IbmCloudRest.post "#{@root}/_compact"
251
+ end
252
+
253
+ # Create the database
254
+ def create!
255
+ bool = server.create_db(@name) rescue false
256
+ bool && true
257
+ end
258
+
259
+ # Delete and re create the database
260
+ def recreate!
261
+ delete!
262
+ create!
263
+ rescue HttpAbstraction::ResourceNotFound
264
+ ensure
265
+ create!
266
+ end
267
+
268
+ # Replicates via "pulling" from another database to this database. Makes no attempt to deal with conflicts.
269
+ def replicate_from other_db
270
+ raise ArgumentError, "must provide a CouchReset::Database" unless other_db.kind_of?(IbmCloudRest::Database)
271
+ IbmCloudRest.post "#{@host}/_replicate", :source => other_db.root, :target => name
272
+ end
273
+
274
+ # Replicates via "pushing" to another database. Makes no attempt to deal with conflicts.
275
+ def replicate_to other_db
276
+ raise ArgumentError, "must provide a CouchReset::Database" unless other_db.kind_of?(IbmCloudRest::Database)
277
+ IbmCloudRest.post "#{@host}/_replicate", :target => other_db.root, :source => name
278
+ end
279
+
280
+ # DELETE the database itself. This is not undoable and could be rather
281
+ # catastrophic. Use with care!
282
+ def delete!
283
+ clear_extended_doc_fresh_cache
284
+ IbmCloudRest.delete @root
285
+ end
286
+
287
+ private
288
+
289
+ def clear_extended_doc_fresh_cache
290
+ ::IbmCloudRest::ExtendedDocument.subclasses.each{|klass| klass.design_doc_fresh = false if klass.respond_to?(:design_doc_fresh=) }
291
+ end
292
+
293
+ def uri_for_attachment(doc, name)
294
+ if doc.is_a?(String)
295
+ puts "IbmCloudRest::Database#fetch_attachment will eventually require a doc as the first argument, not a doc.id"
296
+ docid = doc
297
+ rev = nil
298
+ else
299
+ docid = doc['_id']
300
+ rev = doc['_rev']
301
+ end
302
+ docid = escape_docid(docid)
303
+ name = CGI.escape(name)
304
+ rev = "?rev=#{doc['_rev']}" if rev
305
+ "/#{docid}/#{name}#{rev}"
306
+ end
307
+
308
+ def url_for_attachment(doc, name)
309
+ @root + uri_for_attachment(doc, name)
310
+ end
311
+
312
+ def escape_docid id
313
+ /^_design\/(.*)/ =~ id ? "_design/#{CGI.escape($1)}" : CGI.escape(id)
314
+ end
315
+
316
+ def encode_attachments(attachments)
317
+ attachments.each do |k,v|
318
+ next if v['stub']
319
+ v['data'] = base64(v['data'])
320
+ end
321
+ attachments
322
+ end
323
+
324
+ def base64(data)
325
+ Base64.encode64(data).gsub(/\s/,'')
326
+ end
327
+ end
328
+ end