module Xcodeproj class Project module Object class PBXGroup def sync(group) ensure_internal_consistency(group) # Make sure we don't belong to any other groups if excluded_from_sync? Synx::Tabber.puts "#{basename}/ (excluded)".yellow else Synx::Tabber.puts "#{basename}/".green Synx::Tabber.increase squash_duplicate_file_references # Child directories may not exist yet (and may be different for # each file) if this is a localized group, so we do the mkpath call # inside the loops. files.each do |pbx_file| pbx_file.work_pathname.dirname.mkpath pbx_file.sync(self) end all_groups.each do |group| group.work_pathname.dirname.mkpath group.sync(self) end sync_path Synx::Tabber.decrease end end def excluded_from_sync? project.group_exclusions.include?(hierarchy_path) end def move_entries_not_in_xcodeproj if excluded_from_sync? Synx::Tabber.puts "#{basename}/ (excluded)".yellow elsif real_path.exist? Synx::Tabber.puts "#{basename}/".green Synx::Tabber.increase real_path.children.each do |entry_pathname| unless project.has_object_for_pathname?(entry_pathname) handle_unused_entry(entry_pathname) end end all_groups.each(&:move_entries_not_in_xcodeproj) Synx::Tabber.decrease end end def sync_path self.path = work_pathname.relative_path_from(parent.work_pathname).to_s self.source_tree = "" end private :sync_path def all_groups children.select { |child| child.is_a?(Xcodeproj::Project::Object::PBXGroup)} end def handle_unused_entry(entry_pathname) entries_to_ignore = %W(.DS_Store) unless entries_to_ignore.include?(entry_pathname.basename.to_s) if entry_pathname.directory? # recurse Synx::Tabber.puts entry_pathname.basename.to_s.green Synx::Tabber.increase # Don't create the directory manually: if it has children, it will # be created then, and if it doesn't, we don't want it. entry_pathname.children.each { |child| handle_unused_entry(child) } Synx::Tabber.decrease elsif entry_pathname.file? handle_unused_file(entry_pathname) end end end private :handle_unused_entry def handle_unused_file(file_pathname) prune_file_extensions = %W(.h .m .xib .mm .c .png .jpg .jpeg) is_file_to_prune = prune_file_extensions.include?(file_pathname.extname.downcase) if is_file_to_prune && project.prune Synx::Tabber.puts "#{file_pathname.basename} (removed source/image file that is not referenced by the Xcode project)".red return elsif !project.prune || !is_file_to_prune destination = project.pathname_to_work_pathname(file_pathname.parent.realpath) destination.mkpath FileUtils.mv(file_pathname.realpath, destination) if is_file_to_prune Synx::Tabber.puts "#{file_pathname.basename} (source/image file that is not referenced by the Xcode project)".yellow else Synx::Tabber.puts file_pathname.basename end end end private :handle_unused_file def squash_duplicate_file_references files.each { |f| f.ensure_internal_consistency(self) } grouped_by_path = files.group_by do |file| file.real_path.cleanpath end duplicates = grouped_by_path.select do |file_path, files| files.count > 1 end duplicates.each do |file_path, files| file = files.last # Removes all references (files array) remove_reference(file) # Adds just one back self << file Synx::Tabber.puts "#{file.basename} (removed duplicate reference)".red end end private :squash_duplicate_file_references def groups_containing_forward_slash found_groups = [] groups.each do |group| unless group.excluded_from_sync? found_groups << group if group.basename.include?("/") found_groups |= group.groups_containing_forward_slash end end found_groups end end end end end