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,103 @@
|
|
1
|
+
require 'molinillo/dependency_graph'
|
2
|
+
|
3
|
+
module Pod
|
4
|
+
class Installer
|
5
|
+
class Analyzer
|
6
|
+
# Generates dependencies that require the specific version of the Pods
|
7
|
+
# that haven't changed in the {Lockfile}.
|
8
|
+
module LockingDependencyAnalyzer
|
9
|
+
# Generates dependencies that require the specific version of the Pods
|
10
|
+
# that haven't changed in the {Lockfile}.
|
11
|
+
#
|
12
|
+
# These dependencies are passed to the {Resolver}, unless the installer
|
13
|
+
# is in update mode, to prevent it from upgrading the Pods that weren't
|
14
|
+
# changed in the {Podfile}.
|
15
|
+
#
|
16
|
+
# @param [Lockfile] lockfile the lockfile containing dependency constraints
|
17
|
+
#
|
18
|
+
# @param [Array<String>] pods_to_update
|
19
|
+
# List of pod names which needs to be updated because installer is
|
20
|
+
# in update mode for these pods. Pods in this list and all their recursive dependencies
|
21
|
+
# will not be included in generated dependency graph
|
22
|
+
#
|
23
|
+
# @param [Array<String>] pods_to_unlock
|
24
|
+
# List of pod names whose version constraints will be removed from the generated dependency graph.
|
25
|
+
# Recursive dependencies of the pods won't be affected. This is currently used to force local pods
|
26
|
+
# to be evaluated again whenever checksum of the specification of the local pods changes.
|
27
|
+
#
|
28
|
+
# @return [Molinillo::DependencyGraph<Dependency>] the dependencies
|
29
|
+
# generated by the lockfile that prevent the resolver to update
|
30
|
+
# a Pod.
|
31
|
+
#
|
32
|
+
def self.generate_version_locking_dependencies(lockfile, pods_to_update, pods_to_unlock = [])
|
33
|
+
dependency_graph = Molinillo::DependencyGraph.new
|
34
|
+
|
35
|
+
if lockfile
|
36
|
+
added_dependency_strings = Set.new
|
37
|
+
|
38
|
+
explicit_dependencies = lockfile.dependencies
|
39
|
+
explicit_dependencies.each do |dependency|
|
40
|
+
dependency_graph.add_vertex(dependency.name, dependency, true)
|
41
|
+
end
|
42
|
+
|
43
|
+
pods = lockfile.to_hash['PODS'] || []
|
44
|
+
pods.each do |pod|
|
45
|
+
add_to_dependency_graph(pod, [], dependency_graph, pods_to_unlock, added_dependency_strings)
|
46
|
+
end
|
47
|
+
|
48
|
+
pods_to_update = pods_to_update.flat_map do |u|
|
49
|
+
root_name = Specification.root_name(u).downcase
|
50
|
+
dependency_graph.vertices.each_key.select { |n| Specification.root_name(n).downcase == root_name }
|
51
|
+
end
|
52
|
+
|
53
|
+
pods_to_update.each do |u|
|
54
|
+
dependency_graph.detach_vertex_named(u)
|
55
|
+
end
|
56
|
+
|
57
|
+
dependency_graph.each do |vertex|
|
58
|
+
next unless dep = vertex.payload
|
59
|
+
dep.podspec_repo ||= lockfile.spec_repo(dep.root_name)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
dependency_graph
|
64
|
+
end
|
65
|
+
|
66
|
+
# Generates a completely 'unlocked' dependency graph.
|
67
|
+
#
|
68
|
+
# @return [Molinillo::DependencyGraph<Dependency>] an empty dependency
|
69
|
+
# graph
|
70
|
+
#
|
71
|
+
def self.unlocked_dependency_graph
|
72
|
+
Molinillo::DependencyGraph.new
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def self.add_child_vertex_to_graph(dependency_string, parents, dependency_graph, pods_to_unlock, added_dependency_strings)
|
78
|
+
return unless added_dependency_strings.add?(dependency_string)
|
79
|
+
dependency = Dependency.from_string(dependency_string)
|
80
|
+
if pods_to_unlock.include?(dependency.root_name)
|
81
|
+
dependency = Dependency.new(dependency.name)
|
82
|
+
end
|
83
|
+
vertex = dependency_graph.add_child_vertex(dependency.name, nil, parents, nil)
|
84
|
+
dependency = vertex.payload.merge(dependency) if vertex.payload
|
85
|
+
vertex.payload = dependency
|
86
|
+
dependency
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.add_to_dependency_graph(object, parents, dependency_graph, pods_to_unlock, added_dependency_strings)
|
90
|
+
case object
|
91
|
+
when String
|
92
|
+
add_child_vertex_to_graph(object, parents, dependency_graph, pods_to_unlock, added_dependency_strings)
|
93
|
+
when Hash
|
94
|
+
object.each do |key, value|
|
95
|
+
dependency = add_child_vertex_to_graph(key, parents, dependency_graph, pods_to_unlock, added_dependency_strings)
|
96
|
+
value.each { |v| add_to_dependency_graph(v, [dependency.name], dependency_graph, pods_to_unlock, added_dependency_strings) }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Pod
|
2
|
+
class Installer
|
3
|
+
class Analyzer
|
4
|
+
# Bundles the information needed to setup a {PodTarget}.
|
5
|
+
class PodVariant
|
6
|
+
# @return [Array<Specification>] the spec and subspecs for the target
|
7
|
+
#
|
8
|
+
attr_reader :specs
|
9
|
+
|
10
|
+
# @return [Array<Specification>] the test specs for the target
|
11
|
+
#
|
12
|
+
attr_reader :test_specs
|
13
|
+
|
14
|
+
# @return [Array<Specification>] the app specs for the target
|
15
|
+
#
|
16
|
+
attr_reader :app_specs
|
17
|
+
|
18
|
+
# @return [Platform] the platform
|
19
|
+
#
|
20
|
+
attr_reader :platform
|
21
|
+
|
22
|
+
# @return [BuildType] the build type of the target
|
23
|
+
#
|
24
|
+
attr_reader :build_type
|
25
|
+
|
26
|
+
# @return [String] the Swift version of the target.
|
27
|
+
#
|
28
|
+
attr_reader :swift_version
|
29
|
+
|
30
|
+
# Initialize a new instance from its attributes.
|
31
|
+
#
|
32
|
+
# @param [Array<Specification>] specs @see #specs
|
33
|
+
# @param [Array<Specification>] test_specs @see #test_specs
|
34
|
+
# @param [Array<Specification>] app_specs @see #app_specs
|
35
|
+
# @param [Platform] platform @see #platform
|
36
|
+
# @param [BuildType] build_type @see #build_type
|
37
|
+
# @param [String] swift_version @see #swift_version
|
38
|
+
#
|
39
|
+
def initialize(specs, test_specs, app_specs, platform, build_type = BuildType.static_library,
|
40
|
+
swift_version = nil)
|
41
|
+
@specs = specs
|
42
|
+
@test_specs = test_specs
|
43
|
+
@app_specs = app_specs
|
44
|
+
@platform = platform
|
45
|
+
@build_type = build_type
|
46
|
+
@swift_version = swift_version
|
47
|
+
@hash = [specs, platform, build_type, swift_version].hash
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Specification] the root specification
|
51
|
+
#
|
52
|
+
def root_spec
|
53
|
+
specs.first.root
|
54
|
+
end
|
55
|
+
|
56
|
+
# @note Non library specs are intentionally not included as part of the equality for pod variants since a pod
|
57
|
+
# variant should not be affected by the number of test nor app specs included.
|
58
|
+
#
|
59
|
+
# @return [Bool] whether the {PodVariant} is equal to another taking all all their attributes into account
|
60
|
+
#
|
61
|
+
def ==(other)
|
62
|
+
self.class == other.class &&
|
63
|
+
build_type == other.build_type &&
|
64
|
+
swift_version == other.swift_version &&
|
65
|
+
platform == other.platform &&
|
66
|
+
specs == other.specs
|
67
|
+
end
|
68
|
+
alias_method :eql?, :==
|
69
|
+
|
70
|
+
# Hashes the instance by all its attributes.
|
71
|
+
#
|
72
|
+
# This adds support to make instances usable as Hash keys.
|
73
|
+
#
|
74
|
+
# @!visibility private
|
75
|
+
attr_reader :hash
|
76
|
+
|
77
|
+
# @param [String] swift_version The swift version to use for this variant.
|
78
|
+
#
|
79
|
+
# @return [PodVariant] A copy of this pod variant with the specified Swift version.
|
80
|
+
#
|
81
|
+
def scoped_with_swift_version(swift_version)
|
82
|
+
PodVariant.new(specs, test_specs, app_specs, platform, build_type, swift_version)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Pod
|
4
|
+
class Installer
|
5
|
+
class Analyzer
|
6
|
+
# Collects all {PodVariant}.
|
7
|
+
class PodVariantSet
|
8
|
+
# @return [Array<PodVariant>] the different variants within this set.
|
9
|
+
#
|
10
|
+
attr_reader :variants
|
11
|
+
|
12
|
+
# Initialize a new instance.
|
13
|
+
#
|
14
|
+
# @param [Array<PodVariant>] variants @see #variants
|
15
|
+
#
|
16
|
+
def initialize(variants)
|
17
|
+
@variants = variants
|
18
|
+
end
|
19
|
+
|
20
|
+
# Describes what makes each {PodVariant} distinct among the others.
|
21
|
+
#
|
22
|
+
# @return [Hash<PodVariant, String>]
|
23
|
+
#
|
24
|
+
def scope_suffixes
|
25
|
+
return { variants.first => nil } if variants.count == 1
|
26
|
+
Hash[scope_by_specs.map do |variant, scope|
|
27
|
+
require 'digest'
|
28
|
+
scope = Digest::MD5.hexdigest(scope)[0..7] if !scope.nil? && scope.length >= 50
|
29
|
+
[variant, scope]
|
30
|
+
end]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Groups the collection by result of the block.
|
34
|
+
#
|
35
|
+
# @param [Block<Variant, #hash>] block
|
36
|
+
# @return [Array<PodVariantSet>]
|
37
|
+
#
|
38
|
+
def group_by(&block)
|
39
|
+
variants.group_by(&block).map { |_, v| PodVariantSet.new(v) }
|
40
|
+
end
|
41
|
+
|
42
|
+
# @private
|
43
|
+
#
|
44
|
+
# Prepends the given scoped {PodVariant}s with another scoping label, if there
|
45
|
+
# was more than one group of {PodVariant}s given.
|
46
|
+
#
|
47
|
+
# @param [Array<Hash<PodVariant, String>>] scoped_variants
|
48
|
+
# {PodVariant}s, which where grouped on base of a criteria, which is used
|
49
|
+
# in the block argument to generate a descriptive label.
|
50
|
+
#
|
51
|
+
# @param [Block<PodVariant, String>] block
|
52
|
+
# takes a {PodVariant} and returns a scope suffix which is prepended, if
|
53
|
+
# necessary.
|
54
|
+
#
|
55
|
+
# @return [Hash<PodVariant, String>]
|
56
|
+
#
|
57
|
+
def scope_if_necessary(scoped_variants, &block)
|
58
|
+
if scoped_variants.count == 1
|
59
|
+
return scoped_variants.first
|
60
|
+
end
|
61
|
+
Hash[scoped_variants.flat_map do |variants|
|
62
|
+
variants.map do |variant, suffix|
|
63
|
+
prefix = block.call(variant)
|
64
|
+
scope = [prefix, suffix].compact.join('-')
|
65
|
+
[variant, !scope.empty? ? scope : nil]
|
66
|
+
end
|
67
|
+
end]
|
68
|
+
end
|
69
|
+
|
70
|
+
# @private
|
71
|
+
# @return [Hash<PodVariant, String>]
|
72
|
+
#
|
73
|
+
def scope_by_build_type
|
74
|
+
scope_if_necessary(group_by { |v| v.build_type.packaging }.map(&:scope_by_linkage)) do |variant|
|
75
|
+
variant.build_type.packaging
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# @private
|
80
|
+
# @return [Hash<PodVariant, String>]
|
81
|
+
#
|
82
|
+
def scope_by_linkage
|
83
|
+
scope_if_necessary(group_by { |v| v.build_type.linkage }.map(&:scope_by_platform)) do |variant|
|
84
|
+
variant.build_type.linkage
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# @private
|
89
|
+
# @return [Hash<PodVariant, String>]
|
90
|
+
#
|
91
|
+
def scope_by_platform
|
92
|
+
grouped_variants = group_by { |v| v.platform.name }
|
93
|
+
if grouped_variants.all? { |set| set.variants.count == 1 }
|
94
|
+
# => Platform name
|
95
|
+
platform_name_proc = proc { |v| Platform.string_name(v.platform.symbolic_name).tr(' ', '') }
|
96
|
+
else
|
97
|
+
grouped_variants = group_by(&:platform)
|
98
|
+
# => Platform name + SDK version
|
99
|
+
platform_name_proc = proc { |v| v.platform.to_s.tr(' ', '') }
|
100
|
+
end
|
101
|
+
scope_if_necessary(grouped_variants.map(&:scope_by_swift_version), &platform_name_proc)
|
102
|
+
end
|
103
|
+
|
104
|
+
# @private
|
105
|
+
# @return [Hash<PodVariant, String>]
|
106
|
+
#
|
107
|
+
def scope_by_swift_version
|
108
|
+
scope_if_necessary(group_by(&:swift_version).map(&:scope_without_suffix)) do |variant|
|
109
|
+
variant.swift_version ? "Swift#{variant.swift_version}" : ''
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# @private
|
114
|
+
# @return [Hash<PodVariant, String>]
|
115
|
+
#
|
116
|
+
def scope_by_specs
|
117
|
+
root_spec = variants.first.root_spec
|
118
|
+
specs = [root_spec]
|
119
|
+
specs += if root_spec.default_subspecs.empty?
|
120
|
+
root_spec.subspecs.compact
|
121
|
+
else
|
122
|
+
root_spec.default_subspecs.map do |subspec_name|
|
123
|
+
root_spec.subspec_by_name("#{root_spec.name}/#{subspec_name}")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
default_specs = Set.new(specs)
|
127
|
+
grouped_variants = group_by(&:specs)
|
128
|
+
all_spec_variants = grouped_variants.map { |set| set.variants.first.specs }
|
129
|
+
common_specs = all_spec_variants.map(&:to_set).flatten.inject(&:&)
|
130
|
+
omit_common_specs = common_specs.any? && common_specs.proper_superset?(default_specs)
|
131
|
+
scope_if_necessary(grouped_variants.map(&:scope_by_build_type)) do |variant|
|
132
|
+
specs = variant.specs.to_set
|
133
|
+
|
134
|
+
# The current variant contains all default specs
|
135
|
+
omit_default_specs = default_specs.any? && default_specs.subset?(specs)
|
136
|
+
if omit_default_specs
|
137
|
+
specs -= default_specs
|
138
|
+
end
|
139
|
+
|
140
|
+
# There are common specs, which are different from the default specs
|
141
|
+
if omit_common_specs
|
142
|
+
specs -= common_specs
|
143
|
+
end
|
144
|
+
|
145
|
+
spec_names = specs.map do |spec|
|
146
|
+
spec.root? ? '.root' : spec.name.split('/')[1..-1].join('_')
|
147
|
+
end.sort
|
148
|
+
if spec_names.empty?
|
149
|
+
omit_common_specs ? '.common' : nil
|
150
|
+
else
|
151
|
+
if omit_common_specs
|
152
|
+
spec_names.unshift('.common')
|
153
|
+
elsif omit_default_specs
|
154
|
+
spec_names.unshift('.default')
|
155
|
+
end
|
156
|
+
spec_names.reduce('') do |acc, name|
|
157
|
+
"#{acc}#{acc.empty? || name[0] == '.' ? '' : '-'}#{name}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# @private
|
164
|
+
#
|
165
|
+
# Helps to define scope suffixes recursively.
|
166
|
+
#
|
167
|
+
# @return [Hash<PodVariant, String>]
|
168
|
+
#
|
169
|
+
def scope_without_suffix
|
170
|
+
Hash[variants.map { |v| [v, nil] }]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Pod
|
2
|
+
class Installer
|
3
|
+
class Analyzer
|
4
|
+
# Caches podfile & target definition dependencies, so they do not need to be re-computed
|
5
|
+
# from the internal hash on each access
|
6
|
+
#
|
7
|
+
class PodfileDependencyCache
|
8
|
+
# @return [Array<Pod::Dependency>]
|
9
|
+
# All the dependencies in the podfile
|
10
|
+
#
|
11
|
+
attr_reader :podfile_dependencies
|
12
|
+
|
13
|
+
def initialize(podfile_dependencies, dependencies_by_target_definition)
|
14
|
+
@podfile_dependencies = podfile_dependencies
|
15
|
+
@dependencies_by_target_definition = dependencies_by_target_definition
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the dependencies for the given target definition
|
19
|
+
#
|
20
|
+
def target_definition_dependencies(target_definition)
|
21
|
+
@dependencies_by_target_definition[target_definition] ||
|
22
|
+
raise(ArgumentError, "dependencies for #{target_definition.inspect} do not exist in the cache")
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns a list of all of the target definitions in the Podfile
|
26
|
+
#
|
27
|
+
def target_definition_list
|
28
|
+
@dependencies_by_target_definition.keys
|
29
|
+
end
|
30
|
+
|
31
|
+
# Creates a {PodfileDependencyCache} from the given {Podfile}
|
32
|
+
#
|
33
|
+
# @param [Podfile] podfile
|
34
|
+
# The {Podfile} from which dependencies should be cached
|
35
|
+
#
|
36
|
+
# @return [PodfileDependencyCache]
|
37
|
+
# A warmed, immutable cache of all the dependencies in the {Podfile}
|
38
|
+
#
|
39
|
+
def self.from_podfile(podfile)
|
40
|
+
raise ArgumentError, 'Must be initialized with a podfile' unless podfile
|
41
|
+
podfile_dependencies = []
|
42
|
+
dependencies_by_target_definition = {}
|
43
|
+
podfile.target_definition_list.each do |target_definition|
|
44
|
+
deps = target_definition.dependencies.freeze
|
45
|
+
podfile_dependencies.concat deps
|
46
|
+
dependencies_by_target_definition[target_definition] = deps
|
47
|
+
end
|
48
|
+
podfile_dependencies.uniq!
|
49
|
+
|
50
|
+
new(podfile_dependencies.freeze, dependencies_by_target_definition.freeze)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,268 @@
|
|
1
|
+
module Pod
|
2
|
+
class Installer
|
3
|
+
class Analyzer
|
4
|
+
# Analyze the sandbox to detect which Pods should be removed, and which
|
5
|
+
# ones should be reinstalled.
|
6
|
+
#
|
7
|
+
# The logic is the following:
|
8
|
+
#
|
9
|
+
# Added
|
10
|
+
# - If not present in the sandbox lockfile.
|
11
|
+
# - The directory of the Pod doesn't exits.
|
12
|
+
#
|
13
|
+
# Changed
|
14
|
+
# - The version of the Pod changed.
|
15
|
+
# - The SHA of the specification file changed.
|
16
|
+
# - The specific installed (sub)specs of the same Pod changed.
|
17
|
+
# - The specification is from an external source and the
|
18
|
+
# installation process is in update mode.
|
19
|
+
# - The directory of the Pod is empty.
|
20
|
+
# - The Pod has been pre-downloaded.
|
21
|
+
#
|
22
|
+
# Removed
|
23
|
+
# - If a specification is present in the lockfile but not in the resolved
|
24
|
+
# specs.
|
25
|
+
#
|
26
|
+
# Unchanged
|
27
|
+
# - If none of the above conditions match.
|
28
|
+
#
|
29
|
+
class SandboxAnalyzer
|
30
|
+
# @return [Sandbox] The sandbox to analyze.
|
31
|
+
#
|
32
|
+
attr_reader :sandbox
|
33
|
+
|
34
|
+
# @return [Podfile] The Podfile to analyze dependencies.
|
35
|
+
#
|
36
|
+
attr_reader :podfile
|
37
|
+
|
38
|
+
# @return [Array<Specifications>] The specifications returned by the
|
39
|
+
# resolver.
|
40
|
+
#
|
41
|
+
attr_reader :specs
|
42
|
+
|
43
|
+
# @return [Bool] Whether the installation is performed in update mode.
|
44
|
+
#
|
45
|
+
attr_reader :update_mode
|
46
|
+
|
47
|
+
alias_method :update_mode?, :update_mode
|
48
|
+
|
49
|
+
# Init a new SandboxAnalyzer
|
50
|
+
#
|
51
|
+
# @param [Sandbox] sandbox @see sandbox
|
52
|
+
# @param [Podfile] podfile @see podfile
|
53
|
+
# @param [Array<Specifications>] specs @see specs
|
54
|
+
# @param [Bool] update_mode @see update_mode
|
55
|
+
#
|
56
|
+
def initialize(sandbox, podfile, specs, update_mode)
|
57
|
+
@sandbox = sandbox
|
58
|
+
@podfile = podfile
|
59
|
+
@specs = specs
|
60
|
+
@update_mode = update_mode
|
61
|
+
end
|
62
|
+
|
63
|
+
# Performs the analysis to the detect the state of the sandbox respect
|
64
|
+
# to the resolved specifications.
|
65
|
+
#
|
66
|
+
# @return [void]
|
67
|
+
#
|
68
|
+
def analyze
|
69
|
+
state = SpecsState.new
|
70
|
+
if sandbox_manifest
|
71
|
+
all_names = (resolved_pods + sandbox_pods).uniq.sort
|
72
|
+
all_names.sort.each do |name|
|
73
|
+
state.add_name(name, pod_state(name))
|
74
|
+
end
|
75
|
+
else
|
76
|
+
state.added.merge(resolved_pods)
|
77
|
+
end
|
78
|
+
state
|
79
|
+
end
|
80
|
+
|
81
|
+
#---------------------------------------------------------------------#
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# @!group Pod state
|
86
|
+
|
87
|
+
# Returns the state of the Pod with the given name.
|
88
|
+
#
|
89
|
+
# @param [String] pod
|
90
|
+
# the name of the Pod.
|
91
|
+
#
|
92
|
+
# @return [Symbol] The state
|
93
|
+
#
|
94
|
+
def pod_state(pod)
|
95
|
+
return :added if pod_added?(pod)
|
96
|
+
return :deleted if pod_deleted?(pod)
|
97
|
+
return :changed if pod_changed?(pod)
|
98
|
+
:unchanged
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns whether the Pod with the given name should be installed.
|
102
|
+
#
|
103
|
+
# @note A Pod whose folder doesn't exists is considered added.
|
104
|
+
#
|
105
|
+
# @param [String] pod
|
106
|
+
# the name of the Pod.
|
107
|
+
#
|
108
|
+
# @return [Bool] Whether the Pod is added.
|
109
|
+
#
|
110
|
+
def pod_added?(pod)
|
111
|
+
return true if resolved_pods.include?(pod) && !sandbox_pods.include?(pod)
|
112
|
+
return true if !sandbox.local?(pod) && !folder_exist?(pod)
|
113
|
+
false
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns whether the Pod with the given name should be removed from
|
117
|
+
# the installation.
|
118
|
+
#
|
119
|
+
# @param [String] pod
|
120
|
+
# the name of the Pod.
|
121
|
+
#
|
122
|
+
# @return [Bool] Whether the Pod is deleted.
|
123
|
+
#
|
124
|
+
def pod_deleted?(pod)
|
125
|
+
return true if !resolved_pods.include?(pod) && sandbox_pods.include?(pod)
|
126
|
+
false
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns whether the Pod with the given name should be considered
|
130
|
+
# changed and thus should be reinstalled.
|
131
|
+
#
|
132
|
+
# @note In update mode, as there is no way to know if a remote source
|
133
|
+
# hash changed the Pods from external
|
134
|
+
# sources are always marked as changed.
|
135
|
+
#
|
136
|
+
# @note A Pod whose folder is empty is considered changed.
|
137
|
+
#
|
138
|
+
# @param [String] pod
|
139
|
+
# the name of the Pod.
|
140
|
+
#
|
141
|
+
# @return [Bool] Whether the Pod is changed.
|
142
|
+
#
|
143
|
+
def pod_changed?(pod)
|
144
|
+
spec = root_spec(pod)
|
145
|
+
return true if spec.version != sandbox_version(pod)
|
146
|
+
return true if spec.checksum != sandbox_checksum(pod)
|
147
|
+
return true if resolved_spec_names(pod) != sandbox_spec_names(pod)
|
148
|
+
podfile_dep = podfile_dependency(pod)&.tap { |dep| dep.podspec_repo = nil }
|
149
|
+
return true if podfile_dep != sandbox_dependency(pod)
|
150
|
+
return true if sandbox.predownloaded?(pod)
|
151
|
+
return true if folder_empty?(pod)
|
152
|
+
false
|
153
|
+
end
|
154
|
+
|
155
|
+
#---------------------------------------------------------------------#
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
# @!group Private helpers
|
160
|
+
|
161
|
+
# @return [Lockfile] The manifest to use for the sandbox.
|
162
|
+
#
|
163
|
+
def sandbox_manifest
|
164
|
+
sandbox.manifest
|
165
|
+
end
|
166
|
+
|
167
|
+
#--------------------------------------#
|
168
|
+
|
169
|
+
# @return [Array<String>] The name of the resolved Pods.
|
170
|
+
#
|
171
|
+
def resolved_pods
|
172
|
+
@resolved_pods ||= specs.map { |spec| spec.root.name }.uniq
|
173
|
+
end
|
174
|
+
|
175
|
+
# @return [Array<String>] The name of the Pods stored in the sandbox
|
176
|
+
# manifest.
|
177
|
+
#
|
178
|
+
def sandbox_pods
|
179
|
+
@sandbox_pods ||= sandbox_manifest.pod_names.map { |name| Specification.root_name(name) }.uniq
|
180
|
+
end
|
181
|
+
|
182
|
+
# @return [Array<String>] The name of the resolved specifications
|
183
|
+
# (includes subspecs).
|
184
|
+
#
|
185
|
+
# @param [String] pod
|
186
|
+
# the name of the Pod.
|
187
|
+
#
|
188
|
+
def resolved_spec_names(pod)
|
189
|
+
specs.select { |s| s.root.name == pod }.map(&:name).uniq.sort
|
190
|
+
end
|
191
|
+
|
192
|
+
# @return [Array<String>] The name of the specifications stored in the
|
193
|
+
# sandbox manifest (includes subspecs).
|
194
|
+
#
|
195
|
+
# @param [String] pod
|
196
|
+
# the name of the Pod.
|
197
|
+
#
|
198
|
+
def sandbox_spec_names(pod)
|
199
|
+
sandbox_manifest.pod_names.select { |name| Specification.root_name(name) == pod }.uniq.sort
|
200
|
+
end
|
201
|
+
|
202
|
+
# @return [Specification] The root specification for the Pod with the
|
203
|
+
# given name.
|
204
|
+
#
|
205
|
+
# @param [String] pod
|
206
|
+
# the name of the Pod.
|
207
|
+
#
|
208
|
+
def root_spec(pod)
|
209
|
+
specs.find { |s| s.root.name == pod }.root
|
210
|
+
end
|
211
|
+
|
212
|
+
#--------------------------------------#
|
213
|
+
|
214
|
+
# @return [Version] The version of Pod with the given name stored in
|
215
|
+
# the sandbox.
|
216
|
+
#
|
217
|
+
# @param [String] pod
|
218
|
+
# the name of the Pod.
|
219
|
+
#
|
220
|
+
def sandbox_version(pod)
|
221
|
+
sandbox_manifest.version(pod)
|
222
|
+
end
|
223
|
+
|
224
|
+
# @return [String] The checksum of the specification of the Pod with
|
225
|
+
# the given name stored in the sandbox.
|
226
|
+
#
|
227
|
+
# @param [String] pod
|
228
|
+
# the name of the Pod.
|
229
|
+
#
|
230
|
+
def sandbox_checksum(pod)
|
231
|
+
sandbox_manifest.checksum(pod)
|
232
|
+
end
|
233
|
+
|
234
|
+
# @return [Dependency, nil] The dependency with the given name stored in the sandbox.
|
235
|
+
#
|
236
|
+
# @param [String] pod
|
237
|
+
# the name of the Pod.
|
238
|
+
#
|
239
|
+
def sandbox_dependency(pod)
|
240
|
+
sandbox_manifest.dependencies.find { |d| d.name == pod }
|
241
|
+
end
|
242
|
+
|
243
|
+
#--------------------------------------#
|
244
|
+
|
245
|
+
# @return [Dependency, nil] The dependency with the given name from the podfile.
|
246
|
+
#
|
247
|
+
# @param [String] pod
|
248
|
+
# the name of the Pod.
|
249
|
+
#
|
250
|
+
def podfile_dependency(pod)
|
251
|
+
podfile.dependencies.find { |d| d.name == pod }
|
252
|
+
end
|
253
|
+
|
254
|
+
#--------------------------------------#
|
255
|
+
|
256
|
+
def folder_exist?(pod)
|
257
|
+
sandbox.pod_dir(pod).exist?
|
258
|
+
end
|
259
|
+
|
260
|
+
def folder_empty?(pod)
|
261
|
+
Dir.glob(sandbox.pod_dir(pod) + '*').empty?
|
262
|
+
end
|
263
|
+
|
264
|
+
#---------------------------------------------------------------------#
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|