dor-services 4.6.5 → 4.6.6.1

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.
@@ -27,7 +27,6 @@ Dor::Config.configure do
27
27
  end
28
28
 
29
29
  stacks do
30
- document_cache_storage_root '/home/lyberadmin/document_cache'
31
30
  document_cache_host 'purl-dev.stanford.edu'
32
31
  document_cache_user 'lyberadmin'
33
32
  local_workspace_root '/dor/workspace'
@@ -253,8 +253,8 @@ module Dor
253
253
  end
254
254
  end
255
255
  def agreement
256
- if agreement_object and agreement_object.first
257
- agreement_object.first.pid
256
+ if agreement_object
257
+ agreement_object.pid
258
258
  else
259
259
  ''
260
260
  end
@@ -7,20 +7,39 @@ module Dor
7
7
 
8
8
  # Push file changes for shelve-able files into the stacks
9
9
  def shelve
10
+ # retrieve the differences between the current contentMetadata and the previously ingested version
11
+ shelve_diff = get_shelve_diff
12
+ # determine the location of the object's files in the stacks area
13
+ stacks_druid = DruidTools::StacksDruid.new id, Config.stacks.local_stacks_root
14
+ stacks_object_pathname = Pathname(stacks_druid.path)
15
+ # determine the location of the object's content files in the workspace area
16
+ workspace_druid = DruidTools::Druid.new(id,Config.stacks.local_workspace_root)
17
+ workspace_content_pathname = workspace_content_dir(shelve_diff, workspace_druid)
18
+ # delete, rename, or copy files to the stacks area
19
+ DigitalStacksService.remove_from_stacks(stacks_object_pathname, shelve_diff)
20
+ DigitalStacksService.rename_in_stacks(stacks_object_pathname, shelve_diff)
21
+ DigitalStacksService.shelve_to_stacks(workspace_content_pathname, stacks_object_pathname, shelve_diff)
22
+ end
23
+
24
+ # retrieve the differences between the current contentMetadata and the previously ingested version
25
+ # (filtering to select only the files that should be shelved to stacks)
26
+ def get_shelve_diff
10
27
  inventory_diff_xml = self.get_content_diff(:shelve)
11
28
  inventory_diff = Moab::FileInventoryDifference.parse(inventory_diff_xml)
12
- content_group_diff = inventory_diff.group_difference("content")
13
- deltas = content_group_diff.file_deltas
29
+ shelve_diff = inventory_diff.group_difference("content")
30
+ shelve_diff
31
+ end
14
32
 
15
- if content_group_diff.rename_require_temp_files(deltas[:renamed])
16
- triplets = content_group_diff.rename_tempfile_triplets(deltas[:renamed])
17
- DigitalStacksService.rename_in_stacks self.pid, triplets.collect{|old,new,temp| [old,temp]}
18
- DigitalStacksService.rename_in_stacks self.pid, triplets.collect{|old,new,temp| [temp,new]}
19
- else
20
- DigitalStacksService.rename_in_stacks self.pid, deltas[:renamed]
21
- end
22
- DigitalStacksService.shelve_to_stacks self.pid, deltas[:modified] + deltas[:added] + deltas[:copyadded].collect{|old,new| new}
23
- DigitalStacksService.remove_from_stacks self.pid, deltas[:deleted] + deltas[:copydeleted]
33
+ # Find the location of the object's content files in the workspace area
34
+ # @param [Moab::FileGroupDifference] content_diff The differences between the current contentMetadata and the previously ingested version
35
+ # @param [DruidTools::Druid] workspace_druid the location of the object's files in the workspace area
36
+ # @return [Pathname] The location of the object's content files in the workspace area
37
+ def workspace_content_dir (content_diff, workspace_druid)
38
+ deltas = content_diff.file_deltas
39
+ filelist = deltas[:modified] + deltas[:added] + deltas[:copyadded].collect{|old,new| new}
40
+ return nil if filelist.empty?
41
+ content_pathname = Pathname(workspace_druid.find_filelist_parent('content', filelist))
42
+ content_pathname
24
43
  end
25
44
 
26
45
  end
@@ -2,42 +2,127 @@ require 'net/ssh'
2
2
  require 'net/sftp'
3
3
 
4
4
  module Dor
5
+
5
6
  class DigitalStacksService
6
7
 
7
- def self.transfer_to_document_store(id, content, filename)
8
- druid = DruidTools::PurlDruid.new id, Config.stacks.local_document_cache_root
9
- druid.content_dir # create the druid tree if it doesn't exist yet
10
- File.open(File.join(druid.content_dir, filename), 'w') {|f| f.write content }
8
+ # Delete files from stacks that have change type 'deleted', 'copydeleted', or 'modified'
9
+ # @param [Pathname] stacks_object_pathname the stacks location of the digital object
10
+ # @param [Moab::FileGroupDifference] content_diff the content file version differences report
11
+ def self.remove_from_stacks(stacks_object_pathname, content_diff)
12
+ [:deleted, :copydeleted, :modified].each do |change_type|
13
+ subset = content_diff.subset(change_type) # {Moab::FileGroupDifferenceSubset}
14
+ subset.files.each do |moab_file| # {Moab::FileInstanceDifference}
15
+ moab_signature = moab_file.signatures.first # {Moab::FileSignature}
16
+ file_pathname = stacks_object_pathname.join(moab_file.basis_path)
17
+ self.delete_file(file_pathname, moab_signature)
18
+ end
19
+ end
20
+ end
21
+
22
+ # Delete a file, but only if it exists and matches the expected signature
23
+ # @param [Pathname] file_pathname The location of the file to be deleted
24
+ # @param [Moab::FileSignature] moab_signature The fixity values of the file
25
+ # @return [Boolean] true if file deleted, false otherwise
26
+ def self.delete_file(file_pathname, moab_signature)
27
+ if file_pathname.exist? and (file_pathname.size == moab_signature.size)
28
+ file_signature = Moab::FileSignature.new.signature_from_file(file_pathname)
29
+ if (file_signature == moab_signature)
30
+ file_pathname.delete
31
+ return true
32
+ end
33
+ end
34
+ return false
35
+ end
36
+
37
+ # Rename files from stacks that have change type 'renamed' using an intermediate temp filename.
38
+ # The 2-step renaming allows chained or cyclic renames to occur without file collisions.
39
+ # @param [Pathname] stacks_object_pathname the stacks location of the digital object
40
+ # @param [Moab::FileGroupDifference] content_diff the content file version differences report
41
+ def self.rename_in_stacks(stacks_object_pathname, content_diff)
42
+ subset = content_diff.subset(:renamed) # {Moab::FileGroupDifferenceSubset
43
+
44
+ # 1st Pass - rename files from original name to checksum-based name
45
+ subset.files.each do |moab_file| # {Moab::FileInstanceDifference}
46
+ moab_signature = moab_file.signatures.first # {Moab::FileSignature}
47
+ original_pathname = stacks_object_pathname.join(moab_file.basis_path)
48
+ temp_pathname = stacks_object_pathname.join(moab_signature.checksums.values.last)
49
+ self.rename_file(original_pathname, temp_pathname, moab_signature)
50
+ end
51
+
52
+ # 2nd Pass - rename files from checksum-based name to new name
53
+ subset.files.each do |moab_file| # {Moab::FileInstanceDifference}
54
+ moab_signature = moab_file.signatures.first # {Moab::FileSignature}
55
+ temp_pathname = stacks_object_pathname.join(moab_signature.checksums.values.last)
56
+ new_pathname = stacks_object_pathname.join(moab_file.other_path)
57
+ self.rename_file(temp_pathname, new_pathname, moab_signature)
58
+ end
59
+
11
60
  end
12
61
 
13
- def self.remove_from_stacks(id, files)
14
- files.each do |file|
15
- dr = DruidTools::StacksDruid.new id, Config.stacks.local_stacks_root
16
- content = dr.find_content file
17
- FileUtils.rm content if content
62
+ # Rename a file, but only if it exists and has the expected signature
63
+ # @param [Pathname] old_pathname The original location/name of the file being renamed
64
+ # @param [Pathname] new_pathname The new location/name of the file
65
+ # @param [Moab::FileSignature] moab_signature The fixity values of the file
66
+ # @return [Boolean] true if file renamed, false otherwise
67
+ def self.rename_file(old_pathname, new_pathname, moab_signature)
68
+ if old_pathname.exist? and (old_pathname.size == moab_signature.size)
69
+ file_signature = Moab::FileSignature.new.signature_from_file(old_pathname)
70
+ if (file_signature == moab_signature)
71
+ new_pathname.parent.mkpath
72
+ old_pathname.rename(new_pathname)
73
+ return true
74
+ end
18
75
  end
76
+ return false
19
77
  end
20
78
 
21
- # @param [String] id object pid
22
- # @param [Array<Array<String>>] file_map an array of two string arrays. Each inner array represents old-file/new-file mappings. First string is the old file name, second string is the new file name. e.g:
23
- # [ ['src1.file', 'dest1.file'], ['src2.file', 'dest2.file'] ]
24
- def self.rename_in_stacks(id, file_map)
25
- return if file_map.nil? or file_map.empty?
26
- dr = DruidTools::StacksDruid.new id, Config.stacks.local_stacks_root
27
- content_dir = dr.find_filelist_parent('content', file_map.first.first)
28
- file_map.each do |src, dest|
29
- File.rename(File.join(content_dir, src), File.join(content_dir, dest))
79
+ # Add files to stacks that have change type 'added', 'copyadded' or 'modified'.
80
+ # @param [Pathname] workspace_content_pathname The dor workspace location of the digital object's content fies
81
+ # @param [Pathname] stacks_object_pathname the stacks location of the digital object's shelved files
82
+ # @param [Moab::FileGroupDifference] content_diff the content file version differences report
83
+ def self.shelve_to_stacks(workspace_content_pathname, stacks_object_pathname, content_diff)
84
+ return false if workspace_content_pathname.nil?
85
+ [:added, :copyadded, :modified,].each do |change_type|
86
+ subset = content_diff.subset(change_type) # {Moab::FileGroupDifferenceSubset
87
+ subset.files.each do |moab_file| # {Moab::FileInstanceDifference}
88
+ moab_signature = moab_file.signatures.last # {Moab::FileSignature}
89
+ filename = (change_type == :modified) ? moab_file.basis_path : moab_file.other_path
90
+ workspace_pathname = workspace_content_pathname.join(filename)
91
+ stacks_pathname = stacks_object_pathname.join(filename)
92
+ self.copy_file(workspace_pathname, stacks_pathname, moab_signature)
93
+ end
30
94
  end
95
+ true
31
96
  end
32
97
 
33
- def self.shelve_to_stacks(id, files)
34
- workspace_druid = DruidTools::Druid.new(id,Config.stacks.local_workspace_root)
35
- stacks_druid = DruidTools::StacksDruid.new(id,Config.stacks.local_stacks_root)
36
- files.each do |file|
37
- stacks_druid.content_dir
38
- workspace_file = workspace_druid.find_content(file)
39
- FileUtils.cp workspace_file, stacks_druid.content_dir
98
+ # Copy a file to stacks, but only if it does not yet exist with the expected signature
99
+ # @param [Pathname] workspace_pathname The location of the file in the DOR workspace
100
+ # @param [Pathname] stacks_pathname The location of the file in the stacks
101
+ # @param [Moab::FileSignature] moab_signature The fixity values of the file
102
+ # @return [Boolean] true if file copied, false otherwise
103
+ def self.copy_file(workspace_pathname, stacks_pathname, moab_signature)
104
+ if stacks_pathname.exist?
105
+ file_signature = Moab::FileSignature.new.signature_from_file(stacks_pathname)
106
+ stacks_pathname.delete if (file_signature != moab_signature)
107
+ end
108
+ unless stacks_pathname.exist?
109
+ FileUtils.cp workspace_pathname.to_s, stacks_pathname.to_s
110
+ return true
40
111
  end
112
+ return false
113
+ end
114
+
115
+ ### depricated ???
116
+
117
+ # Create a file inside the content directory under the stacks.local_document_cache_root
118
+ # @param [String] id The druid identifier for the object
119
+ # @param [String] content The contents of the file to be created
120
+ # @param [String] filename The name of the file to be created
121
+ # @return [void]
122
+ def self.transfer_to_document_store(id, content, filename)
123
+ druid = DruidTools::PurlDruid.new id, Config.stacks.local_document_cache_root
124
+ druid.content_dir # create the druid tree if it doesn't exist yet
125
+ File.open(File.join(druid.content_dir, filename), 'w') { |f| f.write content }
41
126
  end
42
127
 
43
128
  # Assumes the digital stacks storage root is mounted to the local file system
@@ -1,3 +1,3 @@
1
1
  module Dor
2
- VERSION = '4.6.5'
2
+ VERSION = '4.6.6.1'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dor-services
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.6.5
4
+ version: 4.6.6.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2014-03-13 00:00:00.000000000 Z
16
+ date: 2014-06-10 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: active-fedora