| require 'fileutils' |
| |
| module Pod |
| # The sandbox provides support for the directory that CocoaPods uses for an |
| # installation. In this directory the Pods projects, the support files and |
| # the sources of the Pods are stored. |
| # |
| # CocoaPods assumes to have control of the sandbox. |
| # |
| # Once completed the sandbox will have the following file structure: |
| # |
| # Pods |
| # | |
| # +-- Headers |
| # | +-- Private |
| # | | +-- [Pod Name] |
| # | +-- Public |
| # | +-- [Pod Name] |
| # | |
| # +-- Local Podspecs |
| # | +-- External Sources |
| # | +-- Normal Sources |
| # | |
| # +-- Target Support Files |
| # | +-- [Target Name] |
| # | +-- Pods-acknowledgements.markdown |
| # | +-- Pods-acknowledgements.plist |
| # | +-- Pods-dummy.m |
| # | +-- Pods-prefix.pch |
| # | +-- Pods.xcconfig |
| # | |
| # +-- [Pod Name] |
| # | |
| # +-- Manifest.lock |
| # | |
| # +-- Pods.xcodeproj |
| # |
| class Sandbox |
| autoload :FileAccessor, 'cocoapods/sandbox/file_accessor' |
| autoload :HeadersStore, 'cocoapods/sandbox/headers_store' |
| autoload :PathList, 'cocoapods/sandbox/path_list' |
| autoload :PodDirCleaner, 'cocoapods/sandbox/pod_dir_cleaner' |
| autoload :PodspecFinder, 'cocoapods/sandbox/podspec_finder' |
| |
| # @return [Pathname] the root of the sandbox. |
| # |
| attr_reader :root |
| |
| # @return [HeadersStore] the header directory for the user targets. |
| # |
| attr_reader :public_headers |
| |
| # Initialize a new instance |
| # |
| # @param [String, Pathname] root @see root |
| # |
| def initialize(root) |
| FileUtils.mkdir_p(root) |
| @root = Pathname.new(root).realpath |
| @public_headers = HeadersStore.new(self, 'Public') |
| @predownloaded_pods = [] |
| @checkout_sources = {} |
| @development_pods = {} |
| @pods_with_absolute_path = [] |
| end |
| |
| # @return [Lockfile] the manifest which contains the information about the |
| # installed pods. |
| # |
| attr_accessor :manifest |
| |
| def manifest |
| @manifest ||= begin |
| Lockfile.from_file(manifest_path) if manifest_path.exist? |
| end |
| end |
| |
| # @return [Project] the Pods project. |
| # |
| attr_accessor :project |
| |
| # Removes the files of the Pod with the given name from the sandbox. |
| # |
| # @return [void] |
| # |
| def clean_pod(name) |
| root_name = Specification.root_name(name) |
| unless local?(root_name) |
| path = pod_dir(name) |
| path.rmtree if path.exist? |
| end |
| podspec_path = specification_path(name) |
| podspec_path.rmtree if podspec_path |
| end |
| |
| # Prepares the sandbox for a new installation removing any file that will |
| # be regenerated and ensuring that the directories exists. |
| # |
| def prepare |
| FileUtils.rm_rf(headers_root) |
| |
| FileUtils.mkdir_p(headers_root) |
| FileUtils.mkdir_p(sources_root) |
| FileUtils.mkdir_p(specifications_root) |
| FileUtils.mkdir_p(target_support_files_root) |
| end |
| |
| # @return [String] a string representation suitable for debugging. |
| # |
| def inspect |
| "#<#{self.class}> with root #{root}" |
| end |
| |
| #-------------------------------------------------------------------------# |
| |
| public |
| |
| # @!group Paths |
| |
| # @return [Pathname] the path of the manifest. |
| # |
| def manifest_path |
| root + 'Manifest.lock' |
| end |
| |
| # @return [Pathname] the path of the Pods project. |
| # |
| def project_path |
| root + 'Pods.xcodeproj' |
| end |
| |
| # Returns the path for the directory where the support files of |
| # a target are stored. |
| # |
| # @param [String] name |
| # The name of the target. |
| # |
| # @return [Pathname] the path of the support files. |
| # |
| def target_support_files_dir(name) |
| target_support_files_root + name |
| end |
| |
| # Returns the path where the Pod with the given name is stored, taking into |
| # account whether the Pod is locally sourced. |
| # |
| # @param [String] name |
| # The name of the Pod. |
| # |
| # @return [Pathname] the path of the Pod. |
| # |
| def pod_dir(name) |
| root_name = Specification.root_name(name) |
| if local?(root_name) |
| Pathname.new(development_pods[root_name].dirname) |
| else |
| sources_root + root_name |
| end |
| end |
| |
| # Returns true if the path as originally specified was absolute. |
| # |
| # @param [String] name |
| # |
| # @return [Bool] true if originally absolute |
| # |
| def local_path_was_absolute?(name) |
| @pods_with_absolute_path.include? name |
| end |
| |
| # @return [Pathname] The directory where headers are stored. |
| # |
| def headers_root |
| root + 'Headers' |
| end |
| |
| # @return [Pathname] The directory where the downloaded sources of |
| # the Pods are stored. |
| # |
| def sources_root |
| root |
| end |
| |
| # @return [Pathname] the path for the directory where the |
| # specifications are stored. |
| # |
| def specifications_root |
| root + 'Local Podspecs' |
| end |
| |
| # @return [Pathname] The directory where the files generated by |
| # CocoaPods to support the umbrella targets are stored. |
| # |
| def target_support_files_root |
| root + 'Target Support Files' |
| end |
| |
| #-------------------------------------------------------------------------# |
| |
| public |
| |
| # @!group Specification store |
| |
| # Returns the specification for the Pod with the given name. |
| # |
| # @param [String] name |
| # the name of the Pod for which the specification is requested. |
| # |
| # @return [Specification] the specification if the file is found. |
| # |
| def specification(name) |
| if file = specification_path(name) |
| original_path = development_pods[name] |
| Specification.from_file(original_path || file) |
| end |
| end |
| |
| # Returns the path of the specification for the Pod with the |
| # given name, if one is stored. |
| # |
| # @param [String] name |
| # the name of the Pod for which the podspec file is requested. |
| # |
| # @return [Pathname] the path or nil. |
| # @return [Nil] if the podspec is not stored. |
| # |
| def specification_path(name) |
| name = Specification.root_name(name) |
| path = specifications_root + "#{name}.podspec" |
| if path.exist? |
| path |
| else |
| path = specifications_root + "#{name}.podspec.json" |
| if path.exist? |
| path |
| end |
| end |
| end |
| |
| # Stores a specification in the `Local Podspecs` folder. |
| # |
| # @param [String] name |
| # the name of the pod |
| # |
| # @param [String, Pathname] podspec |
| # The contents of the specification (String) or the path to a |
| # podspec file (Pathname). |
| # |
| # @return [void] |
| # |
| # |
| def store_podspec(name, podspec, _external_source = false, json = false) |
| file_name = json ? "#{name}.podspec.json" : "#{name}.podspec" |
| output_path = specifications_root + file_name |
| output_path.dirname.mkpath |
| if podspec.is_a?(String) |
| output_path.open('w') { |f| f.puts(podspec) } |
| else |
| unless podspec.exist? |
| raise Informative, "No podspec found for `#{name}` in #{podspec}" |
| end |
| FileUtils.copy(podspec, output_path) |
| end |
| |
| Dir.chdir(podspec.is_a?(Pathname) ? File.dirname(podspec) : Dir.pwd) do |
| spec = Specification.from_file(output_path) |
| |
| unless spec.name == name |
| raise Informative, "The name of the given podspec `#{spec.name}` doesn't match the expected one `#{name}`" |
| end |
| end |
| end |
| |
| #-------------------------------------------------------------------------# |
| |
| public |
| |
| # @!group Pods information |
| |
| # Marks a Pod as pre-downloaded |
| # |
| # @param [String] name |
| # The name of the Pod. |
| # |
| # @return [void] |
| # |
| def store_pre_downloaded_pod(name) |
| root_name = Specification.root_name(name) |
| predownloaded_pods << root_name |
| end |
| |
| # @return [Array<String>] The names of the pods that have been |
| # pre-downloaded from an external source. |
| # |
| attr_reader :predownloaded_pods |
| |
| # Checks if a Pod has been pre-downloaded by the resolver in order to fetch |
| # the podspec. |
| # |
| # @param [String] name |
| # The name of the Pod. |
| # |
| # @return [Bool] Whether the Pod has been pre-downloaded. |
| # |
| def predownloaded?(name) |
| root_name = Specification.root_name(name) |
| predownloaded_pods.include?(root_name) |
| end |
| |
| #--------------------------------------# |
| |
| # Stores the local path of a Pod. |
| # |
| # @param [String] name |
| # The name of the Pod. |
| # |
| # @param [Hash] source |
| # The hash which contains the options as returned by the |
| # downloader. |
| # |
| # @return [void] |
| # |
| def store_checkout_source(name, source) |
| root_name = Specification.root_name(name) |
| checkout_sources[root_name] = source |
| end |
| |
| # Removes the checkout source of a Pod. |
| # |
| # @param [String] name |
| # The name of the Pod. |
| # |
| # @return [void] |
| # |
| def remove_checkout_source(name) |
| root_name = Specification.root_name(name) |
| checkout_sources.delete(root_name) |
| end |
| |
| # @return [Hash{String=>Hash}] The options necessary to recreate the exact |
| # checkout of a given Pod grouped by its name. |
| # |
| attr_reader :checkout_sources |
| |
| #--------------------------------------# |
| |
| # Stores the local path of a Pod. |
| # |
| # @param [String] name |
| # The name of the Pod. |
| # |
| # @param [Pathname, String] path |
| # The path to the local Podspec |
| # |
| # @param [Bool] was_absolute |
| # True if the specified local path was absolute. |
| # |
| # @return [void] |
| # |
| def store_local_path(name, path, was_absolute = false) |
| root_name = Specification.root_name(name) |
| path = Pathname.new(path) unless path.is_a?(Pathname) |
| development_pods[root_name] = path |
| @pods_with_absolute_path << root_name if was_absolute |
| end |
| |
| # @return [Hash{String=>Pathname}] The path of the Pods' podspecs with a local source |
| # grouped by their root name. |
| # |
| # @todo Rename (e.g. `pods_with_local_path`) |
| # |
| attr_reader :development_pods |
| |
| # Checks if a Pod is locally sourced? |
| # |
| # @param [String] name |
| # The name of the Pod. |
| # |
| # @return [Bool] Whether the Pod is locally sourced. |
| # |
| def local?(name) |
| !local_podspec(name).nil? |
| end |
| |
| # @param [String] name |
| # The name of a locally specified Pod |
| # |
| # @return [Pathname] Path to the local Podspec of the Pod |
| # |
| def local_podspec(name) |
| root_name = Specification.root_name(name) |
| if path = development_pods[root_name] |
| Pathname.new(path) |
| end |
| end |
| |
| #-------------------------------------------------------------------------# |
| |
| public |
| |
| # @!group Pods Helpers |
| |
| # Creates the file accessors for the given Pod Targets. |
| # |
| # @param [Array<PodTarget>] pod_targets |
| # The Pod Targets to create file accessors for. |
| # |
| def create_file_accessors(pod_targets) |
| pod_targets.each do |pod_target| |
| pod_root = pod_dir(pod_target.root_spec.name) |
| path_list = PathList.new(pod_root) |
| file_accessors = pod_target.specs.map do |spec| |
| FileAccessor.new(path_list, spec.consumer(pod_target.platform)) |
| end |
| pod_target.file_accessors ||= [] |
| pod_target.file_accessors.concat(file_accessors) |
| end |
| end |
| |
| #-------------------------------------------------------------------------# |
| end |
| end |