cocoapods-binary-ht 1.0.0

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 (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.