duracloud-client 0.9.1 → 0.10.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/Gemfile +1 -2
- data/README.md +39 -49
- data/duracloud.gemspec +0 -1
- data/lib/duracloud.rb +34 -8
- data/lib/duracloud/abstract_entity.rb +11 -22
- data/lib/duracloud/cli.rb +35 -40
- data/lib/duracloud/client.rb +6 -35
- data/lib/duracloud/command_options.rb +11 -2
- data/lib/duracloud/commands.rb +4 -0
- data/lib/duracloud/commands/store_content.rb +13 -0
- data/lib/duracloud/content.rb +20 -7
- data/lib/duracloud/content_manifest.rb +5 -6
- data/lib/duracloud/request.rb +30 -14
- data/lib/duracloud/response.rb +2 -3
- data/lib/duracloud/response_handler.rb +63 -0
- data/lib/duracloud/rest_methods.rb +3 -2
- data/lib/duracloud/space.rb +8 -9
- data/lib/duracloud/storage_report.rb +1 -6
- data/lib/duracloud/sync_validation.rb +6 -4
- data/lib/duracloud/version.rb +1 -1
- data/spec/spec_helper.rb +4 -6
- data/spec/unit/cli_spec.rb +28 -14
- data/spec/unit/content_spec.rb +1 -2
- metadata +4 -28
- data/gemfiles/Gemfile.activemodel-4.2 +0 -3
- data/gemfiles/Gemfile.activemodel-5.0 +0 -3
- data/lib/duracloud/configuration.rb +0 -42
- data/lib/duracloud/connection.rb +0 -18
- data/lib/duracloud/durastore_request.rb +0 -7
- data/lib/duracloud/error_handler.rb +0 -56
data/lib/duracloud/client.rb
CHANGED
@@ -1,46 +1,17 @@
|
|
1
|
-
require "forwardable"
|
2
|
-
|
3
1
|
module Duracloud
|
4
2
|
class Client
|
5
|
-
extend Forwardable
|
6
3
|
extend RestMethods
|
7
4
|
include RestMethods
|
8
5
|
|
9
|
-
def self.execute(
|
10
|
-
new.execute(
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.configure
|
14
|
-
yield Configuration
|
6
|
+
def self.execute(http_method, url, **options, &block)
|
7
|
+
new.execute(http_method, url, **options, &block)
|
15
8
|
end
|
16
9
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def initialize(**options)
|
22
|
-
@config = Configuration.new(**options)
|
23
|
-
end
|
24
|
-
|
25
|
-
def execute(request_class, http_method, url, **options, &block)
|
26
|
-
request = request_class.new(self, http_method, url, **options)
|
27
|
-
response = request.execute(&block)
|
28
|
-
handle_response(response)
|
29
|
-
response
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def handle_response(response)
|
35
|
-
logger.debug([self.class.to_s, response.request_method, response.url, response.request_query,
|
36
|
-
response.status, response.reason].join(' '))
|
37
|
-
if response.error?
|
38
|
-
ErrorHandler.call(response)
|
39
|
-
elsif %w(POST PUT DELETE).include?(response.request_method) &&
|
40
|
-
response.plain_text? &&
|
41
|
-
response.has_body?
|
42
|
-
logger.info(response.body)
|
10
|
+
def execute(http_method, url, **options, &block)
|
11
|
+
Request.execute(http_method, url, **options, &block).tap do |response|
|
12
|
+
ResponseHandler.call(response)
|
43
13
|
end
|
44
14
|
end
|
15
|
+
|
45
16
|
end
|
46
17
|
end
|
@@ -4,10 +4,14 @@ require 'hashie'
|
|
4
4
|
module Duracloud
|
5
5
|
class CommandOptions < Hashie::Mash
|
6
6
|
|
7
|
-
def
|
8
|
-
|
7
|
+
def self.parse(*args)
|
8
|
+
new.parse(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse(*args)
|
9
12
|
self.command = args.shift if CLI::COMMANDS.include?(args.first)
|
10
13
|
parser.parse!(args)
|
14
|
+
to_hash(symbolize_keys: true)
|
11
15
|
end
|
12
16
|
|
13
17
|
def print_version
|
@@ -113,6 +117,11 @@ module Duracloud
|
|
113
117
|
opts.on("--[no-]all-spaces", "Get report for all spaces") do |v|
|
114
118
|
self.all_spaces = v
|
115
119
|
end
|
120
|
+
|
121
|
+
opts.on("-t", "--content-type CONTENT_TYPE",
|
122
|
+
"Media type of content to store") do |v|
|
123
|
+
self.content_type = v
|
124
|
+
end
|
116
125
|
end
|
117
126
|
end
|
118
127
|
|
data/lib/duracloud/commands.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Duracloud::Commands
|
2
|
+
class StoreContent < Command
|
3
|
+
|
4
|
+
def call
|
5
|
+
File.open(infile, "rb") do |body|
|
6
|
+
Duracloud::Content.create(space_id: space_id, store_id: store_id,
|
7
|
+
content_id: content_id, body: body,
|
8
|
+
md5: md5, content_type: content_type)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
data/lib/duracloud/content.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require "active_model"
|
2
|
-
|
3
1
|
module Duracloud
|
4
2
|
#
|
5
3
|
# A piece of content in DuraCloud
|
@@ -13,6 +11,17 @@ module Duracloud
|
|
13
11
|
COPY_SOURCE_STORE_HEADER = "x-dura-meta-copy-source-store"
|
14
12
|
MANIFEST_EXT = ".dura-manifest"
|
15
13
|
|
14
|
+
property :space_id, required: true
|
15
|
+
property :content_id, required: true
|
16
|
+
property :store_id
|
17
|
+
property :body
|
18
|
+
property :md5
|
19
|
+
property :content_type
|
20
|
+
property :size
|
21
|
+
property :modified
|
22
|
+
|
23
|
+
alias_method :id, :content_id
|
24
|
+
|
16
25
|
# Does the content exist in DuraCloud?
|
17
26
|
# @return [Boolean] whether the content exists.
|
18
27
|
# @raise [Duracloud::MessageDigestError] the provided digest in the :md5 keyword option,
|
@@ -45,10 +54,14 @@ module Duracloud
|
|
45
54
|
new(**kwargs).save
|
46
55
|
end
|
47
56
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
57
|
+
# Delete content from DuraCloud.
|
58
|
+
# @return [Duraclound::Content] the deleted content.
|
59
|
+
# @raise [Duracloud::NotFoundError] the space, content or store (if given) does not exist.
|
60
|
+
# @raise [Duracloud::MessageDigestError] the provided digest in the :md5 keyword option,
|
61
|
+
# if given, does not match the stored value.
|
62
|
+
def self.delete(**kwargs)
|
63
|
+
find(**kwargs).delete
|
64
|
+
end
|
52
65
|
|
53
66
|
# Return the space associated with this content.
|
54
67
|
# @return [Duracloud::Space] the space.
|
@@ -81,7 +94,7 @@ module Duracloud
|
|
81
94
|
# The current instance still represents the original content.
|
82
95
|
# @raise [Duracloud::Error]
|
83
96
|
def copy(**args)
|
84
|
-
dest = args.
|
97
|
+
dest = args.reject { |k, v| k == :force }
|
85
98
|
dest[:space_id] ||= space_id
|
86
99
|
dest[:store_id] ||= store_id
|
87
100
|
dest[:content_id] ||= content_id
|
@@ -1,13 +1,12 @@
|
|
1
1
|
require 'nokogiri'
|
2
|
-
require '
|
2
|
+
require 'hashie'
|
3
3
|
|
4
4
|
module Duracloud
|
5
|
-
class ContentManifest
|
6
|
-
include ActiveModel::Model
|
5
|
+
class ContentManifest < Hashie::Dash
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
property :space_id, required: true
|
8
|
+
property :manifest_id, required: true
|
9
|
+
property :store_id
|
11
10
|
|
12
11
|
def self.find(**kwargs)
|
13
12
|
new(**kwargs).tap do |manifest|
|
data/lib/duracloud/request.rb
CHANGED
@@ -1,29 +1,47 @@
|
|
1
1
|
require 'addressable/uri'
|
2
|
+
require 'httpclient'
|
2
3
|
|
3
4
|
module Duracloud
|
4
5
|
class Request
|
5
|
-
attr_reader :client, :url, :http_method, :body, :headers, :query
|
6
6
|
|
7
|
-
|
7
|
+
attr_reader :url, :http_method, :body, :headers, :query
|
8
|
+
|
9
|
+
def self.execute(http_method, url, **options, &block)
|
10
|
+
request = new(http_method, url, **options)
|
11
|
+
request.execute(&block)
|
12
|
+
end
|
13
|
+
|
8
14
|
# @param http_method [Symbol] the lower-case symbol corresponding to HTTP method
|
9
15
|
# @param url [String] relative or absolute URL
|
10
16
|
# @param body [String] the body of the request
|
11
17
|
# @param headers [Hash] HTTP headers
|
12
18
|
# @param query [Hash] Query string parameters
|
13
19
|
# def initialize(client, http_method, url, body: nil, headers: nil, query: nil)
|
14
|
-
def initialize(
|
15
|
-
@client = client
|
20
|
+
def initialize(http_method, url, **options)
|
16
21
|
@http_method = http_method
|
17
22
|
@url = Addressable::URI.parse(url).normalize.to_s
|
18
23
|
set_options(options.dup)
|
19
24
|
end
|
20
25
|
|
21
26
|
def execute(&block)
|
22
|
-
|
27
|
+
Response.new(original_response(&block)).tap do |response|
|
28
|
+
log_request(response)
|
29
|
+
end
|
23
30
|
end
|
24
31
|
|
25
32
|
private
|
26
33
|
|
34
|
+
def log_request(response)
|
35
|
+
message = [ self.class.to_s,
|
36
|
+
response.request_method,
|
37
|
+
response.request_uri,
|
38
|
+
response.request_query,
|
39
|
+
response.status,
|
40
|
+
response.reason
|
41
|
+
].join(' ')
|
42
|
+
Duracloud.logger.debug(message)
|
43
|
+
end
|
44
|
+
|
27
45
|
def original_response(&block)
|
28
46
|
connection.send(http_method,
|
29
47
|
url,
|
@@ -41,16 +59,14 @@ module Duracloud
|
|
41
59
|
@query = query.merge(options).reject { |k, v| v.to_s.empty? }
|
42
60
|
end
|
43
61
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
def response_class
|
49
|
-
Response
|
50
|
-
end
|
51
|
-
|
62
|
+
# @return [HTTPClient] An HTTP connection to DuraCloud.
|
63
|
+
# @note We are using HTTPClient because Net::HTTP capitalizes
|
64
|
+
# request header names which is incompatible with DuraCloud's
|
65
|
+
# custom case-sensitive content property headers (x-dura-meta-*).
|
52
66
|
def connection
|
53
|
-
|
67
|
+
HTTPClient.new(base_url: Duracloud.base_url, force_basic_auth: Duracloud.auth?).tap do |conn|
|
68
|
+
conn.set_auth(Duracloud.base_url, Duracloud.user, Duracloud.password) if Duracloud.auth?
|
69
|
+
end
|
54
70
|
end
|
55
71
|
end
|
56
72
|
end
|
data/lib/duracloud/response.rb
CHANGED
@@ -8,12 +8,10 @@ module Duracloud
|
|
8
8
|
attr_reader :original_response
|
9
9
|
|
10
10
|
delegate [:header, :body, :code, :ok?, :redirect?, :status, :reason] => :original_response,
|
11
|
-
:content_type => :header,
|
11
|
+
[:content_type, :request_method, :request_uri, :request_query] => :header,
|
12
12
|
:empty? => :body
|
13
13
|
|
14
14
|
def_delegator :header, :request_uri, :url
|
15
|
-
def_delegator :header, :request_method
|
16
|
-
def_delegator :header, :request_query
|
17
15
|
|
18
16
|
def initialize(original_response)
|
19
17
|
@original_response = original_response
|
@@ -49,5 +47,6 @@ module Duracloud
|
|
49
47
|
def modified
|
50
48
|
DateTime.parse(header["last-modified"].first) rescue nil
|
51
49
|
end
|
50
|
+
|
52
51
|
end
|
53
52
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Duracloud
|
2
|
+
class ResponseHandler
|
3
|
+
|
4
|
+
def self.call(response)
|
5
|
+
new(response).call
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :response
|
9
|
+
|
10
|
+
def initialize(response)
|
11
|
+
@response = response
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
handle_error
|
16
|
+
log_response
|
17
|
+
end
|
18
|
+
|
19
|
+
def log_response
|
20
|
+
if loggable_response_body?
|
21
|
+
Duracloud.logger.info(response.body)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def loggable_response_body?
|
26
|
+
%w(POST PUT DELETE).include?(response.request_method) &&
|
27
|
+
response.plain_text? &&
|
28
|
+
response.has_body?
|
29
|
+
end
|
30
|
+
|
31
|
+
def handle_error
|
32
|
+
if response.error?
|
33
|
+
raise exception, error_message
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def error_message
|
38
|
+
if response.plain_text? && response.has_body?
|
39
|
+
response.body
|
40
|
+
else
|
41
|
+
[ response.status, response.reason ].join(' ')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def exception
|
46
|
+
case response.status
|
47
|
+
when 400
|
48
|
+
BadRequestError
|
49
|
+
when 404
|
50
|
+
NotFoundError
|
51
|
+
when 409
|
52
|
+
ConflictError
|
53
|
+
else
|
54
|
+
if response.status >= 500
|
55
|
+
ServerError
|
56
|
+
else
|
57
|
+
Error
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -125,8 +125,9 @@ module Duracloud
|
|
125
125
|
|
126
126
|
private
|
127
127
|
|
128
|
-
def durastore(
|
129
|
-
|
128
|
+
def durastore(http_method, url_path, **options, &block)
|
129
|
+
url = [ "durastore", url_path ].join("/")
|
130
|
+
execute(http_method, url, **options, &block)
|
130
131
|
end
|
131
132
|
|
132
133
|
def durastore_content(http_method, space_id, content_id, **options, &block)
|
data/lib/duracloud/space.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'date'
|
2
|
+
require 'nokogiri'
|
3
3
|
|
4
4
|
module Duracloud
|
5
5
|
#
|
@@ -7,7 +7,10 @@ module Duracloud
|
|
7
7
|
#
|
8
8
|
class Space < AbstractEntity
|
9
9
|
|
10
|
-
|
10
|
+
property :space_id, required: true
|
11
|
+
property :store_id
|
12
|
+
|
13
|
+
alias_method :id, :space_id
|
11
14
|
|
12
15
|
# Max size of content item list for one request.
|
13
16
|
# This limit is imposed by Duracloud.
|
@@ -117,12 +120,6 @@ module Duracloud
|
|
117
120
|
end
|
118
121
|
end
|
119
122
|
|
120
|
-
attr_accessor :space_id, :store_id
|
121
|
-
alias_method :id, :space_id
|
122
|
-
|
123
|
-
after_save :reset_acls
|
124
|
-
before_delete :reset_acls
|
125
|
-
|
126
123
|
# @param space_id [String] the space ID
|
127
124
|
# @param store_id [String] the store ID (optional)
|
128
125
|
def initialize(space_id, store_id = nil)
|
@@ -249,11 +246,13 @@ module Duracloud
|
|
249
246
|
end
|
250
247
|
|
251
248
|
def do_delete
|
249
|
+
reset_acls
|
252
250
|
Client.delete_space(id, **query)
|
253
251
|
end
|
254
252
|
|
255
253
|
def do_save
|
256
254
|
persisted? ? update : create
|
255
|
+
reset_acls
|
257
256
|
end
|
258
257
|
|
259
258
|
def query
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'hashie'
|
2
|
-
require 'active_support'
|
3
2
|
|
4
3
|
module Duracloud
|
5
4
|
class StorageReport < Hashie::Trash
|
@@ -15,17 +14,13 @@ module Duracloud
|
|
15
14
|
@time ||= Time.at(timestamp / 1000.0).utc
|
16
15
|
end
|
17
16
|
|
18
|
-
def human_size
|
19
|
-
ActiveSupport::NumberHelper.number_to_human_size(byte_count, prefix: :si)
|
20
|
-
end
|
21
|
-
|
22
17
|
def to_s
|
23
18
|
<<-EOS
|
24
19
|
Date: #{time}
|
25
20
|
Space ID: #{space_id || "(all)"}
|
26
21
|
Store ID: #{store_id}
|
27
22
|
Objects: #{object_count}
|
28
|
-
Total size: #{
|
23
|
+
Total size: #{byte_count} bytes
|
29
24
|
EOS
|
30
25
|
end
|
31
26
|
|
@@ -1,11 +1,10 @@
|
|
1
|
-
require 'active_model'
|
2
1
|
require 'tempfile'
|
3
2
|
require 'csv'
|
4
3
|
require 'fileutils'
|
4
|
+
require 'hashie'
|
5
5
|
|
6
6
|
module Duracloud
|
7
|
-
class SyncValidation
|
8
|
-
include ActiveModel::Model
|
7
|
+
class SyncValidation < Hashie::Dash
|
9
8
|
|
10
9
|
TWO_SPACES = ' '
|
11
10
|
MD5_CSV_OPTS = { col_sep: TWO_SPACES }.freeze
|
@@ -15,7 +14,10 @@ module Duracloud
|
|
15
14
|
CHANGED = "CHANGED"
|
16
15
|
FOUND = "FOUND"
|
17
16
|
|
18
|
-
|
17
|
+
property :space_id, required: true
|
18
|
+
property :content_dir, required: true
|
19
|
+
property :store_id
|
20
|
+
property :work_dir
|
19
21
|
|
20
22
|
def self.call(*args)
|
21
23
|
new(*args).call
|