lyber-utils 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Stanford University Library
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ = lyber_utils
2
+
3
+ Require the following:
4
+ require 'lyber_utils'
5
+
6
+
7
+ This will give you:
8
+ LyberUtils::BagitBag
9
+ LyberUtils::ChecksumValidate
10
+ LyberUtils::FileUtilities
11
+
12
+ If you do not want all 3, you can require the individual classes. I.E. if you only want the bagit utils, then require:
13
+ require 'lyber_utils/bagit_bag'
14
+
15
+ The BagitBag class requires the bagit gem
16
+ http://github.com/flazz/bagit
17
+
18
+ == Build and release procedure
19
+ Modify the version number in lyber-utils.gemspec, then push your commits to AFS. DO NOT TAG!
20
+ Run: 'rake dlss_release' to tag, build, and publish the lyber-core gem
21
+ See the Rakefile and the LyberCore::DlssRelease task in lyberteam-devel/lib/dlss/rake/dlss_release.rb
22
+ for more details
23
+
24
+ == Releases
25
+ - <b>1.3</b> Started to use Dor::Config for workspace configuration
26
+ - <b>0.1.1</b> Update dependent version of nokogiri for more flexibility
27
+ - <b>0.1.2</b> Ensure bag begins with an empty directory. Disallow nil values in bag-info.txt properties
28
+
29
+ == Copyright
30
+
31
+ Copyright (c) 2011 Stanford University Library. See LICENSE for details.
@@ -0,0 +1,3 @@
1
+ require 'lyber_utils/file_utilities'
2
+ require 'lyber_utils/checksum_validate'
3
+ require 'lyber_utils/bagit_bag'
@@ -0,0 +1,108 @@
1
+ require 'find'
2
+ require 'fileutils'
3
+ require 'bagit' # http://github.com/flazz/bagit
4
+
5
+ module LyberUtils
6
+
7
+ class BagitBag
8
+
9
+ attr_reader :bag_dir
10
+
11
+ def initialize(bag_dir)
12
+ @bag_dir = bag_dir
13
+ create_bag
14
+ end
15
+
16
+ def create_bag()
17
+ if (File.exist?(@bag_dir))
18
+ FileUtils.rm_r(@bag_dir)
19
+ end
20
+ @bag = BagIt::Bag.new @bag_dir
21
+ end
22
+
23
+ def add_content_files(source_dir, use_links)
24
+ data_content_dir = File.join(@bag_dir, 'data', 'content')
25
+ copy_dir(source_dir, data_content_dir, use_links)
26
+ end
27
+
28
+ def copy_dir(source_dir, target_dir, use_links)
29
+ FileUtils.mkdir_p(target_dir)
30
+ Dir.foreach(source_dir) do |file|
31
+ unless (file == '.' or file == '..')
32
+ source_file = File.join(source_dir, file)
33
+ target_file = File.join(target_dir, file)
34
+ if File.directory?(source_file)
35
+ copy_dir(source_file, target_file, use_links)
36
+ elsif (use_links)
37
+ FileUtils.ln(source_file, target_file, :force => true)
38
+ else
39
+ FileUtils.cp(source_file, target_file)
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ def add_metadata_file_from_string(metadata_string, file_name)
46
+ if (not metadata_string.nil?)
47
+ data_file_path = "metadata/#{file_name}"
48
+ @bag.add_file(data_file_path) do |io|
49
+ io.puts metadata_string
50
+ end
51
+ end
52
+ end
53
+
54
+ def write_metadata_info(md_hash)
55
+ # make sure none of the md_hash values are nil
56
+ md_hash.each do |key, value|
57
+ raise "The bag-info.txt value for #{key} is not allowed to be nil" if value.nil?
58
+ end
59
+ payload = bag_payload()
60
+ bag_info_hash = {
61
+ 'Bag-Size' => bag_size_human(payload[0]),
62
+ 'Payload-Oxum' => "#{payload[0]}.#{payload[1]}",
63
+ 'Bagging-Date' => DateTime.now.to_s[0..9]
64
+ }
65
+ @bag.write_bag_info(md_hash.merge(bag_info_hash))
66
+ end
67
+
68
+ def bag_payload()
69
+ bytes = 0
70
+ files = 0
71
+ Find.find(@bag.data_dir) do |filepath|
72
+ if (not File.directory?(filepath))
73
+ bytes += File.size(filepath)
74
+ files += 1
75
+ end
76
+ end
77
+ return [bytes, files]
78
+ end
79
+
80
+ def bag_size_human(bytes)
81
+ count = 0
82
+ size = bytes
83
+ while (size >= 1000 and count < 4)
84
+ size /= 1000.0
85
+ count += 1
86
+ end
87
+ if (count == 0)
88
+ return sprintf("%d B", size)
89
+ else
90
+ return sprintf("%.2f %s", size, %w[B KB MB GB TB][count])
91
+ end
92
+ end
93
+
94
+ def write_manifests()
95
+ @bag.manifest!
96
+ @bag.tagmanifest!
97
+ end
98
+
99
+ def validate()
100
+ if not @bag.valid?
101
+ raise "bag not valid: #{@bag_dir}"
102
+ end
103
+
104
+ end
105
+
106
+ end
107
+
108
+ end
@@ -0,0 +1,109 @@
1
+ require 'nokogiri'
2
+
3
+
4
+ module LyberUtils
5
+
6
+ class ChecksumValidate
7
+
8
+ # Test the equality of two hashes
9
+ # @return [Boolean]
10
+ def self.compare_hashes(hash1, hash2)
11
+ return (hash1 == hash2)
12
+ end
13
+
14
+ # create a new hash containing:
15
+ # entries from hash1 where:
16
+ # * key is in hash1 but missing from hash2
17
+ # * value is different in the two hashes
18
+ # entries from hash2 where:
19
+ # * key is in hash2 but missing from hash1
20
+ # @return [Hash]
21
+ def self.get_hash_differences(hash1, hash2)
22
+ hash1.reject { |k, v| hash2[k] == v }.merge!(hash2.reject { |k, v| hash1.has_key?(k) })
23
+ end
24
+
25
+ # Generate a filename => checksum hash
26
+ # from an output of the md5sum (or compatible) program
27
+ # @return [Hash]
28
+ def self.md5_hash_from_md5sum(md5sum)
29
+ checksum_hash = {}
30
+ md5sum.each do |line|
31
+ line.chomp!
32
+ digest, filename = line.split(/[ *]{2}/)
33
+ checksum_hash[filename] = digest.downcase
34
+ end
35
+ return checksum_hash
36
+ end
37
+
38
+ # Generate a filename => checksum hash
39
+ # from the contents of a METS file
40
+ # @return [Hash]
41
+ def self.md5_hash_from_mets(mets)
42
+ mets_checksum_hash = {}
43
+ doc = Nokogiri::XML(mets)
44
+ doc.xpath('/mets:mets/mets:fileSec//mets:file', {'mets' => 'http://www.loc.gov/METS/'}).each do |filenode|
45
+ digest = filenode.attribute('CHECKSUM')
46
+ if (digest)
47
+ flocat = filenode.xpath('mets:FLocat', {'mets' => 'http://www.loc.gov/METS/'}).first
48
+ if (flocat)
49
+ filename = flocat.attribute_with_ns('href', 'http://www.w3.org/1999/xlink')
50
+ if (filename)
51
+ mets_checksum_hash[filename.text] = digest.text.downcase
52
+ end
53
+ end
54
+ end
55
+ end
56
+ return mets_checksum_hash
57
+ end
58
+
59
+ # Generate a filename => checksum hash
60
+ # from contentMetadata XML
61
+ # @return [Hash]
62
+ def self.md5_hash_from_content_metadata(content_md)
63
+ content_md_checksum_hash = {}
64
+ doc = Nokogiri::XML(content_md)
65
+ doc.xpath('/contentMetadata/resource[@type="page"]/file').each do |filenode|
66
+ filename = filenode.attribute('id')
67
+ if (filename)
68
+ md5_element = filenode.xpath('checksum[@type="MD5"]').first
69
+ if (md5_element)
70
+ digest = md5_element.text
71
+ if (digest)
72
+ content_md_checksum_hash[filename.text] = digest.downcase
73
+ end
74
+ end
75
+ end
76
+ end
77
+ return content_md_checksum_hash
78
+ end
79
+
80
+ # Verifies MD5 checksums for the files in a directory
81
+ # against the checksum values in the supplied file
82
+ # (Uses md5sum command)
83
+ #
84
+ # = Inputs:
85
+ # * directory = dirname containing the file to be checked
86
+ # * checksum_file = the name of the file containing the expected checksums
87
+ #
88
+ # = Return value:
89
+ # * The method will return true if the verification is successful.
90
+ # * The method will raise an exception if either the md5sum command fails,
91
+ # or a test of the md5sum output indicates a checksum mismatch.
92
+ # The exception's message will contain the explaination of the failure.
93
+ def self.verify_md5sum_checksums(directory, checksum_file)
94
+ # LyberCore::Log.debug("verifying checksums in #{directory}")
95
+ dir_save = Dir.pwd
96
+ Dir.chdir(directory)
97
+ checksum_cmd = 'md5sum -c ' + checksum_file + ' | grep -v OK | wc -l'
98
+ badcount = FileUtilities.execute(checksum_cmd).to_i
99
+ if not (badcount==0)
100
+ raise "#{badcount} files had bad checksums"
101
+ end
102
+ return true
103
+ ensure
104
+ Dir.chdir(dir_save)
105
+ end
106
+
107
+ end
108
+
109
+ end
@@ -0,0 +1,169 @@
1
+ require 'fileutils'
2
+ require 'systemu'
3
+
4
+ # File Utilities for use in transferring filesystem objects,
5
+ # decrypting a file, unpacking a targz archive, and validating checksums
6
+ # @author rnanders@stanford.edu
7
+ module LyberUtils
8
+
9
+ class FileUtilities
10
+
11
+
12
+ # Executes a system command in a subprocess.
13
+ # The method will return stdout from the command if execution was successful.
14
+ # The method will raise an exception if if execution fails.
15
+ # The exception's message will contain the explaination of the failure.
16
+ # @param [String] command the command to be executed
17
+ # @return [String] stdout from the command if execution was successful
18
+ def FileUtilities.execute(command)
19
+ status, stdout, stderr = systemu(command)
20
+ if (status.exitstatus != 0)
21
+ raise stderr
22
+ end
23
+ return stdout
24
+ rescue
25
+ msg = "Command failed to execute: [#{command}] caused by <STDERR = #{stderr.split($/).join('; ')}>"
26
+ msg << " STDOUT = #{stdout.split($/).join('; ')}" if (stdout && (stdout.length > 0))
27
+ raise msg
28
+
29
+ end
30
+
31
+ # Generates a dirname for storing or retrieving a file in
32
+ # "pair tree" hierachical structure, where the path is derived
33
+ # from segments of a barcode string
34
+ #
35
+ # = Input:
36
+ # * barcode = barcode string
37
+ #
38
+ # = Return value:
39
+ # * A string containing a slash-delimited dirname derived from the barcode
40
+ def FileUtilities.pair_tree_from_barcode(barcode)
41
+ if (barcode.class != String)
42
+ raise "Barcode must be a String"
43
+ end
44
+ # figure out if this is a SUL barcode or from coordinate library
45
+ library_prefix=barcode[0..4]
46
+ if (library_prefix == '36105')
47
+ pair_tree=barcode[5..10].gsub(/(..)/, '\1/')
48
+ else
49
+ library_prefix=barcode[0..2]
50
+ pair_tree=barcode[3..8].gsub(/(..)/, '\1/')
51
+ end
52
+ return "#{library_prefix}/#{pair_tree}"
53
+ end
54
+
55
+ # Transfers a filesystem object (file or directory)
56
+ # from a source to a target location. Uses rsync in "archive" mode
57
+ # over an ssh connection.
58
+ #
59
+ # = Inputs:
60
+ # * filename = basename of the filesystem object to be transferred
61
+ # * source_dir = dirname of the source location from which the object is read
62
+ # * dest_dir = dirname of the target location to which the object is written
63
+ # If one of the locations is on a remote server, then the dirname should be
64
+ # prefixed with user@hosthame:
65
+ #
66
+ # = Return value:
67
+ # * The method will return true if the transfer is successful.
68
+ # * The method will raise an exception if either the rsync command fails,
69
+ # or a test for the existence of the transferred object fails.
70
+ # The exception's message will contain the explaination of the failure
71
+ #
72
+ # Network transfers will only succeed if the appropriate public key
73
+ # authentication has been previously set up.
74
+ def FileUtilities.transfer_object(filename, source_dir, dest_dir)
75
+ source_path=File.join(source_dir, filename)
76
+ rsync='rsync -a -e ssh '
77
+ rsync_cmd = rsync + "'" + source_path + "' " + dest_dir
78
+ # LyberCore::Log.debug("rsync command is: #{rsync_cmd}")
79
+ self.execute(rsync_cmd)
80
+ if not File.exists?(File.join(dest_dir, filename))
81
+ raise "#{filename} is not found in #{dest_dir}"
82
+ end
83
+ return true
84
+ end
85
+
86
+ # Decrypts a GPG encrypted file using the "gpg" command
87
+ #
88
+ # = Inputs:
89
+ # * workspace_dir = dirname containing the file
90
+ # * targzgpg = the filename of the GPG encrypted file
91
+ # * targz = the filename of the unencrypted file
92
+ # * passphrase = the string used to decrypt the file
93
+ #
94
+ # = Return value:
95
+ # * The method will return true if the decryption is successful.
96
+ # * The method will raise an exception if either the decryption command fails,
97
+ # or a test for the existence of the decrypted file fails.
98
+ # The exception's message will contain the explaination of the failure
99
+ def FileUtilities.gpgdecrypt(workspace_dir, targzgpg, targz, passphrase)
100
+ # LyberCore::Log.debug("decrypting #{targzgpg}")
101
+ gpg_cmd="/usr/bin/gpg --passphrase '#{passphrase}' " +
102
+ "--batch --no-mdc-warning --no-secmem-warning " +
103
+ " --output " + File.join(workspace_dir, targz) +
104
+ " --decrypt " + File.join(workspace_dir, targzgpg)
105
+ self.execute(gpg_cmd)
106
+ if not File.exists?(File.join(workspace_dir, targz))
107
+ raise "#{targz} was not created in #{workspace_dir}"
108
+ end
109
+ return true
110
+ end
111
+
112
+ # Unpacks a TAR-ed, GZipped archive using a "tar -xzf" command
113
+ #
114
+ # = Inputs:
115
+ # * original_dir = dirname containing the archive file
116
+ # * targz = the filename of the archive file
117
+ # * destination_dir = the target directory into which the contents are written
118
+ #
119
+ # = Return value:
120
+ # * The method will return true if the unpacking is successful.
121
+ # * The method will raise an exception if either the unpack command fails,
122
+ # or a test for the existence of files in the target directory fails.
123
+ # The exception's message will contain the explaination of the failure.
124
+ def FileUtilities.unpack(original_dir, targz, destination_dir)
125
+ # LyberCore::Log.debug("unpacking #{targz}")
126
+ FileUtils.mkdir_p(destination_dir)
127
+ dir_save = Dir.pwd
128
+ Dir.chdir(destination_dir)
129
+ unpack_cmd="tar -xzf " + File.join(original_dir, targz)
130
+ self.execute(unpack_cmd)
131
+ if not (Dir.entries(destination_dir).length > 0)
132
+ raise "#{destination_dir} is empty"
133
+ end
134
+ return true
135
+ ensure
136
+ Dir.chdir(dir_save)
137
+ end
138
+
139
+ # Tars a directory hierarchy
140
+ #
141
+ # = Inputs:
142
+ # * source_path = the filesystem object to be tarred
143
+ # * dest_path = name of the tar file to be written
144
+ # (if nil create sourcname.tar in the same dir as the source object)
145
+ #
146
+ # = Return value:
147
+ # * The method will return true if the transfer is successful.
148
+ # * The method will raise an exception if either the rsync command fails,
149
+ # or a test for the existence of the transferred object fails.
150
+ # The exception's message will contain the explaination of the failure
151
+ #
152
+ def FileUtilities.tar_object(source_path, dest_path=nil)
153
+ if (dest_path.nil?)
154
+ dest_path = source_path + ".tar"
155
+ end
156
+ parent_path = File.dirname(source_path)
157
+ object_name = File.basename(source_path)
158
+ tar="cd #{parent_path}; tar --force-local -chf "
159
+ tar_cmd = "#{tar} '#{dest_path}' '#{object_name}'"
160
+ self.execute(tar_cmd)
161
+ if not File.exists?(dest_path)
162
+ raise "#{dest_path} was not created"
163
+ end
164
+ return true
165
+ end
166
+
167
+ end
168
+
169
+ end
@@ -0,0 +1,32 @@
1
+ desc "Generate RDoc"
2
+ task :doc => ['doc:generate']
3
+
4
+ namespace :doc do
5
+ project_root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
6
+ doc_destination = File.join(project_root, 'rdoc')
7
+
8
+ begin
9
+ require 'yard'
10
+ require 'yard/rake/yardoc_task'
11
+
12
+ YARD::Rake::YardocTask.new(:generate) do |yt|
13
+ yt.files = Dir.glob(File.join(project_root, 'lib', '*.rb')) +
14
+ Dir.glob(File.join(project_root, 'lib', '**', '*.rb')) +
15
+ [ File.join(project_root, 'README.rdoc') ] +
16
+ [ File.join(project_root, 'LICENSE') ]
17
+
18
+ yt.options = ['--output-dir', doc_destination, '--readme', 'README.rdoc']
19
+ end
20
+ rescue LoadError
21
+ desc "Generate YARD Documentation"
22
+ task :generate do
23
+ abort "Please install the YARD gem to generate rdoc."
24
+ end
25
+ end
26
+
27
+ desc "Remove generated documenation"
28
+ task :clean do
29
+ rm_r doc_destination if File.exists?(doc_destination)
30
+ end
31
+
32
+ end
metadata ADDED
@@ -0,0 +1,241 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lyber-utils
3
+ version: !ruby/object:Gem::Version
4
+ hash: 31
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 2
10
+ version: 0.1.2
11
+ platform: ruby
12
+ authors:
13
+ - Richard Anderson
14
+ - Willy Mene
15
+ - Michael Klein
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2011-09-27 00:00:00 Z
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 27
29
+ segments:
30
+ - 0
31
+ - 1
32
+ - 0
33
+ version: 0.1.0
34
+ version_requirements: *id001
35
+ name: bagit
36
+ prerelease: false
37
+ type: :runtime
38
+ - !ruby/object:Gem::Dependency
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 113
45
+ segments:
46
+ - 1
47
+ - 4
48
+ - 3
49
+ - 1
50
+ version: 1.4.3.1
51
+ version_requirements: *id002
52
+ name: nokogiri
53
+ prerelease: false
54
+ type: :runtime
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 31
62
+ segments:
63
+ - 1
64
+ - 2
65
+ - 0
66
+ version: 1.2.0
67
+ version_requirements: *id003
68
+ name: systemu
69
+ prerelease: false
70
+ type: :runtime
71
+ - !ruby/object:Gem::Dependency
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ version_requirements: *id004
82
+ name: validatable
83
+ prerelease: false
84
+ type: :runtime
85
+ - !ruby/object:Gem::Dependency
86
+ requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 13
92
+ segments:
93
+ - 0
94
+ - 4
95
+ - 1
96
+ version: 0.4.1
97
+ version_requirements: *id005
98
+ name: lyberteam-devel
99
+ prerelease: false
100
+ type: :development
101
+ - !ruby/object:Gem::Dependency
102
+ requirement: &id006 !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 49
108
+ segments:
109
+ - 0
110
+ - 8
111
+ - 7
112
+ version: 0.8.7
113
+ version_requirements: *id006
114
+ name: rake
115
+ prerelease: false
116
+ type: :development
117
+ - !ruby/object:Gem::Dependency
118
+ requirement: &id007 !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ hash: 3
124
+ segments:
125
+ - 0
126
+ version: "0"
127
+ version_requirements: *id007
128
+ name: rcov
129
+ prerelease: false
130
+ type: :development
131
+ - !ruby/object:Gem::Dependency
132
+ requirement: &id008 !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ hash: 3
138
+ segments:
139
+ - 0
140
+ version: "0"
141
+ version_requirements: *id008
142
+ name: rdoc
143
+ prerelease: false
144
+ type: :development
145
+ - !ruby/object:Gem::Dependency
146
+ requirement: &id009 !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - <
150
+ - !ruby/object:Gem::Version
151
+ hash: 3
152
+ segments:
153
+ - 2
154
+ - 0
155
+ version: "2.0"
156
+ version_requirements: *id009
157
+ name: rspec
158
+ prerelease: false
159
+ type: :development
160
+ - !ruby/object:Gem::Dependency
161
+ requirement: &id010 !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ hash: 3
167
+ segments:
168
+ - 0
169
+ version: "0"
170
+ version_requirements: *id010
171
+ name: ruby-debug
172
+ prerelease: false
173
+ type: :development
174
+ - !ruby/object:Gem::Dependency
175
+ requirement: &id011 !ruby/object:Gem::Requirement
176
+ none: false
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ hash: 3
181
+ segments:
182
+ - 0
183
+ version: "0"
184
+ version_requirements: *id011
185
+ name: yard
186
+ prerelease: false
187
+ type: :development
188
+ description: Contains classes perform generic utilty functions
189
+ email:
190
+ - rnanders@stanford.edu
191
+ executables: []
192
+
193
+ extensions: []
194
+
195
+ extra_rdoc_files: []
196
+
197
+ files:
198
+ - lib/lyber-utils.rb
199
+ - lib/lyber_utils/bagit_bag.rb
200
+ - lib/lyber_utils/checksum_validate.rb
201
+ - lib/lyber_utils/file_utilities.rb
202
+ - lib/tasks/rdoc.rake
203
+ - LICENSE
204
+ - README.rdoc
205
+ homepage:
206
+ licenses: []
207
+
208
+ post_install_message:
209
+ rdoc_options: []
210
+
211
+ require_paths:
212
+ - lib
213
+ required_ruby_version: !ruby/object:Gem::Requirement
214
+ none: false
215
+ requirements:
216
+ - - ">="
217
+ - !ruby/object:Gem::Version
218
+ hash: 3
219
+ segments:
220
+ - 0
221
+ version: "0"
222
+ required_rubygems_version: !ruby/object:Gem::Requirement
223
+ none: false
224
+ requirements:
225
+ - - ">="
226
+ - !ruby/object:Gem::Version
227
+ hash: 23
228
+ segments:
229
+ - 1
230
+ - 3
231
+ - 6
232
+ version: 1.3.6
233
+ requirements: []
234
+
235
+ rubyforge_project:
236
+ rubygems_version: 1.8.10
237
+ signing_key:
238
+ specification_version: 3
239
+ summary: Generic utilities used by the SULAIR Digital Library
240
+ test_files: []
241
+