Class: Longleaf::SelectionOptionsParser

Inherits:
Object
  • Object
show all
Extended by:
Logging
Defined in:
lib/longleaf/helpers/selection_options_parser.rb

Overview

Helper for parsing manifest inputs used for registration

Class Method Summary collapse

Methods included from Logging

initialize_logger, initialize_logger, logger, logger

Class Method Details

.create_registered_selector(options, app_config_manager) ⇒ Object

Parses the provided options to create a selector for registered files

Parameters:

Returns:

  • selector



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# 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) ⇒ Object



210
211
212
213
# File 'lib/longleaf/helpers/selection_options_parser.rb', line 210

def self.fail(message)
  logger.failure(message)
  exit 1
end

.parse_manifest(manifest_vals) ⇒ Object

Parses the provided manifest options, reading the contents of the manifests to produce a mapping from files to one or more algorithms. . <manifest_path> OR @-

Parameters:

  • manifest_vals (Array)

    List of manifest option values. They may be in one of the following formats: <alg_name>:<manifest_path> OR <alg_name>:@-

Returns:

  • 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.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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
# 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) ⇒ Object

Parses the provided options to construct a file selector and digest provider for use in registration commands.

Parameters:

Returns:

  • The file selector and digest provider.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# 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) ⇒ Object

Parses the -l from_list option, reading the list of files specified either from the provided file path or STDIN

Parameters:

  • from_list

    option value, either a file path or “@-”

Returns:

  • list of files from the from_list



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# 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)) ⇒ Object

Splits a string of quoted or unquoted tokens separated by spaces

Parameters:



147
148
149
150
151
# 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) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
# 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