Class: FastlaneCore::ConfigurationFile

Inherits:
Object
  • Object
show all
Defined in:
fastlane_core/lib/fastlane_core/configuration/configuration_file.rb

Overview

Responsible for loading configuration files

Defined Under Namespace

Classes: ExceptionWhileParsingError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config, path, block_for_missing, skip_printing_values = false) ⇒ ConfigurationFile

Returns a new instance of ConfigurationFile.

Parameters:

  • config (FastlaneCore::Configuration)

    is used to gather required information about the configuration

  • path (String)

    The path to the configuration file to use


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
# File 'fastlane_core/lib/fastlane_core/configuration/configuration_file.rb', line 28

def initialize(config, path, block_for_missing, skip_printing_values = false)
  self.available_keys = config.all_keys
  self.configfile_path = path
  self.options = {}

  @block_for_missing = block_for_missing
  content = File.read(path, encoding: "utf-8")

  # From https://github.com/orta/danger/blob/master/lib/danger/Dangerfile.rb
  if content.tr!('“”‘’‛', %(""'''))
    UI.error("Your #{File.basename(path)} has had smart quotes sanitised. " \
              'To avoid issues in the future, you should not use ' \
              'TextEdit for editing it. If you are not using TextEdit, ' \
              'you should turn off smart quotes in your editor of choice.')
  end

  begin
    # rubocop:disable Security/Eval
    eval(content) # this is okay in this case
    # rubocop:enable Security/Eval

    print_resulting_config_values unless skip_printing_values # only on success
  rescue SyntaxError => ex
    line = ex.to_s.match(/\(eval\):(\d+)/)[1]
    UI.error("Error in your #{File.basename(path)} at line #{line}")
    UI.content_error(content, line)
    UI.user_error!("Syntax error in your configuration file '#{path}' on line #{line}: #{ex}")
  rescue => ex
    raise ExceptionWhileParsingError.new(ex, self.options), "Error while parsing config file at #{path}"
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_sym, *arguments, &block) ⇒ Object


85
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
# File 'fastlane_core/lib/fastlane_core/configuration/configuration_file.rb', line 85

def method_missing(method_sym, *arguments, &block)
  # First, check if the key is actually available
  return if self.options.key?(method_sym)

  if self.available_keys.include?(method_sym)

    value = arguments.first
    value = yield if value.nil? && block_given?

    if value.nil?
      unless block_given?
        # The config file has something like this:
        #
        #   clean
        #
        # without specifying a value for the method call
        # or a block. This is most likely a user error
        # So we tell the user that they can provide a value
        warning = ["In the config file '#{self.configfile_path}'"]
        warning << "you have the line #{method_sym}, but didn't provide"
        warning << "any value. Make sure to append a value right after the"
        warning << "option name. Make sure to check the docs for more information"
        UI.important(warning.join(" "))
      end
      return
    end

    self.modified_values[method_sym] = value

    # to support frozen strings (e.g. ENV variables) too
    # we have to dupe the value
    # in < Ruby 2.4.0 `.dup` is not support by boolean values
    # and there is no good way to check if a class actually
    # responds to `dup`, so we have to rescue the exception
    begin
      value = value.dup
    rescue TypeError
      # Nothing specific to do here, if we can't dupe, we just
      # deal with it (boolean values can't be from env variables anyway)
    end
    self.options[method_sym] = value
  else
    # We can't set this value, maybe the tool using this configuration system has its own
    # way of handling this block, as this might be a special block (e.g. ipa block) that's only
    # executed on demand
    if @block_for_missing
      @block_for_missing.call(method_sym, arguments, block)
    else
      self.options[method_sym] = '' # important, since this will raise a good exception for free
    end
  end
end

Instance Attribute Details

#available_keysObject

Available keys from the config file


18
19
20
# File 'fastlane_core/lib/fastlane_core/configuration/configuration_file.rb', line 18

def available_keys
  @available_keys
end

#configfile_pathObject

Path to the config file represented by the current object


24
25
26
# File 'fastlane_core/lib/fastlane_core/configuration/configuration_file.rb', line 24

def configfile_path
  @configfile_path
end

#optionsObject

After loading, contains all the found options


21
22
23
# File 'fastlane_core/lib/fastlane_core/configuration/configuration_file.rb', line 21

def options
  @options
end

Instance Method Details

#for_lane(lane_name) { ... } ⇒ Object

Override configuration for a specific lane. If received lane name does not match the lane name available as environment variable, no changes will be applied.

Parameters:

  • lane_name

    Symbol representing a lane name.

Yields:

  • Block to run for overriding configuration values.


145
146
147
148
149
150
151
# File 'fastlane_core/lib/fastlane_core/configuration/configuration_file.rb', line 145

def for_lane(lane_name)
  if ENV["FASTLANE_LANE_NAME"] == lane_name.to_s
    with_a_clean_config_merged_when_complete do
      yield
    end
  end
end

#for_platform(platform_name) { ... } ⇒ Object

Override configuration for a specific platform. If received platform name does not match the platform name available as environment variable, no changes will be applied.

Parameters:

  • platform_name

    Symbol representing a platform name.

Yields:

  • Block to run for overriding configuration values.


160
161
162
163
164
165
166
# File 'fastlane_core/lib/fastlane_core/configuration/configuration_file.rb', line 160

def for_platform(platform_name)
  if ENV["FASTLANE_PLATFORM_NAME"] == platform_name.to_s
    with_a_clean_config_merged_when_complete do
      yield
    end
  end
end

#modified_valuesObject

This is used to display only the values that have changed in the summary table


81
82
83
# File 'fastlane_core/lib/fastlane_core/configuration/configuration_file.rb', line 81

def modified_values
  @modified_values ||= {}
end

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'fastlane_core/lib/fastlane_core/configuration/configuration_file.rb', line 60

def print_resulting_config_values
  require 'terminal-table'
  UI.success("Successfully loaded '#{File.expand_path(self.configfile_path)}' 📄")

  # Show message when self.modified_values is empty
  if self.modified_values.empty?
    UI.important("No values defined in '#{self.configfile_path}'")
    return
  end

  rows = self.modified_values.collect do |key, value|
    [key, value] if value.to_s.length > 0
  end.compact

  puts("")
  puts(Terminal::Table.new(rows: FastlaneCore::PrintTable.transform_output(rows),
                          title: "Detected Values from '#{self.configfile_path}'"))
  puts("")
end

#with_a_clean_config_merged_when_completeObject

Allows a configuration block (for_lane, for_platform) to get a clean configuration for applying values, so that values can be overridden (once) again. Those values are then merged into the surrounding configuration as the block completes


172
173
174
175
176
177
178
179
180
# File 'fastlane_core/lib/fastlane_core/configuration/configuration_file.rb', line 172

def with_a_clean_config_merged_when_complete
  previous_config = self.options.dup
  self.options = {}
  begin
    yield
  ensure
    self.options = previous_config.merge(self.options)
  end
end