Class: Fastlane::Actions::PrepareBuildResourcesAction

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

Class Method Summary collapse

Class Method Details

.authorsObject



180
181
182
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 180

def self.authors
  ["Jakob Jensen"]
end

.available_optionsObject



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/prepare_build_resources/actions/prepare_build_resources_action.rb', line 184

def self.available_options
  [
    FastlaneCore::ConfigItem.new(key: :build,
                            env_name: "PREPARE_BUILD_RESOURCES_BUILD",
                         description: "A block with the actual building that should be performed",
                            optional: false,
                                type: Proc),
    FastlaneCore::ConfigItem.new(key: :keychain_path,
                            env_name: "PREPARE_BUILD_RESOURCES_KEYCHAIN_PATH",
                         description: "Path to the keychain that need to be available while building",
                            optional: false,
                                type: String),
    FastlaneCore::ConfigItem.new(key: :keychain_password,
                            env_name: "PREPARE_BUILD_RESOURCES_KEYCHAIN_PASSWORD",
                         description: "Password to the supplied keychain",
                            optional: false,
                                type: String),
    FastlaneCore::ConfigItem.new(key: :provisioning_profile_paths,
                            env_name: "PREPARE_BUILD_RESOURCES_YOUR_PROVISIONING_PROFILE_PATHS",
                         description: "Paths to the provisioning profiles that need to be available while building",
                            optional: false,
                                type: Array),
    FastlaneCore::ConfigItem.new(key: :verbose,
                            env_name: "PREPARE_BUILD_RESOURCES_YOUR_VERBOSE",
                         description: "Print verbose information about what the plugin is doing, *NOTE* that this will print your keychain password as well",
                       default_value: false,
                            optional: true,
                                type: TrueClass),
    FastlaneCore::ConfigItem.new(key: :dry_run,
                            env_name: "PREPARE_BUILD_RESOURCES_YOUR_DRY_RUN",
                         description: "Do not perform changes, but instead print what would have happened",
                       default_value: false,
                            optional: true,
                                type: TrueClass)
  ]
end

.cleanup_files(safe_keychain_path, safe_profile_paths) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 70

def self.cleanup_files(safe_keychain_path, safe_profile_paths)
  begin
    safe_profile_paths.each do |file, _|
      self.rm(file)
    end
  rescue
  end

  begin
    self.rm(safe_keychain_path)
  rescue
  end
end

.cp(src, dest) ⇒ Object



162
163
164
165
166
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 162

def self.cp(src, dest)
  @debug_messages.push("$ cp #{src} -> #{dest}")
  UI.message @debug_messages.last if @verbose
  FileUtils.cp(src, dest) unless @dry_run
end

.descriptionObject

Fastlane methods:



176
177
178
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 176

def self.description
  "Prepares certificates and provisioning profiles for building and removes them afterwards."
end

.execute(command, error_callback = nil) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 150

def self.execute(command, error_callback = nil)
  @debug_messages.push("$ #{command}")
  output = ""
  if @dry_run
    UI.message @debug_messages.last if @verbose
  else
    output = Fastlane::Actions.sh(command, log: @verbose, error_callback: error_callback)
  end

  output
end

.is_supported?(platform) ⇒ Boolean

Returns:

  • (Boolean)


221
222
223
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 221

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

.known_keychainsObject



131
132
133
134
135
136
137
138
139
140
141
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 131

def self.known_keychains
  keychains = []
  output = Fastlane::Actions.sh("security list-keychains", log: false).split(/\n/)
  output.each do |k|
    next if k.include?("/System.keychain")
    trimmed_keychain = k.strip
    keychains.push(trimmed_keychain[1..-2])
  end

  keychains
end

.prepare_keychains(known_keychains, safe_keychain_path) ⇒ Object



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

def self.prepare_keychains(known_keychains, safe_keychain_path)
  prepared_keychains = known_keychains.dup
  prepared_keychains.unshift(safe_keychain_path)

  prepared_keychains
end

.random_name(length) ⇒ Object



110
111
112
113
114
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 110

def self.random_name(length)
  random_name = rand(36**length).to_s(36)

  random_name
end

.reset_keychain(known_keychains, safe_keychain_path, safe_profile_paths) ⇒ Object



63
64
65
66
67
68
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 63

def self.reset_keychain(known_keychains, safe_keychain_path, safe_profile_paths)
  self.execute(
    "security list-keychains -s #{known_keychains.shelljoin}",
    proc { |_| self.cleanup_files(safe_keychain_path, safe_profile_paths) }
  )
end

.rm(file) ⇒ Object



168
169
170
171
172
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 168

def self.rm(file)
  @debug_messages.push("$ rm #{file}")
  UI.message @debug_messages.last if @verbose
  File.delete(file) unless @dry_run || !File.exist?(file)
end

.run(params) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 4

def self.run(params)
  @debug_messages = []
  @dry_run = params[:dry_run]
  @verbose = params[:verbose] || @dry_run

  keychain_path = self.validate_keychain(params)
  profile_paths = self.validate_profiles(params)

  safe_keychain_path = self.safe_keychain_path(keychain_path)
  safe_profile_paths = self.safe_profile_paths(profile_paths)

  known_keychains = self.known_keychains
  prepared_keychains = self.prepare_keychains(known_keychains, safe_keychain_path)

  safe_profile_paths.each do |dest, src|
    self.cp(src, dest)
  end

  self.cp(keychain_path, safe_keychain_path)

  self.execute(
    "security list-keychains -s #{prepared_keychains.shelljoin}",
    proc { |_| self.safe_cleanup_resource(safe_keychain_path, safe_profile_paths, known_keychains) }
  )

  self.execute(
    "security unlock-keychain -p #{params[:keychain_password].shellescape} #{safe_keychain_path.shellescape}",
    proc { |_| self.safe_cleanup_resource(safe_keychain_path, safe_profile_paths, known_keychains) }
  )

  begin
    Dir.chdir('fastlane') do
      params[:build].call(safe_keychain_path, safe_profile_paths) unless @dry_run
    end
  rescue
    raise
  ensure
    self.safe_cleanup_resource(safe_keychain_path, safe_profile_paths, known_keychains)
  end

  return @debug_messages.join("\n") if Helper.is_test?
end

.safe_cleanup_resource(safe_keychain_path, safe_profile_paths, known_keychains) ⇒ Object

internal methods:



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 49

def self.safe_cleanup_resource(safe_keychain_path, safe_profile_paths, known_keychains)
  self.execute(
    "security lock-keychain #{safe_keychain_path.shellescape}",
    lambda do |_|
      self.reset_keychain(known_keychains, safe_keychain_path, safe_profile_paths)
      self.cleanup_files(safe_keychain_path, safe_profile_paths)
    end
  )

  self.reset_keychain(known_keychains, safe_keychain_path, safe_profile_paths)

  self.cleanup_files(safe_keychain_path, safe_profile_paths)
end

.safe_keychain_path(keychain_path) ⇒ Object



103
104
105
106
107
108
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 103

def self.safe_keychain_path(keychain_path)
  random_name = self.random_name(16)
  safe_keychain_path = File.join(File.dirname(keychain_path), "#{random_name}.keychain")

  safe_keychain_path
end

.safe_profile_paths(profile_paths) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 116

def self.safe_profile_paths(profile_paths)
  safe_profiles = {}
  profile_paths.each do |path|
    safe_path = nil
    loop do
      random_name = self.random_name(32)
      safe_path = File.expand_path(File.join("~/Library/MobileDevice/Provisioning Profiles/", "prepare-build-resources-#{random_name}.mobileprovision"))
      break unless safe_profiles.key?(safe_path)
    end
    safe_profiles[safe_path] = path
  end

  safe_profiles
end

.validate_keychain(params) ⇒ Object



84
85
86
87
88
89
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 84

def self.validate_keychain(params)
  keychain_path = File.expand_path params[:keychain_path]
  UI.user_error! "Keychain '#{params[:keychain_path]}' was not found." unless File.exist?(keychain_path)

  keychain_path
end

.validate_profiles(params) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
# File 'lib/fastlane/plugin/prepare_build_resources/actions/prepare_build_resources_action.rb', line 91

def self.validate_profiles(params)
  UI.user_error! "No provisioning profiles were provided." unless params[:provisioning_profile_paths].length > 0
  profiles = []
  params[:provisioning_profile_paths].each do |p|
    path = File.expand_path p
    UI.user_error! "Provisioning profile '#{p}' was not found." unless File.exist?(path)
    profiles.push(path)
  end

  profiles
end