duracloud-client 0.9.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|