lib/longleaf/candidates/file_selector.rb in longleaf-0.2.0.pre.1 vs lib/longleaf/candidates/file_selector.rb in longleaf-0.3.0

- old
+ new

@@ -2,48 +2,69 @@ module Longleaf # Selects and allows for iteration over files which match a provided set of selection criteria class FileSelector include Longleaf::Logging - + SPECIFICITY_PATH = 'path' + SPECIFICITY_STORAGE_LOCATION = 'storage_location' + + attr_reader :specificity + # May only provide either file_paths or storage_locations def initialize(file_paths: nil, storage_locations: nil, app_config:) if nil_or_empty?(file_paths) && nil_or_empty?(storage_locations) raise ArgumentError.new("Must provide either file paths or storage locations") end if !nil_or_empty?(file_paths) && !nil_or_empty?(storage_locations) raise ArgumentError.new("Cannot provide both file paths and storage locations") end @app_config = app_config # The top level paths targeted by this selector - @target_paths = file_paths + @target_paths = file_paths&.map do |path| + # Resolve relative paths against pwd + pathname = Pathname.new(path) + if !pathname.absolute? + path = File.join(Dir.pwd, path) + end + path = File.expand_path(path) + + # adding trailing /'s to directories + if Dir.exist?(path) && !path.end_with?('/') + path + '/' + else + path + end + end # The set of storage locations to select file paths from @storage_locations = storage_locations # Validate that the selected storage locations are known - unless @storage_locations.nil? + if @storage_locations.nil? + @specificity = SPECIFICITY_PATH + else + @specificity = SPECIFICITY_STORAGE_LOCATION locations = @app_config.location_manager.locations @storage_locations.each do |loc_name| unless locations.key?(loc_name) raise StorageLocationUnavailableError.new("Cannot select unknown storage location #{loc_name}.") end end end end - + # @return [Array] a list of top level paths from which files will be selected def target_paths # If starting from locations, initialize by expanding locations out to their actual paths if @target_paths.nil? && !@storage_locations.nil? @target_paths = Array.new @storage_locations.each do |loc_name| @target_paths << @app_config.location_manager.locations[loc_name].path end end - + @target_paths end - + # Get the next file path for this selector. # @return [String] an absolute path to the next file targeted by this selector, # or nil if no more files selected def next_path if @paths.nil? @@ -52,36 +73,47 @@ @paths = target_paths.reverse end # No more paths to return return nil if @paths&.empty? - + # Get the most recently added path for depth first traversal of selected paths path = @paths.pop until path.nil? do @app_config.location_manager.verify_path_in_location(path) - + if File.exist?(path) if File.directory?(path) logger.debug("Expanding directory #{path}") # For a directory, add all children to file_paths - Dir.entries(path).sort.reverse.each do |child| + Dir.entries(path).sort.reverse_each do |child| @paths << File.join(path, child) unless child == '.' or child == '..' end else logger.debug("Returning file #{path}") return path end else raise InvalidStoragePathError.new("File #{path} does not exist.") end - + # Returned path was not a suitable file, try the next path path = @paths.pop end end - + + # Iterate through the file paths for this selector and execute the provided block with each. + # A block is required. + def each + file_path = next_path + until file_path.nil? + yield file_path + + file_path = next_path + end + end + # return [Array] a list of all storage locations being targeted by this selector def storage_locations # Determine what storage_locations are represented by the given file paths if @storage_locations.nil? && !@target_paths.nil? loc_set = Set.new @@ -89,19 +121,19 @@ loc = @app_config.location_manager.get_location_by_path(path) loc_set.add(loc.name) unless loc.nil? end @storage_locations = loc_set.to_a end - + if @storage_locations.nil? @storage_locations = Array.new end - + @storage_locations end - + private def nil_or_empty?(value) value.nil? || value.empty? end end -end \ No newline at end of file +end