Class: Fastlane::SwiftRunnerUpgrader

Inherits:
Object
  • Object
show all
Defined in:
fastlane/lib/fastlane/swift_runner_upgrader.rb

Overview

build project

Constant Summary collapse

API_VERSION_REGEX =

also used by SwiftFastlaneAPIGenerator

/FastlaneRunnerAPIVersion\s*\[\s*([0-9]+.[0-9]+.[0-9]+)\s*\]/
RELATIVE_SOURCE_FILE_PATH =
"../"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSwiftRunnerUpgrader

Returns a new instance of SwiftRunnerUpgrader.


28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 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

  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

Instance Attribute Details

#fastlane_runner_targetObject

FastlaneRunner xcodeproj target


20
21
22
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 20

def fastlane_runner_target
  @fastlane_runner_target
end

#manifest_groupsObject

unique list of group names that came from the manifest


22
23
24
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 22

def manifest_groups
  @manifest_groups
end

#manifest_hashObject

hash of file names to group names they belong to


21
22
23
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 21

def manifest_hash
  @manifest_hash
end

#source_swift_code_file_folder_pathObject

source location of where we're copying file from during the upgrade process


24
25
26
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 24

def source_swift_code_file_folder_path
  @source_swift_code_file_folder_path
end

#target_projectObject

project we'll be updating


19
20
21
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 19

def target_project
  @target_project
end

#target_swift_code_file_folder_pathObject

location in filesystem where all swift files should exist when we're done


23
24
25
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 23

def target_swift_code_file_folder_path
  @target_swift_code_file_folder_path
end

Instance Method Details

#add_missing_groups_and_files!(dry_run: false) ⇒ Object

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!


178
179
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
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 178

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!Object


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 130

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) ⇒ Object

currently just copies file, even if not needed.


110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 110

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) ⇒ Boolean

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

Returns:


80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 80

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)

  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_groupsObject


67
68
69
70
71
72
73
74
75
76
77
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 67

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) ⇒ Object


59
60
61
62
63
64
65
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 59

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) ⇒ Object


45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'fastlane/lib/fastlane/swift_runner_upgrader.rb', line 45

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