Module: BagIt::Manifest

Included in:
Bag
Defined in:
lib/bagit/manifest.rb

Overview

Requires response to bag_dir, tag_files, bag_files

Instance Method Summary collapse

Instance Method Details

#add_tag_file(path, src_path = nil) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/bagit/manifest.rb', line 114

def add_tag_file(path, src_path = nil)
  f = File.join(@bag_dir, path)
  raise "Tag file already in manifest: #{path}" if tag_files.include?(f)

  if !File.exist? f
    FileUtils.mkdir_p File.dirname(f)

    # write file
    if src_path.nil?
      File.open(f, 'w') { |io| yield io }
    else
      FileUtils.cp src_path, f
    end
    # this adds the manifest and bag info files on initial creation
    # it must only run when the manifest doesn't already exist or it will
    # infinitely recall add_tag_file. Better way of doing this?
    tagmanifest!
  elsif !src_path.nil?
    raise "Tag file already exists, will not overwrite: #{path}\n Use add_tag_file(path) to add an existing tag file."
  end

  data = File.open(f, &:read)
  rel_path = Pathname.new(f).relative_path_from(Pathname.new(bag_dir)).to_s

  # sha1
  sha1 = Digest::SHA1.hexdigest data
  File.open(tagmanifest_file(:sha1), 'a') { |io| io.puts "#{sha1} #{rel_path}" }

  # md5
  md5 = Digest::MD5.hexdigest data
  File.open(tagmanifest_file(:md5), 'a') { |io| io.puts "#{md5} #{rel_path}" }
  tag_files
end

#delete_tag_file(path) ⇒ Object



155
156
157
158
159
160
# File 'lib/bagit/manifest.rb', line 155

def delete_tag_file(path)
  filepath = File.join(@bag_dir, path)
  raise "Tag file does not exist: #{path}" unless File.exist? filepath
  remove_tag_file(path) if tag_files.include?(path)
  FileUtils.rm filepath
end

#encode_filename(s) ⇒ Object



8
9
10
11
12
# File 'lib/bagit/manifest.rb', line 8

def encode_filename(s)
  s = s.gsub(/\r/, '%0D')
  s = s.gsub(/\n/, '%0A')
  s
end

#fixed?Boolean

Returns true if all present manifested files’ message digests match the actual message digest

Returns:

  • (Boolean)


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/bagit/manifest.rb', line 164

def fixed?
  (manifest_files + tagmanifest_files).all? do |mf|
    # extract the algorithm
    mf =~ /manifest-(.+).txt$/

    algo = case Regexp.last_match(1)
           when /sha1/i
             Digest::SHA1
           when /md5/i
             Digest::MD5
           else
             :unknown
           end

    # check it, an unknown algorithm is always true
    if algo == :unknown
      true
    else
      lines = File.open(mf, &:readlines)

      lines.all? do |line|
        manifested_digest, path = line.chomp.split(/\s+/, 2)
        actual_digest = File.open(File.join(@bag_dir, path)) { |io| algo.hexdigest io.read }
        actual_digest == manifested_digest
      end

    end
  end
end

#manifest!(algo: 'default') ⇒ Object

Generate manifest files for all the bag files



28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/bagit/manifest.rb', line 28

def manifest!(algo: 'default')
  # nuke all the existing manifest files
  manifest_files.each { |f| FileUtils.rm f }

  # manifest each tag file for each algorithm
  bag_files.each do |f|
    rel_path = encode_filename(Pathname.new(f).relative_path_from(Pathname.new(bag_dir)).to_s)

    write_checksum(checksum_algo: algo, relative_path: rel_path, file: f)
  end
  tagmanifest!
end

#manifest_file(algo) ⇒ Object

A path to a manifest file of the specified algorithm



23
24
25
# File 'lib/bagit/manifest.rb', line 23

def manifest_file(algo)
  File.join bag_dir, "manifest-#{algo}.txt"
end

#manifest_filesObject

All tag files that are bag manifest files (manifest-.txt)



15
16
17
18
19
20
# File 'lib/bagit/manifest.rb', line 15

def manifest_files
  files = Dir[File.join(@bag_dir, '*')].select do |f|
    File.file?(f) && File.basename(f) =~ /^manifest-.*.txt$/
  end
  files
end

#remove_tag_file(path) ⇒ Object



148
149
150
151
152
153
# File 'lib/bagit/manifest.rb', line 148

def remove_tag_file(path)
  tags = tag_files
  raise "Tag file is not in manifest: #{path}" unless tags.include?(File.join(@bag_dir, path))
  tags.delete(File.join(@bag_dir, path))
  tagmanifest!(tags)
end

#tagmanifest!(tags = nil) ⇒ Object

Generate manifest files for all the tag files (except the tag manifest files)



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/bagit/manifest.rb', line 92

def tagmanifest!(tags = nil)
  tags = tag_files if tags.nil?

  # nuke all the existing tagmanifest files
  tagmanifest_files.each { |f| FileUtils.rm f }

  # ensure presence of manfiest files
  manifest_files.each do |manifest|
    tags << manifest unless tags.include?(manifest)
  end

  # ensure presence of bag info files
  tags << bag_info_txt_file unless tags.include?(bag_info_txt_file)
  tags << bagit_txt_file unless tags.include?(bagit_txt_file)

  # manifest each (non tagmanifest) tag file for each algorithm
  tags.each do |f|
    add_tag_file(Pathname.new(f).relative_path_from(Pathname.new(bag_dir)).to_s)
  end
  tag_files
end

#tagmanifest_file(algo) ⇒ Object

A path to a tagmanifest file of the specified algorithm



86
87
88
# File 'lib/bagit/manifest.rb', line 86

def tagmanifest_file(algo)
  File.join bag_dir, "tagmanifest-#{algo}.txt"
end

#tagmanifest_filesObject

All tag files that are bag manifest files (tagmanifest-.txt)



78
79
80
81
82
83
# File 'lib/bagit/manifest.rb', line 78

def tagmanifest_files
  files = Dir[File.join(@bag_dir, '*')].select do |f|
    File.file?(f) && File.basename(f) =~ /^tagmanifest-.*.txt$/
  end
  files
end

#write_checksum(checksum_algo:, relative_path:, file:) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/bagit/manifest.rb', line 41

def write_checksum(checksum_algo:, relative_path:, file:)
  case checksum_algo
  when 'sha1'
    write_sha1(file, relative_path)
  when 'md5'
    write_md5(file, relative_path)
  when 'sha256'
    write_sha256(file, relative_path)
  when 'sha512'
    write_sha256(file, relative_path)
  when 'default'
    write_sha1(file, relative_path)
    write_md5(file, relative_path)
  end
end

#write_md5(f, rel_path) ⇒ Object



62
63
64
65
# File 'lib/bagit/manifest.rb', line 62

def write_md5(f, rel_path)
  md5 = Digest::MD5.file f
  File.open(manifest_file(:md5), 'a') { |io| io.puts "#{md5} #{rel_path}" }
end

#write_sha1(f, rel_path) ⇒ Object



57
58
59
60
# File 'lib/bagit/manifest.rb', line 57

def write_sha1(f, rel_path)
  sha1 = Digest::SHA1.file f
  File.open(manifest_file(:sha1), 'a') { |io| io.puts "#{sha1} #{rel_path}" }
end

#write_sha256(f, rel_path) ⇒ Object



67
68
69
70
# File 'lib/bagit/manifest.rb', line 67

def write_sha256(f, rel_path)
  sha256 = Digest::SHA256.file f
  File.open(manifest_file(:sha256), 'a') { |io| io.puts "#{sha256} #{rel_path}" }
end

#write_sha512(f, rel_path) ⇒ Object



72
73
74
75
# File 'lib/bagit/manifest.rb', line 72

def write_sha512(f, rel_path)
  sha512 = Digest::SHA512.file f
  File.open(manifest_file(:sha512), 'a') { |io| io.puts "#{sha512} #{rel_path}" }
end