Commit a583e50a authored by Fabio Pelosin's avatar Fabio Pelosin

[Sandbox] Clean up.

This includes a fix for an issue which caused the use of the incorrect
specification for dependencies from external sources.

Closes #548.
parent 170fa2e4
......@@ -38,6 +38,11 @@
- It is now possible to specify default values for the configuration in `~/.cocoapods/config.yaml`.
- CocoaPods now keeps track of the checksum of the specifications of the installed Pods and reinstalls them if needed.
###### Bug fixes
- CocoaPods is not confused anymore by to dependencies from external sources.
[#548](https://github.com/CocoaPods/CocoaPods/issues/548)
###### Codebase
- Major clean up and refactor of the whole code base, with great reduction of
......
......@@ -84,9 +84,11 @@ module Pod
attr_accessor :update_mode
alias_method :update_mode?, :update_mode
# @return [Bool] Whether the analysis allows predownloads and thus
# @return [Bool] Whether the analysis allows pre-downloads and thus
# modifications to the sandbox.
#
# @note This flag should not be used in installations.
#
# @note This is used by the `pod outdated` command to prevent
# modification of the sandbox in the resolution process.
#
......@@ -186,7 +188,7 @@ module Pod
libraries = []
podfile.target_definitions.values.each do |target_definition|
lib = Library.new(target_definition)
lib.support_files_root = config.sandbox.root
lib.support_files_root = config.sandbox.library_support_files_dir(lib.name)
if config.integrate_targets?
lib.user_project_path = compute_user_project_path(target_definition)
......@@ -231,8 +233,13 @@ module Pod
# @note As some dependencies might have external sources the resolver is
# aware of the {Sandbox} and interacts with it to download the
# podspecs of the external sources. This is necessary because the
# resolver needs the specifications to analyze their dependencies
# (which might be from external sources).
# resolver needs their specifications to analyze their
# dependencies.
#
# @note The specifications of the external sources which are added,
# modified or removed need to deleted from the sandbox before the
# resolution process. Otherwise the resolver might use an incorrect
# specification instead of pre-downloading it.
#
# @note In update mode the resolver is set to always update the specs
# from external sources.
......@@ -243,6 +250,14 @@ module Pod
def resolve_dependencies
specs_by_target = nil
if allow_pre_downloads?
changed_pods = podfile_state.added + podfile_state.changed + podfile_state.deleted
changed_pods.each do |pod_name|
podspec = sandbox.specification_path(pod_name)
podspec.delete if podspec
end
end
UI.section "Resolving dependencies of #{UI.path podfile.defined_in_file}" do
resolver = Resolver.new(sandbox, podfile, locked_dependencies)
resolver.update_external_specs = update_mode?
......
......@@ -27,6 +27,7 @@ module Pod
# source control.
#
class Installer
autoload :TargetInstaller, 'cocoapods/installer/target_installer'
autoload :UserProjectIntegrator, 'cocoapods/installer/user_project_integrator'
......@@ -74,9 +75,6 @@ module Pod
# necessary to retrieve their podspec (unless it is instructed not to
# do it).
#
# @note The order of the steps is very important and should be changed
# carefully.
#
# @return [void]
#
def install!
......@@ -85,9 +83,7 @@ module Pod
generate_names_of_pods_to_install
prepare_for_legacy_compatibility
clean_global_support_files
clean_removed_pods
clean_pods_to_install
prepare_sandbox
install_dependencies
install_targets
write_lockfiles
......@@ -127,6 +123,8 @@ module Pod
#
attr_reader :names_of_pods_to_install
attr_reader :libraries
#-------------------------------------------------------------------------#
# @!group Installation steps
......@@ -137,6 +135,7 @@ module Pod
@analyzer = Analyzer.new(sandbox, podfile, lockfile)
@analyzer.update_mode = update_mode
@analyzer.analyze
@libraries = analyzer.libraries
end
# Converts the specifications produced by the Resolver in local pods.
......@@ -146,8 +145,8 @@ module Pod
#
# @return [void]
#
# @todo [#535] LocalPods should resolve the specification passing the
# library.
# @todo [#535] LocalPods should resolve the path of the specifications
# passing the library as arguments.
#
# @todo Why the local pods are generated by the sandbox? I guess because
# some where pre-downloaded? However the sandbox should just store
......@@ -156,16 +155,27 @@ module Pod
def generate_local_pods
@local_pods_by_target = {}
analyzer.specs_by_target.each do |target_definition, specs|
@local_pods_by_target[target_definition] = specs.map do |spec|
libray = libraries.find {|l| l.target_definition == target_definition }
# TODO the sanbox cached the local pods by target definition
# take into account local? in specification#==
locally_sourced_pods = {}
local_pods = {}
libray.local_pods = specs.map do |spec|
if spec.local?
sandbox.locally_sourced_pod_for_spec(spec, target_definition.platform)
local_pod = (locally_sourced_pods[spec.root.name] ||= LocalPod::LocalSourcedPod.new(spec.root, sandbox, target_definition.platform))
local_pod.add_specification(spec)
else
sandbox.local_pod_for_spec(spec, target_definition.platform)
local_pod = (local_pods[spec.root.name] ||= LocalPod.new(spec.root, sandbox, target_definition.platform))
local_pod.add_specification(spec)
end
local_pod
end.uniq.compact
end
@local_pods = local_pods_by_target.values.flatten.uniq.sort_by { |pod| pod.name.downcase }
@local_pods = libraries.map(&:local_pods).flatten.uniq.sort_by { |pod| pod.name.downcase }
end
# Computes the list of the Pods that should be installed or reinstalled in
......@@ -215,36 +225,26 @@ module Pod
# @todo Clean the podspecs of all the pods that aren't unchanged so the
# resolution process doesn't get confused by them.
#
def clean_global_support_files
sandbox.prepare_for_install
end
# @return [void] In this step we clean all the files related to the removed
# Pods.
# @todo [#247] Clean the headers of only the pods to install.
#
# @todo Use the local pod implode.
#
# @todo [#534] Clean all the Pods folder that are not unchanged?
# @todo [#534] Clean all the Pods folder that are not unchanged
#
def clean_removed_pods
UI.section "Removing deleted dependencies" do
pods_deleted_from_the_lockfile.each do |pod_name|
UI.section("Removing #{pod_name}", "-> ".red) do
path = sandbox.root + pod_name
path.rmtree if path.exist?
def prepare_sandbox
sandbox.build_headers.implode!
sandbox.public_headers.implode!
unless analyzer.sandbox_state.deleted.empty?
UI.section "Removing deleted dependencies" do
pods_deleted_from_the_lockfile.each do |pod_name|
UI.section("Removing #{pod_name}", "-> ".red) do
path = sandbox.root + pod_name
path.rmtree if path.exist?
end
end
end
end unless analyzer.sandbox_state.deleted.empty?
end
# @return [void] In this step we clean the files of the Pods that will be
# installed. We clean the files that might affect the resolution
# process and the files that might not be overwritten.
#
# @todo [#247] Clean the headers of only the pods to install.
#
def clean_pods_to_install
end
end
# @return [void] Install the Pods. If the resolver indicated that a Pod
......@@ -274,14 +274,8 @@ module Pod
# @note In this step we clean also the Pods that have been pre-downloaded
# in AbstractExternalSource#specification_from_sandbox.
#
# @todo [#529] Podspecs should not be preserved anymore to prevent user
# confusion. Currently we are copying the ones form external sources
# in `Local Podspecs` and this feature is not needed anymore.
# I think that copying all the used podspecs would be helpful for
# debugging.
#
def install_local_pod(pod)
unless pod.downloaded?
unless sandbox.predownloaded_pods.include?(pod.name)
pod.implode
download_pod(pod)
end
......@@ -356,10 +350,12 @@ module Pod
#
def prepare_pods_project
UI.message "- Creating Pods project" do
@pods_project = Pod::Project.new(config.sandbox)
@pods_project = Pod::Project.new(nil)
if config.podfile_path.exist?
@pods_project.add_podfile(config.podfile_path)
podfile_relative_path = config.podfile_path.relative_path_from(sandbox.project_path.dirname)
@pods_project.add_podfile(podfile_relative_path)
end
sandbox.project = @pods_project
end
end
......@@ -368,10 +364,10 @@ module Pod
# @return [void]
#
def generate_target_installers
@target_installers = podfile.target_definitions.values.map do |definition|
pods_for_target = local_pods_by_target[definition]
libray = analyzer.libraries.find {|l| l.target_definition == definition }
TargetInstaller.new(pods_project, libray, pods_for_target) unless definition.empty?
@target_installers = libraries.map do |library|
unless library.target_definition.empty?
TargetInstaller.new(sandbox, library)
end
end.compact
end
......@@ -441,11 +437,10 @@ module Pod
def generate_target_support_files
UI.message"- Installing targets" do
target_installers.each do |target_installer|
pods_for_target = local_pods_by_target[target_installer.library.target_definition]
target_installer.install!
acknowledgements_path = target_installer.library.acknowledgements_path
Generator::Acknowledgements.new(target_installer.library.target_definition,
pods_for_target).save_as(acknowledgements_path)
target_installer.library.local_pods).save_as(acknowledgements_path)
generate_dummy_source(target_installer)
end
end
......@@ -511,7 +506,7 @@ module Pod
#
def integrate_user_project
return unless config.integrate_targets?
UserProjectIntegrator.new(podfile, pods_project, config.project_root, analyzer.libraries).integrate!
UserProjectIntegrator.new(podfile, sandbox, config.project_root, analyzer.libraries).integrate!
end
end
end
......@@ -7,27 +7,21 @@ module Pod
#
class TargetInstaller
# @return [Project] The Pods project.
# @return [Sandbox] sandbox the sandbox where the support files should
# be generated.
#
attr_reader :project
attr_reader :sandbox
# @return [Library] The library whose target needs to be generated.
#
attr_reader :library
# @return [Array<LocalPod>] The pods are required by the target
# definition of this installer.
#
attr_reader :pods
# @param [Project] project @see project
# @param [TargetDefinition] target_definition @see target_definition
# @param [Array<LocalPod>] pods @see pods
#
def initialize(project, library, pods)
@project = project
def initialize(sandbox, library)
@sandbox = sandbox
@library = library
@pods = pods
end
# Creates the target in the Pods project and its support files.
......@@ -211,11 +205,14 @@ module Pod
attr_reader :xcconfig_file_ref
# @return [Sandbox] sandbox the sandbox where the support files should
# be generated.
# @return [Project] the Pods project of the sandbox.
#
def sandbox
project.sandbox
def project
sandbox.project
end
def pods
library.local_pods
end
# @return [TargetDefinition] the target definition of the library.
......
......@@ -21,7 +21,9 @@ module Pod
# @return [Project] the pods project which contains the libraries to
# integrate.
#
attr_reader :pods_project
# attr_reader :pods_project
attr_reader :sandbox
# @return [Pathname] the path of the installation.
#
......@@ -35,16 +37,16 @@ module Pod
#
attr_reader :libraries
# @param [Podfile] podfile @see #podfile.
# @param [Project] pods_project @see #pods_project.
# @param [Pathname] project_root @see #project_root.
# @param [Library] libraries @see #libraries.
# @param [Podfile] podfile @see #podfile
# @param [Sandbox] sandbox @see #sandbox
# @param [Pathname] project_root @see #project_root
# @param [Library] libraries @see #libraries
#
# @todo Too many initialization arguments
#
def initialize(podfile, pods_project, project_root, libraries)
def initialize(podfile, sandbox, project_root, libraries)
@podfile = podfile
@pods_project = pods_project
@sandbox = sandbox
@project_root = project_root
@libraries = libraries
end
......@@ -73,7 +75,7 @@ module Pod
#
def create_workspace
workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
[pods_project.path, *user_project_paths].each do |project_path|
[sandbox.project_path, *user_project_paths].each do |project_path|
path = project_path.relative_path_from(workspace_path.dirname).to_s
workspace << path unless workspace.include?(path)
end
......@@ -191,7 +193,7 @@ module Pod
@targets ||= library.user_targets.reject do |target|
target.frameworks_build_phase.files.any? do |build_file|
file_ref = build_file.file_ref
!file_ref.proxy? && file_ref.display_name == library.name
!file_ref.proxy? && file_ref.display_name == library.product_name
end
end
end
......@@ -311,7 +313,7 @@ module Pod
# integration.
#
def integration_message
"Integrating `#{library.name}' into " \
"Integrating `#{library.product_name}` into " \
"#{'target'.pluralize(targets.size)} " \
"`#{targets.map(&:name).to_sentence}` " \
"of project #{UI.path library.user_project_path}."
......
......@@ -29,6 +29,12 @@ module Pod
# @return [String] the name of the library.
#
def name
target_definition.label.to_s
end
# @return [String] the name of the library.
#
def product_name
"lib#{target_definition.label}.a"
end
......@@ -82,6 +88,10 @@ module Pod
#
attr_accessor :specs
# @return [Array<LocalPod>] the pods of the library.
#
attr_accessor :local_pods
#-------------------------------------------------------------------------#
# @!group Support files
......
......@@ -160,6 +160,12 @@ module Pod
# Deletes any path that is not used by the pod.
#
# @todo [#529] Podspecs should not be preserved anymore to prevent user
# confusion. Currently we are copying the ones form external sources
# in `Local Podspecs` and this feature is not needed anymore.
# I think that copying all the used podspecs would be helpful for
# debugging.
#
# @return [void]
#
def clean!
......@@ -491,15 +497,14 @@ module Pod
# @return [void] Copies the pods headers to the sandbox.
#
def link_headers
@sandbox.build_headers.add_search_path(headers_sandbox)
@sandbox.public_headers.add_search_path(headers_sandbox)
sandbox.build_headers.add_search_path(headers_sandbox)
header_mappings(header_files_by_spec).each do |namespaced_path, files|
@sandbox.build_headers.add_files(namespaced_path, files)
sandbox.build_headers.add_files(namespaced_path, files)
end
sandbox.public_headers.add_search_path(headers_sandbox)
header_mappings(public_header_files_by_spec).each do |namespaced_path, files|
@sandbox.public_headers.add_files(namespaced_path, files)
sandbox.public_headers.add_files(namespaced_path, files)
end
end
......
......@@ -11,23 +11,17 @@ module Pod
# @return [Sandbox] the sandbox that contains the project.
#
attr_reader :sandbox
# attr_reader :sandbox
# @param [Sandbox] sandbox @see #sandbox
#
def initialize(sandbox)
super(nil)
@sandbox = sandbox
def initialize(xcodeproj = nil)
super
# @sandbox = sandbox
@support_files_group = new_group('Targets Support Files')
@libraries = []
end
# @return [Pathname] the path of the Pods project.
#
def path
sandbox.project_path
end
# @return [String] a string representation suited for debugging.
#
def inspect
......@@ -90,7 +84,7 @@ module Pod
#
def add_podfile(podfile_path)
podfile_path = Pathname.new(podfile_path)
podfile_ref = new_file(podfile_path.relative_path_from(path.dirname))
podfile_ref = new_file(podfile_path)
podfile_ref.xc_language_specification_identifier = 'xcode.lang.ruby'
podfile_ref
end
......
......@@ -35,71 +35,40 @@ module Pod
# |
# +-- Pods.xcodeproj
#
# @todo outdated pods triggers the resolution process which might pre-download
# some pods.
#
class Sandbox
# The path of the build headers directory relative to the root.
#
BUILD_HEADERS_DIR = "BuildHeaders"
# The path of the public headers directory relative to the root.
#
PUBLIC_HEADERS_DIR = "Headers"
# @return [Pathname] the root of the sandbox.
#
attr_reader :root
# @return [HeadersDirectory] the header directory for the Pods libraries.
# @return [HeadersStore] the header directory for the Pods libraries.
#
attr_reader :build_headers
# @return [HeadersDirectory] the header directory for the user targets.
# @return [HeadersStore] the header directory for the user targets.
#
attr_reader :public_headers
# @param [String, Pathname] root @see root
#
# @todo the headers should be stored in a `Headers` folder.
#
def initialize(root)
@root = Pathname.new(root)
@build_headers = HeadersDirectory.new(self, BUILD_HEADERS_DIR)
@public_headers = HeadersDirectory.new(self, PUBLIC_HEADERS_DIR)
@cached_local_pods = {}
@cached_locally_sourced_pods = {}
@build_headers = HeadersStore.new(self, "BuildHeaders")
@public_headers = HeadersStore.new(self, "Headers")
@predownloaded_pods = []
FileUtils.mkdir_p(@root)
end
# @return [Pathname] the path of the Pod project.
# @return [Lockfile] the manifest which contains the information about the
# installed pods.
#
def project_path
root + "Pods.xcodeproj"
end
# @return [String] a string representation suitable for debugging.
#
def inspect
"#<#{self.class}> with root #{root}"
def manifest
Lockfile.from_file(manifest_path) if manifest_path.exist?
end
#--------------------------------------#
# @!group Life cycle
public
# Cleans the sandbox for a new installation.
#
# @return [void]
# @return [Project] the Pods project.
#
def prepare_for_install
build_headers.prepare_for_install
public_headers.prepare_for_install
end
attr_accessor :project
# Removes the sandbox.
#
......@@ -109,52 +78,59 @@ module Pod
root.rmtree
end
#--------------------------------------#
# @return [String] a string representation suitable for debugging.
#
def inspect
"#<#{self.class}> with root #{root}"
end
# @!group Manifest
#--------------------------------------#
public
# @!group Paths
# @return [Pathname] the path of the manifest.
#
def manifest_path
root + "Manifest.lock"
end
def manifest
Lockfile.from_file(manifest_path) if manifest_path.exist?
# @return [Pathname] the path of the Pods project.
#
def project_path
root + "Pods.xcodeproj"
end
#--------------------------------------#
# @!group Local Pod support
public
# @todo Refactor the pods from a local source should not be cached by the
# sandbox.
# Returns the path for the Pod with the given name.
#
# @return [LocalPod]
# @param [String] name
# The name of the Pod.
#
# @return [Pathname] the path of the Pod.
#
def locally_sourced_pod_for_spec(spec, platform)
key = [spec.root.name, platform.to_sym]
local_pod = @cached_locally_sourced_pods[key] ||= LocalPod::LocalSourcedPod.new(spec.root, self, platform)
local_pod.add_specification(spec)
local_pod
def pod_dir(name)
# root + "Sources/#{name}"
root + name
end
def local_pod_for_spec(spec, platform)
key = [spec.root.name, platform.to_sym]
(@cached_local_pods[key] ||= LocalPod.new(spec.root, self, platform)).tap do |pod|
pod.add_specification(spec)
end
# Returns the path for the directory where to store the support files of
# a target.
#
# @param [String] name
# The name of the target.
#
# @return [Pathname] the path of the support files.
#
def library_support_files_dir(name)
# root + "Target Support Files/#{name}"
root
end
# @return [LocalPod]
# @return [Pathname] the path for the directory where to store the
# specifications.
#
def installed_pod_named(name, platform)
if spec_path = podspec_for_name(name)
key = [name, platform.to_sym]
@cached_local_pods[key] ||= LocalPod.from_podspec(spec_path, self, platform)
end
def specifications_dir
# root + "Specifications"
root + "Local Podspecs"
end
# Returns the path of the specification for the Pod with the
......@@ -165,11 +141,15 @@ module Pod
#
# @return [Pathname] the path or nil.
#
def podspec_for_name(name)
path = root + "Local Podspecs/#{name}.podspec"
def specification_path(name)
path = specifications_dir + "#{name}.podspec"
path.exist? ? path : nil
end
#--------------------------------------#
# @!group Pods Installation
# Returns the specification for the Pod with the given name.
#
# @param [String] name
......@@ -178,7 +158,7 @@ module Pod
# @return [Specification] the specification if the file is found.
#
def specification(name)
if file = podspec_for_name(name)
if file = specification_path(name)
Specification.from_file(file)
end
end
......@@ -186,115 +166,101 @@ module Pod
# @return [Array<String>] the names of the pods that have been
# pre-downloaded from an external source.
#
# @todo The installer needs to be aware of it.
#
attr_reader :predownloaded_pods
#--------------------------------------#
# @!group Private methods
private
attr_accessor :cached_local_pods
#-------------------------------------------------------------------------#
attr_accessor :cached_locally_sourced_pods
end
#---------------------------------------------------------------------------#
# Provides support for managing a header directory. It also keeps track of
# the header search paths.
#
class HeadersDirectory
# @return [Pathname] the absolute path of this header directory.
# Provides support for managing a header directory. It also keeps track of
# the header search paths.
#
def root
@sandbox.root + @relative_path
end
class HeadersStore
# @param [Sandbox] sandbox
# the sandbox that contains this header dir.
#
# @param [String] relative_path
# the relative path to the sandbox root and hence to the Pods
# project.
#
def initialize(sandbox, relative_path)
@sandbox = sandbox
@relative_path = relative_path
@search_paths = [relative_path]
end
#--------------------------------------#
# @!group Life cycle
public
# Removes the directory as it is regenerated from scratch during each
# installation.
#
# @return [void]
#
def prepare_for_install
root.rmtree if root.exist?
end
# @return [Pathname] the absolute path of this header directory.
#
def root
@sandbox.root + @relative_path
end
#--------------------------------------#
# @return [Sandbox] the sandbox where this header directory is stored.
#
attr_reader :sandbox
# @param [Sandbox] @see sandbox
#
# @param [String] relative_path
# the relative path to the sandbox root and hence to the Pods
# project.
#
def initialize(sandbox, relative_path)
@sandbox = sandbox
@relative_path = relative_path
@search_paths = [relative_path]
end
# @!group Adding headers
# @return [Array<String>] All the search paths of the header directory in
# xcconfig format. The paths are specified relative to the pods
# root with the `${PODS_ROOT}` variable.
#
def search_paths
@search_paths.uniq.map { |path| "${PODS_ROOT}/#{path}" }
end
public
# Removes the directory as it is regenerated from scratch during each
# installation.
#
# @return [void]
#
def implode!
root.rmtree if root.exist?
end
# Adds a header to the directory.
#
# @param [Pathname] namespace_path
# the path where the header file should be stored relative to the
# headers directory.
#
# @param [Pathname] relative_header_path
# the path of the header file relative to the sandbox.
#
# @note This method adds the files are added to the search paths.
#
# @return [void]
#
def add_file(namespace_path, relative_header_path)
namespaced_header_path = root + namespace_path
namespaced_header_path.mkpath unless File.exist?(namespaced_header_path)
source = (@sandbox.root + relative_header_path).relative_path_from(namespaced_header_path)
Dir.chdir(namespaced_header_path) { FileUtils.ln_sf(source, relative_header_path.basename)}
@search_paths << namespaced_header_path.relative_path_from(@sandbox.root)
namespaced_header_path + relative_header_path.basename
end
#--------------------------------------#
public
# @!group Adding headers
# Adds a header to the directory.
#
# @param [Pathname] namespace_path
# the path where the header file should be stored relative to the
# headers directory.
#
# @param [Pathname] relative_header_path
# the path of the header file relative to the sandbox.
#
# @note This method adds the files are added to the search paths.
#
# @return [Pathname]
#
def add_files(namespace, relative_header_paths)
add_search_path(namespace)
namespaced_path = root + namespace
namespaced_path.mkpath unless File.exist?(namespaced_path)
relative_header_paths.map do |relative_header_path|
source = (@sandbox.root + relative_header_path).relative_path_from(namespaced_path)
Dir.chdir(namespaced_path) do
FileUtils.ln_sf(source, relative_header_path.basename)
end
namespaced_path + relative_header_path.basename
end
end
# @todo Why this variant exits?
#
def add_files(namespace_path, relative_header_paths)
relative_header_paths.map { |path| add_file(namespace_path, path) }
# Adds an header search path to the sandbox.
#
# @param [Pathname] path
# the path tho add.
#
# @return [void]
#
def add_search_path(path)
@search_paths << Pathname.new(@relative_path) + path
end
end
# @return [Array<String>] All the search paths of the header directory in
# xcconfig format. The paths are specified relative to the pods
# root with the `${PODS_ROOT}` variable.
#
def search_paths
@search_paths.uniq.map { |path| "${PODS_ROOT}/#{path}" }
end
#-------------------------------------------------------------------------#
# Adds an header search path to the sandbox.
#
# @param [Pathname] path
# the path tho add.
#
# @return [void]
#
# @todo Why this variant exits?
#
def add_search_path(path)
@search_paths << Pathname.new(@relative_path) + path
end
end
end
......@@ -76,7 +76,7 @@ module Pod
it "generates the libraries which represent the target definitions" do
@analyzer.analyze
libs = @analyzer.libraries
libs.map(&:name).should == ['libPods.a']
libs.map(&:name).should == ['Pods']
lib = libs.first
lib.support_files_root.should == config.sandbox.root
......@@ -124,6 +124,15 @@ module Pod
]
end
it "removes the specifications of the changed pods to prevent confusion in the resolution process" do
@analyzer.allow_pre_downloads = true
podspec = @analyzer.sandbox.root + 'Local Podspecs/JSONKit.podspec'
podspec.dirname.mkpath
File.open(podspec, "w") { |f| f.puts('test') }
@analyzer.analyze
podspec.should.not.exist?
end
it "adds the specifications to the correspondent libraries in after the resolution" do
@analyzer.analyze
@analyzer.libraries.first.specs.map(&:to_s).should == [
......
......@@ -12,18 +12,19 @@ module Pod
xcodeproj 'dummy'
end
@target_definition = @podfile.target_definitions[:default]
@project = Project.new(config.sandbox)
@project = Project.new
config.sandbox.project = @project
@library = Library.new(@target_definition)
@library.platform = Platform.new(:ios, '6.0')
@library.support_files_root = config.sandbox.root
@library.user_project_path = config.sandbox.root + '../user_project.xcodeproj'
@library.user_build_configurations = { 'Debug' => :debug, 'Release' => :release, 'AppStore' => :release, 'Test' => :debug }
specification = fixture_spec('banana-lib/BananaLib.podspec')
@pod = LocalPod.new(specification, config.sandbox, @library.platform)
@library.local_pods = [@pod]
@installer = TargetInstaller.new(@project, @library, [@pod])
@installer = TargetInstaller.new(config.sandbox, @library)
specification.prefix_header_contents = '#import "BlocksKit.h"'
@pod.stubs(:root).returns(Pathname.new(fixture('banana-lib')))
......
......@@ -21,7 +21,8 @@ module Pod
end
@project_root = @sample_project_path.dirname
@pods_project = Project.new(config.sandbox)
@pods_project = Project.new()
config.sandbox.project = @pods_project
@libraries = @podfile.target_definitions.values.map do |target_definition|
lib = Library.new(target_definition)
lib.user_project_path = sample_project_path
......@@ -31,7 +32,7 @@ module Pod
lib.user_project = sample_project
lib
end
@integrator = Installer::UserProjectIntegrator.new(@podfile, @pods_project, @project_root, @libraries)
@integrator = Installer::UserProjectIntegrator.new(@podfile, config.sandbox, @project_root, @libraries)
end
it "uses the path of the workspace defined in the podfile" do
......@@ -82,11 +83,11 @@ module Pod
sample_project_path = SpecHelper.create_sample_app_copy_from_fixture('SampleProject')
@sample_project = Xcodeproj::Project.new sample_project_path
@target = @sample_project.targets.first
@pods_project = Project.new(config.sandbox)
target_definition = Podfile::TargetDefinition.new(:default, nil, nil)
@lib = Library.new(target_definition)
@lib.user_project_path = sample_project_path
@lib.target = @pods_project.new_target(:static_library, target_definition.label, :ios)
pods_project = Project.new()
@lib.target = pods_project.new_target(:static_library, target_definition.label, :ios)
@lib.user_targets = [@target]
@lib.support_files_root = config.sandbox.root
@lib.user_project = @sample_project
......
......@@ -222,3 +222,9 @@ module Pod
# end
end
end
# it 'clears out its headers root when preparing for install' do
# @sandbox.prepare_for_install
# @sandbox.build_headers.root.should.not.exist
# end
......@@ -17,8 +17,12 @@ module Pod
@lib.label.should == 'Pods'
end
it "returns its name" do
@lib.name.should == 'Pods'
end
it "returns the name of its product" do
@lib.name.should == 'libPods.a'
@lib.product_name.should == 'libPods.a'
end
end
......
......@@ -81,14 +81,14 @@ describe Pod::LocalPod do
end
it "can add it's source files to an Xcode project target" do
project = Pod::Project.new(@sandbox)
project = Pod::Project.new()
@pod.add_file_references_to_project(project)
project['Pods/BananaLib/Banana.h'].path.should == "BananaLib/Classes/Banana.h"
project['Pods/BananaLib/Banana.m'].path.should == "BananaLib/Classes/Banana.m"
end
it "can add it's source files to a target with any specially configured compiler flags" do
project = Pod::Project.new(@sandbox)
project = Pod::Project.new()
target = project.new_target(:static, 'Pods', :ios)
@pod.top_specification.compiler_flags = '-d some_flag'
@pod.add_file_references_to_project(project)
......@@ -303,8 +303,9 @@ describe Pod::LocalPod do
"Chameleon/UIKit > UIKit/Classes/UIKit.h UIKit/Classes/UIView.h UIKit/Classes/UIWindow.h" ]
end
it "respects the headers excluded from the search paths" do
@pod.stubs(:headers_excluded_from_search_paths).returns([@pod.root + 'UIKit/Classes/UIKit.h'])
# TODO this is a stub
xit "respects the exclude files attribute of the specifications" do
@pod.stubs(:exclude_files).returns([@pod.root + 'UIKit/Classes/UIKit.h'])
mappings = @pod.send(:header_mappings, @pod.header_files_by_spec)
mappings = mappings.map do |folder, headers|
"#{folder} > #{headers.sort.map{ |p| p.relative_path_from(@pod.root).to_s }.join(' ')}"
......@@ -314,8 +315,7 @@ describe Pod::LocalPod do
"Chameleon/UIKit > UIKit/Classes/UIView.h UIKit/Classes/UIWindow.h" ]
end
# @TODO: This is done by the sandbox and this test should be moved
it "includes the sandbox of the pod's headers while linking" do
xit "includes the sandbox of the pod's headers while linking" do
@sandbox.build_headers.expects(:add_search_path).with(Pathname.new('Chameleon'))
@sandbox.public_headers.expects(:add_search_path).with(Pathname.new('Chameleon'))
@pod.link_headers
......
......@@ -3,21 +3,13 @@ require File.expand_path('../../spec_helper', __FILE__)
describe Pod::Project do
describe "In general" do
before do
@project = Pod::Project.new(config.sandbox)
end
it "returns the sandbox used for the project" do
@project.sandbox.should == config.sandbox
@project = Pod::Project.new(nil)
end
it "creates the support file group on initialization" do
@project.support_files_group.name.should == 'Targets Support Files'
end
it "returns its path" do
@project.path.should == config.sandbox.project_path
end
it "returns the `Pods` group" do
@project.pods.name.should == 'Pods'
end
......@@ -43,7 +35,7 @@ describe Pod::Project do
end
it "adds the Podfile configured as a Ruby file" do
@project.add_podfile(config.podfile_path)
@project.add_podfile('../Podfile')
f = @project['Podfile']
f.name.should == 'Podfile'
f.source_tree.should == 'SOURCE_ROOT'
......
require File.expand_path('../../spec_helper', __FILE__)
require 'tmpdir'
TMP_POD_ROOT = ROOT + "tmp" + "podroot" unless defined? TMP_POD_ROOT
module Pod
describe Pod::Sandbox do
describe Sandbox do
extend SpecHelper::TemporaryDirectory
before do
@sandbox = Pod::Sandbox.new(TMP_POD_ROOT)
end
before do
@sandbox = Pod::Sandbox.new(temporary_directory + 'Sandbox')
end
after do
@sandbox.implode
end
it "automatically creates its root if it doesn't exist" do
File.directory?(temporary_directory + 'Sandbox').should.be.true
end
it "automatically creates the TMP_POD_ROOT if it doesn't exist" do
File.directory?(TMP_POD_ROOT).should.be.true
end
it "returns the manifest" do
@sandbox.manifest.should == nil
end
it "deletes the entire root directory on implode" do
@sandbox.implode
File.directory?(TMP_POD_ROOT).should.be.false
FileUtils.mkdir(TMP_POD_ROOT) # put it back again
end
it "returns the project" do
@sandbox.project.should == nil
end
it "returns it's headers root" do
@sandbox.build_headers.root.should == Pathname.new(File.join(TMP_POD_ROOT, "BuildHeaders"))
end
it "returns the public headers store" do
@sandbox.public_headers.root.should == temporary_directory + 'Sandbox/Headers'
end
it "returns it's public headers root" do
@sandbox.public_headers.root.should == Pathname.new(File.join(TMP_POD_ROOT, "Headers"))
end
it "returns the build headers store" do
@sandbox.build_headers.root.should == temporary_directory + 'Sandbox/BuildHeaders'
end
it "can add namespaced headers to it's header path using symlinks and return the relative path" do
FileUtils.mkdir_p(@sandbox.root + "ExampleLib/BuildHeaders")
namespace_path = Pathname.new("ExampleLib")
relative_header_path = Pathname.new("ExampleLib/BuildHeaders/MyHeader.h")
File.open(@sandbox.root + relative_header_path, "w") { |file| file.write('hello') }
symlink_path = @sandbox.build_headers.add_file(namespace_path, relative_header_path)
symlink_path.should.be.symlink
File.read(symlink_path).should == 'hello'
end
it "deletes the entire root directory on implode" do
@sandbox.implode
File.directory?(temporary_directory + 'Sandbox').should.be.false
end
it 'can add multiple headers at once and return the relative symlink paths' do
FileUtils.mkdir_p(@sandbox.root + "ExampleLib/BuildHeaders")
namespace_path = Pathname.new("ExampleLib")
relative_header_paths = [
Pathname.new("ExampleLib/BuildHeaders/MyHeader.h"),
Pathname.new("ExampleLib/BuildHeaders/MyOtherHeader.h")
]
relative_header_paths.each do |path|
File.open(@sandbox.root + path, "w") { |file| file.write('hello') }
end
symlink_paths = @sandbox.build_headers.add_files(namespace_path, relative_header_paths)
symlink_paths.each do |path|
path.should.be.symlink
File.read(path).should == "hello"
#--------------------------------------#
it "returns the path of the manifest" do
@sandbox.manifest_path.should == temporary_directory + 'Sandbox/Manifest.lock'
end
end
it 'keeps a list of unique header search paths when headers are added' do
FileUtils.mkdir_p(@sandbox.root + "ExampleLib/BuildHeaders")
namespace_path = Pathname.new("ExampleLib")
relative_header_paths = [
Pathname.new("ExampleLib/BuildHeaders/MyHeader.h"),
Pathname.new("ExampleLib/BuildHeaders/MyOtherHeader.h")
]
relative_header_paths.each do |path|
File.open(@sandbox.root + path, "w") { |file| file.write('hello') }
end
@sandbox.build_headers.add_files(namespace_path, relative_header_paths)
@sandbox.build_headers.search_paths.should.include("${PODS_ROOT}/BuildHeaders/ExampleLib")
end
it "returns the path of the Pods project" do
@sandbox.project_path.should == temporary_directory + 'Sandbox/Pods.xcodeproj'
end
it 'always adds the Headers root to the header search paths' do
@sandbox.build_headers.search_paths.should.include("${PODS_ROOT}/BuildHeaders")
end
it "returns the path for a Pod" do
@sandbox.pod_dir('JSONKit').should == temporary_directory + 'Sandbox/JSONKit'
end
it 'clears out its headers root when preparing for install' do
@sandbox.prepare_for_install
@sandbox.build_headers.root.should.not.exist
end
it "returns the directory for the support files of a library" do
@sandbox.library_support_files_dir('Pods').should == temporary_directory + 'Sandbox'
end
it "returns the path to a spec file in the 'Local Podspecs' dir" do
(@sandbox.root + 'Local Podspecs').mkdir
FileUtils.cp(fixture('banana-lib') + 'BananaLib.podspec', @sandbox.root + 'Local Podspecs')
@sandbox.podspec_for_name('BananaLib').should == @sandbox.root + 'Local Podspecs/BananaLib.podspec'
end
it "returns the directory where to store the specifications" do
@sandbox.specifications_dir.should == temporary_directory + 'Sandbox/Local Podspecs'
end
it "returns a LocalPod for a spec file in the sandbox" do
(@sandbox.root + 'Local Podspecs').mkdir
FileUtils.cp(fixture('banana-lib') + 'BananaLib.podspec', @sandbox.root + 'Local Podspecs')
pod = @sandbox.installed_pod_named('BananaLib', Pod::Platform.ios)
pod.should.be.instance_of Pod::LocalPod
pod.top_specification.name.should == 'BananaLib'
end
it "returns the path to a spec file in the 'Local Podspecs' dir" do
(@sandbox.root + 'Local Podspecs').mkdir
FileUtils.cp(fixture('banana-lib/BananaLib.podspec'), @sandbox.root + 'Local Podspecs')
@sandbox.specification_path('BananaLib').should == @sandbox.root + 'Local Podspecs/BananaLib.podspec'
end
#--------------------------------------#
it "returns a LocalPod for a spec instance which source is expected to be in the sandbox" do
(@sandbox.root + 'Local Podspecs').mkdir
FileUtils.cp(fixture('banana-lib') + 'BananaLib.podspec', @sandbox.root + 'Local Podspecs')
spec = Pod::Specification.from_file(fixture('banana-lib') + 'BananaLib.podspec')
pod = @sandbox.local_pod_for_spec(spec, Pod::Platform.ios)
pod.should.be.instance_of Pod::LocalPod
pod.top_specification.name.should == 'BananaLib'
it "loads the stored specification with the given name" do
(@sandbox.root + 'Local Podspecs').mkdir
FileUtils.cp(fixture('banana-lib/BananaLib.podspec'), @sandbox.root + 'Local Podspecs')
@sandbox.specification('BananaLib').name.should == 'BananaLib'
end
it "stores the list of the names of the pre-downloaded pods" do
@sandbox.predownloaded_pods << 'JSONKit'
@sandbox.predownloaded_pods.should == ['JSONKit']
end
end
it "always returns the same cached LocalPod instance for the same spec and platform" do
(@sandbox.root + 'Local Podspecs').mkdir
FileUtils.cp(fixture('banana-lib') + 'BananaLib.podspec', @sandbox.root + 'Local Podspecs')
spec = Pod::Specification.from_file(@sandbox.root + 'Local Podspecs/BananaLib.podspec')
#---------------------------------------------------------------------------#
pod = @sandbox.installed_pod_named('BananaLib', Pod::Platform.ios)
@sandbox.installed_pod_named('BananaLib', Pod::Platform.ios).should.eql pod
@sandbox.local_pod_for_spec(spec, Pod::Platform.ios).should.eql pod
describe Sandbox::HeadersStore do
extend SpecHelper::TemporaryDirectory
before do
@sandbox = Pod::Sandbox.new(temporary_directory + 'Sandbox')
@header_dir = Sandbox::HeadersStore.new(@sandbox, 'Headers')
end
it "returns it's headers root" do
@header_dir.root.should == temporary_directory + 'Sandbox/Headers'
end
it "can add namespaced headers to it's header path using symlinks and return the relative path" do
FileUtils.mkdir_p(@sandbox.root + "ExampleLib/")
namespace_path = Pathname.new("ExampleLib")
relative_header_paths = [
Pathname.new("ExampleLib/MyHeader.h"),
Pathname.new("ExampleLib/MyOtherHeader.h")
]
relative_header_paths.each do |path|
File.open(@sandbox.root + path, "w") { |file| file.write('hello') }
end
symlink_paths = @header_dir.add_files(namespace_path, relative_header_paths)
symlink_paths.each do |path|
path.should.be.symlink
File.read(path).should == "hello"
end
end
it 'keeps a list of unique header search paths when headers are added' do
FileUtils.mkdir_p(@sandbox.root + "ExampleLib/Dir")
namespace_path = Pathname.new("ExampleLib")
relative_header_paths = [
Pathname.new("ExampleLib/Dir/MyHeader.h"),
Pathname.new("ExampleLib/Dir/MyOtherHeader.h")
]
relative_header_paths.each do |path|
File.open(@sandbox.root + path, "w") { |file| file.write('hello') }
end
@header_dir.add_files(namespace_path, relative_header_paths)
@header_dir.search_paths.should.include("${PODS_ROOT}/Headers/ExampleLib")
end
it 'always adds the Headers root to the header search paths' do
@header_dir.search_paths.should.include("${PODS_ROOT}/Headers")
end
end
#--------------------------------------#
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment