Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional hidden file detection (#51) #52

Merged
merged 10 commits into from
Jul 31, 2024
26 changes: 24 additions & 2 deletions lib/bagit/bag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,40 @@
require "bagit/valid"

module BagIt
class FileFinder
def self.find(dir)
raise NotImplementedError
end
end

class StandardFileFinder < FileFinder
def self.find(dir)
Dir[File.join(dir, "**", "*")].select { |f| File.file? f }
end
end

class StandardWithHiddenFileFinder < FileFinder
def self.find(dir)
Dir.glob(File.join(dir, "**", "*"), File::FNM_DOTMATCH).select { |f| File.file? f }
end
end

# Represents the state of a bag on a filesystem
class Bag
attr_reader :bag_dir
attr_reader :detect_hidden

include Validity # Validity functionality
include Info # bagit & bag info functionality
include Manifest # manifest related functionality
include Fetch # fetch related functionality

# Make a new Bag based at path
def initialize(path, info = {}, _create = false)
def initialize(path, info = {}, _create = false, detect_hidden = false)
@bag_dir = path
@detect_hidden = detect_hidden
@file_finder = @detect_hidden ? StandardWithHiddenFileFinder : StandardFileFinder

# make the dir structure if it doesn't exist
FileUtils.mkdir bag_dir unless File.directory? bag_dir
FileUtils.mkdir data_dir unless File.directory? data_dir
Expand All @@ -37,7 +59,7 @@ def data_dir

# Return the paths to each bag file relative to bag_dir
def bag_files
Dir[File.join(data_dir, "**", "*")].select { |f| File.file? f }
@file_finder.find(data_dir)
end

# Return the paths to each tag file relative to bag_dir
Expand Down
6 changes: 5 additions & 1 deletion lib/bagit/valid.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ def complete?

empty_manifests.each do |file|
logger.error("#{file} is manifested but not present".red)
errors.add :completeness, "#{file} is manifested but not present"
error_message = "#{file} is manifested but not present"
if !detect_hidden && file.start_with?(File.join("data", "."))
error_message += "; consider turning on hidden file detection"
end
errors.add :completeness, error_message
end
tag_empty_manifests.each do |file|
logger.error("#{file} is a manifested tag but not present".red)
Expand Down
27 changes: 27 additions & 0 deletions spec/bagit_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,31 @@
end
end
end

describe "bag with hidden files" do
before do
@sandbox = Sandbox.new

# make the bag
@bag_path = File.join @sandbox.to_s, "the_bag"
@bag = described_class.new @bag_path, {}, false, true

# add some files
@bag.add_file(".keep") { |io| io.puts "" }
@bag.add_file("test.txt") { |io| io.puts "testing testing" }
end

after do
@sandbox.cleanup!
end

describe "#bag_files" do
it "returns an array including non-hidden and hidden files" do
files = @bag.bag_files.map { |f| f.sub(File.join(@bag_path, "data", ""), "") }
expect(files).to be_a_kind_of(Array)
expect(files).not_to be_empty
expect(files).to eq([".keep", "test.txt"])
end
end
end
end
67 changes: 65 additions & 2 deletions spec/validation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,17 @@

it "is invalid if there are files that are in the manifest but not in the bag" do
# add a file and then remove it through the back door
@bag.add_file("file-k") { |io| io.puts "time to go" }
file_name = "file-k"
@bag.add_file(file_name) { |io| io.puts "time to go" }
@bag.manifest!

FileUtils.rm File.join(@bag.bag_dir, "data", "file-k")
FileUtils.rm File.join(@bag.bag_dir, "data", file_name)

@bag.validate_only("true_for/completeness")
expect(@bag.errors.on(:completeness)).not_to be_empty
expect(@bag.errors.on(:completeness)).to include(
"#{File.join("data", file_name)} is manifested but not present"
)
expect(@bag).not_to be_valid
end

Expand Down Expand Up @@ -139,4 +143,63 @@
end
end
end

describe "a bag with unmanifested hidden files" do
before do
@sandbox = Sandbox.new

# make a bag with hidden files not manifested
@source_bag_path = File.join @sandbox.to_s, "the_bag"
@source_bag = described_class.new @source_bag_path, {}, false, false
@source_bag.add_file(".keep") { |io| io.puts "" }
@source_bag.add_file("test.txt") { |io| io.puts "testing testing" }
@source_bag.manifest!
end

after do
@sandbox.cleanup!
end

it "fails validation when hidden file detection is on" do
@aware_bag = described_class.new @source_bag_path, {}, false, true
expect(@aware_bag).to_not be_valid
expect(@aware_bag.errors.on(:completeness)).not_to be_empty
end

it "passes validation when hidden file detection is off" do
@unaware_bag = described_class.new @source_bag_path, {}, false, false
expect(@unaware_bag).to be_valid
end
end

describe "a bag with manifested hidden files" do
before do
@sandbox = Sandbox.new

# make a bag with hidden files manifested
@source_bag_path = File.join @sandbox.to_s, "the_bag"
@source_bag = described_class.new @source_bag_path, {}, false, true
@source_bag.add_file(".keep") { |io| io.puts "" }
@source_bag.add_file("test.txt") { |io| io.puts "testing testing" }
@source_bag.manifest!
end

after do
@sandbox.cleanup!
end

it "passes validation when hidden file detection is on" do
@aware_bag = described_class.new @source_bag_path, {}, false, true
expect(@aware_bag).to be_valid
end

it "fails validation when hidden file detection is off, with suggested fix offered" do
@unaware_bag = described_class.new @source_bag_path, {}, false, false
expect(@unaware_bag).to_not be_valid
expect(@unaware_bag.errors.on(:completeness)).not_to be_empty
expect(@unaware_bag.errors.on(:completeness)).to include(
"data/.keep is manifested but not present; consider turning on hidden file detection"
)
end
end
end