Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[match] increase match speed with caching
- Loading branch information
Showing
22 changed files
with
1,184 additions
and
349 deletions.
There are no files selected for viewing
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
require 'fastlane_core/provisioning_profile' | ||
require 'spaceship/client' | ||
require_relative 'portal_fetcher' | ||
module Match | ||
class Portal | ||
class Cache | ||
def self.build(params:, bundle_id_identifiers:) | ||
require_relative 'profile_includes' | ||
require 'sigh' | ||
|
||
profile_type = Sigh.profile_type_for_distribution_type( | ||
platform: params[:platform], | ||
distribution_type: params[:type] | ||
) | ||
|
||
cache = Portal::Cache.new( | ||
platform: params[:platform], | ||
profile_type: profile_type, | ||
additional_cert_types: params[:additional_cert_types], | ||
bundle_id_identifiers: bundle_id_identifiers, | ||
needs_profiles_devices: ProfileIncludes.can_force_include?(params: params, notify: true) && !params[:force] && !params[:readonly], | ||
needs_profiles_certificate_content: !ProfileIncludes.can_force_include_all_certificates?(params: params), | ||
include_mac_in_profiles: params[:include_mac_in_profiles] | ||
) | ||
|
||
return cache | ||
end | ||
|
||
attr_reader :platform, :profile_type, :bundle_id_identifiers, :additional_cert_types, :needs_profiles_devices, :needs_profiles_certificate_content, :include_mac_in_profiles | ||
|
||
def initialize(platform:, profile_type:, additional_cert_types:, bundle_id_identifiers:, needs_profiles_devices:, needs_profiles_certificate_content:, include_mac_in_profiles:) | ||
@platform = platform | ||
@profile_type = profile_type | ||
|
||
# Bundle Ids | ||
@bundle_id_identifiers = bundle_id_identifiers | ||
|
||
# Certs | ||
@additional_cert_types = additional_cert_types | ||
|
||
# Profiles | ||
@needs_profiles_devices = needs_profiles_devices | ||
@needs_profiles_certificate_content = needs_profiles_certificate_content | ||
|
||
# Devices | ||
@include_mac_in_profiles = include_mac_in_profiles | ||
end | ||
|
||
def portal_profile(stored_profile_path:, keychain_path:) | ||
parsed = FastlaneCore::ProvisioningProfile.parse(stored_profile_path, keychain_path) | ||
uuid = parsed["UUID"] | ||
|
||
portal_profile = self.profiles.detect { |i| i.uuid == uuid } | ||
|
||
portal_profile | ||
end | ||
|
||
def reset_certificates | ||
@certificates = nil | ||
end | ||
|
||
def forget_portal_profile(portal_profile) | ||
return unless @profiles && portal_profile | ||
|
||
@profiles -= [portal_profile] | ||
end | ||
|
||
def bundle_ids | ||
return @bundle_ids.dup if @bundle_ids | ||
|
||
@bundle_ids = Match::Portal::Fetcher.bundle_ids( | ||
bundle_id_identifiers: @bundle_id_identifiers | ||
) | ||
|
||
return @bundle_ids.dup | ||
end | ||
|
||
def certificates | ||
return @certificates.dup if @certificates | ||
|
||
@certificates = Match::Portal::Fetcher.certificates( | ||
platform: @platform, | ||
profile_type: @profile_type, | ||
additional_cert_types: @additional_cert_types | ||
) | ||
|
||
return @certificates.dup | ||
end | ||
|
||
def profiles | ||
return @profiles.dup if @profiles | ||
|
||
@profiles = Match::Portal::Fetcher.profiles( | ||
profile_type: @profile_type, | ||
needs_profiles_devices: @needs_profiles_devices, | ||
needs_profiles_certificate_content: @needs_profiles_certificate_content | ||
) | ||
|
||
return @profiles.dup | ||
end | ||
|
||
def devices | ||
return @devices.dup if @devices | ||
|
||
@devices = Match::Portal::Fetcher.devices( | ||
platform: @platform, | ||
include_mac_in_profiles: @include_mac_in_profiles | ||
) | ||
|
||
return @devices.dup | ||
end | ||
end | ||
end | ||
end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
require 'fastlane_core/provisioning_profile' | ||
require 'spaceship/client' | ||
require 'spaceship/connect_api/models/profile' | ||
|
||
module Match | ||
class Portal | ||
module Fetcher | ||
def self.profiles(profile_type:, needs_profiles_devices: false, needs_profiles_certificate_content: false, name: nil) | ||
includes = ['bundleId'] | ||
|
||
if needs_profiles_devices | ||
includes += ['devices', 'certificates'] | ||
end | ||
|
||
if needs_profiles_certificate_content | ||
includes += ['certificates'] | ||
end | ||
|
||
profiles = Spaceship::ConnectAPI::Profile.all( | ||
filter: { profileType: profile_type, name: name }.compact, | ||
includes: includes.uniq.join(',') | ||
) | ||
|
||
profiles | ||
end | ||
|
||
def self.certificates(platform:, profile_type:, additional_cert_types:) | ||
require 'sigh' | ||
certificate_types = Sigh.certificate_types_for_profile_and_platform(platform: platform, profile_type: profile_type) | ||
|
||
additional_cert_types ||= [] | ||
additional_cert_types.map! do |cert_type| | ||
case Match.cert_type_sym(cert_type) | ||
when :mac_installer_distribution | ||
Spaceship::ConnectAPI::Certificate::CertificateType::MAC_INSTALLER_DISTRIBUTION | ||
when :developer_id_installer | ||
Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_INSTALLER | ||
end | ||
end | ||
|
||
certificate_types += additional_cert_types | ||
|
||
filter = { certificateType: certificate_types.sort.join(',') } unless certificate_types.empty? | ||
|
||
certificates = Spaceship::ConnectAPI::Certificate.all( | ||
filter: filter | ||
).select(&:valid?) | ||
|
||
certificates | ||
end | ||
|
||
def self.devices(platform: nil, include_mac_in_profiles: false) | ||
devices = Spaceship::ConnectAPI::Device.devices_for_platform( | ||
platform: platform, | ||
include_mac_in_profiles: include_mac_in_profiles | ||
) | ||
|
||
devices | ||
end | ||
|
||
def self.bundle_ids(bundle_id_identifiers: nil) | ||
filter = nil | ||
if bundle_id_identifiers | ||
if bundle_id_identifiers.kind_of?(Array) | ||
filter = { identifier: bundle_id_identifiers.join(',') } | ||
else | ||
filter = { identifier: bundle_id_identifiers } | ||
end | ||
end | ||
|
||
bundle_ids = Spaceship::ConnectAPI::BundleId.all( | ||
filter: filter | ||
) | ||
|
||
bundle_ids | ||
end | ||
end | ||
end | ||
end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
require_relative 'portal_fetcher' | ||
require_relative 'module' | ||
|
||
module Match | ||
class ProfileIncludes | ||
PROV_TYPES_WITH_DEVICES = [:adhoc, :development] | ||
PROV_TYPES_WITH_MULTIPLE_CERTIFICATES = [:development] | ||
|
||
def self.can_force_include?(params:, notify:) | ||
self.can_force_include_all_devices?(params: params, notify: notify) && | ||
self.can_force_include_all_certificates?(params: params, notify: notify) | ||
end | ||
|
||
############### | ||
# | ||
# DEVICES | ||
# | ||
############### | ||
|
||
def self.should_force_include_all_devices?(params:, portal_profile:, cached_devices:) | ||
return false unless self.can_force_include_all_devices?(params: params) | ||
|
||
force = device_count_different?(portal_profile: portal_profile, platform: params[:platform], include_mac_in_profiles: params[:include_mac_in_profiles], cached_devices: cached_devices) | ||
|
||
return force | ||
end | ||
|
||
def self.can_force_include_all_devices?(params:, notify: false) | ||
return false if params[:readonly] || params[:force] | ||
return false unless params[:force_for_new_devices] | ||
|
||
provisioning_type = params[:type].to_sym | ||
|
||
can_force = PROV_TYPES_WITH_DEVICES.include?(provisioning_type) | ||
|
||
if !can_force && notify | ||
# App Store provisioning profiles don't contain device identifiers and | ||
# thus shouldn't be renewed if the device count has changed. | ||
UI.important("Warning: `force_for_new_devices` is set but is ignored for #{provisioning_type}.") | ||
UI.important("You can safely stop specifying `force_for_new_devices` when running Match for type '#{provisioning_type}'.") | ||
end | ||
|
||
can_force | ||
end | ||
|
||
def self.device_count_different?(portal_profile:, platform:, include_mac_in_profiles:, cached_devices:) | ||
return false unless portal_profile | ||
|
||
profile_device_count = portal_profile.devices.count | ||
|
||
devices = cached_devices | ||
devices ||= Match::Portal::Fetcher.devices(platform: platform, include_mac_in_profiles: include_mac_in_profiles) | ||
portal_device_count = devices.size | ||
|
||
device_count_different = portal_device_count != profile_device_count | ||
|
||
UI.important("Devices count differs. Portal count: #{portal_device_count}. Profile count: #{profile_device_count}") if device_count_different | ||
|
||
return device_count_different | ||
end | ||
|
||
############### | ||
# | ||
# CERTIFICATES | ||
# | ||
############### | ||
|
||
def self.should_force_include_all_certificates?(params:, portal_profile:, cached_certificates:) | ||
return false unless self.can_force_include_all_certificates?(params: params) | ||
|
||
force = certificate_count_different?(portal_profile: portal_profile, platform: params[:platform], cached_certificates: cached_certificates) | ||
|
||
return force | ||
end | ||
|
||
def self.can_force_include_all_certificates?(params:, notify: false) | ||
return false if params[:readonly] || params[:force] | ||
return false unless params[:force_for_new_certificates] | ||
|
||
unless params[:include_all_certificates] | ||
UI.important("You specified 'force_for_new_certificates: true', but new certificates will not be added, cause 'include_all_certificates' is 'false'") if notify | ||
return false | ||
end | ||
|
||
provisioning_type = params[:type].to_sym | ||
|
||
can_force = PROV_TYPES_WITH_MULTIPLE_CERTIFICATES.include?(provisioning_type) | ||
|
||
if !can_force && notify | ||
# All other (not development) provisioning profiles don't contain | ||
# multiple certificates, thus shouldn't be renewed | ||
# if the certificates count has changed. | ||
UI.important("Warning: `force_for_new_certificates` is set but is ignored for non-'development' provisioning profiles.") | ||
UI.important("You can safely stop specifying `force_for_new_certificates` when running Match for '#{provisioning_type}' provisioning profiles.") | ||
end | ||
|
||
can_force | ||
end | ||
|
||
def self.certificate_count_different?(portal_profile:, platform:, cached_certificates:) | ||
return false unless portal_profile | ||
|
||
# When a certificate expires (not revoked) provisioning profile stays valid. | ||
# And if we regenerate certificate count will not differ: | ||
# * For portal certificates, we filter out the expired one but includes a new certificate; | ||
# * Profile still contains an expired certificate and is valid. | ||
# Thus, we need to check the validity of profile certificates too. | ||
profile_certs_count = portal_profile.certificates.select(&:valid?).count | ||
|
||
certificates = cached_certificates | ||
certificates ||= Match::Portal::Fetcher.certificates(platform: platform, profile_type: portal_profile.profile_type) | ||
portal_certs_count = certificates.size | ||
|
||
certificate_count_different = portal_certs_count != profile_certs_count | ||
|
||
UI.important("Certificate count differs. Portal count: #{portal_certs_count}. Profile count: #{profile_certs_count}") if certificate_count_different | ||
|
||
return certificate_count_different | ||
end | ||
end | ||
end |
Oops, something went wrong.