cocoapods-binary-gcp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module CocoapodsBinary
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,101 @@
1
+ require_relative '../tool/tool'
2
+ require_relative 'prebuild_sandbox'
3
+
4
+ module Pod
5
+
6
+ # a flag that indicate stages
7
+ class_attr_accessor :is_prebuild_stage
8
+
9
+
10
+ # a switch for the `pod` DSL to make it only valid for ':binary => true'
11
+ class Podfile
12
+ module DSL
13
+
14
+ @@enable_prebuild_patch = false
15
+
16
+ # when enable, `pod` function will skip all pods without 'prebuild => true'
17
+ def self.enable_prebuild_patch(value)
18
+ @@enable_prebuild_patch = value
19
+ end
20
+
21
+ # --- patch ---
22
+ old_method = instance_method(:pod)
23
+
24
+ define_method(:pod) do |name, *args|
25
+ if !@@enable_prebuild_patch
26
+ old_method.bind(self).(name, *args)
27
+ return
28
+ end
29
+
30
+ # patched content
31
+ should_prebuild = Pod::Podfile::DSL.prebuild_all
32
+ local = false
33
+
34
+ options = args.last
35
+ if options.is_a?(Hash) and options[Pod::Prebuild.keyword] != nil
36
+ should_prebuild = options[Pod::Prebuild.keyword]
37
+ local = (options[:path] != nil)
38
+ end
39
+
40
+ if not Pod::Podfile::DSL.except_binary_list.nil?
41
+ should_prebuild = !Pod::Podfile::DSL.except_binary_list.include?(name)
42
+ end
43
+
44
+ if should_prebuild and (not local)
45
+ old_method.bind(self).(name, *args)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+ # a force disable option for integral
53
+ class Installer
54
+ def self.force_disable_integration(value)
55
+ @@force_disable_integration = value
56
+ end
57
+
58
+ old_method = instance_method(:integrate_user_project)
59
+ define_method(:integrate_user_project) do
60
+ if @@force_disable_integration
61
+ return
62
+ end
63
+ old_method.bind(self).()
64
+ end
65
+ end
66
+
67
+ # a option to disable install complete message
68
+ class Installer
69
+ def self.disable_install_complete_message(value)
70
+ @@disable_install_complete_message = value
71
+ end
72
+
73
+ old_method = instance_method(:print_post_install_message)
74
+ define_method(:print_post_install_message) do
75
+ if @@disable_install_complete_message
76
+ return
77
+ end
78
+ old_method.bind(self).()
79
+ end
80
+ end
81
+
82
+ # option to disable write lockfiles
83
+ class Config
84
+
85
+ @@force_disable_write_lockfile = false
86
+ def self.force_disable_write_lockfile(value)
87
+ @@force_disable_write_lockfile = value
88
+ end
89
+
90
+ old_method = instance_method(:lockfile_path)
91
+ define_method(:lockfile_path) do
92
+ if @@force_disable_write_lockfile
93
+ # As config is a singleton, sandbox_root refer to the standard sandbox.
94
+ return PrebuildSandbox.from_standard_sanbox_path(sandbox_root).root + 'Manifest.lock.tmp'
95
+ else
96
+ return old_method.bind(self).()
97
+ end
98
+ end
99
+ end
100
+
101
+ end
@@ -0,0 +1,78 @@
1
+ # ABOUT NAMES
2
+ #
3
+ # There are many kinds of name in cocoapods. Two main names are widely used in this plugin.
4
+ # - root_spec.name (spec.root_name, targe.pod_name):
5
+ # aka "pod_name"
6
+ # the name we use in podfile. the concept.
7
+ #
8
+ # - target.name:
9
+ # aka "target_name"
10
+ # the name of the final target in xcode project. the final real thing.
11
+ #
12
+ # One pod may have multiple targets in xcode project, due to one pod can be used in mutiple
13
+ # platform simultaneously. So one `root_spec.name` may have multiple coresponding `target.name`s.
14
+ # Therefore, map a spec to/from targets is a little complecated. It's one to many.
15
+ #
16
+
17
+ # Tool to transform Pod_name to target efficiently
18
+ module Pod
19
+ def self.fast_get_targets_for_pod_name(pod_name, targets, cache)
20
+ pod_name_to_targets_hash = nil
21
+ if cache.empty?
22
+ pod_name_to_targets_hash = targets.reduce({}) do |sum, target|
23
+ array = sum[target.pod_name] || []
24
+ array << target
25
+ sum[target.pod_name] = array
26
+ sum
27
+ end
28
+ cache << pod_name_to_targets_hash
29
+ else
30
+ pod_name_to_targets_hash = cache.first
31
+ end
32
+
33
+ pod_name_to_targets_hash[pod_name] || []
34
+ end
35
+ end
36
+
37
+
38
+
39
+
40
+
41
+
42
+ # Target:
43
+
44
+ # def pod_name
45
+ # root_spec.name
46
+ # end
47
+
48
+ # def name
49
+ # pod_name + #{scope_suffix}
50
+ # end
51
+
52
+ # def product_module_name
53
+ # root_spec.module_name
54
+ # end
55
+
56
+ # def framework_name
57
+ # "#{product_module_name}.framework"
58
+ # end
59
+
60
+ # def product_name
61
+ # if requires_frameworks?
62
+ # framework_name
63
+ # else
64
+ # static_library_name
65
+ # end
66
+ # end
67
+
68
+ # def product_basename
69
+ # if requires_frameworks?
70
+ # product_module_name
71
+ # else
72
+ # label
73
+ # end
74
+ # end
75
+
76
+ # def framework_name
77
+ # "#{product_module_name}.framework"
78
+ # end
@@ -0,0 +1,41 @@
1
+ require_relative '../tool/tool'
2
+
3
+ module Pod
4
+ class Prebuild
5
+
6
+ # Pass the data between the 2 steps
7
+ #
8
+ # At step 2, the normal pod install, it needs some info of the
9
+ # prebuilt step. So we store it here.
10
+ #
11
+ class Passer
12
+
13
+ # indicate the add/remove/update of prebuit pods
14
+ # @return [Analyzer::SpecsState]
15
+ #
16
+ class_attr_accessor :prebuild_pods_changes
17
+
18
+
19
+ # represent the path of resurces to copy
20
+ class ResourcePath
21
+ attr_accessor :real_file_path
22
+ attr_accessor :target_file_path
23
+ end
24
+ # Save the resoures for static framework, and used when installing the prebuild framework
25
+ # static framework needs copy the resurces mannully
26
+ #
27
+ # @return [Hash<String, [Passer::ResourcePath]>]
28
+ class_attr_accessor :resources_to_copy_for_static_framework
29
+ self.resources_to_copy_for_static_framework = {}
30
+
31
+ # Some pod won't be build in prebuild stage even if it have `binary=>true`.
32
+ # The targets of this pods have `oshould_build? == true`.
33
+ # We should skip integration (patch spec) for this pods
34
+ #
35
+ # @return [Array<String>]
36
+ class_attr_accessor :target_names_to_skip_integration_framework
37
+ self.target_names_to_skip_integration_framework = []
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,133 @@
1
+ module Pod
2
+
3
+ class Prebuild
4
+ def self.keyword
5
+ :binary
6
+ end
7
+ end
8
+
9
+ class Podfile
10
+ class TargetDefinition
11
+
12
+ ## --- option for setting using prebuild framework ---
13
+ def parse_prebuild_framework(name, requirements)
14
+ should_prebuild = Pod::Podfile::DSL.prebuild_all
15
+
16
+ options = requirements.last
17
+ if options.is_a?(Hash) && options[Pod::Prebuild.keyword] != nil
18
+ should_prebuild = options.delete(Pod::Prebuild.keyword)
19
+ requirements.pop if options.empty?
20
+ end
21
+
22
+ pod_name = Specification.root_name(name)
23
+ set_prebuild_for_pod(pod_name, should_prebuild)
24
+ end
25
+
26
+ def set_prebuild_for_pod(pod_name, should_prebuild)
27
+
28
+ if should_prebuild == true
29
+ @prebuild_framework_pod_names ||= []
30
+ @prebuild_framework_pod_names.push pod_name
31
+ else
32
+ @should_not_prebuild_framework_pod_names ||= []
33
+ @should_not_prebuild_framework_pod_names.push pod_name
34
+ end
35
+ end
36
+
37
+ def prebuild_framework_pod_names
38
+ names = @prebuild_framework_pod_names || []
39
+ if parent != nil and parent.kind_of? TargetDefinition
40
+ names += parent.prebuild_framework_pod_names
41
+ end
42
+ names
43
+ end
44
+ def should_not_prebuild_framework_pod_names
45
+ names = @should_not_prebuild_framework_pod_names || []
46
+ if parent != nil and parent.kind_of? TargetDefinition
47
+ names += parent.should_not_prebuild_framework_pod_names
48
+ end
49
+ names
50
+ end
51
+
52
+ # ---- patch method ----
53
+ # We want modify `store_pod` method, but it's hard to insert a line in the
54
+ # implementation. So we patch a method called in `store_pod`.
55
+ old_method = instance_method(:parse_inhibit_warnings)
56
+
57
+ define_method(:parse_inhibit_warnings) do |name, requirements|
58
+ parse_prebuild_framework(name, requirements)
59
+ old_method.bind(self).(name, requirements)
60
+ end
61
+
62
+ end
63
+ end
64
+ end
65
+
66
+
67
+ module Pod
68
+ class Installer
69
+
70
+ def prebuild_pod_targets
71
+ @prebuild_pod_targets ||= (
72
+ all = []
73
+
74
+ aggregate_targets = self.aggregate_targets
75
+ aggregate_targets.each do |aggregate_target|
76
+ target_definition = aggregate_target.target_definition
77
+ targets = aggregate_target.pod_targets || []
78
+
79
+ # filter prebuild
80
+ prebuild_names = target_definition.prebuild_framework_pod_names
81
+ if not Podfile::DSL.prebuild_all
82
+ targets = targets.select { |pod_target| prebuild_names.include?(pod_target.pod_name) }
83
+ end
84
+ dependency_targets = targets.map {|t| t.recursive_dependent_targets }.flatten.uniq || []
85
+ targets = (targets + dependency_targets).uniq
86
+
87
+ # filter should not prebuild
88
+ explict_should_not_names = target_definition.should_not_prebuild_framework_pod_names
89
+ targets = targets.reject { |pod_target| explict_should_not_names.include?(pod_target.pod_name) }
90
+
91
+ if not Pod::Podfile::DSL.except_binary_list.nil?
92
+ targets = targets.reject { |pod_target| Pod::Podfile::DSL.except_binary_list.include?(pod_target.pod_name) }
93
+ end
94
+
95
+ all += targets
96
+ end
97
+
98
+ all = all.reject {|pod_target| sandbox.local?(pod_target.pod_name) }
99
+ all.uniq
100
+ )
101
+ end
102
+
103
+ # the root names who needs prebuild, including dependency pods.
104
+ def prebuild_pod_names
105
+ @prebuild_pod_names ||= self.prebuild_pod_targets.map(&:pod_name)
106
+ end
107
+
108
+
109
+ def validate_every_pod_only_have_one_form
110
+
111
+ multi_targets_pods = self.pod_targets.group_by do |t|
112
+ t.pod_name
113
+ end.select do |k, v|
114
+ v.map{|t| t.platform.name }.count > 1
115
+ end
116
+
117
+ multi_targets_pods = multi_targets_pods.reject do |name, targets|
118
+ contained = targets.map{|t| self.prebuild_pod_targets.include? t }
119
+ contained.uniq.count == 1 # all equal
120
+ end
121
+
122
+ return if multi_targets_pods.empty?
123
+
124
+ warnings = "One pod can only be prebuilt or not prebuilt. These pod have different forms in multiple targets:\n"
125
+ warnings += multi_targets_pods.map{|name, targets| " #{name}: #{targets.map{|t|t.platform.name}}"}.join("\n")
126
+ raise Informative, warnings
127
+ end
128
+
129
+ end
130
+ end
131
+
132
+
133
+
@@ -0,0 +1,73 @@
1
+ require_relative "names"
2
+
3
+ module Pod
4
+ class PrebuildSandbox < Sandbox
5
+
6
+ # [String] standard_sandbox_path
7
+ def self.from_standard_sanbox_path(path)
8
+ prebuild_sandbox_path = Pathname.new(path).realpath + "_Prebuild"
9
+ self.new(prebuild_sandbox_path)
10
+ end
11
+
12
+ def self.from_standard_sandbox(sandbox)
13
+ self.from_standard_sanbox_path(sandbox.root)
14
+ end
15
+
16
+ def standard_sanbox_path
17
+ self.root.parent
18
+ end
19
+
20
+ def generate_framework_path
21
+ self.root + "GeneratedFrameworks"
22
+ end
23
+
24
+ # @param name [String] pass the target.name (may containing platform suffix)
25
+ # @return [Pathname] the folder containing the framework file.
26
+ def framework_folder_path_for_target_name(name)
27
+ self.generate_framework_path + name
28
+ end
29
+
30
+
31
+ def exsited_framework_target_names
32
+ exsited_framework_name_pairs.map {|pair| pair[0]}.uniq
33
+ end
34
+ def exsited_framework_pod_names
35
+ exsited_framework_name_pairs.map {|pair| pair[1]}.uniq
36
+ end
37
+ def existed_target_names_for_pod_name(pod_name)
38
+ exsited_framework_name_pairs.select {|pair| pair[1] == pod_name }.map { |pair| pair[0]}
39
+ end
40
+
41
+
42
+
43
+ def save_pod_name_for_target(target)
44
+ folder = framework_folder_path_for_target_name(target.name)
45
+ return unless folder.exist?
46
+ flag_file_path = folder + "#{target.pod_name}.pod_name"
47
+ File.write(flag_file_path.to_s, "")
48
+ end
49
+
50
+
51
+ private
52
+
53
+ def pod_name_for_target_folder(target_folder_path)
54
+ name = Pathname.new(target_folder_path).children.find do |child|
55
+ child.to_s.end_with? ".pod_name"
56
+ end
57
+ name = name.basename(".pod_name").to_s unless name.nil?
58
+ name ||= Pathname.new(target_folder_path).basename.to_s # for compatibility with older version
59
+ end
60
+
61
+ # Array<[target_name, pod_name]>
62
+ def exsited_framework_name_pairs
63
+ return [] unless generate_framework_path.exist?
64
+ generate_framework_path.children().map do |framework_path|
65
+ if framework_path.directory? && (not framework_path.children.empty?)
66
+ [framework_path.basename.to_s, pod_name_for_target_folder(framework_path)]
67
+ else
68
+ nil
69
+ end
70
+ end.reject(&:nil?).uniq
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,133 @@
1
+ require 'digest'
2
+ require_relative '../tool/tool'
3
+ require "google/cloud/storage"
4
+ require 'zip'
5
+
6
+ module Pod
7
+ class Prebuild
8
+ class SharedCache
9
+ extend Config::Mixin
10
+
11
+ # `true` if there is cache for the target
12
+ # `false` otherwise
13
+ #
14
+ # @return [Boolean]
15
+ def self.has?(target, options)
16
+ if Podfile::DSL.shared_cache_enabled
17
+ path = framework_cache_path_for(target, options)
18
+ if path.exist?
19
+ Pod::UI.puts "Local cache for #{target.name} found"
20
+ true
21
+ else
22
+ Pod::UI.puts "Local cache for #{target.name} not found"
23
+ if Podfile::DSL.shared_gcp_cache_enabled
24
+ cloud_path = cloud_framework_path_for(target, options)
25
+ storage = Google::Cloud::Storage.new
26
+ bucket = storage.bucket(Podfile::DSL.gcp_options[:bucket])
27
+ file = bucket.file "#{cloud_path}"
28
+ if not file.nil?
29
+ Pod::UI.puts "GCP cache for #{target.name} found, downloading..."
30
+ Dir.mktmpdir {|dir|
31
+ file.download "#{dir}/framework.zip"
32
+ unzip("#{dir}/framework.zip", path)
33
+ }
34
+ true
35
+ else
36
+ Pod::UI.puts "GCP cache for #{target.name} not found"
37
+ false
38
+ end
39
+ else
40
+ false
41
+ end
42
+ end
43
+ else
44
+ false
45
+ end
46
+ end
47
+
48
+ # Copies input_path to target's cache
49
+ def self.cache(target, input_path, options)
50
+ if not Podfile::DSL.shared_cache_enabled
51
+ return
52
+ end
53
+ cache_path = framework_cache_path_for(target, options)
54
+ cache_path.mkpath unless cache_path.exist?
55
+ FileUtils.cp_r "#{input_path}/.", cache_path
56
+
57
+ if Podfile::DSL.shared_gcp_cache_enabled
58
+ cloud_path = cloud_framework_path_for(target, options)
59
+ storage = Google::Cloud::Storage.new
60
+ bucket = storage.bucket(Podfile::DSL.gcp_options[:bucket])
61
+
62
+ Pod::UI.puts "Save to remote cache"
63
+ Dir.mktmpdir {|dir|
64
+ zip(cache_path, "#{dir}/framework.zip")
65
+ bucket.create_file "#{dir}/framework.zip",
66
+ "#{cloud_path}"
67
+ }
68
+ end
69
+ end
70
+
71
+ # Path of the target's cache
72
+ #
73
+ # @return [Pathname]
74
+ def self.framework_cache_path_for(target, options)
75
+ framework_cache_path = cache_root + xcode_version
76
+ framework_cache_path = framework_cache_path + target.name
77
+ framework_cache_path = framework_cache_path + target.version
78
+ options_with_platform = options + [target.platform.name]
79
+ framework_cache_path = framework_cache_path + Digest::MD5.hexdigest(options_with_platform.to_s).to_s
80
+ end
81
+
82
+ def self.cloud_framework_path_for(target, options)
83
+ cloud_cache_path = Pathname.new('').to_s + xcode_version
84
+ cloud_cache_path = cloud_cache_path + target.name
85
+ cloud_cache_path = cloud_cache_path + target.version
86
+ options_with_platform = options + [target.platform.name]
87
+ cloud_cache_path = cloud_cache_path + Digest::MD5.hexdigest(options_with_platform.to_s).to_s
88
+ end
89
+
90
+ def self.zip(dir, zip_dir)
91
+ Zip::File.open(zip_dir, Zip::File::CREATE)do |zipfile|
92
+ Find.find(dir) do |path|
93
+ Find.prune if File.basename(path)[0] == ?.
94
+ dest = /#{dir}\/(\w.*)/.match(path)
95
+ # Skip files if they exists
96
+ begin
97
+ zipfile.add(dest[1],path) if dest
98
+ rescue Zip::ZipEntryExistsError
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ def self.unzip(zip, unzip_dir, remove_after = false)
105
+ Zip::File.open(zip) do |zip_file|
106
+ zip_file.each do |f|
107
+ f_path=File.join(unzip_dir, f.name)
108
+ FileUtils.mkdir_p(File.dirname(f_path))
109
+ zip_file.extract(f, f_path) unless File.exist?(f_path)
110
+ end
111
+ end
112
+ FileUtils.rm(zip) if remove_after
113
+ end
114
+
115
+ # Current xcode version.
116
+ #
117
+ # @return [String]
118
+ private
119
+ class_attr_accessor :xcode_version
120
+ # Converts from "Xcode 10.2.1\nBuild version 10E1001\n" to "10.2.1".
121
+ self.xcode_version = `xcodebuild -version`.split("\n").first.split().last || "Unkwown"
122
+
123
+ # Path of the cache folder
124
+ # Reusing cache_root from cocoapods's config
125
+ # `~Library/Caches/CocoaPods` is default value
126
+ #
127
+ # @return [Pathname]
128
+ private
129
+ class_attr_accessor :cache_root
130
+ self.cache_root = config.cache_root + 'Prebuilt'
131
+ end
132
+ end
133
+ end