class CococapodsPodfilePatch::PodfilePatch

Constants

ABSTRACT_PATCH_TARGET_NAME

Public Instance Methods

all_dependencies(target_defination) click to toggle source
# File lib/cocoapods-podfile_patch/podfile_patch.rb, line 91
def all_dependencies(target_defination)
    d = get_raw_dependencies(target_defination) 
    d += (target_defination.children.map do |subtarget|
        all_dependencies(subtarget)
    end.flatten || [])
    d
end
get_raw_dependencies(target_defination) click to toggle source
  1. find all dependency patch_targetdef: patched_dependencies

  2. modify targetdef's depedencies recursively:

    - replace the requirement to the one in patched_dependencies 
    - add to target if not contained
# File lib/cocoapods-podfile_patch/podfile_patch.rb, line 86
def get_raw_dependencies(target_defination)
    (target_defination.send :get_hash_value, 'dependencies') || []
end
load_patch_target(podfile, patchfile_path) click to toggle source
# File lib/cocoapods-podfile_patch/podfile_patch.rb, line 12
def load_patch_target(podfile, patchfile_path)

    # find patch file
    patch_file_path = Pathname.new(patchfile_path)
    if not patch_file_path.expand_path.file? 
        podfile_root_path = Pathname.new(podfile.defined_in_file).dirname
        patch_file_path = (podfile_root_path + patch_file_path).expand_path
    end
    if not patch_file_path.file?
        Pod::UI.info "Podfile patch feature is enabled. (No patch file now.)"
        return  
    end
    
    # load patch file content. And add it to a abstract target
    contents = File.read(patch_file_path)
    podfile.target ABSTRACT_PATCH_TARGET_NAME do
        podfile.instance_eval contents
    end

    # find the patch target and delete it in original podfile
    root_target = podfile.root_target_definitions[0]
    patch_target = root_target.children.find {|t| t.name == ABSTRACT_PATCH_TARGET_NAME }
    root_target.children.delete(patch_target)

    return patch_target
end
merge_patch_and_original_podfile(podfile, patch_target) click to toggle source
# File lib/cocoapods-podfile_patch/podfile_patch.rb, line 40
def merge_patch_and_original_podfile(podfile, patch_target)
    
    root_target = podfile.root_target_definitions[0]
    
    # merge patch_target and original_target
    patch_target.name = root_target.name
    merge_target_definitions_dependency(root_target,  patch_target)

    Pod::UI.titled_section "Podfile patch feature is enabled" do
        next unless Pod::UI.config.verbose?
        Pod::UI.section "Patchfile Info" do 
            self.print_podfile_raw_dependencies patch_target
        end
        Pod::UI.section "Modified Podfile Info" do 
            self.print_podfile_raw_dependencies root_target
        end
    end
end
merge_target_definitions_dependency(targetdef, patch_targetdef) click to toggle source
# File lib/cocoapods-podfile_patch/podfile_patch.rb, line 60
def merge_target_definitions_dependency(targetdef, patch_targetdef)
    # Demo Data
    # Original Target
    # ```
    # TargetDefination 'Pods':
    # [{"BDWebImage"=>["1.0.1.1-binary"]}]
    #
    #     TargetDefination 'Pods-FrameworkDemos_Tests':
    #     ["BDWebImage/SDAdapter", "BDWebImage/Download", {"TTNetworkManager"=>["2.2.8.46-rc.18"]}, {"AFNetworking"=>[{:path=>"/Users/lea/Downloads/AFNetworking"}]}]
    #
    #     TargetDefination 'Pods-FrameworkDemos_Example':
    #     ["BDWebImage", {"TTNetworkManager"=>["2.2.8.46-rc.18"]}]
    # ```
    #
    # Patch Target
    # ```
    # TargetDefination 'Pods':
    # [{"AFNetworking"=>["2.3"]}]
    # ```

    # 1. find all dependency patch_targetdef: patched_dependencies
    # 2. modify targetdef's depedencies recursively:
    #       - replace the requirement to the one in patched_dependencies
    #       - add to target if not contained


    def get_raw_dependencies(target_defination)
        (target_defination.send :get_hash_value, 'dependencies') || []
    end

    all_dependencies_in_patch = begin
        def all_dependencies(target_defination)
            d = get_raw_dependencies(target_defination) 
            d += (target_defination.children.map do |subtarget|
                all_dependencies(subtarget)
            end.flatten || [])
            d
        end
        all_dependencies(patch_targetdef)
    end
    
    def transform_target_dependency_to_dict(dependencies)
        dict = {}
        dependencies.each do |name_or_hash|
            if name_or_hash.is_a?(Hash)
                name = name_or_hash.keys.first
                requirements = name_or_hash.values.first
                dict[name] = requirements
            else
                dict[name_or_hash] = {}
            end
        end
        dict
    end

    dependencies_dict_in_patch = transform_target_dependency_to_dict(all_dependencies_in_patch)

    def modify_target_defination_recursively(target_defination, &block)
        block.call(target_defination)
        target_defination.children.each { |t| modify_target_defination_recursively(t, &block) }
    end

    patch_file_all_targets_dict = begin
        targets = {}
        modify_target_defination_recursively(patch_targetdef) do |t|
            targets[t.name] = t
        end
        targets
    end

    patch_file_target_to_dependency_dict = begin
        dict = {}
        modify_target_defination_recursively(patch_targetdef) do |t|
            deps = get_raw_dependencies(t)
            dict[t.name] = transform_target_dependency_to_dict(deps)
        end
        dict
    end

    modified_dependencies_names = {} # pod name => target name

    modify_target_defination_recursively(targetdef) do |t|
        deps = get_raw_dependencies(t)
        new_deps = []
        deps_set = Set.new
        
        # modify origianl dependency
        deps.each do |name_or_hash|
            name = nil
            if name_or_hash.is_a?(Hash)
                name = name_or_hash.keys.first
            else
                name = name_or_hash
            end
            if dependencies_dict_in_patch.key? name
                new_deps << {name => dependencies_dict_in_patch[name]}
                modified_dependencies_names[name] = t
            else
                new_deps << name_or_hash
            end
            deps_set.add(name)
        end
        # add new dependency
        patching_deps = patch_file_target_to_dependency_dict[t.name]
        if not patching_deps.blank?
            patching_deps.each do |name, requirements|
                if not deps_set.include? name
                    new_deps << (requirements.empty? ? name : {name => requirements})
                    modified_dependencies_names[name] = t
                end
            end
        end

        t.send :set_hash_value, "dependencies", new_deps
    end

    # handle MODULAR_HEADERS & INHIBIT_WARNING
    [ 'inhibit_warnings',
    'use_modular_headers'].each do |method|
        modify_target_defination_recursively(targetdef) do |t|
            original_inhibit_warning_dict = t.send(:get_hash_value,method, {})
            original_inhibit_warning_dict.each do |key, value|
                # the key is "for_pods" or "not_for_pods" or "all"
                # Clear if patchfile have modified the pod
                next unless value.kind_of? Array
                value.reject! { |name| modified_dependencies_names.include? name}
            end

            patch_target = patch_file_all_targets_dict[t.name]
            if not patch_target.nil?
                patch_inhibit_warning_dict = patch_target.send(:get_hash_value,method, {})
                patch_inhibit_warning_dict.each do |key, value|
                    if value.kind_of? Array
                        original = original_inhibit_warning_dict[key] || []
                        original.concat(value).uniq! 
                        original_inhibit_warning_dict[key] = original
                    elsif [true, false].include? value # "all"
                        original_inhibit_warning_dict[key] = value
                    end
                end
            end
            # delete key if blank
            if original_inhibit_warning_dict.empty?
                t.send(:internal_hash).delete(method)
            end
        end
    end

    # handle CONFIGURATION_WHITELIST
    modify_target_defination_recursively(targetdef) do |t|
        key = "configuration_pod_whitelist"
        original = t.send :get_hash_value, key, {}
        original.each do |config_name, pods|
            # Clear if patchfile have modified the pod
            next unless pods.kind_of? Array
            pods.reject! { |name| modified_dependencies_names.include? name}
        end
        
        patch_target = patch_file_all_targets_dict[t.name]
        if not patch_target.nil?
            patched = patch_target.send :raw_configuration_pod_whitelist
            patched.each do |config_name, pods|
                next unless pods.kind_of? Array
                original_pods = original[config_name] || []
                original_pods.concat(pods).uniq! 
                original[config_name] = original_pods
            end
        end
        # delete key if blank
        if original.empty?
            t.send(:internal_hash).delete(key)
        end
    end
end
modify_target_defination_recursively(target_defination, &block) click to toggle source
# File lib/cocoapods-podfile_patch/podfile_patch.rb, line 117
def modify_target_defination_recursively(target_defination, &block)
    block.call(target_defination)
    target_defination.children.each { |t| modify_target_defination_recursively(t, &block) }
end
print_podfile_raw_dependencies(target) click to toggle source
print_target_def_and_its_dependencies(target_def, intend = "") click to toggle source
transform_target_dependency_to_dict(dependencies) click to toggle source
# File lib/cocoapods-podfile_patch/podfile_patch.rb, line 101
def transform_target_dependency_to_dict(dependencies)
    dict = {}
    dependencies.each do |name_or_hash|
        if name_or_hash.is_a?(Hash)
            name = name_or_hash.keys.first
            requirements = name_or_hash.values.first
            dict[name] = requirements
        else
            dict[name_or_hash] = {}
        end
    end
    dict
end