Created
April 28, 2020 14:43
-
-
Save alloy/5d202d4a3fdb3844d0bc7490f628d671 to your computer and use it in GitHub Desktop.
Example of ways to introspect Xcode build settings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# gem install xcodeproj claide hashdiff | |
require 'xcodeproj' | |
require 'claide' | |
require 'pp' | |
argv = CLAide::ARGV.new(ARGV) | |
project_path = argv.shift_argument | |
target_name = argv.option("target") | |
target_type = argv.option("target-type", "PBXNativeTarget") | |
config_name = argv.option("config") | |
diff = argv.flag?("diff") | |
intersection = argv.flag?("intersection") | |
if project_path.nil? || argv.flag?('help') | |
puts "Usage:" | |
puts "\truby #{__FILE__} path/to/the.xcodeproj [OPTIONS]" | |
puts | |
puts "Options:" | |
puts "\t--target-type=type\tThe types of targets to operate on, defaults to PBXNativeTarget" | |
puts "\t--target=name\t\tThe target to limit to" | |
puts "\t--config=name\t\tThe build configuration to operate on/limit to" | |
puts "\t--intersection\t\tFinds the intersection of all configurations" | |
puts "\t--diff\t\t\tWhen combined with `--intersection` target configurations,\n\t\t\t\tare diffed against the intersection; otherwise\n\t\t\t\tconfigurations in `target` are diffed against `config`" | |
puts | |
exit 1 | |
end | |
def print_header(content) | |
puts "=" * 80 | |
puts content | |
puts "=" * 80 | |
end | |
def print_target_header(target, config) | |
print_header "#{target.name}: #{config.name}" | |
end | |
def dump_target(target, config_name = nil) | |
target.build_configurations.each do |config| | |
next if config_name && config.name != config_name | |
print_target_header(target, config) | |
pp config.build_settings | |
puts | |
end | |
end | |
def diff_target_config(target, base_config, skip_config_name = nil) | |
require 'hashdiff' | |
target.build_configurations.each do |config| | |
next if config.name == skip_config_name | |
print_target_header(target, config) | |
pp Hashdiff.diff(base_config, config.build_settings) | |
puts | |
end | |
end | |
def diff_target_config_to_others(target, config_name) | |
base_config = target.build_configurations.find { |c| c.name == config_name } | |
diff_target_config(target, base_config.build_settings, config_name) | |
end | |
def intersect(targets, config_name) | |
require 'hashdiff' | |
result = nil | |
targets.each do |target| | |
target.build_configurations.each do |config| | |
next if config_name && config.name != config_name | |
if result.nil? | |
result = config.build_settings | |
else | |
Hashdiff.diff(result, config.build_settings) | |
.reverse # Remove elements from back to front, otherwise indices will no longer be correct. | |
.each do |type, key, *val| | |
case type | |
when "-" | |
if key.include?("[") | |
_, key, index = key.match(/^(\w+)\[(\d+)\]$/).to_a | |
result[key].delete_at(index.to_i) | |
else | |
result.delete(key) | |
end | |
when "~" | |
before, after = Array(val[0]), Array(val[1]) | |
before.delete_if { |x| !after.include?(x) } | |
case before.size | |
when 0 | |
result.delete(key) | |
when 1 | |
result[key] = before[0] | |
else | |
result[key] = before | |
end | |
else | |
end | |
end | |
end | |
end | |
end | |
result | |
end | |
project = Xcodeproj::Project.open(project_path) | |
targets = target_type ? project.targets.select { |t| t.class.name.split("::").last == target_type } : project.targets | |
if intersection | |
result = intersect(targets, config_name) | |
print_header("Intersection") | |
pp result | |
if diff | |
targets.each do |target| | |
next if target_name && target.name != target_name | |
diff_target_config(target, result) | |
end | |
end | |
else | |
if target_name | |
target = targets.find { |t| t.name == target_name } | |
if diff | |
diff_target_config_to_others(target, config_name) | |
else | |
dump_target(target, config_name) | |
end | |
else | |
targets.each do |target| | |
dump_target(target, config_name) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment