cocoapods 0.16.4 → 0.17.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +108 -0
  3. data/README.md +3 -3
  4. data/bin/pod +1 -1
  5. data/lib/cocoapods.rb +31 -31
  6. data/lib/cocoapods/command.rb +62 -107
  7. data/lib/cocoapods/command/inter_process_communication.rb +103 -0
  8. data/lib/cocoapods/command/list.rb +45 -44
  9. data/lib/cocoapods/command/outdated.rb +28 -25
  10. data/lib/cocoapods/command/project.rb +90 -0
  11. data/lib/cocoapods/command/push.rb +50 -32
  12. data/lib/cocoapods/command/repo.rb +125 -155
  13. data/lib/cocoapods/command/search.rb +23 -12
  14. data/lib/cocoapods/command/setup.rb +103 -64
  15. data/lib/cocoapods/command/spec.rb +329 -90
  16. data/lib/cocoapods/config.rb +197 -44
  17. data/lib/cocoapods/downloader.rb +47 -34
  18. data/lib/cocoapods/executable.rb +98 -41
  19. data/lib/cocoapods/external_sources.rb +325 -0
  20. data/lib/cocoapods/file_list.rb +8 -1
  21. data/lib/cocoapods/gem_version.rb +7 -0
  22. data/lib/cocoapods/generator/acknowledgements.rb +71 -7
  23. data/lib/cocoapods/generator/acknowledgements/markdown.rb +10 -9
  24. data/lib/cocoapods/generator/acknowledgements/plist.rb +9 -8
  25. data/lib/cocoapods/generator/copy_resources_script.rb +2 -2
  26. data/lib/cocoapods/generator/documentation.rb +153 -37
  27. data/lib/cocoapods/generator/prefix_header.rb +82 -0
  28. data/lib/cocoapods/generator/target_header.rb +58 -0
  29. data/lib/cocoapods/generator/xcconfig.rb +130 -0
  30. data/lib/cocoapods/hooks/installer_representation.rb +123 -0
  31. data/lib/cocoapods/hooks/library_representation.rb +79 -0
  32. data/lib/cocoapods/hooks/pod_representation.rb +74 -0
  33. data/lib/cocoapods/installer.rb +398 -147
  34. data/lib/cocoapods/installer/analyzer.rb +556 -0
  35. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +253 -0
  36. data/lib/cocoapods/installer/file_references_installer.rb +179 -0
  37. data/lib/cocoapods/installer/pod_source_installer.rb +289 -0
  38. data/lib/cocoapods/installer/target_installer.rb +307 -112
  39. data/lib/cocoapods/installer/user_project_integrator.rb +140 -176
  40. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +193 -0
  41. data/lib/cocoapods/library.rb +195 -0
  42. data/lib/cocoapods/open_uri.rb +16 -14
  43. data/lib/cocoapods/project.rb +175 -52
  44. data/lib/cocoapods/resolver.rb +151 -164
  45. data/lib/cocoapods/sandbox.rb +276 -54
  46. data/lib/cocoapods/sandbox/file_accessor.rb +210 -0
  47. data/lib/cocoapods/sandbox/headers_store.rb +96 -0
  48. data/lib/cocoapods/sandbox/path_list.rb +178 -0
  49. data/lib/cocoapods/sources_manager.rb +218 -0
  50. data/lib/cocoapods/user_interface.rb +82 -18
  51. data/lib/cocoapods/{command → user_interface}/error_report.rb +5 -5
  52. data/lib/cocoapods/validator.rb +379 -0
  53. metadata +74 -55
  54. data/lib/cocoapods/command/install.rb +0 -55
  55. data/lib/cocoapods/command/linter.rb +0 -317
  56. data/lib/cocoapods/command/update.rb +0 -25
  57. data/lib/cocoapods/dependency.rb +0 -285
  58. data/lib/cocoapods/downloader/git.rb +0 -276
  59. data/lib/cocoapods/downloader/http.rb +0 -99
  60. data/lib/cocoapods/downloader/mercurial.rb +0 -26
  61. data/lib/cocoapods/downloader/subversion.rb +0 -42
  62. data/lib/cocoapods/local_pod.rb +0 -620
  63. data/lib/cocoapods/lockfile.rb +0 -274
  64. data/lib/cocoapods/platform.rb +0 -127
  65. data/lib/cocoapods/podfile.rb +0 -551
  66. data/lib/cocoapods/source.rb +0 -223
  67. data/lib/cocoapods/specification.rb +0 -579
  68. data/lib/cocoapods/specification/set.rb +0 -175
  69. data/lib/cocoapods/specification/statistics.rb +0 -112
  70. data/lib/cocoapods/user_interface/ui_pod.rb +0 -130
  71. data/lib/cocoapods/version.rb +0 -26
@@ -0,0 +1,130 @@
1
+ module Pod
2
+ module Generator
3
+
4
+ # Generates an xcconfig file for each target of the Pods project. The
5
+ # configuration file should be used by the user target as well.
6
+ #
7
+ class XCConfig
8
+
9
+ # @return [Sandbox] the sandbox where the Pods project is installed.
10
+ #
11
+ attr_reader :sandbox
12
+
13
+ # @return [Array<Specification::Consumer>] the consumers for the
14
+ # specifications of the library which needs the xcconfig.
15
+ #
16
+ attr_reader :spec_consumers
17
+
18
+ # @return [String] the relative path of the Pods root respect the user
19
+ # project that should be integrated by this library.
20
+ #
21
+ attr_reader :relative_pods_root
22
+
23
+ # @param [Sandbox] sandbox @see sandbox
24
+ # @param [Array<LocalPod>] pods @see pods
25
+ # @param [String] relative_pods_root @see relative_pods_root
26
+ #
27
+ def initialize(sandbox, spec_consumers, relative_pods_root)
28
+ @sandbox = sandbox
29
+ @spec_consumers = spec_consumers
30
+ @relative_pods_root = relative_pods_root
31
+ end
32
+
33
+ # @return [Bool] whether the Podfile specifies to add the `-fobjc-arc`
34
+ # flag for compatibility.
35
+ #
36
+ attr_accessor :set_arc_compatibility_flag
37
+
38
+ #-----------------------------------------------------------------------#
39
+
40
+ # Generates the xcconfig for the library.
41
+ #
42
+ # @return [Xcodeproj::Config]
43
+ #
44
+ # @note The value `PODS_HEADERS_SEARCH_PATHS` is used to store the headers
45
+ # so xcconfig can reference the variable.
46
+ #
47
+ def generate
48
+ ld_flags = '-ObjC'
49
+ if set_arc_compatibility_flag && spec_consumers.any? { |consumer| consumer.requires_arc }
50
+ ld_flags << ' -fobjc-arc'
51
+ end
52
+
53
+ @xcconfig = Xcodeproj::Config.new({
54
+ 'ALWAYS_SEARCH_USER_PATHS' => 'YES',
55
+ 'OTHER_LDFLAGS' => ld_flags,
56
+ 'HEADER_SEARCH_PATHS' => '${PODS_HEADERS_SEARCH_PATHS}',
57
+ 'PODS_ROOT' => relative_pods_root,
58
+ 'PODS_HEADERS_SEARCH_PATHS' => '${PODS_PUBLIC_HEADERS_SEARCH_PATHS}',
59
+ 'PODS_BUILD_HEADERS_SEARCH_PATHS' => quote(sandbox.build_headers.search_paths),
60
+ 'PODS_PUBLIC_HEADERS_SEARCH_PATHS' => quote(sandbox.public_headers.search_paths),
61
+ })
62
+
63
+ spec_consumers.each do |consumer|
64
+ @xcconfig.merge!(consumer.xcconfig);
65
+ @xcconfig.libraries.merge(consumer.libraries);
66
+ @xcconfig.frameworks.merge(consumer.frameworks);
67
+ @xcconfig.weak_frameworks.merge(consumer.weak_frameworks);
68
+ end
69
+
70
+ @xcconfig
71
+ end
72
+
73
+ # @return [Xcodeproj::Config] The generated xcconfig.
74
+ #
75
+ attr_reader :xcconfig
76
+
77
+ # @return [Hash] The settings of the xcconfig that the Pods project
78
+ # needs to override.
79
+ #
80
+ def self.pods_project_settings
81
+ { 'PODS_ROOT' => '${SRCROOT}',
82
+ 'PODS_HEADERS_SEARCH_PATHS' => '${PODS_BUILD_HEADERS_SEARCH_PATHS}' }
83
+ end
84
+
85
+ # Generates and saves the xcconfig to the given path.
86
+ #
87
+ # @param [Pathname] path
88
+ # the path where the prefix header should be stored.
89
+ #
90
+ # @return [void]
91
+ #
92
+ def save_as(path)
93
+ path.open('w') { |file| file.write(generate) }
94
+ end
95
+
96
+ #-----------------------------------------------------------------------#
97
+
98
+ # @!group Private helpers.
99
+
100
+ private
101
+
102
+ # @return [String] the default linker flags. `-ObjC` is always included
103
+ # while `-fobjc-arc` is included only if requested in the
104
+ # Podfile.
105
+ #
106
+ def default_ld_flags
107
+ flags = %w[ -ObjC ]
108
+ requires_arc = pods.any? { |pod| pod.requires_arc? }
109
+ if requires_arc && set_arc_compatibility_flag
110
+ flags << '-fobjc-arc'
111
+ end
112
+ flags.join(" ")
113
+ end
114
+
115
+ # Converts an array of strings to a single string where the each string
116
+ # is surrounded by double quotes and separated by a space. Used to
117
+ # represent strings in a xcconfig file.
118
+ #
119
+ # @param [Array<String>] strings
120
+ # a list of strings.
121
+ #
122
+ # @return [String] the resulting string.
123
+ #
124
+ def quote(strings)
125
+ strings.sort.map { |s| %W|"#{s}"| }.join(" ")
126
+ end
127
+ end
128
+ end
129
+ end
130
+
@@ -0,0 +1,123 @@
1
+ module Pod
2
+
3
+ class Podfile
4
+ def config
5
+ UI.warn "Podfile#config is deprecated. The config is accessible from " \
6
+ "the parameter passed to the hooks"
7
+ Config.instance
8
+ end
9
+ end
10
+
11
+ module Hooks
12
+
13
+ # The installer representation to pass to the hooks.
14
+ #
15
+ class InstallerRepresentation
16
+
17
+ public
18
+
19
+ # @!group Public Hooks API
20
+
21
+ # @return [Pathname] The root of the sandbox.
22
+ #
23
+ def sandbox_root
24
+ installer.sandbox.root
25
+ end
26
+
27
+ # @return [Pod::Project] the `Pods/Pods.xcodeproj` project.
28
+ #
29
+ def project
30
+ installer.pods_project
31
+ end
32
+
33
+ # @return [Array<PodRepresentation>] The representation of the Pods.
34
+ #
35
+ def pods
36
+ installer.pod_reps
37
+ end
38
+
39
+ # @return [Array<LibraryRepresentation>] The representation of the
40
+ # libraries.
41
+ #
42
+ def libraries
43
+ installer.library_reps
44
+ end
45
+
46
+ # @return [Hash{LibraryRepresentation => Array<Specification>}] The
47
+ # specifications grouped by target definition.
48
+ #
49
+ def specs_by_lib
50
+ result = {}
51
+ installer.libraries.each do |lib|
52
+ result[installer.library_rep(lib)] = lib.specs
53
+ end
54
+ result
55
+ end
56
+
57
+ # @return [Hash{LibraryRepresentation => Array<PodRepresentation>}] The
58
+ # local pod instances grouped by target.
59
+ #
60
+ def pods_by_lib
61
+ result = {}
62
+ installer.libraries.each do |lib|
63
+ pod_names = lib.specs.map { |spec| spec.root.name }.uniq
64
+ pod_reps = pods.select { |rep| pod_names.include?(rep.name) }
65
+ result[lib.target_definition] = pod_reps
66
+ end
67
+ result
68
+ end
69
+
70
+ #-----------------------------------------------------------------------#
71
+ public
72
+
73
+ # @!group Compatibility
74
+ #
75
+ # The following aliases provides compatibility with CP < 0.17
76
+
77
+ alias :target_installers :libraries
78
+ alias :specs_by_target :specs_by_lib
79
+ alias :local_pods_by_target :pods_by_lib
80
+
81
+ #-----------------------------------------------------------------------#
82
+
83
+ public
84
+
85
+ # @!group Unsafe Hooks API
86
+ #
87
+ # The interface of the following objects might change at any time.
88
+ # If there some information which is needed, please open an issue.
89
+
90
+ # @return [Sandbox] sandbox the sandbox where the support files should
91
+ # be generated.
92
+ #
93
+ def sandbox
94
+ installer.sandbox
95
+ end
96
+
97
+ # @return [Config] The config singleton used for the installation.
98
+ #
99
+ def config
100
+ Config.instance
101
+ end
102
+
103
+ # @return [Installer] The installer described by this instance.
104
+ #
105
+ attr_reader :installer
106
+
107
+ #-----------------------------------------------------------------------#
108
+
109
+ # @!group Private implementation
110
+
111
+ # @param [Installer] installer @see installer
112
+ #
113
+ def initialize(installer)
114
+ @installer = installer
115
+ end
116
+
117
+ #-----------------------------------------------------------------------#
118
+
119
+ end
120
+ end
121
+ end
122
+
123
+
@@ -0,0 +1,79 @@
1
+ module Pod
2
+ module Hooks
3
+ class LibraryRepresentation
4
+
5
+ # Stores the information of the target installer
6
+
7
+ #-----------------------------------------------------------------------#
8
+
9
+ # @return [String] The name of the Pods library.
10
+ #
11
+ def name
12
+ library.name
13
+ end
14
+
15
+ # @return [Array<Dependency>] The dependencies of this library.
16
+ #
17
+ def dependencies
18
+ target_definition.dependencies
19
+ end
20
+
21
+ # @return [Pathname] The path of the prefix_header
22
+ #
23
+ def prefix_header_filename
24
+ library.prefix_header_path
25
+ end
26
+
27
+ # @return [Project] The Pods project of the sandbox.
28
+ #
29
+ def project
30
+ sandbox.project
31
+ end
32
+
33
+ # @return [TargetDefinition] The target definition of the library.
34
+ #
35
+ def target_definition
36
+ library.target_definition
37
+ end
38
+
39
+ #-----------------------------------------------------------------------#
40
+
41
+ public
42
+
43
+ # @!group Unsafe Hooks API
44
+
45
+ # @return [Sandbox] sandbox the sandbox where the support files should
46
+ # be generated.
47
+ #
48
+ attr_reader :sandbox
49
+
50
+ # @return [Library] The library whose target needs to be generated.
51
+ #
52
+ attr_reader :library
53
+
54
+ # @return [PBXNativeTarget] The target generated by the installation
55
+ # process.
56
+ #
57
+ def target
58
+ library.target
59
+ end
60
+
61
+ #-----------------------------------------------------------------------#
62
+
63
+ # @!group Private implementation
64
+
65
+ # @param [Sandbox] sandbox @see sandbox
66
+ # @param [Library] library @see library
67
+ #
68
+ def initialize(sandbox, library)
69
+ @sandbox = sandbox
70
+ @library = library
71
+ end
72
+
73
+ #-----------------------------------------------------------------------#
74
+
75
+ end
76
+ end
77
+ end
78
+
79
+
@@ -0,0 +1,74 @@
1
+ module Pod
2
+
3
+ class Specification
4
+ def config
5
+ UI.warn "Specification#config is deprecated. The config is accessible from " \
6
+ "the parameter passed to the hooks"
7
+ Config.instance
8
+ end
9
+ end
10
+
11
+ module Hooks
12
+
13
+ # Stores the information of the Installer for the hooks
14
+ #
15
+ class PodRepresentation
16
+
17
+ # @return [String]
18
+ #
19
+ attr_accessor :name
20
+
21
+ # @return [Version]
22
+ #
23
+ def version
24
+ root_spec.version
25
+ end
26
+
27
+ # @return [Specification]
28
+ #
29
+ def root_spec
30
+ file_accessors.first.spec.root
31
+ end
32
+
33
+ # @return [Array<Specification>]
34
+ #
35
+ def specs
36
+ file_accessors.map(&:spec).uniq
37
+ end
38
+
39
+ # @return [Pathname]
40
+ #
41
+ def root
42
+ file_accessors.first.path_list.root
43
+ end
44
+
45
+ # @return [Array<Pathname>]
46
+ #
47
+ def source_files
48
+ file_accessors.map(&:source_files).flatten.uniq
49
+ end
50
+
51
+ #-----------------------------------------------------------------------#
52
+
53
+ # @!group Private implementation
54
+
55
+ # @param [Installer] installer @see installer
56
+ #
57
+ def initialize(name, file_accessors)
58
+ @name = name
59
+ @file_accessors = file_accessors
60
+ end
61
+
62
+ def to_s
63
+ root_spec.to_s
64
+ end
65
+
66
+ private
67
+
68
+ attr_reader :file_accessors
69
+
70
+ #-----------------------------------------------------------------------#
71
+
72
+ end
73
+ end
74
+ end
@@ -1,216 +1,467 @@
1
- require 'colored'
2
-
3
1
  module Pod
2
+
3
+ # The Installer is responsible of taking a Podfile and transform it in the
4
+ # Pods libraries. It also integrates the user project so the Pods
5
+ # libraries can be used out of the box.
6
+ #
7
+ # The Installer is capable of doing incremental updates to an existing Pod
8
+ # installation.
9
+ #
10
+ # The Installer gets the information that it needs mainly from 3 files:
11
+ #
12
+ # - Podfile: The specification written by the user that contains
13
+ # information about targets and Pods.
14
+ # - Podfile.lock: Contains information about the pods that were previously
15
+ # installed and in concert with the Podfile provides information about
16
+ # which specific version of a Pod should be installed. This file is
17
+ # ignored in update mode.
18
+ # - Manifest.lock: A file contained in the Pods folder that keeps track of
19
+ # the pods installed in the local machine. This files is used once the
20
+ # exact versions of the Pods has been computed to detect if that version
21
+ # is already installed. This file is not intended to be kept under source
22
+ # control and is a copy of the Podfile.lock.
23
+ #
24
+ # The Installer is designed to work in environments where the Podfile folder
25
+ # is under source control and environments where it is not. The rest of the
26
+ # files, like the user project and the workspace are assumed to be under
27
+ # source control.
28
+ #
4
29
  class Installer
5
- autoload :TargetInstaller, 'cocoapods/installer/target_installer'
6
- autoload :UserProjectIntegrator, 'cocoapods/installer/user_project_integrator'
30
+
31
+ autoload :Analyzer, 'cocoapods/installer/analyzer'
32
+ autoload :FileReferencesInstaller, 'cocoapods/installer/file_references_installer'
33
+ autoload :PodSourceInstaller, 'cocoapods/installer/pod_source_installer'
34
+ autoload :TargetInstaller, 'cocoapods/installer/target_installer'
35
+ autoload :UserProjectIntegrator, 'cocoapods/installer/user_project_integrator'
7
36
 
8
37
  include Config::Mixin
9
38
 
10
- attr_reader :resolver, :sandbox, :lockfile
39
+ # @return [Sandbox] The sandbox where the Pods should be installed.
40
+ #
41
+ attr_reader :sandbox
42
+
43
+ # @return [Podfile] The Podfile specification that contains the information
44
+ # of the Pods that should be installed.
45
+ #
46
+ attr_reader :podfile
47
+
48
+ # @return [Lockfile] The Lockfile that stores the information about the
49
+ # Pods previously installed on any machine.
50
+ #
51
+ attr_reader :lockfile
52
+
53
+ # @param [Sandbox] sandbox @see sandbox
54
+ # @param [Podfile] podfile @see podfile
55
+ # @param [Lockfile] lockfile @see lockfile
56
+ #
57
+ def initialize(sandbox, podfile, lockfile = nil)
58
+ @sandbox = sandbox
59
+ @podfile = podfile
60
+ @lockfile = lockfile
61
+ end
62
+
63
+ # @return [Bool] Whether the installer is in update mode. In update mode
64
+ # the contents of the Lockfile are not taken into account for
65
+ # deciding what Pods to install.
66
+ #
67
+ attr_accessor :update_mode
68
+
69
+ # Installs the Pods.
70
+ #
71
+ # The installation process of is mostly linear with few minor complications
72
+ # to keep in mind:
73
+ #
74
+ # - The stored podspecs need to be cleaned before the resolution step
75
+ # otherwise the sandbox might return an old podspec and not download
76
+ # the new one from an external source.
77
+ # - The resolver might trigger the download of Pods from external sources
78
+ # necessary to retrieve their podspec (unless it is instructed not to
79
+ # do it).
80
+ #
81
+ # @return [void]
82
+ #
83
+ def install!
84
+ resolve_dependencies
85
+ download_dependencies
86
+ generate_pods_project
87
+ integrate_user_project if config.integrate_targets?
88
+ end
11
89
 
12
- def initialize(resolver)
13
- @resolver = resolver
14
- @podfile = resolver.podfile
15
- @sandbox = resolver.sandbox
90
+ def resolve_dependencies
91
+ UI.section "Analyzing dependencies" do
92
+ analyze
93
+ prepare_for_legacy_compatibility
94
+ clean_sandbox
95
+ end
16
96
  end
17
97
 
18
- def project
19
- return @project if @project
20
- @project = Pod::Project.new
21
- @project.user_build_configurations = @podfile.user_build_configurations
22
- pods.each { |p| p.add_file_references_to_project(@project) }
23
- pods.each { |p| p.link_headers }
24
- @project
98
+ def download_dependencies
99
+ UI.section "Downloading dependencies" do
100
+ create_file_accessors
101
+ install_pod_sources
102
+ end
25
103
  end
26
104
 
27
- def target_installers
28
- @target_installers ||= @podfile.target_definitions.values.map do |definition|
29
- TargetInstaller.new(@podfile, project, definition) unless definition.empty?
30
- end.compact
105
+ def generate_pods_project
106
+ UI.section "Generating Pods project" do
107
+ prepare_pods_project
108
+ run_pre_install_hooks
109
+ install_file_references
110
+ install_targets
111
+ run_post_install_hooks
112
+ write_pod_project
113
+ write_lockfiles
114
+ end
31
115
  end
32
116
 
33
- # Install the Pods. If the resolver indicated that a Pod should be installed
34
- # and it exits, it is removed an then reinstalled. In any case if the Pod
35
- # doesn't exits it is installed.
117
+ #-------------------------------------------------------------------------#
118
+
119
+ public
120
+
121
+ # @!group Installation results
122
+
123
+ # @return [Analyzer] the analyzer which provides the information about what
124
+ # needs to be installed.
125
+ #
126
+ attr_reader :analysis_result
127
+
128
+ # @return [Pod::Project] the `Pods/Pods.xcodeproj` project.
129
+ #
130
+ attr_reader :pods_project
131
+
132
+ # @return [Array<String>] The Pods that should be installed.
133
+ #
134
+ attr_reader :names_of_pods_to_install
135
+
136
+ # @return [Array<Library>] The libraries generated by the installation
137
+ # process.
138
+ #
139
+ attr_reader :libraries
140
+
141
+ # @return [Array<Specification>] The specifications that where installed.
142
+ #
143
+ attr_accessor :installed_specs
144
+
145
+ #-------------------------------------------------------------------------#
146
+
147
+ private
148
+
149
+ # @!group Installation steps
150
+
151
+ # @return [void]
152
+ #
153
+ def analyze
154
+ analyzer = Analyzer.new(sandbox, podfile, lockfile)
155
+ analyzer.update_mode = update_mode
156
+ @analysis_result = analyzer.analyze
157
+ @libraries = analyzer.result.libraries
158
+ end
159
+
160
+ # Prepares the Pods folder in order to be compatible with the most recent
161
+ # version of CocoaPods.
36
162
  #
37
163
  # @return [void]
38
164
  #
39
- def install_dependencies!
40
- pods.sort_by { |pod| pod.top_specification.name.downcase }.each do |pod|
41
- should_install = @resolver.should_install?(pod.top_specification.name) || !pod.exists?
42
- if should_install
43
- UI.section("Installing #{pod}".green, "-> ".green) do
44
- unless pod.downloaded?
45
- pod.implode
46
- download_pod(pod)
47
- end
48
- # The docs need to be generated before cleaning because the
49
- # documentation is created for all the subspecs.
50
- generate_docs(pod)
51
- # Here we clean pod's that just have been downloaded or have been
52
- # pre-downloaded in AbstractExternalSource#specification_from_sandbox.
53
- pod.clean! if config.clean?
165
+ def prepare_for_legacy_compatibility
166
+ # move_target_support_files_if_needed
167
+ # move_Local_Podspecs_to_Podspecs_if_needed
168
+ # move_pods_to_sources_folder_if_needed
169
+ end
170
+
171
+ # @return [void] In this step we clean all the folders that will be
172
+ # regenerated from scratch and any file which might not be
173
+ # overwritten.
174
+ #
175
+ # @todo [#247] Clean the headers of only the pods to install.
176
+ #
177
+ def clean_sandbox
178
+ sandbox.build_headers.implode!
179
+ sandbox.public_headers.implode!
180
+
181
+ unless sandbox_state.deleted.empty?
182
+ title_options = { :verbose_prefix => "-> ".red }
183
+ sandbox_state.deleted.each do |pod_name|
184
+ UI.titled_section("Removing #{pod_name}".red, title_options) do
185
+ sandbox.clean_pod(pod_name)
54
186
  end
55
- else
56
- UI.section("Using #{pod}", "-> ".green)
57
187
  end
58
188
  end
59
189
  end
60
190
 
61
- def download_pod(pod)
62
- downloader = Downloader.for_pod(pod)
63
- # Force the `bleeding edge' version if necessary.
64
- if pod.top_specification.version.head?
65
- if downloader.respond_to?(:download_head)
66
- downloader.download_head
67
- else
68
- raise Informative, "The downloader of class `#{downloader.class.name}' does not support the `:head' option."
191
+ # TODO: the file accessor should be initialized by the sandbox as they
192
+ # created by the Pod source installer as well.
193
+ #
194
+ def create_file_accessors
195
+ libraries.each do |library|
196
+ library.specs.each do |spec|
197
+ pod_root = sandbox.pod_dir(spec.root.name)
198
+ path_list = Sandbox::PathList.new(pod_root)
199
+ file_accessor = Sandbox::FileAccessor.new(path_list, spec.consumer(library.platform))
200
+ library.file_accessors ||= []
201
+ library.file_accessors << file_accessor
69
202
  end
70
- else
71
- downloader.download
72
203
  end
73
- pod.downloaded = true
74
204
  end
75
205
 
76
- #TODO: move to generator ?
77
- def generate_docs(pod)
78
- doc_generator = Generator::Documentation.new(pod)
79
- if ( config.generate_docs? && !doc_generator.already_installed? )
80
- UI.section " > Installing documentation"
81
- doc_generator.generate(config.doc_install?)
82
- else
83
- UI.section " > Using existing documentation"
206
+ # Downloads, installs the documentation and cleans the sources of the Pods
207
+ # which need to be installed.
208
+ #
209
+ # @return [void]
210
+ #
211
+ def install_pod_sources
212
+ @installed_specs = []
213
+ pods_to_install = sandbox_state.added | sandbox_state.changed
214
+ title_options = { :verbose_prefix => "-> ".green }
215
+ root_specs.sort_by(&:name).each do |spec|
216
+ if pods_to_install.include?(spec.name)
217
+ UI.titled_section("Installing #{spec}".green, title_options) do
218
+ install_source_of_pod(spec.name)
219
+ end
220
+ else
221
+ UI.titled_section("Using #{spec}", title_options)
222
+ end
84
223
  end
85
224
  end
86
225
 
87
- # @TODO: use the local pod implode
226
+ # Install the Pods. If the resolver indicated that a Pod should be
227
+ # installed and it exits, it is removed an then reinstalled. In any case if
228
+ # the Pod doesn't exits it is installed.
88
229
  #
89
- def remove_deleted_dependencies!
90
- resolver.removed_pods.each do |pod_name|
91
- UI.section("Removing #{pod_name}", "-> ".red) do
92
- path = sandbox.root + pod_name
93
- path.rmtree if path.exist?
230
+ # @return [void]
231
+ #
232
+ def install_source_of_pod(pod_name)
233
+ specs_by_platform = {}
234
+ libraries.each do |library|
235
+ specs = library.specs.select { |spec| spec.root.name == pod_name }
236
+
237
+ unless specs.empty?
238
+ specs_by_platform[library.platform] ||= []
239
+ specs_by_platform[library.platform].concat(specs)
94
240
  end
95
241
  end
242
+
243
+ pod_installer = PodSourceInstaller.new(sandbox, specs_by_platform)
244
+ pod_installer.clean = config.clean?
245
+ pod_installer.aggressive_cache = config.aggressive_cache?
246
+ pod_installer.generate_docs = config.generate_docs?
247
+ pod_installer.install_docs = config.install_docs?
248
+ pod_installer.install!
249
+ @installed_specs.concat(specs_by_platform.values.flatten)
96
250
  end
97
251
 
98
- def install!
99
- @sandbox.prepare_for_install
100
- UI.section "Resolving dependencies of #{UI.path @podfile.defined_in_file}" do
101
- specs_by_target
252
+ # Creates the Pods project from scratch if it doesn't exists.
253
+ #
254
+ # @return [void]
255
+ #
256
+ # @todo Clean and modify the project if it exists.
257
+ #
258
+ def prepare_pods_project
259
+ UI.message "- Creating Pods project" do
260
+ @pods_project = Pod::Project.new(sandbox.project_path)
261
+ if config.podfile_path.exist?
262
+ @pods_project.add_podfile(config.podfile_path)
263
+ end
264
+ sandbox.project = @pods_project
102
265
  end
266
+ end
103
267
 
104
- UI.section "Removing deleted dependencies" do
105
- remove_deleted_dependencies!
106
- end unless resolver.removed_pods.empty?
107
-
108
- UI.section "Downloading dependencies" do
109
- install_dependencies!
110
- end
111
268
 
112
- UI.section "Generating support files" do
113
- UI.message "- Running pre install hooks" do
114
- run_pre_install_hooks
115
- end
269
+ # Installs the file references in the Pods project. This is done once per
270
+ # Pod as the same file reference might be shared by multiple targets.
271
+ #
272
+ # @return [void]
273
+ #
274
+ def install_file_references
275
+ installer = FileReferencesInstaller.new(sandbox, libraries, pods_project)
276
+ installer.install!
277
+ end
116
278
 
117
- UI.message"- Generating project" do
118
- project
279
+ # Installs the targets of the Pods projects and generates their support
280
+ # files.
281
+ #
282
+ # @return [void]
283
+ #
284
+ def install_targets
285
+ UI.message"- Installing targets" do
286
+ libraries.sort_by(&:name).each do |library|
287
+ next if library.target_definition.empty?
288
+ target_installer = TargetInstaller.new(sandbox, library)
289
+ target_installer.install!
119
290
  end
291
+ end
292
+ end
120
293
 
121
- UI.message"- Installing targets" do
122
- generate_target_support_files
123
- end
294
+ # Writes the Pods project to the disk.
295
+ #
296
+ # @return [void]
297
+ #
298
+ def write_pod_project
299
+ UI.message "- Writing Xcode project file to #{UI.path sandbox.project_path}" do
300
+ pods_project.main_group.sort_by_type!
301
+ pods_project['Frameworks'].sort_by_type!
302
+ pods_project.save_as(sandbox.project_path)
303
+ end
304
+ end
124
305
 
125
- UI.message "- Running post install hooks" do
126
- # Post install hooks run _before_ saving of project, so that they can alter it before saving.
127
- run_post_install_hooks
128
- end
306
+ # Writes the Podfile and the lock files.
307
+ #
308
+ # @todo Pass the checkout options to the Lockfile.
309
+ #
310
+ # @return [void]
311
+ #
312
+ def write_lockfiles
313
+ # checkout_options = sandbox.checkout_options
314
+ @lockfile = Lockfile.generate(podfile, analysis_result.specifications)
129
315
 
130
- UI.message "- Writing Xcode project file to #{UI.path @sandbox.project_path}" do
131
- project.save_as(@sandbox.project_path)
132
- end
316
+ UI.message "- Writing Lockfile in #{UI.path config.lockfile_path}" do
317
+ @lockfile.write_to_disk(config.lockfile_path)
318
+ end
133
319
 
134
- UI.message "- Writing lockfile in #{UI.path config.project_lockfile}" do
135
- @lockfile = Lockfile.generate(@podfile, specs_by_target.values.flatten)
136
- @lockfile.write_to_disk(config.project_lockfile)
137
- end
320
+ UI.message "- Writing Manifest in #{UI.path sandbox.manifest_path}" do
321
+ @lockfile.write_to_disk(sandbox.manifest_path)
138
322
  end
323
+ end
139
324
 
140
- UserProjectIntegrator.new(@podfile).integrate! if config.integrate_targets?
325
+ # Integrates the user projects adding the dependencies on the CocoaPods
326
+ # libraries, setting them up to use the xcconfigs and performing other
327
+ # actions. This step is also responsible of creating the workspace if
328
+ # needed.
329
+ #
330
+ # @return [void]
331
+ #
332
+ # @todo [#397] The libraries should be cleaned and the re-added on every
333
+ # installation. Maybe a clean_user_project phase should be added.
334
+ # In any case it appears to be a good idea store target definition
335
+ # information in the lockfile.
336
+ #
337
+ def integrate_user_project
338
+ UI.section "Integrating client #{'project'.pluralize(libraries.map(&:user_project_path).uniq.count) }" do
339
+ installation_root = config.installation_root
340
+ integrator = UserProjectIntegrator.new(podfile, sandbox, installation_root, libraries)
341
+ integrator.integrate!
342
+ end
141
343
  end
142
344
 
345
+ #-------------------------------------------------------------------------#
346
+
347
+ private
348
+
349
+ # @!group Hooks
350
+
351
+ # Runs the pre install hooks of the installed specs and of the Podfile.
352
+ #
353
+ # @return [void]
354
+ #
143
355
  def run_pre_install_hooks
144
- pods_by_target.each do |target_definition, pods|
145
- pods.each do |pod|
146
- pod.top_specification.pre_install(pod, target_definition)
356
+ UI.message "- Running pre install hooks" do
357
+ installed_specs.each do |spec|
358
+ executed = false
359
+ libraries_using_spec(spec).each do |lib|
360
+ executed ||= spec.pre_install!(pod_rep(spec.root.name), library_rep(lib))
361
+ end
362
+ UI.message "- #{spec.name}" if executed
147
363
  end
364
+
365
+ executed = @podfile.pre_install!(installer_rep)
366
+ UI.message "- Podfile" if executed
148
367
  end
149
- @podfile.pre_install!(self)
150
368
  end
151
369
 
370
+ # Runs the post install hooks of the installed specs and of the Podfile.
371
+ #
372
+ # @note Post install hooks run _before_ saving of project, so that they
373
+ # can alter it before it is written to the disk.
374
+ #
375
+ # @return [void]
376
+ #
152
377
  def run_post_install_hooks
153
- # we loop over target installers instead of pods, because we yield the target installer
154
- # to the spec post install hook.
155
- target_installers.each do |target_installer|
156
- specs_by_target[target_installer.target_definition].each do |spec|
157
- spec.post_install(target_installer)
378
+ UI.message "- Running post install hooks" do
379
+ installed_specs.each do |spec|
380
+ executed = false
381
+ libraries_using_spec(spec).each do |lib|
382
+ executed ||= spec.post_install!(library_rep(lib))
383
+ end
384
+ UI.message "- #{spec.name}" if executed
158
385
  end
386
+ executed = @podfile.post_install!(installer_rep)
387
+ UI.message "- Podfile" if executed
159
388
  end
160
- @podfile.post_install!(self)
161
389
  end
162
390
 
163
- def generate_target_support_files
164
- target_installers.each do |target_installer|
165
- pods_for_target = pods_by_target[target_installer.target_definition]
166
- target_installer.install!(pods_for_target, @sandbox)
167
- acknowledgements_path = target_installer.target_definition.acknowledgements_path
168
- Generator::Acknowledgements.new(target_installer.target_definition,
169
- pods_for_target).save_as(acknowledgements_path)
170
- generate_dummy_source(target_installer)
171
- end
391
+ #-------------------------------------------------------------------------#
392
+
393
+ public
394
+
395
+ # @!group Hooks Data
396
+
397
+ # @return [InstallerRepresentation]
398
+ #
399
+ def installer_rep
400
+ Hooks::InstallerRepresentation.new(self)
172
401
  end
173
402
 
174
- def generate_dummy_source(target_installer)
175
- class_name_identifier = target_installer.target_definition.label
176
- dummy_source = Generator::DummySource.new(class_name_identifier)
177
- filename = "#{dummy_source.class_name}.m"
178
- pathname = Pathname.new(sandbox.root + filename)
179
- dummy_source.save_as(pathname)
403
+ # @return [PodRepresentation] The hook representation of a Pod.
404
+ #
405
+ # @param [String] pod
406
+ # The name of the pod.
407
+ #
408
+ # @return [PodRepresentation] The pod representation.
409
+ #
410
+ def pod_rep(pod)
411
+ all_file_accessors = libraries.map(&:file_accessors).flatten.compact
412
+ file_accessors = all_file_accessors.select { |fa| fa.spec.root.name == pod }
413
+ Hooks::PodRepresentation.new(pod, file_accessors)
414
+ end
180
415
 
181
- file = project.new_file(filename, "Targets Support Files")
182
- target_installer.target.source_build_phase.add_file_reference(file)
416
+ # @return [LibraryRepresentation]
417
+ #
418
+ def library_rep(library)
419
+ Hooks::LibraryRepresentation.new(sandbox, library)
183
420
  end
184
421
 
185
- def specs_by_target
186
- @specs_by_target ||= @resolver.resolve
422
+ # @return [Array<LibraryRepresentation>]
423
+ #
424
+ def library_reps
425
+ @library_reps ||= libraries.map { |lib| library_rep(lib) }
187
426
  end
188
427
 
189
- # @return [Array<Specification>] All dependencies that have been resolved.
190
- def specifications
191
- specs_by_target.values.flatten
428
+ # @return [Array<PodRepresentation>]
429
+ #
430
+ def pod_reps
431
+ root_specs.sort_by { |spec| spec.name }.map { |spec| pod_rep(spec.name) }
192
432
  end
193
433
 
194
- # @return [Array<LocalPod>] A list of LocalPod instances for each
195
- # dependency that is not a download-only one.
196
- def pods
197
- pods_by_target.values.flatten.uniq
434
+ # Returns the libraries which use the given specification.
435
+ #
436
+ # @param [Specification] spec
437
+ # The specification for which the client libraries are needed.
438
+ #
439
+ # @return [Array<Library>] The library.
440
+ #
441
+ def libraries_using_spec(spec)
442
+ libraries.select { |lib| lib.specs.include?(spec) }
198
443
  end
199
444
 
200
- def pods_by_target
201
- @pods_by_spec = {}
202
- result = {}
203
- specs_by_target.each do |target_definition, specs|
204
- @pods_by_spec[target_definition.platform] = {}
205
- result[target_definition] = specs.map do |spec|
206
- if spec.local?
207
- @sandbox.locally_sourced_pod_for_spec(spec, target_definition.platform)
208
- else
209
- @sandbox.local_pod_for_spec(spec, target_definition.platform)
210
- end
211
- end.uniq.compact
212
- end
213
- result
445
+ #-------------------------------------------------------------------------#
446
+
447
+ private
448
+
449
+ # @!group Private helpers
450
+
451
+ # @return [Array<Specification>] All the root specifications of the
452
+ # installation.
453
+ #
454
+ def root_specs
455
+ analysis_result.specifications.map { |spec| spec.root }.uniq
456
+ end
457
+
458
+ # @return [SpecsState] The state of the sandbox returned by the analyzer.
459
+ #
460
+ def sandbox_state
461
+ analysis_result.sandbox_state
214
462
  end
463
+
464
+ #-------------------------------------------------------------------------#
465
+
215
466
  end
216
467
  end