Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ DERIVED_DATA_DIR = File.join('.build').freeze
RELEASES_ROOT_DIR = File.join('releases').freeze

EXECUTABLE_NAME = 'XCRemoteCache'
EXECUTABLE_NAMES = ['xclibtool', 'xcpostbuild', 'xcprebuild', 'xcprepare', 'xcswiftc', 'xcld', 'xcldplusplus', 'xclipo']
EXECUTABLE_NAMES = ['xclibtool', 'xcpostbuild', 'xcprebuild', 'xcprepare', 'xcswiftc', 'swiftc', 'xcswift-frontend', 'swift-frontend', 'xcld', 'xcldplusplus', 'xclipo']
PROJECT_NAME = 'XCRemoteCache'

SWIFTLINT_ENABLED = true
Expand Down Expand Up @@ -59,6 +59,10 @@ task :build, [:configuration, :arch, :sdks, :is_archive] do |task, args|

# Path of the executable looks like: `.build/(debug|release)/XCRemoteCache`
build_path_base = File.join(DERIVED_DATA_DIR, args.configuration)
# swift-frontent integration requires that the SWIFT_EXEC is `swiftc` so create
# a symbolic link between swiftc->xcswiftc and swift-frontend->xcswift-frontend
system("cd #{build_path_base} && ln -s xcswiftc swiftc")
system("cd #{build_path_base} && ln -s xcswift-frontend swift-frontend")
sdk_build_paths = EXECUTABLE_NAMES.map {|e| File.join(build_path_base, e)}

build_paths.push(sdk_build_paths)
Expand Down Expand Up @@ -130,7 +134,9 @@ def create_release_zip(build_paths)
# Create and move files into the release directory
mkdir_p release_dir
build_paths.each {|p|
cp_r p, release_dir
# -r for recursive
# -P for copying symbolic link as is
system("cp -rP #{p} #{release_dir}")
}

output_artifact_basename = "#{PROJECT_NAME}.zip"
Expand All @@ -139,7 +145,8 @@ def create_release_zip(build_paths)
# -X: no extras (uid, gid, file times, ...)
# -x: exclude .DS_Store
# -r: recursive
system("zip -X -x '*.DS_Store' -r #{output_artifact_basename} .") or abort "zip failure"
# -y: to store symbolic links (used for swiftc -> xcswiftc)
system("zip -X -x '*.DS_Store' -r -y #{output_artifact_basename} .") or abort "zip failure"
# List contents of zip file
system("unzip -l #{output_artifact_basename}") or abort "unzip failure"
end
Expand Down
15 changes: 9 additions & 6 deletions cocoapods-plugin/lib/cocoapods-xcremotecache/command/hooks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ def self.enable_xcremotecache(
exclude_build_configurations,
final_target,
fake_src_root,
exclude_sdks_configurations
exclude_sdks_configurations,
enable_swift_driver_integration
)
srcroot_relative_xc_location = parent_dir(xc_location, repo_distance)
# location of the entrite CocoaPods project, relative to SRCROOT
Expand All @@ -137,14 +138,15 @@ def self.enable_xcremotecache(
elsif mode == 'producer' || mode == 'producer-fast'
config.build_settings.delete('CC') if config.build_settings.key?('CC')
end
reset_build_setting(config.build_settings, 'SWIFT_EXEC', "$SRCROOT/#{srcroot_relative_xc_location}/xcswiftc", exclude_sdks_configurations)
swiftc_name = enable_swift_driver_integration ? 'swiftc' : 'xcswiftc'
reset_build_setting(config.build_settings, 'SWIFT_EXEC', "$SRCROOT/#{srcroot_relative_xc_location}/#{swiftc_name}", exclude_sdks_configurations)
reset_build_setting(config.build_settings, 'LIBTOOL', "$SRCROOT/#{srcroot_relative_xc_location}/xclibtool", exclude_sdks_configurations)
# Setting LIBTOOL to '' breaks SwiftDriver intengration so resetting it to the original value 'libtool' for all excluded configurations
add_build_setting_for_sdks(config.build_settings, 'LIBTOOL', 'libtool', exclude_sdks_configurations)
reset_build_setting(config.build_settings, 'LD', "$SRCROOT/#{srcroot_relative_xc_location}/xcld", exclude_sdks_configurations)
reset_build_setting(config.build_settings, 'LDPLUSPLUS', "$SRCROOT/#{srcroot_relative_xc_location}/xcldplusplus", exclude_sdks_configurations)
reset_build_setting(config.build_settings, 'LIPO', "$SRCROOT/#{srcroot_relative_xc_location}/xclipo", exclude_sdks_configurations)
reset_build_setting(config.build_settings, 'SWIFT_USE_INTEGRATED_DRIVER', 'NO', exclude_sdks_configurations)
reset_build_setting(config.build_settings, 'SWIFT_USE_INTEGRATED_DRIVER', 'NO', exclude_sdks_configurations) unless enable_swift_driver_integration

reset_build_setting(config.build_settings, 'XCREMOTE_CACHE_FAKE_SRCROOT', fake_src_root, exclude_sdks_configurations)
reset_build_setting(config.build_settings, 'XCRC_PLATFORM_PREFERRED_ARCH', "$(LINK_FILE_LIST_$(CURRENT_VARIANT)_$(PLATFORM_PREFERRED_ARCH):dir:standardizepath:file:default=arm64)", exclude_sdks_configurations)
Expand Down Expand Up @@ -498,6 +500,7 @@ def self.save_lldbinit_rewrite(user_proj_directory,fake_src_root)
check_platform = @@configuration['check_platform']
fake_src_root = @@configuration['fake_src_root']
exclude_sdks_configurations = @@configuration['exclude_sdks_configurations'] || []
enable_swift_driver_integration = @@configuration['enable_swift_driver_integration'] || false

xccc_location_absolute = "#{user_proj_directory}/#{xccc_location}"
xcrc_location_absolute = "#{user_proj_directory}/#{xcrc_location}"
Expand All @@ -521,7 +524,7 @@ def self.save_lldbinit_rewrite(user_proj_directory,fake_src_root)
next if target.name.start_with?("Pods-")
next if target.name.end_with?("Tests")
next if exclude_targets.include?(target.name)
enable_xcremotecache(target, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations)
enable_xcremotecache(target, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations, enable_swift_driver_integration)
end

# Create .rcinfo into `Pods` directory as that .xcodeproj reads configuration from .xcodeproj location
Expand All @@ -534,7 +537,7 @@ def self.save_lldbinit_rewrite(user_proj_directory,fake_src_root)
next if target.source_build_phase.files_references.empty?
next if target.name.end_with?("Tests")
next if exclude_targets.include?(target.name)
enable_xcremotecache(target, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations)
enable_xcremotecache(target, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations, enable_swift_driver_integration)
end
generated_project.save()
end
Expand Down Expand Up @@ -575,7 +578,7 @@ def self.save_lldbinit_rewrite(user_proj_directory,fake_src_root)
# Attach XCRC to the app targets
user_project.targets.each do |target|
next if exclude_targets.include?(target.name)
enable_xcremotecache(target, 0, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations)
enable_xcremotecache(target, 0, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations, enable_swift_driver_integration)
end

# Set Target sourcemap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
# limitations under the License.

module CocoapodsXcremotecache
VERSION = "0.0.16"
VERSION = "0.0.17"
end
84 changes: 58 additions & 26 deletions tasks/e2e.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'json'
require "ostruct"
require 'yaml'

desc 'Support for E2E tests: building XCRemoteCache-enabled xcodeproj using xcodebuild'
namespace :e2e do
Expand All @@ -25,12 +26,21 @@
'primary_branch' => GIT_BRANCH,
'mode' => 'consumer',
'final_target' => 'XCRemoteCacheSample',
'artifact_maximum_age' => 0
'artifact_maximum_age' => 0,

}.freeze
# A list of configurations to merge with SHARED_COCOAPODS_CONFIG to run tests with
CONFIGS = {
'no_swift_driver' => {},
'swift_driver' => {
'enable_swift_driver_integration' => true
}
}.freeze
DEFAULT_EXPECTATIONS = {
'misses' => 0,
'hit_rate' => 100
}.freeze
EXCLUDED_ARCHS = 'x86_64'

Stats = Struct.new(:hits, :misses, :hit_rate)

Expand All @@ -43,9 +53,14 @@
start_nginx
configure_git

# Run scenarios for all Podfile scenarios
for podfile_path in Dir.glob('e2eTests/**/*.Podfile')
run_cocoapods_scenario(podfile_path)
for config_name, custom_config in CONFIGS
config = SHARED_COCOAPODS_CONFIG.merge(custom_config)
puts "Running E2E tests for config: #{config_name}"

# Run scenarios for all Podfile scenarios
for podfile_path in Dir.glob('e2eTests/**/*.Podfile')
run_cocoapods_scenario(config, podfile_path)
end
end
# Revert all side effects
clean
Expand All @@ -56,13 +71,27 @@
clean_server
start_nginx
configure_git
CONFIGS.each do |config_name, config|
puts "Running Standalone tests for config: #{config_name}"
run_standalone_scenario(config, config_name)
end
end

def self.run_standalone_scenario(config, config_name)
# Prepare binaries for the standalone mode
prepare_for_standalone(E2E_STANDALONE_SAMPLE_DIR)

puts 'Building standalone producer...'
####### Producer #########
clean_git

Dir.chdir(E2E_STANDALONE_SAMPLE_DIR) do
clean_git
system 'git checkout -f .'
# Include the config in the "shared" configuration that is commited-in to '.rcinfo'
rcinfo_path = '.rcinfo'
rcinfo = YAML.load(File.read(rcinfo_path)).merge(config)
File.open(rcinfo_path, 'w') {|f| f.write rcinfo.to_yaml }

# Run integrate the project
system("pwd")
system("#{XCRC_BINARIES}/xcprepare integrate --input StandaloneApp.xcodeproj --mode producer --final-producer-target StandaloneApp --configurations-exclude #{CONFIGURATIONS_EXCLUDE}")
Expand All @@ -76,22 +105,25 @@

####### Consumer #########
# new dir to emulate different srcroot
consumer_srcroot = "#{E2E_STANDALONE_SAMPLE_DIR}_consumer"
consumer_srcroot = "#{E2E_STANDALONE_SAMPLE_DIR}_consumer_#{config_name}"
system("mv #{E2E_STANDALONE_SAMPLE_DIR} #{consumer_srcroot}")
at_exit { puts("reverting #{E2E_STANDALONE_SAMPLE_DIR}"); system("mv #{consumer_srcroot} #{E2E_STANDALONE_SAMPLE_DIR}") }

prepare_for_standalone(consumer_srcroot)
Dir.chdir(consumer_srcroot) do
system("#{XCRC_BINARIES}/xcprepare integrate --input StandaloneApp.xcodeproj --mode consumer --final-producer-target StandaloneApp --consumer-eligible-configurations #{CONFIGURATION} --configurations-exclude #{CONFIGURATIONS_EXCLUDE}")
build_project(nil, "StandaloneApp.xcodeproj", 'WatchExtension', 'watch', 'watchOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer"})
build_project(nil, "StandaloneApp.xcodeproj", 'StandaloneApp', 'iphone', 'iOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer"})
valide_hit_rate(OpenStruct.new(DEFAULT_EXPECTATIONS))

puts 'Building standalone consumer with local change...'
# Extra: validate local compilation of the Standalone ObjC code
system("echo '' >> StandaloneApp/StandaloneObjc.m")
build_project(nil, "StandaloneApp.xcodeproj", 'WatchExtension', 'watch', 'watchOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_local"})
build_project(nil, "StandaloneApp.xcodeproj", 'StandaloneApp', 'iphone', 'iOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_local"})
begin
prepare_for_standalone(consumer_srcroot)
Dir.chdir(consumer_srcroot) do
system("#{XCRC_BINARIES}/xcprepare integrate --input StandaloneApp.xcodeproj --mode consumer --final-producer-target StandaloneApp --consumer-eligible-configurations #{CONFIGURATION} --configurations-exclude #{CONFIGURATIONS_EXCLUDE}")
build_project(nil, "StandaloneApp.xcodeproj", 'WatchExtension', 'watch', 'watchOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_#{config_name}"})
build_project(nil, "StandaloneApp.xcodeproj", 'StandaloneApp', 'iphone', 'iOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_#{config_name}"})
valide_hit_rate(OpenStruct.new(DEFAULT_EXPECTATIONS))

puts 'Building standalone consumer with local change...'
# Extra: validate local compilation of the Standalone ObjC code
system("echo '' >> StandaloneApp/StandaloneObjc.m")
build_project(nil, "StandaloneApp.xcodeproj", 'WatchExtension', 'watch', 'watchOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_local_#{config_name}"})
build_project(nil, "StandaloneApp.xcodeproj", 'StandaloneApp', 'iphone', 'iOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_local_#{config_name}"})
end
ensure
puts("reverting #{E2E_STANDALONE_SAMPLE_DIR}")
system("mv #{consumer_srcroot} #{E2E_STANDALONE_SAMPLE_DIR}")
end

# Revert all side effects
Expand Down Expand Up @@ -153,9 +185,9 @@ def self.clean
end

# xcremotecache configuration to add to Podfile
def self.cocoapods_configuration_string(extra_configs = {})
def self.cocoapods_configuration_string(config, extra_configs = {})
configuration_lines = ['xcremotecache({']
all_properties = SHARED_COCOAPODS_CONFIG.merge(extra_configs)
all_properties = config.merge(extra_configs)
config_lines = all_properties.map {|key, value| " \"#{key}\" => #{value.inspect},"}
configuration_lines.push(*config_lines)
configuration_lines << '})'
Expand All @@ -182,7 +214,7 @@ def self.build_project(workspace, project, scheme, sdk = 'iphone', platform = 'i
'derivedDataPath' => DERIVED_DATA_PATH,
}.merge(extra_args).compact
xcodebuild_vars = {
'EXCLUDED_ARCHS' => 'arm64'
'EXCLUDED_ARCHS' => EXCLUDED_ARCHS
}
args = ['set -o pipefail;', 'xcodebuild']
args.push(*xcodebuild_args.map {|k,v| "-#{k} '#{v}'"})
Expand Down Expand Up @@ -227,12 +259,12 @@ def self.valide_hit_rate(expectations)
puts("Hit rate: #{status.hit_rate}% (#{status.hits}/#{all_targets})")
end

def self.run_cocoapods_scenario(template_path)
def self.run_cocoapods_scenario(config, template_path)
# Optional file, which adds extra cocoapods configs to a template
template_config_path = "#{template_path}.config"
extra_config = File.exist?(template_config_path) ? JSON.load(File.read(template_config_path)) : {}
producer_configuration = cocoapods_configuration_string({'mode' => 'producer'}.merge(extra_config))
consumer_configuration = cocoapods_configuration_string(extra_config)
producer_configuration = cocoapods_configuration_string(config, {'mode' => 'producer'}.merge(extra_config))
consumer_configuration = cocoapods_configuration_string(config, extra_config)
expectations = build_expectations(template_path)

puts("****** Scenario: #{template_path}")
Expand Down