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



112
113
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
# File 'lib/bagit/manifest.rb', line 112

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.read(f)
  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



153
154
155
156
157
158
# File 'lib/bagit/manifest.rb', line 153

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



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

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

#fixed?Boolean

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

Returns:

  • (Boolean)


162
163
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
# File 'lib/bagit/manifest.rb', line 162

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



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

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



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

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

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

#remove_tag_file(path) ⇒ Object



146
147
148
149
150
151
# File 'lib/bagit/manifest.rb', line 146

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)



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

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



84
85
86
# File 'lib/bagit/manifest.rb', line 84

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

#tagmanifest_filesObject

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



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

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

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



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

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



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

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



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

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



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

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



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

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