cocoapods-binary-ht 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cocoapods-binary-cache.rb +2 -0
  3. data/lib/cocoapods-binary-ht/cache/all.rb +9 -0
  4. data/lib/cocoapods-binary-ht/cache/validation_result.rb +73 -0
  5. data/lib/cocoapods-binary-ht/cache/validator.rb +20 -0
  6. data/lib/cocoapods-binary-ht/cache/validator_accumulated.rb +4 -0
  7. data/lib/cocoapods-binary-ht/cache/validator_base.rb +112 -0
  8. data/lib/cocoapods-binary-ht/cache/validator_dependencies_graph.rb +25 -0
  9. data/lib/cocoapods-binary-ht/cache/validator_dev_pods.rb +30 -0
  10. data/lib/cocoapods-binary-ht/cache/validator_exclusion.rb +14 -0
  11. data/lib/cocoapods-binary-ht/cache/validator_non_dev_pods.rb +13 -0
  12. data/lib/cocoapods-binary-ht/cache/validator_with_podfile.rb +9 -0
  13. data/lib/cocoapods-binary-ht/dependencies_graph/dependencies_graph.rb +108 -0
  14. data/lib/cocoapods-binary-ht/dependencies_graph/graph_visualizer.rb +65 -0
  15. data/lib/cocoapods-binary-ht/diagnosis/base.rb +13 -0
  16. data/lib/cocoapods-binary-ht/diagnosis/diagnosis.rb +24 -0
  17. data/lib/cocoapods-binary-ht/diagnosis/integration.rb +23 -0
  18. data/lib/cocoapods-binary-ht/env.rb +32 -0
  19. data/lib/cocoapods-binary-ht/helper/benchmark_show.rb +11 -0
  20. data/lib/cocoapods-binary-ht/helper/checksum.rb +18 -0
  21. data/lib/cocoapods-binary-ht/helper/json.rb +37 -0
  22. data/lib/cocoapods-binary-ht/helper/lockfile.rb +90 -0
  23. data/lib/cocoapods-binary-ht/helper/path_utils.rb +8 -0
  24. data/lib/cocoapods-binary-ht/helper/podspec.rb +20 -0
  25. data/lib/cocoapods-binary-ht/hooks/post_install.rb +23 -0
  26. data/lib/cocoapods-binary-ht/hooks/pre_install.rb +121 -0
  27. data/lib/cocoapods-binary-ht/main.rb +21 -0
  28. data/lib/cocoapods-binary-ht/pod-binary/LICENSE.txt +22 -0
  29. data/lib/cocoapods-binary-ht/pod-binary/helper/build.rb +37 -0
  30. data/lib/cocoapods-binary-ht/pod-binary/helper/detected_prebuilt_pods/installer.rb +25 -0
  31. data/lib/cocoapods-binary-ht/pod-binary/helper/detected_prebuilt_pods/target_definition.rb +29 -0
  32. data/lib/cocoapods-binary-ht/pod-binary/helper/names.rb +27 -0
  33. data/lib/cocoapods-binary-ht/pod-binary/helper/podfile_options.rb +2 -0
  34. data/lib/cocoapods-binary-ht/pod-binary/helper/prebuild_sandbox.rb +71 -0
  35. data/lib/cocoapods-binary-ht/pod-binary/helper/sandbox.rb +9 -0
  36. data/lib/cocoapods-binary-ht/pod-binary/helper/target_checker.rb +42 -0
  37. data/lib/cocoapods-binary-ht/pod-binary/integration/alter_specs.rb +150 -0
  38. data/lib/cocoapods-binary-ht/pod-binary/integration/patch/embed_framework_script.rb +36 -0
  39. data/lib/cocoapods-binary-ht/pod-binary/integration/patch/resolve_dependencies.rb +20 -0
  40. data/lib/cocoapods-binary-ht/pod-binary/integration/patch/sandbox_analyzer_state.rb +29 -0
  41. data/lib/cocoapods-binary-ht/pod-binary/integration/patch/source_installation.rb +55 -0
  42. data/lib/cocoapods-binary-ht/pod-binary/integration/source_installer.rb +114 -0
  43. data/lib/cocoapods-binary-ht/pod-binary/integration/validation.rb +20 -0
  44. data/lib/cocoapods-binary-ht/pod-binary/integration.rb +11 -0
  45. data/lib/cocoapods-binary-ht/pod-binary/prebuild.rb +166 -0
  46. data/lib/cocoapods-binary-ht/pod-binary/prebuild_dsl.rb +10 -0
  47. data/lib/cocoapods-binary-ht/pod-binary/prebuild_hook.rb +10 -0
  48. data/lib/cocoapods-binary-ht/pod-rome/LICENSE.txt +22 -0
  49. data/lib/cocoapods-binary-ht/pod-rome/xcodebuild_command.rb +266 -0
  50. data/lib/cocoapods-binary-ht/pod-rome/xcodebuild_raw.rb +68 -0
  51. data/lib/cocoapods-binary-ht/prebuild_output/metadata.rb +63 -0
  52. data/lib/cocoapods-binary-ht/prebuild_output/output.rb +44 -0
  53. data/lib/cocoapods-binary-ht/state_store.rb +21 -0
  54. data/lib/cocoapods-binary-ht/ui.rb +9 -0
  55. data/lib/cocoapods_plugin.rb +5 -0
  56. data/lib/command/binary.rb +37 -0
  57. data/lib/command/config.rb +215 -0
  58. data/lib/command/executor/base.rb +37 -0
  59. data/lib/command/executor/fetcher.rb +67 -0
  60. data/lib/command/executor/prebuilder.rb +61 -0
  61. data/lib/command/executor/pusher.rb +35 -0
  62. data/lib/command/executor/visualizer.rb +23 -0
  63. data/lib/command/fetch.rb +22 -0
  64. data/lib/command/helper/zip.rb +20 -0
  65. data/lib/command/prebuild.rb +47 -0
  66. data/lib/command/push.rb +22 -0
  67. data/lib/command/visualize.rb +34 -0
  68. metadata +209 -0
@@ -0,0 +1,150 @@
1
+ module Pod
2
+ class Installer
3
+ def alter_specs_for_prebuilt_pods
4
+ cache = []
5
+
6
+ @original_specs = analysis_result.specifications
7
+ .map { |spec| [spec.name, Pod::Specification.from_file(spec.defined_in_file)] }
8
+ .to_h
9
+
10
+ analysis_result.specifications
11
+ .select { |spec| should_integrate_prebuilt_pod?(spec.root.name) }
12
+ .group_by(&:root)
13
+ .each do |_, specs|
14
+ first_subspec_or_self = specs.find(&:subspec?) || specs[0]
15
+ specs.each do |spec|
16
+ alterations = {
17
+ :source_files => true,
18
+ :resources => true,
19
+ :license => true,
20
+ :vendored_framework => spec == first_subspec_or_self
21
+ }
22
+ alter_spec(spec, alterations, cache)
23
+ end
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def metadata_of_target(name)
30
+ @metadata_by_target ||= {}
31
+ metadata = @metadata_by_target[name]
32
+ return metadata unless metadata.nil?
33
+
34
+ framework_path = sandbox.prebuild_sandbox.framework_folder_path_for_target_name(name)
35
+ metadata = PodPrebuild::Metadata.in_dir(framework_path)
36
+ @metadata_by_target[name] = metadata
37
+ metadata
38
+ end
39
+
40
+ def alter_spec(spec, alterations, cache)
41
+ metadata = metadata_of_target(spec.root.name)
42
+ targets = Pod.fast_get_targets_for_pod_name(spec.root.name, pod_targets, cache)
43
+ platforms = targets.map { |target| target.platform.name.to_s }.uniq
44
+
45
+ if alterations[:vendored_framework]
46
+ targets.each do |target|
47
+ # Use the prebuilt frameworks as vendered frameworks.
48
+ # The framework_file_path rule is decided in `install_for_prebuild`,
49
+ # as to compitable with older version and be less wordy.
50
+ framework_file_path = target.framework_name
51
+ framework_file_path = target.name + "/" + framework_file_path if targets.count > 1
52
+ framework_file_path = PodPrebuild.config.prebuilt_path(path: framework_file_path)
53
+ add_vendered_framework(spec, target.platform.name.to_s, framework_file_path)
54
+ end
55
+ end
56
+
57
+ empty_source_files(spec, platforms) if alterations[:source_files]
58
+ if alterations[:resources]
59
+ if metadata.static_framework?
60
+ tweak_resources_for_xib(spec, platforms)
61
+ tweak_resources_for_resource_bundles(spec, platforms)
62
+ else
63
+ # For dynamic frameworks, resources & resource bundles are already bundled inside the framework.
64
+ # We need to empty resources & resource bundles. Otherwise, there will be duplications
65
+ # (resources locating in both app bundle and framework bundle)
66
+ empty_resources(spec, platforms)
67
+ end
68
+ end
69
+ empty_liscence(spec) if alterations[:license]
70
+ end
71
+
72
+ def empty_resources(spec, platforms)
73
+ spec.attributes_hash["resources"] = nil
74
+ spec.attributes_hash["resource_bundles"] = nil
75
+ platforms.each do |platform|
76
+ next if spec.attributes_hash[platform].nil?
77
+
78
+ spec.attributes_hash[platform]["resources"] = nil
79
+ spec.attributes_hash[platform]["resource_bundles"] = nil
80
+ end
81
+ end
82
+
83
+ def tweak_resources_for_xib(spec, platforms)
84
+ # This is a workaround for prebuilt static framework that has `*.xib` files in the resources
85
+ # (declared by `spec.resources = ...`)
86
+ # ---------------------------------------------------------------
87
+ # In the prebuild stage, a XIB file is compiled as a NIB file in the framework.
88
+ # In the integration stage, this file is added to the script `Pods-<Target>-resources.sh`:
89
+ # - If it's a XIB, it's installed to the target bundle by `ibtool`
90
+ # - If it's a NIB, it's copied directly to the target bundle
91
+ # Since the one embedded in the prebuilt framework is a NIB (already compiled)
92
+ # --> We need to alter the spec so that this file will be copied to the target bundle
93
+ change_xib_to_nib = ->(path) { path.sub(".xib", ".nib") }
94
+ update_resources = lambda do |resources|
95
+ if resources.is_a?(String)
96
+ change_xib_to_nib.call(resources)
97
+ elsif resources.is_a?(Array)
98
+ resources.map { |item| change_xib_to_nib.call(item) }
99
+ end
100
+ end
101
+ spec.attributes_hash["resources"] = update_resources.call(spec.attributes_hash["resources"])
102
+ platforms.each do |platform|
103
+ next if spec.attributes_hash[platform].nil?
104
+
105
+ platform_resources = spec.attributes_hash[platform]["resources"]
106
+ spec.attributes_hash[platform]["resources"] = update_resources.call(platform_resources)
107
+ end
108
+ end
109
+
110
+ def tweak_resources_for_resource_bundles(spec, platforms)
111
+ add_resource_bundles_to_resources = lambda do |attributes|
112
+ return if attributes.nil?
113
+
114
+ resource_bundles = attributes["resource_bundles"] || {}
115
+ resource_bundle_names = resource_bundles.keys
116
+ attributes["resource_bundles"] = nil
117
+ attributes["resources"] ||= []
118
+ attributes["resources"] = [attributes["resources"]] if attributes["resources"].is_a?(String)
119
+ attributes["resources"] += resource_bundle_names.map do |name|
120
+ PodPrebuild.config.prebuilt_path(path: "#{name}.bundle")
121
+ end
122
+ end
123
+
124
+ add_resource_bundles_to_resources.call(spec.attributes_hash)
125
+ platforms.each do |platform|
126
+ add_resource_bundles_to_resources.call(spec.attributes_hash[platform])
127
+ end
128
+ end
129
+
130
+ def add_vendered_framework(spec, platform, added_framework_file_path)
131
+ spec.attributes_hash[platform] = {} if spec.attributes_hash[platform].nil?
132
+ vendored_frameworks = spec.attributes_hash[platform]["vendored_frameworks"] || []
133
+ vendored_frameworks = [vendored_frameworks] if vendored_frameworks.is_a?(String)
134
+ vendored_frameworks += [added_framework_file_path]
135
+ spec.attributes_hash[platform]["vendored_frameworks"] = vendored_frameworks
136
+ end
137
+
138
+ def empty_source_files(spec, platforms)
139
+ spec.attributes_hash["source_files"] = []
140
+ platforms.each do |platform|
141
+ spec.attributes_hash[platform]["source_files"] = [] unless spec.attributes_hash[platform].nil?
142
+ end
143
+ end
144
+
145
+ def empty_liscence(spec)
146
+ spec.attributes_hash["license"] = {}
147
+ spec.root.attributes_hash["license"] = {}
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,36 @@
1
+ # A fix in embeded frameworks script.
2
+ #
3
+ # The framework file in pod target folder is a symblink. The EmbedFrameworksScript use `readlink`
4
+ # to read the read path. As the symlink is a relative symlink, readlink cannot handle it well. So
5
+ # we override the `readlink` to a fixed version.
6
+ #
7
+ module Pod
8
+ module Generator
9
+ class EmbedFrameworksScript
10
+ old_method = instance_method(:script)
11
+ define_method(:script) do
12
+ script = old_method.bind(self).call
13
+ patch = <<-SH.strip_heredoc
14
+ #!/bin/sh
15
+ # ---- this is added by cocoapods-binary ---
16
+ # Readlink cannot handle relative symlink well, so we override it to a new one
17
+ # If the path isn't an absolute path, we add a realtive prefix.
18
+ old_read_link=`which readlink`
19
+ readlink () {
20
+ path=`$old_read_link "$1"`;
21
+ if [ $(echo "$path" | cut -c 1-1) = '/' ]; then
22
+ echo $path;
23
+ else
24
+ echo "`dirname $1`/$path";
25
+ fi
26
+ }
27
+ # ---
28
+ SH
29
+
30
+ # patch the rsync for copy dSYM symlink
31
+ script = script.gsub "rsync --delete", "rsync --copy-links --delete"
32
+ patch + script
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ # Let cocoapods use the prebuild framework files in install process.
2
+ #
3
+ # the code only effect the second pod install process.
4
+ #
5
+ module Pod
6
+ class Installer
7
+ # Modify specification to use only the prebuild framework after analyzing
8
+ original_resolve_dependencies = instance_method(:resolve_dependencies)
9
+ define_method(:resolve_dependencies) do
10
+ original_resolve_dependencies.bind(self).call
11
+
12
+ # check the pods
13
+ # Although we have did it in prebuild stage, it's not sufficient.
14
+ # Same pod may appear in another target in form of source code.
15
+ # Prebuild.check_one_pod_should_have_only_one_target(prebuilt_pod_targets)
16
+ validate_every_pod_only_have_one_form
17
+ alter_specs_for_prebuilt_pods
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ module Pod
2
+ class Installer
3
+ class Analyzer
4
+ class SandboxAnalyzer
5
+ original_analyze = instance_method(:analyze)
6
+ define_method(:analyze) do
7
+ state = original_analyze.bind(self).call
8
+ state = alter_state(state)
9
+ state
10
+ end
11
+
12
+ private
13
+
14
+ def alter_state(state)
15
+ return state if PodPrebuild.config.tracked_prebuilt_pod_names.empty?
16
+
17
+ prebuilt = PodPrebuild.config.tracked_prebuilt_pod_names
18
+ Pod::UI.message "Alter sandbox state: treat prebuilt frameworks as added: #{prebuilt.to_a}"
19
+ SpecsState.new(
20
+ :added => (state.added + prebuilt).uniq,
21
+ :changed => state.changed - prebuilt,
22
+ :removed => state.deleted - prebuilt,
23
+ :unchanged => state.unchanged - prebuilt
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,55 @@
1
+ require_relative "../source_installer"
2
+
3
+ module Pod
4
+ class Installer
5
+ # Override the download step to skip download and prepare file in target folder
6
+ alias original_create_pod_installer create_pod_installer
7
+ def create_pod_installer(name)
8
+ if should_integrate_prebuilt_pod?(name)
9
+ create_prebuilt_source_installer(name)
10
+ else
11
+ create_normal_source_installer(name)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def create_normal_source_installer(name)
18
+ original_create_pod_installer(name)
19
+ end
20
+
21
+ def original_specs_by_platform(name)
22
+ specs_for_pod(name).map do |platform, specs|
23
+ specs_ = specs.map { |spec| @original_specs[spec.name] }
24
+ [platform, specs_]
25
+ end.to_h
26
+ end
27
+
28
+ def create_prebuilt_source_installer(name)
29
+ # A source installer needs to install with the original spec (instead of the altered spec).
30
+ # Otherwise, the cache will be corrupted because CocoaPods packs necessary dirs/files from temp dir
31
+ # to the cache dir based on the spec.
32
+ source_installer = PodSourceInstaller.new(sandbox, podfile, original_specs_by_platform(name))
33
+ pod_installer = PrebuiltSourceInstaller.new(
34
+ sandbox,
35
+ podfile,
36
+ specs_for_pod(name),
37
+ source_installer: source_installer
38
+ )
39
+ pod_installers << pod_installer
40
+ pod_installer
41
+ end
42
+
43
+ def should_integrate_prebuilt_pod?(name)
44
+ if PodPrebuild.config.prebuild_job? && PodPrebuild.config.targets_to_prebuild_from_cli.empty?
45
+ # In a prebuild job, at the integration stage, all prebuilt frameworks should be
46
+ # ready for integration regardless of whether there was any cache miss or not.
47
+ # Those that are missed were prebuilt in the prebuild stage.
48
+ PodPrebuild.state.cache_validation.include?(name)
49
+ else
50
+ prebuilt = PodPrebuild.state.cache_validation.hit + PodPrebuild.config.targets_to_prebuild_from_cli
51
+ prebuilt.include?(name)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,114 @@
1
+ module Pod
2
+ class Installer
3
+ class PrebuiltSourceInstaller < PodSourceInstaller
4
+ def initialize(*args, **kwargs)
5
+ @source_installer = kwargs.delete(:source_installer)
6
+ super(*args, **kwargs)
7
+ end
8
+
9
+ def prebuild_sandbox
10
+ @prebuild_sandbox ||= Pod::PrebuildSandbox.from_standard_sandbox(sandbox)
11
+ end
12
+
13
+ def install!
14
+ @source_installer.install!
15
+ install_prebuilt_framework!
16
+ end
17
+
18
+ private
19
+
20
+ def install_prebuilt_framework!
21
+ return if !PodPrebuild.config.dev_pods_enabled? && sandbox.local?(name)
22
+
23
+ # make a symlink to target folder
24
+ # TODO (bang): Unify to 1 sandbox to optimize and avoid inconsistency
25
+ # if spec used in multiple platforms, it may return multiple paths
26
+ target_names = prebuild_sandbox.existed_target_names_for_pod_name(name)
27
+ target_names.each do |name|
28
+ real_file_folder = prebuild_sandbox.framework_folder_path_for_target_name(name)
29
+
30
+ # If have only one platform, just place int the root folder of this pod.
31
+ # If have multiple paths, we use a sperated folder to store different
32
+ # platform frameworks. e.g. AFNetworking/AFNetworking-iOS/AFNetworking.framework
33
+ target_folder = sandbox.pod_dir(self.name)
34
+ target_folder += real_file_folder.basename if target_names.count > 1
35
+ target_folder += PodPrebuild.config.prebuilt_path
36
+ target_folder.rmtree if target_folder.exist?
37
+ target_folder.mkpath
38
+
39
+ walk(real_file_folder) do |child|
40
+ source = child
41
+ # only make symlink to file and `.framework` folder
42
+ if child.directory? && [".framework", ".xcframework", ".dSYM"].include?(child.extname)
43
+ if [".framework", ".xcframework"].include?(child.extname)
44
+ mirror_with_symlink(source, real_file_folder, target_folder)
45
+ end
46
+ # Ignore dsym here to avoid cocoapods from adding install_dsym to buildphase-script
47
+ # That can cause duplicated output files error in Xcode 11 (warning in Xcode 10)
48
+ # We need more setup to support local debuging with prebuilt dSYM
49
+ next false # Don't go deeper
50
+ elsif child.file?
51
+ mirror_with_symlink(source, real_file_folder, target_folder)
52
+ next true
53
+ else
54
+ next true
55
+ end
56
+ end
57
+
58
+ # symbol link copy resource for static framework
59
+ metadata = PodPrebuild::Metadata.in_dir(real_file_folder)
60
+ next unless metadata.static_framework?
61
+
62
+ metadata.resources.each do |path|
63
+ target_file_path = Pathname(path)
64
+ .sub("${PODS_ROOT}", sandbox.root.to_path)
65
+ .sub("${PODS_CONFIGURATION_BUILD_DIR}", sandbox.root.to_path)
66
+ next if target_file_path.exist?
67
+
68
+ real_file_path = real_file_folder + metadata.framework_name + File.basename(path)
69
+
70
+ # TODO (thuyen): Fix https://github.com/pandaleecn/cocoapods-binary-ht/issues/45
71
+
72
+ case File.extname(path)
73
+ when ".xib"
74
+ # https://github.com/pandaleecn/cocoapods-binary-ht/issues/7
75
+ # When ".xib" files are compiled in a framework, it becomes ".nib" files
76
+ # --> We need to correct the path extension
77
+ real_file_path = real_file_path.sub_ext(".nib")
78
+ target_file_path = target_file_path.sub(".xib", ".nib")
79
+ when ".bundle"
80
+ next if metadata.resource_bundles.include?(File.basename(path))
81
+
82
+ real_file_path = real_file_folder + File.basename(path) unless real_file_path.exist?
83
+ end
84
+ make_link(real_file_path, target_file_path)
85
+ end
86
+ end
87
+ end
88
+
89
+ def walk(path, &action)
90
+ return unless path.exist?
91
+
92
+ path.children.each do |child|
93
+ result = action.call(child, &action)
94
+ if child.directory?
95
+ walk(child, &action) if result
96
+ end
97
+ end
98
+ end
99
+
100
+ def make_link(source, target)
101
+ source = Pathname.new(source)
102
+ target = Pathname.new(target)
103
+ target.rmtree if target.exist?
104
+ target.parent.mkpath unless target.parent.exist?
105
+ relative_source = source.relative_path_from(target.parent)
106
+ FileUtils.ln_sf(relative_source, target)
107
+ end
108
+
109
+ def mirror_with_symlink(source, basefolder, target_folder)
110
+ make_link(source, target_folder + source.relative_path_from(basefolder))
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,20 @@
1
+ module Pod
2
+ class Installer
3
+ def validate_every_pod_only_have_one_form
4
+ multi_targets_pods = pod_targets
5
+ .group_by(&:pod_name)
6
+ .select do |_, targets|
7
+ is_multi_targets = targets.map { |t| t.platform.name }.uniq.count > 1
8
+ is_multi_forms = targets.map { |t| prebuilt_pod_targets.include?(t) }.uniq.count > 1
9
+ is_multi_targets && is_multi_forms
10
+ end
11
+ return if multi_targets_pods.empty?
12
+
13
+ warnings = "One pod can only be prebuilt or not prebuilt. These pod have different forms in multiple targets:\n"
14
+ warnings += multi_targets_pods
15
+ .map { |name, targets| " #{name}: #{targets.map { |t| t.platform.name }}" }
16
+ .join("\n")
17
+ raise Informative, warnings
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ require_relative "helper/podfile_options"
2
+ require_relative "helper/prebuild_sandbox"
3
+ require_relative "helper/sandbox"
4
+ require_relative "helper/names"
5
+ require_relative "helper/target_checker"
6
+ require_relative "integration/alter_specs"
7
+ require_relative "integration/validation"
8
+ require_relative "integration/patch/embed_framework_script"
9
+ require_relative "integration/patch/sandbox_analyzer_state"
10
+ require_relative "integration/patch/resolve_dependencies"
11
+ require_relative "integration/patch/source_installation"
@@ -0,0 +1,166 @@
1
+ require "fileutils"
2
+ require_relative "../prebuild_output/output"
3
+ require_relative "../helper/lockfile"
4
+ require_relative "helper/target_checker"
5
+ require_relative "helper/build"
6
+
7
+ module Pod
8
+ class PrebuildInstaller < Installer # rubocop:disable Metrics/ClassLength
9
+ attr_reader :lockfile_wrapper
10
+
11
+ def initialize(options)
12
+ super(options[:sandbox], options[:podfile], options[:lockfile])
13
+ @cache_validation = options[:cache_validation]
14
+ @lockfile_wrapper = lockfile && PodPrebuild::Lockfile.new(lockfile)
15
+ end
16
+
17
+ def installation_options
18
+ # Skip integrating user targets for prebuild Pods project.
19
+ @installation_options ||= Pod::Installer::InstallationOptions.new(
20
+ super.to_h.merge(:integrate_targets => false)
21
+ )
22
+ end
23
+
24
+ def run_code_gen!(targets)
25
+ return if PodPrebuild.config.prebuild_code_gen.nil?
26
+
27
+ Pod::UI.title("Running code generation...") do
28
+ PodPrebuild.config.prebuild_code_gen.call(self, targets)
29
+ end
30
+ end
31
+
32
+ def prebuild_output
33
+ @prebuild_output ||= PodPrebuild::Output.new(sandbox)
34
+ end
35
+
36
+ def targets_to_prebuild
37
+ to_build = PodPrebuild.config.targets_to_prebuild_from_cli
38
+ if to_build.empty?
39
+ to_build = PodPrebuild.config.prebuild_all_pods? ? @cache_validation.all : @cache_validation.missed
40
+ end
41
+ pod_targets.select { |target| to_build.include?(target.name) }
42
+ end
43
+
44
+ def prebuild_frameworks!
45
+ existed_framework_folder = sandbox.generate_framework_path
46
+ sandbox_path = sandbox.root
47
+ targets = targets_to_prebuild
48
+ Pod::UI.puts "Prebuild frameworks (total #{targets.count}): #{targets.map(&:name)}".magenta
49
+
50
+ run_code_gen!(targets)
51
+
52
+ PodPrebuild.remove_build_dir(sandbox_path)
53
+ PodPrebuild.build(
54
+ sandbox: sandbox_path,
55
+ targets: targets,
56
+ configuration: PodPrebuild.config.prebuild_config,
57
+ output_path: sandbox.generate_framework_path,
58
+ bitcode_enabled: PodPrebuild.config.bitcode_enabled?,
59
+ device_build_enabled: PodPrebuild.config.device_build_enabled?,
60
+ disable_dsym: PodPrebuild.config.disable_dsym?,
61
+ log_path: PodPrebuild.config.xcodebuild_log_path,
62
+ args: PodPrebuild.config.build_args
63
+ )
64
+ PodPrebuild.remove_build_dir(sandbox_path)
65
+
66
+ targets.each do |target|
67
+ collect_metadata(target, sandbox.framework_folder_path_for_target_name(target.name))
68
+ end
69
+
70
+ # copy vendored libraries and frameworks
71
+ targets.each do |target|
72
+ root_path = sandbox.pod_dir(target.name)
73
+ target_folder = sandbox.framework_folder_path_for_target_name(target.name)
74
+
75
+ # If target shouldn't build, we copy all the original files
76
+ # This is for target with only .a and .h files
77
+ unless target.should_build?
78
+ FileUtils.cp_r(root_path, target_folder, :remove_destination => true)
79
+ next
80
+ end
81
+
82
+ target.spec_consumers.each do |consumer|
83
+ file_accessor = Sandbox::FileAccessor.new(root_path, consumer)
84
+ lib_paths = file_accessor.vendored_frameworks || []
85
+ lib_paths += file_accessor.vendored_libraries
86
+ # @TODO dSYM files
87
+ lib_paths.each do |lib_path|
88
+ relative = lib_path.relative_path_from(root_path)
89
+ destination = target_folder + relative
90
+ destination.dirname.mkpath unless destination.dirname.exist?
91
+ FileUtils.cp_r(lib_path, destination, :remove_destination => true)
92
+ end
93
+ end
94
+ end
95
+
96
+ # save the pod_name for prebuild framwork in sandbox
97
+ targets.each do |target|
98
+ sandbox.save_pod_name_for_target target
99
+ end
100
+
101
+ # Remove useless files
102
+ # remove useless pods
103
+ all_needed_names = pod_targets.map(&:name).uniq
104
+ useless_target_names = sandbox.exsited_framework_target_names.reject do |name|
105
+ all_needed_names.include? name
106
+ end
107
+ useless_target_names.each do |name|
108
+ Pod::UI.message "Remove: #{name}"
109
+ path = sandbox.framework_folder_path_for_target_name(name)
110
+ path.rmtree if path.exist?
111
+ end
112
+
113
+ if PodPrebuild.config.dont_remove_source_code?
114
+ # just remove the tmp files
115
+ path = sandbox.root + "Manifest.lock.tmp"
116
+ path.rmtree if path.exist?
117
+ else
118
+ # only keep manifest.lock and framework folder in _Prebuild
119
+ to_remain_files = ["Manifest.lock", File.basename(existed_framework_folder)]
120
+ to_delete_files = sandbox_path.children.reject { |file| to_remain_files.include?(File.basename(file)) }
121
+ to_delete_files.each { |file| file.rmtree if file.exist? }
122
+ end
123
+
124
+ prebuild_output.write_delta_file(
125
+ updated: targets.map { |target| target.label.to_s },
126
+ deleted: useless_target_names
127
+ )
128
+ end
129
+
130
+ def clean_delta_file
131
+ prebuild_output.clean_delta_file
132
+ end
133
+
134
+ def collect_metadata(target, output_path)
135
+ metadata = PodPrebuild::Metadata.in_dir(output_path)
136
+ metadata.framework_name = target.framework_name
137
+ metadata.static_framework = target.static_framework?
138
+ resource_paths = target.resource_paths
139
+ metadata.resources = resource_paths.is_a?(Hash) ? resource_paths.values.flatten : resource_paths
140
+ metadata.resource_bundles = target
141
+ .file_accessors
142
+ .map { |f| f.resource_bundles.keys }
143
+ .flatten
144
+ .map { |name| "#{name}.bundle" }
145
+ metadata.build_settings = pods_project.targets
146
+ .detect { |native_target| native_target.name == target.name }
147
+ .build_configurations
148
+ .detect { |config| config.name == PodPrebuild.config.prebuild_config }
149
+ .build_settings
150
+ metadata.source_hash = @lockfile_wrapper && @lockfile_wrapper.dev_pod_hash(target.name)
151
+
152
+ # Store root path for code-coverage support later
153
+ # TODO: update driver code-coverage logic to use path stored here
154
+ project_root = PathUtils.remove_last_path_component(@sandbox.standard_sanbox_path.to_s)
155
+ metadata.project_root = project_root
156
+ metadata.save!
157
+ end
158
+
159
+ # patch the post install hook
160
+ old_method2 = instance_method(:run_plugins_post_install_hooks)
161
+ define_method(:run_plugins_post_install_hooks) do
162
+ old_method2.bind(self).call
163
+ prebuild_frameworks! if PodPrebuild::Env.prebuild_stage?
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,10 @@
1
+ module Pod
2
+ class Podfile
3
+ module DSL
4
+ def config_cocoapods_binary_cache(options)
5
+ PodPrebuild.config.dsl_config = options
6
+ PodPrebuild.config.validate_dsl_config
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require_relative "helper/podfile_options"
2
+ require_relative "helper/prebuild_sandbox"
3
+
4
+ Pod::HooksManager.register("cocoapods-binary-ht", :pre_install) do |installer_context|
5
+ PodPrebuild::PreInstallHook.new(installer_context).run
6
+ end
7
+
8
+ Pod::HooksManager.register("cocoapods-binary-ht", :post_install) do |installer_context|
9
+ PodPrebuild::PostInstallHook.new(installer_context).run
10
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Boris Bügling <boris@icculus.org>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.