dor-services 4.6.5 → 4.6.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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