Rome
Rome copied to clipboard
[Enhancement] Build only missing frameworks (= new pods)
Hello
Some pods take a really long time to build (Realm for exemple) , or some Podfile may refer to dozen of pods. Adding a new pod in the Podfile currently means rebuilding every pods.
A cool enhancement would be to build only frameworks that are missing in /Rome folder. or if a new version is available & has been downloaded with Cocoapods
:)
Hello
I didn't create a pull request because this is the first time I write in ruby so the code might be ( / may be / is ) ugly :stuck_out_tongue_winking_eye:
It only build new pods (those without corresponding .framework in /Rome folder).
If a new version of a pod is downloaded, it won't be built unless the framework has been previously manually deleted.
post_install.rb
require 'fourflusher'
CONFIGURATION = "Release"
PLATFORMS = { 'iphonesimulator' => 'iOS',
'appletvsimulator' => 'tvOS',
'watchsimulator' => 'watchOS' }
def build_for_iosish_platform(sandbox, build_dir, destination, target, device, simulator)
deployment_target = target.platform_deployment_target
target_label = target.cocoapods_target_label
spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
spec_names.each do |root_name, module_name|
executable_path = "#{build_dir}/#{root_name}"
device_lib = "#{build_dir}/#{CONFIGURATION}-#{device}/#{root_name}/#{module_name}.framework/#{module_name}"
device_framework_lib = File.dirname(device_lib)
simulator_lib = "#{build_dir}/#{CONFIGURATION}-#{simulator}/#{root_name}/#{module_name}.framework/#{module_name}"
rome_lib = "#{destination}/#{module_name}.framework"
if (module_name.start_with?('Pods-') || File.directory?(rome_lib))
Pod::UI.puts "• Using #{root_name}"
else
Pod::UI.puts "→ Building #{root_name}"
xcodebuild(sandbox, root_name, device, deployment_target)
xcodebuild(sandbox, root_name, simulator, deployment_target)
next unless File.file?(device_lib) && File.file?(simulator_lib)
lipo_log = `lipo -create -output #{executable_path} #{device_lib} #{simulator_lib}`
puts lipo_log unless File.exist?(executable_path)
FileUtils.mv executable_path, device_lib
FileUtils.mv device_framework_lib, build_dir
FileUtils.rm simulator_lib if File.file?(simulator_lib)
FileUtils.rm device_lib if File.file?(device_lib)
end
end
end
def xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil)
args = %W(-project #{sandbox.project_path.basename} -scheme #{target} -configuration #{CONFIGURATION} -sdk #{sdk})
platform = PLATFORMS[sdk]
args += Fourflusher::SimControl.new.destination(:oldest, platform, deployment_target) unless platform.nil?
Pod::Executable.execute_command 'xcodebuild', args, true
end
Pod::HooksManager.register('cocoapods-rome', :post_install) do |installer_context|
Pod::UI.puts "Rome"
sandbox_root = Pathname(installer_context.sandbox_root)
sandbox = Pod::Sandbox.new(sandbox_root)
build_dir = sandbox_root.parent + 'build'
destination = sandbox_root.parent + 'Rome'
FileUtils.mkdir_p build_dir
FileUtils.mkdir_p destination
installer_context.umbrella_targets.each do |umbrella|
umbrella.specs.each do |spec|
consumer = spec.consumer(umbrella.platform_name)
file_accessor = Pod::Sandbox::FileAccessor.new(sandbox.pod_dir(spec.root.name), consumer)
if(file_accessor.vendored_frameworks.count > 0)
file_accessor.vendored_frameworks.each do |framework|
Pod::UI.puts "• Copying #{spec.root.name}"
FileUtils.cp_r framework, destination, :remove_destination => true
end
end
end
end
Dir.chdir(sandbox.project_path.dirname) do
targets = installer_context.umbrella_targets.select { |t| t.specs.any? }
targets.each do |target|
case target.platform_name
when :ios then build_for_iosish_platform(sandbox, build_dir, destination, target, 'iphoneos', 'iphonesimulator')
when :osx then xcodebuild(sandbox, target.cocoapods_target_label)
when :tvos then build_for_iosish_platform(sandbox, build_dir, destination, target, 'appletvos', 'appletvsimulator')
when :watchos then build_for_iosish_platform(sandbox, build_dir, destination, target, 'watchos', 'watchsimulator')
else raise "Unknown platform '#{target.platform_name}'" end
end
end
raise Pod::Informative, 'The build directory was not found in the expected location.' unless build_dir.directory?
frameworks = Pathname.glob("#{build_dir}/**/*.framework").reject { |f| f.to_s =~ /Pods.*\.framework/ }
installer_context.umbrella_targets.each do |umbrella|
umbrella.specs.each do |spec|
consumer = spec.consumer(umbrella.platform_name)
file_accessor = Pod::Sandbox::FileAccessor.new(sandbox.pod_dir(spec.root.name), consumer)
frameworks += file_accessor.vendored_libraries
end
end
frameworks.uniq!
frameworks.each do |framework|
FileUtils.cp_r framework, destination, :remove_destination => true
end
build_dir.rmtree if build_dir.directory?
end
Far from perfect, but it will do the trick :)
I hope it won't break anything :D
I'm not a big fan of making this based solely on the presence of the .framework
on the filesystem — that's just bound to confuse people.
@neonichu Hi there. I see this is an old discussion, but do you have any suggestion about being able to recompile just the pods that are new or upgraded? Basically similar to what pod install
does without the Rome plugin?
In our case, we are using a caching system to store all the precompiled binaries and would like to change them only if needed. As the system is now, running pod install
will rebuild everything and all the binaries will be different (of course).
@bpoplauschi this plugin might be of use to you (note that I haven't used it myself so I cannot vouchers for anything)
https://github.com/leavez/cocoapods-binary