cocoapods-project-gen 0.1.0 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +73 -23
- data/bin/xcframework +11 -0
- data/lib/cocoapods-project-gen/command/command.rb +25 -0
- data/lib/cocoapods-project-gen/command/gen.rb +122 -0
- data/lib/cocoapods-project-gen/gem_version.rb +1 -1
- data/lib/cocoapods-project-gen/gen/build/headers_store.rb +104 -0
- data/lib/cocoapods-project-gen/gen/build/xcode_build.rb +47 -0
- data/lib/cocoapods-project-gen/gen/constants.rb +71 -0
- data/lib/cocoapods-project-gen/gen/pod/pod_copy_cleaner.rb +50 -0
- data/lib/cocoapods-project-gen/gen/pod/project_gen_helper.rb +341 -0
- data/lib/cocoapods-project-gen/gen/pod/swift_module_helper.rb +134 -0
- data/lib/cocoapods-project-gen/gen/product/product_helper.rb +93 -0
- data/lib/cocoapods-project-gen/gen/product.rb +165 -0
- data/lib/cocoapods-project-gen/gen/project_builder.rb +144 -0
- data/lib/cocoapods-project-gen/gen/project_gen.rb +179 -128
- data/lib/cocoapods-project-gen/gen/results.rb +143 -0
- data/lib/cocoapods-project-gen/gen/utils.rb +35 -0
- data/lib/cocoapods-project-gen/gen/xcframework_gen.rb +44 -0
- data/lib/cocoapods-project-gen.rb +14 -7
- metadata +21 -6
- data/lib/cocoapods-project-gen/gen/swift_module_helper.rb +0 -52
| @@ -0,0 +1,165 @@ | |
| 1 | 
            +
            module ProjectGen
         | 
| 2 | 
            +
              require 'cocoapods-project-gen/gen/product/product_helper'
         | 
| 3 | 
            +
              require 'cocoapods-project-gen/gen/build/xcode_build'
         | 
| 4 | 
            +
              class Products
         | 
| 5 | 
            +
                attr_reader :products
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize(spec, products)
         | 
| 8 | 
            +
                  @products = products
         | 
| 9 | 
            +
                  @spec = spec
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def add_pod_targets_file_accessors_paths
         | 
| 13 | 
            +
                  products.each(&:add_pod_target_file_accessors_paths)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def create_bin_products
         | 
| 17 | 
            +
                  FileUtils.rm_rf(product_path) if product_path.exist?
         | 
| 18 | 
            +
                  build_xcframework
         | 
| 19 | 
            +
                  add_pod_targets_file_accessors_paths
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                # Performs platform specific analysis. It requires to download the source
         | 
| 23 | 
            +
                # at each iteration
         | 
| 24 | 
            +
                #
         | 
| 25 | 
            +
                # @note   Xcode warnings are treated as notes because the spec maintainer
         | 
| 26 | 
            +
                #         might not be the author of the library
         | 
| 27 | 
            +
                # @return [void]
         | 
| 28 | 
            +
                def build_xcframework
         | 
| 29 | 
            +
                  xc_args = @products.flat_map(&:create_bin_product_args!)
         | 
| 30 | 
            +
                  error = XcodeBuild.create_xcframework?(xc_args, xcframework_product_path)
         | 
| 31 | 
            +
                  print_pod_xcframework_infos unless error
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def xcframework_product_path
         | 
| 35 | 
            +
                  @products[0].xcframework_product_path
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def product_path
         | 
| 39 | 
            +
                  @products[0].product_path
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                private
         | 
| 43 | 
            +
                # Prints the list of specs & pod cache dirs for a single pod name.
         | 
| 44 | 
            +
                #
         | 
| 45 | 
            +
                # This output is valid YAML so it can be parsed with 3rd party tools
         | 
| 46 | 
            +
                #
         | 
| 47 | 
            +
                def print_pod_xcframework_infos
         | 
| 48 | 
            +
                  product = @products[0]
         | 
| 49 | 
            +
                  Results.puts("#{product.xcframework_name}:".green)
         | 
| 50 | 
            +
                  Results.puts("  - Version: #{product.version}".green)
         | 
| 51 | 
            +
                  Results.puts("    Type:    #{product.product_type}".green)
         | 
| 52 | 
            +
                  Results.puts("    path:    #{product_path}".green)
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              class Product
         | 
| 57 | 
            +
                include ProductHelper
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                attr_reader :target, :product_root
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def initialize(target, product_root, root, archive_paths)
         | 
| 62 | 
            +
                  @target = GenTarget.new(target)
         | 
| 63 | 
            +
                  @archive_paths = archive_paths
         | 
| 64 | 
            +
                  @product_root = product_root
         | 
| 65 | 
            +
                  @root = root
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def create_bin_product_args!
         | 
| 69 | 
            +
                  @archive_paths.flat_map do |path|
         | 
| 70 | 
            +
                    headers_dir = path.dirname.join(pod_name).join('Headers')
         | 
| 71 | 
            +
                    args = %W[-archive #{path}]
         | 
| 72 | 
            +
                    args + if build_as_framework?
         | 
| 73 | 
            +
                             %W[-framework #{product_name}]
         | 
| 74 | 
            +
                           else
         | 
| 75 | 
            +
                             h_a = %W[-headers #{headers_dir}] if headers_dir.exist? && headers_dir.children.count.nonzero?
         | 
| 76 | 
            +
                             %W[-library #{static_library_name}] + (h_a || [])
         | 
| 77 | 
            +
                           end
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                def add_pod_target_file_accessors_paths
         | 
| 82 | 
            +
                  add_vendored_frameworks
         | 
| 83 | 
            +
                  add_vendored_libraries
         | 
| 84 | 
            +
                  add_resources
         | 
| 85 | 
            +
                  add_other_files
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                private
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                # Removes the source files of the Pods to the Pods project.
         | 
| 91 | 
            +
                #
         | 
| 92 | 
            +
                # @note   The source files are grouped by Pod and in turn by subspec
         | 
| 93 | 
            +
                #         (recursively).
         | 
| 94 | 
            +
                #
         | 
| 95 | 
            +
                # @return [void]
         | 
| 96 | 
            +
                #
         | 
| 97 | 
            +
                def remove_source_files_references
         | 
| 98 | 
            +
                  Pod::UI.message '- Removing source files' do
         | 
| 99 | 
            +
                    extensions = Pod::Sandbox::FileAccessor::SOURCE_FILE_EXTENSIONS
         | 
| 100 | 
            +
                    source_files = file_accessors.flat_map { |file_accessor| file_accessor.send(:source_files) }
         | 
| 101 | 
            +
                    source_files.each do |f|
         | 
| 102 | 
            +
                      next unless extensions.include?(f.extname)
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                      relative_path = f.relative_path_from(pod_dir)
         | 
| 105 | 
            +
                      full_source_path = @product_path.join(relative_path)
         | 
| 106 | 
            +
                      FileUtils.rm_rf(full_source_path)
         | 
| 107 | 
            +
                    end
         | 
| 108 | 
            +
                  end
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                # Adds the bundled frameworks to the Pods project
         | 
| 112 | 
            +
                #
         | 
| 113 | 
            +
                # @return [void]
         | 
| 114 | 
            +
                #
         | 
| 115 | 
            +
                def add_vendored_frameworks
         | 
| 116 | 
            +
                  Pod::UI.message '- Adding frameworks' do
         | 
| 117 | 
            +
                    add_file_accessors_paths_to_products_group(:vendored_frameworks)
         | 
| 118 | 
            +
                  end
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                # Adds the bundled libraries to the Pods project
         | 
| 122 | 
            +
                #
         | 
| 123 | 
            +
                # @return [void]
         | 
| 124 | 
            +
                #
         | 
| 125 | 
            +
                def add_vendored_libraries
         | 
| 126 | 
            +
                  Pod::UI.message '- Adding libraries' do
         | 
| 127 | 
            +
                    add_file_accessors_paths_to_products_group(:vendored_libraries)
         | 
| 128 | 
            +
                  end
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                # Adds the resources of the Pods to the Pods project.
         | 
| 132 | 
            +
                #
         | 
| 133 | 
            +
                # @note   The source files are grouped by Pod and in turn by subspec
         | 
| 134 | 
            +
                #         (recursively) in the resources group.
         | 
| 135 | 
            +
                #
         | 
| 136 | 
            +
                # @return [void]
         | 
| 137 | 
            +
                #
         | 
| 138 | 
            +
                def add_resources
         | 
| 139 | 
            +
                  Pod::UI.message '- Adding resources' do
         | 
| 140 | 
            +
                    add_file_accessors_paths_to_products_group(:resources)
         | 
| 141 | 
            +
                    add_file_accessors_paths_to_products_group(:resource_bundle_files)
         | 
| 142 | 
            +
                  end
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                def add_other_files
         | 
| 146 | 
            +
                  Pod::UI.message '- Adding other files' do
         | 
| 147 | 
            +
                    add_file_accessors_paths_to_products_group(:license)
         | 
| 148 | 
            +
                    add_file_accessors_paths_to_products_group(:readme)
         | 
| 149 | 
            +
                  end
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                def add_file_accessors_paths_to_products_group(file_accessor_key)
         | 
| 153 | 
            +
                  fs = file_accessors.flat_map { |file_accessor| file_accessor.send(file_accessor_key) }.compact
         | 
| 154 | 
            +
                  fs.each do |f|
         | 
| 155 | 
            +
                    relative_path = f.relative_path_from(pod_dir)
         | 
| 156 | 
            +
                    full_source_path = product_path.join(relative_path)
         | 
| 157 | 
            +
                    next if full_source_path.exist?
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                    full_source_dir = product_path.join(relative_path.parent)
         | 
| 160 | 
            +
                    FileUtils.mkdir_p(full_source_dir) unless full_source_dir.exist?
         | 
| 161 | 
            +
                    FileUtils.cp_r(%W[#{f}], full_source_dir)
         | 
| 162 | 
            +
                  end
         | 
| 163 | 
            +
                end
         | 
| 164 | 
            +
              end
         | 
| 165 | 
            +
            end
         | 
| @@ -0,0 +1,144 @@ | |
| 1 | 
            +
            require 'cocoapods'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ProjectGen
         | 
| 4 | 
            +
              class BuildManager
         | 
| 5 | 
            +
                require 'cocoapods-project-gen/gen/build/xcode_build'
         | 
| 6 | 
            +
                require 'cocoapods-project-gen/gen/product'
         | 
| 7 | 
            +
                require 'cocoapods-project-gen/gen/build/headers_store'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                attr_reader :root
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(app_root, root = nil, no_clean: true, fail_fast: true)
         | 
| 12 | 
            +
                  @root = root.nil? ? app_root : root
         | 
| 13 | 
            +
                  @app_root = app_root
         | 
| 14 | 
            +
                  @no_clean = no_clean
         | 
| 15 | 
            +
                  @fail_fast = fail_fast
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def product_dir
         | 
| 19 | 
            +
                  Pathname.new(root.parent).join('./project_gen_products').expand_path
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def archives_dir
         | 
| 23 | 
            +
                  Pathname.new(root.parent).join('./project_gen_archives').expand_path
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                # Integrates the user projects associated with the {TargetDefinitions}
         | 
| 27 | 
            +
                # with the Pods project and its products.
         | 
| 28 | 
            +
                #
         | 
| 29 | 
            +
                # @return [void]
         | 
| 30 | 
            +
                #
         | 
| 31 | 
            +
                def create_xcframework_products!(platforms, pod_targets, configuration = nil, build_library_for_distribution: false)
         | 
| 32 | 
            +
                  ts = pod_targets.values.flatten
         | 
| 33 | 
            +
                  Results.puts '-> Start Archiving...'.green
         | 
| 34 | 
            +
                  platform_archive_paths = Hash[platforms.map do |platform|
         | 
| 35 | 
            +
                    archive_paths = compute_archive_paths(platform, ts, configuration, build_library_for_distribution)
         | 
| 36 | 
            +
                    [platform.name, archive_paths]
         | 
| 37 | 
            +
                  end]
         | 
| 38 | 
            +
                  return if platform_archive_paths.values.flatten.empty?
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  output = Hash[pod_targets.map do |key, targets|
         | 
| 41 | 
            +
                    products = targets.map do |target|
         | 
| 42 | 
            +
                      Product.new(target, product_dir, root.parent, platform_archive_paths[target.platform.name])
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                    ps = Products.new(key, products)
         | 
| 45 | 
            +
                    ps.create_bin_products
         | 
| 46 | 
            +
                    ps.add_pod_targets_file_accessors_paths
         | 
| 47 | 
            +
                    [key, ps.product_path]
         | 
| 48 | 
            +
                  end]
         | 
| 49 | 
            +
                  unless @no_clean
         | 
| 50 | 
            +
                    FileUtils.rm_rf(@app_root)
         | 
| 51 | 
            +
                    FileUtils.rm_rf(archives_dir)
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                  output
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                private
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def compute_archive_paths(platform, pod_targets, configuration, build_library_for_distribution)
         | 
| 59 | 
            +
                  sdks = Constants.sdks(platform.name)
         | 
| 60 | 
            +
                  archive_paths_by_platform(sdks, platform, pod_targets, configuration, build_library_for_distribution)
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def archive_paths_by_platform(sdks, platform, pod_targets, configuration, build_library_for_distribution)
         | 
| 64 | 
            +
                  sdks.map do |sdk|
         | 
| 65 | 
            +
                    args = if build_library_for_distribution
         | 
| 66 | 
            +
                             %w[BUILD_LIBRARY_FOR_DISTRIBUTION=YES]
         | 
| 67 | 
            +
                           else
         | 
| 68 | 
            +
                             []
         | 
| 69 | 
            +
                           end
         | 
| 70 | 
            +
                    args += %W[-destination generic/platform=#{Constants::SDK_DESTINATION[sdk]}]
         | 
| 71 | 
            +
                    args += %W[-configuration #{configuration}] unless configuration.nil?
         | 
| 72 | 
            +
                    args += %W[-sdk #{sdk}]
         | 
| 73 | 
            +
                    pod_project_path = File.expand_path('./Pods/Pods.xcodeproj', @app_root)
         | 
| 74 | 
            +
                    archive_root = archives_dir.join(sdk.to_s)
         | 
| 75 | 
            +
                    archive_path = archive_root.join('Pods-App.xcarchive')
         | 
| 76 | 
            +
                    error = XcodeBuild.archive?(args, pod_project_path, "Pods-App-#{platform.string_name}", archive_path)
         | 
| 77 | 
            +
                    break if @fail_fast && error
         | 
| 78 | 
            +
                    next if error
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                    print_pod_archive_infos(sdk, archive_path)
         | 
| 81 | 
            +
                    library_targets = pod_targets.select(&:build_as_library?)
         | 
| 82 | 
            +
                    library_targets.each do |target|
         | 
| 83 | 
            +
                      rename_library_product_name(target, archive_path)
         | 
| 84 | 
            +
                      archive_headers_path = archive_root.join(target.pod_name)
         | 
| 85 | 
            +
                      link_headers(target, archive_headers_path)
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
                    archive_path
         | 
| 88 | 
            +
                  end.compact
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                def rename_library_product_name(target, archive_path)
         | 
| 92 | 
            +
                  return unless target.build_as_library?
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  full_archive_path = archive_path.join('Products/usr/local/lib')
         | 
| 95 | 
            +
                  full_product_path = full_archive_path.join(target.static_library_name)
         | 
| 96 | 
            +
                  scope_suffix = target.scope_suffix
         | 
| 97 | 
            +
                  return unless full_product_path.exist? && scope_suffix && target.label.end_with?(scope_suffix)
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  label = Utils.remove_target_scope_suffix(target.label, scope_suffix)
         | 
| 100 | 
            +
                  new_full_archive_path = full_archive_path.join("lib#{label}.a")
         | 
| 101 | 
            +
                  File.rename(full_product_path, new_full_archive_path)
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                # Creates the link to the headers of the Pod in the sandbox.
         | 
| 105 | 
            +
                #
         | 
| 106 | 
            +
                # @return [void]
         | 
| 107 | 
            +
                #
         | 
| 108 | 
            +
                def link_headers(target, product_path)
         | 
| 109 | 
            +
                  Pod::UI.message '- Linking headers' do
         | 
| 110 | 
            +
                    # When integrating Pod as frameworks, built Pods are built into
         | 
| 111 | 
            +
                    # frameworks, whose headers are included inside the built
         | 
| 112 | 
            +
                    # framework. Those headers do not need to be linked from the
         | 
| 113 | 
            +
                    # sandbox.
         | 
| 114 | 
            +
                    next if target.build_as_framework? && target.should_build?
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                    sandbox = Pod::Sandbox.new(product_path)
         | 
| 117 | 
            +
                    build_headers = ProjectGen::HeadersStore.new(sandbox, '', :public)
         | 
| 118 | 
            +
                    pod_target_header_mappings = target.header_mappings_by_file_accessor.values
         | 
| 119 | 
            +
                    public_header_mappings = target.public_header_mappings_by_file_accessor.values
         | 
| 120 | 
            +
                    headers = pod_target_header_mappings + public_header_mappings
         | 
| 121 | 
            +
                    headers.uniq.each do |header_mappings|
         | 
| 122 | 
            +
                      header_mappings.each do |namespaced_path, files|
         | 
| 123 | 
            +
                        hs = build_headers.add_files('', files)
         | 
| 124 | 
            +
                        build_headers.add_files(namespaced_path, hs, ln: true)
         | 
| 125 | 
            +
                      end
         | 
| 126 | 
            +
                    end
         | 
| 127 | 
            +
                    root_name = Pod::Specification.root_name(target.pod_name)
         | 
| 128 | 
            +
                    pod_dir = target.sandbox.sources_root.join(root_name)
         | 
| 129 | 
            +
                    module_headers = pod_dir.join(Constants::COPY_LIBRARY_SWIFT_HEADERS)
         | 
| 130 | 
            +
                    module_paths = build_headers.add_files(root_name, module_headers.children) if module_headers.exist?
         | 
| 131 | 
            +
                    module_paths
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                # Prints the list of specs & pod cache dirs for a single pod name.
         | 
| 136 | 
            +
                #
         | 
| 137 | 
            +
                # This output is valid YAML so it can be parsed with 3rd party tools
         | 
| 138 | 
            +
                #
         | 
| 139 | 
            +
                def print_pod_archive_infos(sdk, archive_path)
         | 
| 140 | 
            +
                  Results.puts("  - Archive: #{sdk}")
         | 
| 141 | 
            +
                  Results.puts("    path:    #{archive_path}")
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
              end
         | 
| 144 | 
            +
            end
         | 
| @@ -1,10 +1,93 @@ | |
| 1 | 
            -
            require 'cocoapods/validator'
         | 
| 2 | 
            -
            require 'cocoapods-project-gen/gen/swift_module_helper'
         | 
| 3 1 | 
             
            require 'fileutils'
         | 
| 4 2 |  | 
| 5 3 | 
             
            module ProjectGen
         | 
| 6 | 
            -
               | 
| 4 | 
            +
              autoload :PodDirCopyCleaner, 'cocoapods-project-gen/gen/pod/pod_copy_cleaner'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              class ProjectGenerator
         | 
| 7 | 
            +
                require 'cocoapods-project-gen/gen/pod/swift_module_helper'
         | 
| 8 | 
            +
                require 'cocoapods-project-gen/gen/pod/project_gen_helper'
         | 
| 9 | 
            +
             | 
| 7 10 | 
             
                include ProjectGen::SwiftModule
         | 
| 11 | 
            +
                include ProjectGen::Helper
         | 
| 12 | 
            +
                include Pod::Config::Mixin
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                # !@group results
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                attr_reader :results
         | 
| 17 | 
            +
                #-------------------------------------------------------------------------#
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                #  @!group Configuration
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                # When multiple dependencies with different sources, use latest.
         | 
| 22 | 
            +
                #
         | 
| 23 | 
            +
                attr_accessor :use_latest
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                # @return [String] The SWIFT_VERSION that should be used to validate the pod. This is set by passing the
         | 
| 26 | 
            +
                # `--swift-version` parameter during validation.
         | 
| 27 | 
            +
                #
         | 
| 28 | 
            +
                attr_accessor :swift_version
         | 
| 29 | 
            +
                # @return [Boolean] whether the linter should not clean up temporary files
         | 
| 30 | 
            +
                #         for inspection.
         | 
| 31 | 
            +
                #
         | 
| 32 | 
            +
                attr_accessor :no_clean
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                # @return [Boolean] whether the linter should fail as soon as the first build
         | 
| 35 | 
            +
                #         variant causes an error. Helpful for i.e. multi-platforms specs,
         | 
| 36 | 
            +
                #         specs with subspecs.
         | 
| 37 | 
            +
                #
         | 
| 38 | 
            +
                attr_accessor :fail_fast
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                # @return [Boolean] whether the validation should be performed against the root of
         | 
| 41 | 
            +
                #         the podspec instead to its original source.
         | 
| 42 | 
            +
                #
         | 
| 43 | 
            +
                #
         | 
| 44 | 
            +
                attr_accessor :local
         | 
| 45 | 
            +
                alias local? local
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                # @return [Boolean] Whether the validator should fail on warnings, or only on errors.
         | 
| 48 | 
            +
                #
         | 
| 49 | 
            +
                attr_accessor :allow_warnings
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                # @return [String] name of the subspec to check, if nil all subspecs are checked.
         | 
| 52 | 
            +
                #
         | 
| 53 | 
            +
                attr_accessor :only_subspecs
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                # @return [Boolean] Whether frameworks should be used for the installation.
         | 
| 56 | 
            +
                #
         | 
| 57 | 
            +
                attr_accessor :use_frameworks
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                # @return [Boolean] Whether modular headers should be used for the installation.
         | 
| 60 | 
            +
                #
         | 
| 61 | 
            +
                attr_accessor :use_modular_headers
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                # @return [Boolean] Whether static frameworks should be used for the installation.
         | 
| 64 | 
            +
                #
         | 
| 65 | 
            +
                attr_accessor :use_static_frameworks
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                # @return [String] A glob for podspecs to be used during building of
         | 
| 68 | 
            +
                #         the local Podfile via :path.
         | 
| 69 | 
            +
                #
         | 
| 70 | 
            +
                attr_accessor :include_podspecs
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                # @return [String] A glob for podspecs to be used during building of
         | 
| 73 | 
            +
                #         the local Podfile via :podspec.
         | 
| 74 | 
            +
                #
         | 
| 75 | 
            +
                attr_accessor :external_podspecs
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                # !@group Helpers
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                # @return [Array<String>] an array of source URLs used to create the
         | 
| 80 | 
            +
                #         {Podfile} used in the linting process
         | 
| 81 | 
            +
                #
         | 
| 82 | 
            +
                attr_reader :source_urls
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                # @return configuration
         | 
| 85 | 
            +
                #
         | 
| 86 | 
            +
                attr_accessor :configuration
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                #-------------------------------------------------------------------------#
         | 
| 89 | 
            +
                # @return [Boolean]
         | 
| 90 | 
            +
                #
         | 
| 8 91 |  | 
| 9 92 | 
             
                # Initialize a new instance
         | 
| 10 93 | 
             
                #
         | 
| @@ -26,168 +109,136 @@ module ProjectGen | |
| 26 109 | 
             
                #
         | 
| 27 110 | 
             
                # @param  [Boolean] Whether modular headers should be used for the installation.
         | 
| 28 111 | 
             
                #
         | 
| 29 | 
            -
                def self.new_from_local(podspecs, source_urls, platforms = [], product_type = :framework, configuration = :release, swift_version = nil, use_modular_headers: false)
         | 
| 30 | 
            -
                  generator = new( | 
| 31 | 
            -
                  generator.local =  | 
| 32 | 
            -
                  generator.no_subspecs | 
| 33 | 
            -
                  generator. | 
| 112 | 
            +
                def self.new_from_local(podspecs = [], source_urls = [Pod::TrunkSource::TRUNK_REPO_URL], platforms = [], product_type = :framework, configuration = :release, swift_version = nil, use_modular_headers: false)
         | 
| 113 | 
            +
                  generator = new(source_urls, platforms)
         | 
| 114 | 
            +
                  generator.local = true
         | 
| 115 | 
            +
                  generator.no_subspecs = true
         | 
| 116 | 
            +
                  generator.only_subspecs = nil
         | 
| 34 117 | 
             
                  generator.no_clean       = false
         | 
| 35 118 | 
             
                  generator.allow_warnings = true
         | 
| 36 119 | 
             
                  generator.use_frameworks = product_type == :dynamic_framework
         | 
| 37 120 | 
             
                  generator.use_static_frameworks = product_type == :framework
         | 
| 38 | 
            -
                  generator. | 
| 39 | 
            -
                  generator.external_podspecs = podspecs.drop(1)
         | 
| 121 | 
            +
                  generator.include_podspecs = podspecs
         | 
| 40 122 | 
             
                  generator.configuration = configuration
         | 
| 41 | 
            -
                  generator.skip_tests = true
         | 
| 42 123 | 
             
                  generator.use_modular_headers = use_modular_headers
         | 
| 43 | 
            -
                  generator.swift_version = swift_version | 
| 124 | 
            +
                  generator.swift_version = swift_version
         | 
| 44 125 | 
             
                  generator
         | 
| 45 126 | 
             
                end
         | 
| 46 127 |  | 
| 128 | 
            +
                # Initialize a new instance
         | 
| 129 | 
            +
                #
         | 
| 130 | 
            +
                # @param  [Array<String>] source_urls
         | 
| 131 | 
            +
                #         the Source URLs to use in creating a {Podfile}.
         | 
| 132 | 
            +
                #
         | 
| 133 | 
            +
                # @param  [Array<String>] platforms
         | 
| 134 | 
            +
                #         the platforms to lint.
         | 
| 135 | 
            +
                #
         | 
| 136 | 
            +
                def initialize(source_urls, platforms = [])
         | 
| 137 | 
            +
                  @source_urls = source_urls.map { |url| config.sources_manager.source_with_name_or_url(url) }.map(&:url)
         | 
| 138 | 
            +
                  @platforms = platforms.map do |platform|
         | 
| 139 | 
            +
                    result =  case platform.to_s.downcase
         | 
| 140 | 
            +
                              # Platform doesn't recognize 'macos' as being the same as 'osx' when initializing
         | 
| 141 | 
            +
                              when 'macos' then Pod::Platform.macos
         | 
| 142 | 
            +
                              else Pod::Platform.new(platform, nil)
         | 
| 143 | 
            +
                              end
         | 
| 144 | 
            +
                    unless Constants.valid_platform?(result)
         | 
| 145 | 
            +
                      raise Informative, "Unrecognized platform `#{platform}`. Valid platforms: #{VALID_PLATFORMS.join(', ')}"
         | 
| 146 | 
            +
                    end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                    result
         | 
| 149 | 
            +
                  end
         | 
| 150 | 
            +
                  @allow_warnings = true
         | 
| 151 | 
            +
                  @use_frameworks = true
         | 
| 152 | 
            +
                  @use_latest = true
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
             | 
| 47 155 | 
             
                # Create app project
         | 
| 48 | 
            -
                # | 
| 156 | 
            +
                #
         | 
| 49 157 | 
             
                # @param [String, Pathname] dir the temporary directory used by the Gen.
         | 
| 50 158 | 
             
                #
         | 
| 51 | 
            -
                # @param  [block< | 
| 52 | 
            -
                #
         | 
| 53 | 
            -
                def generate!( | 
| 54 | 
            -
                   | 
| 55 | 
            -
                  @results =  | 
| 56 | 
            -
                   | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 159 | 
            +
                # @param  [block<platforms, pod_targets, valid>] &block the block to execute inside the lock.
         | 
| 160 | 
            +
                #
         | 
| 161 | 
            +
                def generate!(work_dir, &block)
         | 
| 162 | 
            +
                  @project_gen_dir = Pathname(work_dir)
         | 
| 163 | 
            +
                  @results = Results.new
         | 
| 164 | 
            +
                  unless config.silent?
         | 
| 165 | 
            +
                    podspecs.each do |spec|
         | 
| 166 | 
            +
                      subspecs = determine_subspecs[spec]
         | 
| 167 | 
            +
                      if subspecs && !subspecs.empty?
         | 
| 168 | 
            +
                        subspecs.each { |s| Results.puts " -> #{s}\r\n" }
         | 
| 169 | 
            +
                      else
         | 
| 170 | 
            +
                        Results.puts " -> #{spec.name}\r\n"
         | 
| 171 | 
            +
                      end
         | 
| 172 | 
            +
                    end
         | 
| 62 173 | 
             
                  end
         | 
| 63 | 
            -
                  @validation_dir = dir
         | 
| 64 | 
            -
                  Pod::UI.print " -> #{a_spec ? a_spec.name : file.basename}\r" unless config.silent?
         | 
| 65 174 | 
             
                  $stdout.flush
         | 
| 66 | 
            -
                   | 
| 67 | 
            -
                   | 
| 68 | 
            -
                   | 
| 69 | 
            -
                   | 
| 175 | 
            +
                  perform_linting
         | 
| 176 | 
            +
                  platforms, pod_targets, valid = install
         | 
| 177 | 
            +
                  @results.print_results
         | 
| 178 | 
            +
                  block.call(platforms, pod_targets, @clean, @fail_fast) if !block.nil? && valid
         | 
| 70 179 | 
             
                end
         | 
| 71 180 |  | 
| 72 | 
            -
                 | 
| 73 | 
            -
             | 
| 181 | 
            +
                # @return [Pathname] the temporary directory used by the linter.
         | 
| 182 | 
            +
                #
         | 
| 183 | 
            +
                def project_gen_dir
         | 
| 184 | 
            +
                  @project_gen_dir ||= Pathname(Dir.mktmpdir(['cocoapods-project-gen-', "-#{spec.name}"]))
         | 
| 74 185 | 
             
                end
         | 
| 75 186 |  | 
| 76 187 | 
             
                private
         | 
| 77 188 |  | 
| 78 | 
            -
                 | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
                     | 
| 83 | 
            -
             | 
| 84 | 
            -
                  end
         | 
| 85 | 
            -
                  platforms = send(:platforms_to_lint, spec)
         | 
| 86 | 
            -
                  valid = platforms.send(fail_fast ? :all? : :each) do |platform|
         | 
| 87 | 
            -
                    Pod::UI.message "\n\n#{spec} - Analyzing on #{platform} platform.".green.reversed
         | 
| 88 | 
            -
                    @consumer = spec.consumer(platform)
         | 
| 89 | 
            -
                    c_method = %i[setup_validation_environment create_app_project handle_local_pod
         | 
| 90 | 
            -
                                  check_file_patterns install_pod validate_swift_version
         | 
| 91 | 
            -
                                  add_app_project_import validate_vendored_dynamic_frameworks]
         | 
| 189 | 
            +
                def install
         | 
| 190 | 
            +
                  podspec = podspecs.find(&:non_library_specification?)
         | 
| 191 | 
            +
                  if podspec
         | 
| 192 | 
            +
                    error('spec', "Validating a non library spec (`#{podspec.name}`) is not supported.")
         | 
| 193 | 
            +
                    [determine_platforms, specs_for_pods, false]
         | 
| 194 | 
            +
                  else
         | 
| 92 195 | 
             
                    begin
         | 
| 93 | 
            -
                       | 
| 196 | 
            +
                      setup_gen_environment
         | 
| 197 | 
            +
                      create_app_project
         | 
| 198 | 
            +
                      download_or_copy_pod
         | 
| 199 | 
            +
                      install_pod
         | 
| 200 | 
            +
                      validate_swift_version
         | 
| 201 | 
            +
                      add_app_project_import
         | 
| 202 | 
            +
                      validate_vendored_dynamic_frameworks
         | 
| 94 203 | 
             
                      valid = validated?
         | 
| 204 | 
            +
                      results.note('Project gen', 'finish!') if valid
         | 
| 205 | 
            +
                      [determine_platforms, specs_for_pods, valid]
         | 
| 206 | 
            +
                    rescue StandardError => e
         | 
| 207 | 
            +
                      message = e.to_s
         | 
| 208 | 
            +
                      message << "\n" << e.backtrace.join("\n") << "\n" if config.verbose?
         | 
| 209 | 
            +
                      error('unknown', "Encountered an unknown error (#{message}) during validation.")
         | 
| 210 | 
            +
                      [determine_platforms, specs_for_pods, false]
         | 
| 95 211 | 
             
                    end
         | 
| 96 | 
            -
                    block.call(platform, pod_targets, valid) unless block&.nil?
         | 
| 97 | 
            -
                    return false if fail_fast && !valid
         | 
| 98 | 
            -
             | 
| 99 | 
            -
                    generate_subspec(spec, dir, &block) unless @no_subspecs
         | 
| 100 | 
            -
                  rescue StandardError => e
         | 
| 101 | 
            -
                    message = e.to_s
         | 
| 102 | 
            -
                    raise Pod::Informative, "Encountered an unknown error\n\n#{message})\n\n#{e.backtrace * "\n"}"
         | 
| 103 | 
            -
                  end
         | 
| 104 | 
            -
                end
         | 
| 105 | 
            -
             | 
| 106 | 
            -
                def generate_subspec(spec, dir, &block)
         | 
| 107 | 
            -
                  spec.subspecs.reject(&:non_library_specification?).send(fail_fast ? :all? : :each) do |subspec|
         | 
| 108 | 
            -
                    @subspec_name = subspec.name
         | 
| 109 | 
            -
                    install(subspec, dir, &block)
         | 
| 110 212 | 
             
                  end
         | 
| 111 213 | 
             
                end
         | 
| 112 214 |  | 
| 113 | 
            -
                def  | 
| 114 | 
            -
                  sandbox = Pod::Sandbox.new(@ | 
| 115 | 
            -
                   | 
| 116 | 
            -
                    ts.supported_on_platform?(consumer.platform_name)
         | 
| 117 | 
            -
                  end.map(&:name)
         | 
| 118 | 
            -
                  podfile = podfile_from_spec(consumer.platform_name, deployment_target, use_frameworks, test_spec_names,
         | 
| 119 | 
            -
                                              use_modular_headers, use_static_frameworks)
         | 
| 120 | 
            -
             | 
| 215 | 
            +
                def download_or_copy_pod
         | 
| 216 | 
            +
                  sandbox = Pod::Sandbox.new(@project_gen_dir + 'Pods')
         | 
| 217 | 
            +
                  podfile = podfile_from_spec(use_frameworks, use_modular_headers, use_static_frameworks)
         | 
| 121 218 | 
             
                  @installer = Pod::Installer.new(sandbox, podfile)
         | 
| 122 219 | 
             
                  @installer.use_default_plugins = false
         | 
| 123 | 
            -
                  @installer.has_dependencies = ! | 
| 124 | 
            -
                  %i[prepare resolve_dependencies  | 
| 220 | 
            +
                  @installer.has_dependencies = podspecs.any? { |podspec| !podspec.all_dependencies.empty? }
         | 
| 221 | 
            +
                  %i[prepare resolve_dependencies install_pod_sources run_podfile_pre_install_hooks clean_pod_sources
         | 
| 222 | 
            +
                     write_lockfiles].each do |m|
         | 
| 125 223 | 
             
                    case m
         | 
| 126 224 | 
             
                    when :clean_pod_sources
         | 
| 127 | 
            -
                      copy_and_clean(sandbox)
         | 
| 128 | 
            -
                       | 
| 225 | 
            +
                      ProjectGen::PodDirCopyCleaner.new(include_specifications).copy_and_clean(config.sandbox_root, sandbox)
         | 
| 226 | 
            +
                      include_specifications.each { |s| sandbox.development_pods.delete(s.name) }
         | 
| 129 227 | 
             
                      @installer.send(m)
         | 
| 130 228 | 
             
                    else
         | 
| 131 229 | 
             
                      @installer.send(m)
         | 
| 132 230 | 
             
                      next unless m == :resolve_dependencies
         | 
| 133 231 |  | 
| 134 | 
            -
                       | 
| 232 | 
            +
                      # local --> source in local
         | 
| 233 | 
            +
                      # no-local --> source from cdn
         | 
| 234 | 
            +
                      # external_podspecs --> source in cdn
         | 
| 235 | 
            +
                      # include_podspecs  --> source in local
         | 
| 236 | 
            +
                      include_specifications.each do |spec|
         | 
| 237 | 
            +
                        sandbox.store_local_path(spec.name, spec.defined_in_file, Utils.absolute?(spec.defined_in_file))
         | 
| 238 | 
            +
                      end
         | 
| 135 239 | 
             
                    end
         | 
| 136 240 | 
             
                  end
         | 
| 137 | 
            -
                   | 
| 138 | 
            -
                  add_swift_library_compatibility_header(library_targets)
         | 
| 139 | 
            -
                  @file_accessor = pod_targets.flat_map(&:file_accessors).find do |fa|
         | 
| 140 | 
            -
                    fa.spec.name == consumer.spec.name
         | 
| 141 | 
            -
                  end
         | 
| 142 | 
            -
                end
         | 
| 143 | 
            -
             | 
| 144 | 
            -
                def podspecs
         | 
| 145 | 
            -
                  ps = [file]
         | 
| 146 | 
            -
                  ps += external_podspecs.map { |pa| Pathname.new(pa) } if external_podspecs
         | 
| 147 | 
            -
                  ps += include_podspecs.map { |pa| Pathname.new(pa) } if include_podspecs
         | 
| 148 | 
            -
                  ps.uniq.map { |path| Pod::Specification.from_file(path) }
         | 
| 149 | 
            -
                end
         | 
| 150 | 
            -
             | 
| 151 | 
            -
                # @return [Bool]
         | 
| 152 | 
            -
                #
         | 
| 153 | 
            -
                def absolute?(path)
         | 
| 154 | 
            -
                  Pathname(path).absolute? || path.to_s.start_with?('~')
         | 
| 155 | 
            -
                end
         | 
| 156 | 
            -
             | 
| 157 | 
            -
                def group_subspecs_by_platform(spec)
         | 
| 158 | 
            -
                  specs_by_platform = {}
         | 
| 159 | 
            -
                  [spec, *spec.recursive_subspecs].each do |ss|
         | 
| 160 | 
            -
                    ss.available_platforms.each do |platform|
         | 
| 161 | 
            -
                      specs_by_platform[platform] ||= []
         | 
| 162 | 
            -
                      specs_by_platform[platform] << ss
         | 
| 163 | 
            -
                    end
         | 
| 164 | 
            -
                  end
         | 
| 165 | 
            -
                  specs_by_platform
         | 
| 166 | 
            -
                end
         | 
| 167 | 
            -
             | 
| 168 | 
            -
                def copy(source, destination, specs_by_platform)
         | 
| 169 | 
            -
                  path_list = Pod::Sandbox::PathList.new(source)
         | 
| 170 | 
            -
                  file_accessors = specs_by_platform.flat_map do |platform, specs|
         | 
| 171 | 
            -
                    specs.flat_map { |spec| Pod::Sandbox::FileAccessor.new(path_list, spec.consumer(platform)) }
         | 
| 172 | 
            -
                  end
         | 
| 173 | 
            -
                  used_files = Pod::Sandbox::FileAccessor.all_files(file_accessors)
         | 
| 174 | 
            -
                  used_files.each do |path|
         | 
| 175 | 
            -
                    path = Pathname(path)
         | 
| 176 | 
            -
                    n_path = destination.join(path.relative_path_from(source))
         | 
| 177 | 
            -
                    n_path.dirname.mkpath
         | 
| 178 | 
            -
                    FileUtils.cp_r(path, n_path.dirname)
         | 
| 179 | 
            -
                  end
         | 
| 180 | 
            -
                end
         | 
| 181 | 
            -
             | 
| 182 | 
            -
                def copy_and_clean(sandbox)
         | 
| 183 | 
            -
                  podspecs.each do |spec|
         | 
| 184 | 
            -
                    destination = config.sandbox_root + spec.name
         | 
| 185 | 
            -
                    source = sandbox.pod_dir(spec.name)
         | 
| 186 | 
            -
                    specs_by_platform = group_subspecs_by_platform(spec)
         | 
| 187 | 
            -
                    destination.parent.mkpath
         | 
| 188 | 
            -
                    FileUtils.rm_rf(destination)
         | 
| 189 | 
            -
                    copy(source, destination, specs_by_platform)
         | 
| 190 | 
            -
                  end
         | 
| 241 | 
            +
                  add_swift_library_compatibility_header(@installer.pod_targets)
         | 
| 191 242 | 
             
                end
         | 
| 192 243 | 
             
              end
         | 
| 193 244 | 
             
            end
         |