class Fastlane::SwiftRunnerUpgrader

build project

Constants

API_VERSION_REGEX
RELATIVE_SOURCE_FILE_PATH

Attributes

fastlane_runner_target[RW]
manifest_groups[RW]
manifest_hash[RW]
source_swift_code_file_folder_path[RW]
target_project[RW]
target_swift_code_file_folder_path[RW]

Public Class Methods

new() click to toggle source
# File fastlane/lib/fastlane/swift_runner_upgrader.rb, line 28
def initialize
  @source_swift_code_file_folder_path = File.expand_path(File.join(Fastlane::ROOT, "/swift"))
  @target_swift_code_file_folder_path = FastlaneCore::FastlaneFolder.swift_folder_path

  Fastlane::Setup.setup_swift_support

  manifest_file = File.join(@source_swift_code_file_folder_path, "/upgrade_manifest.json")
  UI.success("loading manifest: #{manifest_file}")
  @manifest_hash = JSON.parse(File.read(manifest_file))
  @manifest_groups = @manifest_hash.values.uniq

  runner_project_path = FastlaneCore::FastlaneFolder.swift_runner_project_path
  @target_project = Xcodeproj::Project.open(runner_project_path)

  @root_group = @target_project.groups.select { |group| group.name == "Fastlane Runner" }.first

  @fastlane_runner_target = @target_project.targets.select { |target| target.name == "FastlaneRunner" }.first
end

Public Instance Methods

add_missing_groups_and_files!(dry_run: false) click to toggle source

adds new groups, and the files inside those groups Note: this does not add new files to existing groups, that is in add_new_files_to_groups!

# File fastlane/lib/fastlane/swift_runner_upgrader.rb, line 184
def add_missing_groups_and_files!(dry_run: false)
  missing_groups = self.find_missing_groups.to_set
  unless missing_groups.length > 0
    UI.verbose("No missing groups found, so we don't need to worry about adding new groups")
    return false
  end

  # well, we know we have some changes to make, so if this is a dry run,
  # don't bother doing anything and just return true
  return true if dry_run

  missing_groups.each do |missing_group_name|
    new_group = @root_group.new_group(missing_group_name)

    # find every file in the manifest that belongs to the new group, and add it to the new group
    self.manifest_hash.each do |filename, group|
      next unless group.casecmp(missing_group_name.downcase).zero?
      # assumes this is a new file, we don't handle moving files between groups
      new_file_reference = new_group.new_file("#{RELATIVE_SOURCE_FILE_PATH}#{filename}")

      # add references to the target, and make sure they are added to the build phase to
      self.fastlane_runner_target.source_build_phase.add_file_reference(new_file_reference)
    end
  end

  return true # yup, we definitely updated groups
end
add_new_files_to_groups!() click to toggle source
# File fastlane/lib/fastlane/swift_runner_upgrader.rb, line 136
def add_new_files_to_groups!
  inverted_hash = {}

  # need {group => [file1, file2, etc..]} instead of: {file1 => group, file2 => group, etc...}
  self.manifest_hash.each do |filename, group_name|
    group_name = group_name.downcase

    files_in_group = inverted_hash[group_name]
    if files_in_group.nil?
      files_in_group = []
      inverted_hash[group_name] = files_in_group
    end
    files_in_group << filename
  end

  # this helps us signal to the user that we made changes
  updated_project = false
  # iterate through the groups and collect all the swift files in each
  @root_group.groups.each do |group|
    # current group's filenames
    existing_group_files_set = group.files
                                    .select { |file| !file.name.nil? && file.name.end_with?(".swift") }
                                    .map(&:name)
                                    .to_set

    group_name = group.name.downcase
    manifest_group_filenames = inverted_hash[group_name]

    # compare the current group files to what the manifest says should minially be there
    manifest_group_filenames.each do |filename|
      # current group is missing a file from the manifest, need to add it
      next if existing_group_files_set.include?(filename)

      UI.verbose("Adding new file #{filename} to group: `#{group.name}`")
      new_file_reference = group.new_file("#{RELATIVE_SOURCE_FILE_PATH}#{filename}")

      # add references to the target, and make sure they are added to the build phase to
      self.fastlane_runner_target.source_build_phase.add_file_reference(new_file_reference)

      updated_project = true
    end
  end

  return updated_project
end
copy_file_if_needed!(filename: nil, dry_run: false) click to toggle source

currently just copies file, even if not needed.

# File fastlane/lib/fastlane/swift_runner_upgrader.rb, line 116
def copy_file_if_needed!(filename: nil, dry_run: false)
  needs_update = file_needs_update?(filename: filename)
  UI.verbose("file #{filename} needs an update") if needs_update

  # Ok, we know if this file needs an update, can return now if it's a dry run
  return needs_update if dry_run

  unless needs_update
    # no work needed, just return
    return false
  end

  source = File.join(self.source_swift_code_file_folder_path, "/#{filename}")
  target = File.join(self.target_swift_code_file_folder_path, "/#{filename}")

  FileUtils.cp(source, target)
  UI.verbose("Copied #{source} to #{target}")
  return true
end
file_needs_update?(filename: nil) click to toggle source

compares source file against the target file's FastlaneRunnerAPIVersion and returned `true` if there is a difference

# File fastlane/lib/fastlane/swift_runner_upgrader.rb, line 82
def file_needs_update?(filename: nil)
  # looking for something like: FastlaneRunnerAPIVersion [0.9.1]
  regex_to_use = API_VERSION_REGEX

  source = File.join(self.source_swift_code_file_folder_path, "/#{filename}")
  target = File.join(self.target_swift_code_file_folder_path, "/#{filename}")

  # target doesn't have the file yet, so ya, I'd say it needs to be updated
  return true unless File.exist?(target)

  source_file_content = File.read(source)
  target_file_content = File.read(target)

  # ignore if files don't contain FastlaneRunnerAPIVersion
  return false unless source_file_content.include?("FastlaneRunnerAPIVersion")
  return false unless target_file_content.include?("FastlaneRunnerAPIVersion")

  bundled_version = source_file_content.match(regex_to_use)[1]
  target_version = target_file_content.match(regex_to_use)[1]
  file_versions_are_different = bundled_version != target_version

  UI.verbose("#{filename} FastlaneRunnerAPIVersion (bundled/target): #{bundled_version}/#{target_version}")
  files_are_different = source_file_content != target_file_content

  if files_are_different && !file_versions_are_different
    UI.verbose("File versions are the same, but the two files are not equal, so that's a problem, setting needs update to 'true'")
  end

  needs_update = file_versions_are_different || files_are_different

  return needs_update
end
find_missing_groups() click to toggle source
# File fastlane/lib/fastlane/swift_runner_upgrader.rb, line 69
def find_missing_groups
  missing_groups = []

  existing_group_names_set = @root_group.groups.map { |group| group.name.downcase }.to_set
  self.manifest_groups.each do |group_name|
    unless existing_group_names_set.include?(group_name.downcase)
      missing_groups << group_name
    end
  end
  return missing_groups
end
upgrade_files!(dry_run: false) click to toggle source
# File fastlane/lib/fastlane/swift_runner_upgrader.rb, line 61
def upgrade_files!(dry_run: false)
  upgraded_anything = false
  self.manifest_hash.each do |filename, group|
    upgraded_anything = copy_file_if_needed!(filename: filename, dry_run: dry_run) || upgraded_anything
  end
  return upgraded_anything
end
upgrade_if_needed!(dry_run: false) click to toggle source
# File fastlane/lib/fastlane/swift_runner_upgrader.rb, line 47
def upgrade_if_needed!(dry_run: false)
  upgraded = add_missing_groups_and_files!(dry_run: dry_run)
  upgraded = upgrade_files!(dry_run: dry_run) || upgraded
  upgraded = add_new_files_to_groups! || upgraded

  UI.verbose("FastlaneRunner project has been updated and can be written back to disk") if upgraded
  unless dry_run
    UI.verbose("FastlaneRunner project changes have been stored") if upgraded
    target_project.save if upgraded
  end

  return upgraded
end