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.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cocoapods-tt/command/native/install.rb +56 -0
  3. data/lib/cocoapods-tt/command/native/update.rb +157 -0
  4. data/lib/cocoapods-tt/command/tt/make.rb +92 -0
  5. data/lib/cocoapods-tt/command/tt.rb +115 -0
  6. data/lib/cocoapods-tt/command.rb +1 -0
  7. data/lib/cocoapods-tt/gem_version.rb +3 -0
  8. data/lib/cocoapods-tt/native/command.rb +185 -0
  9. data/lib/cocoapods-tt/native/config.rb +366 -0
  10. data/lib/cocoapods-tt/native/core_overrides.rb +1 -0
  11. data/lib/cocoapods-tt/native/downloader/cache.rb +322 -0
  12. data/lib/cocoapods-tt/native/downloader/request.rb +86 -0
  13. data/lib/cocoapods-tt/native/downloader/response.rb +16 -0
  14. data/lib/cocoapods-tt/native/downloader.rb +192 -0
  15. data/lib/cocoapods-tt/native/executable.rb +247 -0
  16. data/lib/cocoapods-tt/native/external_sources/abstract_external_source.rb +205 -0
  17. data/lib/cocoapods-tt/native/external_sources/downloader_source.rb +30 -0
  18. data/lib/cocoapods-tt/native/external_sources/path_source.rb +55 -0
  19. data/lib/cocoapods-tt/native/external_sources/podspec_source.rb +54 -0
  20. data/lib/cocoapods-tt/native/external_sources.rb +57 -0
  21. data/lib/cocoapods-tt/native/gem_version.rb +5 -0
  22. data/lib/cocoapods-tt/native/generator/acknowledgements/markdown.rb +44 -0
  23. data/lib/cocoapods-tt/native/generator/acknowledgements/plist.rb +94 -0
  24. data/lib/cocoapods-tt/native/generator/acknowledgements.rb +107 -0
  25. data/lib/cocoapods-tt/native/generator/app_target_helper.rb +363 -0
  26. data/lib/cocoapods-tt/native/generator/bridge_support.rb +22 -0
  27. data/lib/cocoapods-tt/native/generator/constant.rb +19 -0
  28. data/lib/cocoapods-tt/native/generator/copy_dsyms_script.rb +56 -0
  29. data/lib/cocoapods-tt/native/generator/copy_resources_script.rb +223 -0
  30. data/lib/cocoapods-tt/native/generator/copy_xcframework_script.rb +227 -0
  31. data/lib/cocoapods-tt/native/generator/dummy_source.rb +31 -0
  32. data/lib/cocoapods-tt/native/generator/embed_frameworks_script.rb +196 -0
  33. data/lib/cocoapods-tt/native/generator/file_list.rb +39 -0
  34. data/lib/cocoapods-tt/native/generator/header.rb +103 -0
  35. data/lib/cocoapods-tt/native/generator/info_plist_file.rb +128 -0
  36. data/lib/cocoapods-tt/native/generator/module_map.rb +99 -0
  37. data/lib/cocoapods-tt/native/generator/prefix_header.rb +60 -0
  38. data/lib/cocoapods-tt/native/generator/script_phase_constants.rb +100 -0
  39. data/lib/cocoapods-tt/native/generator/umbrella_header.rb +46 -0
  40. data/lib/cocoapods-tt/native/hooks_manager.rb +132 -0
  41. data/lib/cocoapods-tt/native/installer/analyzer/analysis_result.rb +87 -0
  42. data/lib/cocoapods-tt/native/installer/analyzer/locking_dependency_analyzer.rb +103 -0
  43. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant.rb +87 -0
  44. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant_set.rb +175 -0
  45. data/lib/cocoapods-tt/native/installer/analyzer/podfile_dependency_cache.rb +55 -0
  46. data/lib/cocoapods-tt/native/installer/analyzer/sandbox_analyzer.rb +268 -0
  47. data/lib/cocoapods-tt/native/installer/analyzer/specs_state.rb +108 -0
  48. data/lib/cocoapods-tt/native/installer/analyzer/target_inspection_result.rb +58 -0
  49. data/lib/cocoapods-tt/native/installer/analyzer/target_inspector.rb +258 -0
  50. data/lib/cocoapods-tt/native/installer/analyzer.rb +1204 -0
  51. data/lib/cocoapods-tt/native/installer/base_install_hooks_context.rb +135 -0
  52. data/lib/cocoapods-tt/native/installer/installation_options.rb +195 -0
  53. data/lib/cocoapods-tt/native/installer/pod_source_installer.rb +224 -0
  54. data/lib/cocoapods-tt/native/installer/pod_source_preparer.rb +77 -0
  55. data/lib/cocoapods-tt/native/installer/podfile_validator.rb +168 -0
  56. data/lib/cocoapods-tt/native/installer/post_install_hooks_context.rb +9 -0
  57. data/lib/cocoapods-tt/native/installer/post_integrate_hooks_context.rb +9 -0
  58. data/lib/cocoapods-tt/native/installer/pre_install_hooks_context.rb +51 -0
  59. data/lib/cocoapods-tt/native/installer/pre_integrate_hooks_context.rb +9 -0
  60. data/lib/cocoapods-tt/native/installer/project_cache/project_cache.rb +11 -0
  61. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analysis_result.rb +53 -0
  62. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analyzer.rb +200 -0
  63. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_version.rb +43 -0
  64. data/lib/cocoapods-tt/native/installer/project_cache/project_installation_cache.rb +103 -0
  65. data/lib/cocoapods-tt/native/installer/project_cache/project_metadata_cache.rb +73 -0
  66. data/lib/cocoapods-tt/native/installer/project_cache/target_cache_key.rb +176 -0
  67. data/lib/cocoapods-tt/native/installer/project_cache/target_metadata.rb +74 -0
  68. data/lib/cocoapods-tt/native/installer/sandbox_dir_cleaner.rb +105 -0
  69. data/lib/cocoapods-tt/native/installer/sandbox_header_paths_installer.rb +45 -0
  70. data/lib/cocoapods-tt/native/installer/source_provider_hooks_context.rb +34 -0
  71. data/lib/cocoapods-tt/native/installer/target_uuid_generator.rb +34 -0
  72. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +179 -0
  73. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator.rb +815 -0
  74. data/lib/cocoapods-tt/native/installer/user_project_integrator.rb +280 -0
  75. data/lib/cocoapods-tt/native/installer/xcode/multi_pods_project_generator.rb +82 -0
  76. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +66 -0
  77. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_installer.rb +192 -0
  78. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/app_host_installer.rb +154 -0
  79. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/file_references_installer.rb +329 -0
  80. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +195 -0
  81. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_installer.rb +1239 -0
  82. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_integrator.rb +312 -0
  83. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pods_project_writer.rb +90 -0
  84. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/project_generator.rb +120 -0
  85. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installation_result.rb +140 -0
  86. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer.rb +257 -0
  87. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer_helper.rb +110 -0
  88. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator.rb +291 -0
  89. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator_result.rb +54 -0
  90. data/lib/cocoapods-tt/native/installer/xcode/single_pods_project_generator.rb +38 -0
  91. data/lib/cocoapods-tt/native/installer/xcode/target_validator.rb +170 -0
  92. data/lib/cocoapods-tt/native/installer/xcode.rb +11 -0
  93. data/lib/cocoapods-tt/native/installer.rb +1044 -0
  94. data/lib/cocoapods-tt/native/native_target_extension.rb +60 -0
  95. data/lib/cocoapods-tt/native/open-uri.rb +33 -0
  96. data/lib/cocoapods-tt/native/podfile.rb +13 -0
  97. data/lib/cocoapods-tt/native/project.rb +544 -0
  98. data/lib/cocoapods-tt/native/resolver/lazy_specification.rb +88 -0
  99. data/lib/cocoapods-tt/native/resolver/resolver_specification.rb +41 -0
  100. data/lib/cocoapods-tt/native/resolver.rb +600 -0
  101. data/lib/cocoapods-tt/native/sandbox/file_accessor.rb +532 -0
  102. data/lib/cocoapods-tt/native/sandbox/headers_store.rb +163 -0
  103. data/lib/cocoapods-tt/native/sandbox/path_list.rb +242 -0
  104. data/lib/cocoapods-tt/native/sandbox/pod_dir_cleaner.rb +71 -0
  105. data/lib/cocoapods-tt/native/sandbox/podspec_finder.rb +23 -0
  106. data/lib/cocoapods-tt/native/sandbox.rb +470 -0
  107. data/lib/cocoapods-tt/native/sources_manager.rb +221 -0
  108. data/lib/cocoapods-tt/native/target/aggregate_target.rb +558 -0
  109. data/lib/cocoapods-tt/native/target/build_settings.rb +1385 -0
  110. data/lib/cocoapods-tt/native/target/pod_target.rb +1168 -0
  111. data/lib/cocoapods-tt/native/target.rb +378 -0
  112. data/lib/cocoapods-tt/native/user_interface/error_report.rb +204 -0
  113. data/lib/cocoapods-tt/native/user_interface/inspector_reporter.rb +102 -0
  114. data/lib/cocoapods-tt/native/user_interface.rb +463 -0
  115. data/lib/cocoapods-tt/native/validator.rb +1170 -0
  116. data/lib/cocoapods-tt/native/version_metadata.rb +26 -0
  117. data/lib/cocoapods-tt/native/xcode/framework_paths.rb +54 -0
  118. data/lib/cocoapods-tt/native/xcode/linkage_analyzer.rb +22 -0
  119. data/lib/cocoapods-tt/native/xcode/xcframework/xcframework_slice.rb +138 -0
  120. data/lib/cocoapods-tt/native/xcode/xcframework.rb +99 -0
  121. data/lib/cocoapods-tt/native/xcode.rb +7 -0
  122. data/lib/cocoapods-tt.rb +1 -0
  123. data/lib/cocoapods_plugin.rb +17 -0
  124. 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