class PodBuilder::Install
Public Class Methods
podfile(podfile_content, podfile_items, build_configuration)
click to toggle source
This method will generate prebuilt data by building from “/tmp/pod_builder/Podfile”
# File lib/pod_builder/install.rb, line 142 def self.podfile(podfile_content, podfile_items, build_configuration) puts "Preparing build Podfile".yellow PodBuilder::safe_rm_rf(Configuration.build_path) FileUtils.mkdir_p(Configuration.build_path) init_git(Configuration.build_path) # this is needed to be able to call safe_rm_rf podfile_content = copy_development_pods_source_code(podfile_content, podfile_items) podfile_content = Podfile.update_path_entries(podfile_content, Install.method(:podfile_path_transform)) podfile_content = Podfile.update_project_entries(podfile_content, Install.method(:podfile_path_transform)) podfile_content = Podfile.update_require_entries(podfile_content, Install.method(:podfile_path_transform)) podfile_path = File.join(Configuration.build_path, "Podfile") File.write(podfile_path, podfile_content) begin lock_file = "#{Configuration.build_path}/pod_builder.lock" FileUtils.touch(lock_file) prebuilt_entries = use_prebuilt_entries_for_unchanged_pods(podfile_path, podfile_items) install copy_prebuilt_items(podfile_items - prebuilt_entries) prebuilt_info = prebuilt_info(podfile_items) licenses = license_specifiers() if !OPTIONS.has_key?(:debug) PodBuilder::safe_rm_rf(Configuration.build_path) end return InstallResult.new(licenses, prebuilt_info) rescue Exception => e if File.directory?("#{Configuration.build_path}/Pods/Pods.xcodeproj") activate_pod_scheme() if ENV["DEBUGGING"] system("xed #{Configuration.build_path}/Pods") elsif !OPTIONS.has_key?(:no_stdin_available) confirm = ask("\n\nOh no! Something went wrong during prebuild phase! Do you want to open the prebuild project to debug the error, you will need to add and run the Pods-Dummy scheme? [Y/N] ".red) { |yn| yn.limit = 1, yn.validate = /[yn]/i } if confirm.downcase == 'y' system("xed #{Configuration.build_path}/Pods") end end end raise e ensure FileUtils.rm(lock_file) if File.exist?(lock_file) end end
prebuilt_info(podfile_items)
click to toggle source
# File lib/pod_builder/install.rb, line 198 def self.prebuilt_info(podfile_items) gitignored_files = PodBuilder::gitignoredfiles swift_version = PodBuilder::system_swift_version write_prebuilt_info_filename_gitattributes ret = Hash.new root_names = podfile_items.reject(&:is_prebuilt).map(&:root_name).uniq root_names.each do |prebuilt_name| path = PodBuilder::prebuiltpath(prebuilt_name) unless File.directory?(path) puts "Prebuilt items for #{prebuilt_name} not found".blue next end unless podfile_item = podfile_items.detect { |t| t.name == prebuilt_name } || podfile_items.detect { |t| t.root_name == prebuilt_name } puts "Prebuilt items for #{prebuilt_name} not found #2".blue next end podbuilder_file = File.join(path, Configuration.prebuilt_info_filename) entry = podfile_item.entry(true, false) data = {} data["entry"] = entry data["is_prebuilt"] = podfile_item.is_prebuilt if Dir.glob(File.join(path, "#{podfile_item.prebuilt_rel_path}/Headers/*-Swift.h")).count > 0 data["swift_version"] = swift_version end specs = podfile_items.select { |x| x.module_name == podfile_item.module_name } subspecs_deps = specs.map(&:dependency_names).flatten subspec_self_deps = subspecs_deps.select { |x| x.start_with?("#{prebuilt_name}/") } data["specs"] = (specs.map(&:name) + subspec_self_deps).uniq data["is_static"] = podfile_item.is_static data["original_compile_path"] = Pathname.new(Configuration.build_path).realpath.to_s if hash = build_folder_hash(podfile_item, gitignored_files) data["build_folder_hash"] = hash end ret.merge!({ podbuilder_file => data }) end return ret end
Private Class Methods
activate_pod_scheme()
click to toggle source
# File lib/pod_builder/install.rb, line 491 def self.activate_pod_scheme if scheme_file = Dir.glob("#{Configuration.build_path}/Pods/**/xcschememanagement.plist").first plist = CFPropertyList::List.new(:file => scheme_file) data = CFPropertyList.native_types(plist.value) if !data.dig("SchemeUserState", "Pods-DummyTarget.xcscheme").nil? data["SchemeUserState"]["Pods-DummyTarget.xcscheme"]["isShown"] = true end plist.value = CFPropertyList.guess(data) plist.save(scheme_file, CFPropertyList::List::FORMAT_BINARY) end end
build_folder_hash(podfile_item, exclude_files)
click to toggle source
# File lib/pod_builder/install.rb, line 437 def self.build_folder_hash(podfile_item, exclude_files) if podfile_item.is_development_pod if Pathname.new(podfile_item.path).absolute? item_path = podfile_item.path else item_path = PodBuilder::basepath(podfile_item.path) end rootpath = PodBuilder::git_rootpath file_hashes = [] Dir.glob("#{item_path}/**/*", File::FNM_DOTMATCH) do |path| unless File.file?(path) next end path = File.expand_path(path) rel_path = path.gsub(rootpath, "")[1..] unless exclude_files.include?(rel_path) file_hashes.push(Digest::MD5.hexdigest(File.read(path))) end end return Digest::MD5.hexdigest(file_hashes.join) else # Pod folder might be under .gitignore item_path = "#{Configuration.build_path}/Pods/#{podfile_item.root_name}" if File.directory?(item_path) return `find '#{item_path}' -type f -print0 | sort -z | xargs -0 shasum | shasum | cut -d' ' -f1`.strip() else return nil end end end
build_folder_hash_in_prebuilt_info_file(podfile_item)
click to toggle source
# File lib/pod_builder/install.rb, line 426 def self.build_folder_hash_in_prebuilt_info_file(podfile_item) prebuilt_info_path = PodBuilder::prebuiltpath(File.join(podfile_item.root_name, Configuration.prebuilt_info_filename)) if File.exist?(prebuilt_info_path) data = JSON.parse(File.read(prebuilt_info_path)) return data['build_folder_hash'] else return nil end end
copy_development_pods_source_code(podfile_content, podfile_items)
click to toggle source
# File lib/pod_builder/install.rb, line 259 def self.copy_development_pods_source_code(podfile_content, podfile_items) # Development pods are normally built/integrated without moving files from their original paths. # It is important that CocoaPods compiles the files under Configuration.build_path in order that # DWARF debug info reference to this constant path. Doing otherwise breaks the assumptions that # makes the `generate_lldbinit` command work. development_pods = podfile_items.select { |x| x.is_development_pod } development_pods.each do |podfile_item| destination_path = "#{Configuration.build_path}/Pods/#{podfile_item.name}" FileUtils.mkdir_p(destination_path) if Pathname.new(podfile_item.path).absolute? FileUtils.cp_r("#{podfile_item.path}/.", destination_path) else FileUtils.cp_r("#{PodBuilder::basepath(podfile_item.path)}/.", destination_path) end unless Configuration.build_using_repo_paths podfile_content.gsub!("'#{podfile_item.path}'", "'#{destination_path}'") end end return podfile_content end
copy_prebuilt_items(podfile_items)
click to toggle source
# File lib/pod_builder/install.rb, line 367 def self.copy_prebuilt_items(podfile_items) FileUtils.mkdir_p(PodBuilder::prebuiltpath) non_prebuilt_items = podfile_items.reject(&:is_prebuilt) pod_names = non_prebuilt_items.map(&:root_name).uniq pod_names.reject! { |t| folder_path = PodBuilder::buildpath_prebuiltpath(t) File.directory?(folder_path) && Dir.empty?(folder_path) # When using prebuilt items we end up with empty folders } pod_names.each do |pod_name| root_name = pod_name.split("/").first items_to_delete = Dir.glob("#{PodBuilder::prebuiltpath(root_name)}/**/*") items_to_delete.each { |t| PodBuilder::safe_rm_rf(t) } end # Now copy pod_names.each do |pod_name| root_name = pod_name.split("/").first source_path = PodBuilder::buildpath_prebuiltpath(root_name) unless File.directory?(source_path) puts "Prebuilt items for #{pod_name} not found".blue next end unless Dir.glob("#{source_path}/**/*").select { |t| File.file?(t) }.empty? destination_folder = PodBuilder::prebuiltpath(root_name) FileUtils.mkdir_p(destination_folder) FileUtils.cp_r("#{source_path}/.", destination_folder) end end # Folder won't exist if no dSYM were generated (all static libs) if File.directory?(PodBuilder::buildpath_dsympath) FileUtils.mkdir_p(PodBuilder::dsympath) FileUtils.cp_r(PodBuilder::buildpath_dsympath, PodBuilder::basepath) end end
download()
click to toggle source
# File lib/pod_builder/install.rb, line 347 def self.download puts "Downloading Pods source code".yellow CLAide::Command::PluginManager.load_plugins("cocoapods") Dir.chdir(Configuration.build_path) do Pod::UserInterface::config.silent = true config = Pod::Config.new() installer = Pod::Installer.new(config.sandbox, config.podfile, config.lockfile) installer.repo_update = false installer.update = false installer.prepare installer.resolve_dependencies installer.download_dependencies Pod::UserInterface::config.silent = false end end
init_git(path)
click to toggle source
# File lib/pod_builder/install.rb, line 418 def self.init_git(path) current_dir = Dir.pwd Dir.chdir(path) system("git init") Dir.chdir(current_dir) end
install()
click to toggle source
# File lib/pod_builder/install.rb, line 327 def self.install puts "Preparing build".yellow CLAide::Command::PluginManager.load_plugins("cocoapods") Dir.chdir(Configuration.build_path) do config = Pod::Config.new() installer = Pod::Installer.new(config.sandbox, config.podfile, config.lockfile) installer.repo_update = false installer.update = false install_start_time = Time.now installer.install! install_time = Time.now - install_start_time puts "Build completed in #{install_time.to_i} seconds".blue end end
license_specifiers()
click to toggle source
# File lib/pod_builder/install.rb, line 247 def self.license_specifiers acknowledge_file = "#{Configuration.build_path}/Pods/Target Support Files/Pods-DummyTarget/Pods-DummyTarget-acknowledgements.plist" unless File.exist?(acknowledge_file) raise "\n\nLicense file not found".red end plist = CFPropertyList::List.new(:file => acknowledge_file) data = CFPropertyList.native_types(plist.value) return data["PreferenceSpecifiers"] || [] end
podfile_path_transform(path)
click to toggle source
# File lib/pod_builder/install.rb, line 471 def self.podfile_path_transform(path) if Configuration.build_using_repo_paths return File.expand_path(PodBuilder::basepath(path)) else use_absolute_paths = true podfile_path = File.join(Configuration.build_path, "Podfile") original_basepath = PodBuilder::basepath podfile_base_path = Pathname.new(File.dirname(podfile_path)) original_path = Pathname.new(File.join(original_basepath, path)) replace_path = original_path.relative_path_from(podfile_base_path) if use_absolute_paths replace_path = replace_path.expand_path(podfile_base_path) end return replace_path end end
use_prebuilt_entries_for_unchanged_pods(podfile_path, podfile_items)
click to toggle source
# File lib/pod_builder/install.rb, line 283 def self.use_prebuilt_entries_for_unchanged_pods(podfile_path, podfile_items) podfile_content = File.read(podfile_path) replaced_items = [] if OPTIONS.has_key?(:force_rebuild) podfile_content.gsub!("%%%prebuilt_root_paths%%%", "{}") else download # Copy files under #{Configuration.build_path}/Pods so that we can determine build folder hashes gitignored_files = PodBuilder::gitignoredfiles prebuilt_root_paths = Hash.new # Replace prebuilt entries in Podfile for Pods that have no changes in source code which will avoid rebuilding them items = podfile_items.group_by { |t| t.root_name }.map { |k, v| v.first } # Return one podfile_item per root_name items.each do |item| podspec_path = item.prebuilt_podspec_path if last_build_folder_hash = build_folder_hash_in_prebuilt_info_file(item) if last_build_folder_hash == build_folder_hash(item, gitignored_files) puts "No changes detected to '#{item.root_name}', will skip rebuild".blue replaced_items.push(item) podfile_items.select { |t| t.root_name == item.root_name }.each do |replace_item| replace_regex = "pod '#{Regexp.quote(replace_item.name)}', .*" replace_line_found = podfile_content =~ /#{replace_regex}/i raise "\n\nFailed finding pod entry for '#{replace_item.name}'".red unless replace_line_found podfile_content.gsub!(/#{replace_regex}/, replace_item.prebuilt_entry(true, true)) prebuilt_root_paths[replace_item.root_name] = PodBuilder::prebuiltpath end end end end podfile_content.gsub!("%%%prebuilt_root_paths%%%", prebuilt_root_paths.to_s) end File.write(podfile_path, podfile_content) return replaced_items end
write_prebuilt_info_filename_gitattributes()
click to toggle source
# File lib/pod_builder/install.rb, line 410 def self.write_prebuilt_info_filename_gitattributes gitattributes_path = PodBuilder::basepath(".gitattributes") expected_attributes = ["#{Configuration.configuration_filename} binary"].join unless File.exists?(gitattributes_path) && File.read(gitattributes_path).include?(expected_attributes) File.write(gitattributes_path, expected_attributes, mode: 'a') end end