xcocoapods 1.5.3
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/CHANGELOG.md +6303 -0
- data/LICENSE +28 -0
- data/README.md +80 -0
- data/bin/pod +56 -0
- data/bin/sandbox-pod +168 -0
- data/lib/cocoapods.rb +73 -0
- data/lib/cocoapods/command.rb +175 -0
- data/lib/cocoapods/command/cache.rb +28 -0
- data/lib/cocoapods/command/cache/clean.rb +90 -0
- data/lib/cocoapods/command/cache/list.rb +69 -0
- data/lib/cocoapods/command/env.rb +66 -0
- data/lib/cocoapods/command/init.rb +128 -0
- data/lib/cocoapods/command/install.rb +45 -0
- data/lib/cocoapods/command/ipc.rb +19 -0
- data/lib/cocoapods/command/ipc/list.rb +40 -0
- data/lib/cocoapods/command/ipc/podfile.rb +31 -0
- data/lib/cocoapods/command/ipc/podfile_json.rb +30 -0
- data/lib/cocoapods/command/ipc/repl.rb +51 -0
- data/lib/cocoapods/command/ipc/spec.rb +29 -0
- data/lib/cocoapods/command/ipc/update_search_index.rb +24 -0
- data/lib/cocoapods/command/lib.rb +11 -0
- data/lib/cocoapods/command/lib/create.rb +105 -0
- data/lib/cocoapods/command/lib/lint.rb +121 -0
- data/lib/cocoapods/command/list.rb +39 -0
- data/lib/cocoapods/command/options/project_directory.rb +36 -0
- data/lib/cocoapods/command/options/repo_update.rb +34 -0
- data/lib/cocoapods/command/outdated.rb +140 -0
- data/lib/cocoapods/command/repo.rb +29 -0
- data/lib/cocoapods/command/repo/add.rb +103 -0
- data/lib/cocoapods/command/repo/lint.rb +82 -0
- data/lib/cocoapods/command/repo/list.rb +93 -0
- data/lib/cocoapods/command/repo/push.rb +281 -0
- data/lib/cocoapods/command/repo/remove.rb +36 -0
- data/lib/cocoapods/command/repo/update.rb +28 -0
- data/lib/cocoapods/command/setup.rb +103 -0
- data/lib/cocoapods/command/spec.rb +112 -0
- data/lib/cocoapods/command/spec/cat.rb +51 -0
- data/lib/cocoapods/command/spec/create.rb +283 -0
- data/lib/cocoapods/command/spec/edit.rb +87 -0
- data/lib/cocoapods/command/spec/env_spec.rb +53 -0
- data/lib/cocoapods/command/spec/lint.rb +137 -0
- data/lib/cocoapods/command/spec/which.rb +43 -0
- data/lib/cocoapods/command/update.rb +101 -0
- data/lib/cocoapods/config.rb +347 -0
- data/lib/cocoapods/core_overrides.rb +1 -0
- data/lib/cocoapods/downloader.rb +190 -0
- data/lib/cocoapods/downloader/cache.rb +233 -0
- data/lib/cocoapods/downloader/request.rb +86 -0
- data/lib/cocoapods/downloader/response.rb +16 -0
- data/lib/cocoapods/executable.rb +222 -0
- data/lib/cocoapods/external_sources.rb +57 -0
- data/lib/cocoapods/external_sources/abstract_external_source.rb +205 -0
- data/lib/cocoapods/external_sources/downloader_source.rb +30 -0
- data/lib/cocoapods/external_sources/path_source.rb +55 -0
- data/lib/cocoapods/external_sources/podspec_source.rb +54 -0
- data/lib/cocoapods/gem_version.rb +5 -0
- data/lib/cocoapods/generator/acknowledgements.rb +107 -0
- data/lib/cocoapods/generator/acknowledgements/markdown.rb +44 -0
- data/lib/cocoapods/generator/acknowledgements/plist.rb +94 -0
- data/lib/cocoapods/generator/app_target_helper.rb +244 -0
- data/lib/cocoapods/generator/bridge_support.rb +22 -0
- data/lib/cocoapods/generator/constant.rb +19 -0
- data/lib/cocoapods/generator/copy_resources_script.rb +230 -0
- data/lib/cocoapods/generator/dummy_source.rb +31 -0
- data/lib/cocoapods/generator/embed_frameworks_script.rb +215 -0
- data/lib/cocoapods/generator/header.rb +103 -0
- data/lib/cocoapods/generator/info_plist_file.rb +116 -0
- data/lib/cocoapods/generator/module_map.rb +99 -0
- data/lib/cocoapods/generator/prefix_header.rb +60 -0
- data/lib/cocoapods/generator/umbrella_header.rb +46 -0
- data/lib/cocoapods/hooks_manager.rb +132 -0
- data/lib/cocoapods/installer.rb +703 -0
- data/lib/cocoapods/installer/analyzer.rb +972 -0
- data/lib/cocoapods/installer/analyzer/analysis_result.rb +87 -0
- data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +98 -0
- data/lib/cocoapods/installer/analyzer/pod_variant.rb +67 -0
- data/lib/cocoapods/installer/analyzer/pod_variant_set.rb +157 -0
- data/lib/cocoapods/installer/analyzer/podfile_dependency_cache.rb +54 -0
- data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +240 -0
- data/lib/cocoapods/installer/analyzer/specs_state.rb +84 -0
- data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +53 -0
- data/lib/cocoapods/installer/analyzer/target_inspector.rb +260 -0
- data/lib/cocoapods/installer/installation_options.rb +158 -0
- data/lib/cocoapods/installer/pod_source_installer.rb +202 -0
- data/lib/cocoapods/installer/pod_source_preparer.rb +77 -0
- data/lib/cocoapods/installer/podfile_validator.rb +139 -0
- data/lib/cocoapods/installer/post_install_hooks_context.rb +132 -0
- data/lib/cocoapods/installer/pre_install_hooks_context.rb +51 -0
- data/lib/cocoapods/installer/source_provider_hooks_context.rb +34 -0
- data/lib/cocoapods/installer/user_project_integrator.rb +250 -0
- data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +463 -0
- data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +146 -0
- data/lib/cocoapods/installer/xcode.rb +8 -0
- data/lib/cocoapods/installer/xcode/pods_project_generator.rb +416 -0
- data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +181 -0
- data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +84 -0
- data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +334 -0
- data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +777 -0
- data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +116 -0
- data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +86 -0
- data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +256 -0
- data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +68 -0
- data/lib/cocoapods/installer/xcode/target_validator.rb +147 -0
- data/lib/cocoapods/open-uri.rb +33 -0
- data/lib/cocoapods/project.rb +414 -0
- data/lib/cocoapods/resolver.rb +585 -0
- data/lib/cocoapods/resolver/lazy_specification.rb +79 -0
- data/lib/cocoapods/sandbox.rb +404 -0
- data/lib/cocoapods/sandbox/file_accessor.rb +444 -0
- data/lib/cocoapods/sandbox/headers_store.rb +146 -0
- data/lib/cocoapods/sandbox/path_list.rb +220 -0
- data/lib/cocoapods/sandbox/pod_dir_cleaner.rb +85 -0
- data/lib/cocoapods/sandbox/podspec_finder.rb +23 -0
- data/lib/cocoapods/sources_manager.rb +157 -0
- data/lib/cocoapods/target.rb +261 -0
- data/lib/cocoapods/target/aggregate_target.rb +338 -0
- data/lib/cocoapods/target/build_settings.rb +1075 -0
- data/lib/cocoapods/target/pod_target.rb +559 -0
- data/lib/cocoapods/user_interface.rb +459 -0
- data/lib/cocoapods/user_interface/error_report.rb +187 -0
- data/lib/cocoapods/user_interface/inspector_reporter.rb +109 -0
- data/lib/cocoapods/validator.rb +981 -0
- metadata +533 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
require 'active_support/hash_with_indifferent_access'
|
|
2
|
+
|
|
3
|
+
module Pod
|
|
4
|
+
class Installer
|
|
5
|
+
# Represents the installation options the user can customize via a
|
|
6
|
+
# `Podfile`.
|
|
7
|
+
#
|
|
8
|
+
class InstallationOptions
|
|
9
|
+
# Parses installation options from a podfile.
|
|
10
|
+
#
|
|
11
|
+
# @param [Podfile] podfile the podfile to parse installation options
|
|
12
|
+
# from.
|
|
13
|
+
#
|
|
14
|
+
# @raise [Informative] if `podfile` does not specify a `CocoaPods`
|
|
15
|
+
# install.
|
|
16
|
+
#
|
|
17
|
+
# @return [Self]
|
|
18
|
+
#
|
|
19
|
+
def self.from_podfile(podfile)
|
|
20
|
+
name, options = podfile.installation_method
|
|
21
|
+
unless name.downcase == 'cocoapods'
|
|
22
|
+
raise Informative, "Currently need to specify a `cocoapods` install, you chose `#{name}`."
|
|
23
|
+
end
|
|
24
|
+
new(options)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Defines a new installation option.
|
|
28
|
+
#
|
|
29
|
+
# @param [#to_s] name the name of the option.
|
|
30
|
+
#
|
|
31
|
+
# @param default the default value for the option.
|
|
32
|
+
#
|
|
33
|
+
# @param [Boolean] boolean whether the option has a boolean value.
|
|
34
|
+
#
|
|
35
|
+
# @return [void]
|
|
36
|
+
#
|
|
37
|
+
# @!macro [attach] option
|
|
38
|
+
#
|
|
39
|
+
# @note this option defaults to $2.
|
|
40
|
+
#
|
|
41
|
+
# @return the $1 $0 for installation.
|
|
42
|
+
#
|
|
43
|
+
def self.option(name, default, boolean: true)
|
|
44
|
+
name = name.to_s
|
|
45
|
+
raise ArgumentError, "The `#{name}` option is already defined" if defaults.key?(name)
|
|
46
|
+
defaults[name] = default
|
|
47
|
+
attr_accessor name
|
|
48
|
+
alias_method "#{name}?", name if boolean
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @return [Hash<Symbol,Object>] all known installation options and their
|
|
52
|
+
# default values.
|
|
53
|
+
#
|
|
54
|
+
def self.defaults
|
|
55
|
+
@defaults ||= {}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @return [Array<Symbol>] the names of all known installation options.
|
|
59
|
+
#
|
|
60
|
+
def self.all_options
|
|
61
|
+
defaults.keys
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Initializes the installation options with a hash of options from a
|
|
65
|
+
# Podfile.
|
|
66
|
+
#
|
|
67
|
+
# @param [Hash] options the options to parse.
|
|
68
|
+
#
|
|
69
|
+
# @raise [Informative] if `options` contains any unknown keys.
|
|
70
|
+
#
|
|
71
|
+
def initialize(options = {})
|
|
72
|
+
options = ActiveSupport::HashWithIndifferentAccess.new(options)
|
|
73
|
+
unknown_keys = options.keys - self.class.all_options.map(&:to_s)
|
|
74
|
+
raise Informative, "Unknown installation options: #{unknown_keys.to_sentence}." unless unknown_keys.empty?
|
|
75
|
+
self.class.defaults.each do |key, default|
|
|
76
|
+
value = options.fetch(key, default)
|
|
77
|
+
send("#{key}=", value)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @param [Boolean] include_defaults whether values that match the default
|
|
82
|
+
# for their option should be included. Defaults to `true`.
|
|
83
|
+
#
|
|
84
|
+
# @return [Hash] the options, keyed by option name.
|
|
85
|
+
#
|
|
86
|
+
def to_h(include_defaults: true)
|
|
87
|
+
self.class.defaults.reduce(ActiveSupport::HashWithIndifferentAccess.new) do |hash, (option, default)|
|
|
88
|
+
value = send(option)
|
|
89
|
+
hash[option] = value if include_defaults || value != default
|
|
90
|
+
hash
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def ==(other)
|
|
95
|
+
other.is_a?(self.class) && to_h == other.to_h
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
alias_method :eql, :==
|
|
99
|
+
|
|
100
|
+
def hash
|
|
101
|
+
to_h.hash
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
option :clean, true
|
|
105
|
+
option :deduplicate_targets, true
|
|
106
|
+
option :deterministic_uuids, true
|
|
107
|
+
option :integrate_targets, true
|
|
108
|
+
option :lock_pod_sources, true
|
|
109
|
+
option :warn_for_multiple_pod_sources, true
|
|
110
|
+
option :share_schemes_for_development_pods, false
|
|
111
|
+
|
|
112
|
+
module Mixin
|
|
113
|
+
module ClassMethods
|
|
114
|
+
# Delegates the creation of {#installation_options} to the `Podfile`
|
|
115
|
+
# returned by the given block.
|
|
116
|
+
#
|
|
117
|
+
# @param blk a block that returns the `Podfile` to create
|
|
118
|
+
# installation options from.
|
|
119
|
+
#
|
|
120
|
+
# @return [Void]
|
|
121
|
+
#
|
|
122
|
+
def delegate_installation_options(&blk)
|
|
123
|
+
define_method(:installation_options) do
|
|
124
|
+
@installation_options ||= InstallationOptions.from_podfile(instance_eval(&blk))
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Delegates the installation options attributes directly to
|
|
129
|
+
# {#installation_options}.
|
|
130
|
+
#
|
|
131
|
+
# @return [Void]
|
|
132
|
+
#
|
|
133
|
+
def delegate_installation_option_attributes!
|
|
134
|
+
define_method(:respond_to_missing?) do |name, *args|
|
|
135
|
+
installation_options.respond_to?(name, *args) || super
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
define_method(:method_missing) do |name, *args, &blk|
|
|
139
|
+
if installation_options.respond_to?(name)
|
|
140
|
+
installation_options.send(name, *args, &blk)
|
|
141
|
+
else
|
|
142
|
+
super
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# @return [InstallationOptions] The installation options.
|
|
149
|
+
#
|
|
150
|
+
attr_accessor :installation_options
|
|
151
|
+
|
|
152
|
+
def self.included(mod)
|
|
153
|
+
mod.extend(ClassMethods)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
require 'active_support/core_ext/string/strip'
|
|
2
|
+
|
|
3
|
+
module Pod
|
|
4
|
+
class Installer
|
|
5
|
+
# Controller class responsible of installing the activated specifications
|
|
6
|
+
# of a single Pod.
|
|
7
|
+
#
|
|
8
|
+
# @note This class needs to consider all the activated specs of a Pod.
|
|
9
|
+
#
|
|
10
|
+
class PodSourceInstaller
|
|
11
|
+
UNENCRYPTED_PROTOCOLS = %w(http git).freeze
|
|
12
|
+
|
|
13
|
+
# @return [Sandbox] The installation target.
|
|
14
|
+
#
|
|
15
|
+
attr_reader :sandbox
|
|
16
|
+
|
|
17
|
+
# @return [Hash{Symbol=>Array}] The specifications that need to be
|
|
18
|
+
# installed grouped by platform.
|
|
19
|
+
#
|
|
20
|
+
attr_reader :specs_by_platform
|
|
21
|
+
|
|
22
|
+
# @return [Boolean] Whether the installer is allowed to touch the cache.
|
|
23
|
+
#
|
|
24
|
+
attr_reader :can_cache
|
|
25
|
+
alias_method :can_cache?, :can_cache
|
|
26
|
+
|
|
27
|
+
# Initialize a new instance
|
|
28
|
+
#
|
|
29
|
+
# @param [Sandbox] sandbox @see #sandbox
|
|
30
|
+
# @param [Hash{Symbol=>Array}] specs_by_platform @see #specs_by_platform
|
|
31
|
+
# @param [Boolean] can_cache @see #can_cache
|
|
32
|
+
#
|
|
33
|
+
def initialize(sandbox, specs_by_platform, can_cache: true)
|
|
34
|
+
@sandbox = sandbox
|
|
35
|
+
@specs_by_platform = specs_by_platform
|
|
36
|
+
@can_cache = can_cache
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @return [String] A string suitable for debugging.
|
|
40
|
+
#
|
|
41
|
+
def inspect
|
|
42
|
+
"<#{self.class} sandbox=#{sandbox.root} pod=#{root_spec.name}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @return [String] The name of the pod this installer is installing.
|
|
46
|
+
#
|
|
47
|
+
def name
|
|
48
|
+
root_spec.name
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
#-----------------------------------------------------------------------#
|
|
52
|
+
|
|
53
|
+
public
|
|
54
|
+
|
|
55
|
+
# @!group Installation
|
|
56
|
+
|
|
57
|
+
# Creates the target in the Pods project and the relative support files.
|
|
58
|
+
#
|
|
59
|
+
# @return [void]
|
|
60
|
+
#
|
|
61
|
+
def install!
|
|
62
|
+
download_source unless predownloaded? || local?
|
|
63
|
+
PodSourcePreparer.new(root_spec, root).prepare! if local?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Cleans the installations if appropriate.
|
|
67
|
+
#
|
|
68
|
+
# @return [void]
|
|
69
|
+
#
|
|
70
|
+
def clean!
|
|
71
|
+
clean_installation unless local?
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Locks the source files if appropriate.
|
|
75
|
+
#
|
|
76
|
+
# @return [void]
|
|
77
|
+
#
|
|
78
|
+
def lock_files!(file_accessors)
|
|
79
|
+
return if local?
|
|
80
|
+
FileUtils.chmod('u-w', source_files(file_accessors))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Unlocks the source files if appropriate.
|
|
84
|
+
#
|
|
85
|
+
# @return [void]
|
|
86
|
+
#
|
|
87
|
+
def unlock_files!(file_accessors)
|
|
88
|
+
return if local?
|
|
89
|
+
FileUtils.chmod('u+w', source_files(file_accessors))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
#-----------------------------------------------------------------------#
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
# @!group Installation Steps
|
|
97
|
+
|
|
98
|
+
# Downloads the source of the Pod.
|
|
99
|
+
#
|
|
100
|
+
# @return [void]
|
|
101
|
+
#
|
|
102
|
+
def download_source
|
|
103
|
+
verify_source_is_secure(root_spec)
|
|
104
|
+
download_result = Downloader.download(download_request, root, :can_cache => can_cache?)
|
|
105
|
+
|
|
106
|
+
if (specific_source = download_result.checkout_options) && specific_source != root_spec.source
|
|
107
|
+
sandbox.store_checkout_source(root_spec.name, specific_source)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Verify the source of the spec is secure, which is used to show a warning to the user if that isn't the case
|
|
112
|
+
# This method doesn't verify all protocols, but currently only prohibits unencrypted 'http://' and 'git://''
|
|
113
|
+
# connections.
|
|
114
|
+
#
|
|
115
|
+
# @return [void]
|
|
116
|
+
#
|
|
117
|
+
def verify_source_is_secure(root_spec)
|
|
118
|
+
return if root_spec.source.nil? || (root_spec.source[:http].nil? && root_spec.source[:git].nil?)
|
|
119
|
+
source = if !root_spec.source[:http].nil?
|
|
120
|
+
URI(root_spec.source[:http].to_s)
|
|
121
|
+
elsif !root_spec.source[:git].nil?
|
|
122
|
+
git_source = root_spec.source[:git].to_s
|
|
123
|
+
return unless git_source =~ /^#{URI.regexp}$/
|
|
124
|
+
URI(git_source)
|
|
125
|
+
end
|
|
126
|
+
if UNENCRYPTED_PROTOCOLS.include?(source.scheme)
|
|
127
|
+
UI.warn "'#{root_spec.name}' uses the unencrypted '#{source.scheme}' protocol to transfer the Pod. " \
|
|
128
|
+
'Please be sure you\'re in a safe network with only trusted hosts. ' \
|
|
129
|
+
'Otherwise, please reach out to the library author to notify them of this security issue.'
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def download_request
|
|
134
|
+
Downloader::Request.new(
|
|
135
|
+
:spec => root_spec,
|
|
136
|
+
:released => released?,
|
|
137
|
+
)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Removes all the files not needed for the installation according to the
|
|
141
|
+
# specs by platform.
|
|
142
|
+
#
|
|
143
|
+
# @return [void]
|
|
144
|
+
#
|
|
145
|
+
def clean_installation
|
|
146
|
+
cleaner = Sandbox::PodDirCleaner.new(root, specs_by_platform)
|
|
147
|
+
cleaner.clean!
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
#-----------------------------------------------------------------------#
|
|
151
|
+
|
|
152
|
+
private
|
|
153
|
+
|
|
154
|
+
# @!group Convenience methods.
|
|
155
|
+
|
|
156
|
+
# @return [Array<Specifications>] the specification of the Pod used in
|
|
157
|
+
# this installation.
|
|
158
|
+
#
|
|
159
|
+
def specs
|
|
160
|
+
specs_by_platform.values.flatten
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# @return [Specification] the root specification of the Pod.
|
|
164
|
+
#
|
|
165
|
+
def root_spec
|
|
166
|
+
specs.first.root
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# @return [Pathname] the folder where the source of the Pod is located.
|
|
170
|
+
#
|
|
171
|
+
def root
|
|
172
|
+
sandbox.pod_dir(root_spec.name)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# @return [Boolean] whether the source has been pre downloaded in the
|
|
176
|
+
# resolution process to retrieve its podspec.
|
|
177
|
+
#
|
|
178
|
+
def predownloaded?
|
|
179
|
+
sandbox.predownloaded_pods.include?(root_spec.name)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# @return [Boolean] whether the pod uses the local option and thus
|
|
183
|
+
# CocoaPods should not interfere with the files of the user.
|
|
184
|
+
#
|
|
185
|
+
def local?
|
|
186
|
+
sandbox.local?(root_spec.name)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def released?
|
|
190
|
+
!local? && !predownloaded? && sandbox.specification(root_spec.name) != root_spec
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# @return [Array<Pathname>] The paths of the source files
|
|
194
|
+
#
|
|
195
|
+
def source_files(file_accessors)
|
|
196
|
+
file_accessors.flat_map(&:source_files)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
#-----------------------------------------------------------------------#
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module Pod
|
|
2
|
+
class Installer
|
|
3
|
+
# Controller class responsible of executing the prepare command
|
|
4
|
+
# of a single Pod.
|
|
5
|
+
#
|
|
6
|
+
class PodSourcePreparer
|
|
7
|
+
# @return [Specification] the root specification of the Pod.
|
|
8
|
+
#
|
|
9
|
+
attr_reader :spec
|
|
10
|
+
|
|
11
|
+
# @return [Pathname] the folder where the source of the Pod is located.
|
|
12
|
+
#
|
|
13
|
+
attr_reader :path
|
|
14
|
+
|
|
15
|
+
# Initialize a new instance
|
|
16
|
+
#
|
|
17
|
+
# @param [Specification] spec the root specification of the Pod.
|
|
18
|
+
# @param [Pathname] path the folder where the source of the Pod is located.
|
|
19
|
+
#
|
|
20
|
+
def initialize(spec, path)
|
|
21
|
+
raise "Given spec isn't a root spec, but must be." unless spec.root?
|
|
22
|
+
@spec = spec
|
|
23
|
+
@path = path
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
#-----------------------------------------------------------------------#
|
|
27
|
+
|
|
28
|
+
public
|
|
29
|
+
|
|
30
|
+
# @!group Preparation
|
|
31
|
+
|
|
32
|
+
# Executes the prepare command if there is one.
|
|
33
|
+
#
|
|
34
|
+
# @return [void]
|
|
35
|
+
#
|
|
36
|
+
def prepare!
|
|
37
|
+
run_prepare_command
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
#-----------------------------------------------------------------------#
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# @!group Preparation Steps
|
|
45
|
+
|
|
46
|
+
extend Executable
|
|
47
|
+
executable :bash
|
|
48
|
+
|
|
49
|
+
# Runs the prepare command bash script of the spec.
|
|
50
|
+
#
|
|
51
|
+
# @note Unsets the `CDPATH` env variable before running the
|
|
52
|
+
# shell script to avoid issues with relative paths
|
|
53
|
+
# (issue #1694).
|
|
54
|
+
#
|
|
55
|
+
# @return [void]
|
|
56
|
+
#
|
|
57
|
+
def run_prepare_command
|
|
58
|
+
return unless spec.prepare_command
|
|
59
|
+
UI.section(' > Running prepare command', '', 1) do
|
|
60
|
+
Dir.chdir(path) do
|
|
61
|
+
begin
|
|
62
|
+
ENV.delete('CDPATH')
|
|
63
|
+
ENV['COCOAPODS_VERSION'] = Pod::VERSION
|
|
64
|
+
prepare_command = spec.prepare_command.strip_heredoc.chomp
|
|
65
|
+
full_command = "\nset -e\n" + prepare_command
|
|
66
|
+
bash!('-c', full_command)
|
|
67
|
+
ensure
|
|
68
|
+
ENV.delete('COCOAPODS_VERSION')
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
#-----------------------------------------------------------------------#
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
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 occured during the validation
|
|
12
|
+
#
|
|
13
|
+
attr_reader :errors
|
|
14
|
+
|
|
15
|
+
# @return [Array<String>] any warnings that have occured 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_pod_directives
|
|
40
|
+
validate_no_abstract_only_pods!
|
|
41
|
+
validate_dependencies_are_present!
|
|
42
|
+
validate_no_duplicate_targets!
|
|
43
|
+
|
|
44
|
+
@validated = true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Wether the podfile is valid is not
|
|
48
|
+
# NOTE: Will execute `validate` if the podfile
|
|
49
|
+
# has not yet been validated
|
|
50
|
+
#
|
|
51
|
+
def valid?
|
|
52
|
+
validate unless @validated
|
|
53
|
+
|
|
54
|
+
@validated && errors.empty?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# A message describing any errors in the
|
|
58
|
+
# validation
|
|
59
|
+
#
|
|
60
|
+
def message
|
|
61
|
+
errors.join("\n")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def add_error(error)
|
|
67
|
+
errors << error
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def add_warning(warning)
|
|
71
|
+
warnings << warning
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def validate_pod_directives
|
|
75
|
+
@podfile_dependency_cache.podfile_dependencies.each do |dependency|
|
|
76
|
+
validate_conflicting_external_sources!(dependency)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def validate_conflicting_external_sources!(dependency)
|
|
81
|
+
external_source = dependency.external_source
|
|
82
|
+
return false if external_source.nil?
|
|
83
|
+
|
|
84
|
+
available_downloaders = Downloader.downloader_class_by_key.keys
|
|
85
|
+
specified_downloaders = external_source.select { |key| available_downloaders.include?(key) }
|
|
86
|
+
if specified_downloaders.size > 1
|
|
87
|
+
add_error "The dependency `#{dependency.name}` specifies more than one download strategy(#{specified_downloaders.keys.join(',')})." \
|
|
88
|
+
'Only one is allowed'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
pod_spec_or_path = external_source[:podspec].present? || external_source[:path].present?
|
|
92
|
+
if pod_spec_or_path && specified_downloaders.size > 0
|
|
93
|
+
add_error "The dependency `#{dependency.name}` specifies `podspec` or `path` in combination with other" \
|
|
94
|
+
' download strategies. This is not allowed'
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Warns the user if the podfile is empty.
|
|
99
|
+
#
|
|
100
|
+
# @note The workspace is created in any case and all the user projects
|
|
101
|
+
# are added to it, however the projects are not integrated as
|
|
102
|
+
# there is no way to discern between target definitions which are
|
|
103
|
+
# empty and target definitions which just serve the purpose to
|
|
104
|
+
# wrap other ones. This is not an issue because empty target
|
|
105
|
+
# definitions generate empty libraries.
|
|
106
|
+
#
|
|
107
|
+
# @return [void]
|
|
108
|
+
#
|
|
109
|
+
def validate_dependencies_are_present!
|
|
110
|
+
if @podfile_dependency_cache.target_definition_list.all?(&:empty?)
|
|
111
|
+
add_warning 'The Podfile does not contain any dependencies.'
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Verifies that no dependencies in the Podfile will end up not being built
|
|
116
|
+
# at all. In other words, all dependencies _must_ belong to a non-abstract
|
|
117
|
+
# target, or be inherited by a target where `inheritance == complete`.
|
|
118
|
+
#
|
|
119
|
+
def validate_no_abstract_only_pods!
|
|
120
|
+
all_dependencies = @podfile_dependency_cache.podfile_dependencies
|
|
121
|
+
concrete_dependencies = @podfile_dependency_cache.target_definition_list.reject(&:abstract?).flat_map { |td| @podfile_dependency_cache.target_definition_dependencies(td) }
|
|
122
|
+
abstract_only_dependencies = all_dependencies - concrete_dependencies
|
|
123
|
+
abstract_only_dependencies.each do |dep|
|
|
124
|
+
add_error "The dependency `#{dep}` is not used in any concrete target."
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def validate_no_duplicate_targets!
|
|
129
|
+
@podfile_dependency_cache.target_definition_list.group_by { |td| [td.name, td.user_project_path] }.
|
|
130
|
+
each do |(name, project), definitions|
|
|
131
|
+
next unless definitions.size > 1
|
|
132
|
+
error = "The target `#{name}` is declared twice"
|
|
133
|
+
error << " for the project `#{project}`" if project
|
|
134
|
+
add_error(error << '.')
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|