gym/lib/gym/detect_values.rb in fastlane-2.44.0.beta.20170630010021 vs gym/lib/gym/detect_values.rb in fastlane-2.44.0

- old
+ new

@@ -12,10 +12,12 @@ # Detect the project FastlaneCore::Project.detect_projects(config) Gym.project = FastlaneCore::Project.new(config) + detect_selected_provisioning_profiles + # Go into the project's folder, as there might be a Gymfile there Dir.chdir(File.expand_path("..", Gym.project.path)) do config.load_configuration_file(Gym.gymfile_name) end @@ -51,9 +53,82 @@ end def self.xcode_preferences_dictionary(path) CFPropertyList.native_types(CFPropertyList::List.new(file: path).value) end + + # Since Xcode 9 you need to provide the explicit mapping of what provisioning profile to use for + # each target of your app + # rubocop:disable Style/MultilineBlockChain + def self.detect_selected_provisioning_profiles + return if Gym.config[:export_options] && Gym.config[:export_options][:provisioningProfiles] + + require 'xcodeproj' + + provisioning_profile_mapping = {} + + # Find the xcodeproj file, as the information isn't included in the workspace file + if Gym.project.workspace? + # We have a reference to the workspace, let's find the xcodeproj file + # For some reason the `plist` gem can't parse the content file + # so we'll use a regex to find all group references + + workspace_data_path = File.join(Gym.project.path, "contents.xcworkspacedata") + workspace_data = File.read(workspace_data_path) + project_paths = workspace_data.scan(/\"group:(.*)\"/).collect do |current_match| + # It's a relative path from the workspace file + File.join(File.expand_path("..", Gym.project.path), current_match.first) + end.find_all do |current_match| + !current_match.end_with?("Pods/Pods.xcodeproj") + end + else + project_paths = [Gym.project.path] + end + + # Because there might be multiple projects inside a workspace + # we iterate over all of them (except for CocoaPods) + project_paths.each do |project_path| + UI.verbose("Parsing project file '#{project_path}' to find selected provisioning profiles") + begin + project = Xcodeproj::Project.open(project_path) + project.targets.each do |target| + target.build_configuration_list.build_configurations.each do |build_configuration| + current = build_configuration.build_settings + + bundle_identifier = current["PRODUCT_BUNDLE_IDENTIFIER"] + provisioning_profile_specifier = current["PROVISIONING_PROFILE_SPECIFIER"] + next if provisioning_profile_specifier.to_s.length == 0 + + provisioning_profile_mapping[bundle_identifier] = provisioning_profile_specifier + end + end + rescue => ex + # We catch errors here, as we might run into an exception on one included project + # But maybe the next project actually contains the information we need + if Helper.xcode_at_least?("9.0") + UI.error(ex) + UI.verbose(ex.backtrace.join("\n")) + end + end + end + + return if provisioning_profile_mapping.count == 0 + + Gym.config[:export_options] ||= {} + Gym.config[:export_options][:provisioningProfiles] = provisioning_profile_mapping + UI.message("Detected provisioning profile mapping: #{provisioning_profile_mapping}") + rescue => ex + # We don't want to fail the build if the automatic detection doesn't work + # especially since the mapping is optional for pre Xcode 9 setups + if Helper.xcode_at_least?("9.0") + UI.error("Couldn't automatically detect the provisioning profile mapping") + UI.error("Since Xcode 9 you need to provide an explicit mapping of what") + UI.error("provisioning profile to use for each target of your app") + UI.error(ex) + UI.verbose(ex.backtrace.join("\n")) + end + end + # rubocop:enable Style/MultilineBlockChain def self.detect_scheme Gym.project.select_scheme end