sdr-replication 0.1.0

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.
@@ -0,0 +1,33 @@
1
+ require File.join(File.dirname(__FILE__),'../libdir')
2
+ require 'sdr_replication'
3
+
4
+ module Replication
5
+
6
+ # A wrapper class around the systemu gem that is used for shelling out to the operating system
7
+ # and executing a command
8
+ #
9
+ # @note Copyright (c) 2014 by The Board of Trustees of the Leland Stanford Junior University.
10
+ # All rights reserved. See {file:LICENSE.rdoc} for details.
11
+ class OperatingSystem
12
+
13
+ # Executes a system command in a subprocess.
14
+ # The method will return stdout from the command if execution was successful.
15
+ # The method will raise an exception if if execution fails.
16
+ # The exception's message will contain the explaination of the failure.
17
+ # @param [String] command the command to be executed
18
+ # @return [String] stdout from the command if execution was successful
19
+ def OperatingSystem.execute(command)
20
+ status, stdout, stderr = systemu(command)
21
+ if (status.exitstatus != 0)
22
+ raise stderr
23
+ end
24
+ return stdout
25
+ rescue
26
+ msg = "Command failed to execute: [#{command}] caused by <STDERR = #{stderr.split($/).join('; ')}>"
27
+ msg << " STDOUT = #{stdout.split($/).join('; ')}" if (stdout && (stdout.length > 0))
28
+ raise msg
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,62 @@
1
+ require File.join(File.dirname(__FILE__),'../libdir')
2
+ require 'sdr_replication'
3
+
4
+ module Replication
5
+
6
+ # The metadata concerning the digital object/version that is the subject of replication.
7
+ #
8
+ # @note Copyright (c) 2014 by The Board of Trustees of the Leland Stanford Junior University.
9
+ # All rights reserved. See {file:LICENSE.rdoc} for details.
10
+ class Replica
11
+
12
+ @@replica_cache_pathname = nil
13
+
14
+ # @return [Pathname] The base location of the replica cache
15
+ def Replica.replica_cache_pathname
16
+ @@replica_cache_pathname
17
+ end
18
+
19
+ # @return [Pathname] Set the base location of the replica cache
20
+ # @param [Pathname,String] replica_cache_pathname The base location of the replica cache
21
+ def Replica.replica_cache_pathname=(replica_cache_pathname)
22
+ @@replica_cache_pathname = Pathname(replica_cache_pathname)
23
+ end
24
+
25
+ # @return [String] The unique identifier for the digital object replica
26
+ attr_accessor :replica_id
27
+
28
+ # @return [String] The original home location of the replica (sdr or dpn)
29
+ attr_accessor :home_repository
30
+
31
+ # @return [Time] The timestamp of the datetime at which the replica was created
32
+ attr_accessor :create_date
33
+
34
+ # @return [BagitBag] A bag containing a copy of the replica
35
+ attr_accessor :bagit_bag
36
+
37
+ # @return [Integer] The size (in bytes) of the replic bag's payload
38
+ attr_accessor :payload_size
39
+
40
+ # @return [String] The type of checksum/digest type (:sha1, :sha256)
41
+ attr_accessor :payload_fixity_type
42
+
43
+ # @return [String] The value of the checksum/digest
44
+ attr_accessor :payload_fixity
45
+
46
+ # @param [String] replica_id The unique identifier for the digital object replica
47
+ # @param [String] home_repository The original home location of the replica (sdr or dpn)
48
+ # @return [Replica] Initialize a new Replica object
49
+ def initialize(replica_id, home_repository)
50
+ @replica_id = replica_id
51
+ @home_repository = home_repository
52
+ end
53
+
54
+ # @return [Pathname] The location of the replica bag
55
+ def replica_pathname
56
+ @replica_pathname ||= @@replica_cache_pathname.join(home_repository,replica_id)
57
+ end
58
+
59
+ end
60
+ end
61
+
62
+
@@ -0,0 +1,63 @@
1
+ require File.join(File.dirname(__FILE__),'../libdir')
2
+ require 'sdr_replication'
3
+
4
+ module Replication
5
+
6
+ #
7
+ # @note Copyright (c) 2014 by The Board of Trustees of the Leland Stanford Junior University.
8
+ # All rights reserved. See {file:LICENSE.rdoc} for details.
9
+ class SdrObjectVersion
10
+
11
+ # @return [Moab::StorageObjectVersion] Represents the object version's storage location
12
+ attr_accessor :moab_object_version
13
+
14
+ # @param [Moab::StorageObjectVersion] object_version Represents the object version's storage location
15
+ # @return [SdrObjectVersion] Initialize a new SdrObjectVersion object
16
+ def initialize(object_version)
17
+ @moab_object_version = object_version
18
+ end
19
+
20
+ # @return [String] The digital object identifier (druid)
21
+ def sdr_object_id
22
+ @sdr_object_id ||= moab_object_version.storage_object.digital_object_id
23
+ end
24
+
25
+ # @return [Integer] The digital object version number
26
+ def sdr_version_id
27
+ @sdr_version_id ||= moab_object_version.version_id
28
+ end
29
+
30
+ # @return [Moab::FileInventory] The moab version manifest for the version
31
+ def version_inventory
32
+ @version_inventory ||= moab_object_version.file_inventory('version')
33
+ end
34
+
35
+ # @return [Moab::FileInventory] The moab version manifest for the version
36
+ def version_additions
37
+ @version_additions ||= moab_object_version.file_inventory('additions')
38
+ end
39
+
40
+ # @return [String] The unique identifier for the digital object replica
41
+ def replica_id
42
+ @replica_id ||= "#{sdr_object_id.split(':').last}-#{moab_object_version.version_name}"
43
+ end
44
+
45
+ # @return [Replica] The Replica of the object version that is archived to tape, etc
46
+ def replica
47
+ @replica ||= Replica.new(replica_id, 'sdr')
48
+ end
49
+
50
+ # @return [BagitBag] Copy the object version into a BagIt Bag in tarfile format
51
+ def moab_to_replica_bag
52
+ bag_dir = replica.replica_pathname
53
+ bag = BagitBag.create_bag(bag_dir)
54
+ bag.bag_checksum_types = [:sha256]
55
+ bag.add_payload_tarfile("#{replica_id}.tar",moab_object_version.version_pathname, moab_object_version.storage_object.object_pathname.parent)
56
+ bag.write_bag_info_txt
57
+ bag.write_manifest_checksums('tagmanifest', bag.generate_tagfile_checksums)
58
+ bag
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -0,0 +1,160 @@
1
+ require File.join(File.dirname(__FILE__),'../libdir')
2
+ require 'sdr_replication'
3
+
4
+ module Replication
5
+
6
+ # A tar archive file containing a set of digital object files
7
+ #
8
+ # @note Copyright (c) 2014 by The Board of Trustees of the Leland Stanford Junior University.
9
+ # All rights reserved. See {file:LICENSE.rdoc} for details.
10
+ class Tarfile
11
+
12
+ # @return [String] create archive of the specified format
13
+ # * gnu = GNU tar 1.13.x format
14
+ # * posix = POSIX 1003.1-2001 (pax) format
15
+ attr_accessor :format
16
+
17
+ # @return [Boolean] Follow symlinks and archive the files they point to
18
+ attr_accessor :dereference
19
+
20
+ # @return [Boolean] Verify that files were copied faithfully
21
+ attr_accessor :verify
22
+
23
+ # @return [Boolean] Create/list/extract multi-volume archive (not yet implemented)
24
+ attr_accessor :multi_volume
25
+
26
+ # @param [Hash<Symbol,Object>] options Key,Value pairs specifying initial values of attributes
27
+ # @return [Tarfile] Initialize a new Tarfile object
28
+ def initialize(options=nil)
29
+ options={} if options.nil?
30
+ # set defaults
31
+ @format=:posix
32
+ @dereference = true
33
+ @verify = false
34
+ @multi_volume = false
35
+ # override defaults
36
+ options.each do |key,value|
37
+ #instance_variable_set("@#{key}", value)
38
+ send "#{key}=", value
39
+ end
40
+ end
41
+
42
+ # @return [Pathname] The full path of the ancestor dir in which the tar file resides
43
+ def tarfile_basepath
44
+ raise "Tarfile basepath is nil" unless @tarfile_basepath
45
+ @tarfile_basepath
46
+ end
47
+
48
+ # @param [Pathname,String] basepath The full path of the ancestor dir in which the tar file resides
49
+ # @return [Void] Set the full path of the ancestor dir in which the tar file resides
50
+ def tarfile_basepath=(basepath)
51
+ raise "No pathname specified" unless basepath
52
+ @tarfile_basepath = Pathname(basepath).expand_path
53
+ end
54
+
55
+ # @return [Pathname] the full path of the tar archive file to be created or extracted from
56
+ def tarfile_fullpath
57
+ @tarfile_fullpath
58
+ end
59
+
60
+ # @param [Pathname,String] fullpath The full path of tar file
61
+ # @return [Void] Sets the full path of tar file
62
+ def tarfile_fullpath=(fullpath)
63
+ @tarfile_fullpath = Pathname(fullpath).expand_path
64
+ end
65
+
66
+ # @return [String] The id (path relative to basepath) of the tar file
67
+ def tarfile_relative_path
68
+ @tarfile_fullpath.relative_path_from(@tarfile_basepath).to_s
69
+ end
70
+
71
+ # @return [Pathname] The full path of the source file or directory being archived
72
+ def source_fullpath
73
+ raise "Source pathname is nil" unless @source_pathname
74
+ @source_pathname
75
+ end
76
+
77
+ # @param [Pathname,String] source The full path of the source file or directory being archived
78
+ # @return [Void] Set the full path of the source file or directory being archived
79
+ def source_fullpath=(source)
80
+ raise "No pathname specified" unless source
81
+ @source_pathname = Pathname(source).expand_path
82
+ end
83
+
84
+ # @return [Pathname] The directory that is the basis of relative paths
85
+ def source_basepath
86
+ @source_basepath
87
+ end
88
+
89
+ # @param [Pathname,String] base The directory that is the basis of relative paths
90
+ # @return [Void] Set the base path of the source file or directory being archived
91
+ def source_basepath=(base)
92
+ raise "No pathname specified" unless base
93
+ @source_basepath = Pathname(base).expand_path
94
+ end
95
+
96
+ # @return [Pathname] The relative path from the source base directory to the source directory
97
+ def source_relative_path
98
+ source_fullpath.relative_path_from(source_basepath)
99
+ end
100
+
101
+ # @return [String] The shell command string to be used to create the tarfile
102
+ def create_cmd
103
+ command = "tar --create --file=#{tarfile_fullpath} --format=#{@format} "
104
+ command << "--dereference " if @dereference
105
+ command << "--verify " if @verify
106
+ command << "--directory='#{source_basepath}' " if source_basepath
107
+ command << source_relative_path.to_s
108
+ command
109
+ end
110
+
111
+ # @return [Tarfile] Shell out to the operating system and create the tar archive file
112
+ def create_tarfile
113
+ command = create_cmd
114
+ OperatingSystem.execute(command)
115
+ self
116
+ end
117
+
118
+ # @return [String] The shell command that will list the tarfile's contents
119
+ def list_cmd
120
+ command = "tar --list --file=#{tarfile_fullpath} "
121
+ command
122
+ end
123
+
124
+ # @return [String] The list of the tarfile's contents
125
+ def list_tarfile
126
+ command = list_cmd
127
+ list = OperatingSystem.execute(command)
128
+ list
129
+ end
130
+
131
+ # @return [Pathname] The location of the directory into which the tarfile should be extracted
132
+ def target_pathname
133
+ raise "Target pathname is nil" unless @target_pathname
134
+ @target_pathname
135
+ end
136
+
137
+ # @param [Pathname,String] source The location of the directory into which the tarfile should be extracted
138
+ # @return [Void] Set the location of the directory into which the tarfile should be extracted
139
+ def target_pathname=(target)
140
+ raise "No target pathname specified" unless target
141
+ @target_pathname = Pathname(target).expand_path
142
+ end
143
+
144
+ # @return [String] The shell command that will extract the tarfile's contents # @return [Void]
145
+ def extract_cmd
146
+ command = "tar --extract --file=#{tarfile_fullpath} "
147
+ command << "--directory='#{target_pathname}' " if target_pathname
148
+ command
149
+ end
150
+
151
+ # @return [String] Shell out to the operating system and extract the tar archive file
152
+ def extract_tarfile
153
+ command = extract_cmd
154
+ stdout = OperatingSystem.execute(command)
155
+ stdout
156
+ end
157
+
158
+ end
159
+
160
+ end
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ Bundler.setup
4
+ require 'digest'
5
+ require 'find'
6
+ require 'json/pure'
7
+ require 'moab_stanford'
8
+ require 'pathname'
9
+ require 'rest-client'
10
+ require 'systemu'
11
+
12
+
13
+ # The classes used for SDR Replication workflows
14
+ module Replication
15
+ end
16
+
17
+ require 'replication/archive_catalog'
18
+ require 'replication/bagit_bag'
19
+ require 'replication/file_fixity'
20
+ require 'replication/fixity'
21
+ require 'replication/operating_system'
22
+ require 'replication/replica'
23
+ require 'replication/sdr_object_version'
24
+ require 'replication/tarfile'
25
+ include Replication
26
+
metadata ADDED
@@ -0,0 +1,198 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sdr-replication
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Richard Anderson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json_pure
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: moab-versioning
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: systemu
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rest-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: awesome_print
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: equivalent-xml
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: fakeweb
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 2.14.1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 2.14.1
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.7.1
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.7.1
139
+ - !ruby/object:Gem::Dependency
140
+ name: yard
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: Contains classes to archive and retrieve digital object version content
154
+ and metadata
155
+ email:
156
+ - rnanders@stanford.edu
157
+ executables: []
158
+ extensions: []
159
+ extra_rdoc_files: []
160
+ files:
161
+ - lib/libdir.rb
162
+ - lib/replication/archive_catalog.rb
163
+ - lib/replication/bagit_bag.rb
164
+ - lib/replication/command_consumer.rb
165
+ - lib/replication/command_producer.rb
166
+ - lib/replication/dpn_check_rep.rb
167
+ - lib/replication/file_fixity.rb
168
+ - lib/replication/fixity.rb
169
+ - lib/replication/operating_system.rb
170
+ - lib/replication/replica.rb
171
+ - lib/replication/sdr_object_version.rb
172
+ - lib/replication/tarfile.rb
173
+ - lib/sdr_replication.rb
174
+ homepage:
175
+ licenses: []
176
+ metadata: {}
177
+ post_install_message:
178
+ rdoc_options: []
179
+ require_paths:
180
+ - lib
181
+ required_ruby_version: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: '0'
186
+ required_rubygems_version: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ version: 2.2.1
191
+ requirements: []
192
+ rubyforge_project:
193
+ rubygems_version: 2.2.1
194
+ signing_key:
195
+ specification_version: 4
196
+ summary: Core methods for support of SDR Preservation Core replication
197
+ test_files: []
198
+ has_rdoc: