duracloud-client 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 45e670a025414a048dd0e4043e25a370ef6085ee
4
- data.tar.gz: 43ec5144e26fa7fb3334652bece16f293ddf3324
3
+ metadata.gz: 328f7556852dc8ca4dbdf2fed3314aa6ca2c160b
4
+ data.tar.gz: d10ae8810f1e964d495b8b88142246d42fc2c410
5
5
  SHA512:
6
- metadata.gz: cc638f78a134b5be821ceab5269ed84abe98d8f09bfa3d4122c1bf878dd1ab43d846fe8caf75c933e75fc868c9f3b80df8c7f98314702296535c7d6d10201c33
7
- data.tar.gz: 84dbd31e44ebbc41c3f62ecbc2d9e2c1164f3ef5823818ebb88e4ec9c9051d4d6d15b6334210bf4a226f19851a1e40c3b2186dcd64a5ad568e53f2b19701a4ad
6
+ metadata.gz: efa0688d30ec628915d6497422377c9edf95c06233af784947103ab110a4ea8925b7ff99854ccf829e024414eba6b370edd409dc525ff81b14c8707c1f6ccd93
7
+ data.tar.gz: 08bfcbd0b87934908c9b229b09400648699f90dd32e903b77d362033b8dcdbb1c737e3727e095b4a1343b32930dac68066895e5b5edc84f3d4e04c6e6a2db8e5
@@ -11,11 +11,7 @@ module Duracloud
11
11
  end
12
12
 
13
13
  def tsv
14
- response.body
15
- end
16
-
17
- def to_s
18
- tsv
14
+ super || response.body
19
15
  end
20
16
 
21
17
  private
@@ -19,7 +19,7 @@ module Duracloud
19
19
  end
20
20
 
21
21
  def tsv
22
- report.body
22
+ super || report.body
23
23
  end
24
24
 
25
25
  def completion_date
@@ -107,6 +107,24 @@ module Duracloud
107
107
  @md5
108
108
  end
109
109
 
110
+ # @return [Duracloud::Content] the copied content
111
+ # The current instance still represents the original content.
112
+ def copy(target_space_id:, target_content_id:, target_store_id: nil)
113
+ copy_headers = {'x-dura-meta-copy-source'=>[space_id, content_id].join('/')}
114
+ copy_headers['x-dura-meta-copy-source-store'] = store_id if store_id
115
+ options = { storeID: target_store_id, headers: copy_headers }
116
+ Client.copy_content(target_space_id, target_content_id, **options)
117
+ Content.find(space_id: target_space_id, content_id: target_content_id, store_id: target_store_id, md5: md5)
118
+ end
119
+
120
+ # @return [Duracloud::Content] the moved content
121
+ # The current instance still represents the deleted content.
122
+ def move(**args)
123
+ copied = copy(**args)
124
+ delete
125
+ copied
126
+ end
127
+
110
128
  private
111
129
 
112
130
  def set_md5!(response)
@@ -12,7 +12,7 @@ module Duracloud
12
12
  end
13
13
 
14
14
  def tsv
15
- tsv_response.body
15
+ super || tsv_response.body
16
16
  end
17
17
 
18
18
  def bagit
@@ -19,7 +19,7 @@ module Duracloud
19
19
  SPACE_ACLS = /\A#{PREFIX}acl-/
20
20
 
21
21
  # Copy Content headers
22
- COPY_CONTENT = /\A#{PREFIX}copy-source(-store)\z/
22
+ COPY_CONTENT = /\A#{PREFIX}copy-source(-store)?\z/
23
23
 
24
24
  # DuraCloud internal content properties
25
25
  INTERNAL = /\A#{PREFIX}content-(mimetype|size|checksum|modified)\z/
@@ -49,9 +49,8 @@ module Duracloud
49
49
  durastore_content(:put, space_id, content_id, **options)
50
50
  end
51
51
 
52
- def copy_content(space_id, content_id, **options)
53
- raise NotImplementedError,
54
- "The API method 'Copy Content' has not yet been implemented."
52
+ def copy_content(target_space_id, target_content_id, **options)
53
+ durastore_content(:put, target_space_id, target_content_id, **options)
55
54
  end
56
55
 
57
56
  def delete_content(space_id, content_id, **options)
@@ -91,7 +90,7 @@ module Duracloud
91
90
  end
92
91
 
93
92
  def durastore_content(http_method, space_id, content_id, **options)
94
- escaped_content_id = content_id.gsub(/%/, "%25")
93
+ escaped_content_id = content_id.gsub(/%/, "%25").gsub(/ /, "%20")
95
94
  url = [ space_id, escaped_content_id ].join("/")
96
95
  durastore(http_method, url, **options)
97
96
  end
data/lib/duracloud/tsv.rb CHANGED
@@ -2,31 +2,53 @@ require "csv"
2
2
 
3
3
  module Duracloud
4
4
  module TSV
5
- # @return [CSV::Table]
5
+
6
6
  def csv
7
- @csv ||= CSV::Table.new([]).tap do |csv|
8
- header_line, rows = tsv.split(/\r?\n/, 2)
9
- headers = header_line.split("\t").map { |h| h.downcase.gsub(/-/, "_") }
10
- header_row = CSV::Row.new(headers, headers, true)
11
- csv << header_row
12
- rows.split(/\r?\n/).each do |row|
13
- csv << row.split("\t")
14
- end
15
- end
7
+ @csv ||= CSV.new(tsv, csv_options)
16
8
  end
17
9
 
18
- # @return [Enumerator] rows as hashes
19
10
  def rows
20
- Enumerator.new do |e|
21
- csv.by_row!.each do |row|
22
- next if row.header_row?
23
- e << row.to_hash
24
- end
11
+ @rows ||= Enumerator.new do |e|
12
+ table.each { |row| e << row.to_hash }
25
13
  end
26
14
  end
27
15
 
16
+ def table
17
+ csv.rewind
18
+ csv.read
19
+ ensure
20
+ csv.rewind
21
+ end
22
+
28
23
  def tsv
29
- raise NotImplementedError, "Including module must implement `tsv`."
24
+ @tsv
25
+ end
26
+
27
+ def load_tsv(io_or_str)
28
+ @tsv = io_or_str
29
+ end
30
+
31
+ def load_tsv_file(path)
32
+ load_tsv(File.new(path, "rb"))
30
33
  end
34
+
35
+ def to_s
36
+ tsv.to_s
37
+ end
38
+
39
+ private
40
+
41
+ def csv_options
42
+ { col_sep: "\t",
43
+ quote_char: "`",
44
+ headers: true,
45
+ header_converters: header_converters,
46
+ }
47
+ end
48
+
49
+ def header_converters
50
+ lambda { |h| h.downcase.gsub(/-/, "_") }
51
+ end
52
+
31
53
  end
32
54
  end
@@ -1,3 +1,3 @@
1
1
  module Duracloud
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -1,22 +1,35 @@
1
1
  module Duracloud
2
2
  RSpec.describe AuditLog do
3
3
 
4
- let(:tsv) { File.read(File.expand_path('../../fixtures/audit_log.tsv', __FILE__)) }
5
-
6
- before {
7
- allow(subject).to receive(:tsv) { tsv }
8
- }
4
+ let(:path) { File.expand_path('../../fixtures/audit_log.tsv', __FILE__) }
9
5
 
10
6
  subject { described_class.new("myspace") }
11
7
 
12
- describe "CSV" do
8
+ describe "#csv" do
9
+ before {
10
+ allow(subject).to receive(:tsv) { File.read(path) }
11
+ subject.csv.read
12
+ }
13
13
  specify {
14
14
  expect(subject.csv.headers).to eq(%w(account store_id space_id content_id content_md5 content_size content_mimetype content_properties space_acls source_space_id source_content_id timestamp action username))
15
- expect(subject.csv.size).to eq(7)
16
- expect(subject.csv.to_s.split("\n").first).to eq("account,store_id,space_id,content_id,content_md5,content_size,content_mimetype,content_properties,space_acls,source_space_id,source_content_id,timestamp,action,username")
17
- expect(subject.rows.next).to eq({"account"=>"example", "store_id"=>"1065", "space_id"=>"myspace", "content_id"=>"", "content_md5"=>"", "content_size"=>"", "content_mimetype"=>"", "content_properties"=>"", "space_acls"=>"", "source_space_id"=>"", "source_content_id"=>"", "timestamp"=>"2016-04-27T18:34:18.018", "action"=>"CREATE_SPACE", "username"=>"bob@example.com"})
15
+ expect(subject.rows.to_a.size).to eq(6)
16
+ expect(subject.rows.first).to eq({"account"=>"example", "store_id"=>"1065", "space_id"=>"myspace", "content_id"=>nil, "content_md5"=>nil, "content_size"=>nil, "content_mimetype"=>nil, "content_properties"=>nil, "space_acls"=>nil, "source_space_id"=>nil, "source_content_id"=>nil, "timestamp"=>"2016-04-27T18:34:18.018", "action"=>"CREATE_SPACE", "username"=>"bob@example.com"})
18
17
  }
19
18
  end
20
19
 
20
+ describe "#load_tsv" do
21
+ it "loads a string" do
22
+ tsv = File.read(path)
23
+ subject.load_tsv(tsv)
24
+ expect(subject.tsv).to eq(tsv)
25
+ end
26
+ it "loads an IO" do
27
+ tsv = File.read(path)
28
+ tsv_io = File.new(path, "rb")
29
+ subject.load_tsv(tsv)
30
+ expect(subject.tsv.to_s).to eq(tsv)
31
+ end
32
+ end
33
+
21
34
  end
22
35
  end
@@ -1,22 +1,35 @@
1
1
  module Duracloud
2
2
  RSpec.describe BitIntegrityReport do
3
3
 
4
- let(:tsv) { File.read(File.expand_path('../../fixtures/bit_integrity_report.tsv', __FILE__)) }
5
-
6
- before {
7
- allow(subject).to receive(:tsv) { tsv }
8
- }
4
+ let(:path) { File.expand_path('../../fixtures/bit_integrity_report.tsv', __FILE__) }
9
5
 
10
6
  subject { described_class.new("myspace") }
11
7
 
12
- describe "CSV" do
8
+ describe "#csv" do
9
+ before do
10
+ allow(subject).to receive(:tsv) { File.read(path) }
11
+ subject.csv.read
12
+ end
13
13
  specify {
14
14
  expect(subject.csv.headers).to eq(%w(date_checked account store_id store_type space_id content_id result content_checksum provider_checksum manifest_checksum details))
15
- expect(subject.csv.size).to eq(4)
16
- expect(subject.csv.to_s.split("\n").first).to eq("date_checked,account,store_id,store_type,space_id,content_id,result,content_checksum,provider_checksum,manifest_checksum,details")
17
- expect(subject.rows.next).to eq({"date_checked"=>"2016-05-15T04:11:14", "account"=>"example", "store_id"=>"1065", "store_type"=>"AMAZON_S3", "space_id"=>"myspace", "content_id"=>"BINARIES/00/00/e8/0000e819ac3e67d039d288adaab5b5e44c3c21d9", "result"=>"SUCCESS", "content_checksum"=>"27333f3c06a6d259863384799be68d30", "provider_checksum"=>"27333f3c06a6d259863384799be68d30", "manifest_checksum"=>"27333f3c06a6d259863384799be68d30", "details"=>"--"})
15
+ expect(subject.rows.to_a.size).to eq(3)
16
+ expect(subject.rows.first).to eq({"date_checked"=>"2016-05-15T04:11:14", "account"=>"example", "store_id"=>"1065", "store_type"=>"AMAZON_S3", "space_id"=>"myspace", "content_id"=>"BINARIES/00/00/e8/0000e819ac3e67d039d288adaab5b5e44c3c21d9", "result"=>"SUCCESS", "content_checksum"=>"27333f3c06a6d259863384799be68d30", "provider_checksum"=>"27333f3c06a6d259863384799be68d30", "manifest_checksum"=>"27333f3c06a6d259863384799be68d30", "details"=>"--"})
18
17
  }
19
18
  end
20
19
 
20
+ describe "#load_tsv" do
21
+ it "loads a string" do
22
+ tsv = File.read(path)
23
+ subject.load_tsv(tsv)
24
+ expect(subject.tsv).to eq(tsv)
25
+ end
26
+ it "loads an IO" do
27
+ tsv = File.read(path)
28
+ tsv_io = File.new(path, "rb")
29
+ subject.load_tsv(tsv)
30
+ expect(subject.tsv.to_s).to eq(tsv)
31
+ end
32
+ end
33
+
21
34
  end
22
35
  end
@@ -130,9 +130,9 @@ module Duracloud
130
130
  subject.get_content_properties("foo", "bar")
131
131
  expect(stub).to have_been_requested
132
132
  }
133
- it "escapes percent signs in the content id" do
134
- stub = stub_request(:head, "https://example.com/durastore/foo/z/z/bar%252Fbaz")
135
- subject.get_content_properties("foo", "z/z/bar%2Fbaz")
133
+ it "escapes percent signs and spaces in the content id" do
134
+ stub = stub_request(:head, "https://example.com/durastore/foo/z/z/bar%252Fbaz%20spam%20eggs")
135
+ subject.get_content_properties("foo", "z/z/bar%2Fbaz spam eggs")
136
136
  expect(stub).to have_been_requested
137
137
  end
138
138
  specify {
@@ -240,8 +240,10 @@ module Duracloud
240
240
 
241
241
  describe "copy_content" do
242
242
  specify {
243
- expect { subject.copy_content("foo", "bar", headers: {'x-dura-meta-copy-source'=>'space-id/content-id'}) }
244
- .to raise_error(NotImplementedError)
243
+ stub = stub_request(:put, "https://example.com/durastore/spam/eggs")
244
+ .with(headers: {'x-dura-meta-copy-source'=>'foo/bar'})
245
+ subject.copy_content("spam", "eggs", headers: {'x-dura-meta-copy-source'=>'foo/bar'})
246
+ expect(stub).to have_been_requested
245
247
  }
246
248
  end
247
249
 
@@ -159,19 +159,48 @@ module Duracloud
159
159
  end
160
160
 
161
161
  describe "#properties" do
162
- before {
163
- allow(Client).to receive(:get_content_properties)
164
- .with("foo", "bar", hash_including(storeID: nil)) {
165
- double(headers: {'x-dura-meta-creator'=>'testuser'},
166
- content_type: 'text/plain',
167
- md5: '08a008a01d498c404b0c30852b39d3b8')
168
- }
169
- }
162
+ before do
163
+ stub_request(:head, url)
164
+ .to_return(headers: {'x-dura-meta-creator'=>'testuser',
165
+ 'Content-Type'=>'text/plain',
166
+ 'Content-MD5'=>'08a008a01d498c404b0c30852b39d3b8'})
167
+ end
170
168
  specify {
169
+ pending "Research Webmock problem with return headers"
171
170
  content = Content.find(space_id: "foo", content_id: "bar")
172
171
  expect(content.properties.x_dura_meta_creator).to eq('testuser')
173
172
  }
174
173
  end
175
174
 
175
+ describe "#copy" do
176
+ let(:target) { "https://example.com/durastore/spam/eggs" }
177
+ subject { Content.new(space_id: "foo", content_id: "bar") }
178
+ specify {
179
+ stub1 = stub_request(:put, target)
180
+ .with(headers: {'x-dura-meta-copy-source'=>'foo/bar'})
181
+ stub2 = stub_request(:head, target)
182
+ copied = subject.copy(target_space_id: "spam", target_content_id: "eggs")
183
+ expect(copied).to be_a(Content)
184
+ expect(stub1).to have_been_requested
185
+ expect(stub2).to have_been_requested
186
+ }
187
+ end
188
+
189
+ describe "#move" do
190
+ let(:target) { "https://example.com/durastore/spam/eggs" }
191
+ subject { Content.new(space_id: "foo", content_id: "bar") }
192
+ specify {
193
+ stub1 = stub_request(:put, target)
194
+ .with(headers: {'x-dura-meta-copy-source'=>'foo/bar'})
195
+ stub2 = stub_request(:head, target)
196
+ stub3 = stub_request(:delete, "https://example.com/durastore/foo/bar")
197
+ moved = subject.move(target_space_id: "spam", target_content_id: "eggs")
198
+ expect(moved).to be_a(Content)
199
+ expect(stub1).to have_been_requested
200
+ expect(stub2).to have_been_requested
201
+ expect(stub3).to have_been_requested
202
+ }
203
+ end
204
+
176
205
  end
177
206
  end
@@ -1,22 +1,34 @@
1
1
  module Duracloud
2
2
  RSpec.describe Manifest do
3
3
 
4
- let(:tsv) { File.read(File.expand_path('../../fixtures/manifest.tsv', __FILE__)) }
5
-
6
- before {
7
- allow(subject).to receive(:tsv) { tsv }
8
- }
9
-
10
4
  subject { described_class.new("myspace") }
5
+ let(:path) { File.expand_path('../../fixtures/manifest.tsv', __FILE__) }
11
6
 
12
- describe "CSV" do
7
+ describe "#csv" do
8
+ before do
9
+ allow(subject).to receive(:tsv) { File.read(path) }
10
+ subject.csv.read
11
+ end
13
12
  specify {
14
13
  expect(subject.csv.headers).to eq(%w(space_id content_id md5))
15
- expect(subject.csv.size).to eq(4)
16
- expect(subject.csv.to_s.split("\n").first).to eq("space_id,content_id,md5")
17
- expect(subject.rows.next).to eq({"space_id"=>"myspace", "content_id"=>"METADATA/d6/42/0c/9c/d6420c9c-82f8-4f6a-baf7-37b9be7f4c5f/20160502_172925/manifest-md5.txt", "md5"=>"21fef474787860ccfb67bdd99ddee93a"})
14
+ expect(subject.rows.to_a.size).to eq(3)
15
+ expect(subject.rows.first).to eq({"space_id"=>"myspace", "content_id"=>"METADATA/d6/42/0c/9c/d6420c9c-82f8-4f6a-baf7-37b9be7f4c5f/20160502_172925/manifest-md5.txt", "md5"=>"21fef474787860ccfb67bdd99ddee93a"})
18
16
  }
19
17
  end
20
18
 
19
+ describe "#load_tsv" do
20
+ it "loads a string" do
21
+ tsv = File.read(path)
22
+ subject.load_tsv(tsv)
23
+ expect(subject.tsv).to eq(tsv)
24
+ end
25
+ it "loads an IO" do
26
+ tsv = File.read(path)
27
+ tsv_io = File.new(path, "rb")
28
+ subject.load_tsv(tsv)
29
+ expect(subject.tsv.to_s).to eq(tsv)
30
+ end
31
+ end
32
+
21
33
  end
22
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: duracloud-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Chandek-Stark
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-25 00:00:00.000000000 Z
11
+ date: 2017-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie