Class: Fastlane::Actions::ReadXcconfigAction

Inherits:
Action
  • Object
show all
Defined in:
lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb

Overview

Action to read and resolve values in Xcconfig files.

Implementation collapse

Info and Options collapse

Class Method Summary collapse

Class Method Details

.authorsObject

Plugin action authors.



160
161
162
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 160

def self.authors
  ["Maksym Grebenets"]
end

.available_optionsObject

Plugin action available options.



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
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 180

def self.available_options
  [
    FastlaneCore::ConfigItem.new(key: :path,
                            env_name: "XCCONFIG_ACTIONS_READ_PATH",
                         description: "Path to xcconfig to read",
                            optional: false,
                                type: String,
                        verify_block: proc do |value|
                                        UI.user_error!("Couldn't find xcconfig at path: '#{value}'") unless File.exist?(value)
                                      end),
    FastlaneCore::ConfigItem.new(key: :parent,
                            env_name: "XCCONFIG_ACTIONS_READ_PARENT",
                         description: "Parent xcconfig file to inherit build settings from.\nThis is the xcconfig you'd set on the project level in Xcode",
                            optional: true,
                                type: String,
                        verify_block: proc do |value|
                                        UI.user_error!("Couldn't find parent xcconfig at path: '#{value}'") if value && !File.exist?(value)
                                      end),
    FastlaneCore::ConfigItem.new(key: :resolve,
                            env_name: "XCCONFIG_ACTIONS_READ_RESOLVE",
                         description: "Resolve variables in xcconfigs",
                       default_value: true,
                                type: Boolean),
    FastlaneCore::ConfigItem.new(key: :srcroot,
                            env_name: "XCCONFIG_ACTIONS_READ_SRCROOT",
                         description: "Value for SRCROOT build setting, default is current working directory",
                            optional: true,
                                type: String),
    FastlaneCore::ConfigItem.new(key: :target_name,
                            env_name: "XCCONFIG_ACTIONS_READ_TARGET_NAME",
                         description: "Value for TARGET_NAME build setting",
                            optional: true,
                                type: String),
    FastlaneCore::ConfigItem.new(key: :output_path,
                            env_name: "XCCONFIG_ACTIONS_READ_OUTPUT_PATH",
                         description: "Output path",
                            optional: true,
                                type: String)
  ]
end

.categoryObject

Plugin action category.



175
176
177
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 175

def self.category
  :building
end

.descriptionObject

Plugin action description.



155
156
157
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 155

def self.description
  "Read and resolve contents of xcconfig file and return as JSON"
end

.detailsObject

Plugin action details.



170
171
172
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 170

def self.details
  ""
end

.is_supported?(platform) ⇒ Boolean

Check if platform is supported by the action.

Parameters:

  • platform (Symbol)

    Platform to check.

Returns:

  • (Boolean)

    A Boolean indicating whether the platform is supported by the action.



224
225
226
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 224

def self.is_supported?(platform)
  [:ios, :mac].include?(platform)
end

.read_config(filename) ⇒ Hash<String,String>

Read xcconfig value as a hash.

Parameters:

  • filename (String)

    Xcconfig path.

Returns:

  • (Hash<String,String>)

    Dictionary of xcconfig values.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 71

def self.read_config(filename)
  # TODO: If filename starts with <DEVELOPER_DIR>, then need to resolve it first.
  return {} if filename.nil? || !File.exist?(filename)

  # Used to use Xcodeproj::Config.new(filename) here, but it just doesn't do the job,
  # e.g. it resolves $(inherited) incorrectly, allowing it to work within the scope of one file
  # without any parent config.

  xcconfig = Helper::XcconfigActionsHelper.read_xcconfig(filename)
  config = xcconfig[:config]
  includes = xcconfig[:includes]

  # Xcodeproj does not resolve overrides from included files, so do it manually.
  resolved_includes_config = includes.reduce({}) do |resolved_config, include_path|
    resolved_path = resolve_path(include_path, relative_to: filename)
    resolved_config.merge(read_config(resolved_path))
  end

  config.merge(resolved_includes_config)
end

.resolve(config, parent, srcroot, target_name) ⇒ Hash

Resolve config using parent information.

Parameters:

  • config (Hash)

    Config to resolve.

  • parent (Hash)

    Parent config.

  • srcroot (String)

    Path to use for $(SRCROOT).

  • target_name (String)

    Name to use for $(TARGET_NAME)

Returns:

  • (Hash)

    Resolved config.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 48

def self.resolve(config, parent, srcroot, target_name)
  parent_config = read_config(parent)

  parent_config["SRCROOT"] = srcroot
  parent_config["TARGET_NAME"] = target_name if target_name

  if Helper::XcconfigActionsHelper.command_exist?("xcodebuild")
    # Set value of XCODE_VERSION_MAJOR not available when reading xcconfigs directly.
    xcode_version = `xcodebuild -version | head -n1 | cut -d' ' -f2 | xargs`.strip
    xcode_version_major_padded = xcode_version.split(".").first.rjust(2, "0") + "00"
    parent_config["XCODE_VERSION_MAJOR"] = xcode_version_major_padded
  end

  resolved_parent_config = resolve_config(parent_config)
  resolved_config = resolve_config(config, parent: resolved_parent_config)

  resolved_parent_config.merge(resolved_config)
end

.resolve_config(config, parent: {}) ⇒ Hash<String,String>

Resolve xcconfig values using parent config.

Parameters:

  • config (Hash<String,String>)

    Current dictionary of values.

  • parent (Hash<String,String>) (defaults to: {})

    Resolved parent xcconfig values.

Returns:

  • (Hash<String,String>)

    Resolved xcconfig values.



143
144
145
146
147
148
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 143

def self.resolve_config(config, parent: {})
  config.each do |k, v|
    resolve_value(v, key: k, resolved: config, parent: parent)
  end
  config
end

.resolve_path(path, relative_to:) ⇒ String

Expand given path in relation to another path.

Used to resolved ‘#include “relative/path.xcconfig”’ includes.

Parameters:

  • path (String)

    Path to expand.

  • relative_to (String)

    Parent path to expand in relation to.

Returns:

  • (String)

    Expanded path.



100
101
102
103
104
105
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 100

def self.resolve_path(path, relative_to:)
  # Absolute or special SDK paths need no resolving.
  return path if path.start_with?("/", "<")

  File.expand_path(File.join(File.dirname(relative_to), path))
end

.resolve_value(value, key:, resolved: {}, parent: {}) ⇒ String

Resolve xcconfig value, i.e. expand any of the $() variable references.

Parameters:

  • value (String)

    String value to resolve.

  • key (String)

    Key under which this value is defined in xcconfig. This key will be used to pick up values from parent xcconfig.

  • resolved (Hash<String,String>) (defaults to: {})

    Dictionary of already resolved values.

  • parent (Hash<String,String>) (defaults to: {})

    Dictionary of parent xcconfig values.

Returns:

  • (String)

    Resolved value.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 115

def self.resolve_value(value, key:, resolved: {}, parent: {})
  matches = value.scan(/(\$\([^$\)]*\))/)

  mutable_value = value.dup # Prevent unwanted side-effect of input modification.
  matches.each do |group|
    group.each do |match|
      var_name = match.delete("$()")
      # If inherited, use value from parent config.
      var_value = if var_name == "inherited"
                    parent[key]
                  else
                    resolved[var_name] || parent[var_name]
                  end
      mutable_value.gsub!(match, var_value || "")
      resolved[key] = mutable_value
    end
  end

  # If there are still variables, keep resolving then.
  mutable_value.include?("$(") ? resolve_value(mutable_value, key: key, resolved: resolved, parent: parent) : mutable_value
end

.return_valueObject

Plugin action return value.



165
166
167
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 165

def self.return_value
  "Parse and resolved build settings from xcconfig represented as JSON"
end

.run(params) ⇒ Hash

Run action.

Parameters:

  • params (Hash)

    Action parameters.

Returns:

  • (Hash)

    Xcconfig dictionary.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/fastlane/plugin/xcconfig_actions/actions/read_xcconfig_action.rb', line 19

def self.run(params)
  path = params[:path]
  parent = params[:parent]
  srcroot = params[:srcroot] || Dir.pwd
  target_name = params[:target_name]

  config = read_config(path)

  config = resolve(config, parent, srcroot, target_name) if params[:resolve]

  Actions.lane_context[SharedValues::XCCONFIG_ACTIONS_BUILD_SETTINGS] = config

  if params[:output_path]
    File.open(params[:output_path], "w") { |f| f.puts(config.to_json) }
  else
    return config
  end
end