cocoapods-tt 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/cocoapods-tt/command/native/install.rb +56 -0
- data/lib/cocoapods-tt/command/native/update.rb +157 -0
- data/lib/cocoapods-tt/command/tt/make.rb +92 -0
- data/lib/cocoapods-tt/command/tt.rb +115 -0
- data/lib/cocoapods-tt/command.rb +1 -0
- data/lib/cocoapods-tt/gem_version.rb +3 -0
- data/lib/cocoapods-tt/native/command.rb +185 -0
- data/lib/cocoapods-tt/native/config.rb +366 -0
- data/lib/cocoapods-tt/native/core_overrides.rb +1 -0
- data/lib/cocoapods-tt/native/downloader/cache.rb +322 -0
- data/lib/cocoapods-tt/native/downloader/request.rb +86 -0
- data/lib/cocoapods-tt/native/downloader/response.rb +16 -0
- data/lib/cocoapods-tt/native/downloader.rb +192 -0
- data/lib/cocoapods-tt/native/executable.rb +247 -0
- data/lib/cocoapods-tt/native/external_sources/abstract_external_source.rb +205 -0
- data/lib/cocoapods-tt/native/external_sources/downloader_source.rb +30 -0
- data/lib/cocoapods-tt/native/external_sources/path_source.rb +55 -0
- data/lib/cocoapods-tt/native/external_sources/podspec_source.rb +54 -0
- data/lib/cocoapods-tt/native/external_sources.rb +57 -0
- data/lib/cocoapods-tt/native/gem_version.rb +5 -0
- data/lib/cocoapods-tt/native/generator/acknowledgements/markdown.rb +44 -0
- data/lib/cocoapods-tt/native/generator/acknowledgements/plist.rb +94 -0
- data/lib/cocoapods-tt/native/generator/acknowledgements.rb +107 -0
- data/lib/cocoapods-tt/native/generator/app_target_helper.rb +363 -0
- data/lib/cocoapods-tt/native/generator/bridge_support.rb +22 -0
- data/lib/cocoapods-tt/native/generator/constant.rb +19 -0
- data/lib/cocoapods-tt/native/generator/copy_dsyms_script.rb +56 -0
- data/lib/cocoapods-tt/native/generator/copy_resources_script.rb +223 -0
- data/lib/cocoapods-tt/native/generator/copy_xcframework_script.rb +227 -0
- data/lib/cocoapods-tt/native/generator/dummy_source.rb +31 -0
- data/lib/cocoapods-tt/native/generator/embed_frameworks_script.rb +196 -0
- data/lib/cocoapods-tt/native/generator/file_list.rb +39 -0
- data/lib/cocoapods-tt/native/generator/header.rb +103 -0
- data/lib/cocoapods-tt/native/generator/info_plist_file.rb +128 -0
- data/lib/cocoapods-tt/native/generator/module_map.rb +99 -0
- data/lib/cocoapods-tt/native/generator/prefix_header.rb +60 -0
- data/lib/cocoapods-tt/native/generator/script_phase_constants.rb +100 -0
- data/lib/cocoapods-tt/native/generator/umbrella_header.rb +46 -0
- data/lib/cocoapods-tt/native/hooks_manager.rb +132 -0
- data/lib/cocoapods-tt/native/installer/analyzer/analysis_result.rb +87 -0
- data/lib/cocoapods-tt/native/installer/analyzer/locking_dependency_analyzer.rb +103 -0
- data/lib/cocoapods-tt/native/installer/analyzer/pod_variant.rb +87 -0
- data/lib/cocoapods-tt/native/installer/analyzer/pod_variant_set.rb +175 -0
- data/lib/cocoapods-tt/native/installer/analyzer/podfile_dependency_cache.rb +55 -0
- data/lib/cocoapods-tt/native/installer/analyzer/sandbox_analyzer.rb +268 -0
- data/lib/cocoapods-tt/native/installer/analyzer/specs_state.rb +108 -0
- data/lib/cocoapods-tt/native/installer/analyzer/target_inspection_result.rb +58 -0
- data/lib/cocoapods-tt/native/installer/analyzer/target_inspector.rb +258 -0
- data/lib/cocoapods-tt/native/installer/analyzer.rb +1204 -0
- data/lib/cocoapods-tt/native/installer/base_install_hooks_context.rb +135 -0
- data/lib/cocoapods-tt/native/installer/installation_options.rb +195 -0
- data/lib/cocoapods-tt/native/installer/pod_source_installer.rb +224 -0
- data/lib/cocoapods-tt/native/installer/pod_source_preparer.rb +77 -0
- data/lib/cocoapods-tt/native/installer/podfile_validator.rb +168 -0
- data/lib/cocoapods-tt/native/installer/post_install_hooks_context.rb +9 -0
- data/lib/cocoapods-tt/native/installer/post_integrate_hooks_context.rb +9 -0
- data/lib/cocoapods-tt/native/installer/pre_install_hooks_context.rb +51 -0
- data/lib/cocoapods-tt/native/installer/pre_integrate_hooks_context.rb +9 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache.rb +11 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analysis_result.rb +53 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analyzer.rb +200 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache_version.rb +43 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_installation_cache.rb +103 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_metadata_cache.rb +73 -0
- data/lib/cocoapods-tt/native/installer/project_cache/target_cache_key.rb +176 -0
- data/lib/cocoapods-tt/native/installer/project_cache/target_metadata.rb +74 -0
- data/lib/cocoapods-tt/native/installer/sandbox_dir_cleaner.rb +105 -0
- data/lib/cocoapods-tt/native/installer/sandbox_header_paths_installer.rb +45 -0
- data/lib/cocoapods-tt/native/installer/source_provider_hooks_context.rb +34 -0
- data/lib/cocoapods-tt/native/installer/target_uuid_generator.rb +34 -0
- data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +179 -0
- data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator.rb +815 -0
- data/lib/cocoapods-tt/native/installer/user_project_integrator.rb +280 -0
- data/lib/cocoapods-tt/native/installer/xcode/multi_pods_project_generator.rb +82 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +66 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_installer.rb +192 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/app_host_installer.rb +154 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/file_references_installer.rb +329 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +195 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_installer.rb +1239 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_integrator.rb +312 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pods_project_writer.rb +90 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/project_generator.rb +120 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installation_result.rb +140 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer.rb +257 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer_helper.rb +110 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator.rb +291 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator_result.rb +54 -0
- data/lib/cocoapods-tt/native/installer/xcode/single_pods_project_generator.rb +38 -0
- data/lib/cocoapods-tt/native/installer/xcode/target_validator.rb +170 -0
- data/lib/cocoapods-tt/native/installer/xcode.rb +11 -0
- data/lib/cocoapods-tt/native/installer.rb +1044 -0
- data/lib/cocoapods-tt/native/native_target_extension.rb +60 -0
- data/lib/cocoapods-tt/native/open-uri.rb +33 -0
- data/lib/cocoapods-tt/native/podfile.rb +13 -0
- data/lib/cocoapods-tt/native/project.rb +544 -0
- data/lib/cocoapods-tt/native/resolver/lazy_specification.rb +88 -0
- data/lib/cocoapods-tt/native/resolver/resolver_specification.rb +41 -0
- data/lib/cocoapods-tt/native/resolver.rb +600 -0
- data/lib/cocoapods-tt/native/sandbox/file_accessor.rb +532 -0
- data/lib/cocoapods-tt/native/sandbox/headers_store.rb +163 -0
- data/lib/cocoapods-tt/native/sandbox/path_list.rb +242 -0
- data/lib/cocoapods-tt/native/sandbox/pod_dir_cleaner.rb +71 -0
- data/lib/cocoapods-tt/native/sandbox/podspec_finder.rb +23 -0
- data/lib/cocoapods-tt/native/sandbox.rb +470 -0
- data/lib/cocoapods-tt/native/sources_manager.rb +221 -0
- data/lib/cocoapods-tt/native/target/aggregate_target.rb +558 -0
- data/lib/cocoapods-tt/native/target/build_settings.rb +1385 -0
- data/lib/cocoapods-tt/native/target/pod_target.rb +1168 -0
- data/lib/cocoapods-tt/native/target.rb +378 -0
- data/lib/cocoapods-tt/native/user_interface/error_report.rb +204 -0
- data/lib/cocoapods-tt/native/user_interface/inspector_reporter.rb +102 -0
- data/lib/cocoapods-tt/native/user_interface.rb +463 -0
- data/lib/cocoapods-tt/native/validator.rb +1170 -0
- data/lib/cocoapods-tt/native/version_metadata.rb +26 -0
- data/lib/cocoapods-tt/native/xcode/framework_paths.rb +54 -0
- data/lib/cocoapods-tt/native/xcode/linkage_analyzer.rb +22 -0
- data/lib/cocoapods-tt/native/xcode/xcframework/xcframework_slice.rb +138 -0
- data/lib/cocoapods-tt/native/xcode/xcframework.rb +99 -0
- data/lib/cocoapods-tt/native/xcode.rb +7 -0
- data/lib/cocoapods-tt.rb +1 -0
- data/lib/cocoapods_plugin.rb +17 -0
- metadata +193 -0
@@ -0,0 +1,168 @@
|
|
1
|
+
module Pod
|
2
|
+
class Installer
|
3
|
+
# Validate the podfile before installing to catch errors and
|
4
|
+
# problems
|
5
|
+
#
|
6
|
+
class PodfileValidator
|
7
|
+
# @return [Podfile] The podfile being validated
|
8
|
+
#
|
9
|
+
attr_reader :podfile
|
10
|
+
|
11
|
+
# @return [Array<String>] any errors that have occurred during the validation
|
12
|
+
#
|
13
|
+
attr_reader :errors
|
14
|
+
|
15
|
+
# @return [Array<String>] any warnings that have occurred during the validation
|
16
|
+
#
|
17
|
+
attr_reader :warnings
|
18
|
+
|
19
|
+
# Initialize a new instance
|
20
|
+
#
|
21
|
+
# @param [Podfile] podfile
|
22
|
+
# The podfile to validate
|
23
|
+
#
|
24
|
+
# @param [Analyzer::PodfileDependencyCache] podfile_dependency_cache
|
25
|
+
# An (optional) cache of all the dependencies in the podfile
|
26
|
+
#
|
27
|
+
def initialize(podfile, podfile_dependency_cache = Analyzer::PodfileDependencyCache.from_podfile(podfile))
|
28
|
+
@podfile = podfile
|
29
|
+
@podfile_dependency_cache = podfile_dependency_cache
|
30
|
+
@errors = []
|
31
|
+
@warnings = []
|
32
|
+
@validated = false
|
33
|
+
end
|
34
|
+
|
35
|
+
# Validate the podfile
|
36
|
+
# Errors are added to the errors array
|
37
|
+
#
|
38
|
+
def validate
|
39
|
+
validate_installation_options
|
40
|
+
validate_pod_directives
|
41
|
+
validate_no_abstract_only_pods!
|
42
|
+
validate_dependencies_are_present!
|
43
|
+
validate_no_duplicate_targets!
|
44
|
+
|
45
|
+
@validated = true
|
46
|
+
end
|
47
|
+
|
48
|
+
# Wether the podfile is valid is not
|
49
|
+
# NOTE: Will execute `validate` if the podfile
|
50
|
+
# has not yet been validated
|
51
|
+
#
|
52
|
+
def valid?
|
53
|
+
validate unless @validated
|
54
|
+
|
55
|
+
@validated && errors.empty?
|
56
|
+
end
|
57
|
+
|
58
|
+
# A message describing any errors in the
|
59
|
+
# validation
|
60
|
+
#
|
61
|
+
def message
|
62
|
+
errors.join("\n")
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def add_error(error)
|
68
|
+
errors << error
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_warning(warning)
|
72
|
+
warnings << warning
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate_installation_options
|
76
|
+
installation_options = podfile.installation_options
|
77
|
+
|
78
|
+
# Validate `incremental_installation` depends on `generate_multiple_pod_projects`
|
79
|
+
invalid = installation_options.incremental_installation? && installation_options.incremental_installation != installation_options.generate_multiple_pod_projects
|
80
|
+
add_error 'The installation option `incremental_installation` requires the option `generate_multiple_pod_projects` to also be enabled.' if invalid
|
81
|
+
end
|
82
|
+
|
83
|
+
def validate_pod_directives
|
84
|
+
@podfile_dependency_cache.podfile_dependencies.each do |dependency|
|
85
|
+
validate_conflicting_external_sources!(dependency)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def validate_conflicting_external_sources!(dependency)
|
90
|
+
external_source = dependency.external_source
|
91
|
+
return false if external_source.nil?
|
92
|
+
|
93
|
+
available_downloaders = Downloader.downloader_class_by_key.keys
|
94
|
+
specified_downloaders = external_source.select { |key| available_downloaders.include?(key) }
|
95
|
+
if specified_downloaders.size > 1
|
96
|
+
add_error "The dependency `#{dependency.name}` specifies more than one download strategy(#{specified_downloaders.keys.join(',')})." \
|
97
|
+
'Only one is allowed'
|
98
|
+
end
|
99
|
+
|
100
|
+
pod_spec_or_path = external_source[:podspec].present? || external_source[:path].present?
|
101
|
+
if pod_spec_or_path && specified_downloaders.size > 0
|
102
|
+
add_error "The dependency `#{dependency.name}` specifies `podspec` or `path` in combination with other" \
|
103
|
+
' download strategies. This is not allowed'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Warns the user if the podfile is empty.
|
108
|
+
#
|
109
|
+
# @note The workspace is created in any case and all the user projects
|
110
|
+
# are added to it, however the projects are not integrated as
|
111
|
+
# there is no way to discern between target definitions which are
|
112
|
+
# empty and target definitions which just serve the purpose to
|
113
|
+
# wrap other ones. This is not an issue because empty target
|
114
|
+
# definitions generate empty libraries.
|
115
|
+
#
|
116
|
+
# @return [void]
|
117
|
+
#
|
118
|
+
def validate_dependencies_are_present!
|
119
|
+
if @podfile_dependency_cache.target_definition_list.all?(&:empty?)
|
120
|
+
add_warning 'The Podfile does not contain any dependencies.'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Verifies that no dependencies in the Podfile will end up not being built
|
125
|
+
# at all. In other words, all dependencies should belong to a non-abstract
|
126
|
+
# target, or be inherited by a target where `inheritance == complete`.
|
127
|
+
#
|
128
|
+
def validate_no_abstract_only_pods!
|
129
|
+
@podfile_dependency_cache.target_definition_list.each do |target_definition|
|
130
|
+
dependencies = @podfile_dependency_cache.target_definition_dependencies(target_definition)
|
131
|
+
next if dependencies.empty?
|
132
|
+
next unless target_definition.abstract?
|
133
|
+
|
134
|
+
children = target_definition.recursive_children
|
135
|
+
next if children.any? { |child_target_definition| target_definition_inherits?(:parent => target_definition, :child => child_target_definition) }
|
136
|
+
|
137
|
+
add_warning "The abstract target #{target_definition.name} is not inherited by a concrete target, " \
|
138
|
+
"so the following dependencies won't make it into any targets in your project:" \
|
139
|
+
"\n - #{dependencies.map(&:to_s).sort.join("\n - ")}"
|
140
|
+
|
141
|
+
next if target_definition.platform
|
142
|
+
|
143
|
+
add_error "The abstract target #{target_definition.name} must specify a platform since its dependencies are not inherited by a concrete target."
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def target_definition_inherits?(parent: nil, child: nil)
|
148
|
+
if parent == child
|
149
|
+
true
|
150
|
+
elsif child.exclusive?
|
151
|
+
false
|
152
|
+
else
|
153
|
+
target_definition_inherits?(:parent => parent, :child => child.parent)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def validate_no_duplicate_targets!
|
158
|
+
@podfile_dependency_cache.target_definition_list.group_by { |td| [td.name, td.user_project_path] }.
|
159
|
+
each do |(name, project), definitions|
|
160
|
+
next unless definitions.size > 1
|
161
|
+
error = "The target `#{name}` is declared multiple times"
|
162
|
+
error << " for the project `#{project}`" if project
|
163
|
+
add_error(error << '.')
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Pod
|
2
|
+
class Installer
|
3
|
+
# Context object designed to be used with the HooksManager which describes
|
4
|
+
# the context of the installer before analysis has been completed.
|
5
|
+
#
|
6
|
+
class PreInstallHooksContext
|
7
|
+
# @return [Podfile] The Podfile for the project.
|
8
|
+
#
|
9
|
+
attr_reader :podfile
|
10
|
+
|
11
|
+
# @return [Sandbox] The Sandbox for the project.
|
12
|
+
#
|
13
|
+
attr_reader :sandbox
|
14
|
+
|
15
|
+
# @return [String] The path to the sandbox root (`Pods` directory).
|
16
|
+
#
|
17
|
+
attr_reader :sandbox_root
|
18
|
+
|
19
|
+
# @return [Lockfile] The Lockfile for the project.
|
20
|
+
#
|
21
|
+
attr_reader :lockfile
|
22
|
+
|
23
|
+
# Initialize a new instance
|
24
|
+
#
|
25
|
+
# @param [Sandbox] sandbox see #sandbox
|
26
|
+
# @param [String] sandbox_root see #sandbox_root
|
27
|
+
# @param [Podfile] podfile see #podfile
|
28
|
+
# @param [Lockfile] lockfile see #lockfile
|
29
|
+
#
|
30
|
+
def initialize(podfile, sandbox, sandbox_root, lockfile)
|
31
|
+
@podfile = podfile
|
32
|
+
@sandbox = sandbox
|
33
|
+
@sandbox_root = sandbox_root
|
34
|
+
@lockfile = lockfile
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param [Sandbox] sandbox see {#sandbox}
|
38
|
+
#
|
39
|
+
# @param [Podfile] podfile see {#podfile}
|
40
|
+
#
|
41
|
+
# @param [Lockfile] lockfile see {#lockfile}
|
42
|
+
#
|
43
|
+
# @return [PreInstallHooksContext] Convenience class method to generate the
|
44
|
+
# static context.
|
45
|
+
#
|
46
|
+
def self.generate(sandbox, podfile, lockfile)
|
47
|
+
new(podfile, sandbox, sandbox.root.to_s, lockfile)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Pod
|
2
|
+
class Installer
|
3
|
+
module ProjectCache
|
4
|
+
autoload :ProjectCacheAnalyzer, 'cocoapods/installer/project_cache/project_cache_analyzer'
|
5
|
+
autoload :ProjectInstallationCache, 'cocoapods/installer/project_cache/project_installation_cache'
|
6
|
+
autoload :ProjectMetadataCache, 'cocoapods/installer/project_cache/project_metadata_cache'
|
7
|
+
autoload :ProjectCacheAnalysisResult, 'cocoapods/installer/project_cache/project_cache_analysis_result'
|
8
|
+
autoload :ProjectCacheVersion, 'cocoapods/installer/project_cache/project_cache_version'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Pod
|
2
|
+
class Installer
|
3
|
+
module ProjectCache
|
4
|
+
# The result object from analyzing the project cache.
|
5
|
+
#
|
6
|
+
class ProjectCacheAnalysisResult
|
7
|
+
# @return [Array<PodTarget>]
|
8
|
+
# The list of pod targets that need to be regenerated.
|
9
|
+
#
|
10
|
+
attr_reader :pod_targets_to_generate
|
11
|
+
|
12
|
+
# @return [Array<AggregateTarget>]
|
13
|
+
# The list of aggregate targets that need to be regenerated. This can be nil if we don't want to
|
14
|
+
# generate ANY aggregate targets since we still want to be able to generate an empty list of aggregate
|
15
|
+
# targets.
|
16
|
+
#
|
17
|
+
attr_reader :aggregate_targets_to_generate
|
18
|
+
|
19
|
+
# @return [Hash{String => TargetCacheKey}]
|
20
|
+
# Updated hash of target cache key by target label for all targets.
|
21
|
+
#
|
22
|
+
attr_reader :cache_key_by_target_label
|
23
|
+
|
24
|
+
# @return [Hash{String => Symbol}]
|
25
|
+
# The build configurations to install with each target.
|
26
|
+
#
|
27
|
+
attr_reader :build_configurations
|
28
|
+
|
29
|
+
# @return [Integer]
|
30
|
+
# The project object version to install with each target.
|
31
|
+
#
|
32
|
+
attr_reader :project_object_version
|
33
|
+
|
34
|
+
# Initialize a new instance.
|
35
|
+
#
|
36
|
+
# @param [Array<PodTarget>] pod_targets_to_generate @see #pod_targets_to_generate
|
37
|
+
# @param [Array<AggregateTarget] aggregate_targets_to_generate @see #aggregate_targets_to_generate
|
38
|
+
# @param [Hash{String => TargetCacheKey}] cache_key_by_target_label @see #cache_key_by_target_label
|
39
|
+
# @param [Hash{String => Symbol}] build_configurations @see #build_configurations
|
40
|
+
# @param [Integer] project_object_version @see #project_object_version
|
41
|
+
#
|
42
|
+
def initialize(pod_targets_to_generate, aggregate_targets_to_generate, cache_key_by_target_label,
|
43
|
+
build_configurations, project_object_version)
|
44
|
+
@pod_targets_to_generate = pod_targets_to_generate
|
45
|
+
@aggregate_targets_to_generate = aggregate_targets_to_generate
|
46
|
+
@cache_key_by_target_label = cache_key_by_target_label
|
47
|
+
@build_configurations = build_configurations
|
48
|
+
@project_object_version = project_object_version
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
module Pod
|
2
|
+
class Installer
|
3
|
+
module ProjectCache
|
4
|
+
# Analyzes the project cache and computes which pod targets need to be generated.
|
5
|
+
#
|
6
|
+
class ProjectCacheAnalyzer
|
7
|
+
require 'cocoapods/installer/project_cache/project_cache_analysis_result'
|
8
|
+
|
9
|
+
# @return [Sandbox] Project sandbox.
|
10
|
+
#
|
11
|
+
attr_reader :sandbox
|
12
|
+
|
13
|
+
# @return [ProjectInstallationCache] The cache of targets that were previously installed.
|
14
|
+
#
|
15
|
+
attr_reader :cache
|
16
|
+
|
17
|
+
# @return [Hash{String => Symbol}] The hash of user build configurations.
|
18
|
+
#
|
19
|
+
attr_reader :build_configurations
|
20
|
+
|
21
|
+
# @return [Integer] The object version from the user project.
|
22
|
+
#
|
23
|
+
attr_reader :project_object_version
|
24
|
+
|
25
|
+
# @return [Hash<String, Hash>] The podfile plugins to be run for the installation.
|
26
|
+
#
|
27
|
+
attr_reader :podfile_plugins
|
28
|
+
|
29
|
+
# @return [Array<PodTarget>] The list of pod targets.
|
30
|
+
#
|
31
|
+
attr_reader :pod_targets
|
32
|
+
|
33
|
+
# @return [Array<AggregateTarget>] The list of aggregate targets.
|
34
|
+
#
|
35
|
+
attr_reader :aggregate_targets
|
36
|
+
|
37
|
+
# @return [Hash<Symbol, Object>] Hash of installation options.
|
38
|
+
#
|
39
|
+
attr_reader :installation_options
|
40
|
+
|
41
|
+
# @return [Bool] Flag indicating if we want to ignore the cache and force a clean installation.
|
42
|
+
#
|
43
|
+
attr_reader :clean_install
|
44
|
+
|
45
|
+
# Initialize a new instance.
|
46
|
+
#
|
47
|
+
# @param [Sandbox] sandbox @see #sandbox
|
48
|
+
# @param [ProjectInstallationCache] cache @see #cache
|
49
|
+
# @param [Hash{String => Symbol}] build_configurations @see #build_configurations
|
50
|
+
# @param [Integer] project_object_version @see #project_object_version
|
51
|
+
# @param [Hash<String, Hash>] podfile_plugins @see #podfile_plugins
|
52
|
+
# @param [Array<PodTarget>] pod_targets @see #pod_targets
|
53
|
+
# @param [Array<AggregateTarget>] aggregate_targets @see #aggregate_targets
|
54
|
+
# @param [Hash<Symbol, Object>] installation_options @see #installation_options
|
55
|
+
# @param [Bool] clean_install @see #clean_install
|
56
|
+
#
|
57
|
+
def initialize(sandbox, cache, build_configurations, project_object_version, podfile_plugins, pod_targets, aggregate_targets, installation_options,
|
58
|
+
clean_install: false)
|
59
|
+
@sandbox = sandbox
|
60
|
+
@cache = cache
|
61
|
+
@build_configurations = build_configurations
|
62
|
+
@podfile_plugins = podfile_plugins
|
63
|
+
@pod_targets = pod_targets
|
64
|
+
@aggregate_targets = aggregate_targets
|
65
|
+
@project_object_version = project_object_version
|
66
|
+
@installation_options = installation_options
|
67
|
+
@clean_install = clean_install
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [ProjectCacheAnalysisResult]
|
71
|
+
# Compares all targets stored against the cache and computes which targets need to be regenerated.
|
72
|
+
#
|
73
|
+
def analyze
|
74
|
+
target_by_label = Hash[(pod_targets + aggregate_targets).map { |target| [target.label, target] }]
|
75
|
+
cache_key_by_target_label = create_cache_key_mappings(target_by_label)
|
76
|
+
|
77
|
+
full_install_results = ProjectCacheAnalysisResult.new(pod_targets, aggregate_targets, cache_key_by_target_label,
|
78
|
+
build_configurations, project_object_version)
|
79
|
+
if clean_install
|
80
|
+
UI.message 'Ignoring project cache from the provided `--clean-install` flag.'
|
81
|
+
return full_install_results
|
82
|
+
end
|
83
|
+
|
84
|
+
# Bail out early since these properties affect all targets and their associate projects.
|
85
|
+
if cache.build_configurations != build_configurations ||
|
86
|
+
cache.project_object_version != project_object_version ||
|
87
|
+
YAMLHelper.convert(cache.podfile_plugins) != YAMLHelper.convert(podfile_plugins) ||
|
88
|
+
YAMLHelper.convert(cache.installation_options) != YAMLHelper.convert(installation_options)
|
89
|
+
UI.message 'Ignoring project cache due to project configuration changes.'
|
90
|
+
return full_install_results
|
91
|
+
end
|
92
|
+
|
93
|
+
if project_names_changed?(pod_targets, cache)
|
94
|
+
UI.message 'Ignoring project cache due to project name changes.'
|
95
|
+
return full_install_results
|
96
|
+
end
|
97
|
+
|
98
|
+
pod_targets_to_generate = Set[]
|
99
|
+
aggregate_targets_to_generate = Set[]
|
100
|
+
added_targets = compute_added_targets(target_by_label, cache_key_by_target_label.keys, cache.cache_key_by_target_label.keys)
|
101
|
+
added_pod_targets, added_aggregate_targets = added_targets.partition { |target| target.is_a?(PodTarget) }
|
102
|
+
pod_targets_to_generate.merge(added_pod_targets)
|
103
|
+
aggregate_targets_to_generate.merge(added_aggregate_targets)
|
104
|
+
|
105
|
+
removed_aggregate_target_labels = compute_removed_targets(cache_key_by_target_label.keys, cache.cache_key_by_target_label.keys)
|
106
|
+
|
107
|
+
changed_targets = compute_changed_targets_from_cache(cache_key_by_target_label, target_by_label, cache)
|
108
|
+
changed_pod_targets, changed_aggregate_targets = changed_targets.partition { |target| target.is_a?(PodTarget) }
|
109
|
+
pod_targets_to_generate.merge(changed_pod_targets)
|
110
|
+
aggregate_targets_to_generate.merge(changed_aggregate_targets)
|
111
|
+
|
112
|
+
dirty_targets = compute_dirty_targets(pod_targets + aggregate_targets)
|
113
|
+
dirty_pod_targets, dirty_aggregate_targets = dirty_targets.partition { |target| target.is_a?(PodTarget) }
|
114
|
+
pod_targets_to_generate.merge(dirty_pod_targets)
|
115
|
+
aggregate_targets_to_generate.merge(dirty_aggregate_targets)
|
116
|
+
|
117
|
+
# Since multi xcodeproj will group targets by PodTarget#project_name into individual projects, we need to
|
118
|
+
# append these "sibling" targets to the list of targets we need to generate before finalizing the total list,
|
119
|
+
# otherwise we will end up with missing targets.
|
120
|
+
#
|
121
|
+
sibling_pod_targets = compute_sibling_pod_targets(pod_targets, pod_targets_to_generate)
|
122
|
+
pod_targets_to_generate.merge(sibling_pod_targets)
|
123
|
+
|
124
|
+
# We either return the full list of aggregate targets or none since the aggregate targets go into the
|
125
|
+
# Pods.xcodeproj and so we need to regenerate all aggregate targets when regenerating Pods.xcodeproj.
|
126
|
+
total_aggregate_targets_to_generate = unless aggregate_targets_to_generate.empty? && removed_aggregate_target_labels.empty?
|
127
|
+
aggregate_targets
|
128
|
+
end
|
129
|
+
|
130
|
+
ProjectCacheAnalysisResult.new(pod_targets_to_generate.to_a, total_aggregate_targets_to_generate,
|
131
|
+
cache_key_by_target_label, build_configurations, project_object_version)
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def create_cache_key_mappings(target_by_label)
|
137
|
+
Hash[target_by_label.map do |label, target|
|
138
|
+
case target
|
139
|
+
when PodTarget
|
140
|
+
local = sandbox.local?(target.pod_name)
|
141
|
+
checkout_options = sandbox.checkout_sources[target.pod_name]
|
142
|
+
[label, TargetCacheKey.from_pod_target(sandbox, target, :is_local_pod => local,
|
143
|
+
:checkout_options => checkout_options)]
|
144
|
+
when AggregateTarget
|
145
|
+
[label, TargetCacheKey.from_aggregate_target(sandbox, target)]
|
146
|
+
else
|
147
|
+
raise "[BUG] Unknown target type #{target}"
|
148
|
+
end
|
149
|
+
end]
|
150
|
+
end
|
151
|
+
|
152
|
+
def compute_added_targets(target_by_label, target_labels, cached_target_labels)
|
153
|
+
(target_labels - cached_target_labels).map do |label|
|
154
|
+
target_by_label[label]
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def compute_removed_targets(target_labels, cached_target_labels)
|
159
|
+
cached_target_labels - target_labels
|
160
|
+
end
|
161
|
+
|
162
|
+
def compute_changed_targets_from_cache(cache_key_by_target_label, target_by_label, cache)
|
163
|
+
cache_key_by_target_label.each_with_object([]) do |(label, cache_key), changed_targets|
|
164
|
+
next unless cache.cache_key_by_target_label[label]
|
165
|
+
if cache_key.key_difference(cache.cache_key_by_target_label[label]) == :project
|
166
|
+
changed_targets << target_by_label[label]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def compute_dirty_targets(targets)
|
172
|
+
targets.reject do |target|
|
173
|
+
support_files_dir_exists = File.exist? target.support_files_dir
|
174
|
+
xcodeproj_exists = case target
|
175
|
+
when PodTarget
|
176
|
+
File.exist? sandbox.pod_target_project_path(target.project_name)
|
177
|
+
when AggregateTarget
|
178
|
+
File.exist? sandbox.project_path
|
179
|
+
else
|
180
|
+
raise "[BUG] Unknown target type #{target}"
|
181
|
+
end
|
182
|
+
support_files_dir_exists && xcodeproj_exists
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def compute_sibling_pod_targets(pod_targets, pod_targets_to_generate)
|
187
|
+
pod_targets_by_project_name = pod_targets.group_by(&:project_name)
|
188
|
+
pod_targets_to_generate.flat_map { |t| pod_targets_by_project_name[t.project_name] }
|
189
|
+
end
|
190
|
+
|
191
|
+
def project_names_changed?(pod_targets, cache)
|
192
|
+
pod_targets.any? do |pod_target|
|
193
|
+
next unless (target_cache_key = cache.cache_key_by_target_label[pod_target.label])
|
194
|
+
target_cache_key.project_name != pod_target.project_name
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Pod
|
2
|
+
class Installer
|
3
|
+
module ProjectCache
|
4
|
+
# Object that stores, loads, and holds the version of the project cache.
|
5
|
+
#
|
6
|
+
class ProjectCacheVersion
|
7
|
+
# @return [Version] The version of the project cache.
|
8
|
+
#
|
9
|
+
attr_reader :version
|
10
|
+
|
11
|
+
# Initialize a new instance.
|
12
|
+
#
|
13
|
+
# @param [Version] version @see #version
|
14
|
+
#
|
15
|
+
def initialize(version = Version.create('0'))
|
16
|
+
@version = version
|
17
|
+
end
|
18
|
+
|
19
|
+
# Constructs a ProjectCacheVersion from a file.
|
20
|
+
#
|
21
|
+
# @param [String] path
|
22
|
+
# The path of the project cache
|
23
|
+
#
|
24
|
+
# @return [ProjectCacheVersion]
|
25
|
+
#
|
26
|
+
def self.from_file(path)
|
27
|
+
return ProjectCacheVersion.new unless File.exist?(path)
|
28
|
+
cached_version = Version.create(File.read(path))
|
29
|
+
ProjectCacheVersion.new(cached_version)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [void]
|
33
|
+
#
|
34
|
+
# @param [String] path
|
35
|
+
# The path of the project cache to save.
|
36
|
+
#
|
37
|
+
def save_as(path)
|
38
|
+
Sandbox.update_changed_file(path, version.to_s)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Pod
|
2
|
+
class Installer
|
3
|
+
module ProjectCache
|
4
|
+
# Represents the cache stored at Pods/.project/installation_cache
|
5
|
+
#
|
6
|
+
class ProjectInstallationCache
|
7
|
+
require 'cocoapods/installer/project_cache/target_cache_key'
|
8
|
+
|
9
|
+
# @return [Hash{String => TargetCacheKey}]
|
10
|
+
# Stored hash of target cache key objects for every pod target.
|
11
|
+
#
|
12
|
+
attr_reader :cache_key_by_target_label
|
13
|
+
|
14
|
+
# @return [Hash{String => Symbol}]
|
15
|
+
# Build configurations stored in the cache.
|
16
|
+
#
|
17
|
+
attr_reader :build_configurations
|
18
|
+
|
19
|
+
# @return [Integer]
|
20
|
+
# Project object stored in the cache.
|
21
|
+
#
|
22
|
+
attr_reader :project_object_version
|
23
|
+
|
24
|
+
# @return [Hash<String, Hash>]
|
25
|
+
# Podfile plugins used with a particular install.
|
26
|
+
#
|
27
|
+
attr_reader :podfile_plugins
|
28
|
+
|
29
|
+
# @return [Hash<Symbol, Object>]
|
30
|
+
# Configured installation options
|
31
|
+
#
|
32
|
+
attr_reader :installation_options
|
33
|
+
|
34
|
+
# Initializes a new instance.
|
35
|
+
#
|
36
|
+
# @param [Hash{String => TargetCacheKey}] cache_key_by_target_label @see #cache_key_by_target_label
|
37
|
+
# @param [Hash{String => Symbol}] build_configurations @see #build_configurations
|
38
|
+
# @param [Integer] project_object_version @see #project_object_version
|
39
|
+
# @param [Hash<String, Hash>] podfile_plugins @see #podfile_plugins
|
40
|
+
# @param [Hash<Symbol, Object>] installation_options @see #installation_options
|
41
|
+
#
|
42
|
+
def initialize(cache_key_by_target_label = {}, build_configurations = nil, project_object_version = nil, podfile_plugins = {}, installation_options = {})
|
43
|
+
@cache_key_by_target_label = cache_key_by_target_label
|
44
|
+
@build_configurations = build_configurations
|
45
|
+
@project_object_version = project_object_version
|
46
|
+
@podfile_plugins = podfile_plugins
|
47
|
+
@installation_options = installation_options
|
48
|
+
end
|
49
|
+
|
50
|
+
def update_cache_key_by_target_label!(cache_key_by_target_label)
|
51
|
+
@cache_key_by_target_label = cache_key_by_target_label
|
52
|
+
end
|
53
|
+
|
54
|
+
def update_build_configurations!(build_configurations)
|
55
|
+
@build_configurations = build_configurations
|
56
|
+
end
|
57
|
+
|
58
|
+
def update_project_object_version!(project_object_version)
|
59
|
+
@project_object_version = project_object_version
|
60
|
+
end
|
61
|
+
|
62
|
+
def update_podfile_plugins!(podfile_plugins)
|
63
|
+
@podfile_plugins = podfile_plugins
|
64
|
+
end
|
65
|
+
|
66
|
+
def update_installation_options!(installation_options)
|
67
|
+
@installation_options = installation_options
|
68
|
+
end
|
69
|
+
|
70
|
+
def save_as(path)
|
71
|
+
Pathname(path).dirname.mkpath
|
72
|
+
Sandbox.update_changed_file(path, YAMLHelper.convert(to_hash))
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.from_file(sandbox, path)
|
76
|
+
return ProjectInstallationCache.new unless File.exist?(path)
|
77
|
+
contents = YAMLHelper.load_file(path)
|
78
|
+
cache_keys = contents.fetch('CACHE_KEYS', {})
|
79
|
+
cache_key_by_target_label = Hash[cache_keys.map do |name, key_hash|
|
80
|
+
[name, TargetCacheKey.from_cache_hash(sandbox, key_hash)]
|
81
|
+
end]
|
82
|
+
project_object_version = contents['OBJECT_VERSION']
|
83
|
+
build_configurations = contents['BUILD_CONFIGURATIONS']
|
84
|
+
podfile_plugins = contents['PLUGINS']
|
85
|
+
installation_options = contents['INSTALLATION_OPTIONS']
|
86
|
+
ProjectInstallationCache.new(cache_key_by_target_label, build_configurations, project_object_version, podfile_plugins, installation_options)
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_hash
|
90
|
+
cache_key_contents = Hash[cache_key_by_target_label.map do |label, key|
|
91
|
+
[label, key.to_h]
|
92
|
+
end]
|
93
|
+
contents = { 'CACHE_KEYS' => cache_key_contents }
|
94
|
+
contents['BUILD_CONFIGURATIONS'] = build_configurations if build_configurations
|
95
|
+
contents['OBJECT_VERSION'] = project_object_version if project_object_version
|
96
|
+
contents['PLUGINS'] = podfile_plugins if podfile_plugins
|
97
|
+
contents['INSTALLATION_OPTIONS'] = installation_options if installation_options
|
98
|
+
contents
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|