bagit 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,21 +3,19 @@ require 'digest/sha1'
3
3
  require 'digest/md5'
4
4
 
5
5
  module BagIt
6
-
7
6
  # Requires response to bag_dir, tag_files, bag_files
8
7
  module Manifest
9
8
  def encode_filename(s)
10
- s = s.gsub(/\r/, '%0D')
11
- s = s.gsub(/\n/,'%0A')
12
- return s
9
+ s = s.gsub(/\r/, '%0D')
10
+ s = s.gsub(/\n/, '%0A')
11
+ s
13
12
  end
14
13
 
15
-
16
14
  # All tag files that are bag manifest files (manifest-[algorithm].txt)
17
15
  def manifest_files
18
- files = Dir[File.join(@bag_dir, '*')].select { |f|
19
- File.file? f and File.basename(f) =~ /^manifest-.*.txt$/
20
- }
16
+ files = Dir[File.join(@bag_dir, '*')].select do |f|
17
+ File.file?(f) && File.basename(f) =~ /^manifest-.*.txt$/
18
+ end
21
19
  files
22
20
  end
23
21
 
@@ -28,31 +26,34 @@ module BagIt
28
26
 
29
27
  # Generate manifest files for all the bag files
30
28
  def manifest!(algo: 'default')
31
-
32
29
  # nuke all the existing manifest files
33
- manifest_files.each { |f| FileUtils::rm f }
30
+ manifest_files.each { |f| FileUtils.rm f }
34
31
 
35
32
  # manifest each tag file for each algorithm
36
33
  bag_files.each do |f|
37
34
  rel_path = encode_filename(Pathname.new(f).relative_path_from(Pathname.new(bag_dir)).to_s)
38
35
 
39
- case algo
40
- when 'sha1'
41
- write_sha1(f, rel_path)
42
- when 'md5'
43
- write_md5(f, rel_path)
44
- when 'sha256'
45
- write_sha256(f, rel_path)
46
- when 'sha512'
47
- write_sha256(f, rel_path)
48
- when 'default'
49
- write_sha1(f, rel_path)
50
- write_md5(f, rel_path)
51
- end
36
+ write_checksum(checksum_algo: algo, relative_path: rel_path, file: f)
52
37
  end
53
38
  tagmanifest!
54
39
  end
55
40
 
41
+ def write_checksum(checksum_algo:, relative_path:, file:)
42
+ case checksum_algo
43
+ when 'sha1'
44
+ write_sha1(file, relative_path)
45
+ when 'md5'
46
+ write_md5(file, relative_path)
47
+ when 'sha256'
48
+ write_sha256(file, relative_path)
49
+ when 'sha512'
50
+ write_sha256(file, relative_path)
51
+ when 'default'
52
+ write_sha1(file, relative_path)
53
+ write_md5(file, relative_path)
54
+ end
55
+ end
56
+
56
57
  def write_sha1(f, rel_path)
57
58
  sha1 = Digest::SHA1.file f
58
59
  File.open(manifest_file(:sha1), 'a') { |io| io.puts "#{sha1} #{rel_path}" }
@@ -75,9 +76,9 @@ module BagIt
75
76
 
76
77
  # All tag files that are bag manifest files (tagmanifest-[algorithm].txt)
77
78
  def tagmanifest_files
78
- files = Dir[File.join(@bag_dir, '*')].select { |f|
79
- File.file? f and File.basename(f) =~ /^tagmanifest-.*.txt$/
80
- }
79
+ files = Dir[File.join(@bag_dir, '*')].select do |f|
80
+ File.file?(f) && File.basename(f) =~ /^tagmanifest-.*.txt$/
81
+ end
81
82
  files
82
83
  end
83
84
 
@@ -88,12 +89,11 @@ module BagIt
88
89
 
89
90
  # Generate manifest files for all the tag files (except the tag
90
91
  # manifest files)
91
- def tagmanifest!(tags=nil)
92
-
93
- tags = tag_files if tags == nil
92
+ def tagmanifest!(tags = nil)
93
+ tags = tag_files if tags.nil?
94
94
 
95
95
  # nuke all the existing tagmanifest files
96
- tagmanifest_files.each { |f| FileUtils::rm f }
96
+ tagmanifest_files.each { |f| FileUtils.rm f }
97
97
 
98
98
  # ensure presence of manfiest files
99
99
  manifest_files.each do |manifest|
@@ -111,29 +111,28 @@ module BagIt
111
111
  tag_files
112
112
  end
113
113
 
114
- def add_tag_file(path, src_path=nil)
115
-
114
+ def add_tag_file(path, src_path = nil)
116
115
  f = File.join(@bag_dir, path)
117
116
  raise "Tag file already in manifest: #{path}" if tag_files.include?(f)
118
117
 
119
- if not File.exist? f
120
- FileUtils::mkdir_p File.dirname(f)
118
+ if !File.exist? f
119
+ FileUtils.mkdir_p File.dirname(f)
121
120
 
122
121
  # write file
123
122
  if src_path.nil?
124
123
  File.open(f, 'w') { |io| yield io }
125
124
  else
126
- FileUtils::cp src_path, f
125
+ FileUtils.cp src_path, f
127
126
  end
128
127
  # this adds the manifest and bag info files on initial creation
129
128
  # it must only run when the manifest doesn't already exist or it will
130
129
  # infinitely recall add_tag_file. Better way of doing this?
131
130
  tagmanifest!
132
- elsif not src_path.nil?
131
+ elsif !src_path.nil?
133
132
  raise "Tag file already exists, will not overwrite: #{path}\n Use add_tag_file(path) to add an existing tag file."
134
133
  end
135
134
 
136
- data = File.open(f) { |io| io.read }
135
+ data = File.open(f, &:read)
137
136
  rel_path = Pathname.new(f).relative_path_from(Pathname.new(bag_dir)).to_s
138
137
 
139
138
  # sha1
@@ -157,7 +156,7 @@ module BagIt
157
156
  filepath = File.join(@bag_dir, path)
158
157
  raise "Tag file does not exist: #{path}" unless File.exist? filepath
159
158
  remove_tag_file(path) if tag_files.include?(path)
160
- FileUtils::rm filepath
159
+ FileUtils.rm filepath
161
160
  end
162
161
 
163
162
  # Returns true if all present manifested files' message digests
@@ -167,7 +166,7 @@ module BagIt
167
166
  # extract the algorithm
168
167
  mf =~ /manifest-(.+).txt$/
169
168
 
170
- algo = case $1
169
+ algo = case Regexp.last_match(1)
171
170
  when /sha1/i
172
171
  Digest::SHA1
173
172
  when /md5/i
@@ -177,23 +176,19 @@ module BagIt
177
176
  end
178
177
 
179
178
  # check it, an unknown algorithm is always true
180
- unless algo == :unknown
181
- lines = File.open(mf) { |io| io.readlines }
179
+ if algo == :unknown
180
+ true
181
+ else
182
+ lines = File.open(mf, &:readlines)
182
183
 
183
184
  lines.all? do |line|
184
- manifested_digest, path = line.chomp.split /\s+/, 2
185
+ manifested_digest, path = line.chomp.split(/\s+/, 2)
185
186
  actual_digest = File.open(File.join(@bag_dir, path)) { |io| algo.hexdigest io.read }
186
187
  actual_digest == manifested_digest
187
188
  end
188
189
 
189
- else
190
- true
191
190
  end
192
-
193
191
  end
194
-
195
192
  end
196
-
197
193
  end
198
-
199
194
  end
@@ -1,6 +1,5 @@
1
1
  # Some mixed in functionality for String
2
2
  class String
3
-
4
3
  # Wrap a string to lines of a specified width. All existing newlines
5
4
  # are not guaranteed to be preserved
6
5
  def wrap(width)
@@ -11,7 +10,6 @@ class String
11
10
  else
12
11
  s
13
12
  end
14
-
15
13
  end
16
14
 
17
15
  # Indent each line of a string by n spaces
@@ -20,8 +18,8 @@ class String
20
18
  gsub '\n', "\n#{indent}"
21
19
  end
22
20
 
23
- # Colorize logs
24
- def color(color_code)
21
+ # Colorize logs
22
+ def color(color_code)
25
23
  "\e[#{color_code}m#{self}\e[0m"
26
24
  end
27
25
 
@@ -4,29 +4,26 @@ require 'cgi'
4
4
  require 'logger'
5
5
 
6
6
  module BagIt
7
-
8
7
  class Bag
9
8
  include Validatable
10
- validates_true_for :consistency, :logic => Proc.new { consistent? }
11
- validates_true_for :completeness, :logic => Proc.new { complete? }
9
+ validates_true_for :consistency, logic: proc { consistent? }
10
+ validates_true_for :completeness, logic: proc { complete? }
12
11
  end
13
12
 
14
13
  module Validity
15
14
  def decode_filename(s)
16
- s = s.gsub('%0D',"\r")
17
- s = s.gsub('%0A',"\n")
18
- return s
15
+ s = s.gsub('%0D', "\r")
16
+ s = s.gsub('%0A', "\n")
17
+ s
19
18
  end
20
-
19
+
21
20
  # Return true if the manifest cover all files and all files are
22
21
  # covered.
23
22
  def complete?
24
23
  logger = Logger.new(STDOUT)
25
24
 
26
- if manifest_files == []
27
- errors.add :completeness, "there are no manifest files"
28
- end
29
-
25
+ errors.add :completeness, "there are no manifest files" if manifest_files == []
26
+
30
27
  unmanifested_files.each do |file|
31
28
  logger.error("#{file} is present but not manifested".red)
32
29
  errors.add :completeness, "#{file} is present but not manifested"
@@ -44,38 +41,39 @@ module BagIt
44
41
  errors.on(:completeness).nil?
45
42
  end
46
43
 
44
+ def manifest_type(type)
45
+ case type
46
+ when /sha1/i
47
+ Digest::SHA1
48
+ when /md5/i
49
+ Digest::MD5
50
+ when /sha256/i
51
+ Digest::SHA256
52
+ when /sha384/i
53
+ Digest::SHA384
54
+ when /sha512/i
55
+ Digest::SHA512
56
+ else
57
+ raise ArgumentError, "Algorithm #{manifest_type} is not supported."
58
+ end
59
+ end
60
+
47
61
  # Return true if all manifested files message digests match.
48
62
  def consistent?
49
- (manifest_files|tagmanifest_files).each do |mf|
63
+ (manifest_files | tagmanifest_files).each do |mf|
50
64
  # get the algorithm implementation
51
65
  File.basename(mf) =~ /manifest-(.+).txt$/
52
- manifest_type = $1
53
- algo = case manifest_type
54
- when /sha1/i
55
- Digest::SHA1
56
- when /md5/i
57
- Digest::MD5
58
- when /sha256/i
59
- Digest::SHA256
60
- when /sha384/i
61
- Digest::SHA384
62
- when /sha512/i
63
- Digest::SHA512
64
- else
65
- raise ArgumentError.new("Algorithm #{manifest_type} is not supported.")
66
- end
66
+ type = Regexp.last_match(1)
67
+ algo = manifest_type(type)
67
68
  # Check every file in the manifest
68
69
  File.open(mf) do |io|
69
70
  io.each_line do |line|
70
- expected, path = line.chomp.split /\s+/, 2
71
+ expected, path = line.chomp.split(/\s+/, 2)
71
72
  file = File.join(bag_dir, decode_filename(path))
72
73
 
73
- if File.exist? file
74
- actual = algo.file(file).hexdigest
75
- if expected.downcase != actual
76
- errors.add :consistency, "expected #{file} to have #{algo}: #{expected}, actual is #{actual}"
77
- end
78
- end
74
+ next unless File.exist? file
75
+ actual = algo.file(file).hexdigest
76
+ errors.add :consistency, "expected #{file} to have #{algo}: #{expected}, actual is #{actual}" if expected.downcase != actual
79
77
  end
80
78
  end
81
79
  end
@@ -89,59 +87,53 @@ module BagIt
89
87
  end
90
88
 
91
89
  protected
92
-
93
- # Returns all files in the instance that are not manifested
94
- def unmanifested_files
95
- mfs = manifested_files.map { |f| File.join bag_dir, f }
96
- bag_files.reject { |f| mfs.member? f }
97
- end
98
90
 
99
- # Returns a list of manifested files that are not present
100
- def empty_manifests
101
- bfs = bag_files
102
- manifested_files.reject { |f| bfs.member? File.join(bag_dir, f) }
103
- end
104
- # Returns a list of tag manifested files that are not present
105
- def tag_empty_manifests
106
- empty = []
107
- tag_manifested_files.each do |f|
108
- if !File.exists?(File.join(bag_dir,f))
109
- empty.push f
110
- end
91
+ # Returns all files in the instance that are not manifested
92
+ def unmanifested_files
93
+ mfs = manifested_files.map { |f| File.join bag_dir, f }
94
+ bag_files.reject { |f| mfs.member? f }
111
95
  end
112
- return empty
113
- end
114
- # Returns a list of all files present in the manifest files
115
- def manifested_files
116
96
 
117
- manifest_files.inject([]) do |acc, mf|
97
+ # Returns a list of manifested files that are not present
98
+ def empty_manifests
99
+ bfs = bag_files
100
+ manifested_files.reject { |f| bfs.member? File.join(bag_dir, f) }
101
+ end
118
102
 
119
- files = File.open(mf) do |io|
103
+ # Returns a list of tag manifested files that are not present
104
+ def tag_empty_manifests
105
+ empty = []
106
+ tag_manifested_files.each do |f|
107
+ empty.push f unless File.exist?(File.join(bag_dir, f))
108
+ end
109
+ empty
110
+ end
120
111
 
121
- io.readlines.map do |line|
122
- digest, path = line.chomp.split /\s+/, 2
123
- decode_filename(path)
112
+ # Returns a list of all files present in the manifest files
113
+ def manifested_files
114
+ manifest_files.inject([]) do |acc, mf|
115
+ files = File.open(mf) do |io|
116
+ io.readlines.map do |line|
117
+ _digest, path = line.chomp.split(/\s+/, 2)
118
+ decode_filename(path)
119
+ end
124
120
  end
125
121
 
122
+ (acc + files).uniq
126
123
  end
127
-
128
- (acc + files).uniq
129
124
  end
130
125
 
131
- end
132
- # Returns a list of all files in the tag manifest files
133
- def tag_manifested_files
134
- tagmanifest_files.inject([]) do |acc, mf|
135
- files = File.open(mf) do |io|
136
- io.readlines.map do |line|
137
- digest, path = line.chomp.split /\s+/, 2
138
- path
126
+ # Returns a list of all files in the tag manifest files
127
+ def tag_manifested_files
128
+ tagmanifest_files.inject([]) do |acc, mf|
129
+ files = File.open(mf) do |io|
130
+ io.readlines.map do |line|
131
+ _digest, path = line.chomp.split(/\s+/, 2)
132
+ path
133
+ end
139
134
  end
135
+ (acc + files).uniq
140
136
  end
141
- (acc+files).uniq
142
137
  end
143
- end
144
-
145
138
  end
146
-
147
139
  end
@@ -1,3 +1,3 @@
1
1
  module BagIt
2
- VERSION = "0.4.2"
2
+ VERSION = "0.4.3".freeze
3
3
  end
@@ -2,31 +2,31 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  # based on v0.96 http://www.cdlib.org/inside/diglib/bagit/bagitspec.html
5
- describe BagIt::Bag do
5
+ RSpec.describe BagIt::Bag do
6
6
  describe 'empty bag' do
7
- before(:each) do
7
+ before do
8
8
  @sandbox = Sandbox.new
9
9
  # make the bag
10
10
  @bag_path = File.join @sandbox.to_s, 'the_bag'
11
- @bag = BagIt::Bag.new @bag_path
11
+ @bag = described_class.new @bag_path
12
12
  end
13
13
 
14
- after(:each) do
14
+ after do
15
15
  @sandbox.cleanup!
16
16
  end
17
17
 
18
- it "should be empty" do
18
+ it "is empty" do
19
19
  expect(@bag).to be_empty
20
20
  end
21
21
  end
22
22
 
23
23
  describe 'bag with files' do
24
- before(:each) do
24
+ before do
25
25
  @sandbox = Sandbox.new
26
26
 
27
27
  # make the bag
28
28
  @bag_path = File.join @sandbox.to_s, 'the_bag'
29
- @bag = BagIt::Bag.new @bag_path
29
+ @bag = described_class.new @bag_path
30
30
 
31
31
  # add some files
32
32
  File.open('/dev/urandom') do |rio|
@@ -37,47 +37,49 @@ describe BagIt::Bag do
37
37
  end
38
38
  end
39
39
 
40
- after(:each) do
40
+ after do
41
41
  @sandbox.cleanup!
42
42
  end
43
43
 
44
- it "should be a directory" do
44
+ it "is a directory" do
45
45
  expect(File.directory?(@bag_path)).to be true
46
46
  end
47
47
 
48
- it "should not be empty" do
48
+ it "is not be empty" do
49
49
  expect(@bag).not_to be_empty
50
50
  end
51
51
 
52
- it "should have a sub-directory called data" do
52
+ it "has a sub-directory called data" do
53
53
  data_path = File.join @bag_path, 'data'
54
54
  expect(File.directory?(data_path)).to be true
55
55
  end
56
56
 
57
57
  describe "#add_file" do
58
- it "should allow addition of files via io" do
58
+ it "allows addition of files via io" do
59
59
  @bag.add_file("foo") { |io| io.puts 'all alone' }
60
60
  expect(File.join(@bag_path, "data", "foo")).to exist_on_fs
61
61
  end
62
62
 
63
- it "should allow addition of files via copy" do
63
+ it "allows addition of files via copy" do
64
64
  src_path = File.join @sandbox.to_s, 'somefile'
65
65
  File.open(src_path, 'w') { |io| io.puts "something" }
66
66
  @bag.add_file("foo", src_path) { |io| io.puts 'all alone' }
67
67
  expect(File.join(@bag_path, "data", "foo")).to exist_on_fs
68
68
  end
69
69
 
70
- it "should allow addition of files with deep paths" do
70
+ it "allows addition of files with deep paths" do
71
71
  @bag.add_file("deep/dir/structure/file") { |io| io.puts 'all alone' }
72
72
  expect(File.join(@bag_path, "data", "deep/dir/structure/file")).to exist_on_fs
73
73
  end
74
74
 
75
- it "should not allow overwriting of files" do
76
- expect { @bag.add_file("file-0-💩
77
- ") { |io| io.puts 'overwrite!' } }.to raise_error(RuntimeError)
75
+ it "does not allow overwriting of files" do
76
+ expect do
77
+ @bag.add_file("file-0-💩
78
+ ") { |io| io.puts 'overwrite!' }
79
+ end.to raise_error(RuntimeError)
78
80
  end
79
81
 
80
- it "should update payload oxum" do
82
+ it "updates the payload oxum" do
81
83
  oxum_count = @bag.bag_info["Payload-Oxum"].split('.')[1].to_i
82
84
  @bag.add_file("foo") { |io| io.puts 'all alone' }
83
85
  expect(@bag.bag_info["Payload-Oxum"].split('.')[1].to_i).to eq(oxum_count + 1)
@@ -85,14 +87,14 @@ describe BagIt::Bag do
85
87
  end
86
88
 
87
89
  describe "#remove_file" do
88
- it "should raise an error when deleing non existant files" do
90
+ it "raises an error when deleing non existant files" do
89
91
  expect { @bag.remove_file("file-x") }.to raise_error(RuntimeError)
90
92
  end
91
93
  end
92
94
 
93
95
  describe "#get" do
94
96
  describe "file not in bag" do
95
- it "should return nil" do
97
+ it "returns nil" do
96
98
  expect(@bag.get('foobar')).to be_nil
97
99
  end
98
100
  end
@@ -104,15 +106,15 @@ describe BagIt::Bag do
104
106
  @file = @bag.get("foo")
105
107
  end
106
108
 
107
- it "should return an IO object for the given path" do
109
+ it "returns an IO object for the given path" do
108
110
  expect(@file).to be_a_kind_of(IO)
109
111
  end
110
112
 
111
- it "should have the same content as the file added" do
113
+ it "has the same content as the file added" do
112
114
  expect(@file.read).to eq(@contents)
113
115
  end
114
116
 
115
- it "should accept an optional leading slash or ./" do
117
+ it "accepts an optional leading slash or ./" do
116
118
  expect(@bag.get("/foo").read).to eq(@contents)
117
119
  expect(@bag.get("./foo").read).to eq(@contents)
118
120
  end
@@ -124,7 +126,7 @@ describe BagIt::Bag do
124
126
  @paths = @bag.paths
125
127
  end
126
128
 
127
- it "should return a non-empty Array of Strings" do
129
+ it "returns a non-empty Array of Strings" do
128
130
  expect(@paths).to be_a_kind_of(Array)
129
131
  expect(@paths).not_to be_empty
130
132
  @paths.each do |p|
@@ -132,25 +134,27 @@ describe BagIt::Bag do
132
134
  end
133
135
  end
134
136
 
135
- it "should return relative paths to all files in the data directory" do
136
- expect(@paths).to match_array((0..9).collect { |x| "file-#{x}-💩
137
- " })
137
+ it "returns relative paths to all files in the data directory" do
138
+ expect(@paths).to match_array((0..9).collect do |x|
139
+ "file-#{x}-💩
140
+ "
141
+ end)
138
142
  end
139
143
  end
140
144
 
141
145
  describe "#payload-oxum" do
142
- it "should return a valid oxum" do
146
+ it "returns a valid oxum" do
143
147
  expect(@bag.payload_oxum).to match(/^[0-9]+\.[0-9]+$/)
144
148
  end
145
149
 
146
- it "should accurately specify the number of payload files" do
150
+ it "accurately specifys the number of payload files" do
147
151
  @bag.add_tag_file('non-payload') { |f| f.puts "I shouldn't count in the oxum" }
148
152
  @bag.payload_oxum.split('.')[1] == @bag.bag_files.count
149
153
  end
150
154
  end
151
155
 
152
156
  describe "#gc!" do
153
- it "should clean up empty directories" do
157
+ it "cleans up empty directories" do
154
158
  f = File.join "1", "2", "3", "file"
155
159
  @bag.add_file(f) { |io| io.puts 'all alone' }
156
160
  @bag.remove_file f