cocoapods-binary-cache 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cocoapods-binary-cache.rb +4 -0
  3. data/lib/cocoapods-binary-cache/cache/all.rb +9 -0
  4. data/lib/cocoapods-binary-cache/cache/validation_result.rb +69 -0
  5. data/lib/cocoapods-binary-cache/cache/validator.rb +21 -0
  6. data/lib/cocoapods-binary-cache/cache/validator_accumulated.rb +4 -0
  7. data/lib/cocoapods-binary-cache/cache/validator_base.rb +92 -0
  8. data/lib/cocoapods-binary-cache/cache/validator_dependencies_graph.rb +20 -0
  9. data/lib/cocoapods-binary-cache/cache/validator_dev_pods.rb +22 -0
  10. data/lib/cocoapods-binary-cache/cache/validator_exclusion.rb +14 -0
  11. data/lib/cocoapods-binary-cache/cache/validator_non_dev_pods.rb +13 -0
  12. data/lib/cocoapods-binary-cache/cache/validator_with_podfile.rb +9 -0
  13. data/lib/cocoapods-binary-cache/dependencies_graph/dependencies_graph.rb +95 -0
  14. data/lib/cocoapods-binary-cache/dependencies_graph/graph_visualizer.rb +74 -0
  15. data/lib/cocoapods-binary-cache/gem_version.rb +6 -0
  16. data/lib/cocoapods-binary-cache/helper/benchmark_show.rb +11 -0
  17. data/lib/cocoapods-binary-cache/helper/checksum.rb +12 -0
  18. data/lib/cocoapods-binary-cache/helper/json.rb +37 -0
  19. data/lib/cocoapods-binary-cache/helper/lockfile.rb +67 -0
  20. data/lib/cocoapods-binary-cache/helper/path_utils.rb +8 -0
  21. data/lib/cocoapods-binary-cache/helper/podspec.rb +17 -0
  22. data/lib/cocoapods-binary-cache/hooks/post_install.rb +16 -0
  23. data/lib/cocoapods-binary-cache/hooks/pre_install.rb +141 -0
  24. data/lib/cocoapods-binary-cache/main.rb +21 -0
  25. data/lib/cocoapods-binary-cache/pod-binary/LICENSE.txt +22 -0
  26. data/lib/cocoapods-binary-cache/pod-binary/helper/detected_prebuilt_pods/installer.rb +25 -0
  27. data/lib/cocoapods-binary-cache/pod-binary/helper/detected_prebuilt_pods/target_definition.rb +36 -0
  28. data/lib/cocoapods-binary-cache/pod-binary/helper/feature_switches.rb +90 -0
  29. data/lib/cocoapods-binary-cache/pod-binary/helper/names.rb +36 -0
  30. data/lib/cocoapods-binary-cache/pod-binary/helper/passer.rb +25 -0
  31. data/lib/cocoapods-binary-cache/pod-binary/helper/podfile_options.rb +2 -0
  32. data/lib/cocoapods-binary-cache/pod-binary/helper/prebuild_sandbox.rb +71 -0
  33. data/lib/cocoapods-binary-cache/pod-binary/helper/target_checker.rb +45 -0
  34. data/lib/cocoapods-binary-cache/pod-binary/integration.rb +12 -0
  35. data/lib/cocoapods-binary-cache/pod-binary/integration/alter_specs.rb +93 -0
  36. data/lib/cocoapods-binary-cache/pod-binary/integration/patch/embed_framework_script.rb +36 -0
  37. data/lib/cocoapods-binary-cache/pod-binary/integration/patch/resolve_dependencies.rb +23 -0
  38. data/lib/cocoapods-binary-cache/pod-binary/integration/patch/source_installation.rb +28 -0
  39. data/lib/cocoapods-binary-cache/pod-binary/integration/remove_target_files.rb +29 -0
  40. data/lib/cocoapods-binary-cache/pod-binary/integration/source_installer.rb +111 -0
  41. data/lib/cocoapods-binary-cache/pod-binary/integration/validation.rb +20 -0
  42. data/lib/cocoapods-binary-cache/pod-binary/prebuild.rb +224 -0
  43. data/lib/cocoapods-binary-cache/pod-binary/prebuild_dsl.rb +69 -0
  44. data/lib/cocoapods-binary-cache/pod-binary/prebuild_hook.rb +11 -0
  45. data/lib/cocoapods-binary-cache/pod-binary/tool/tool.rb +12 -0
  46. data/lib/cocoapods-binary-cache/pod-rome/LICENSE.txt +22 -0
  47. data/lib/cocoapods-binary-cache/pod-rome/build_framework.rb +247 -0
  48. data/lib/cocoapods-binary-cache/prebuild_cache.rb +49 -0
  49. data/lib/cocoapods-binary-cache/prebuild_output/metadata.rb +47 -0
  50. data/lib/cocoapods-binary-cache/prebuild_output/output.rb +71 -0
  51. data/lib/cocoapods-binary-cache/scheme_editor.rb +35 -0
  52. data/lib/cocoapods-binary-cache/state_store.rb +11 -0
  53. data/lib/cocoapods-binary-cache/ui.rb +9 -0
  54. data/lib/cocoapods_plugin.rb +5 -0
  55. data/lib/command/binary.rb +18 -0
  56. data/lib/command/config.rb +31 -0
  57. data/lib/command/executor/base.rb +20 -0
  58. data/lib/command/executor/fetcher.rb +44 -0
  59. data/lib/command/executor/prebuilder.rb +58 -0
  60. data/lib/command/executor/pusher.rb +19 -0
  61. data/lib/command/executor/visualizer.rb +20 -0
  62. data/lib/command/fetch.rb +23 -0
  63. data/lib/command/helper/zip.rb +20 -0
  64. data/lib/command/prebuild.rb +29 -0
  65. data/lib/command/visualize.rb +30 -0
  66. metadata +193 -0
@@ -0,0 +1,49 @@
1
+ # Copyright 2019 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved.
2
+ # Use of this source code is governed by an MIT-style license that can be found in the LICENSE file
3
+
4
+ require 'json'
5
+ require 'cocoapods'
6
+ require_relative "helper/checksum"
7
+
8
+ class PodCacheValidator
9
+
10
+ # Cache miss/hit checking for development pods
11
+ # Return 2 Hashes for cache miss and cache hit libraries
12
+ def self.verify_devpod_checksum(sandbox_root, generated_framework_path, lock_file)
13
+ devpod_path = "#{sandbox_root}/devpod/"
14
+ target_path = generated_framework_path
15
+ Pod::UI.puts "verify_devpod_checksum: #{devpod_path}"
16
+ external_sources = lock_file.to_hash["EXTERNAL SOURCES"]
17
+ unless File.directory?(target_path)
18
+ FileUtils.mkdir_p(target_path)
19
+ end
20
+ missing_pods_dic = Hash[]
21
+ dev_pods_count = 0
22
+ cachehit_pods_dic = Hash[]
23
+ if !external_sources
24
+ Pod::UI.puts 'No development pods!'
25
+ return missing_pods_dic, cachehit_pods
26
+ end
27
+ external_sources.each do |name, attribs|
28
+ if attribs.class == Hash
29
+ path = attribs[:path]
30
+ if path
31
+ hash = FolderChecksum.checksum(path)
32
+ dev_pods_count += 1
33
+ cached_path = "#{devpod_path}#{name}_#{hash}"
34
+ if !Dir.exists?(cached_path)
35
+ missing_pods_dic[name] = hash
36
+ else
37
+ cachehit_pods_dic[name] = hash
38
+ target_dir = "#{target_path}/#{name}"
39
+ FileUtils.rm_r(target_dir, :force => true)
40
+ FileUtils.cp_r(cached_path, target_dir)
41
+ end
42
+ end
43
+ else
44
+ Pod::UI.puts "Error, wrong type: #{attribs}"
45
+ end
46
+ end
47
+ return missing_pods_dic, cachehit_pods_dic
48
+ end
49
+ end
@@ -0,0 +1,47 @@
1
+ module PodPrebuild
2
+ class Metadata < JSONFile
3
+ def self.in_dir(dir)
4
+ PodPrebuild::Metadata.new(dir + "metadata.json")
5
+ end
6
+
7
+ def resources
8
+ @data["resources"] || []
9
+ end
10
+
11
+ def resources=(value)
12
+ @data["resources"] = value
13
+ end
14
+
15
+ def framework_name
16
+ @data["framework_name"]
17
+ end
18
+
19
+ def framework_name=(value)
20
+ @data["framework_name"] = value
21
+ end
22
+
23
+ def static_framework?
24
+ @data["static_framework"] || false
25
+ end
26
+
27
+ def static_framework=(value)
28
+ @data["static_framework"] = value
29
+ end
30
+
31
+ def resource_bundles
32
+ @data["resource_bundles"] || []
33
+ end
34
+
35
+ def resource_bundles=(value)
36
+ @data["resource_bundles"] = value
37
+ end
38
+
39
+ def build_settings
40
+ @data["build_settings"] || {}
41
+ end
42
+
43
+ def build_settings=(value)
44
+ @data["build_settings"] = value
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,71 @@
1
+ # Copyright 2019 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved.
2
+ # Use of this source code is governed by an MIT-style license that can be found in the LICENSE file
3
+
4
+ module PodPrebuild
5
+ class Output
6
+ def initialize(prebuild_sandbox)
7
+ @sandbox = prebuild_sandbox
8
+ end
9
+
10
+ def delta_dir
11
+ @delta_dir ||= File.expand_path("#{@sandbox.root}/../_Prebuild_delta")
12
+ end
13
+
14
+ def delta_file_path
15
+ # TODO (thuyen): Unify this path with PodPrebuild::Config#delta_file_path
16
+ "#{delta_dir}/changes.json"
17
+ end
18
+
19
+ def clean_delta_file
20
+ puts "Clean delta file: #{delta_file_path}"
21
+ FileUtils.rm_rf(delta_file_path)
22
+ end
23
+
24
+ def create_dir_if_needed(dir)
25
+ FileUtils.mkdir_p dir unless File.directory?(dir)
26
+ end
27
+
28
+ # Input 2 arrays of library names
29
+ def write_delta_file(updated, deleted)
30
+ if updated.empty? && deleted.empty?
31
+ Pod::UI.puts "No changes in prebuild"
32
+ return
33
+ end
34
+
35
+ Pod::UI.puts "Write prebuild changes to: #{delta_file_path}"
36
+ create_dir_if_needed(delta_dir)
37
+ changes = PodPrebuild::JSONFile.new(delta_file_path)
38
+ changes["updated"] = updated
39
+ changes["deleted"] = deleted
40
+ changes.save!
41
+ end
42
+
43
+ def process_prebuilt_dev_pods
44
+ devpod_output_path = "#{delta_dir}/devpod_prebuild_output/"
45
+ create_dir_if_needed(devpod_output_path)
46
+ Pod::UI.puts "Copy prebuilt devpod frameworks to output dir: #{devpod_output_path}"
47
+
48
+ # Inject project path (where the framework is built) to support generating code coverage later
49
+ project_root = PathUtils.remove_last_path_component(@sandbox.standard_sanbox_path.to_s)
50
+ template_file_path = devpod_output_path + "prebuilt_map"
51
+ File.open(template_file_path, "w") do |file|
52
+ file.write(project_root)
53
+ end
54
+
55
+ # FIXME (thuyen): Revise usage of cache_miss_dev_pods_dic
56
+ # The behavior of processing outputs of dev pods and non-dev pods should be very SIMILAR
57
+ cache_miss_dev_pods_dic = {}
58
+
59
+ cache_miss_dev_pods_dic.each do |name, hash|
60
+ Pod::UI.puts "Output dev pod lib: #{name} hash: #{hash}"
61
+ built_lib_path = @sandbox.framework_folder_path_for_target_name(name)
62
+ next unless File.directory?(built_lib_path)
63
+
64
+ FileUtils.cp(template_file_path, "#{built_lib_path}/#{name}.framework")
65
+ target_dir = "#{devpod_output_path}#{name}_#{hash}"
66
+ Pod::UI.puts "From: #{built_lib_path} -> #{target_dir}"
67
+ FileUtils.cp_r(built_lib_path, target_dir)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,35 @@
1
+ # Copyright 2019 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved.
2
+ # Use of this source code is governed by an MIT-style license that can be found in the LICENSE file
3
+
4
+ require 'rexml/document'
5
+
6
+ class SchemeEditor
7
+ def self.edit_to_support_code_coverage(sandbox)
8
+ pod_proj_path = sandbox.project_path
9
+ puts "Modify schemes of pod project to support code coverage of prebuilt local pod: #{pod_proj_path}"
10
+ scheme_files = Dir["#{pod_proj_path}/**/*.xcscheme"]
11
+ scheme_files.each do |file_path|
12
+ scheme_name = File.basename(file_path, '.*')
13
+ next unless sandbox.local?(scheme_name)
14
+
15
+ puts "Modify scheme to enable coverage symbol when prebuild: #{scheme_name}"
16
+
17
+ doc = File.open(file_path, 'r') { |f| REXML::Document.new(f) }
18
+ scheme = doc.elements['Scheme']
19
+ test_action = scheme.elements['TestAction']
20
+ next if test_action.attributes['codeCoverageEnabled'] == 'YES'
21
+
22
+ test_action.add_attribute('codeCoverageEnabled', 'YES')
23
+ test_action.add_attribute('onlyGenerateCoverageForSpecifiedTargets', 'YES')
24
+ coverage_targets = REXML::Element.new('CodeCoverageTargets')
25
+ buildable_ref = scheme.elements['BuildAction'] \
26
+ .elements['BuildActionEntries'] \
27
+ .elements['BuildActionEntry'] \
28
+ .elements['BuildableReference']
29
+ new_buildable_ref = buildable_ref.clone # Need to clone, otherwise the original one will be move to new place
30
+ coverage_targets.add_element(new_buildable_ref)
31
+ test_action.add_element(coverage_targets)
32
+ File.open(file_path, 'w') { |f| doc.write(f) }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ module PodPrebuild
2
+ class StateStore
3
+ @excluded_pods = Set.new
4
+ @cache_validation = CacheValidationResult.new
5
+
6
+ class << self
7
+ attr_accessor :excluded_pods
8
+ attr_accessor :cache_validation
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module Pod
2
+ module UI
3
+ class << self
4
+ def step(message)
5
+ section("❯❯❯ Step: #{message}".magenta) { yield if block_given? }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ # Copyright 2019 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved.
2
+ # Use of this source code is governed by an MIT-style license that can be found in the LICENSE file
3
+
4
+ require "cocoapods-binary-cache/main"
5
+ require "command/binary"
@@ -0,0 +1,18 @@
1
+ require "fileutils"
2
+ require_relative "config"
3
+ require_relative "fetch"
4
+ require_relative "prebuild"
5
+ require_relative "visualize"
6
+
7
+ module Pod
8
+ class Command
9
+ class Binary < Command
10
+ self.abstract_command = true
11
+ self.default_subcommand = "fetch"
12
+
13
+ def prebuild_config
14
+ @prebuild_config ||= PodPrebuild::Config.new("PodBinaryCacheConfig.json")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ require_relative "../cocoapods-binary-cache/helper/json"
2
+
3
+ module PodPrebuild
4
+ class Config
5
+ attr_reader :cache_repo, :cache_path, :prebuild_path
6
+
7
+ def initialize(path)
8
+ @data = PodPrebuild::JSONFile.new(path)
9
+ @cache_repo = @data["cache_repo"] || @data["prebuilt_cache_repo"]
10
+ @cache_path = File.expand_path(@data["cache_path"])
11
+ @prebuild_path = @data["prebuild_path"] || "Pods/_Prebuild"
12
+ end
13
+
14
+ def manifest_path(in_cache: false)
15
+ root_dir(in_cache) + "/Manifest.lock"
16
+ end
17
+
18
+ def root_dir(in_cache)
19
+ in_cache ? @cache_path : @prebuild_path
20
+ end
21
+
22
+ def generated_frameworks_dir(in_cache: false)
23
+ root_dir(in_cache) + "/GeneratedFrameworks"
24
+ end
25
+
26
+ def delta_file_path
27
+ # TODO (thuyen): Unify this path with PodPrebuild::Output#delta_file_path
28
+ "Pods/_Prebuild_delta/changes.json"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ module PodPrebuild
2
+ class CommandExecutor
3
+ def initialize(options)
4
+ @config = options[:config]
5
+ end
6
+
7
+ def git(cmd, options = {})
8
+ comps = ["git"]
9
+ comps << "-C" << @config.cache_path unless options[:cache_repo] == false
10
+ comps << cmd
11
+ comps << "&> /dev/null" if options[:ignore_output]
12
+ comps << "|| true" if options[:can_fail]
13
+ `#{comps.join(" ")}`
14
+ end
15
+
16
+ def git_clone(cmd, options = {})
17
+ git("clone #{cmd}", options.merge(:cache_repo => false))
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ require_relative "base"
2
+ require_relative "../helper/zip"
3
+
4
+ module PodPrebuild
5
+ class CacheFetcher < CommandExecutor
6
+ def initialize(options)
7
+ super(options)
8
+ @cache_branch = options[:cache_branch]
9
+ end
10
+
11
+ def run
12
+ Pod::UI.step("Fetching cache") do
13
+ fetch_cache(@config.cache_repo, @cache_branch, @config.cache_path)
14
+ unzip_cache
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def fetch_cache(repo, branch, dest_dir)
21
+ Pod::UI.puts "Fetching cache from #{repo} (branch: #{branch})".green
22
+ if Dir.exist?(dest_dir + "/.git")
23
+ git("fetch origin #{branch}")
24
+ git("checkout -f FETCH_HEAD", ignore_output: true)
25
+ git("branch -D #{branch} || true", ignore_output: true, can_fail: true)
26
+ git("checkout -b #{branch}")
27
+ else
28
+ FileUtils.rm_rf(dest_dir)
29
+ git_clone("--depth=1 --branch=#{branch} #{repo} #{dest_dir}")
30
+ end
31
+ end
32
+
33
+ def unzip_cache
34
+ Pod::UI.puts "Unzipping cache: #{@config.cache_path} -> #{@config.prebuild_path}".green
35
+ FileUtils.rm_rf(@config.prebuild_path)
36
+ FileUtils.mkdir_p(@config.prebuild_path)
37
+
38
+ FileUtils.cp(@config.manifest_path(in_cache: true), @config.manifest_path)
39
+ Dir[@config.generated_frameworks_dir(in_cache: true) + "/*.zip"].each do |path|
40
+ ZipUtils.unzip(path, to_dir: @config.generated_frameworks_dir)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,58 @@
1
+ require_relative "base"
2
+ require_relative "fetcher"
3
+ require_relative "pusher"
4
+
5
+ module PodPrebuild
6
+ class CachePrebuilder < CommandExecutor
7
+ def initialize(options)
8
+ super(options)
9
+ @cache_branch = options[:cache_branch]
10
+ @push_cache = options[:push_cache]
11
+ @fetcher = PodPrebuild::CacheFetcher.new(options)
12
+ @pusher = PodPrebuild::CachePusher.new(options)
13
+ end
14
+
15
+ def run
16
+ @fetcher.run
17
+ prebuild
18
+ changes = PodPrebuild::JSONFile.new(@config.delta_file_path)
19
+ return if changes.empty?
20
+
21
+ sync_cache(changes)
22
+ @pusher.run if @push_cache
23
+ end
24
+
25
+ private
26
+
27
+ def prebuild
28
+ Pod::UI.step("Installation") do
29
+ Pod::Command::Install.new(CLAide::ARGV.new([])).run
30
+ end
31
+ end
32
+
33
+ def sync_cache(changes)
34
+ Pod::UI.step("Syncing cache") do
35
+ FileUtils.cp(@config.manifest_path, @config.manifest_path(in_cache: true))
36
+ clean_cache(changes["deleted"])
37
+ zip_to_cache(changes["updated"])
38
+ end
39
+ end
40
+
41
+ def zip_to_cache(pods_to_update)
42
+ pods_to_update.each do |pod|
43
+ Pod::UI.puts "- Update cache: #{pod}"
44
+ ZipUtils.zip(
45
+ "#{@config.generated_frameworks_dir}/#{pod}",
46
+ to_dir: @config.generated_frameworks_dir(in_cache: true)
47
+ )
48
+ end
49
+ end
50
+
51
+ def clean_cache(pods_to_delete)
52
+ pods_to_delete.each do |pod|
53
+ Pod::UI.puts "- Clean up cache: #{pod}"
54
+ FileUtils.rm_rf("#{@config.generated_frameworks_dir(in_cache: true)}/#{pod}.zip")
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,19 @@
1
+ require_relative "base"
2
+
3
+ module PodPrebuild
4
+ class CachePusher < CommandExecutor
5
+ def initialize(options)
6
+ super(options)
7
+ @cache_branch = options[:cache_branch]
8
+ end
9
+
10
+ def run
11
+ Pod::UI.step("Pushing cache") do
12
+ commit_message = "Update prebuilt cache".shellescape
13
+ git("add .")
14
+ git("commit -m '#{commit_message}'")
15
+ git("push origin head")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ require_relative "base"
2
+ require_relative "../../cocoapods-binary-cache/dependencies_graph/dependencies_graph"
3
+
4
+ module PodPrebuild
5
+ class Visualizer < CommandExecutor
6
+ def initialize(options)
7
+ super(options)
8
+ @lockfile = options[:lockfile]
9
+ @open = options[:open]
10
+ @output_dir = options[:output_dir]
11
+ end
12
+
13
+ def run
14
+ FileUtils.mkdir_p(@output_dir)
15
+ graph = DependenciesGraph.new(@lockfile)
16
+ graph.write_graphic_file("png", "#{@output_dir}/graph", Set.new)
17
+ `open #{@output_dir}/graph.png` if @open
18
+ end
19
+ end
20
+ end