druid-tools 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cf9c519783ef2847427e51eaa3f35cb768d9406c
4
- data.tar.gz: ae57ca611f4fc4edd01ddaa35d6a366697e715dc
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YWYwNmM0OTExYjMwZDEyZTI4OTlmMGIzMGE5NzQ2NWY0NTlmNGVlOQ==
5
+ data.tar.gz: !binary |-
6
+ MDllNDUwYWUzMzJiZDUzZDUxZTA3NmQyYjFkMDQ1Y2FkMDQ3OWFhNg==
5
7
  SHA512:
6
- metadata.gz: 2bbdd81ce14eb76a1c65d2b94b483dc69b7148ea197f49a28e3395f9682e61d179d220a81bd407562bf744c671a6c4101c7ea64c111cefa515f2a08972fe95e3
7
- data.tar.gz: 75c06f9555897382202c5997571cfb4e15555e85a43deefba0702121e8392c33f7a5d7799d2a714c5d9397562ad651b1f4f3ad5553a1833b7209b6345234fdef
8
+ metadata.gz: !binary |-
9
+ YWQ4NzY4ODNiYWI3NjZmZTQ0MDE3NDQzYTE5OWNiMjJhZTk3N2Y0ZTlhM2U5
10
+ ZDI3NDc2NTU4NDNlOTBiMWRmOWFiNjM5NDAzNzBlOWY3NGU5MDI5NTU3ZmJk
11
+ NTgxMThjYTlmODU0NTJhYTBhNDYzZDk5NTg4ODU2NmNlNTZlZWU=
12
+ data.tar.gz: !binary |-
13
+ N2E4ODdiZGEwMzI1YTU5ODE5ZDA1MjIxMmVjNmNhODZmZmQ0YTE1ZGY4Yzhl
14
+ ODYwOTY3NWEwOTU1ZWE4NDcwYzdhODcwYTI1YzliMmRkZTNkNDFjMjE1ZmI2
15
+ YzAwYTdlZjJkNTA3NDQxM2QyMzRmZWJkNGEyYjUzNTRjNDZhNzA=
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.3
1
+ 0.4.0
@@ -1,7 +1,9 @@
1
1
  require 'pathname'
2
+ require 'fileutils'
2
3
 
3
4
  module DruidTools
4
5
  class Druid
6
+ @@deletes_directory_name = '.deletes'
5
7
  attr_accessor :druid, :base
6
8
 
7
9
  class << self
@@ -136,16 +138,84 @@ module DruidTools
136
138
  parent = this_path.parent
137
139
  parent.rmtree if parent.exist? && parent != base_pathname
138
140
  prune_ancestors parent.parent
141
+ creates_delete_record
139
142
  end
140
-
143
+
144
+ #This function checks for existance of a .deletes dir one level into the path (ex: stacks/.deletes or purl/.deletes).
145
+ #If the directory does not exist, it is created. If the directory exists, check to see if the current druid has an entry there, if it does delete it.
146
+ #This is done because a file might be deleted, then republishing, then deleted we again, and we want to log the most recent delete.
147
+ #
148
+ #@raises [Errno::EACCES] If write priveleges are denied
149
+ #
150
+ #@return [void]
151
+ def prep_deletes_dir
152
+ #Check for existences of deletes dir
153
+ create_deletes_dir if !deletes_dir_exists?
154
+ #In theory we could return true after this step (if it fires), since if there was no deletes dir then the file can't be present in the dir
155
+
156
+ #Check to see if this druid has been deleted before, meaning file currently exists
157
+ deletes_delete_record if deletes_record_exists?
158
+ end
159
+
160
+ #Provide the location for the .deletes directory in the tree
161
+ #
162
+ #@return [Pathname] the path to the directory, ex: "stacks/.deletes"
163
+ def deletes_dir_pathname
164
+ return Pathname(self.base.to_s + (File::SEPARATOR+@@deletes_directory_name))
165
+ end
166
+
167
+ def deletes_record_pathname
168
+ return Pathname(deletes_dir_pathname.to_s + File::SEPARATOR + self.id)
169
+ end
170
+
171
+ #Using the deletes directory path supplied by deletes_dir_pathname, this function determines if this directory exists
172
+ #
173
+ #@return [Boolean] true if if exists, false if it does not
174
+ def deletes_dir_exists?
175
+ return File.directory?(deletes_dir_pathname)
176
+ end
177
+
178
+ def deletes_record_exists?
179
+ return File.exists?(deletes_dir_pathname.to_s + File::SEPARATOR + self.id)
180
+ end
181
+
182
+ #Creates the deletes dir using the path supplied by deletes_dir_pathname
183
+ #
184
+ #@raises [Errno::EACCES] If write priveleges are denied
185
+ #
186
+ #@return [void]
187
+ def create_deletes_dir
188
+ FileUtils::mkdir_p deletes_dir_pathname
189
+ end
190
+
191
+ #Deletes the delete record if it currently exists. This is done to change the filed created, not just last modified time, on the system
192
+ #
193
+ #@raises [Errno::EACCES] If write priveleges are denied
194
+ #
195
+ #return [void]
196
+ def deletes_delete_record
197
+ FileUtils.rm(deletes_record_pathname) if deletes_record_exists? #thrown in to prevent an Errno::ENOENT if you call this on something without a delete record
198
+ end
199
+
200
+ #Creates an empty (pointer) file using the object's id in the .deletes dir
201
+ #
202
+ #@raises [Errno::EACCES] If write priveleges are denied
203
+ #
204
+ #@return [void]
205
+ def creates_delete_record
206
+ prep_deletes_dir
207
+ FileUtils.touch(deletes_record_pathname)
208
+ end
209
+
141
210
  # @param [Pathname] outermost_branch The branch at which pruning begins
142
211
  # @return [void] Ascend the druid tree and prune empty branches
143
212
  def prune_ancestors(outermost_branch)
144
- while outermost_branch.exist? && outermost_branch.children.size == 0
213
+ while outermost_branch.children.size == 0
145
214
  outermost_branch.rmdir
146
215
  outermost_branch = outermost_branch.parent
147
216
  break if outermost_branch == base_pathname
148
217
  end
218
+ rescue
149
219
  end
150
220
 
151
221
  end
@@ -16,7 +16,7 @@ describe DruidTools::Druid do
16
16
  FileUtils.rm_rf(File.join(@fixture_dir,'cd'))
17
17
  end
18
18
 
19
- it "should be able to validate druid strings using the valid? class method" do
19
+ it "validate druid strings using the valid? class method" do
20
20
  tests = [
21
21
  # Expected Input druid
22
22
  [true, 'druid:aa000bb0001'],
@@ -44,28 +44,28 @@ describe DruidTools::Druid do
44
44
  end
45
45
  end
46
46
 
47
- it "should provide the full druid including the prefix" do
47
+ it "provides the full druid including the prefix" do
48
48
  DruidTools::Druid.new('druid:cd456ef7890',@fixture_dir).druid.should == 'druid:cd456ef7890'
49
49
  DruidTools::Druid.new('cd456ef7890',@fixture_dir).druid.should == 'druid:cd456ef7890'
50
50
  end
51
51
 
52
- it "should extract the ID from the stem" do
52
+ it "extracts the ID from the stem" do
53
53
  DruidTools::Druid.new('druid:cd456ef7890',@fixture_dir).id.should == 'cd456ef7890'
54
54
  DruidTools::Druid.new('cd456ef7890',@fixture_dir).id.should == 'cd456ef7890'
55
55
  end
56
56
 
57
- it "should raise an exception if the druid is invalid" do
57
+ it "raises an exception if the druid is invalid" do
58
58
  lambda { DruidTools::Druid.new('nondruid:cd456ef7890',@fixture_dir) }.should raise_error(ArgumentError)
59
59
  lambda { DruidTools::Druid.new('druid:cd4567ef890',@fixture_dir) }.should raise_error(ArgumentError)
60
60
  end
61
61
 
62
- it "should build a druid tree from a druid" do
62
+ it "builds a druid tree from a druid" do
63
63
  druid = DruidTools::Druid.new(@druid_1,@fixture_dir)
64
64
  druid.tree.should == ['cd','456','ef','7890','cd456ef7890']
65
65
  druid.path.should == @tree_1
66
66
  end
67
67
 
68
- it "should create and destroy druid directories" do
68
+ it "creates and destroys druid directories" do
69
69
  File.exists?(@tree_1).should eq false
70
70
  File.exists?(@tree_2).should eq false
71
71
 
@@ -99,7 +99,7 @@ describe DruidTools::Druid do
99
99
  DruidTools::Druid.prefix = 'druid'
100
100
  end
101
101
 
102
- it "should handle alternate prefixes" do
102
+ it "handles alternate prefixes" do
103
103
  lambda { DruidTools::Druid.new('druid:cd456ef7890',@fixture_dir) }.should raise_error(ArgumentError)
104
104
  DruidTools::Druid.new('sulair:cd456ef7890',@fixture_dir).id.should == 'cd456ef7890'
105
105
  DruidTools::Druid.new('cd456ef7890',@fixture_dir).druid.should == 'sulair:cd456ef7890'
@@ -107,7 +107,7 @@ describe DruidTools::Druid do
107
107
  end
108
108
 
109
109
  describe "content directories" do
110
- it "should know where its content goes" do
110
+ it "knows where its content goes" do
111
111
  druid = DruidTools::Druid.new(@druid_1,@fixture_dir)
112
112
  druid.content_dir(false).should == File.join(@tree_1,'content')
113
113
  druid.metadata_dir(false).should == File.join(@tree_1,'metadata')
@@ -118,7 +118,7 @@ describe DruidTools::Druid do
118
118
  File.exists?(File.join(@tree_1,'temp')).should eq false
119
119
  end
120
120
 
121
- it "should create its content directories on the fly" do
121
+ it "creates its content directories on the fly" do
122
122
  druid = DruidTools::Druid.new(@druid_1,@fixture_dir)
123
123
  druid.content_dir.should == File.join(@tree_1,'content')
124
124
  druid.metadata_dir.should == File.join(@tree_1,'metadata')
@@ -129,7 +129,7 @@ describe DruidTools::Druid do
129
129
  File.exists?(File.join(@tree_1,'temp')).should eq true
130
130
  end
131
131
 
132
- it "should match glob" do
132
+ it "matches glob" do
133
133
  druid = DruidTools::Druid.new(@druid_1,@fixture_dir)
134
134
  druid.mkdir
135
135
  Dir.glob(File.join(File.dirname(druid.path), DruidTools::Druid::glob)).size.should == 1
@@ -142,37 +142,37 @@ describe DruidTools::Druid do
142
142
  @filelist = %w(1 2 3 4).collect { |num| "someFile#{num}" }
143
143
  end
144
144
 
145
- it "should find content in content directories" do
145
+ it "finds content in content directories" do
146
146
  location = @druid.content_dir
147
147
  File.open(File.join(location,'someContent'),'w') { |f| f.write 'This is the content' }
148
148
  @druid.find_content('someContent').should == File.join(location,'someContent')
149
149
  end
150
150
 
151
- it "should find content in the root directory" do
151
+ it "finds content in the root directory" do
152
152
  location = @druid.path(nil,true)
153
153
  File.open(File.join(location,'someContent'),'w') { |f| f.write 'This is the content' }
154
154
  @druid.find_content('someContent').should == File.join(location,'someContent')
155
155
  end
156
156
 
157
- it "should find content in the leaf directory" do
157
+ it "finds content in the leaf directory" do
158
158
  location = File.expand_path('..',@druid.path(nil,true))
159
159
  File.open(File.join(location,'someContent'),'w') { |f| f.write 'This is the content' }
160
160
  @druid.find_content('someContent').should == File.join(location,'someContent')
161
161
  end
162
162
 
163
- it "should not find content in the wrong content directory" do
163
+ it "does not find content in the wrong content directory" do
164
164
  location = @druid.metadata_dir
165
165
  File.open(File.join(location,'someContent'),'w') { |f| f.write 'This is the content' }
166
166
  @druid.find_content('someContent').should be_nil
167
167
  end
168
168
 
169
- it "should not find content in a higher-up directory" do
169
+ it "does not find content in a higher-up directory" do
170
170
  location = File.expand_path('../..',@druid.path(nil,true))
171
171
  File.open(File.join(location,'someContent'),'w') { |f| f.write 'This is the content' }
172
172
  @druid.find_content('someContent').should be_nil
173
173
  end
174
174
 
175
- it "should find a filelist in the content directory" do
175
+ it "finds a filelist in the content directory" do
176
176
  location = Pathname(@druid.content_dir)
177
177
  @filelist.each do |filename|
178
178
  location.join(filename).open('w') { |f| f.write "This is #{filename}" }
@@ -180,7 +180,7 @@ describe DruidTools::Druid do
180
180
  @druid.find_filelist_parent('content',@filelist).should == location
181
181
  end
182
182
 
183
- it "should find a filelist in the root directory" do
183
+ it "finds a filelist in the root directory" do
184
184
  location = Pathname(@druid.path(nil,true))
185
185
  @filelist.each do |filename|
186
186
  location.join(filename).open('w') { |f| f.write "This is #{filename}" }
@@ -188,7 +188,7 @@ describe DruidTools::Druid do
188
188
  @druid.find_filelist_parent('content',@filelist).should == location
189
189
  end
190
190
 
191
- it "should find a filelist in the leaf directory" do
191
+ it "finds a filelist in the leaf directory" do
192
192
  location = Pathname(File.expand_path('..',@druid.path(nil,true)))
193
193
  @filelist.each do |filename|
194
194
  location.join(filename).open('w') { |f| f.write "This is #{filename}" }
@@ -196,12 +196,12 @@ describe DruidTools::Druid do
196
196
  @druid.find_filelist_parent('content',@filelist).should == location
197
197
  end
198
198
 
199
- it "should raise an exception if the first file in the filelist is not found" do
199
+ it "raises an exception if the first file in the filelist is not found" do
200
200
  location = Pathname(@druid.content_dir)
201
201
  lambda{@druid.find_filelist_parent('content',@filelist)}.should raise_exception(/content dir not found for 'someFile1' when searching/)
202
202
  end
203
203
 
204
- it "should raise an exception if any other file in the filelist is not found" do
204
+ it "raises an exception if any other file in the filelist is not found" do
205
205
  location = Pathname(@druid.content_dir)
206
206
  location.join(@filelist.first).open('w') { |f| f.write "This is #{@filelist.first}" }
207
207
  lambda{@druid.find_filelist_parent('content',@filelist)}.should raise_exception(/File 'someFile2' not found/)
@@ -240,7 +240,7 @@ describe DruidTools::Druid do
240
240
  File.readlink(@tree_2).should == @source_dir
241
241
  end
242
242
 
243
- it "should not error out if the link to source already exists" do
243
+ it "does not error out if the link to source already exists" do
244
244
  @dr.mkdir_with_final_link(@source_dir)
245
245
  File.should be_symlink(@dr.path)
246
246
  File.readlink(@tree_2).should == @source_dir
@@ -250,6 +250,8 @@ describe DruidTools::Druid do
250
250
  @dr.mkdir(@fixture_dir)
251
251
  lambda { @dr.mkdir_with_final_link(@source_di) }.should raise_error(DruidTools::DifferentContentExistsError)
252
252
  end
253
+
254
+
253
255
  end
254
256
 
255
257
  describe "#prune!" do
@@ -259,7 +261,8 @@ describe DruidTools::Druid do
259
261
  let(:dr1) { DruidTools::Druid.new @druid_1, workspace }
260
262
  let(:dr2) { DruidTools::Druid.new @druid_2, workspace }
261
263
  let(:pathname1) { dr1.pathname }
262
-
264
+
265
+
263
266
  after(:each) do
264
267
  FileUtils.remove_entry workspace
265
268
  end
@@ -267,6 +270,8 @@ describe DruidTools::Druid do
267
270
  context "shared ancestor" do
268
271
 
269
272
  before(:each) do
273
+ #Nil the create records for this context because we're in a known read only one
274
+
270
275
  dr1.mkdir
271
276
  dr2.mkdir
272
277
  dr1.prune!
@@ -290,20 +295,123 @@ describe DruidTools::Druid do
290
295
  end
291
296
 
292
297
  it "removes all directories up to the base path when there are no common ancestors" do
298
+ #Make sure a delete record is not present
299
+ expect(dr1.deletes_record_exists?).to be_falsey
300
+
301
+ #Nil the create records for this test
293
302
  dr1.mkdir
294
303
  dr1.prune!
295
304
  expect(File).to_not exist(File.join(workspace, 'cd'))
296
305
  expect(File).to exist(workspace)
306
+
307
+ #Make sure a delete record was created
308
+ expect(dr1.deletes_dir_exists?).to be_truthy
309
+ expect(dr1.deletes_record_exists?).to be_truthy
297
310
  end
298
311
 
299
312
  it "removes directories with symlinks" do
313
+ #Make sure a delete record is not present
314
+ expect(dr2.deletes_record_exists?).to be_falsey
315
+
316
+ #Nil the create records for this test
300
317
  source_dir = File.join workspace, 'src_dir'
301
318
  FileUtils.mkdir_p(source_dir)
302
319
  dr2.mkdir_with_final_link(source_dir)
303
320
  dr2.prune!
304
321
  expect(File).to_not exist(dr2.path)
305
322
  expect(File).to_not exist(File.join(workspace, 'cd'))
323
+
324
+ #Make sure a delete record was created
325
+ expect(dr2.deletes_dir_exists?).to be_truthy
326
+ expect(dr2.deletes_record_exists?).to be_truthy
327
+ end
328
+
329
+ describe "logging deleted druids" do
330
+
331
+ #Purge any paths or delete records created in the test
332
+ after :each do
333
+ #Remove the .deletes dir to clean up
334
+ dr2.deletes_delete_record if dr2.deletes_record_exists?
335
+ FileUtils.rm_rf dr2.deletes_dir_pathname
336
+
337
+ end
338
+
339
+ it "returns the path to the .deletes directory as a Pathname" do
340
+ expect(dr2.deletes_dir_pathname.class).to eq(Pathname)
341
+ end
342
+
343
+ it "returns the path to the delete record for a druid as a Pathname" do
344
+ expect(dr2.deletes_record_pathname.class).to eq(Pathname)
345
+ end
346
+
347
+ it "returns the path to the delete record for a druid as top_level/.deletes/druid" do
348
+ expect(dr2.deletes_record_pathname.to_s).to eq("#{dr2.base}/.deletes/#{dr2.id}")
349
+ end
350
+
351
+ it "returns false when the .deletes dir is not present on the file system" do
352
+ expect(dr2.deletes_dir_exists?).to be_falsey
353
+ end
354
+
355
+ it "creates the .deletes dir and detect it exists" do
356
+
357
+ #Clean the .deletes dir if present
358
+ FileUtils.rm_rf dr2.deletes_dir_pathname
359
+
360
+ #Test for exists? and create
361
+ expect(dr2.deletes_dir_exists?).to be_falsey
362
+ dr2.create_deletes_dir
363
+ expect(dr2.deletes_dir_exists?).to be_truthy
364
+ end
365
+
366
+ it "returns false when the .deletes dir does not have a deleted record for a druid" do
367
+ expect(dr2.deletes_record_exists?).to be_falsey
368
+ end
369
+
370
+ it "creates a deleted record with a parent directory that has no .deletes directory and no deleted for the file and successfully create a delete record there" do
371
+ #Expect there not to be a .deletes dir or file (the file expectation is redundant I know)
372
+ expect(dr2.deletes_dir_exists?).to be_falsey
373
+ expect(dr2.deletes_record_exists?).to be_falsey
374
+
375
+ #Create the delete record
376
+ dr2.creates_delete_record
377
+
378
+ #Check to ensure items were created
379
+ expect(dr2.deletes_dir_exists?).to be_truthy
380
+ expect(dr2.deletes_record_exists?).to be_truthy
381
+ end
382
+
383
+ it "creates a delete record with a parent directory that has a .deletes directory that does not contain a delete record for this druid" do
384
+ #Expect there not to be a .deletes dir or file (the file expectation is redundant I know)
385
+ expect(dr2.deletes_dir_exists?).to be_falsey
386
+ expect(dr2.deletes_record_exists?).to be_falsey
387
+
388
+ #Creates the deletes dir and check
389
+ dr2.create_deletes_dir
390
+ expect(dr2.deletes_dir_exists?).to be_truthy
391
+ expect(dr2.deletes_record_exists?).to be_falsey
392
+
393
+ #Create the delete record
394
+ dr2.creates_delete_record
395
+
396
+ #Check to ensure items were created
397
+ expect(dr2.deletes_dir_exists?).to be_truthy
398
+ expect(dr2.deletes_record_exists?).to be_truthy
399
+ end
400
+
401
+ it "creates a delete record with a parent directory that does not have a .deletes directory and contains an older delete record" do
402
+ #Expect there not to be a .deletes dir or file (the file expectation is redundant I know)
403
+ expect(dr2.deletes_dir_exists?).to be_falsey
404
+ expect(dr2.deletes_record_exists?).to be_falsey
405
+
406
+ dr2.creates_delete_record
407
+ time = Time.now
408
+ expect(File.mtime(dr2.deletes_record_pathname)).to be <= time
409
+ sleep(1) #force a one second pause in case the machine is fast (as in not some old Commodore64), since mtime only goes down to the second
410
+
411
+ dr2.creates_delete_record
412
+ #Should have a new newer deleted record
413
+ expect(File.mtime(dr2.deletes_record_pathname)).to be > time
414
+ end
306
415
  end
307
416
  end
308
-
309
417
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: druid-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Klein
@@ -9,34 +9,34 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-04-18 00:00:00.000000000 Z
12
+ date: 2015-03-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ">="
18
+ - - ! '>='
19
19
  - !ruby/object:Gem::Version
20
20
  version: 10.1.0
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - ">="
25
+ - - ! '>='
26
26
  - !ruby/object:Gem::Version
27
27
  version: 10.1.0
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rspec
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - "~>"
32
+ - - ~>
33
33
  - !ruby/object:Gem::Version
34
34
  version: '3.0'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - "~>"
39
+ - - ~>
40
40
  - !ruby/object:Gem::Version
41
41
  version: '3.0'
42
42
  description: Tools to manipulate DRUID trees and content directories
@@ -46,7 +46,7 @@ executables: []
46
46
  extensions: []
47
47
  extra_rdoc_files: []
48
48
  files:
49
- - ".gitignore"
49
+ - .gitignore
50
50
  - Gemfile
51
51
  - LICENSE
52
52
  - README.md
@@ -103,17 +103,17 @@ require_paths:
103
103
  - lib
104
104
  required_ruby_version: !ruby/object:Gem::Requirement
105
105
  requirements:
106
- - - ">="
106
+ - - ! '>='
107
107
  - !ruby/object:Gem::Version
108
108
  version: '0'
109
109
  required_rubygems_version: !ruby/object:Gem::Requirement
110
110
  requirements:
111
- - - ">="
111
+ - - ! '>='
112
112
  - !ruby/object:Gem::Version
113
113
  version: '0'
114
114
  requirements: []
115
115
  rubyforge_project:
116
- rubygems_version: 2.4.5
116
+ rubygems_version: 2.1.2
117
117
  signing_key:
118
118
  specification_version: 4
119
119
  summary: Tools to manipulate DRUID trees and content directories