class Longleaf::SelectionOptionsParser

Helper for parsing manifest inputs used for registration

Public Class Methods

create_registered_selector(options, app_config_manager) click to toggle source

Parses the provided options to create a selector for registered files @param options [Hash] command options @param app_config_manager [ApplicationConfigManager] app config manager @return selector

# File lib/longleaf/helpers/selection_options_parser.rb, line 157
def self.create_registered_selector(options, app_config_manager)
  there_can_be_only_one("Only one of the following selection options may be provided: -l, -f, -s",
      options, :file, :location, :from_list)
      
  if !options[:from_list].nil?
    file_paths = read_from_list(options[:from_list])
    return RegisteredFileSelector.new(file_paths: file_paths, app_config: app_config_manager)
  elsif !options[:file].nil?
    file_paths = options[:file].split(/\s*,\s*/)
    return RegisteredFileSelector.new(file_paths: file_paths, app_config: app_config_manager)
  elsif !options[:location].nil?
    storage_locations = options[:location].split(/\s*,\s*/)
    return RegisteredFileSelector.new(storage_locations: storage_locations, app_config: app_config_manager)
  else
    logger.failure("Must provide one of the following file selection options: -l, -f, or -s")
    exit 1
  end
end
fail(message) click to toggle source
# File lib/longleaf/helpers/selection_options_parser.rb, line 210
def self.fail(message)
  logger.failure(message)
  exit 1
end
parse_manifest(manifest_vals) click to toggle source
Parses the provided manifest options, reading the contents of the manifests to produce
a mapping from files to one or more algorithms.
@param manifest_vals [Array] List of manifest option values. They may be in one of the following formats:
      <alg_name>:<manifest_path> OR <alg_name>:@-

. <manifest_path> OR @-

@return a hash containing the aggregated contents of the provided manifests. The keys are
   paths to manifested files. The values are hashes, mapping digest algorithms to digest values.
# File lib/longleaf/helpers/selection_options_parser.rb, line 86
def self.parse_manifest(manifest_vals)
  alg_manifest_pairs = []
  # interpret option inputs into a list of algorithms to manifest sources
  manifest_vals.each do |manifest_val|
    if manifest_val.include?(':')
      manifest_parts = manifest_val.split(':', 2)
      alg_manifest_pairs << manifest_parts
    else
      # algorithm not specified in option value
      alg_manifest_pairs << [nil, manifest_val]
    end
  end
  if alg_manifest_pairs.select { |mpair| mpair[1] == '@-' }.count > 1
    self.fail("Cannot specify more than one manifest from STDIN")
  end

  # read the provided manifests to build a mapping from file uri to all supplied digests
  digests_mapping = Hash.new { |h,k| h[k] = Hash.new }
  logical_phys_mapping = Hash.new
  alg_manifest_pairs.each do |mpair|
    source_stream = nil
    # Determine if reading from a manifest file or stdin
    if mpair[1] == '@-'
      source_stream = $stdin
    else
      source_stream = File.new(mpair[1])
    end

    current_alg = mpair[0]
    multi_digest_manifest = current_alg.nil?
    source_stream.each_line do |line|
      line = line.strip
      if multi_digest_manifest && /^[a-zA-Z0-9]+:$/ =~ line
        # Found a digest algorithm header, assuming succeeding entries are of this type
        current_alg = line.chomp(':')
        # Verify that the digest algorithm is known to longleaf
        if !DigestHelper.is_known_algorithm?(current_alg)
          self.fail("Manifest specifies unknown digest algorithm: #{current_alg}")
        end
      else
        if current_alg.nil?
          self.fail("Manifest with unknown checksums encountered, an algorithm must be specified")
        end
        entry_parts = self.split_quoted(line)
        if entry_parts.length != 2 && entry_parts.length != 3
          self.fail("Invalid manifest entry: #{line}")
        end

        digests_mapping[entry_parts[1]][current_alg] = entry_parts[0]
        if (entry_parts.length == 3)
          logical_phys_mapping[entry_parts[1]] = entry_parts[2]
        end
      end
    end
  end

  [digests_mapping, logical_phys_mapping]
end
parse_registration_selection_options(options, app_config_manager) click to toggle source

Parses the provided options to construct a file selector and digest provider for use in registration commands. @param options [Hash] command options @param app_config_manager [ApplicationConfigManager] app config manager @return The file selector and digest provider.

# File lib/longleaf/helpers/selection_options_parser.rb, line 17
def self.parse_registration_selection_options(options, app_config_manager)
  there_can_be_only_one("Only one of the following selection options may be provided: -m, -f, -s",
      options, :file, :manifest, :location)

  if !options[:manifest].nil?
    digests_mapping, logical_phys_mapping = self.parse_manifest(options[:manifest])
    physical_provider = PhysicalPathProvider.new(logical_phys_mapping)
    selector = FileSelector.new(file_paths: digests_mapping.keys,
         physical_provider: physical_provider,
         app_config: app_config_manager)
    digest_provider = ManifestDigestProvider.new(digests_mapping)
  elsif !options[:file].nil?
    if options[:checksums]
      checksums = options[:checksums]
      # validate checksum list format, must a comma delimited list of prefix:checksums
      if /^[^:,]+:[^:,]+(,[^:,]+:[^:,]+)*$/.match(checksums)
        # convert checksum list into hash with prefix as key
        checksums = Hash[*checksums.split(/\s*[:,]\s*/)]
        digest_provider = SingleDigestProvider.new(checksums)
      else
        logger.failure("Invalid checksums parameter format, see `longleaf help <command>` for more information")
        exit 1
      end
    end

    file_paths = self.split_quoted(options[:file], "\\s*,\\s*")
    if !options[:physical_path].nil?
      physical_paths = self.split_quoted(options[:physical_path], "\\s*,\\s*")
      if physical_paths.length != file_paths.length
        logger.failure("Invalid physical paths parameter, number of paths did not match number of logical paths")
        exit 1
      end
      logical_phys_mapping = Hash[file_paths.zip physical_paths]
      physical_provider = PhysicalPathProvider.new(logical_phys_mapping)
    else
      physical_provider = PhysicalPathProvider.new
    end
    
    selector = FileSelector.new(file_paths: file_paths,
         physical_provider: physical_provider,
         app_config: app_config_manager)
  else
    logger.failure("Must provide one of the following file selection options: -f, l, or -m")
    exit 1
  end

  [selector, digest_provider, physical_provider]
end
read_from_list(from_list) click to toggle source

Parses the -l from_list option, reading the list of files specified either from the provided file path or STDIN @param from_list option value, either a file path or “@-” @return list of files from the from_list

# File lib/longleaf/helpers/selection_options_parser.rb, line 180
def self.read_from_list(from_list)
  from_list = from_list.strip
  if from_list.empty?
    logger.failure("List parameter must not be empty")
    exit 1
  end
  
  if from_list == '@-'
    source_stream = $stdin
  else
    begin
      source_stream = File.new(from_list)
    rescue Errno::ENOENT
      logger.failure("Specified list file does not exist: #{from_list}")
      exit 1
    end
  end
  
  lines = []
  source_stream.each_line do |line|
    lines << line.strip
  end
  
  if lines.empty?
    logger.failure("File list is empty, must provide one or more files for this operation")
    exit 1
  end
  lines
end
split_quoted(text, delimiter = "\\s+", limit = -1) click to toggle source

Splits a string of quoted or unquoted tokens separated by spaces @param

# File lib/longleaf/helpers/selection_options_parser.rb, line 147
def self.split_quoted(text, delimiter = "\\s+", limit = -1)
  text.split(/#{delimiter}(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/, limit)
      .select {|s| not s.empty? }
      .map {|s| s.gsub(/(^ +)|( +$)|(^["']+)|(["']+$)/, '')}
end
there_can_be_only_one(failure_msg, options, *names) click to toggle source
# File lib/longleaf/helpers/selection_options_parser.rb, line 66
def self.there_can_be_only_one(failure_msg, options, *names)
  got_one = false
  names.each do |name|
    if !options[name].nil?
      if got_one
        logger.failure(failure_msg)
        exit 1
      end
      got_one = true
    end
  end
end