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



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
147
148
# File 'lib/bagit/manifest.rb', line 116

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



157
158
159
160
161
162
# File 'lib/bagit/manifest.rb', line 157

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



10
11
12
13
14
# File 'lib/bagit/manifest.rb', line 10

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)


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
193
194
# File 'lib/bagit/manifest.rb', line 166

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



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

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



25
26
27
# File 'lib/bagit/manifest.rb', line 25

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

#manifest_filesObject

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



17
18
19
20
21
22
# File 'lib/bagit/manifest.rb', line 17

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

#remove_tag_file(path) ⇒ Object



150
151
152
153
154
155
# File 'lib/bagit/manifest.rb', line 150

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)



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

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



88
89
90
# File 'lib/bagit/manifest.rb', line 88

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

#tagmanifest_filesObject

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



80
81
82
83
84
85
# File 'lib/bagit/manifest.rb', line 80

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

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



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

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_sha512(file, relative_path)
  when "default"
    write_sha1(file, relative_path)
    write_md5(file, relative_path)
  end
end

#write_md5(f, rel_path) ⇒ Object



64
65
66
67
# File 'lib/bagit/manifest.rb', line 64

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



59
60
61
62
# File 'lib/bagit/manifest.rb', line 59

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



69
70
71
72
# File 'lib/bagit/manifest.rb', line 69

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



74
75
76
77
# File 'lib/bagit/manifest.rb', line 74

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