bagit 0.3.5 → 0.4.4
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.
- checksums.yaml +5 -5
- data/.gitignore +2 -1
- data/.travis.yml +1 -2
- data/Gemfile +4 -2
- data/README.md +1 -1
- data/Rakefile +11 -8
- data/bagit.gemspec +25 -21
- data/bin/bagit +59 -63
- data/lib/bagit.rb +8 -6
- data/lib/bagit/bag.rb +43 -47
- data/lib/bagit/fetch.rb +23 -27
- data/lib/bagit/file.rb +11 -14
- data/lib/bagit/info.rb +39 -51
- data/lib/bagit/manifest.rb +72 -49
- data/lib/bagit/string.rb +6 -6
- data/lib/bagit/valid.rb +51 -57
- data/lib/bagit/version.rb +3 -1
- data/spec/bagit_spec.rb +59 -54
- data/spec/fetch_spec.rb +33 -38
- data/spec/manifest_spec.rb +107 -111
- data/spec/spec_helper.rb +12 -12
- data/spec/tag_info_spec.rb +101 -108
- data/spec/tag_spec.rb +47 -49
- data/spec/util/bagit_matchers.rb +5 -14
- data/spec/validation_spec.rb +108 -110
- metadata +50 -9
data/spec/manifest_spec.rb
CHANGED
@@ -1,148 +1,144 @@
|
|
1
|
-
#
|
2
|
-
require 'spec_helper'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
3
|
+
require "spec_helper"
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
5
|
+
describe BagIt::Bag do
|
6
|
+
describe "BagIt Manifests" do
|
7
|
+
before do
|
8
|
+
@sandbox = Sandbox.new
|
9
|
+
|
10
|
+
# make the bag
|
11
|
+
@bag_path = File.join @sandbox.to_s, "the_bag"
|
12
|
+
@bag = described_class.new @bag_path
|
13
|
+
|
14
|
+
# add some files
|
15
|
+
File.open("/dev/urandom") do |rio|
|
16
|
+
10.times do |n|
|
17
|
+
@bag.add_file("file-#{n}-💩
|
18
|
+
") { |io| io.write rio.read(16) }
|
19
|
+
@bag.add_tag_file("tag-#{n}") { |io| io.write rio.read(16) }
|
20
|
+
end
|
20
21
|
end
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
22
|
end
|
26
23
|
|
27
|
-
|
28
|
-
|
29
|
-
after(:each) do
|
30
|
-
@sandbox.cleanup!
|
31
|
-
end
|
32
|
-
|
33
|
-
shared_examples_for "a manifest file" do
|
34
|
-
|
35
|
-
before do
|
36
|
-
pattern = File.join @bag_path, '*manifest-*.txt'
|
37
|
-
@manifest_files = Dir.glob pattern
|
24
|
+
after do
|
25
|
+
@sandbox.cleanup!
|
38
26
|
end
|
39
27
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
28
|
+
shared_examples_for "a manifest file" do
|
29
|
+
before do
|
30
|
+
pattern = File.join @bag_path, "*manifest-*.txt"
|
31
|
+
@manifest_files = Dir.glob pattern
|
32
|
+
end
|
44
33
|
|
45
|
-
|
46
|
-
|
47
|
-
|
34
|
+
it "has a valid algorithm in the name (at least md5 or sha1)" do
|
35
|
+
algorithms = @manifest_files.map { |mf|
|
36
|
+
mf =~ /manifest-(.*).txt$/
|
37
|
+
Regexp.last_match(1)
|
38
|
+
}
|
39
|
+
algorithms.each { |a| expect(a).to be_in("md5", "sha1") }
|
40
|
+
end
|
41
|
+
|
42
|
+
it "is not an empty file" do
|
43
|
+
@manifest_files.each { |mf| expect(File.size(mf)).not_to eq(0) }
|
44
|
+
end
|
48
45
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
it "only contains lines of the format CHECKSUM FILENAME" do
|
47
|
+
@manifest_files.each do |file|
|
48
|
+
File.open(file) do |io|
|
49
|
+
io.each_line { |line| expect(line).to match(/^[a-fA-F0-9]+\s+[^\s].+$/) }
|
50
|
+
end
|
53
51
|
end
|
54
52
|
end
|
55
|
-
end
|
56
53
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
it "validates after adding a file and remanifesting" do
|
55
|
+
@bag.add_file("newfile.txt") { |io| io.puts("new file to remanifest") }
|
56
|
+
@bag.manifest!
|
57
|
+
expect(@bag).to be_valid
|
58
|
+
end
|
61
59
|
end
|
62
60
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
before do
|
68
|
-
@bag.manifest!
|
69
|
-
end
|
61
|
+
describe "bag manifest files" do
|
62
|
+
before do
|
63
|
+
@bag.manifest!
|
64
|
+
end
|
70
65
|
|
71
|
-
|
66
|
+
it_behaves_like "a manifest file"
|
72
67
|
|
73
|
-
|
74
|
-
|
75
|
-
|
68
|
+
it "has a manifest file" do
|
69
|
+
expect(@bag.manifest_files).not_to be_empty
|
70
|
+
end
|
76
71
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
72
|
+
it "only contains bag files" do
|
73
|
+
@bag.manifest_files.each do |mf|
|
74
|
+
File.open(mf) do |io|
|
75
|
+
io.each_line do |line|
|
76
|
+
expect(line.chomp).to match(/^[a-f0-9]+\s+data\/[^\s].+$/)
|
77
|
+
end
|
82
78
|
end
|
83
79
|
end
|
84
80
|
end
|
85
81
|
end
|
86
82
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
before do
|
92
|
-
@bag.add_tag_file("test-tag") { |f| f.puts "all alone" }
|
93
|
-
end
|
83
|
+
describe "tag manifest files" do
|
84
|
+
before do
|
85
|
+
@bag.add_tag_file("test-tag") { |f| f.puts "all alone" }
|
86
|
+
end
|
94
87
|
|
95
|
-
|
88
|
+
it_should_behave_like "a manifest file"
|
96
89
|
|
97
|
-
|
98
|
-
|
99
|
-
end
|
100
|
-
it "should only contain tag files" do
|
101
|
-
@bag.tagmanifest_files.each do |mf|
|
102
|
-
File.open(mf) do |io|
|
103
|
-
io.each_line do |line|
|
104
|
-
expect(line.chomp).to match(/^[a-fA-F0-9]+\s+(?!data\/)[^\s].+$/)
|
105
|
-
end
|
106
|
-
end
|
90
|
+
it "has a tag manifest file" do
|
91
|
+
expect(@bag.tagmanifest_files).not_to be_empty
|
107
92
|
end
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
93
|
+
it "only contains tag files" do
|
94
|
+
@bag.tagmanifest_files.each do |mf|
|
95
|
+
File.open(mf) do |io|
|
96
|
+
io.each_line do |line|
|
97
|
+
expect(line.chomp).to match(/^[a-fA-F0-9]+\s+(?!data\/)[^\s].+$/)
|
98
|
+
end
|
99
|
+
end
|
115
100
|
end
|
116
101
|
end
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
102
|
+
it "contains manifest and bag info files" do
|
103
|
+
@bag.tagmanifest_files.each do |mf|
|
104
|
+
expect(File.open(mf).read).to include(File.basename(@bag.bag_info_txt_file))
|
105
|
+
expect(File.open(mf).read).to include(File.basename(@bag.bagit_txt_file))
|
106
|
+
@bag.manifest_files.each do |man|
|
107
|
+
expect(File.open(mf).read).to include(man)
|
108
|
+
end
|
122
109
|
end
|
123
110
|
end
|
124
|
-
|
125
|
-
describe "removing tracked files" do
|
126
|
-
before(:each) do
|
127
|
-
@bag.remove_tag_file "tag-1"
|
128
|
-
@bag.delete_tag_file "tag-2"
|
129
|
-
end
|
130
|
-
it "should still have the untracked tag file on the file system" do
|
131
|
-
expect(File.join(@bag_path, "tag-1")).to exist_on_fs
|
132
|
-
end
|
133
|
-
it "should not have the deleted tag file on the file system" do
|
134
|
-
expect(File.join(@bag_path, "tag-2")).not_to exist_on_fs
|
135
|
-
end
|
136
|
-
it "should not have the removed or deleted tag files in the manifest" do
|
111
|
+
it "does not contain the untracked tag file" do
|
137
112
|
@bag.tagmanifest_files.each do |mf|
|
138
113
|
File.open(mf) do |io|
|
139
|
-
expect(io.read).not_to include "tag-
|
140
|
-
expect(io.read).not_to include "tag-2"
|
114
|
+
expect(io.read).not_to include "tag-notrack"
|
141
115
|
end
|
142
116
|
end
|
143
117
|
end
|
144
|
-
end
|
145
|
-
end
|
146
118
|
|
119
|
+
describe "removing tracked files" do
|
120
|
+
before do
|
121
|
+
@bag.remove_tag_file "tag-1"
|
122
|
+
@bag.delete_tag_file "tag-2"
|
123
|
+
end
|
124
|
+
|
125
|
+
it "still has the untracked tag file on the file system" do
|
126
|
+
expect(File.join(@bag_path, "tag-1")).to exist_on_fs
|
127
|
+
end
|
147
128
|
|
129
|
+
it "doesn't have the deleted tag file on the file system" do
|
130
|
+
expect(File.join(@bag_path, "tag-2")).not_to exist_on_fs
|
131
|
+
end
|
132
|
+
|
133
|
+
it "doesn't have the removed or deleted tag files in the manifest" do
|
134
|
+
@bag.tagmanifest_files.each do |mf|
|
135
|
+
File.open(mf) do |io|
|
136
|
+
expect(io.read).not_to include "tag-1"
|
137
|
+
expect(io.read).not_to include "tag-2"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
148
144
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,37 +1,37 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "bundler"
|
5
|
+
require "coveralls"
|
4
6
|
|
5
7
|
Bundler.require(:default, :test)
|
6
8
|
|
7
9
|
Coveralls.wear!
|
8
10
|
|
9
|
-
require File.expand_path(
|
11
|
+
require File.expand_path("./util/bagit_matchers", File.dirname(__FILE__))
|
10
12
|
|
11
13
|
RSpec.configure do |config|
|
12
14
|
config.include(BagitMatchers)
|
13
15
|
end
|
14
16
|
|
15
|
-
|
16
|
-
require
|
17
|
+
$LOAD_PATH.unshift File.expand_path("../lib", File.dirname(__FILE__))
|
18
|
+
require "bagit"
|
17
19
|
|
18
|
-
require
|
20
|
+
require "tempfile"
|
19
21
|
|
20
22
|
class Sandbox
|
21
|
-
|
22
23
|
def initialize
|
23
|
-
tf = Tempfile.open
|
24
|
+
tf = Tempfile.open "sandbox"
|
24
25
|
@path = tf.path
|
25
26
|
tf.close!
|
26
|
-
FileUtils
|
27
|
+
FileUtils.mkdir @path
|
27
28
|
end
|
28
29
|
|
29
30
|
def cleanup!
|
30
|
-
FileUtils
|
31
|
+
FileUtils.rm_rf @path
|
31
32
|
end
|
32
33
|
|
33
34
|
def to_s
|
34
35
|
@path
|
35
36
|
end
|
36
|
-
|
37
37
|
end
|
data/spec/tag_info_spec.rb
CHANGED
@@ -1,133 +1,126 @@
|
|
1
|
-
#
|
2
|
-
require 'spec_helper'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
3
|
+
require "spec_helper"
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
describe BagIt::Bag do
|
6
|
+
describe "Tag Info Files" do
|
7
|
+
before do
|
8
|
+
@sandbox = Sandbox.new
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
# make the bag
|
11
|
+
@bag_path = File.join @sandbox.to_s, "the_bag"
|
12
|
+
@bag = described_class.new @bag_path
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
# add some files
|
15
|
+
File.open("/dev/urandom") do |rio|
|
16
|
+
10.times do |n|
|
17
|
+
@bag.add_file("file-#{n}-💩
|
18
|
+
end
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
after(:each) do
|
24
|
-
@sandbox.cleanup!
|
25
|
-
end
|
26
|
-
|
27
|
-
describe "bagit.txt" do
|
28
|
-
|
29
|
-
before do
|
30
|
-
path = File.join @bag_path, 'bagit.txt'
|
31
|
-
@lines = File.open(path) { |io| io.readlines }
|
22
|
+
after do
|
23
|
+
@sandbox.cleanup!
|
32
24
|
end
|
33
25
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
expect(@lines.size).to eq(2)
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should have a bagit version" do
|
43
|
-
a = @lines.select { |line| line.chomp =~ /BagIt-Version:\s*\d+\.\d+/ }
|
44
|
-
expect(a).not_to be_empty
|
45
|
-
end
|
26
|
+
describe "bagit.txt" do
|
27
|
+
before do
|
28
|
+
path = File.join @bag_path, "bagit.txt"
|
29
|
+
@lines = File.open(path, &:readlines)
|
30
|
+
end
|
46
31
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
32
|
+
it "creates a file bagit.txt on bag initialization" do
|
33
|
+
expect(File.join(@bag_path, "bagit.txt")).to exist_on_fs
|
34
|
+
end
|
51
35
|
|
52
|
-
|
36
|
+
it "has exactly two lines" do
|
37
|
+
expect(@lines.size).to eq(2)
|
38
|
+
end
|
53
39
|
|
54
|
-
|
40
|
+
it "has a bagit version" do
|
41
|
+
a = @lines.select { |line| line.chomp =~ /BagIt-Version:\s*\d+\.\d+/ }
|
42
|
+
expect(a).not_to be_empty
|
43
|
+
end
|
55
44
|
|
56
|
-
|
57
|
-
|
58
|
-
|
45
|
+
it "has a tag file encoding" do
|
46
|
+
a = @lines.select { |line| line.chomp =~ /Tag-File-Character-Encoding:\s*.+/ }
|
47
|
+
expect(a).not_to be_empty
|
48
|
+
end
|
59
49
|
end
|
60
50
|
|
61
|
-
|
62
|
-
|
63
|
-
|
51
|
+
describe "bag-info.txt" do
|
52
|
+
before do
|
53
|
+
path = File.join @bag_path, "bag-info.txt"
|
54
|
+
@lines = File.open(path, &:readlines)
|
55
|
+
end
|
64
56
|
|
65
|
-
|
66
|
-
|
67
|
-
|
57
|
+
it "isn't empty" do
|
58
|
+
expect(@lines).not_to be_empty
|
59
|
+
end
|
68
60
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
61
|
+
it "contains lines of the format LABEL: VALUE (like an email header)" do
|
62
|
+
@lines.each { |line| expect(line.chomp).to match(/^[^\s]+\s*:\s+.*$/) }
|
63
|
+
end
|
73
64
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enimad
|
78
|
-
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
79
|
-
aliquip ex ea commodo consequat. Duis aute irure dolor in
|
80
|
-
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
81
|
-
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
|
82
|
-
culpa qui officia deserunt mollit anim id est laborum.
|
83
|
-
LOREM
|
84
|
-
@bag.write_bag_info 'Lorem' => longline
|
85
|
-
expect(@bag.bag_info.keys.length).to eq(4) # this isn't a great test. Changed it from 1 to 4 because unrelated changes caused failure.
|
86
|
-
end
|
65
|
+
it "is case insensitive with respect to LABELs" do
|
66
|
+
expect { @bag.write_bag_info "foo" => "lowercase", "Foo" => "capital" }.to raise_error(/Multiple labels/)
|
67
|
+
end
|
87
68
|
|
88
|
-
|
89
|
-
|
90
|
-
|
69
|
+
it "folds long VALUEs" do
|
70
|
+
longline = <<~LOREM
|
71
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
|
72
|
+
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enimad
|
73
|
+
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
74
|
+
aliquip ex ea commodo consequat. Duis aute irure dolor in
|
75
|
+
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
76
|
+
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
|
77
|
+
culpa qui officia deserunt mollit anim id est laborum.
|
78
|
+
LOREM
|
79
|
+
@bag.write_bag_info "Lorem" => longline
|
80
|
+
expect(@bag.bag_info.keys.length).to eq(4) # this isn't a great test. Changed it from 1 to 4 because unrelated changes caused failure.
|
81
|
+
end
|
91
82
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
83
|
+
it "specifys a bag software agent" do
|
84
|
+
expect(@bag.bag_info.keys).to include("Bag-Software-Agent")
|
85
|
+
end
|
96
86
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
it "should not override any previous values" do
|
101
|
-
path = File.join @bag_path, 'bag-info.txt'
|
102
|
-
@bag.write_bag_info 'Bag-Software-Agent' => 'Some Other Agent'
|
103
|
-
@bag.write_bag_info 'Source-Organization' => 'Awesome Inc.'
|
104
|
-
@bag.write_bag_info 'Bagging-Date' => '1901-01-01'
|
105
|
-
@bag.write_bag_info
|
106
|
-
contents = File.open(path).read
|
107
|
-
expect(contents).to include "Some Other Agent"
|
108
|
-
expect(contents).to include "Awesome Inc."
|
109
|
-
expect(contents).to include "1901-01-01"
|
110
|
-
end
|
111
|
-
it "should override previous tags when they collide with new ones" do
|
112
|
-
path = File.join @bag_path, 'bag-info.txt'
|
113
|
-
@bag.write_bag_info 'Source-Organization' => 'Awesome Inc.'
|
114
|
-
@bag.write_bag_info 'Source-Organization' => 'Awesome LLC.'
|
115
|
-
contents = File.open(path).read
|
116
|
-
expect(contents).to include "Awesome LLC."
|
117
|
-
expect(contents).not_to include "Awesome Inc."
|
118
|
-
end
|
119
|
-
it "should contain values passed to bag" do
|
120
|
-
hash = {"Bag-Software-Agent" => "rspec",
|
121
|
-
"Bagging-Date" => "2012-11-21",
|
122
|
-
"Contact-Name" => "Willis Corto",
|
123
|
-
"Some-Tag" => "Some Value"
|
124
|
-
}
|
125
|
-
bag_with_info = BagIt::Bag.new(@bag_path + '2', hash)
|
126
|
-
hash.each do |key, value|
|
127
|
-
expect(bag_with_info.bag_info[key]).to eq(value)
|
87
|
+
it "contains a valid bagging date" do
|
88
|
+
expect(@bag.bag_info.keys).to include("Bagging-Date")
|
89
|
+
@bag.bag_info["Bagging-Date"] =~ /^^[0-9]{4}-[0-9]{2}-[0-9]{2}$/
|
128
90
|
end
|
129
|
-
end
|
130
91
|
|
92
|
+
it "contains a payload oxum" do
|
93
|
+
expect(@bag.bag_info.keys).to include("Payload-Oxum")
|
94
|
+
end
|
95
|
+
it "does not override any previous values" do
|
96
|
+
path = File.join @bag_path, "bag-info.txt"
|
97
|
+
@bag.write_bag_info "Bag-Software-Agent" => "Some Other Agent"
|
98
|
+
@bag.write_bag_info "Source-Organization" => "Awesome Inc."
|
99
|
+
@bag.write_bag_info "Bagging-Date" => "1901-01-01"
|
100
|
+
@bag.write_bag_info
|
101
|
+
contents = File.open(path).read
|
102
|
+
expect(contents).to include "Some Other Agent"
|
103
|
+
expect(contents).to include "Awesome Inc."
|
104
|
+
expect(contents).to include "1901-01-01"
|
105
|
+
end
|
106
|
+
it "overrides previous tags when they collide with new ones" do
|
107
|
+
path = File.join @bag_path, "bag-info.txt"
|
108
|
+
@bag.write_bag_info "Source-Organization" => "Awesome Inc."
|
109
|
+
@bag.write_bag_info "Source-Organization" => "Awesome LLC."
|
110
|
+
contents = File.open(path).read
|
111
|
+
expect(contents).to include "Awesome LLC."
|
112
|
+
expect(contents).not_to include "Awesome Inc."
|
113
|
+
end
|
114
|
+
it "contains values passed to bag" do
|
115
|
+
hash = {"Bag-Software-Agent" => "rspec",
|
116
|
+
"Bagging-Date" => "2012-11-21",
|
117
|
+
"Contact-Name" => "Willis Corto",
|
118
|
+
"Some-Tag" => "Some Value"}
|
119
|
+
bag_with_info = described_class.new(@bag_path + "2", hash)
|
120
|
+
hash.each do |key, value|
|
121
|
+
expect(bag_with_info.bag_info[key]).to eq(value)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
131
125
|
end
|
132
|
-
|
133
126
|
end
|