Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
C
cocoapods
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gengmeiios
cocoapods
Commits
697f8bd1
Commit
697f8bd1
authored
Oct 21, 2012
by
Fabio Pelosin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WIP
parent
6ca21338
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
523 additions
and
420 deletions
+523
-420
.kick
.kick
+0
-3
linter.rb
lib/cocoapods/command/linter.rb
+2
-3
installer.rb
lib/cocoapods/installer.rb
+312
-236
integration_spec.rb
spec/integration_spec.rb
+2
-4
installer_spec.rb
spec/unit/installer_spec.rb
+207
-174
No files found.
.kick
View file @
697f8bd1
...
...
@@ -6,9 +6,6 @@ process do |files|
specs = files.take_and_map do |file|
if file =~ %r{lib/cocoapods/(.+?)\.rb$}
s = Dir.glob("spec/**/#{File.basename(file, '.rb')}_spec.rb")
if file =~ %r{lib/cocoapods/installer.*\.rb$}
s.concat(['spec/unit/installer_spec.rb', 'spec/unit/installer/target_installer_spec.rb'])
end
s.uniq unless s.empty?
end
end
...
...
lib/cocoapods/command/linter.rb
View file @
697f8bd1
...
...
@@ -113,10 +113,9 @@ module Pod
config
.
verbose
config
.
skip_repo_update
=
true
sandbox
=
Sandbox
.
new
(
config
.
project_pods_root
)
resolver
=
Resolver
.
new
(
podfile
,
nil
,
sandbox
)
installer
=
Installer
.
new
(
resolver
)
installer
=
Installer
.
new
(
sandbox
,
podfile
)
installer
.
install!
@pod
=
installer
.
pods
.
find
{
|
pod
|
pod
.
top_specification
==
spec
}
@pod
=
installer
.
local_
pods
.
find
{
|
pod
|
pod
.
top_specification
==
spec
}
config
.
silent
end
...
...
lib/cocoapods/installer.rb
View file @
697f8bd1
module
Pod
# The
installer is the core of CocoaPods. This class is responsible of taking
# a Podfile and transform it in the Pods libraries. This class also
# The
{Installer} is the core of CocoaPods. This class is responsible of
#
taking
a Podfile and transform it in the Pods libraries. This class also
# integrates the user project so the Pods libraries can be used out of the
# box.
#
# The
i
nstaller is capable of doing incremental updates to an existing Pod
# The
I
nstaller is capable of doing incremental updates to an existing Pod
# installation.
#
# The
i
nstaller gets the information that it needs mainly from 3 files:
# The
I
nstaller gets the information that it needs mainly from 3 files:
#
# - Podfile: The specification written by the user that contains
# information about targets and Pods.
...
...
@@ -16,11 +16,11 @@ module Pod
# installed and in concert with the Podfile provides information about
# which specific version of a Pod should be installed. This file is
# ignored in update mode.
# -
Pods.lock: A file contained in the Pods folder that keeps track
#
of the pods installed in the local machine. This files is used onc
e
#
the exact versions of the Pods has been computed to detect if that
#
version is already installed. This file is not intended to be kept
#
under source
control and is a copy of the Podfile.lock.
# -
Manifest.lock: A file contained in the Pods folder that keeps track of
#
the pods installed in the local machine. This files is used once th
e
#
exact versions of the Pods has been computed to detect if that version
#
is already installed. This file is not intended to be kept under source
# control and is a copy of the Podfile.lock.
#
# Once completed the installer should produce the following file structure:
#
...
...
@@ -45,7 +45,7 @@ module Pod
# | +-- Pods-prefix.pch
# | +-- PodsDummy_Pods.m
# |
# +--
Pods
.lock
# +--
Manifest
.lock
# |
# +-- Pods.xcodeproj
#
...
...
@@ -55,23 +55,27 @@ module Pod
include
Config
::
Mixin
# @return [Sandbox] The sandbox where to install the Pods.
# @return [Sandbox]
# the sandbox where the Pods should be installed.
#
attr_reader
:sandbox
# @return [Podfile] The Podfile specification that contains the
# information of the Pods that should be installed.
# @return [Podfile]
# the Podfile specification that contains the information of the Pods
# that should be installed.
#
attr_reader
:podfile
# @return [Lockfile] The Lockfile that stores the information about the
# installed Pods.
# @return [Lockfile]
# the Lockfile that stores the information about the Pods previously
# installed on any machine.
#
attr_reader
:lockfile
# @return [Bool] Whether the installer is in update mode. In update
# mode the contents of the Lockfile are not taken into
# account for deciding what Pods to install.
# @return [Bool]
# whether the installer is in update mode. In update mode the contents of
# the Lockfile are not taken into account for deciding what Pods to
# install.
#
attr_reader
:update_mode
...
...
@@ -87,8 +91,10 @@ module Pod
@update_mode
=
update_mode
end
# @return [void] The installation process of is mostly linear with few
# minor complications to keep in mind:
# Installs the Pods.
#
# The installation process of is mostly linear with few minor complications
# to keep in mind:
#
# - The stored podspecs need to be cleaned before the resolution step
# otherwise the sandbox might return an old podspec and not download
...
...
@@ -100,141 +106,159 @@ module Pod
# @note The order of the steps is very important and should be changed
# carefully.
#
#
TODO:
#
@return [void]
#
def
install!
# TODO: prepare_for_legacy_compatibility
compare_podfile_and_lockfile
analyze
prepare_for_legacy_compatibility
clean_global_support_files
clean_removed_pods
clean_pods_to_install
install_dependencies
install_targets
write_lockfiles
integrate_user_project
end
# Performs only the computation parts of an installation.
#
# It is used by the `outdated` subcommand.
#
# @return [void]
#
def
analyze
generate_pods_by_podfile_state
update_repositories_if_needed
generate_locked_dependencies
resolve_dependencies
generate_local_pods
generate_pods_that_should_be_installed
end
# TODO: detect_installed_versions
create_local_pods
detect_pods_to_install
install_dependencies
#---------------------------------------------------------------------------#
generate_support_files
write_lockfile
# TODO: write_sandbox_lockfile
# @!group Analysis products
integrate_user_project
end
public
# @return [void] the
# @return [Array<String>]
# the names of the pods that were added to Podfile since the last
# installation on any machine.
#
def
dry_run
end
attr_reader
:pods_added_from_the_lockfile
# @return [Array<String>]
# the names of the pods whose version requirements in the Podfile are
# incompatible with the version stored in the lockfile.
#
attr_reader
:pods_changed_from_the_lockfile
# @!group Prepare for legacy compatibility
# @return [Array<String>]
# the names of the pods that were deleted from Podfile since the last
# installation on any machine.
#
attr_reader
:pods_deleted_from_the_lockfile
# @return [void] In this step we prepare the Pods folder in order to be
# compatible with the most recent version of CocoaPods.
# @return [Array<String>]
# the names of the pods that didn't change since the last installation on
# any machine.
#
# @note This step should be removed by version 1.0.
attr_reader
:pods_unchanged_from_the_lockfile
# @return [Array<Dependency>]
# the dependencies generate by the lockfile that prevent the resolver to
# update a Pod.
#
def
prepare_for_legacy_compatibility
# move_target_support_files_if_needed
# copy_lock_file_to_Pods_lock_if_needed
# move_Local_Podspecs_to_Podspecs_if_needed
# move_pods_to_sources_folder_if_needed
end
attr_reader
:locked_dependencies
# @return [Hash{TargetDefinition => Array<Spec>}]
# the specifications grouped by target as identified in the
# resolve_dependencies step.
#
attr_reader
:specs_by_target
# @return [Array<Specification>]
# the specifications of the resolved version of Pods that should be
# installed.
#
attr_reader
:specifications
# @!group Detect Podfile changes step
# @return [Hash{TargetDefinition => Array<LocalPod>}]
# the local pod instances grouped by target.
#
attr_reader
:local_pods_by_target
# @return [Hash{Symbol => Array<Spec>}] The name of the pods directly
# specified in the Podfile grouped by a symbol representing their state
# (added, changed, removed, unchanged) as identified by the {Lockfile}.
# @return [Array<LocalPod>]
# the list of LocalPod instances for each dependency sorted by name.
#
attr_reader
:
pods_by_state
attr_reader
:
local_pods
# @return [
void] In this step the podfile is compared with the lockfile in
#
order to detect which dependencies should be lock
ed.
# @return [
Array<String>]
#
the Pods that should be install
ed.
#
# #TODO: If there is not lockfile all the Pods should be marked as added.
# #TODO: This should use the Pods.lock file because they are used by the
# to detect what needs to be installed.
attr_reader
:pods_to_install
#---------------------------------------------------------------------------#
# @!group Installation products
public
# @return [Pod::Project]
# the `Pods/Pods.xcodeproj` project.
#
def
compare_podfile_and_lockfile
if
lockfile
UI
.
section
"Finding added, modified or removed dependencies:"
do
@pods_by_state
=
lockfile
.
detect_changes_with_podfile
(
podfile
)
display_dependencies_state
end
else
@pods_by_state
=
{}
end
end
attr_reader
:pods_project
# @return [
void] Displays the state of each dependency.
# @return [
Array<TargetInstaller>]
#
def
display_dependencies_state
return
unless
config
.
verbose?
marks
=
{
:added
=>
"A"
.
green
,
:changed
=>
"M"
.
yellow
,
:removed
=>
"R"
.
red
,
:unchanged
=>
"-"
}
pods_by_state
.
each
do
|
symbol
,
pod_names
|
pod_names
.
each
do
|
pod_name
|
UI
.
message
(
"
#{
marks
[
symbol
]
}
#{
pod_name
}
"
,
''
,
2
)
end
end
end
attr_reader
:target_installers
#---------------------------------------------------------------------------#
# @!group Pre-installation computations
# @!group Cleaning steps
private
#
@return [void] In this step we clean all the folders that will be
#
regenerated from scratch and any file which might not be overwritten
.
#
Compares the {Podfile} with the {Lockfile} in order to detect which
#
dependencies should be locked
.
#
# @TODO: Clean the podspecs of all the pods that aren't unchanged so the
# resolution process doesn't get confused by them.
# @return [void]
#
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: If there is not Lockfile all the Pods should be marked as added.
#
#
@TODO: Use the local pod implode.
#
@TODO: [#534] Clean all the Pods folder that are not unchanged?
#
TODO: Once the manifest.lock is implemented only the unchanged pods
#
should be tracked.
#
def
clean_removed_pods
UI
.
section
"Removing deleted dependencies"
do
pods_by_state
[
:removed
].
each
do
|
pod_name
|
UI
.
section
(
"Removing
#{
pod_name
}
"
,
"-> "
.
red
)
do
path
=
sandbox
.
root
+
pod_name
path
.
rmtree
if
path
.
exist?
end
def
generate_pods_by_podfile_state
if
lockfile
UI
.
section
"Finding added, modified or removed dependencies:"
do
pods_by_state
=
lockfile
.
detect_changes_with_podfile
(
podfile
)
@pods_added_from_the_lockfile
=
pods_by_state
[
:added
]
||
[]
@pods_deleted_from_the_lockfile
=
pods_by_state
[
:removed
]
||
[]
@pods_changed_from_the_lockfile
=
pods_by_state
[
:changed
]
||
[]
@pods_unchanged_from_the_lockfile
=
pods_by_state
[
:unchanged
]
||
[]
display_pods_by_lockfile_state
end
end
unless
pods_by_state
[
:removed
].
empty?
else
@pods_added_from_the_lockfile
=
[]
@pods_deleted_from_the_lockfile
=
[]
@pods_changed_from_the_lockfile
=
[]
@pods_unchanged_from_the_lockfile
=
[]
end
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.
# Displays the state of each dependency.
#
# @
TODO: [#247] Clean the headers of only the pods to install.
# @
return [void]
#
def
clean_pods_to_install
def
display_pods_by_lockfile_state
return
unless
config
.
verbose?
pods_added_from_the_lockfile
.
each
{
|
pod
|
UI
.
message
(
"A"
.
green
+
"
#{
pod
}
"
,
''
,
2
)
}
pods_deleted_from_the_lockfile
.
each
{
|
pod
|
UI
.
message
(
"R"
.
red
+
"
#{
pod
}
"
,
''
,
2
)
}
pods_changed_from_the_lockfile
.
each
{
|
pod
|
UI
.
message
(
"M"
.
yellow
+
"
#{
pod
}
"
,
''
,
2
)
}
pods_unchanged_from_the_lockfile
.
each
{
|
pod
|
UI
.
message
(
"-"
+
"
#{
pod
}
"
,
''
,
2
)
}
end
# @!group Generate locked dependencies step
# @return [void] Lazily updates the source repositories. The update is
# triggered if:
# - There are pods that changed in the Podfile.
...
...
@@ -244,56 +268,52 @@ module Pod
# TODO: Remove the lockfile condition once compare_podfile_and_lockfile
# is updated.
#
# TODO: Lazy resolution can't be done if we want to fully support detection
# of changes in specifications checksum.
#
def
update_repositories_if_needed
return
if
config
.
skip_repo_update?
changed_pods
=
(
pods_by_state
[
:added
]
+
pods_by_state
[
:changed
])
UI
.
section
'Updating spec repositories'
do
Command
::
Repo
.
new
(
Command
::
ARGV
.
new
([
"update"
])).
run
end
if
!
lockfile
||
!
changed_pods
.
empty?
||
update_mode
changed_pods
=
(
pods_changed_from_the_lockfile
+
pods_deleted_from_the_lockfile
)
should_update
=
!
lockfile
||
!
changed_pods
.
empty?
||
update_mode
if
should_update
UI
.
section
'Updating spec repositories'
do
Command
::
Repo
.
new
(
Command
::
ARGV
.
new
([
"update"
])).
run
end
end
end
# @!group Generate locked dependencies step
# @return [Array<Specification>] All dependencies that have been resolved.
# Generates dependencies that require the specific version of the Pods that
# haven't changed in the {Lockfile}.
#
attr_reader
:locked_dependencies
# @return [void] In this step we generate the dependencies of necessary to
# prevent the resolver from updating the pods which are in unchanged
# state. The Podfile is compared to the Podfile.lock to detect what
# version of a dependency should be locked.
# These dependencies are passed to the {Resolver}, unless the installer is
# in update mode, to prevent it from upgrading the Pods that weren't
# changed in the {Podfile}.
#
# @return [void]
#
def
generate_locked_dependencies
if
update_mode
@locked_dependencies
=
[]
else
@locked_dependencies
=
pods_by_state
[
:unchanged
].
map
do
|
pod_name
|
lockfile
.
dependency_for_installed_pod_named
(
pod_name
)
end
@locked_dependencies
=
pods_unchanged_from_the_lockfile
.
map
do
|
pod
|
lockfile
.
dependency_for_installed_pod_named
(
pod
)
end
end
# @!group Resolution steps
# @return [Hash{Podfile::TargetDefinition => Array<Spec>}]
# The specifications grouped by target as identified in
# the resolve_dependencies step.
# Converts the Podfile in a list of specifications grouped by target.
#
attr_reader
:specs_by_target
# @return [Array<Specification>] All dependencies that have been resolved.
# @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).
#
attr_reader
:specifications
# @return [void] Converts the Podfile in a list of specifications grouped
# by target.
# @note In update mode the resolver is set to always update the specs from
# external sources.
#
#
In update mode the specs from external sources are always downloaded.
#
@return [void]
#
def
resolve_dependencies
UI
.
section
"Resolving dependencies of
#{
UI
.
path
podfile
.
defined_in_file
}
"
do
resolver
=
Resolver
.
new
(
sandbox
,
podfile
,
locked_dependencies
)
locked_deps
=
update_mode
?
[]
:
locked_dependencies
resolver
=
Resolver
.
new
(
sandbox
,
podfile
,
locked_deps
)
resolver
.
update_external_specs
=
update_mode
@specs_by_target
=
resolver
.
resolve
@specifications
=
specs_by_target
.
values
.
flatten
...
...
@@ -301,27 +321,25 @@ module Pod
end
# @!group Detect Pods to install step
# @return [Array<String>] The names of the Pods that should be installed.
# Computes the list of the Pods that should be installed or reinstalled in
# the {Sandbox}.
#
attr_reader
:pods_to_install
#
@return [<void>] In this step the pods to install are detected.
#
The pods to install are identified as the Pods that don't exist in the
#
sandbox or the Pods whose version differs from the one of the lockfile
.
# The pods to install are identified as the Pods that don't exist in the
# sandbox or the Pods whose version differs from the one of the lockfile.
#
#
In update mode specs originating from external dependencies and or from
#
head sources are always reinstalled
.
#
# In update mode specs originating from external dependencies and or from
# head sources are always reinstalled.
# @return [void]
#
# TODO: Decide a how the Lockfile should report versions.
# TODO: [#534] Detect if the folder of a Pod is empty.
# TODO: Use {Sandbox} manifest.
#
def
detect_pods_to_install
# TODO: [#534] Detect if the folder of a Pod is empty.
#
def
generate_pods_that_should_be_installed
changed_pods_names
=
[]
if
lockfile
changed_pods
=
pods
.
select
do
|
pod
|
changed_pods
=
local_
pods
.
select
do
|
pod
|
pod
.
top_specification
.
version
!=
lockfile
.
pods_versions
[
pod
.
name
]
end
if
update_mode
...
...
@@ -330,42 +348,33 @@ module Pod
resolver
.
pods_from_external_sources
.
include?
(
pod
.
name
)
end
end
changed_pods_names
+=
@pods_by_state
[
:added
]
+
@pods_by_state
[
:changed
]
changed_pods_names
+=
pods_added_from_the_lockfile
+
pods_changed_from_the_lockfile
else
changed_pods
=
pods
changed_pods
=
local_
pods
end
not_existing_pods
=
pods
.
reject
{
|
pod
|
pod
.
exists?
}
not_existing_pods
=
local_
pods
.
reject
{
|
pod
|
pod
.
exists?
}
@pods_to_install
=
(
changed_pods
+
not_existing_pods
).
uniq
end
# @!group Install step
# @return [Hash{Podfile::TargetDefinition => Array<LocalPod>}]
# Converts the specifications produced by the Resolver in local pods.
#
attr_reader
:pods_by_target
# @return [Array<LocalPod>] A list of LocalPod instances for each
# dependency sorted by name.
# (that is not a download-only one?)
attr_reader
:pods
# @return [void] In this step the specifications obtained by the resolver
# are converted in local pods. The LocalPod class is responsible to
# handle the concrete representation of a specification a sandbox.
# The LocalPod class is responsible to handle the concrete representation
# of a specification in the {Sandbox}.
#
# @return [void]
#
#
@
TODO: [#535] Pods should be accumulated per Target, also in the Local
#
Pod class. The Local Pod class should have a method to add itself
#
to a given project so it can use the sources of all the activated
#
podspecs across all targets. Also cleaning should take into
#
account
that.
# TODO: [#535] Pods should be accumulated per Target, also in the Local
# Pod class. The Local Pod class should have a method to add itself
# to a given project so it can use the sources of all the activated
#
podspecs across all targets. Also cleaning should take into account
# that.
#
def
cre
ate_local_pods
@pods_by_target
=
{}
def
gener
ate_local_pods
@
local_
pods_by_target
=
{}
specs_by_target
.
each
do
|
target_definition
,
specs
|
@pods_by_target
[
target_definition
]
=
specs
.
map
do
|
spec
|
@
local_
pods_by_target
[
target_definition
]
=
specs
.
map
do
|
spec
|
if
spec
.
local?
sandbox
.
locally_sourced_pod_for_spec
(
spec
,
target_definition
.
platform
)
else
...
...
@@ -374,12 +383,63 @@ module Pod
end
.
uniq
.
compact
end
@
pods
=
pods_by_target
.
values
.
flatten
.
uniq
.
sort_by
{
|
pod
|
pod
.
name
.
downcase
}
@
local_pods
=
local_
pods_by_target
.
values
.
flatten
.
uniq
.
sort_by
{
|
pod
|
pod
.
name
.
downcase
}
end
#---------------------------------------------------------------------------#
# @!group Installation
private
# Prepares the Pods folder in order to be compatible with the most recent
# version of CocoaPods.
#
# @return [void]
#
def
prepare_for_legacy_compatibility
# move_target_support_files_if_needed
# copy_lock_file_to_Pods_lock_if_needed
# move_Local_Podspecs_to_Podspecs_if_needed
# move_pods_to_sources_folder_if_needed
end
# @return [void] In this step we clean all the folders that will be
# regenerated from scratch and any file which might not be overwritten.
#
# @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
# @!group Install step
# @return [void] In this step we clean all the files related to the removed
# Pods.
#
# @TODO: Use the local pod implode.
# @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?
end
end
end
unless
pods_deleted_from_the_lockfile
.
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
# @return [void] Install the Pods. If the resolver indicated that a Pod
# should be installed and it exits, it is removed an then reinstalled. In
...
...
@@ -387,7 +447,7 @@ module Pod
#
def
install_dependencies
UI
.
section
"Downloading dependencies"
do
pods
.
each
do
|
pod
|
local_
pods
.
each
do
|
pod
|
if
pods_to_install
.
include?
(
pod
)
UI
.
section
(
"Installing
#{
pod
}
"
.
green
,
"-> "
.
green
)
do
install_local_pod
(
pod
)
...
...
@@ -454,18 +514,17 @@ module Pod
end
end
# @!group Generate Pods project and support files step
# @return [void] Creates and populates the targets of the pods project.
# Creates and populates the targets of the pods project.
#
# @note Post install hooks run _before_ saving of project, so that they can
# alter it before saving.
#
def
generate_support_files
# @return [void]
#
def
install_targets
UI
.
section
"Generating support files"
do
prepare_pods_project
generate_target_installers
add_source_files_to_pods_project
run_pre_install_hooks
generate_target_support_files
...
...
@@ -474,13 +533,11 @@ module Pod
end
end
#
@return [Project] The Pods project
.
#
Creates the Pods project from scratch if it doesn't exists
.
#
attr_reader
:pods_project
# @return [void] In this step we create the Pods project from scratch if it
# doesn't exists. If the Pods project exists instead we clean it and
# prepare it for installation.
# TODO clean and modify the project if it exists.
#
# @return [void]
#
def
prepare_pods_project
UI
.
message
"- Creating Pods project"
do
...
...
@@ -489,31 +546,40 @@ module Pod
end
end
# @return [void] In this step we add the source files of the Pods to the
# Pods project. The source files are grouped by Pod and in turn by subspec
# (recursively). Pods are generally added to the Pods group. However, if
# they are local they are added to the Local Pods group.
# Creates a target installer for each definition not empty.
#
# @return [void]
#
def
generate_target_installers
@target_installers
=
podfile
.
target_definitions
.
values
.
map
do
|
definition
|
TargetInstaller
.
new
(
podfile
,
pods_project
,
definition
)
unless
definition
.
empty?
end
.
compact
end
# Adds the source files of the Pods to the Pods project.
#
# @TODO [#143] This step is quite slow and should be made incremental by
# modifying only the files of the changed pods. Xcodeproj deletion
# and sorting of folders is required.
# The source files are grouped by Pod and in turn by subspec
# (recursively). Pods are generally added to the `Pods` group, however, if
# they have a local source they are added to the `Local Pods` group.
#
# @return [void]
#
# TODO Clean the groups of the deleted Pods and add only the Pods that
# should be installed.
#
# TODO [#588] Add file references for the resources of the Pods as well so
# they are visible for the user.
#
def
add_source_files_to_pods_project
UI
.
message
"- Adding source files to Pods project"
do
pods
.
each
{
|
p
|
p
.
add_file_references_to_project
(
@
project
)
}
pods
.
each
{
|
p
|
p
.
link_headers
}
local_pods
.
each
{
|
p
|
p
.
add_file_references_to_project
(
pods_
project
)
}
local_
pods
.
each
{
|
p
|
p
.
link_headers
}
end
end
def
target_installers
@target_installers
||=
podfile
.
target_definitions
.
values
.
map
do
|
definition
|
TargetInstaller
.
new
(
podfile
,
pods_project
,
definition
)
unless
definition
.
empty?
end
.
compact
end
def
run_pre_install_hooks
UI
.
message
"- Running pre install hooks"
do
pods_by_target
.
each
do
|
target_definition
,
pods
|
local_
pods_by_target
.
each
do
|
target_definition
,
pods
|
pods
.
each
do
|
pod
|
pod
.
top_specification
.
pre_install
(
pod
,
target_definition
)
end
...
...
@@ -538,7 +604,7 @@ module Pod
def
generate_target_support_files
UI
.
message
"- Installing targets"
do
target_installers
.
each
do
|
target_installer
|
pods_for_target
=
pods_by_target
[
target_installer
.
target_definition
]
pods_for_target
=
local_
pods_by_target
[
target_installer
.
target_definition
]
target_installer
.
install!
(
pods_for_target
,
sandbox
)
acknowledgements_path
=
target_installer
.
target_definition
.
acknowledgements_path
Generator
::
Acknowledgements
.
new
(
target_installer
.
target_definition
,
...
...
@@ -554,41 +620,51 @@ module Pod
filename
=
"
#{
dummy_source
.
class_name
}
.m"
pathname
=
Pathname
.
new
(
sandbox
.
root
+
filename
)
dummy_source
.
save_as
(
pathname
)
file
=
project
.
new_file
(
filename
,
"Targets Support Files"
)
file
=
p
ods_p
roject
.
new_file
(
filename
,
"Targets Support Files"
)
target_installer
.
target
.
source_build_phase
.
add_file_reference
(
file
)
end
# Writes the Pods project to the disk.
#
# @return [void]
#
def
write_pod_project
UI
.
message
"- Writing Xcode project file to
#{
UI
.
path
@sandbox
.
project_path
}
"
do
pods_project
.
save_as
(
@sandbox
.
project_path
)
end
end
# @!group Lockfile related steps
def
write_lockfile
# Writes the Podfile and the {Sandbox} lock files.
#
# @return [void]
#
# TODO: [#552] Implement
#
def
write_lockfiles
@lockfile
=
Lockfile
.
generate
(
podfile
,
specs_by_target
.
values
.
flatten
)
UI
.
message
"- Writing Lockfile in
#{
UI
.
path
config
.
project_lockfile
}
"
do
@lockfile
=
Lockfile
.
generate
(
podfile
,
specs_by_target
.
values
.
flatten
)
@lockfile
.
write_to_disk
(
config
.
project_lockfile
)
end
end
# @TODO: [#552] Implement
#
def
write_sandbox_lockfile
# UI.message "- Writing Manifest in #{UI.path sandbox.manifest_path}" do
# @lockfile.write_to_disk(sandbox.manifest_path)
# end
end
# @!group Integrate user project step
# @return [void] In this step the user project is integrated. The Pods
# libraries are added, the build script are added, and the xcconfig files
# are set.
# Integrates the user project.
#
# The following actions are performed:
# - libraries are added.
# - the build script are added.
# - the xcconfig files are set.
#
# @return [void]
#
# TODO: [#397] The libraries should be cleaned and the re-added on every
# installation. Maybe a clean_user_project phase should be added.
#
#
@TODO: [#397] The libraries should be cleaned and the re-added on every
#
install. Maybe a clean_user_project phase should be added
.
#
TODO: [#588] The resources should be added through a build phase instead
#
of using a script
.
#
def
integrate_user_project
UserProjectIntegrator
.
new
(
podfile
).
integrate!
if
config
.
integrate_targets?
...
...
spec/integration_spec.rb
View file @
697f8bd1
...
...
@@ -70,8 +70,7 @@ else
end
# Note that we are *not* using the stubbed SpecHelper::Installer subclass.
resolver
=
Pod
::
Resolver
.
new
(
podfile
,
nil
,
Pod
::
Sandbox
.
new
(
config
.
project_pods_root
))
installer
=
Pod
::
Installer
.
new
(
resolver
)
installer
=
Pod
::
Installer
.
new
(
Pod
::
Sandbox
.
new
(
config
.
project_pods_root
),
podfile
)
installer
.
install!
result
=
installer
.
lockfile
.
to_hash
result
[
'PODS'
].
should
==
[
'SSToolkit (0.1.3)'
]
...
...
@@ -88,8 +87,7 @@ else
pod
'Reachability'
,
:podspec
=>
url
end
resolver
=
Pod
::
Resolver
.
new
(
podfile
,
nil
,
Pod
::
Sandbox
.
new
(
config
.
project_pods_root
))
installer
=
SpecHelper
::
Installer
.
new
(
resolver
)
installer
=
SpecHelper
::
Installer
.
new
(
Pod
::
Sandbox
.
new
(
config
.
project_pods_root
),
podfile
)
installer
.
install!
result
=
installer
.
lockfile
.
to_hash
result
[
'PODS'
].
should
==
[
'Reachability (1.2.3)'
]
...
...
spec/unit/installer_spec.rb
View file @
697f8bd1
...
...
@@ -2,200 +2,233 @@ require File.expand_path('../../spec_helper', __FILE__)
module
Pod
describe
Installer
do
before
do
@sandbox
=
temporary_sandbox
config
.
repos_dir
=
fixture
(
'spec-repos'
)
config
.
project_pods_root
=
@sandbox
.
root
FileUtils
.
cp_r
(
fixture
(
'integration/JSONKit'
),
@sandbox
.
root
+
'JSONKit'
)
end
describe
"by default"
do
before
do
podfile
=
Podfile
.
new
do
platform
:ios
xcodeproj
'MyProject'
pod
'JSONKit'
end
@sandbox
=
temporary_sandbox
config
.
project_pods_root
=
temporary_sandbox
.
root
FileUtils
.
cp_r
(
fixture
(
'integration/JSONKit'
),
@sandbox
.
root
+
'JSONKit'
)
@installer
=
Installer
.
new
(
sandbox
,
podfile
)
target_installer
=
@installer
.
target_installers
.
first
target_installer
.
generate_xcconfig
([],
@sandbox
)
@xcconfig
=
target_installer
.
xcconfig
.
to_hash
end
it
"sets the header search paths where installed Pod headers can be found"
do
@xcconfig
[
'ALWAYS_SEARCH_USER_PATHS'
].
should
==
'YES'
end
it
"configures the project to load all members that implement Objective-c classes or categories from the static library"
do
@xcconfig
[
'OTHER_LDFLAGS'
].
should
==
'-ObjC'
end
it
"sets the PODS_ROOT build variable"
do
@xcconfig
[
'PODS_ROOT'
].
should
.
not
==
nil
end
it
"generates a BridgeSupport metadata file from all the pod headers"
do
podfile
=
Podfile
.
new
do
platform
:osx
pod
'ASIHTTPRequest'
end
FileUtils
.
cp_r
(
fixture
(
'integration/ASIHTTPRequest'
),
@sandbox
.
root
+
'ASIHTTPRequest'
)
resolver
=
Resolver
.
new
(
podfile
,
nil
,
@sandbox
)
installer
=
Installer
.
new
(
resolver
)
pods
=
installer
.
specifications
.
map
do
|
spec
|
LocalPod
.
new
(
spec
,
installer
.
sandbox
,
podfile
.
target_definitions
[
:default
].
platform
)
end
expected
=
pods
.
map
{
|
pod
|
pod
.
header_files
}.
flatten
.
map
{
|
header
|
config
.
project_pods_root
+
header
}
expected
.
size
.
should
>
0
installer
.
target_installers
.
first
.
bridge_support_generator_for
(
pods
,
installer
.
sandbox
).
headers
.
should
==
expected
end
it
"omits empty target definitions"
do
podfile
=
Podfile
.
new
do
platform
:ios
target
:not_empty
do
pod
'JSONKit'
end
end
resolver
=
Resolver
.
new
(
podfile
,
nil
,
@sandbox
)
installer
=
Installer
.
new
(
resolver
)
installer
.
target_installers
.
map
(
&
:target_definition
).
map
(
&
:name
).
should
==
[
:not_empty
]
end
it
"adds the user's build configurations"
do
path
=
fixture
(
'SampleProject/SampleProject.xcodeproj'
)
podfile
=
Podfile
.
new
do
platform
:ios
xcodeproj
path
,
'App Store'
=>
:release
end
resolver
=
Resolver
.
new
(
podfile
,
nil
,
Sandbox
.
new
(
fixture
(
'integration'
)))
installer
=
Installer
.
new
(
resolver
)
installer
.
project
.
build_configurations
.
map
(
&
:name
).
sort
.
should
==
[
'App Store'
,
'Debug'
,
'Release'
,
'Test'
]
end
it
"forces downloading of the `bleeding edge' version of a pod"
do
podfile
=
Podfile
.
new
do
platform
:ios
pod
'JSONKit'
,
:head
end
resolver
=
Resolver
.
new
(
podfile
,
nil
,
Sandbox
.
new
(
fixture
(
'integration'
)))
installer
=
Installer
.
new
(
resolver
)
pod
=
installer
.
pods
.
first
downloader
=
stub
(
'Downloader'
)
Downloader
.
stubs
(
:for_pod
).
returns
(
downloader
)
downloader
.
expects
(
:download_head
)
installer
.
download_pod
(
pod
)
end
end
describe
"concerning xcconfig files generation"
do
before
do
describe
"Concerning pre-installation computations"
do
def
generate_podfile
(
pods
=
[
'JSONKit'
])
podfile
=
Podfile
.
new
do
platform
:ios
xcodeproj
'MyProject'
pod
'JSONKit'
pod
s
.
each
{
|
name
|
pod
name
}
end
sandbox
=
Sandbox
.
new
(
fixture
(
'integration'
))
installer
=
Installer
.
new
(
sandbox
,
podfile
)
@xcconfig
=
installer
.
target_installers
.
first
.
xcconfig
.
to_hash
end
it
"sets the header search paths where installed Pod headers can be found"
do
@xcconfig
[
'ALWAYS_SEARCH_USER_PATHS'
].
should
==
'YES'
end
it
"configures the project to load all members that implement Objective-c classes or categories from the static library"
do
@xcconfig
[
'OTHER_LDFLAGS'
].
should
==
'-ObjC'
end
it
"sets the PODS_ROOT build variable"
do
@xcconfig
[
'PODS_ROOT'
].
should
.
not
==
nil
def
generate_lockfile
hash
=
{}
hash
[
'PODS'
]
=
[]
hash
[
'DEPENDENCIES'
]
=
[]
hash
[
'SPEC CHECKSUMS'
]
=
[]
hash
[
'COCOAPODS'
]
=
Pod
::
VERSION
Pod
::
Lockfile
.
new
(
hash
)
end
end
describe
"concerning multiple pods originating form the same spec"
do
extend
SpecHelper
::
Fixture
before
do
sandbox
=
temporary_sandbox
Pod
::
Config
.
instance
.
project_pods_root
=
sandbox
.
root
Pod
::
Config
.
instance
.
integrate_targets
=
false
podspec_path
=
fixture
(
'integration/Reachability/Reachability.podspec'
)
podfile
=
Podfile
.
new
do
platform
:osx
pod
'Reachability'
,
:podspec
=>
podspec_path
.
to_s
target
:debug
do
pod
'Reachability'
end
end
resolver
=
Resolver
.
new
(
podfile
,
nil
,
sandbox
)
@installer
=
Installer
.
new
(
resolver
)
end
# The double installation leads to a bug when different subspecs are
# activated for the same pod. We need a way to install a pod only
# once while keeping all the files of the actived subspecs.
#
# LocalPodSet?
#
it
"installs the pods only once"
do
LocalPod
.
any_instance
.
stubs
(
:downloaded?
).
returns
(
false
)
Downloader
::
GitHub
.
any_instance
.
expects
(
:download
).
once
podfile
=
generate_podfile
lockfile
=
generate_lockfile
@installer
=
Installer
.
new
(
@sandbox
,
podfile
,
lockfile
)
@installer
.
install!
end
it
"cleans a pod only onc
e"
do
LocalPod
.
any_instance
.
expects
(
:clean!
).
once
@installer
.
install!
end
# describe "#analyz
e" do
# it "doesn't affects creates changes in the file system" do
# end
#
end
it
"adds the files of the pod to the Pods project only once"
do
@installer
.
install!
group
=
@installer
.
project
.
pods
.
groups
.
find
{
|
g
|
g
.
name
==
'Reachability'
}
group
.
files
.
map
(
&
:name
).
should
==
[
"Reachability.h"
,
"Reachability.m"
]
it
"marks all pods as added if there is no lockfile"
do
@installer
.
pods_added_from_the_lockfile
.
should
==
[
'JSONKit'
]
end
it
"lists a pod only once"
do
reachability_pods
=
@installer
.
pods
.
map
(
&
:to_s
).
select
{
|
s
|
s
.
include?
(
'Reachability'
)
}
reachability_pods
.
count
.
should
==
1
end
end
describe
"concerning namespacing"
do
extend
SpecHelper
::
Fixture
before
do
sandbox
=
temporary_sandbox
Pod
::
Config
.
instance
.
project_pods_root
=
sandbox
.
root
Pod
::
Config
.
instance
.
integrate_targets
=
false
podspec_path
=
fixture
(
'chameleon'
)
podfile
=
Podfile
.
new
do
platform
:osx
pod
'Chameleon'
,
:local
=>
podspec_path
end
resolver
=
Resolver
.
new
(
podfile
,
nil
,
sandbox
)
@installer
=
Installer
.
new
(
resolver
)
end
it
"namespaces local pods"
do
@installer
.
install!
group
=
@installer
.
project
[
'Local Pods'
]
group
.
groups
.
map
(
&
:name
).
sort
.
should
==
%w| Chameleon |
end
it
"namespaces subspecs"
do
@installer
.
install!
group
=
@installer
.
project
[
'Local Pods/Chameleon'
]
group
.
groups
.
map
(
&
:name
).
sort
.
should
==
%w| AVFoundation AssetsLibrary MediaPlayer MessageUI StoreKit UIKit |
end
end
# describe "by default" do
# before do
# podfile = Podfile.new do
# platform :ios
# xcodeproj 'MyProject'
# pod 'JSONKit'
# end
# @sandbox = temporary_sandbox
# config.project_pods_root = temporary_sandbox.root
# FileUtils.cp_r(fixture('integration/JSONKit'), @sandbox.root + 'JSONKit')
# @installer = Installer.new(@sandbox, podfile)
# target_installer = @installer.target_installers.first
# target_installer.generate_xcconfig([], @sandbox)
# @xcconfig = target_installer.xcconfig.to_hash
# end
# it "sets the header search paths where installed Pod headers can be found" do
# @xcconfig['ALWAYS_SEARCH_USER_PATHS'].should == 'YES'
# end
# it "configures the project to load all members that implement Objective-c classes or categories from the static library" do
# @xcconfig['OTHER_LDFLAGS'].should == '-ObjC'
# end
# it "sets the PODS_ROOT build variable" do
# @xcconfig['PODS_ROOT'].should.not == nil
# end
# it "generates a BridgeSupport metadata file from all the pod headers" do
# podfile = Podfile.new do
# platform :osx
# pod 'ASIHTTPRequest'
# end
# FileUtils.cp_r(fixture('integration/ASIHTTPRequest'), @sandbox.root + 'ASIHTTPRequest')
# installer = Installer.new(@sandbox, podfile)
# pods = installer.specifications.map do |spec|
# LocalPod.new(spec, installer.sandbox, podfile.target_definitions[:default].platform)
# end
# expected = pods.map { |pod| pod.header_files }.flatten.map { |header| config.project_pods_root + header }
# expected.size.should > 0
# installer.target_installers.first.bridge_support_generator_for(pods, installer.sandbox).headers.should == expected
# end
# it "omits empty target definitions" do
# podfile = Podfile.new do
# platform :ios
# target :not_empty do
# pod 'JSONKit'
# end
# end
# installer = Installer.new(@sandbox, podfile)
# installer.target_installers.map(&:target_definition).map(&:name).should == [:not_empty]
# end
# it "adds the user's build configurations" do
# path = fixture('SampleProject/SampleProject.xcodeproj')
# podfile = Podfile.new do
# platform :ios
# xcodeproj path, 'App Store' => :release
# end
# installer = Installer.new(@sandbox, podfile)
# installer.project.build_configurations.map(&:name).sort.should == ['App Store', 'Debug', 'Release', 'Test']
# end
# it "forces downloading of the `bleeding edge' version of a pod" do
# podfile = Podfile.new do
# platform :ios
# pod 'JSONKit', :head
# end
# installer = Installer.new(@sandbox, podfile)
# pod = installer.pods.first
# downloader = stub('Downloader')
# Downloader.stubs(:for_pod).returns(downloader)
# downloader.expects(:download_head)
# installer.download_pod(pod)
# end
# end
# describe "concerning xcconfig files generation" do
# before do
# podfile = Podfile.new do
# platform :ios
# xcodeproj 'MyProject'
# pod 'JSONKit'
# end
# sandbox = Sandbox.new(fixture('integration'))
# installer = Installer.new(sandbox, podfile)
# @xcconfig = installer.target_installers.first.xcconfig.to_hash
# end
# it "sets the header search paths where installed Pod headers can be found" do
# @xcconfig['ALWAYS_SEARCH_USER_PATHS'].should == 'YES'
# end
# it "configures the project to load all members that implement Objective-c classes or categories from the static library" do
# @xcconfig['OTHER_LDFLAGS'].should == '-ObjC'
# end
# it "sets the PODS_ROOT build variable" do
# @xcconfig['PODS_ROOT'].should.not == nil
# end
# end
# describe "concerning multiple pods originating form the same spec" do
# extend SpecHelper::Fixture
# before do
# sandbox = temporary_sandbox
# Pod::Config.instance.project_pods_root = sandbox.root
# Pod::Config.instance.integrate_targets = false
# podspec_path = fixture('integration/Reachability/Reachability.podspec')
# podfile = Podfile.new do
# platform :osx
# pod 'Reachability', :podspec => podspec_path.to_s
# target :debug do
# pod 'Reachability'
# end
# end
# resolver = Resolver.new(podfile, nil, sandbox)
# @installer = Installer.new(resolver)
# end
# # The double installation leads to a bug when different subspecs are
# # activated for the same pod. We need a way to install a pod only
# # once while keeping all the files of the actived subspecs.
# #
# # LocalPodSet?
# #
# it "installs the pods only once" do
# LocalPod.any_instance.stubs(:downloaded?).returns(false)
# Downloader::GitHub.any_instance.expects(:download).once
# @installer.install!
# end
# it "cleans a pod only once" do
# LocalPod.any_instance.expects(:clean!).once
# @installer.install!
# end
# it "adds the files of the pod to the Pods project only once" do
# @installer.install!
# group = @installer.project.pods.groups.find { |g| g.name == 'Reachability' }
# group.files.map(&:name).should == ["Reachability.h", "Reachability.m"]
# end
# it "lists a pod only once" do
# reachability_pods = @installer.pods.map(&:to_s).select { |s| s.include?('Reachability') }
# reachability_pods.count.should == 1
# end
# end
# describe "concerning namespacing" do
# extend SpecHelper::Fixture
# before do
# sandbox = temporary_sandbox
# Pod::Config.instance.project_pods_root = sandbox.root
# Pod::Config.instance.integrate_targets = false
# podspec_path = fixture('chameleon')
# podfile = Podfile.new do
# platform :osx
# pod 'Chameleon', :local => podspec_path
# end
# resolver = Resolver.new(podfile, nil, sandbox)
# @installer = Installer.new(resolver)
# end
# it "namespaces local pods" do
# @installer.install!
# group = @installer.project['Local Pods']
# group.groups.map(&:name).sort.should == %w| Chameleon |
# end
# it "namespaces subspecs" do
# @installer.install!
# group = @installer.project['Local Pods/Chameleon']
# group.groups.map(&:name).sort.should == %w| AVFoundation AssetsLibrary MediaPlayer MessageUI StoreKit UIKit |
# end
# end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment