cocoapods-binary-cache 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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