pod-builder-y 2.3.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/.gitignore +19 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +13 -0
- data/README.md +385 -0
- data/Rakefile +2 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/exe/pod_builder_y +406 -0
- data/lib/core_ext/string.rb +5 -0
- data/lib/pod_builder/analyze.rb +59 -0
- data/lib/pod_builder/analyzer.rb +16 -0
- data/lib/pod_builder/command.rb +14 -0
- data/lib/pod_builder/command/build.rb +228 -0
- data/lib/pod_builder/command/build_all.rb +15 -0
- data/lib/pod_builder/command/clean.rb +75 -0
- data/lib/pod_builder/command/deintegrate.rb +101 -0
- data/lib/pod_builder/command/generate_lldbinit.rb +128 -0
- data/lib/pod_builder/command/generate_podspec.rb +22 -0
- data/lib/pod_builder/command/info.rb +18 -0
- data/lib/pod_builder/command/init.rb +148 -0
- data/lib/pod_builder/command/install_sources.rb +79 -0
- data/lib/pod_builder/command/none.rb +16 -0
- data/lib/pod_builder/command/restore_all.rb +33 -0
- data/lib/pod_builder/command/switch.rb +224 -0
- data/lib/pod_builder/command/sync_podfile.rb +34 -0
- data/lib/pod_builder/command/update.rb +43 -0
- data/lib/pod_builder/configuration.rb +300 -0
- data/lib/pod_builder/core.rb +222 -0
- data/lib/pod_builder/info.rb +90 -0
- data/lib/pod_builder/install.rb +505 -0
- data/lib/pod_builder/licenses.rb +73 -0
- data/lib/pod_builder/podfile.rb +700 -0
- data/lib/pod_builder/podfile/pre_actions_swizzles.rb +84 -0
- data/lib/pod_builder/podfile_cp.rb +99 -0
- data/lib/pod_builder/podfile_item.rb +530 -0
- data/lib/pod_builder/podspec.rb +269 -0
- data/lib/pod_builder/rome/post_install.rb +446 -0
- data/lib/pod_builder/rome/pre_install.rb +6 -0
- data/lib/pod_builder/templates/build_podfile.template +70 -0
- data/lib/pod_builder/templates/build_podspec.template +19 -0
- data/lib/pod_builder/version.rb +4 -0
- data/pod-builder.gemspec +37 -0
- metadata +240 -0
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'cocoapods'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'colored'
|
4
|
+
|
5
|
+
require 'pod_builder/podfile'
|
6
|
+
require 'pod_builder/podfile_cp'
|
7
|
+
require 'pod_builder/podfile_item'
|
8
|
+
require 'pod_builder/analyze'
|
9
|
+
require 'pod_builder/analyzer'
|
10
|
+
require 'pod_builder/install'
|
11
|
+
require 'pod_builder/info'
|
12
|
+
require 'pod_builder/configuration'
|
13
|
+
require 'pod_builder/podspec'
|
14
|
+
require 'pod_builder/licenses'
|
15
|
+
|
16
|
+
require 'core_ext/string'
|
17
|
+
|
18
|
+
module PodBuilder
|
19
|
+
@@xcodeproj_path = nil
|
20
|
+
@@xcodeworkspace_path = nil
|
21
|
+
|
22
|
+
def self.git_rootpath
|
23
|
+
return `git rev-parse --show-toplevel`.strip()
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.safe_rm_rf(path)
|
27
|
+
unless File.exist?(path)
|
28
|
+
return
|
29
|
+
end
|
30
|
+
|
31
|
+
unless File.directory?(path)
|
32
|
+
FileUtils.rm(path)
|
33
|
+
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
current_dir = Dir.pwd
|
38
|
+
|
39
|
+
Dir.chdir(path)
|
40
|
+
|
41
|
+
rootpath = git_rootpath()
|
42
|
+
raise "\n\nNo git repository found in '#{path}', can't delete files!\n".red if rootpath.empty? && !path.start_with?(Configuration.build_base_path)
|
43
|
+
|
44
|
+
FileUtils.rm_rf(path)
|
45
|
+
|
46
|
+
if File.exist?(current_dir)
|
47
|
+
Dir.chdir(current_dir)
|
48
|
+
else
|
49
|
+
Dir.chdir(basepath)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.gitignoredfiles
|
54
|
+
Dir.chdir(git_rootpath) do
|
55
|
+
return `git status --ignored -s | grep "^\!\!" | cut -c4-`.strip().split("\n")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.basepath(child = "")
|
60
|
+
if child.nil?
|
61
|
+
return nil
|
62
|
+
end
|
63
|
+
|
64
|
+
return "#{Configuration.base_path}/#{child}".gsub("//", "/").gsub(/\/$/, '')
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.prebuiltpath(child = "")
|
68
|
+
if child.nil?
|
69
|
+
return nil
|
70
|
+
end
|
71
|
+
|
72
|
+
path = basepath("Prebuilt")
|
73
|
+
if child.length > 0
|
74
|
+
path += "/#{child}"
|
75
|
+
end
|
76
|
+
|
77
|
+
return path
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.buildpath_prebuiltpath(child = "")
|
81
|
+
if child.nil?
|
82
|
+
return nil
|
83
|
+
end
|
84
|
+
|
85
|
+
path = "#{Configuration.build_path}/Prebuilt"
|
86
|
+
if child.length > 0
|
87
|
+
path += "/#{child}"
|
88
|
+
end
|
89
|
+
|
90
|
+
return path
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.buildpath_dsympath(child = "")
|
94
|
+
if child.nil?
|
95
|
+
return nil
|
96
|
+
end
|
97
|
+
|
98
|
+
path = "#{Configuration.build_path}/dSYM"
|
99
|
+
if child.length > 0
|
100
|
+
path += "/#{child}"
|
101
|
+
end
|
102
|
+
|
103
|
+
return path
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.dsympath(child = "")
|
107
|
+
if child.nil?
|
108
|
+
return nil
|
109
|
+
end
|
110
|
+
|
111
|
+
path = basepath("dSYM")
|
112
|
+
if child.length > 0
|
113
|
+
path += "/#{child}"
|
114
|
+
end
|
115
|
+
|
116
|
+
return path
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.project_path(child = "")
|
120
|
+
project = PodBuilder::find_xcodeworkspace
|
121
|
+
|
122
|
+
return project ? "#{File.dirname(project)}/#{child}".gsub("//", "/").gsub(/\/$/, '') : nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.find_xcodeproj
|
126
|
+
unless @@xcodeproj_path.nil?
|
127
|
+
return @@xcodeproj_path
|
128
|
+
end
|
129
|
+
project_name = File.basename(find_xcodeworkspace, ".*")
|
130
|
+
|
131
|
+
xcodeprojects = Dir.glob("#{home}/**/#{project_name}.xcodeproj").select { |x|
|
132
|
+
folder_in_home = x.gsub(home, "")
|
133
|
+
!folder_in_home.include?("/Pods/") && !x.include?(PodBuilder::basepath("Sources")) && !x.include?(PodBuilder::basepath + "/")
|
134
|
+
}
|
135
|
+
raise "\n\nxcodeproj not found!".red if xcodeprojects.count == 0
|
136
|
+
raise "\n\nFound multiple xcodeproj:\n#{xcodeprojects.join("\n")}".red if xcodeprojects.count > 1
|
137
|
+
|
138
|
+
@@xcodeproj_path = xcodeprojects.first
|
139
|
+
return @@xcodeproj_path
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.find_xcodeworkspace
|
143
|
+
unless @@xcodeworkspace_path.nil?
|
144
|
+
return @@xcodeworkspace_path
|
145
|
+
end
|
146
|
+
|
147
|
+
xcworkspaces = Dir.glob("#{home}/**/#{Configuration.project_name}*.xcworkspace").select { |x|
|
148
|
+
folder_in_home = x.gsub(home, "")
|
149
|
+
!folder_in_home.include?("/Pods/") && !x.include?(PodBuilder::basepath("Sources")) && !x.include?(PodBuilder::basepath + "/") && !x.include?(".xcodeproj/")
|
150
|
+
}
|
151
|
+
raise "\n\nxcworkspace not found!".red if xcworkspaces.count == 0
|
152
|
+
raise "\n\nFound multiple xcworkspaces:\n#{xcworkspaces.join("\n")}".red if xcworkspaces.count > 1
|
153
|
+
|
154
|
+
@@xcodeworkspace_path = xcworkspaces.first
|
155
|
+
return @@xcodeworkspace_path
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.prepare_basepath
|
159
|
+
workspace_path = PodBuilder::find_xcodeworkspace
|
160
|
+
project_path = PodBuilder::find_xcodeproj
|
161
|
+
if workspace_path && project_path
|
162
|
+
FileUtils.mkdir_p(basepath("Pods/Target Support Files"))
|
163
|
+
FileUtils.cp_r(workspace_path, basepath)
|
164
|
+
FileUtils.cp_r(project_path, basepath)
|
165
|
+
FileUtils.rm_f(basepath("Podfile.lock"))
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.clean_basepath
|
170
|
+
if path = PodBuilder::find_xcodeproj
|
171
|
+
PodBuilder::safe_rm_rf(basepath(File.basename(path)))
|
172
|
+
end
|
173
|
+
if path = PodBuilder::find_xcodeworkspace
|
174
|
+
PodBuilder::safe_rm_rf(basepath(File.basename(path)))
|
175
|
+
end
|
176
|
+
|
177
|
+
PodBuilder::safe_rm_rf(basepath("Pods"))
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.system_swift_version
|
181
|
+
swift_version = `swiftc --version | grep -o 'swiftlang-.*\s'`.strip()
|
182
|
+
raise "\n\nUnsupported swift compiler version, expecting `swiftlang` keyword in `swiftc --version`".red if swift_version.length == 0
|
183
|
+
return swift_version
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.add_lockfile
|
187
|
+
lockfile_path = Configuration.lockfile_path
|
188
|
+
|
189
|
+
if File.exist?(lockfile_path)
|
190
|
+
if pid = File.read(lockfile_path)
|
191
|
+
begin
|
192
|
+
if Process.getpgid(pid)
|
193
|
+
if Configuration.deterministic_build
|
194
|
+
raise "\n\nAnother PodBuilder pending task is running\n".red
|
195
|
+
else
|
196
|
+
raise "\n\nAnother PodBuilder pending task is running on this project\n".red
|
197
|
+
end
|
198
|
+
end
|
199
|
+
rescue
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
File.write(lockfile_path, Process.pid, mode: "w")
|
205
|
+
end
|
206
|
+
|
207
|
+
def self.remove_lockfile
|
208
|
+
lockfile_path = Configuration.lockfile_path
|
209
|
+
|
210
|
+
if File.exist?(lockfile_path)
|
211
|
+
FileUtils.rm(lockfile_path)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
private
|
216
|
+
|
217
|
+
def self.home
|
218
|
+
rootpath = git_rootpath
|
219
|
+
raise "\n\nNo git repository found in current folder `#{Dir.pwd}`!\n".red if rootpath.empty?
|
220
|
+
return rootpath
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module PodBuilder
|
4
|
+
class Info
|
5
|
+
def self.generate_info
|
6
|
+
swift_version = PodBuilder::system_swift_version
|
7
|
+
result = {}
|
8
|
+
name = nil
|
9
|
+
|
10
|
+
Dir.glob(PodBuilder::prebuiltpath("**/#{Configuration.prebuilt_info_filename}")).each do |json_path|
|
11
|
+
name, prebuilt_info = prebuilt_info(json_path)
|
12
|
+
result[name] = prebuilt_info
|
13
|
+
end
|
14
|
+
|
15
|
+
return result
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def self.pod_name_from_entry(line)
|
21
|
+
if (matches = line&.match(/pod '(.*?)'/)) && matches.size == 2
|
22
|
+
pod_name = matches[1]
|
23
|
+
|
24
|
+
return pod_name
|
25
|
+
end
|
26
|
+
|
27
|
+
return "unknown_podname"
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.version_info_from_entry(line)
|
31
|
+
if (matches = line&.match(/pod '(.*)', '=(.*)'/)) && matches.size == 3
|
32
|
+
pod_name = matches[1]
|
33
|
+
tag = matches[2]
|
34
|
+
|
35
|
+
return { "tag": tag }
|
36
|
+
elsif (matches = line&.match(/pod '(.*)', :git => '(.*)', :commit => '(.*)'/)) && matches.size == 4
|
37
|
+
pod_name = matches[1]
|
38
|
+
repo = matches[2]
|
39
|
+
hash = matches[3]
|
40
|
+
|
41
|
+
return { "repo": repo, "hash": hash }
|
42
|
+
elsif (matches = line&.match(/pod '(.*)', :git => '(.*)', :branch => '(.*)'/)) && matches.size == 4
|
43
|
+
pod_name = matches[1]
|
44
|
+
repo = matches[2]
|
45
|
+
branch = matches[3]
|
46
|
+
|
47
|
+
return { "repo": repo, "branch": branch }
|
48
|
+
elsif (matches = line&.match(/pod '(.*)', :git => '(.*)', :tag => '(.*)'/)) && matches.size == 4
|
49
|
+
pod_name = matches[1]
|
50
|
+
repo = matches[2]
|
51
|
+
tag = matches[3]
|
52
|
+
|
53
|
+
return { "repo": repo, "tag": tag }
|
54
|
+
elsif (matches = line&.match(/pod '(.*)', :path => '(.*)'/)) && matches.size == 3
|
55
|
+
pod_name = matches[1]
|
56
|
+
|
57
|
+
return { "repo": "local" }
|
58
|
+
elsif (matches = line&.match(/pod '(.*)', :podspec => '(.*)'/)) && matches.size == 3
|
59
|
+
pod_name = matches[1]
|
60
|
+
|
61
|
+
return { "repo": "local" }
|
62
|
+
else
|
63
|
+
raise "\n\nFailed extracting version from line:\n#{line}\n\n".red
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.prebuilt_info(path)
|
68
|
+
unless File.exist?(path)
|
69
|
+
return {}
|
70
|
+
end
|
71
|
+
|
72
|
+
data = JSON.load(File.read(path))
|
73
|
+
|
74
|
+
result = {}
|
75
|
+
if swift_version = data["swift_version"]
|
76
|
+
result.merge!({ "swift_version": swift_version})
|
77
|
+
end
|
78
|
+
|
79
|
+
pod_version = version_info_from_entry(data["entry"])
|
80
|
+
pod_name = pod_name_from_entry(data["entry"])
|
81
|
+
|
82
|
+
result.merge!({ "version": pod_version })
|
83
|
+
result.merge!({ "specs": (data["specs"] || []) })
|
84
|
+
result.merge!({ "is_static": (data["is_static"] || false) })
|
85
|
+
result.merge!({ "original_compile_path": (data["original_compile_path"] || "") })
|
86
|
+
|
87
|
+
return pod_name, result
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,505 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'colored'
|
3
|
+
require 'highline/import'
|
4
|
+
|
5
|
+
# The following begin/end clause contains a set of monkey patches of the original CP implementation
|
6
|
+
|
7
|
+
# The Pod::Target and Pod::Installer::Xcode::PodTargetDependencyInstaller swizzles patch
|
8
|
+
# the following issues:
|
9
|
+
# - https://github.com/CocoaPods/Rome/issues/81
|
10
|
+
# - https://github.com/leavez/cocoapods-binary/issues/50
|
11
|
+
begin
|
12
|
+
require 'cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb'
|
13
|
+
|
14
|
+
class Pod::Specification
|
15
|
+
Pod::Specification.singleton_class.send(:alias_method, :swz_from_hash, :from_hash)
|
16
|
+
Pod::Specification.singleton_class.send(:alias_method, :swz_from_string, :from_string)
|
17
|
+
|
18
|
+
def self.from_string(*args)
|
19
|
+
spec = swz_from_string(*args)
|
20
|
+
|
21
|
+
if overrides = PodBuilder::Configuration.spec_overrides[spec.name]
|
22
|
+
overrides.each do |k, v|
|
23
|
+
if spec.attributes_hash[k].is_a?(Hash)
|
24
|
+
current = spec.attributes_hash[k]
|
25
|
+
spec.attributes_hash[k] = current.merge(v)
|
26
|
+
else
|
27
|
+
spec.attributes_hash[k] = v
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
spec
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Pod::Target
|
37
|
+
attr_accessor :mock_dynamic_framework
|
38
|
+
|
39
|
+
alias_method :swz_build_type, :build_type
|
40
|
+
|
41
|
+
def build_type
|
42
|
+
if mock_dynamic_framework == true
|
43
|
+
if defined?(Pod::BuildType) # CocoaPods 1.9 and later
|
44
|
+
Pod::BuildType.new(linkage: :dynamic, packaging: :framework)
|
45
|
+
elsif defined?(Pod::Target::BuildType) # CocoaPods 1.7, 1.8
|
46
|
+
Pod::Target::BuildType.new(linkage: :dynamic, packaging: :framework)
|
47
|
+
else
|
48
|
+
raise "\n\nBuildType not found. Open an issue reporting your CocoaPods version".red
|
49
|
+
end
|
50
|
+
else
|
51
|
+
swz_build_type()
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Pod::PodTarget
|
57
|
+
@@modules_override = Hash.new
|
58
|
+
|
59
|
+
def self.modules_override= (x)
|
60
|
+
@@modules_override = x
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.modules_override
|
64
|
+
return @@modules_override
|
65
|
+
end
|
66
|
+
|
67
|
+
alias_method :swz_defines_module?, :defines_module?
|
68
|
+
|
69
|
+
def defines_module?
|
70
|
+
return @@modules_override.has_key?(name) ? @@modules_override[name] : swz_defines_module?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Starting from CocoaPods 1.10.0 and later resources are no longer copied inside the .framework
|
75
|
+
# when building static frameworks. While this is correct when using CP normally, for redistributable
|
76
|
+
# frameworks we require resources to be shipped along the binary
|
77
|
+
class Pod::Installer::Xcode::PodsProjectGenerator::PodTargetInstaller
|
78
|
+
alias_method :swz_add_files_to_build_phases, :add_files_to_build_phases
|
79
|
+
|
80
|
+
def add_files_to_build_phases(native_target, test_native_targets, app_native_targets)
|
81
|
+
target.mock_dynamic_framework = target.build_as_static_framework?
|
82
|
+
swz_add_files_to_build_phases(native_target, test_native_targets, app_native_targets)
|
83
|
+
target.mock_dynamic_framework = false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class Pod::Installer::Xcode::PodTargetDependencyInstaller
|
88
|
+
alias_method :swz_wire_resource_bundle_targets, :wire_resource_bundle_targets
|
89
|
+
|
90
|
+
def wire_resource_bundle_targets(resource_bundle_targets, native_target, pod_target)
|
91
|
+
pod_target.mock_dynamic_framework = pod_target.build_as_static_framework?
|
92
|
+
res = swz_wire_resource_bundle_targets(resource_bundle_targets, native_target, pod_target)
|
93
|
+
pod_target.mock_dynamic_framework = false
|
94
|
+
return res
|
95
|
+
end
|
96
|
+
end
|
97
|
+
rescue LoadError
|
98
|
+
# CocoaPods 1.6.2 or earlier
|
99
|
+
end
|
100
|
+
|
101
|
+
module PodBuilder
|
102
|
+
class InstallResult
|
103
|
+
# @return [Array<Hash>] The installed licenses
|
104
|
+
#
|
105
|
+
attr_reader :licenses
|
106
|
+
|
107
|
+
# @return [Hash] A hash containing the expected prebuilt_info filename and content
|
108
|
+
#
|
109
|
+
attr_reader :prebuilt_info
|
110
|
+
|
111
|
+
def initialize(licenses = [], prebuilt_info = Hash.new)
|
112
|
+
@licenses = licenses
|
113
|
+
@prebuilt_info = prebuilt_info
|
114
|
+
end
|
115
|
+
|
116
|
+
def +(obj)
|
117
|
+
merged_licenses = @licenses.dup + obj.licenses
|
118
|
+
merged_prebuilt_info = @prebuilt_info.dup
|
119
|
+
|
120
|
+
merged_prebuilt_info.each do |key, value|
|
121
|
+
if obj.prebuilt_info.has_key?(key)
|
122
|
+
specs = merged_prebuilt_info[key]["specs"] || []
|
123
|
+
specs += (obj.prebuilt_info[key]["specs"] || [])
|
124
|
+
merged_prebuilt_info[key]["specs"] = specs.uniq
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
merged_prebuilt_info = obj.prebuilt_info.merge(merged_prebuilt_info)
|
129
|
+
|
130
|
+
return InstallResult.new(merged_licenses, merged_prebuilt_info)
|
131
|
+
end
|
132
|
+
|
133
|
+
def write_prebuilt_info_files
|
134
|
+
prebuilt_info.each do |file_path, file_content|
|
135
|
+
File.write(file_path, JSON.pretty_generate(file_content))
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class Install
|
141
|
+
# This method will generate prebuilt data by building from "/tmp/pod_builder/Podfile"
|
142
|
+
def self.podfile(podfile_content, podfile_items, build_configuration)
|
143
|
+
puts "Preparing build Podfile".yellow
|
144
|
+
|
145
|
+
PodBuilder::safe_rm_rf(Configuration.build_path)
|
146
|
+
FileUtils.mkdir_p(Configuration.build_path)
|
147
|
+
|
148
|
+
init_git(Configuration.build_path) # this is needed to be able to call safe_rm_rf
|
149
|
+
|
150
|
+
podfile_content = copy_development_pods_source_code(podfile_content, podfile_items)
|
151
|
+
|
152
|
+
podfile_content = Podfile.update_path_entries(podfile_content, Install.method(:podfile_path_transform))
|
153
|
+
podfile_content = Podfile.update_project_entries(podfile_content, Install.method(:podfile_path_transform))
|
154
|
+
podfile_content = Podfile.update_require_entries(podfile_content, Install.method(:podfile_path_transform))
|
155
|
+
|
156
|
+
podfile_path = File.join(Configuration.build_path, "Podfile")
|
157
|
+
File.write(podfile_path, podfile_content)
|
158
|
+
|
159
|
+
begin
|
160
|
+
lock_file = "#{Configuration.build_path}/pod_builder.lock"
|
161
|
+
FileUtils.touch(lock_file)
|
162
|
+
|
163
|
+
prebuilt_entries = use_prebuilt_entries_for_unchanged_pods(podfile_path, podfile_items)
|
164
|
+
|
165
|
+
install
|
166
|
+
|
167
|
+
copy_prebuilt_items(podfile_items - prebuilt_entries)
|
168
|
+
|
169
|
+
prebuilt_info = prebuilt_info(podfile_items)
|
170
|
+
licenses = license_specifiers()
|
171
|
+
|
172
|
+
if !OPTIONS.has_key?(:debug)
|
173
|
+
PodBuilder::safe_rm_rf(Configuration.build_path)
|
174
|
+
end
|
175
|
+
|
176
|
+
return InstallResult.new(licenses, prebuilt_info)
|
177
|
+
rescue Exception => e
|
178
|
+
if File.directory?("#{Configuration.build_path}/Pods/Pods.xcodeproj")
|
179
|
+
activate_pod_scheme()
|
180
|
+
|
181
|
+
if ENV["DEBUGGING"]
|
182
|
+
system("xed #{Configuration.build_path}/Pods")
|
183
|
+
elsif !OPTIONS.has_key?(:no_stdin_available)
|
184
|
+
confirm = ask("\n\nOh no! Something went wrong during prebuild phase! Do you want to open the prebuild project to debug the error, you will need to add and run the Pods-Dummy scheme? [Y/N] ".red) { |yn| yn.limit = 1, yn.validate = /[yn]/i }
|
185
|
+
|
186
|
+
if confirm.downcase == 'y'
|
187
|
+
system("xed #{Configuration.build_path}/Pods")
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
raise e
|
193
|
+
ensure
|
194
|
+
FileUtils.rm(lock_file) if File.exist?(lock_file)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.prebuilt_info(podfile_items)
|
199
|
+
gitignored_files = PodBuilder::gitignoredfiles
|
200
|
+
|
201
|
+
swift_version = PodBuilder::system_swift_version
|
202
|
+
|
203
|
+
write_prebuilt_info_filename_gitattributes
|
204
|
+
|
205
|
+
ret = Hash.new
|
206
|
+
root_names = podfile_items.reject(&:is_prebuilt).map(&:root_name).uniq
|
207
|
+
root_names.each do |prebuilt_name|
|
208
|
+
path = PodBuilder::prebuiltpath(prebuilt_name)
|
209
|
+
|
210
|
+
unless File.directory?(path)
|
211
|
+
puts "Prebuilt items for #{prebuilt_name} not found".blue
|
212
|
+
next
|
213
|
+
end
|
214
|
+
|
215
|
+
unless podfile_item = podfile_items.detect { |t| t.name == prebuilt_name } || podfile_items.detect { |t| t.root_name == prebuilt_name }
|
216
|
+
puts "Prebuilt items for #{prebuilt_name} not found #2".blue
|
217
|
+
next
|
218
|
+
end
|
219
|
+
|
220
|
+
podbuilder_file = File.join(path, Configuration.prebuilt_info_filename)
|
221
|
+
entry = podfile_item.entry(true, false)
|
222
|
+
|
223
|
+
data = {}
|
224
|
+
data["entry"] = entry
|
225
|
+
data["is_prebuilt"] = podfile_item.is_prebuilt
|
226
|
+
if Dir.glob(File.join(path, "#{podfile_item.prebuilt_rel_path}/Headers/*-Swift.h")).count > 0
|
227
|
+
data["swift_version"] = swift_version
|
228
|
+
end
|
229
|
+
|
230
|
+
specs = podfile_items.select { |x| x.module_name == podfile_item.module_name }
|
231
|
+
subspecs_deps = specs.map(&:dependency_names).flatten
|
232
|
+
subspec_self_deps = subspecs_deps.select { |x| x.start_with?("#{prebuilt_name}/") }
|
233
|
+
data["specs"] = (specs.map(&:name) + subspec_self_deps).uniq
|
234
|
+
data["is_static"] = podfile_item.is_static
|
235
|
+
data["original_compile_path"] = Pathname.new(Configuration.build_path).realpath.to_s
|
236
|
+
if hash = build_folder_hash(podfile_item, gitignored_files)
|
237
|
+
data["build_folder_hash"] = hash
|
238
|
+
end
|
239
|
+
|
240
|
+
ret.merge!({ podbuilder_file => data })
|
241
|
+
end
|
242
|
+
|
243
|
+
return ret
|
244
|
+
end
|
245
|
+
private
|
246
|
+
|
247
|
+
def self.license_specifiers
|
248
|
+
acknowledge_file = "#{Configuration.build_path}/Pods/Target Support Files/Pods-DummyTarget/Pods-DummyTarget-acknowledgements.plist"
|
249
|
+
unless File.exist?(acknowledge_file)
|
250
|
+
raise "\n\nLicense file not found".red
|
251
|
+
end
|
252
|
+
|
253
|
+
plist = CFPropertyList::List.new(:file => acknowledge_file)
|
254
|
+
data = CFPropertyList.native_types(plist.value)
|
255
|
+
|
256
|
+
return data["PreferenceSpecifiers"] || []
|
257
|
+
end
|
258
|
+
|
259
|
+
def self.copy_development_pods_source_code(podfile_content, podfile_items)
|
260
|
+
# Development pods are normally built/integrated without moving files from their original paths.
|
261
|
+
# It is important that CocoaPods compiles the files under Configuration.build_path in order that
|
262
|
+
# DWARF debug info reference to this constant path. Doing otherwise breaks the assumptions that
|
263
|
+
# makes the `generate_lldbinit` command work.
|
264
|
+
development_pods = podfile_items.select { |x| x.is_development_pod }
|
265
|
+
development_pods.each do |podfile_item|
|
266
|
+
destination_path = "#{Configuration.build_path}/Pods/#{podfile_item.name}"
|
267
|
+
FileUtils.mkdir_p(destination_path)
|
268
|
+
|
269
|
+
if Pathname.new(podfile_item.path).absolute?
|
270
|
+
FileUtils.cp_r("#{podfile_item.path}/.", destination_path)
|
271
|
+
else
|
272
|
+
FileUtils.cp_r("#{PodBuilder::basepath(podfile_item.path)}/.", destination_path)
|
273
|
+
end
|
274
|
+
|
275
|
+
unless Configuration.build_using_repo_paths
|
276
|
+
podfile_content.gsub!("'#{podfile_item.path}'", "'#{destination_path}'")
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
return podfile_content
|
281
|
+
end
|
282
|
+
|
283
|
+
def self.use_prebuilt_entries_for_unchanged_pods(podfile_path, podfile_items)
|
284
|
+
podfile_content = File.read(podfile_path)
|
285
|
+
|
286
|
+
replaced_items = []
|
287
|
+
|
288
|
+
if OPTIONS.has_key?(:force_rebuild)
|
289
|
+
podfile_content.gsub!("%%%prebuilt_root_paths%%%", "{}")
|
290
|
+
else
|
291
|
+
download # Copy files under #{Configuration.build_path}/Pods so that we can determine build folder hashes
|
292
|
+
|
293
|
+
gitignored_files = PodBuilder::gitignoredfiles
|
294
|
+
|
295
|
+
prebuilt_root_paths = Hash.new
|
296
|
+
|
297
|
+
# Replace prebuilt entries in Podfile for Pods that have no changes in source code which will avoid rebuilding them
|
298
|
+
items = podfile_items.group_by { |t| t.root_name }.map { |k, v| v.first } # Return one podfile_item per root_name
|
299
|
+
items.each do |item|
|
300
|
+
podspec_path = item.prebuilt_podspec_path
|
301
|
+
if last_build_folder_hash = build_folder_hash_in_prebuilt_info_file(item)
|
302
|
+
if last_build_folder_hash == build_folder_hash(item, gitignored_files)
|
303
|
+
puts "No changes detected to '#{item.root_name}', will skip rebuild".blue
|
304
|
+
|
305
|
+
replaced_items.push(item)
|
306
|
+
|
307
|
+
podfile_items.select { |t| t.root_name == item.root_name }.each do |replace_item|
|
308
|
+
replace_regex = "pod '#{Regexp.quote(replace_item.name)}', .*"
|
309
|
+
replace_line_found = podfile_content =~ /#{replace_regex}/i
|
310
|
+
raise "\n\nFailed finding pod entry for '#{replace_item.name}'".red unless replace_line_found
|
311
|
+
podfile_content.gsub!(/#{replace_regex}/, replace_item.prebuilt_entry(true, true))
|
312
|
+
|
313
|
+
prebuilt_root_paths[replace_item.root_name] = PodBuilder::prebuiltpath
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
podfile_content.gsub!("%%%prebuilt_root_paths%%%", prebuilt_root_paths.to_s)
|
320
|
+
end
|
321
|
+
|
322
|
+
File.write(podfile_path, podfile_content)
|
323
|
+
|
324
|
+
return replaced_items
|
325
|
+
end
|
326
|
+
|
327
|
+
def self.install
|
328
|
+
puts "Preparing build".yellow
|
329
|
+
|
330
|
+
CLAide::Command::PluginManager.load_plugins("cocoapods")
|
331
|
+
|
332
|
+
Dir.chdir(Configuration.build_path) do
|
333
|
+
config = Pod::Config.new()
|
334
|
+
installer = Pod::Installer.new(config.sandbox, config.podfile, config.lockfile)
|
335
|
+
installer.repo_update = false
|
336
|
+
installer.update = false
|
337
|
+
|
338
|
+
install_start_time = Time.now
|
339
|
+
|
340
|
+
installer.install!
|
341
|
+
install_time = Time.now - install_start_time
|
342
|
+
|
343
|
+
puts "Build completed in #{install_time.to_i} seconds".blue
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def self.download
|
348
|
+
puts "Downloading Pods source code".yellow
|
349
|
+
|
350
|
+
CLAide::Command::PluginManager.load_plugins("cocoapods")
|
351
|
+
|
352
|
+
Dir.chdir(Configuration.build_path) do
|
353
|
+
Pod::UserInterface::config.silent = true
|
354
|
+
|
355
|
+
config = Pod::Config.new()
|
356
|
+
installer = Pod::Installer.new(config.sandbox, config.podfile, config.lockfile)
|
357
|
+
installer.repo_update = false
|
358
|
+
installer.update = false
|
359
|
+
installer.prepare
|
360
|
+
installer.resolve_dependencies
|
361
|
+
installer.download_dependencies
|
362
|
+
|
363
|
+
Pod::UserInterface::config.silent = false
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
def self.copy_prebuilt_items(podfile_items)
|
368
|
+
FileUtils.mkdir_p(PodBuilder::prebuiltpath)
|
369
|
+
|
370
|
+
non_prebuilt_items = podfile_items.reject(&:is_prebuilt)
|
371
|
+
|
372
|
+
pod_names = non_prebuilt_items.map(&:root_name).uniq
|
373
|
+
|
374
|
+
pod_names.reject! { |t|
|
375
|
+
folder_path = PodBuilder::buildpath_prebuiltpath(t)
|
376
|
+
File.directory?(folder_path) && Dir.empty?(folder_path) # When using prebuilt items we end up with empty folders
|
377
|
+
}
|
378
|
+
|
379
|
+
pod_names.each do |pod_name|
|
380
|
+
root_name = pod_name.split("/").first
|
381
|
+
|
382
|
+
items_to_delete = Dir.glob("#{PodBuilder::prebuiltpath(root_name)}/**/*")
|
383
|
+
items_to_delete.each { |t| PodBuilder::safe_rm_rf(t) }
|
384
|
+
end
|
385
|
+
|
386
|
+
# Now copy
|
387
|
+
pod_names.each do |pod_name|
|
388
|
+
root_name = pod_name.split("/").first
|
389
|
+
source_path = PodBuilder::buildpath_prebuiltpath(root_name)
|
390
|
+
|
391
|
+
unless File.directory?(source_path)
|
392
|
+
puts "Prebuilt items for #{pod_name} not found".blue
|
393
|
+
next
|
394
|
+
end
|
395
|
+
|
396
|
+
unless Dir.glob("#{source_path}/**/*").select { |t| File.file?(t) }.empty?
|
397
|
+
destination_folder = PodBuilder::prebuiltpath(root_name)
|
398
|
+
FileUtils.mkdir_p(destination_folder)
|
399
|
+
FileUtils.cp_r("#{source_path}/.", destination_folder)
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
# Folder won't exist if no dSYM were generated (all static libs)
|
404
|
+
if File.directory?(PodBuilder::buildpath_dsympath)
|
405
|
+
FileUtils.mkdir_p(PodBuilder::dsympath)
|
406
|
+
FileUtils.cp_r(PodBuilder::buildpath_dsympath, PodBuilder::basepath)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
def self.write_prebuilt_info_filename_gitattributes
|
411
|
+
gitattributes_path = PodBuilder::basepath(".gitattributes")
|
412
|
+
expected_attributes = ["#{Configuration.configuration_filename} binary"].join
|
413
|
+
unless File.exists?(gitattributes_path) && File.read(gitattributes_path).include?(expected_attributes)
|
414
|
+
File.write(gitattributes_path, expected_attributes, mode: 'a')
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
def self.init_git(path)
|
419
|
+
current_dir = Dir.pwd
|
420
|
+
|
421
|
+
Dir.chdir(path)
|
422
|
+
system("git init")
|
423
|
+
Dir.chdir(current_dir)
|
424
|
+
end
|
425
|
+
|
426
|
+
def self.build_folder_hash_in_prebuilt_info_file(podfile_item)
|
427
|
+
prebuilt_info_path = PodBuilder::prebuiltpath(File.join(podfile_item.root_name, Configuration.prebuilt_info_filename))
|
428
|
+
|
429
|
+
if File.exist?(prebuilt_info_path)
|
430
|
+
data = JSON.parse(File.read(prebuilt_info_path))
|
431
|
+
return data['build_folder_hash']
|
432
|
+
else
|
433
|
+
return nil
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
def self.build_folder_hash(podfile_item, exclude_files)
|
438
|
+
if podfile_item.is_development_pod
|
439
|
+
if Pathname.new(podfile_item.path).absolute?
|
440
|
+
item_path = podfile_item.path
|
441
|
+
else
|
442
|
+
item_path = PodBuilder::basepath(podfile_item.path)
|
443
|
+
end
|
444
|
+
|
445
|
+
rootpath = PodBuilder::git_rootpath
|
446
|
+
file_hashes = []
|
447
|
+
Dir.glob("#{item_path}/**/*", File::FNM_DOTMATCH) do |path|
|
448
|
+
unless File.file?(path)
|
449
|
+
next
|
450
|
+
end
|
451
|
+
|
452
|
+
path = File.expand_path(path)
|
453
|
+
rel_path = path.gsub(rootpath, "")[1..]
|
454
|
+
unless exclude_files.include?(rel_path)
|
455
|
+
file_hashes.push(Digest::MD5.hexdigest(File.read(path)))
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
return Digest::MD5.hexdigest(file_hashes.join)
|
460
|
+
else
|
461
|
+
# Pod folder might be under .gitignore
|
462
|
+
item_path = "#{Configuration.build_path}/Pods/#{podfile_item.root_name}"
|
463
|
+
if File.directory?(item_path)
|
464
|
+
return `find '#{item_path}' -type f -print0 | sort -z | xargs -0 shasum | shasum | cut -d' ' -f1`.strip()
|
465
|
+
else
|
466
|
+
return nil
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
def self.podfile_path_transform(path)
|
472
|
+
if Configuration.build_using_repo_paths
|
473
|
+
return File.expand_path(PodBuilder::basepath(path))
|
474
|
+
else
|
475
|
+
use_absolute_paths = true
|
476
|
+
podfile_path = File.join(Configuration.build_path, "Podfile")
|
477
|
+
original_basepath = PodBuilder::basepath
|
478
|
+
|
479
|
+
podfile_base_path = Pathname.new(File.dirname(podfile_path))
|
480
|
+
|
481
|
+
original_path = Pathname.new(File.join(original_basepath, path))
|
482
|
+
replace_path = original_path.relative_path_from(podfile_base_path)
|
483
|
+
if use_absolute_paths
|
484
|
+
replace_path = replace_path.expand_path(podfile_base_path)
|
485
|
+
end
|
486
|
+
|
487
|
+
return replace_path
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
def self.activate_pod_scheme
|
492
|
+
if scheme_file = Dir.glob("#{Configuration.build_path}/Pods/**/xcschememanagement.plist").first
|
493
|
+
plist = CFPropertyList::List.new(:file => scheme_file)
|
494
|
+
data = CFPropertyList.native_types(plist.value)
|
495
|
+
|
496
|
+
if !data.dig("SchemeUserState", "Pods-DummyTarget.xcscheme").nil?
|
497
|
+
data["SchemeUserState"]["Pods-DummyTarget.xcscheme"]["isShown"] = true
|
498
|
+
end
|
499
|
+
|
500
|
+
plist.value = CFPropertyList.guess(data)
|
501
|
+
plist.save(scheme_file, CFPropertyList::List::FORMAT_BINARY)
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|